/* ==========================================================================
   Gaia Group — main.css
   One stylesheet. No framework. Mobile first. No motion (CLAUDE.md).
   Colours per CLAUDE.md visual system:
     #004650 primary deep teal   — headers, nav, footer, big number blocks
     #0FB5A6 accent teal         — CTAs, plus position/interaction states only (D191):
                                   focus rings, hover, current-page underline, journey-bar
                                   current step, price-callout edge, roundel. Never decoration.
     #1a1a1a body ink on white / off-white
   ========================================================================== */

:root {
  --teal: #004650;
  --teal-dark: #003239;
  --teal-line: #cfdcde;
  --teal-wash: #eef3f4;
  --accent: #0fb5a6;
  --accent-dark: #0c9689;
  --ink: #1a1a1a;
  --ink-mid: #4a5558;
  --white: #ffffff;
  --off: #f7f8f8;
  --warn-wash: #fff8e6;
  --warn-line: #e6c86a;

  --wrap: 1100px;
  --gap: 1.5rem;
}

/* --- reset ------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: auto; /* no motion */
}

body {
  margin: 0;
  background: var(--white);
  color: var(--ink);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Arial, Helvetica, sans-serif;
  font-size: 18px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

img, svg { max-width: 100%; height: auto; display: block; }

a { color: var(--teal); text-decoration: underline; text-underline-offset: 2px; }
a:hover { color: var(--accent-dark); }

/* --- typography -------------------------------------------------------- */

h1, h2, h3, h4 {
  margin: 0 0 0.6em;
  line-height: 1.12;
  letter-spacing: -0.02em;
  font-weight: 700;
  color: var(--teal);
  text-wrap: balance;
}

h1 { font-size: clamp(2rem, 7.4vw, 3.4rem); }
h2 { font-size: clamp(1.55rem, 5vw, 2.3rem); }
h3 { font-size: clamp(1.2rem, 3.6vw, 1.45rem); }
h4 { font-size: 1.05rem; }

p, ul, ol, dl { margin: 0 0 1.1em; }
li { margin-bottom: 0.45em; }
strong { font-weight: 700; }

.lede {
  font-size: clamp(1.1rem, 3.6vw, 1.3rem);
  color: var(--ink);
}

.small { font-size: 0.92rem; }

/* Source / rate / disclosure notes. Rule 6: the assumed rate sits with the £. */
.note {
  font-size: 0.88rem;
  line-height: 1.5;
  color: var(--ink-mid);
  margin: 0 0 1em;
}
.note--tight { margin-bottom: 0; }

/* Notes on a teal ground need a light ink or they vanish. */
.hero .note,
.section--teal .note { color: #b9d3d5; }
.hero .note strong,
.section--teal .note strong { color: var(--white); }

/* --- layout ------------------------------------------------------------ */

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 0 1.15rem;
}

.section { padding: 2.75rem 0; }
.section--alt { background: var(--off); }
.section--teal { background: var(--teal); color: var(--white); }
.section--teal h2, .section--teal h3 { color: var(--white); }
.section--teal a { color: var(--white); }

.section > .wrap > :last-child { margin-bottom: 0; }

.grid { display: grid; gap: var(--gap); }

@media (min-width: 700px) {
  .section { padding: 3.75rem 0; }
  .grid--3 { grid-template-columns: repeat(3, 1fr); }
  .grid--2 { grid-template-columns: repeat(2, 1fr); }
  .grid--4 { grid-template-columns: repeat(4, 1fr); }
}

/* --- skip link -------------------------------------------------------- */

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--white);
  color: var(--teal);
  padding: 0.7rem 1rem;
  z-index: 20;
}
.skip:focus { left: 0; }

/* --- header / nav ----------------------------------------------------- */

.masthead {
  background: var(--teal);
  color: var(--white);
  padding: 0.85rem 0;
}

.masthead__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1.25rem;
}

.brand {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  font-size: 1.22rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--white);
  text-decoration: none;
  margin-right: auto;
}
.brand img { width: 30px; height: 30px; }

.nav ul {
  display: flex;
  flex-wrap: wrap;
  /* 0.875rem, tightened from 1.15rem 26 July 2026. Nine nav items plus the
     134px wordmark and the 194px CTA overflow 1100px at the old gap: the
     button drops to a second row and the masthead goes 66px -> 113px. This
     recovers ~35px, which with three shortened labels lands the nav at 674px
     and holds one row. MEASURE before adding a tenth item. */
  gap: 0.35rem 0.875rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.nav li { margin: 0; }

.nav a {
  color: var(--white);
  text-decoration: none;
  font-size: 0.97rem;
  border-bottom: 2px solid transparent;
  padding-bottom: 2px;
}
.nav a:hover,
.nav a[aria-current="page"] { color: var(--white); border-bottom-color: var(--accent); }

/* --- buttons — accent teal is for CTAs and nothing else ---------------- */

.btn {
  display: inline-block;
  background: var(--accent);
  color: #00312f;
  font-size: 1.02rem;
  font-weight: 700;
  line-height: 1.3;
  text-decoration: none;
  padding: 0.85rem 1.3rem;
  border: 2px solid var(--accent);
  border-radius: 3px;
}
.btn:hover { background: var(--accent-dark); border-color: var(--accent-dark); color: #00312f; }

.btn--nav { padding: 0.5rem 0.9rem; font-size: 0.95rem; }

.btn--ghost {
  background: transparent;
  color: var(--teal);
  border-color: var(--teal);
}
.btn--ghost:hover { background: var(--teal); border-color: var(--teal); color: var(--white); }

.section--teal .btn--ghost { color: var(--white); border-color: var(--white); }
.section--teal .btn--ghost:hover { background: var(--white); color: var(--teal); }

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.8rem;
  align-items: center;
  margin-bottom: 1.1em;
}

/* --- hero ------------------------------------------------------------- */

.hero {
  background: var(--teal);
  color: var(--white);
  padding: 2.25rem 0 2.75rem;
}
.hero h1 { color: var(--white); margin-bottom: 0.5em; }
.hero .lede { color: #dcebec; max-width: 34ch; }
/* The award credit line's link. Without this it takes the global a{} teal and
   paints #004650 on the hero's #004650 ground - invisible (DESIGN_BRIEF §5,
   the teal-on-teal trap). White on #004650 is 10.5:1; the underline survives
   from the global rule, same pattern as .section--teal a and .hero__alt a. */
.hero__cred a { color: var(--white); }

@media (min-width: 900px) {
  .hero { padding: 3.5rem 0 4rem; }
  .hero__inner {
    display: grid;
    grid-template-columns: 1.05fr 0.95fr;
    gap: 2.5rem;
    align-items: start;
  }
  /* the ladder is a full-width second row beneath both columns */
  .hero__ladder { grid-column: 1 / -1; }
}

/* --- the numbers: hero elements, not photography ---------------------- */

.figures {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.5rem;
  margin: 1.75rem 0 1.5rem;
  border-top: 1px solid rgba(255, 255, 255, 0.28);
  padding-top: 1.25rem;
}

.figure__pc {
  display: block;
  font-size: clamp(2.6rem, 12vw, 4.4rem);
  font-weight: 700;
  line-height: 0.95;
  letter-spacing: -0.045em;
  color: var(--white);
}
.figure__label {
  display: block;
  font-size: 0.82rem;
  line-height: 1.35;
  color: #b9d3d5;
  margin-top: 0.45rem;
}

/* Case-study result blocks put a kWh total and a £ figure alongside the
   percentage. Those strings are far wider than "89%", so a hard 3-up grid
   overflows at 375px. Let them wrap, and hold 3-up once there is room. */
.figures--metrics {
  grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr));
}
.figures--metrics .figure__pc {
  font-size: clamp(2rem, 8.5vw, 3.4rem);
}

/* Same block on a light background */
.figures--light {
  border-top-color: var(--teal-line);
  margin-top: 0;
}
.figures--light .figure__pc { color: var(--teal); }
.figures--light .figure__label { color: var(--ink-mid); }

/* --- image placeholder: marked, never a stock substitute (rule 9) ------ */

.shot-needed {
  border: 2px dashed rgba(255, 255, 255, 0.45);
  background: rgba(255, 255, 255, 0.05);
  color: #cfe3e4;
  padding: 1.5rem 1.25rem;
  font-size: 0.9rem;
  line-height: 1.5;
  border-radius: 3px;
  min-height: 230px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.5rem;
}
.shot-needed strong { color: var(--white); display: block; font-size: 0.98rem; }
.shot-needed p { margin: 0; }

/* --- cards ------------------------------------------------------------ */

.card {
  background: var(--white);
  border: 1px solid var(--teal-line);
  border-top: 4px solid var(--teal);
  padding: 1.35rem 1.25rem;
  border-radius: 3px;
}
.card > :last-child { margin-bottom: 0; }
.card h3 { margin-bottom: 0.4em; }

.card__pc {
  display: block;
  font-size: 2.9rem;
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.04em;
  color: var(--teal);
  margin-bottom: 0.2rem;
}
.card__who {
  display: block;
  font-size: 0.86rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-mid);
  margin-bottom: 0.9rem;
}

.card dl { margin: 0 0 0.9em; font-size: 0.95rem; }
.card dt {
  font-weight: 700;
  color: var(--ink-mid);
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.card dd { margin: 0 0 0.6em; }

/* --- problem blocks --------------------------------------------------- */

.problem {
  border-left: 4px solid var(--teal);
  padding-left: 1.1rem;
}
.problem > :last-child { margin-bottom: 0; }
.problem h3 { margin-bottom: 0.35em; }

/* --- guarantee / callout boxes ---------------------------------------- */

.callout {
  background: var(--teal-wash);
  border: 1px solid var(--teal-line);
  border-left: 5px solid var(--teal);
  padding: 1.3rem 1.25rem;
  border-radius: 3px;
}
.callout > :last-child { margin-bottom: 0; }
.callout h3 { margin-bottom: 0.45em; }

.callout--price {
  background: var(--white);
}

/* The one line of arithmetic we publish — methodology/, mechanism 1.
   Set apart so a QS can find it without it reading as a code block. */
.formula {
  background: var(--teal-wash);
  border-left: 5px solid var(--teal);
  padding: 0.9rem 1.1rem;
  border-radius: 3px;
  font-size: 1.05rem;
  line-height: 1.45;
  color: var(--teal);
}
.price-block { margin-top: 1.5rem; }
.price-line {
  display: block;
  font-size: clamp(1.6rem, 5.5vw, 2.15rem);
  font-weight: 700;
  letter-spacing: -0.03em;
  color: var(--teal);
  line-height: 1.15;
  margin-bottom: 0.35rem;
}

.section--teal .callout {
  background: rgba(255, 255, 255, 0.07);
  border-color: rgba(255, 255, 255, 0.3);
  border-left-color: var(--accent);
}

/* The price block stays a white card even on teal — it is the confidence signal. */
.section--teal .callout--price {
  background: var(--white);
  color: var(--ink);
  border-color: var(--teal-line);
  border-left-color: var(--accent);
}
.section--teal .callout--price .price-line { color: var(--teal); }
.section--teal .callout--price a { color: var(--teal); }
.section--teal .callout--price a:hover { color: var(--accent-dark); }

/* --- how it works: diagram + its text equivalent ---------------------- */

.diagram {
  max-width: 480px;
  margin: 0 auto 1.5rem;
  background: var(--white);
  border: 1px solid var(--teal-line);
  border-radius: 3px;
  padding: 0.75rem;
}

@media (min-width: 860px) {
  .diagram-pair {
    display: grid;
    /* minmax(0, 1fr), not bare 1fr: a grid item's min-width:auto stops a 1fr
       track shrinking below the circuit-schedule table's min-content, so the
       grid blew the page out at 860 instead of letting .table-scroll pan.
       A 0 min lets the track shrink and hands overflow to .table-scroll. */
    grid-template-columns: 460px minmax(0, 1fr);
    gap: 2.5rem;
    align-items: start;
  }
  .diagram { margin: 0; }
}

.scheme { margin: 0; font-size: 0.97rem; }
.scheme dt {
  font-weight: 700;
  color: var(--teal);
  margin-top: 0.9em;
}
.scheme dd { margin: 0.15em 0 0; }

/* --- footer ----------------------------------------------------------- */

.footer {
  background: var(--teal-dark);
  color: #c3d6d8;
  padding: 2.25rem 0 2.5rem;
  font-size: 0.95rem;
}
.footer h2 {
  color: var(--white);
  font-size: 1rem;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  margin-bottom: 0.7em;
}
.footer a { color: var(--white); }
.footer ul { list-style: none; padding: 0; margin: 0 0 1.5em; }
.footer li { margin-bottom: 0.4em; }

.footer__legal {
  border-top: 1px solid rgba(255, 255, 255, 0.18);
  padding-top: 1.25rem;
  margin-top: 0.5rem;
  font-size: 0.86rem;
}
.footer__legal p { margin-bottom: 0.5em; }

@media (min-width: 700px) {
  .footer__cols { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--gap); }
}

/* --- brand lockup: masthead + footer, library and funnel pages (26 July 2026) --
   Installed from gaia block bgs.ai. Live text "Gaia" stays live text (accessible
   and indexable) rather than becoming an image; only the mark is a graphic, and
   it is decorative there because the text already carries the name.
   Masthead and footer are both on brand-teal backgrounds estate-wide, so the mark
   uses the D053 dark-context accent (#0FB5A6) rather than currentColor — inheriting
   currentColor here would resolve to white (.brand's text colour), not teal. -------- */
.brand-mark { width: 1.35em; height: 1.35em; color: #0FB5A6; flex: 0 0 auto; }
.footer__brand {
  display: flex; align-items: center; gap: 0.5rem;
  font-size: 1.05rem; font-weight: 700; letter-spacing: -0.01em;
  color: var(--white); text-decoration: none; margin-bottom: 1.5rem;
}
.footer__brand .brand-mark { width: 1.2em; height: 1.2em; }

/* --- utilities -------------------------------------------------------- */

.vh {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.mb0 { margin-bottom: 0; }

/* ==========================================================================
   Shared components added for the multi-page build (Batch 1)
   ========================================================================== */

/* --- eyebrow / page intro ---------------------------------------------- */

.eyebrow {
  display: block;
  font-size: 0.82rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--ink-mid);
  margin-bottom: 0.6rem;
}
.hero .eyebrow, .section--teal .eyebrow { color: #8fc0c2; }

/* Page header band for interior pages */
.pagehead {
  background: var(--teal);
  color: var(--white);
  padding: 2rem 0 2.25rem;
}
.pagehead h1 { color: var(--white); margin-bottom: 0.45em; }
.pagehead .lede { color: #dcebec; max-width: 62ch; }
.pagehead > .wrap > :last-child { margin-bottom: 0; }

@media (min-width: 700px) {
  .pagehead { padding: 3rem 0 3.25rem; }
}

/* --- prose width for reading-heavy pages ------------------------------- */

.prose { max-width: 68ch; }
.prose > :last-child { margin-bottom: 0; }

/* --- third-party citation blocks (awards/) ----------------------------
   Someone else's words, their attribution, and a prominent link to the
   original. The link is the proof, so it is never a footnote.
   No logos, no badges — text and links only.
   ---------------------------------------------------------------------- */

.cite {
  margin: 0 0 1.75rem;
  padding: 0 0 0 1.25rem;
  border-left: 4px solid var(--teal-line);
  max-width: 68ch;
}
.cite blockquote {
  margin: 0 0 0.85rem;
  font-size: clamp(1.08rem, 2.6vw, 1.25rem);
  line-height: 1.5;
  color: var(--ink);
}
.cite blockquote p { margin: 0 0 0.6em; }
.cite blockquote > :last-child { margin-bottom: 0; }

/* The award citation itself — the one quote that gets set large. */
.cite--hero { border-left-width: 5px; border-left-color: var(--teal); }
.cite--hero blockquote {
  font-size: clamp(1.3rem, 4vw, 1.9rem);
  line-height: 1.32;
  letter-spacing: -0.018em;
  font-weight: 700;
  color: var(--teal);
}

.cite__source {
  margin: 0;
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--ink-mid);
}
.cite__source strong { color: var(--ink); }
.cite__source a { font-weight: 700; }

/* Read-the-original link, given weight rather than tucked away */
.source-link {
  display: inline-block;
  margin-top: 0.35rem;
  font-weight: 700;
  word-break: break-word;
}
.source-link::after { content: " \2197"; text-decoration: none; }

/* Who said it, above the quote */
.cite__who {
  margin: 0 0 0.5rem;
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-mid);
}

/* Judging panel / plain named lists */
.namelist { list-style: none; margin: 0 0 1.2em; padding: 0; max-width: 68ch; }
.namelist li {
  margin: 0;
  padding: 0.55rem 0;
  border-bottom: 1px solid var(--teal-line);
  font-size: 0.97rem;
}
.namelist li:first-child { border-top: 1px solid var(--teal-line); }
.namelist strong { color: var(--teal); }

/* --- FAQ / questions page --------------------------------------------- */

.qa {
  border-top: 1px solid var(--teal-line);
  padding-top: 1.6rem;
  margin-top: 1.6rem;
}
.qa:first-of-type { border-top: 0; padding-top: 0; margin-top: 0; }
/* No scroll-margin-top on .qa or #won. Both carried 60px to clear the .gp-chev
   bar; the bar is no longer sticky and /questions/ and /awards/ no longer carry
   it at all, so there is nothing to clear. Reverted 28 July 2026. */

.qa h2 {
  font-size: clamp(1.25rem, 4vw, 1.6rem);
  margin-bottom: 0.5em;
}
.qa > :last-child { margin-bottom: 0; }
.qa p, .qa ul, .qa ol { max-width: 68ch; }

/* Jump list at the top of a long page */
.jump {
  background: var(--off);
  border: 1px solid var(--teal-line);
  border-radius: 3px;
  padding: 1.1rem 1.25rem;
  margin-bottom: 2.25rem;
}
.jump h2 {
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--ink-mid);
  margin-bottom: 0.7em;
}
.jump ol {
  margin: 0;
  padding-left: 1.2rem;
  font-size: 0.97rem;
  columns: 1;
}
.jump li { margin-bottom: 0.4em; }

@media (min-width: 780px) {
  .jump ol { columns: 2; column-gap: 2rem; }
}

/* --- definition-style fact tables ------------------------------------- */

.facts {
  width: 100%;
  max-width: 68ch;          /* match prose — a 2-row table shouldn't span 1100px */
  border-collapse: collapse;
  font-size: 0.97rem;
  margin: 0 0 1.4em;
}
.facts th, .facts td {
  text-align: left;
  vertical-align: top;
  padding: 0.6rem 0.75rem;
  border-bottom: 1px solid var(--teal-line);
}
.facts th {
  font-weight: 700;
  color: var(--teal);
  width: 34%;
  /* Must wrap on narrow screens — a nowrap header with multi-word content
     forces horizontal overflow at 375px. Only hold one line once there's room. */
  white-space: normal;
}

@media (min-width: 700px) {
  .facts th { white-space: nowrap; }
  .facts th:has(br) { white-space: normal; }
}
.facts caption {
  text-align: left;
  font-size: 0.88rem;
  color: var(--ink-mid);
  padding-bottom: 0.6rem;
}

/* Wide tables scroll inside their own container, never the page */
.table-scroll {
  overflow-x: auto;
  margin: 0 0 1.4em;
  -webkit-overflow-scrolling: touch;
}
.table-scroll .facts { margin-bottom: 0; min-width: 30rem; }

/* --- inline placeholder block (rule 12) ------------------------------- */

.needed {
  border: 2px dashed var(--teal-line);
  background: var(--off);
  color: var(--ink-mid);
  padding: 1.25rem;
  border-radius: 3px;
  font-size: 0.9rem;
  line-height: 1.5;
  margin: 0 0 1.4em;
}
.needed strong { display: block; color: var(--teal); font-size: 0.98rem; margin-bottom: 0.3rem; }
.needed p { margin: 0; }

/* --- funnel pages: no nav, single column ------------------------------ */

.funnel-top {
  background: var(--teal);
  color: var(--white);
  padding: 1rem 0;
}
.funnel-top .brand { margin-right: 0; }

.credibility {
  font-size: 0.92rem;
  color: var(--ink-mid);
  border-top: 1px solid var(--teal-line);
  padding-top: 1.1rem;
  margin-top: 2rem;
}

/* --- forms ------------------------------------------------------------ */

.field { margin-bottom: 1.1rem; }
.field label {
  display: block;
  font-weight: 700;
  font-size: 0.95rem;
  color: var(--teal);
  margin-bottom: 0.3rem;
}
.field .hint {
  display: block;
  font-weight: 400;
  font-size: 0.86rem;
  color: var(--ink-mid);
  margin-top: 0.15rem;
}
.field input,
.field select,
.field textarea {
  width: 100%;
  font: inherit;
  font-size: 1rem;
  color: var(--ink);
  background: var(--white);
  border: 1px solid #9fb3b6;
  border-radius: 3px;
  padding: 0.6rem 0.7rem;
}
.field input:focus,
.field select:focus,
.field textarea:focus {
  outline: 3px solid var(--accent);
  outline-offset: 1px;
  border-color: var(--teal);
}
fieldset {
  border: 1px solid var(--teal-line);
  border-radius: 3px;
  padding: 1rem 1.1rem 0.4rem;
  margin: 0 0 1.4rem;
}
legend {
  font-weight: 700;
  color: var(--teal);
  padding: 0 0.4rem;
  font-size: 0.95rem;
}
.req { color: #a1341f; font-weight: 700; }

@media (min-width: 640px) {
  .field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 0 1.25rem; }
}

/* ==========================================================================
   SAVINGS MODELLER — /modeller/
   The calculator is open: no gate on the inputs (CLAUDE.md rule 15).
   ========================================================================== */

.mod-fieldset {
  border: 1px solid var(--teal-line);
  border-radius: 3px;
  padding: 1.25rem 1.25rem 1.4rem;
  margin: 0 0 1.5rem;
  background: var(--white);
}
.mod-fieldset legend {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0 0.5rem;
  font-size: 1.1rem;
  font-weight: 700;
  color: var(--teal);
}
.mod-step {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.7rem;
  height: 1.7rem;
  border-radius: 50%;
  background: var(--teal);
  color: var(--white);
  font-size: 0.9rem;
}

.mod-grid { display: grid; gap: 1.1rem; }
@media (min-width: 620px) {
  .mod-grid { grid-template-columns: repeat(2, 1fr); }
  .mod-grid--mix { grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); }
}

.mod-field { margin-bottom: 1.1rem; }
.mod-field:last-child { margin-bottom: 0; }
.mod-grid .mod-field { margin-bottom: 0; }

.mod-field label,
.mod-label {
  display: block;
  font-weight: 700;
  font-size: 0.97rem;
  color: var(--teal);
  margin-bottom: 0.35rem;
}

.mod-field input[type="number"],
.mod-field input[type="email"],
.mod-field select,
.gate__row input {
  width: 100%;
  font: inherit;
  font-size: 1.05rem;
  padding: 0.6rem 0.7rem;
  border: 2px solid var(--teal-line);
  border-radius: 3px;
  background: var(--white);
  color: var(--ink);
}
.mod-field input:focus-visible,
.mod-field select:focus-visible,
.gate__row input:focus-visible {
  outline: 3px solid var(--teal);
  outline-offset: 1px;
  border-color: var(--teal);
}

.mod-hint { font-size: 0.86rem; color: var(--ink-mid); margin: 0.35rem 0 0; }

.mod-radios { display: flex; flex-wrap: wrap; gap: 0.5rem 1.25rem; }
.mod-radios--stack { flex-direction: column; gap: 0.6rem; }
.mod-radios label {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  font-weight: 400;
  color: var(--ink);
  margin: 0;
  font-size: 0.99rem;
}
.mod-radios input { width: 1.1rem; height: 1.1rem; accent-color: var(--teal); }

.mod-warning {
  margin: 0.9rem 0 0;
  padding: 0.7rem 0.85rem;
  background: var(--warn-wash);
  border-left: 4px solid var(--warn-line);
  border-radius: 3px;
  font-size: 0.92rem;
}

/* the stop panel for generator / hybrid */
.callout--stop { border-left-color: var(--warn-line); background: var(--warn-wash); }

/* "narrow this down" — progressive disclosure */
.narrow-toggle {
  display: block;
  width: 100%;
  text-align: left;
  font: inherit;
  cursor: pointer;
  background: var(--teal-wash);
  border: 2px dashed var(--teal-line);
  border-radius: 3px;
  padding: 1rem 1.15rem;
  margin: 0 0 1.5rem;
  color: var(--teal);
}
.narrow-toggle:hover { border-color: var(--teal); }
.narrow-toggle:focus-visible { outline: 3px solid var(--teal); outline-offset: 2px; }
.narrow-toggle__label { display: block; font-weight: 700; font-size: 1.05rem; }
.narrow-toggle__sub { display: block; font-size: 0.9rem; color: var(--ink-mid); margin-top: 0.2rem; }

/* the shrinking error bar — the mechanic, so it gets a status line */
.band-status {
  margin: 0 0 1.75rem;
  padding: 0.8rem 1rem;
  border-left: 4px solid var(--teal-line);
  background: var(--white);
  font-size: 0.95rem;
  border-radius: 3px;
}
.band-status--narrow { border-left-color: var(--teal); }

/* lead with waste, not savings */
.result-hero { margin: 0 0 2.25rem; }
.result-hero h2 { font-size: clamp(1.1rem, 2.6vw, 1.3rem); margin-bottom: 0.3em; }
.result-hero__figure {
  margin: 0 0 0.3rem;
  font-size: clamp(2.2rem, 8vw, 3.8rem);
  font-weight: 700;
  line-height: 1.02;
  letter-spacing: -0.04em;
  color: var(--teal);
}
.result-hero__sub { margin: 0; color: var(--ink-mid); max-width: 60ch; }

.rate-tag { font-size: 0.86rem; color: var(--ink-mid); white-space: nowrap; }

/* net position — the most important block on the page */
.net-block {
  border: 1px solid var(--teal-line);
  border-left: 5px solid var(--teal);
  border-radius: 3px;
  padding: 1.2rem 1.25rem;
  background: var(--white);
  margin-bottom: 1.5rem;
}
.net-block > :last-child { margin-bottom: 0; }
.net-block--unguaranteed { border-left-color: var(--warn-line); background: var(--warn-wash); }
.net-line { font-size: clamp(1.15rem, 3vw, 1.45rem); margin-bottom: 0.6rem; }
.net-line strong { color: var(--teal); }
.guarantee-value {
  font-size: 1.05rem;
  padding-top: 0.7rem;
  border-top: 1px solid var(--teal-line);
}
.guarantee-value strong { color: var(--teal); }

/* the twelve-month curve */
.curve { margin: 1.25rem 0; }
.curve svg { width: 100%; height: auto; display: block; }
.curve-details { margin: 0 0 1.75rem; }
.curve-details summary {
  cursor: pointer;
  font-weight: 700;
  color: var(--teal);
  padding: 0.5rem 0;
}
.curve-details summary:focus-visible { outline: 3px solid var(--teal); outline-offset: 2px; }

/* the one gate — after the value, never before it */
.gate {
  margin: 2.5rem 0 0;
  padding: 1.4rem 1.35rem;
  background: var(--teal-wash);
  border: 1px solid var(--teal-line);
  border-radius: 3px;
}
.gate h3 { margin-bottom: 0.4em; }
.gate__form label { display: block; font-weight: 700; font-size: 0.95rem; color: var(--teal); margin-bottom: 0.35rem; }
.gate__row { display: flex; flex-wrap: wrap; gap: 0.7rem; }
.gate__row input { flex: 1 1 16rem; }
.gate__row .btn { flex: 0 0 auto; }


/* ==========================================================================
   HOW IT WORKS — SCENARIO ANIMATIONS  (.gs / .gs-*)
   Originally lifted from gaia-scenarios-fixed.html, ARCHIVED OUT OF THIS REPO
   28 July 2026 to "GAIA OS/archive/website-reference-2026-07/" - retired, not
   provenance; do not re-lift from it. Fully scoped: every rule
   is under .gs, so nothing here can reach the rest of the estate.

   ✅ TWO CARVE-OUTS, BOTH GRANTED (26 July 2026). Recorded in CLAUDE.md —
   the colour one under Visual system, the webfont one under Tech
   constraints. Do not "fix" either one back to brand defaults.

   1. WEBFONT — GRANTED, SCOPED. Archivo 400/500/600/800 is permitted on a
      LISTED SET OF PAGES only; CLAUDE.md holds the list. The import has been
      STRIPPED from this shared stylesheet and must stay out — left here it
      pulls the webfont onto all 20 pages, which is a different decision and
      one that has not been taken. Each permitted page carries its own <link>.
      Everything else falls back to the estate stack.

   2. COLOUR — GRANTED UNCONDITIONALLY. #F5972B amber, #5FD5E8 cyan, #8E1C55
      magenta, #9A7BFF violet on #08070C. None are brand colours, and #0FB5A6
      is otherwise reserved for CTAs estate-wide. This is a documented
      exception because the colours are a LEGEND, not decoration — each
      carries a fixed meaning the reader holds across three scenarios:
        amber   drawing power / energy being spent
        cyan    AutoMate has acted (shed, setback, paused)
        magenta the counterfactual — what would have happened
        violet  protected, never switched — LIFE SAFETY ONLY
        grey    off / not running
      🔒 Violet is used for nothing else anywhere. That exclusivity is the
      whole point of it — it is how a reader knows life-safety is untouchable.

   font-variant-numeric: tabular-nums appears throughout and is LOAD-BEARING.
   It is what stops the counting readouts jittering mid-animation. If the
   webfont is ever withdrawn, these declarations must survive the fallback or the
   numbers twitch every frame and the page reads as broken.
   ========================================================================== */

.gs{--void:#08070C;--panel:#100E18;--edge:rgba(140,135,151,.2);--ash:#8C8797;--bone:#EFECF2;
--burn:#F5972B;--act:#5FD5E8;--ghost:#8E1C55;--prot:#9A7BFF;--idle:#5A566E;
background:var(--void);color:var(--bone);font-family:'Archivo',system-ui,sans-serif}
.gs *{box-sizing:border-box;margin:0}
.gs-sec{padding:clamp(30px,5vw,68px) clamp(20px,4vw,60px);border-top:1px solid var(--edge)}
.gs-sec:first-of-type{border-top:0}
.gs-tag{font:600 12px/1 'Archivo','Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif;letter-spacing:.02em;color:var(--burn)}
.gs-h{margin-top:14px;font-weight:800;font-size:clamp(28px,5vw,58px);line-height:.94;letter-spacing:-.035em;text-transform:uppercase;max-width:18ch}
.gs-h span{color:var(--burn)}
.gs-lede{margin-top:18px;font-size:15px;line-height:1.62;color:var(--ash);max-width:54ch}

.gs-read{margin-top:clamp(24px,3.2vw,36px);display:flex;flex-wrap:wrap;gap:clamp(18px,3.2vw,40px)}
.gs-read p{font-family:'Archivo','Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif}
.gs-read b{display:block;font-weight:600;font-size:clamp(24px,3.4vw,40px);line-height:1;letter-spacing:-.045em;font-variant-numeric:tabular-nums;font-feature-settings:'tnum' 1}
.gs-read small{display:block;margin-top:10px;font:400 12.5px/1.5 'Archivo','Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif;letter-spacing:.005em;color:var(--ash)}
.gs .r-g b{color:var(--ghost)}.gs .r-a b{color:var(--act)}.gs .r-b b{color:var(--burn)}
.gs .r-p b{color:var(--prot)}.gs .r-n b{color:var(--bone);font-size:clamp(17px,2.2vw,23px)}

.gs-panel{margin-top:clamp(20px,2.6vw,28px);border:1px solid var(--edge);background:var(--panel);padding:clamp(14px,2vw,20px) clamp(10px,1.6vw,16px) clamp(6px,1vw,10px)}
.gs-panel svg{width:100%;height:auto;display:block}
.gs-key{display:flex;flex-wrap:wrap;gap:18px;margin-top:14px;padding:0 6px;font:400 12.5px/1 'Archivo','Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif;letter-spacing:.005em;color:var(--ash)}
.gs-key span{display:flex;align-items:center;gap:7px}
.gs-key i{width:16px;height:0;border-top:2px solid;font-style:normal}
.gs-key i.d{border-top-style:dashed}
.gs-key i.sq{width:11px;height:11px;border:none;border-radius:2px}

.gs-step{margin-top:18px;border-left:2px solid var(--edge);padding:6px 0 6px 18px;min-height:64px;
font-size:14.5px;line-height:1.6;color:var(--ash);max-width:62ch;transition:border-color .7s}
.gs-step b{color:var(--bone);font-weight:500}
.gs-step.w{border-color:var(--ghost)}.gs-step.a{border-color:var(--act)}.gs-step.p{border-color:var(--prot)}

.gs-cells{margin-top:20px;display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px}
.gs-cell{border:1px solid var(--edge);background:var(--panel);padding:14px 14px 12px;transition:border-color .8s,background .8s}
.gs-cell.burn{border-color:rgba(245,151,43,.55);background:rgba(245,151,43,.05)}
.gs-cell.act{border-color:rgba(95,213,232,.5);background:rgba(95,213,232,.05)}
.gs-cell.prot{border-color:rgba(154,123,255,.5);background:rgba(154,123,255,.05)}
.gs-cn{font:600 13px/1.4 'Archivo','Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif;letter-spacing:-.005em;color:var(--bone)}
.gs-cn em{font-style:normal;display:block;margin-top:6px;letter-spacing:.09em;color:var(--ash);font-weight:400;text-transform:none;font-size:10.5px}
.gs-apps{margin-top:14px;display:flex;gap:9px;flex-wrap:wrap;align-items:center;min-height:46px}
.gs-ic{width:44px;height:44px;flex:0 0 auto;color:var(--idle);transition:color .8s,transform .8s}
.gs-ic.burn{color:var(--burn);transform:scale(1.09)}
.gs-ic.act{color:var(--act);transform:scale(.94)}
.gs-ic.prot{color:var(--prot)}
.gs-cv{margin-top:13px;font:600 12px/1 'Archivo','Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif;letter-spacing:.02em;font-variant-numeric:tabular-nums;color:var(--idle);transition:color .8s}
.gs-cv.burn{color:var(--burn)}.gs-cv.act{color:var(--act)}.gs-cv.prot{color:var(--prot)}

.gs-beat{margin-top:20px;display:flex;flex-wrap:wrap;gap:26px;align-items:baseline;font:400 12.5px/1.55 'Archivo','Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif;letter-spacing:.01em;color:var(--ash)}
.gs-beat b{color:var(--bone);font-weight:600;font-variant-numeric:tabular-nums}

.gs-log{margin-top:22px}
.gs-le{display:grid;grid-template-columns:52px minmax(0,1fr);gap:14px;padding:9px 0;border-bottom:1px solid rgba(140,135,151,.11);
font:400 13px/1.55 'Archivo','Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif;letter-spacing:.005em;opacity:0;transform:translateY(4px);transition:opacity .7s,transform .7s}
.gs-le.on{opacity:1;transform:none}
.gs-le u{text-decoration:none;color:var(--ash);font-weight:600;font-variant-numeric:tabular-nums;letter-spacing:.04em}
.gs-le s{text-decoration:none;color:var(--bone)}
.gs-le.w s{color:var(--ghost)}.gs-le.a s{color:var(--act)}.gs-le.p s{color:var(--prot)}

.gs-truth{margin-top:24px;border-left:2px solid var(--burn);padding:2px 0 2px 18px;font-size:13.5px;line-height:1.65;color:var(--ash);max-width:58ch}
.gs-truth b{color:var(--bone);font-weight:500}
.gs-btn{margin-top:26px;background:none;border:1px solid var(--edge);color:var(--ash);padding:12px 22px;
font:600 12px/1 'Archivo','Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif;letter-spacing:.02em;cursor:pointer;transition:all .25s}
.gs-btn:hover,.gs-btn:focus-visible{border-color:var(--burn);color:var(--burn)}
.gs-btn:disabled{opacity:.3;cursor:default}
.gs-btn:focus-visible{outline:2px solid var(--burn);outline-offset:3px}
@media (max-width:700px){.gs-cells{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (prefers-reduced-motion:reduce){.gs-le,.gs-ic,.gs-cv,.gs-cell,.gs-step{transition:none}}

/* --- scenario 3 run-comparison strip (v3) ------------------------------
   The magenta bar is a repeating-linear-gradient HATCH, not a solid fill.
   That is deliberate: it marks the timer run as the counterfactual — the
   same job the dashed stroke does on the scenario 1 and 2 curves. Do not
   flatten it to a solid colour; the hatch is what says "this did not
   actually happen".
   Scoped under .gs like everything else in this block.
   ---------------------------------------------------------------------- */
.gs-runs{margin-top:20px;border:1px solid var(--edge);background:var(--panel);padding:16px 18px 14px}
.gs-run{display:grid;grid-template-columns:150px minmax(0,1fr);gap:14px;align-items:center;margin-bottom:10px}
.gs-rl{font:400 12.5px/1.3 'Archivo','Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif;color:var(--ash)}
.gs-rt{position:relative;height:26px;background:rgba(140,135,151,.09);border-radius:3px}
.gs-rb{position:absolute;top:0;bottom:0;border-radius:3px;display:flex;align-items:center;padding:0 10px;white-space:nowrap;
font:500 11.5px/1 'Archivo','Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif;color:#08070C;overflow:hidden;transition:width 1.4s cubic-bezier(.4,0,.2,1)}
.gs-rb.ghost{background:repeating-linear-gradient(45deg,#8E1C55 0 5px,#6B1441 5px 10px);color:#F4D6E2}
.gs-rb.act{background:var(--act)}
.gs-rn{margin-top:12px;font:400 12.5px/1.5 'Archivo','Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif;color:var(--ash)}
@media (max-width:640px){.gs-run{grid-template-columns:1fr;gap:6px}}

/* --- scenario 1 capacity block (v4) -----------------------------------
   Peak shaving sells on CAPACITY, not energy. The peak sizes the generator
   hired or the connection paid for, across the whole job — so the old
   "barely changes the energy you use" framing put the strongest commercial
   argument in the product into a caveat. This two-column block replaces it.
   Scoped under .gs.
   ---------------------------------------------------------------------- */
.gs-cap{margin-top:22px;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:1px;background:var(--edge)}
.gs-capcol{background:var(--panel);padding:18px 20px 16px}
.gs-caph{font:600 14.5px/1.35 'Archivo','Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif;color:var(--burn);letter-spacing:-.01em}
.gs-capb{margin-top:11px;font:400 13.5px/1.62 'Archivo','Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif;color:var(--ash)}
.gs-capb b{color:var(--bone);font-weight:600}
.gs-capn{margin-top:12px;padding-top:11px;border-top:1px solid var(--edge);font:400 12.5px/1.55 'Archivo','Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif;color:var(--idle)}
@media (max-width:700px){.gs-cap{grid-template-columns:1fr}}

/* ==========================================================================
   PORTAL RENDERS  (.pv / .pv-*)  —  /datamate/ and /automate/
   A crisp HTML/CSS render of the Gaia portal, embedded like a product page.

   🔒 SCOPING IS LOAD-BEARING. Every rule is under .pv, and the product's own
   UI colours are declared as custom properties on .pv-light / .pv-dark ONLY.
   They cannot reach the estate.

   ✅ GREEN #16A34A AND RED #EF4444 ARE PERMITTED HERE, AND ONLY HERE.
   They are the PRODUCT's interface colours, not our marketing palette — a
   render of the app is no more bound by the CTA-colour rule than a screenshot
   would be. Do not "correct" them to brand teal, and do not use them anywhere
   outside a .pv component.

   🔒 THE ONLY TEALS ARE #004650 (brand) AND #0FB5A6 (approved accent).
   The wordmark is #004650 in the light render and #0FB5A6 in the dark one,
   because #004650 is invisible on near-black. No third teal. The reference
   replica's #2DD4BF and #0E4C59 are both wrong and must not come back.

   Icons are INLINE SVG at point of use — no icon font, no CDN, no <use>.
   An icon font renders empty boxes when a corporate network blocks the CDN,
   which is precisely where a bid manager will open this.
   ========================================================================== */

.pv {
  --pv-radius: 14px;
  margin: 0 0 1.5rem;
  border-radius: var(--pv-radius);
  overflow: hidden;
  border: 1px solid var(--pv-edge);
  background: var(--pv-app);
  box-shadow: 0 18px 44px rgba(20, 40, 45, 0.14);
  font-size: 15px;
  line-height: 1.4;
}

/* --- the two moods ----------------------------------------------------- */
.pv-light {
  --pv-chrome: #eef1ef;  --pv-edge: #e2e6e4;  --pv-app: #f7f8f7;
  --pv-panel: #ffffff;   --pv-ink: #1a2b2e;   --pv-dim: #5a6b6e;
  --pv-faint: #8a9896;   --pv-accent: #16a34a; --pv-accent-wash: #e7f5ec;
  --pv-mark: #004650;
}
.pv-dark {
  --pv-chrome: #141516;  --pv-edge: #26282a;  --pv-app: #0e0f10;
  --pv-panel: #141516;   --pv-ink: #f5f5f5;   --pv-dim: #9ba0a0;
  --pv-faint: #7c8181;   --pv-accent: #ef4444; --pv-accent-wash: #1e1416;
  --pv-mark: #0fb5a6;
}

/* --- browser chrome ----------------------------------------------------- */
.pv-bar {
  display: flex; align-items: center; gap: 7px;
  padding: 10px 13px;
  background: var(--pv-chrome);
  border-bottom: 1px solid var(--pv-edge);
}
.pv-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--pv-edge); flex: none; }
.pv-dark .pv-dot { background: #2e3133; }
.pv-url { margin-left: 10px; font-size: 12px; color: var(--pv-faint); }

/* --- app body ----------------------------------------------------------- */
.pv-body { display: flex; min-height: 430px; }

.pv-side {
  width: 168px; flex: none;
  background: var(--pv-panel);
  border-right: 1px solid var(--pv-edge);
  padding: 15px 10px;
  display: flex; flex-direction: column; gap: 3px;
}
.pv-brand {
  display: flex; align-items: center; gap: 6px;
  padding: 2px 6px 13px;
  font-size: 18px; font-weight: 600; letter-spacing: -0.3px;
  color: var(--pv-mark);
}
.pv-nav {
  display: flex; align-items: center; gap: 9px;
  padding: 7px 9px; border-radius: 9px;
  font-size: 13px; color: var(--pv-dim);
}
.pv-nav--on {
  background: var(--pv-accent-wash);
  color: var(--pv-accent);
  font-weight: 500;
}
.pv-rule { border-top: 1px solid var(--pv-edge); margin: 11px 4px 8px; }
.pv-eyebrow { font-size: 11px; color: var(--pv-faint); padding: 0 6px 4px; letter-spacing: .3px; }
.pv-recent { font-size: 12px; color: var(--pv-dim); padding: 4px 6px; line-height: 1.3; }

.pv-main { flex: 1; padding: 26px 30px; display: flex; flex-direction: column; align-items: center; }
.pv-avatar {
  width: 46px; height: 46px; border-radius: 50%;
  background: var(--pv-accent-wash); color: var(--pv-accent);
  display: flex; align-items: center; justify-content: center; margin-bottom: 12px;
}
.pv-hi { font-size: 23px; font-weight: 600; color: var(--pv-ink); text-align: center; }
.pv-hi b { color: var(--pv-accent); font-weight: 600; }
.pv-sub {
  font-size: 13px; color: var(--pv-dim); text-align: center;
  max-width: 42ch; margin: 8px 0 18px; line-height: 1.55;
}

.pv-stats { display: flex; gap: 12px; width: 100%; max-width: 460px; margin-bottom: 15px; }
.pv-stat {
  flex: 1; background: var(--pv-panel); border: 1px solid var(--pv-edge);
  border-radius: 12px; padding: 12px 14px;
  display: flex; align-items: center; gap: 10px; color: var(--pv-accent);
}
.pv-stat div { color: var(--pv-ink); }
.pv-stat strong { display: block; font-size: 13px; font-weight: 500; }
.pv-stat strong em { font-style: normal; color: var(--pv-accent); }
.pv-stat small { display: block; font-size: 11.5px; color: var(--pv-faint); }

.pv-ask {
  width: 100%; max-width: 460px; background: var(--pv-panel);
  border: 1px solid var(--pv-edge); border-radius: 12px;
  padding: 13px 14px; display: flex; flex-direction: column; gap: 16px;
  margin-bottom: 15px;
}
.pv-dark .pv-ask { border-color: #7a2a2a; }
.pv-light .pv-ask { border-color: #cbd8d4; }
.pv-ask__ph { font-size: 13.5px; color: var(--pv-faint); }
.pv-ask__row { display: flex; align-items: center; justify-content: space-between; color: var(--pv-faint); }
.pv-send {
  width: 32px; height: 32px; border-radius: 9px;
  background: var(--pv-accent); color: #fff;
  display: flex; align-items: center; justify-content: center;
}

.pv-prompts {
  display: grid; grid-template-columns: 1fr 1fr; gap: 10px;
  width: 100%; max-width: 460px;
}
.pv-prompt {
  background: var(--pv-panel); border: 1px solid var(--pv-edge);
  border-radius: 12px; padding: 11px 12px; color: var(--pv-accent);
}
.pv-prompt span {
  display: block; margin-top: 7px; font-size: 12px;
  color: var(--pv-dim); line-height: 1.35;
}
.pv-foot {
  display: flex; align-items: center; gap: 8px; margin-top: 16px;
  font-size: 11.5px; color: var(--pv-faint);
}
.pv-foot .pv-i { color: var(--pv-accent); }

/* --- caption: every figure inside a render is illustrative -------------- */
.pv-cap {
  margin: 0 0 1.75rem; font-size: 0.86rem; line-height: 1.5; color: var(--ink-mid);
}

/* --- feature showcase --------------------------------------------------- */
.pf { display: grid; gap: 1.15rem; margin: 1.75rem 0 0; }
@media (min-width: 640px) { .pf { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) { .pf { grid-template-columns: repeat(3, 1fr); } }

.pf-item {
  border: 1px solid var(--teal-line); border-radius: 3px;
  padding: 1.1rem 1.15rem; background: var(--white);
}
.pf-item h3 { font-size: 1.02rem; margin-bottom: 0.35em; display: flex; align-items: center; gap: 0.55rem; }
.pf-item h3 .pv-i { color: var(--teal); flex: none; }
.pf-item p { font-size: 0.93rem; color: var(--ink-mid); margin: 0; }

/* Locked feature — the upgrade teaser on /datamate/. 26 July 2026: was dark with a red
   icon, borrowing DataMate's portal mood (00 §2) for a feature DataMate does not have —
   backwards, and the loudest thing on a page trying to give DataMate away free. Same card
   shape and background as its eleven siblings now; only the icon is muted and the tag
   reads as "available on the paid tier", not "different product". */
.pf-item--locked h3 .pv-i { color: var(--ink-mid); }
.pf-item--locked p { color: var(--ink-mid); }
.pf-item--locked .pf-tag {
  display: inline-flex; align-items: center; gap: 0.3em; margin-top: 0.7rem;
  padding: 0.15rem 0.6rem; border: 1px solid var(--teal-line); border-radius: 99px;
  font-size: 0.72rem; font-weight: 600; letter-spacing: 0.02em; color: var(--teal);
  text-decoration: none;
}
.pf-item--locked .pf-tag:hover { background: var(--teal-wash); }

@media (max-width: 720px) {
  .pv-body { flex-direction: column; }
  .pv-side { width: 100%; border-right: 0; border-bottom: 1px solid var(--pv-edge); }
  .pv-side .pv-rule, .pv-side .pv-eyebrow, .pv-side .pv-recent { display: none; }
  .pv-side { flex-direction: row; flex-wrap: wrap; align-items: center; gap: 6px; }
  .pv-brand { padding: 0 6px 0 0; }
  .pv-main { padding: 22px 16px; }
  .pv-prompts { grid-template-columns: 1fr; }
}

/* --- scenario 3 & 4 shared: lead-in line and the award footnote ---------
   .gs-award is deliberately small and grey and sits AFTER the argument.
   A quiet line of fact reads as credible; a badge reads as marketing, and
   this page has to read as engineering. No trophy, no gold, no badge.
   ---------------------------------------------------------------------- */
.gs-lead{margin-top:22px;font:400 clamp(16px,2vw,19px)/1.55 'Archivo','Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif;color:var(--bone);max-width:54ch}
.gs-lead b{font-weight:600;color:var(--burn)}
.gs-award{display:block;margin-top:13px;padding-top:12px;border-top:1px solid var(--edge);font-size:12.5px;line-height:1.5;color:var(--idle)}

/* ==========================================================================
   SCREEN-READER-ONLY
   🔒 NOT display:none and NOT visibility:hidden — both remove the content from
   the accessibility tree, which defeats the entire purpose. This is the clip
   pattern: off-canvas but still announced, still in the DOM, still crawlable.
   ========================================================================== */
.sr-only {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* --- portal render at full width ----------------------------------------
   The render now leads /datamate/ and /automate/ full-width rather than
   sitting in a half-width column. The base sizes were drawn for a ~520px
   frame: a 168px sidebar and a 460px content cap look stranded once the
   frame is ~1060px, so the internal proportions scale with it.
   Ratios follow the source replica — sidebar ~22% of the frame, centre
   content ~72% of the remaining panel.
   ---------------------------------------------------------------------- */
@media (min-width: 900px) {
  .pv-side { width: 214px; padding: 20px 14px; gap: 4px; }
  .pv-brand { font-size: 20px; padding-bottom: 16px; }
  .pv-nav { font-size: 13.5px; padding: 9px 11px; }
  .pv-recent { font-size: 12.5px; }
  .pv-main { padding: 38px 44px; }
  .pv-body { min-height: 520px; }
  .pv-hi { font-size: 27px; }
  .pv-sub { font-size: 14px; max-width: 52ch; margin-bottom: 22px; }
  .pv-stats, .pv-ask, .pv-prompts { max-width: 620px; }
  .pv-stat { padding: 14px 17px; }
  .pv-prompt { padding: 13px 15px; }
  .pv-prompt span { font-size: 12.5px; }
  .pv-avatar { width: 52px; height: 52px; }
}

/* --- sticky sub-nav on the two long product pages ------------------------
   /datamate/ and /automate/ run to ~5,500px. The density is deliberate
   (00 §9a: library pages are dense and evidence-led) but dense and buried
   are not the same thing — this makes the page navigable without cutting
   anything. Sits under the masthead, which is not itself sticky.
   ---------------------------------------------------------------------- */
.subnav {
  background: var(--teal-wash);
  border-bottom: 1px solid var(--teal-line);
  position: sticky; top: 0; z-index: 15;
}
.subnav ul {
  display: flex; flex-wrap: nowrap; gap: 0.3rem 1.4rem;
  margin: 0 auto; padding: 0.7rem 1.15rem;
  max-width: var(--wrap); list-style: none;
  overflow-x: auto; -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.subnav ul::-webkit-scrollbar { display: none; }
.subnav li { margin: 0; flex: none; }
.subnav a {
  text-decoration: none;
  font-size: 0.9rem; font-weight: 500;
  color: var(--teal);
  white-space: nowrap;
  border-bottom: 2px solid transparent;
  padding-bottom: 2px;
}
.subnav a:hover, .subnav a:focus-visible { border-bottom-color: var(--accent); }

/* anchored sections must clear the sticky rail. Back to 4rem/64px for .subnav
   alone, 28 July 2026: this was bumped to 100px when .gp-chev stacked above
   .subnav, and .gp-chev is no longer sticky, so .subnav (51px) is the only
   sticky thing on these two pages again. #settling and #after stay in the list
   - they are datamate's own subnav targets, were missing before and that fix is
   unrelated to the chevron. */
#portal, #measured, #fortnight, #review, #get, #price, #board, #rules,
#settling, #after {
  scroll-margin-top: 4rem;
}

/* --- the scenario picker, the chat visual and the compact panel overrides ---
   Originally lifted from gaia-scenarios-fixed.html, ARCHIVED OUT OF THIS REPO
   28 July 2026 to "GAIA OS/archive/website-reference-2026-07/" - retired, not
   provenance; do not re-lift from it. Thirteen animated scenarios
   on one scroll is unusable, and thirteen IntersectionObservers means thirteen
   animations competing for attention. So: one tablist, one stage, twelve panels
   hidden, ONE animation running. The four themed picker columns are doing sales
   work, not tidying.

   🔒 The ".gs-panelsec" override block is LOAD-BEARING, not cosmetic. It shrinks
   the headline, caps the chart at 780px and compacts the cells and icons so that
   everything that ANIMATES - readouts, chart, step caption, cells - fits one
   viewport. Prose (.gs-lead, .gs-truth) sits below a top border by design, to be
   read after rather than during. Loosen these and the scenarios span three
   screens again, which is the bug they exist to fix.
   ------------------------------------------------------------------------- */
.gs-chat{margin-top:22px;border:1px solid var(--edge);background:var(--panel);padding:20px 22px}
.gs-msg{max-width:60ch;padding:13px 16px;border-radius:12px;font:400 14px/1.6 'Archivo','Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif;opacity:0;transform:translateY(6px);transition:opacity .6s,transform .6s}
.gs-msg.on{opacity:1;transform:none}
.gs-msg.you{margin-left:auto;background:rgba(140,135,151,.13);color:var(--bone);border-bottom-right-radius:4px}
.gs-msg.sys{background:rgba(95,213,232,.08);border:1px solid rgba(95,213,232,.22);color:var(--ash);border-bottom-left-radius:4px;margin-top:12px}
.gs-msg.sys b{color:var(--bone);font-weight:600}
.gs-msg.you+.gs-msg.you{margin-top:12px}
.gs-evi{margin-top:11px;padding-top:10px;border-top:1px solid rgba(95,213,232,.2);font:400 12.5px/1.55 'Archivo','Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif;color:var(--idle)}
.gs-gate{margin-top:16px;border-left:2px solid var(--prot);padding:3px 0 3px 16px;font:400 13px/1.6 'Archivo','Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif;color:var(--ash);opacity:0;transition:opacity .6s}
.gs-gate.on{opacity:1}
.gs-gate b{color:var(--prot);font-weight:600}
.gs-pickwrap{padding:0 clamp(20px,4vw,60px) clamp(20px,3vw,34px)}
/* 🔒 D072, 27 July 2026 — heading + instruction so the picker reads as a
   labelled control, not a footer. Two short lines only: the mobile budget
   below (max-width:560px) trims them further so the animated region is
   never pushed far down the page on a phone. */
.gs-pick-h{font:700 16px/1.3 'Archivo','Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif;color:var(--bone);letter-spacing:-.01em}
.gs-pick-i{margin-top:5px;margin-bottom:clamp(16px,2.4vw,22px);font:400 13px/1.5 'Archivo','Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif;color:var(--ash);max-width:52ch}
.gs-pick{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:clamp(14px,2vw,26px);border-top:1px solid var(--edge);padding-top:clamp(20px,3vw,30px);
counter-reset:scenario}
.gs-pgroup{display:flex;flex-direction:column;gap:5px}
.gs-ph{font:600 11.5px/1.35 'Archivo','Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif;color:var(--burn);margin-bottom:5px}
/* The counter is reset once on .gs-pick and incremented on every .gs-pb, so
   it runs 01-13 continuously THROUGH the four .gs-pgroup wrappers in DOM
   order without ever needing to be numbered by hand or re-synced if a
   scenario is added, removed or reordered. */
.gs-pb{display:flex;align-items:center;gap:10px;width:100%;text-align:left;background:none;border:0;border-left:3px solid var(--edge);
padding:9px 24px 9px 11px;position:relative;color:var(--ash);cursor:pointer;transition:color .2s,border-color .2s,background .2s;
font:400 13.5px/1.4 'Archivo','Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif}
.gs-pb::before{counter-increment:scenario;content:counter(scenario,decimal-leading-zero);flex:0 0 auto;
display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:3px;
background:rgba(140,135,151,.16);color:var(--ash);font:600 10.5px/1 'Archivo','Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif;
font-variant-numeric:tabular-nums;transition:background .2s,color .2s}
/* Resting chevron: the affordance requirement — every item reads as a
   control before the first hover, without becoming a filled button. */
.gs-pb::after{content:'\203A';position:absolute;right:9px;top:50%;transform:translateY(-50%);
color:var(--edge);font-size:16px;line-height:1;transition:color .2s,transform .2s}
.gs-pb:hover{color:var(--bone);border-left-color:var(--ash);background:rgba(140,135,151,.06)}
.gs-pb:hover::after{color:var(--ash);transform:translateY(-50%) translateX(2px)}
/* Selected state — a step change, not a nudge (D072): the number chip
   FILLS solid burn, the chevron is REPLACED by a filled "playing" triangle,
   the row tint and left bar both strengthen well past hover. Four signals
   together so it registers at a glance, not just on close reading. */
.gs-pb[aria-selected="true"]{color:var(--bone);border-left-color:var(--burn);background:rgba(245,151,43,.16);font-weight:700}
.gs-pb[aria-selected="true"]::before{background:var(--burn);color:var(--void)}
.gs-pb[aria-selected="true"]::after{content:'\25B6';color:var(--burn);font-size:11px;transform:translateY(-50%)}
.gs-pb:focus-visible{outline:2px solid var(--burn);outline-offset:2px}
.gs-stage{min-height:70vh}
.gs-panelsec{border-top:0;padding-top:clamp(10px,1.5vw,18px)}
.gs-panelsec[hidden]{display:none}
/* --- scenario panels: everything that ANIMATES must fit one viewport --- */
/* 12px, not 58px: the 58 cleared the sticky .gp-chev bar, and /how-it-works/ no
   longer carries that bar at all - it carries the full .gp map only. 28 Jul 2026 */
.gs-panelsec{scroll-margin-top:12px;padding-top:clamp(12px,1.6vw,20px)}
.gs-panelsec .gs-h{font-size:clamp(20px,2.5vw,31px);line-height:.99;margin-top:11px;max-width:24ch}
.gs-panelsec .gs-lede{margin-top:12px;font-size:14px;line-height:1.5;max-width:64ch}
.gs-panelsec .gs-read{margin-top:16px;gap:clamp(16px,2.4vw,32px)}
.gs-panelsec .gs-read b{font-size:clamp(19px,2.3vw,27px)}
.gs-panelsec .gs-read small{margin-top:6px;font-size:11px;line-height:1.4}
.gs-panelsec .gs-panel{margin-top:14px;max-width:780px;padding:clamp(10px,1.4vw,14px) clamp(8px,1.2vw,12px) 4px}
.gs-panelsec .gs-key{margin-top:9px;gap:14px;font-size:10.5px}
.gs-panelsec .gs-step{margin-top:13px;min-height:54px;font-size:13.5px;line-height:1.5;max-width:74ch}
.gs-panelsec .gs-cells{margin-top:13px;gap:8px}
.gs-panelsec .gs-cell{padding:10px 11px 9px}
.gs-panelsec .gs-cn{font-size:11.5px}
.gs-panelsec .gs-cn em{margin-top:3px;font-size:10px}
.gs-panelsec .gs-apps{margin-top:9px;min-height:34px;gap:7px}
.gs-panelsec .gs-ic{width:32px;height:32px}
.gs-panelsec .gs-cv{margin-top:8px;font-size:11px}
.gs-panelsec .gs-runs{margin-top:10px;padding:8px 12px 6px}
.gs-panelsec .gs-run{margin-bottom:4px}
.gs-panelsec .gs-rt{height:22px}
/* s3 is the only panel carrying .gs-runs, and it was the one panel over the
   900px budget (985px) — the run-comparison strip is the argument in that
   scenario, so it stays visible; everything AROUND it was tightened instead. */
.gs-panelsec .gs-run{grid-template-columns:118px minmax(0,1fr);gap:10px}
.gs-panelsec .gs-rl{font-size:11px}
.gs-panelsec .gs-rb{font-size:10.5px;padding:0 8px}
.gs-panelsec .gs-rn{margin-top:7px;font-size:11px;line-height:1.4}
/* s3 alone still ran to 962px after compacting .gs-runs (ruling 26 July 2026) -
   the chart is the widest thing left driving its height. Narrowing just this
   panel's chart (aspect-ratio locked, so narrower = shorter) closes the rest of
   the gap without touching the other 12 panels or losing the run-comparison
   strip, which is the part of s3 that must stay visible. */
#s3 .gs-panel{max-width:600px}

.gs-panelsec .gs-chat{margin-top:14px;padding:14px 16px}
.gs-panelsec .gs-msg{font-size:13px;line-height:1.5;padding:10px 13px}
.gs-panelsec .gs-gate{margin-top:12px;font-size:12.5px}
/* prose sits BELOW the animated region by design — read after, not during */
.gs-panelsec .gs-lead{margin-top:20px;padding-top:18px;border-top:1px solid var(--edge);font-size:15px}
.gs-panelsec .gs-cap{margin-top:18px}
.gs-truth{margin-top:24px;border-left:2px solid var(--burn);padding:2px 0 2px 18px;font-size:13.5px;line-height:1.65;color:var(--ash);max-width:58ch}
.gs-truth b{color:var(--bone);font-weight:500}
.gs-btn{margin-top:26px;background:none;border:1px solid var(--edge);color:var(--ash);padding:12px 22px;
font:600 12px/1 'Archivo','Segoe UI','Helvetica Neue',Helvetica,Arial,sans-serif;letter-spacing:.02em;cursor:pointer;transition:all .25s}
.gs-btn:hover,.gs-btn:focus-visible{border-color:var(--burn);color:var(--burn)}
.gs-btn:disabled{opacity:.3;cursor:default}
.gs-btn:focus-visible{outline:2px solid var(--burn);outline-offset:3px}
@media (max-width:900px){.gs-pick{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:560px){.gs-pick{grid-template-columns:1fr}
.gs-pick-h{font-size:15px}.gs-pick-i{margin-bottom:14px}}
@media (max-width:700px){.gs-cells{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (prefers-reduced-motion:reduce){.gs-le,.gs-ic,.gs-cv,.gs-cell,.gs-step{transition:none}}

/* The per-panel illustrative marker. Deep linking means #scenario-11 can be
   somebody's entry point, so they never read s0's full caveat. Every panel
   therefore carries a short one it cannot be separated from.
   .gs-tag ships line-height:1 from the reference, which collides once these
   longer eyebrows wrap at 375px - overridden here rather than in the lifted
   block, so a re-lift does not silently undo it. */
.gs-tag{line-height:1.5}
.gs-illus{display:inline-block;margin-left:6px;padding:2px 7px;border:1px solid var(--ash);
  border-radius:99px;font-size:10.5px;font-weight:500;letter-spacing:.04em;
  text-transform:uppercase;color:var(--ash);white-space:nowrap}

/* --- "Other ways to start": the three-card wall (26 July 2026) --------------
   Replaces the equal-weight ladder. Three cards, not four - the demo portal is
   sales collateral and gets one page plus one mid-page text link, never a card.

   Hierarchy is explicit, not implied: card 1 spans two columns on desktop, is
   flagged "Recommended first step", and carries the solid CTA; cards 2 and 3 are
   half-width with ghost buttons. The cost line is set at body weight in the ink
   colour because it is what sorts the reader now - it is not a caption.
   Buttons are width:100% inside equal grid tracks, so label length cannot make
   the row look accidental.
   A 4th card inserted second just flows into the next track - only
   .wall__card--lead is sized up, so nothing else needs changing.
   ------------------------------------------------------------------------- */
.wall { list-style: none; margin: 0; padding: 0; display: grid; gap: 1rem; }
.wall__card {
  display: grid; grid-template-rows: auto auto 1fr auto; gap: 0.5rem;
  border: 1px solid var(--teal-line); border-radius: 3px;
  padding: 1.25rem 1.3rem 1.35rem; background: var(--white);
}
.wall__card h3 { margin: 0; font-size: 1.08rem; }
.wall__card p { margin: 0; }
.wall__what { font-size: 0.95rem; color: var(--ink-mid); line-height: 1.45; }
.wall__cost { font-size: 0.95rem; color: var(--ink); font-weight: 600; line-height: 1.45; }
.wall__card .btn { width: 100%; text-align: center; align-self: end; margin-top: 0.35rem; }
.wall__flag {
  font-size: 0.75rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--teal);
}
.wall__card--lead {
  border-color: var(--teal); border-top: 4px solid var(--teal);
  background: var(--teal-wash);
}
.wall__card--lead h3 { font-size: 1.3rem; }
@media (min-width: 820px) {
  .wall { grid-template-columns: repeat(4, 1fr); }
  .wall__card--lead { grid-column: span 2; grid-row: span 1; }

  /* ADDED 5 Aug. The four-track wall assumes THREE cards - lead spanning two, then two
     half-width. The D219/rule-18 pass removed self-referential cards from /datamate/,
     /modeller/ and /modeller-v2/, leaving two cards in a four-track grid and a visible
     hole at the end of the row. /datamate/ was the worst: two 254px cards in a 1063px
     wall, so half the row was empty. Nobody had opened these in a browser.
     A two-card wall now uses two tracks and the lead stops spanning. */
  .wall:has(.wall__card:nth-child(2):last-child) { grid-template-columns: repeat(2, 1fr); }
  .wall:has(.wall__card:nth-child(2):last-child) .wall__card--lead { grid-column: span 1; }
}

/* The hero's subordinate route. Body text, not a button, not bold - it exists to
   serve a cold reader without competing with the primary ask. If this ever starts
   reading as a second CTA, it has failed (rule 17). */
.hero__alt { margin: 0.55rem 0 0; font-size: 0.98rem; color: #b9d3d5; }
.hero__alt a { color: var(--white); }
/* Global teal link is invisible on the teal hero (DESIGN_BRIEF §5 trap); white = 10.54:1 vs #004650. Landed overnight under 5-15/D162 for morning review. */
.hero__cred a { color: var(--white); }

/* --- modeller gate: optional mobilisation-capture disclosure (26 July 2026) --------
   Collapsed by default so it adds zero visible height to the row that actually
   converts (the email field). Reuses .gate__form label styling. */
.gate__more { margin-top: 0.6rem; }
.gate__more summary { cursor: pointer; font-size: 0.88rem; color: var(--teal); font-weight: 600; }
.gate__extra { display: grid; gap: 0.6rem; margin-top: 0.7rem; max-width: 22rem; }
.gate__extra input {
  font: inherit; padding: 0.5rem 0.6rem; border: 1px solid var(--teal-line);
  border-radius: 3px; background: var(--white); color: var(--ink);
}

/* --- brand-word: the real wordmark artwork, replacing live text (26 July 2026) ------
   Reversal of the earlier live-text ruling - a logo is an image, and rendering
   "Gaia" in Archivo was never the real letterforms (wide light G, single-storey
   geometric a). currentColor, so it inherits whatever .brand/.footer__brand
   already set (var(--white) on these dark masthead/footer backgrounds) - same
   colour the live text rendered, no visual regression. Aspect ratio from the
   source geometry is 544.64:192.8 (~2.825:1); height in em so it scales with
   the surrounding font-size exactly as the text it replaces did. */
.brand-word { height: 1.8em; width: auto; flex: 0 0 auto; }
/* The rule the comment above always promised but never had (G-24, found live 2 Aug
   2026): the SVG's paths carry no fill attribute, so without this every browser
   fell back to default BLACK - the wordmark rendered black on the dark teal
   masthead and footer, estate-wide, since 26 July. currentColor picks up
   .brand/.footer__brand's var(--white) as documented. */
.brand-word path { fill: currentColor; }
/* Same defect, same day, in the roundel beside it: .brand-mark at line 488 sets
   color:#0FB5A6 intending the accent teal, but its paths carry no fill either, so
   the roundel rendered black too. Found by render-verifier while confirming the
   wordmark fix - it was invisible as a bug while the wordmark was also black. */
.brand-mark path { fill: currentColor; }
/* Enlarged 26 July 2026: at 0.92em the wordmark rendered 51px wide in a 66px
   masthead, which reads as a detail rather than a logo. 1.8em puts the full
   lockup around 140px, mid-way through the 120-160px norm, and the masthead
   still holds one row at 66px. Measured, not guessed - re-measure if changed.
   The footer keeps a smaller setting - see below. */
.footer__brand .brand-word { height: 1.3em; }

/* Funnel's bottom demo fallback. Subordinate to everything above it by design -
   it is the lesser ask offered only after the reader has passed on the bigger one. */
.reassure--alt { margin-top: 1.1rem; opacity: 0.92; }

/* --- modeller as a bid tool (26 July 2026) ---------------------------------
   The three-step ladder above the fold, the copy-paste line item, and the
   Step 2 handoff that was missing - the numbers used to appear and the
   conversation stopped. ---------------------------------------------------- */
.steps-mini { list-style: none; margin: 1.1rem 0 0; padding: 0; display: grid; gap: 0.3rem;
  font-size: 0.95rem; color: var(--ink-mid); }
.steps-mini strong { color: var(--teal); }
/* The step ladder lives in .pagehead, which is TEAL. The defaults above are the
   light-background case; without these overrides the strong text and both links
   render #004650 on #004650 and are invisible. Third time this trap has bitten
   today (hero credit line, funnel wordmark, here) - if a component can sit on
   the teal pagehead, style it for teal explicitly. */
.pagehead .steps-mini { color: #b9d3d5; }
.pagehead .steps-mini strong { color: var(--white); }
.pagehead .steps-mini a { color: var(--white); }

.step-flag { font-size: 0.8rem; font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--teal); margin: 0 0 0.5rem; }

/* The line a QS actually pastes. Monospaced-ish selectable block, deliberately
   the first thing in the results. */
.paste-line { border: 1px solid var(--teal); border-left: 5px solid var(--teal);
  background: var(--teal-wash); border-radius: 3px; padding: 1rem 1.15rem; margin-bottom: 1.5rem; }
.paste-line__label { margin: 0 0 0.4rem; font-size: 0.78rem; font-weight: 700;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--teal); }
.paste-line__text { margin: 0; font-size: 1.02rem; font-weight: 600; color: var(--ink);
  line-height: 1.5; user-select: all; }
.paste-line__note { margin: 0.5rem 0 0; font-size: 0.87rem; color: var(--ink-mid); }

.step-next { border-top: 1px solid var(--teal-line); margin-top: 2rem; padding-top: 1.5rem; }
.prose-list { margin: 0 0 1rem; padding-left: 1.2rem; }
.prose-list li { margin-bottom: 0.4em; }

/* --- masthead gets a wider container than the content column (26 July 2026) ---
   The nav reached nine items and the CTA is 194px; with the 134px wordmark that
   overflows the 1100px content wrap, dropping the button to a second row and
   taking the masthead 66px -> 113px.

   The masthead does not need to align to the reading column - at 1440 there was
   340px of unused margin either side. Widening it here is the layout change that
   keeps every ruled label intact: "Free cabin waste check", "Cabin cost tool"
   and "See inside" all survive unshortened.
   Measured: 1100 breaks, 1200 holds, 1240 leaves headroom. Below 1240 the
   max-width is inert, so narrow screens are untouched.
   🔒 MEASURE before adding a tenth nav item - this is the second time the
   masthead has run out of room in one day. */
.masthead .wrap { max-width: 1240px; }

/* --- the customer-journey pipeline (26 July 2026) --------------------------
   Chevron stage tracker, same markup on every page. Six steps in three acts,
   under the company slogan.

   🔒 NO .done / tick STATE EXISTS HERE, DELIBERATELY. The website cannot know
   what an anonymous visitor has done, so a completed step can only ever be a
   guess. Ticks are legitimate in an AUTORESPONDER, where the trigger tells us
   what they did - that variant is a plain <table>, spec in TODO_WIRING. If you
   are adding progress tracking to the public site, stop and re-read CLAUDE.md.

   🔒 Steps 5 and 6 are <span>, not <a> - a cold visitor should not be invited
   to jump past four free steps onto a price.
   Palette: brand teal, the approved accent, and greys. No new hues.
   ------------------------------------------------------------------------- */
.gp {
  --gp-mute: #DDE6E6; --gp-muteink: #5E7376; --gp-edge: #C6D6D6;
  background: #F4F7F7;
  padding: clamp(20px, 3vw, 34px) 0;
  border-bottom: 1px solid var(--gp-edge);
}
.gp h2 { font-size: clamp(18px, 2.2vw, 23px); margin-bottom: 0.35em; }
.gp-lede { margin: 0 0 1.1rem; font-size: 0.92rem; line-height: 1.55;
  color: var(--gp-muteink); max-width: 64ch; }
.gp-lede b { color: var(--teal); font-weight: 600; }

.gp .acts { display: grid; grid-template-columns: repeat(6, 1fr); gap: 3px; margin-bottom: 7px; }
.gp .act { border-bottom: 2px solid var(--gp-edge); padding: 0 4px 6px; }
.gp .act i { display: block; font-style: normal; font-weight: 800; font-size: 12.5px;
  line-height: 1; letter-spacing: .02em; text-transform: uppercase; color: var(--teal); }
.gp .act u { display: block; text-decoration: none; margin-top: 4px; font-size: 11px;
  line-height: 1.3; color: var(--gp-muteink); }
.gp .a1 { grid-column: span 3; } .gp .a2 { grid-column: span 2; } .gp .a3 { grid-column: span 1; }

.gp .pl { display: grid; grid-template-columns: repeat(6, 1fr); gap: 3px;
  list-style: none; padding: 0; margin: 0; }
.gp .pl > li { min-width: 0; }
.gp .pl a, .gp .pl > li > span {
  display: block; height: 100%; text-decoration: none; padding: 12px 20px 12px 28px;
  clip-path: polygon(0 0, calc(100% - 14px) 0, 100% 50%, calc(100% - 14px) 100%, 0 100%, 14px 50%);
  background: var(--gp-mute); color: var(--gp-muteink);
  transition: background .2s, color .2s;
}
.gp .pl > li:first-child a, .gp .pl > li:first-child > span {
  padding-left: 20px;
  clip-path: polygon(0 0, calc(100% - 14px) 0, 100% 50%, calc(100% - 14px) 100%, 0 100%);
}
.gp .pl > li:last-child a, .gp .pl > li:last-child > span {
  clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%, 14px 50%);
}
.gp .pl .n { display: block; font-weight: 600; font-size: 9.5px; line-height: 1;
  letter-spacing: .1em; text-transform: uppercase; opacity: .75; }
.gp .pl .t { display: block; margin-top: 5px; font-weight: 700; font-size: 13.5px;
  line-height: 1.18; letter-spacing: -.01em; }
.gp .pl .c { display: block; margin-top: 4px; font-size: 10.5px; line-height: 1.3; opacity: .82; }
.gp .pl .free { display: inline-block; margin-top: 5px; font-weight: 600; font-size: 9px;
  line-height: 1; letter-spacing: .08em; text-transform: uppercase; padding: 3px 5px;
  border-radius: 2px; background: rgba(0, 70, 80, .1); }
/* current step: accent fill AND the words "you are here" in the step label, so it
   is identifiable without relying on colour. */
.gp .pl .now { background: var(--accent); color: #00232a; }
.gp .pl .now .n { opacity: 1; font-weight: 700; }
.gp .pl .now .free { background: rgba(0, 35, 42, .14); }
.gp .pl a:hover { background: #C9D8D8; color: var(--teal); }
.gp .pl a:focus-visible { outline: 3px solid var(--teal); outline-offset: 2px; }

@media (max-width: 860px) {
  .gp .acts { display: none; }
  .gp .pl { grid-template-columns: 1fr; gap: 2px; }
  .gp .pl a, .gp .pl > li > span,
  .gp .pl > li:first-child a, .gp .pl > li:first-child > span,
  .gp .pl > li:last-child a, .gp .pl > li:last-child > span {
    padding: 12px 18px 20px;
    clip-path: polygon(0 0, 100% 0, 100% calc(100% - 11px), 50% 100%, 0 calc(100% - 11px));
  }
  .gp .pl > li:last-child a, .gp .pl > li:last-child > span {
    padding-bottom: 12px; clip-path: none;
  }
  .gp .pl .t { font-size: 15px; } .gp .pl .c { font-size: 11.5px; }
  /* act names reappear between the groups once the acts row is gone */
  .gp .pl > li[data-act]::before {
    content: attr(data-act); display: block; margin: 14px 0 5px;
    font-weight: 800; font-size: 11.5px; line-height: 1; letter-spacing: .1em;
    text-transform: uppercase; color: var(--teal);
  }
}

/* --- the pipeline folds below 860px (26 July 2026) -------------------------
   959px of pipeline ahead of the content on every mobile page was too much.
   CSS-only, no JS: the markup ships as a CLOSED <details>, so mobile gets the
   fold for free and it still works with scripting off. On desktop
   `display: contents` dissolves the <details> box and the summary is hidden,
   which reveals the closed content - verified in-browser before building.
   The <summary> IS the mobile "you are here" indicator: it names the step and
   the free count, so a reader who never expands it still learns both.
   ------------------------------------------------------------------------- */
.gp-fold { margin: 0; }
.gp-sum {
  cursor: pointer; list-style: none;
  padding: 14px 0; font-weight: 700; font-size: 0.95rem; line-height: 1.4;
  color: var(--teal); display: flex; align-items: center; gap: 0.6rem;
}
.gp-sum::-webkit-details-marker { display: none; }
.gp-sum::after {
  content: ''; flex: 0 0 auto; margin-left: auto;
  width: 8px; height: 8px; border-right: 2px solid var(--teal);
  border-bottom: 2px solid var(--teal); transform: rotate(45deg);
  transition: transform .2s;
}
.gp-fold[open] .gp-sum::after { transform: rotate(-135deg); }
.gp-sum:focus-visible { outline: 3px solid var(--teal); outline-offset: 2px; }

@media (min-width: 861px) { .gp-sum { display: none; } }

/* Collapsed height budget on mobile: the section padding dominates once the
   chevrons are hidden, so it tightens here and the expanded state absorbs it. */
@media (max-width: 860px) {
  .gp { padding: 8px 0; }
  .gp-sum { padding: 9px 0; font-size: 0.92rem; }
  .gp-fold[open] .gp-sum { margin-bottom: 4px; }
  .gp-fold[open] { padding-bottom: 10px; }
}

/* 🔒 WHY THIS NEEDS ONE LINE OF JS, and why display:contents was rejected.
   The obvious CSS-only trick - ship the <details> CLOSED and dissolve it on
   desktop with `display: contents` - LOOKS like it works: the content renders
   and a child measures a real height. It is a trap. The closed content does
   NOT contribute to its ancestors' layout, so the .gp section collapsed to
   69px on desktop with the pipeline spilling out of it. Measure the PARENT,
   not the child, if you ever retest this.
   So: the markup ships OPEN (correct with no JS anywhere, and correct on
   desktop full stop) and the script below closes it only on narrow screens.
   No-JS mobile therefore shows the full map - tall, but complete and honest. */

/* The pipeline's next-step line. Subordinate to the hero CTA by design - a text
   link, not a fifth button (rule 17: the estate already has the masthead ask,
   the hero ask and the three-card wall). Lives OUTSIDE .gp-fold so the mobile
   collapse never hides it. Step pages only. */
.gp-next {
  margin: 12px 0 0; font-size: 0.95rem; font-weight: 600; color: var(--teal);
}
.gp-next a { color: var(--teal); text-underline-offset: 3px; }
.gp-next a:hover { color: var(--accent-dark); }
@media (max-width: 860px) { .gp-next { margin-top: 8px; } }

/* ==========================================================================
   THIN STEPPER — 28 July 2026 (D072-class correction, rule 19). The full
   six-chevron .gp map was outranking content: 959px of navigation before a
   visitor learned what the page was even about. Orientation should cost about
   one line, so on most pages it now does - a single thin bar BELOW the H1 and
   intro, never above them.

   🔒 WHERE IT GOES, amended the same day. Every library page EXCEPT the five
   that carry something else:
     - /how-it-works/                          the full .gp map, nothing else
     - /modeller/ /modeller-v2/ /datamate/ /automate/   the full .gp-chev bar
   🔒 And NO page under /offers/ carries this line, or the bar, or the map.
   Rule 16: a funnel gets no nav, so it gets no stepper either. Both offers
   pages carried this line until 28 July 2026 and no longer do.

   🔒 "Still free" / "free" stays bold - it is the most valuable and most
   invisible fact in the funnel and the one part of this bar that earns its
   space. 🔒 No step number is claimed on a page that isn't one of the five
   marked steps (rule 19) - same honesty rule as the full map, just smaller.
   ========================================================================== */
.gp-thin {
  background: #F4F7F7;
  border-top: 1px solid #C6D6D6;
  border-bottom: 1px solid #C6D6D6;
  padding: 10px 0;
}
.gp-thin__line {
  margin: 0; display: flex; flex-wrap: wrap; align-items: baseline;
  column-gap: 10px; row-gap: 2px;
  font-size: 0.86rem; line-height: 1.4; color: #5E7376;
}
.gp-thin__acts {
  font-weight: 800; font-size: 0.78rem; letter-spacing: .04em;
  text-transform: uppercase; color: var(--teal); white-space: nowrap;
}
.gp-thin__dash { color: #9AAEB0; }
.gp-thin__status strong { color: var(--teal); font-weight: 700; }
.gp-thin__sep { margin: 0 2px; color: #9AAEB0; }
.gp-thin a { color: var(--teal); font-weight: 600; text-underline-offset: 3px; }
.gp-thin a:hover { color: var(--accent-dark); }
@media (max-width: 560px) {
  .gp-thin__acts { display: block; }
  .gp-thin__dash { display: none; }
}

/* ==========================================================================
   THE CHEVRON BAR (.gp-chev) — the FULL journey bar. Built 28 July 2026 and
   amended the same day (rule 19). Three corrections to what first shipped:

   🔒 1. NOT STICKY, AT ANY WIDTH. It used to stick from 860px up. A journey
   bar is orientation, and orientation does not need to follow a reader down
   5,500px of a product page — it needs to be seen once. Un-sticking it also
   removes every compensation the stick forced, all reverted with it:
   .subnav's 42px top offset, the 100px anchor bump on /datamate/ and
   /automate/, .qa and #won at 60px, and .gs-panelsec at 58px.

   🔒 2. FOUR PAGES ONLY — /modeller/, /modeller-v2/, /datamate/, /automate/.
   It was on twelve. Every other page carrying the pipeline is back to the thin
   .gp-thin line; /how-it-works/ carries its full .gp map and nothing else; and
   NO page under /offers/ carries either component (rule 16 — funnels get no
   nav, so they get no stepper).

   🔒 3. THREE TIERS, and the hierarchy IS the point. The old bar made steps
   1, 3 and 4 equally clickable on every page: three peers presented as equals,
   which is precisely the failure rule 18 names — it makes the reader choose
   instead of act.
     1. --current   the step this page IS. Marked "YOU ARE HERE". NOT a link.
     2. --next      ONE dominant control. The only link in the whole bar.
     3. everything else — an inert muted marker, a <span>, no href.

   ⚠️ /automate/ IS STEP 4 AND CARRIES NO --next. Its next step is 5, and rule
   19 forbids linking steps 5 and 6: "a cold visitor clicking step 5 skips four
   free steps and lands on a price." So that one bar has zero links, and that
   page wraps it in a <div> rather than a <nav>. Do not "fix" it by linking
   step 5 — the absence is the rule holding, not an oversight.

   ⚠️ COLOUR — FLAGGED, NOT CHANGED. Rule 17 says #0FB5A6 is the CTA colour
   and marks nothing else, yet --current fills with it. That predates this
   change (the full .gp map's .now does the same), so it is left exactly as
   shipped rather than altered under a task that was not about the palette.
   It now sits beside a real control, so it wants a ruling. --next deliberately
   takes teal instead, so this change does not spread the accent any further.

   Visual language borrowed from .gp .pl's chevron clip-path, scaled down.
   Rule 19 still applies: the current step only, never a completed one — no
   ticks, no fill, no greyed "done" state. There is deliberately no .done
   class. If you are adding one, stop.
   ========================================================================== */
.gp-chev {
  --gpc-mute: #DDE6E6; --gpc-muteink: #5E7376; --gpc-edge: #C6D6D6;
  background: #F4F7F7;
  border-top: 1px solid var(--gpc-edge);
  border-bottom: 1px solid var(--gpc-edge);
}
.gp-chev__list {
  display: grid; grid-template-columns: repeat(6, 1fr); grid-auto-rows: 62px; gap: 2px;
  align-items: center; line-height: 1;
  list-style: none; margin: 0 auto; padding: 0;
  max-width: var(--wrap);
}
.gp-chev__item { min-width: 0; }
.gp-chev__link {
  display: flex; align-items: center; justify-content: center; gap: 5px;
  /* Row height and type scaled up 8 Aug 2026 (Jamie): the bar is now six live
     controls, not one control and five markers, so it has to be comfortably
     clickable and readable. 40px -> 52px, 12px -> 14px. */
  height: 62px; text-decoration: none;
  padding: 0 12px 0 20px;
  clip-path: polygon(0 0, calc(100% - 12px) 0, 100% 50%, calc(100% - 12px) 100%, 0 100%, 12px 50%);
  background: var(--gpc-mute); color: var(--gpc-muteink);
  font-size: 14px; font-weight: 600; white-space: nowrap; overflow: hidden;
  transition: background .2s, color .2s;
}
.gp-chev__item:first-child .gp-chev__link {
  padding-left: 14px;
  clip-path: polygon(0 0, calc(100% - 12px) 0, 100% 50%, calc(100% - 12px) 100%, 0 100%);
}
.gp-chev__item:last-child .gp-chev__link {
  clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%, 12px 50%);
}
.gp-chev__n { font-weight: 700; opacity: .7; }
.gp-chev__t { overflow: hidden; text-overflow: ellipsis; }
.gp-chev__free { font-size: 10px; text-transform: uppercase; letter-spacing: .05em; opacity: .8; white-space: nowrap; }
/* both hidden by default: --current turns on "YOU ARE HERE", --next the arrow */
.gp-chev__here { display: none; }
.gp-chev__go { display: none; }

/* --- tier 1: YOU ARE HERE. A position marker, never a control. ----------- */
.gp-chev__item--current .gp-chev__link {
  background: var(--accent); color: #00232a;
  flex-direction: column; gap: 0; line-height: 1.2;
}
.gp-chev__item--current .gp-chev__n { opacity: 1; }
/* ⚠️ The current step used to HIDE its price badge, on the reasoning that "YOU ARE
   HERE" was the only thing worth saying there. Ruled otherwise 8 Aug 2026 (Jamie):
   step 1 is free and has to say so on the page where it matters most - the page a
   visitor is actually standing on. Both now show, stacked. */
.gp-chev__item--current .gp-chev__free { display: block; opacity: .9; }
.gp-chev__item--current .gp-chev__here {
  display: block; font-size: 9px; font-weight: 700; letter-spacing: .05em;
  text-transform: uppercase; opacity: .85;
}

/* --- tier 2: the ONE dominant next control, and the bar's only link ------
   Teal, not accent — see the colour note in this section's header. It reads as
   the actionable chevron because it is the only dark one and the only one
   carrying an arrow, not because it borrowed the CTA colour. The "Free" /
   "Still free" badge stays at full opacity here: on the one chevron a reader
   is being invited to click, the price being nothing is the whole argument. */
.gp-chev__item--next .gp-chev__link {
  background: var(--teal); color: var(--white);
  font-weight: 700;
}
.gp-chev__item--next .gp-chev__n { opacity: .8; }
.gp-chev__item--next .gp-chev__free { opacity: 1; }
.gp-chev__item--next .gp-chev__go { display: inline; font-weight: 700; }
.gp-chev__item--next a.gp-chev__link:hover {
  background: var(--accent-dark); color: #00312f;
}

/* --- every step is a control (Jamie, 8 Aug 2026) -------------------------
   The bar used to have exactly one link (--next). Ruled: all six steps are
   clickable so a reader can move through the pipeline from any page. The
   position marker (--current) stays a span - you cannot navigate to where you
   already are. Hover is the teal fill: it now signals "this is a link you are
   pointing at" rather than "this is the one dominant next step", which is why
   --next was retired from the markup. */
a.gp-chev__link { cursor: pointer; }
a.gp-chev__link:hover {
  background: var(--teal); color: var(--white); font-weight: 700;
}
a.gp-chev__link:hover .gp-chev__n,
a.gp-chev__link:hover .gp-chev__free { opacity: 1; }
a.gp-chev__link:focus-visible { outline: 3px solid var(--teal); outline-offset: -3px; }
/* a teal ring is invisible on the teal chevron */
.gp-chev__item--next a.gp-chev__link:focus-visible { outline-color: var(--white); }

/* 860–1439px: the two chevrons that carry meaning — where you are and where to
   go next — keep their labels; the four inert markers reduce to numbers. Six
   full labels do not fit at 860 (measured), and the ones to drop are the ones
   with no decision attached to them.

   ⚠️ --next WRAPS TO TWO ROWS HERE, and the row height goes to 46px to hold it.
   Measured, not guessed: at 860 a sixth of the wrap is ~143px, and
   "4 Prove it STILL FREE →" on one row ellipsised to "4 Pr…" — the dominant
   control was the one chevron a reader could not read. The badge takes
   flex-basis 100% to force the break, so row 1 is the number and the label and
   row 2 is the badge and the arrow. Do not put it back on one row. */
@media (min-width: 860px) and (max-width: 1439px) {
  /* ⚠️ REVISED 8 Aug 2026. This used to hide the label on every step except the
     two that "carried meaning" (--current and --next). --next has been retired, so
     that rule would have left FIVE bare numbers and one label - and every one of
     those numbers is now a link. Labels stay; the small FREE / £25-a-week badges
     are what drop instead, because they are the part that would not fit. */
  .gp-chev__item:not(.gp-chev__item--current) .gp-chev__free { display: none; }
  .gp-chev__link { font-size: 13px; padding: 0 8px 0 16px; gap: 4px; }
  .gp-chev__list { grid-auto-rows: 66px; }
  .gp-chev__link { height: 66px; }
  .gp-chev__item--next .gp-chev__link {
    flex-wrap: wrap; align-content: center; row-gap: 1px;
  }
  /* the arrow is pulled up beside the label with `order`, not by reordering the
     markup: DOM order stays "label then badge then arrow", which is the reading
     order at 1440 and the order a screen reader gets at every width. Without
     this the badge's flex-basis:100% pushed the arrow onto a THIRD row. */
  .gp-chev__item--next .gp-chev__go { order: 1; }
  .gp-chev__item--next .gp-chev__free {
    order: 2; flex-basis: 100%; text-align: center;
  }
}

/* below 860px: stacks 3x2 so labels stay readable rather than compressing to
   numbers-only. Never sticky here either — at 375 the header alone already
   runs 221px with nine wrapping nav items and no collapse pattern.

   ⚠️ grid-auto-rows: auto IS LOAD-BEARING. The base rule pins rows at 40px for
   the single-row desktop bar; that pin survived into this breakpoint, where the
   links are stacked columns and run well past 40px. Result: every cell was
   clipped at 40px — step 1's "FREE" badge was cut in half and the taller --next
   chevron burst out of its row. Rows size to content here, and the cells
   stretch so a short chevron and a tall one in the same row still line up. */
@media (max-width: 859px) {
  .gp-chev__list {
    grid-template-columns: repeat(3, 1fr); gap: 4px;
    grid-auto-rows: auto; align-items: stretch;
  }
  .gp-chev__link {
    height: auto; min-height: 100%; justify-content: center;
    flex-direction: column; gap: 2px; text-align: center;
    padding: 8px 6px; clip-path: none !important; border-radius: 4px;
  }
  .gp-chev__t { white-space: normal; }
  /* the arrow is a desktop affordance; at this size the chevron is a full-width
     tap target and the arrow only adds a fourth stacked row. */
  .gp-chev__item--next .gp-chev__go { display: none; }
}

/* ==========================================================================
   DRYING ROOM SAFEGUARDS — /drying-room/ only. 🔒 The HTML this styles is
   currently wrapped in an HTML comment (not built yet - see the marker on
   that page). This CSS ships live and unused until it is uncommented; kept
   here rather than deleted so the diagrams don't need re-styling when the
   three features ship. Simple two-state icon crossfades, "diagrams not
   decoration" - no JS, and reduced-motion gets a static resolved state
   rather than a frozen mid-fade frame.
   ========================================================================== */
.dr-safe-grid { margin-top: 1.75rem; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1.75rem; }
.dr-safe { text-align: left; }
.dr-anim { position: relative; width: 48px; height: 48px; margin-bottom: 0.9rem; color: var(--teal); }
.dr-anim svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.dr-anim .s1 { animation: dr-fade-out 5s ease-in-out infinite; }
.dr-anim .s2 { animation: dr-fade-in 5s ease-in-out infinite; }
@keyframes dr-fade-out { 0%, 45% { opacity: 1; } 55%, 100% { opacity: 0; } }
@keyframes dr-fade-in { 0%, 45% { opacity: 0; } 55%, 100% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .dr-anim .s1 { animation: none; opacity: 0; }
  .dr-anim .s2 { animation: none; opacity: 1; }
}
.dr-safe p { font-size: 0.95rem; line-height: 1.55; }
.dr-safe-close { margin-top: 1.5rem; font-size: 1.05rem; font-weight: 600; color: var(--teal); }
@media (max-width: 860px) { .dr-safe-grid { grid-template-columns: 1fr; gap: 1.5rem; } }

/* ==========================================================================
   REAL PHOTOGRAPHY — the estate's first, 28 July 2026. Rule 12: real sites
   only, no stock, no AI. DESIGN_BRIEF: numbers stay the hero; a photograph
   proves the thing is real, it does not carry the page - so this stays
   deliberately plain. No colour-grading, no rounded corners, no shadow
   dressing up a rough site photo as a marketing shot.
   ========================================================================== */
.photo { display: block; margin: 0; }
.photo img { display: block; width: 100%; height: auto; }
.photo-cap {
  margin-top: 0.6rem; font-size: 0.86rem; line-height: 1.5; color: var(--ink-mid);
  max-width: 60ch;
}
.photo--wide { max-width: 780px; }
.photo--med { max-width: 520px; }
.photo--narrow { max-width: 340px; }
