/* ==========================================================================
   CT Innovates — Home page sections
   ========================================================================== */

/* ---------------- Hero --------------------------------------------------- */
.hero {
  position: relative;
  background: var(--grad-hero);
  color: var(--color-on-dark);
  /* slide up beneath the floating nav so the gap above the pill shows the hero */
  margin-top: calc(-1 * var(--header-h));
  padding-block: calc(var(--header-h) + clamp(3.5rem, 2rem + 8vw, 7rem)) clamp(5rem, 3rem + 9vw, 9rem);
  overflow: clip;
}
.hero__grid {
  display: grid;
  grid-template-columns: 1.3fr 0.82fr;
  gap: clamp(2rem, 4vw, 4.5rem);
  align-items: stretch;   /* media scales to the left column's height */
}
.hero__grid > * { min-width: 0; }
.hero__dots { top: -8%; right: -6%; }
.hero h1 { margin-block: var(--space-5) var(--space-6); max-width: 16ch; }
.hero .lede { max-width: var(--measure-narrow); }
.hero__actions { display: flex; flex-wrap: wrap; gap: var(--space-4); margin-top: var(--space-8); }

/* The thesis line closes the copy column. Component lives in components.css so
   Framework's non-negotiables can carry the identical treatment. */
.hero .mantra { max-width: var(--measure-narrow); }

.hero__media { position: relative; isolation: isolate; height: 100%; min-height: 360px; }
/* The photo + its offset panel are ONE composite frame whose bounding box IS
   the stage. Each layer fills the stage minus --peek and anchors to opposite
   corners, so their union exactly equals the stage — the panel can't overflow
   the column at any width, with no breakpoint-specific rules. (The drop-shadows
   stay free: a shadow clipped to the grid would read as broken, not tidy.) */
.hero__stage { position: relative; height: 100%; --peek: 7%; }
.hero__media .frame,
.hero__stage .frame--ghost {
  position: absolute;
  width: calc(100% - var(--peek));
  height: calc(100% - var(--peek));
  aspect-ratio: auto;
}
.hero__media .frame {            /* foreground photo — top-left of the box */
  z-index: 2;
  top: 0; left: 0;
  clip-path: var(--clip-parallelogram);
  border-radius: 0;
  filter:
    drop-shadow(0 6px 10px rgba(4, 10, 30, 0.4))
    drop-shadow(0 20px 30px rgba(4, 10, 30, 0.5));
}
.hero__stage .frame--ghost {     /* offset panel — bottom-right of the box */
  inset: auto;
  bottom: 0; right: 0;
  transform: none;               /* the peek is real layout now, not a shift */
}
.hero .frame--main {
  background-image:
    radial-gradient(rgba(157, 223, 255, 0.22) 1.2px, transparent 1.4px),
    linear-gradient(150deg, var(--navy-600), var(--navy-800));
  background-size: 15px 15px, cover;
}
/* no inset edge — a rectangular border clipped to the parallelogram leaves
   stray slivers at the slanted corners. The offset panel provides separation. */
.hero .frame--main::after { box-shadow: none; }
/* the photo pans toward the cursor inside its mask; the small hover zoom gives
   it room to move without ever exposing the parallelogram edge (JS sets the
   --img-* vars). Identity at rest, so no crop change until hovered. */
.hero__media .frame--main > img {
  /* always slightly zoomed so the pan has slack on both axes; hover only pans */
  transform: scale(1.12) translate(var(--img-x, 0%), var(--img-y, 0%));
  transition: transform 200ms var(--ease-out);   /* responsive while tracking */
  will-change: transform;
}
/* on mouse-leave the photo drifts slowly back to centre (long ease-out tail) */
.hero__media .frame--main.is-returning > img {
  transition: transform 650ms cubic-bezier(0.16, 1, 0.3, 1);
}
@media (prefers-reduced-motion: reduce) {
  .hero__media .frame--main > img { transition: none; }
}
.hero .frame__ph { color: var(--brand-blue-200); }
/* underlay: a solid brand panel the photo sits on — real depth, offset
   down-right so it peeks as a blue angular edge (the originals' stacked-panel
   language). Replaces the floating outline + the detached shard. */
.frame--ghost {
  position: absolute;
  z-index: 1;
  inset: 0;
  clip-path: var(--clip-parallelogram);
  background: var(--grad-deep);
  transform: translate(7%, 7.5%);
  /* the back plane: a soft cast grounds the whole stack on the dark hero */
  filter: drop-shadow(0 24px 30px rgba(0, 0, 0, 0.42));
}
.frame--ghost::after {
  content: "";
  position: absolute; inset: 0;
  background-image: radial-gradient(rgba(255, 255, 255, 0.14) 1px, transparent 1.4px);
  background-size: 16px 16px;
}

/* ---------------- Hero entrance (choreographed, led by the eyebrow) ------ */
/* The eyebrow keeps its line-draw; everything else rises in after it in a
   stacked cascade — left column top-to-bottom, the image alongside the lede,
   the trust chips popping in last. Gated by html.js so no-JS shows everything
   immediately; fully skipped under reduced-motion. */
@media (prefers-reduced-motion: no-preference) {
  html.js .hero__copy h1,
  html.js .hero__copy .lede,
  html.js .hero__actions,
  html.js .hero__media .frame {
    animation: hero-rise 0.7s var(--ease-out) both;
  }
  html.js .hero__copy h1      { animation-delay: 0.14s; }
  html.js .hero__media .frame { animation-delay: 0.26s; }  /* foreground photo lands first */
  html.js .hero__copy .lede   { animation-delay: 0.30s; }
  html.js .hero__actions      { animation-delay: 0.42s; }

  /* the back panel slides out from behind the photo a beat later — the stack
     assembles front-to-back, so you never see a bare blue parallelogram */
  html.js .hero__stage .frame--ghost {
    animation: hero-panel 0.66s var(--ease-out) both;
    animation-delay: 0.46s;
  }

  /* the thesis lands last, after the stack has assembled */
  html.js .hero .mantra { animation: hero-pop 0.5s var(--ease-out) both; animation-delay: 0.58s; }
}
@keyframes hero-rise {
  from { opacity: 0; transform: translateY(20px); }
  to   { opacity: 1; transform: none; }
}
@keyframes hero-panel {
  from { opacity: 0; transform: translate(-16px, -18px); }  /* tucked behind the photo */
  to   { opacity: 1; transform: none; }                     /* settles into its offset */
}
@keyframes hero-pop {
  from { opacity: 0; transform: translateY(10px) scale(0.97); }
  to   { opacity: 1; transform: none; }
}
/* ---------------- Value triad (five-second clarity) ---------------------- */
.triad { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-6); }

/* Large overlapping parallelogram outlines — the site's core angular shape
   surfaced as a faint line motif, scaling the hero's two stacked panels into a
   field. Transparent fill, thin borders; masked to fade out toward the
   headline so it stays a backdrop and never sits behind the text. */
.section--intro { position: relative; overflow: clip; }
.section--intro > .container { position: relative; z-index: 1; }
.paragrid {
  position: absolute; inset: 0; z-index: 0;
  pointer-events: none; overflow: clip;
  color: var(--brand-blue-500);
  opacity: 0.14;
  /* a right-side band, full height — runs top to bottom past the cards and
     stays out of the headline/lede column */
  -webkit-mask-image: linear-gradient(to right, transparent 48%, #000 84%);
          mask-image: linear-gradient(to right, transparent 48%, #000 84%);
}
.paragrid svg { display: block; width: 100%; height: 100%; }
@media (max-width: 880px) {
  .paragrid {
    opacity: 0.14;
    -webkit-mask-image: linear-gradient(to right, transparent 55%, #000 92%);
            mask-image: linear-gradient(to right, transparent 55%, #000 92%);
  }
}

/* ---------------- Role / stage ledger ------------------------------------ */
/* Hallmark · component: roles · system: CT Innovates (locked tokens)
 * pre-emit critique: P5 H5 E5 S5 R5 V4
 *
 * A LIST, not a third card. The site already owns the hairline ledger row
 * (.program on the homepage, .guards__item on Framework) and that figure is
 * the right one for a set of parallel things that each need a name and a
 * sentence. The earlier version was a boxed card with a solid brand header
 * bar -- a second card language two sections from .card--feature, and the
 * system's expanding accent bar rendered as a permanent slab.
 *
 * Mark column carries the name; the content column carries the claim and the
 * line under it. Framework's stages omit the claim and the same rule holds,
 * because the mark spans whatever rows exist.
 */
.roles { list-style: none; margin-top: clamp(2rem, 4vw, 3rem); }
.roles__item {
  display: grid;
  grid-template-columns: minmax(0, 13rem) minmax(0, 1fr);
  column-gap: clamp(1.5rem, 4vw, 3.5rem);
  row-gap: var(--space-2);
  align-items: start;
  padding-block: clamp(1.5rem, 3vw, 2.25rem);
  border-top: 1px solid var(--color-line);
}
.roles__item:last-child { border-bottom: 1px solid var(--color-line); }
/* the name is the mark: it holds the left column on its own, so the row needs
   no icon, no numeral and no box */
.roles__who {
  grid-column: 1;
  grid-row: 1 / -1;
  font-size: var(--text-sm);
  font-weight: var(--fw-bold);
  text-transform: uppercase;
  letter-spacing: 0.14em;
  line-height: 1.35;
  color: var(--color-primary-deep);
}
.roles__claim,
.roles__body { grid-column: 2; }
.roles__claim {
  font-size: var(--text-lg);
  font-weight: var(--fw-bold);
  line-height: 1.3;
  letter-spacing: var(--tracking-tight);
  color: var(--color-ink);
}
.roles__body {
  font-size: var(--text-sm);
  line-height: 1.6;
  color: var(--color-ink-soft);
  max-width: var(--measure-body);
}
.on-dark .roles__item { border-top-color: var(--color-line-dark); }
.on-dark .roles__item:last-child { border-bottom-color: var(--color-line-dark); }
.on-dark .roles__who { color: var(--brand-blue-400); }
.on-dark .roles__claim { color: var(--color-on-dark); }
.on-dark .roles__body { color: var(--color-on-dark-soft); }
@media (max-width: 700px) {
  .roles__item { grid-template-columns: 1fr; }
  .roles__who { grid-row: auto; grid-column: 1; }
  .roles__claim, .roles__body { grid-column: 1; }
}

/* ---------------- One source, multiple outputs -------------------------- */
/* Hallmark · component: one-to-many fan-out · system: CT Innovates (design.md)
 * pre-emit critique: P5 H5 E5 S5 R5 V5
 * The fan-out is made of layout, not of drawing: one statement on the left
 * against five discrete rows on the right, so the 1:5 mass ratio is the idea.
 * design.md names four signature devices and forbids a fifth, so this invents
 * nothing -- .mantra's left bar marks the single source, the hairline ledger
 * carries the five. The supplied graphic was unusable; this needs no image. */
/* This band is --soft, not --dark. It used to be dark and sat directly above
   .practice, which is also dark, so the two read as one long navy stretch.
   The tokens below were converted from their on-dark counterparts; .mantra,
   .claim, .eyebrow and .bracket carry their own light defaults, so they
   needed nothing. */
.source__fan {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.92fr);
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: start;
}
.source__one .mantra { margin-top: var(--space-6); }
.source__one-body {
  margin-top: var(--space-4);
  max-width: var(--measure-lede);
  font-size: var(--text-sm);
  line-height: 1.6;
  color: var(--color-ink-soft);
}

/* The five. One line each -- Chris's names are self-describing, so a gloss
   would only repeat them and cost height. */
.source__many { padding-top: var(--space-2); }
.source__label {
  margin-bottom: var(--space-3);
  font-size: var(--text-xs);
  font-weight: var(--fw-bold);
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--color-primary-deep);
}
.source__outputs { list-style: none; border-top: 1px solid var(--color-line); }
.source__outputs li {
  position: relative;
  padding: var(--space-4) 0 var(--space-4) var(--space-6);
  border-bottom: 1px solid var(--color-line);
  font-size: var(--text-base);
  line-height: 1.4;
  letter-spacing: var(--tracking-tight);
  color: var(--color-ink);
  transition: color var(--dur) var(--ease-out);
}
/* A short rule per row, not a bullet and not a numeral -- the homepage already
   runs 01-03 twice below this, and a third numbered set would read as a
   sequence when these five are a set. */
.source__outputs li::before {
  content: "";
  position: absolute;
  left: 0; top: calc(0.7em + var(--space-4));
  width: var(--space-4); height: 2px;
  background: var(--color-primary);
}

.source .claim { margin-top: clamp(2.5rem, 5vw, 3.5rem); }

@media (max-width: 880px) {
  .source__fan { grid-template-columns: minmax(0, 1fr); }
  .source__many { padding-top: 0; }
}

/* ---------------- The Civic AI Practice (process) ------------------------ */
.practice { position: relative; }
.practice__principle b { color: var(--brand-blue-400); font-weight: var(--fw-bold); }

/* Stacked process rows threaded on a progress rail. As the section scrolls, the
   current step is highlighted and the rail fills to its node — a guided read of
   one connected practice. The rail geometry (--rail-top/-bottom) and progress
   are measured in JS from the live node positions, so the fill always lands
   exactly on a node. Both the rail and the nodes are centred on --rail-x, so
   they can never drift apart. No hover chrome — scroll drives everything. */
.practice-steps {
  --rail-col: 32px;                 /* rail/node gutter width */
  --rail-x: calc(var(--rail-col) / 2); /* shared centre axis for rail + nodes */
  --rail-top: 0px;
  --rail-bottom: 0px;
  --rail-progress: 0px;
  position: relative;
  margin-top: clamp(2rem, 4vw, 3.5rem);
  border-bottom: 1px solid var(--color-line-dark);
}
.practice-steps::before,
.practice-steps::after {
  content: "";
  position: absolute;
  left: calc(var(--rail-x) - 1px);
  width: 2px;
  border-radius: 2px;
}
.practice-steps::before {           /* faint rail, node to node */
  top: var(--rail-top);
  height: calc(var(--rail-bottom) - var(--rail-top));
  background: var(--color-line-dark);
}
.practice-steps::after {            /* bright progress fill */
  top: var(--rail-top);
  height: var(--rail-progress);
  background: var(--grad-primary);
  transition: height 0.45s var(--ease-out);
}
.prow {
  display: grid;
  grid-template-columns: var(--rail-col) minmax(0, 1fr) minmax(0, 1.45fr);
  gap: 0 clamp(1.5rem, 3vw, 2.75rem);
  align-items: start;
  padding: clamp(1.25rem, 2.4vw, 1.85rem) 0;
  border-top: 1px solid var(--color-line-dark);
}
/* node, centred on the rail (matches --rail-x). default = upcoming (hollow) */
.prow__node {
  grid-column: 1;
  justify-self: center;
  margin-top: 0.4rem;
  width: 13px; height: 13px;
  border-radius: 50%;
  border: 2px solid rgba(157, 223, 255, 0.32);
  background: var(--navy-900);
  position: relative; z-index: 1;
  transition: border-color var(--dur) var(--ease-out),
              background var(--dur) var(--ease-out),
              transform var(--dur) var(--ease-out),
              box-shadow var(--dur) var(--ease-out);
}
.prow.is-reached .prow__node { background: var(--brand-blue-500); border-color: var(--brand-blue-400); }
.prow.is-current .prow__node {
  background: var(--brand-blue-400);
  border-color: var(--brand-blue-400);
  transform: scale(1.25);
  box-shadow: 0 0 0 5px rgba(49, 143, 253, 0.16);
}
.prow__lead {
  grid-column: 2;
  display: flex; align-items: baseline;
  gap: clamp(0.75rem, 1.5vw, 1.4rem); min-width: 0;
}
/* 01 over LEARN — the same stacked mark the pricing ledger uses (.program-step__mark),
   held to a fixed column so all three titles start on one line despite
   OPERATIONALIZE being twice the length of LEARN. */
.prow__mark { flex: none; width: 9.5rem; display: flex; flex-direction: column; gap: 0.2rem; }
.prow__stage {
  font-size: var(--text-xs);
  font-weight: var(--fw-bold);
  text-transform: uppercase;
  letter-spacing: 0.14em;
  line-height: 1.2;
  color: color-mix(in srgb, var(--brand-blue-200) 78%, transparent);
  transition: color var(--dur) var(--ease-out);
}
.prow.is-reached .prow__stage { color: var(--brand-blue-200); }
.prow.is-current .prow__stage { color: var(--brand-blue-400); }
.prow__n {
  flex: none;
  font-size: var(--mark-sm);
  font-weight: var(--fw-extra);
  line-height: 1; letter-spacing: -0.02em;
  color: color-mix(in srgb, var(--brand-blue-200) 62%, transparent);
  transition: color var(--dur) var(--ease-out);
}
.prow__title {
  font-size: var(--text-xl);
  font-weight: var(--fw-bold);
  letter-spacing: var(--tracking-tight);
  color: var(--color-on-dark);
  transition: color var(--dur) var(--ease-out);
}
.prow.is-current .prow__n { color: var(--brand-blue-400); }
.prow.is-current .prow__title { color: var(--brand-blue-200); }
.prow__desc {
  grid-column: 3;
  font-size: var(--text-base);
  line-height: 1.55;
  color: var(--color-on-dark-soft);
  max-width: var(--measure-body);
}
@media (prefers-reduced-motion: reduce) {
  .practice-steps::after { transition: none; }
  .prow.is-current .prow__node { transform: none; }
}
@media (max-width: 880px) {
  .practice-steps { --rail-col: 26px; }
  .prow {
    grid-template-columns: var(--rail-col) 1fr;
    grid-template-areas: "node lead" "node desc";
    gap: var(--space-2) var(--space-3);
  }
  .prow__node { grid-area: node; }
  /* the mark stops being a fixed column and sits inline ahead of the title */
  .prow__lead { grid-area: lead; flex-wrap: wrap; }
  .prow__mark { width: auto; flex-direction: row; align-items: baseline; gap: var(--space-2); }
  .prow__desc { grid-area: desc; max-width: none; }
}

/* ---------------- Offer · the two-step program (Hallmark redesign) ------- */
/* Hallmark · component: program-ledger · genre: editorial-civic (inherits CTI)
 * pre-emit critique: P5 H4 E5 S5 R5 V5
 * The two programs are one PATH, not two options: a single panel with 01/02
 * ledger rows (Start here -> Then), a gradient index, topic tags, and price
 * right-aligned. Sequence reads top-to-bottom; no floating cards, no arrow. */
.program {
  /* The card's own padding held its content 44px inside the container, while
     every neighbouring section (.roles, .source__outputs, .practice-steps) runs
     flush to it. The card frame is faint enough that the eye reads the content
     edge, so the block looked short on the right. Pull the card out by exactly
     its padding -- capped at the container gutter so it can never overhang the
     viewport -- and the content lands on the same axis as everything else. */
  --program-pad: clamp(1.5rem, 3vw, 2.75rem);
  --program-bleed: min(var(--program-pad), var(--container-pad));
  margin-inline: calc(-1 * var(--program-bleed));
  margin-top: clamp(2.5rem, 5vw, 3.5rem);
  list-style: none;
  background: var(--color-bg-card);
  border: 1px solid var(--color-line);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}
.program-step {
  display: grid;
  grid-template-columns: 10.5rem minmax(0, 1fr) minmax(15rem, 17rem);
  gap: clamp(1.25rem, 3.5vw, 3rem);
  align-items: start;
  padding-block: clamp(1.75rem, 3.5vw, 2.75rem);
  padding-inline: var(--program-pad);
}
.program-step + .program-step { border-top: 1px solid var(--color-line); }
.program-step__mark { display: flex; flex-direction: column; gap: var(--space-1); }
.program-step__n {
  font-size: var(--mark-md); font-weight: var(--fw-extra);
  line-height: 0.85; letter-spacing: var(--tracking-tight);
  background: var(--grad-primary); -webkit-background-clip: text; background-clip: text; color: transparent;
}
/* Stage names run long ("BUILD THE FOUNDATION"), so the label wraps inside the
   mark column rather than nowrapping out of it into the body text. */
.program-step__label { font-size: var(--text-xs); font-weight: var(--fw-bold); text-transform: uppercase; letter-spacing: 0.12em; line-height: 1.3; color: var(--color-primary-deep); }
/* word marks (Start / Then / Opt 1-3): the same gradient index, sized down so
   the longer strings hold the same mark column as the numerals */
.program-step__n--word { font-size: var(--mark-sm); line-height: 1; text-transform: uppercase; white-space: nowrap; }
.program-step__name { font-size: var(--text-2xl); font-weight: var(--fw-bold); letter-spacing: var(--tracking-tight); color: var(--color-ink); }
.program-step__desc { margin-top: var(--space-2); font-size: var(--text-sm); line-height: 1.5; color: var(--color-ink-soft); max-width: var(--measure-narrow); }
.program-step__tags { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-4); list-style: none; }
.program-step__tags li { font-size: var(--text-xs); font-weight: var(--fw-semibold); color: var(--color-ink-soft); padding: 0.32rem 0.72rem; border-radius: var(--radius-pill); background: var(--color-bg-soft); border: 1px solid var(--color-line); }
.program-step__meta { --price-align: end; --price-size: var(--text-3xl); align-self: end; }

/* shared note under a group of priced cards — used on the homepage ledger and
   on the pricing page under 01 and 02. Defined here because home.css loads everywhere. */
.mods-note { margin-top: var(--space-6); max-width: var(--measure-body); font-size: var(--text-sm); line-height: 1.6; color: var(--color-ink-soft); }
.mods-note strong { font-weight: var(--fw-semibold); color: var(--color-ink); }
.program-step__from { font-size: var(--text-xs); font-weight: var(--fw-semibold); text-transform: uppercase; letter-spacing: 0.08em; }
@media (max-width: 880px) {
  /* The desktop bleed pulls the card out by its own padding so its content
     lands on the container axis. Below 880 the container gutter IS the page's
     only side margin, so bleeding leaves the card flush against the screen
     edge with nothing around it. Sit inside the container instead. */
  .program { margin-inline: 0; }
  .program-step { grid-template-columns: 1fr; gap: var(--space-4); }
  .program-step__mark { flex-direction: row; align-items: baseline; gap: var(--space-3); }
  .program-step__n { font-size: 2.25rem; }
  /* The block moves to the left of the stacked row, so the price has to follow
     it. --price-align is what .price reads; without this the figure stayed
     end-aligned inside a left-hand block, which is what read as broken. */
  .program-step__meta { --price-align: start; align-items: flex-start; text-align: left; flex-direction: row; flex-wrap: wrap; justify-content: space-between; width: 100%; gap: var(--space-3) var(--space-6); }
}

/* section-head CTA — sits under the offer lede, above the two step cards */
.offer__cta { margin-top: var(--space-8); }
/* closing CTA callout lives inside the offer section (on the soft band); its top
   gap matches the section's bottom padding so it reads as its own sub-section */
.offer .cta { margin-top: var(--section-y); }

/* ---------------- Credibility (replaces testimonials) -------------------- */
.cred__grid { display: grid; grid-template-columns: 1.6fr 1fr; gap: clamp(2.5rem, 6vw, 6rem); align-items: stretch; }
.cred__list { display: grid; gap: var(--space-5); margin-top: var(--space-8); }
.cred__item { display: flex; gap: var(--space-4); align-items: flex-start; }
.cred__item .card__icon { flex: none; margin: 0; }
.cred__item h3 { font-size: var(--text-base); font-weight: var(--fw-bold); margin-bottom: var(--space-1); }
.cred__item p { font-size: var(--text-sm); color: var(--color-ink-soft); }
/* the "two streams -> one practice" credibility argument */
.cred__lede { margin-top: var(--space-4); }
.card > p.cred__who,
.cred__who { margin-bottom: var(--space-1); font-size: var(--text-xs); font-weight: var(--fw-bold); text-transform: uppercase; letter-spacing: 0.12em; color: var(--color-primary-deep); }
.cred__streams { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-6); margin-top: var(--space-8); }

/* framed portrait on the right — mirrors the hero composite (photo + offset blue-dot panel) */
/* two founders share the column: identical frame language, stacked, each with
   its own namecard. Everything else about this section is unchanged. */
.cred__media { position: relative; isolation: isolate; height: 100%; display: grid; grid-template-rows: 1fr 1fr; gap: clamp(1.5rem, 3vw, 2.5rem); }
.cred__stage { margin: 0; }
/* frame grows to the section/content height (like the hero); fixed peek so the
   panel shows an equal amount on the right and the bottom (a % peek would differ
   between the two on a non-square frame). */
.cred__stage { position: relative; height: 100%; --peek: 1.35rem; min-height: 15rem; }
.cred__stage .frame--main,
.cred__stage .frame--ghost { position: absolute; width: calc(100% - var(--peek)); height: calc(100% - var(--peek)); aspect-ratio: auto; }
/* distinct shape from the hero's parallelogram — the ghost panel must match the mask */
.cred__stage .frame--main { z-index: 2; top: 0; left: 0; clip-path: var(--clip-notch); border-radius: 0; filter: drop-shadow(0 6px 10px rgba(4, 10, 30, 0.4)) drop-shadow(0 20px 30px rgba(4, 10, 30, 0.5)); }
.cred__stage .frame--main::after { box-shadow: none; }
.cred__stage .frame--ghost { inset: auto; bottom: 0; right: 0; transform: none; clip-path: var(--clip-notch); }
/* name plate overlaid on the photo, like the hero's trust chips */
.cred__namecard { position: absolute; z-index: 5; bottom: 8%; left: -5%; margin: 0; display: grid; gap: 0.1rem; padding: 0.6rem 1.05rem; background: rgba(255, 255, 255, 0.92); -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); border: 1px solid rgba(255, 255, 255, 0.55); border-radius: var(--radius-md); box-shadow: 0 2px 6px -2px rgba(6, 15, 42, 0.28), 0 14px 28px -8px rgba(6, 15, 42, 0.5); }
.cred__namecard-name { font-size: var(--text-base); font-weight: var(--fw-bold); color: var(--color-ink); letter-spacing: var(--tracking-tight); line-height: 1.15; }
.cred__namecard-role { font-size: var(--text-xs); font-weight: var(--fw-semibold); color: var(--color-ink-soft); }
@media (max-width: 560px) { .cred__streams { grid-template-columns: 1fr; gap: var(--space-6); } }

/* Credibility composite entrance — the scroll-triggered twin of the hero's
   on-load assembly. Same structure (photo + offset panel + name plate), so it
   earns the same front-to-back choreography: the portrait lands first, the blue
   panel slides out from behind it, the name plate pops in last. Reuses the hero
   keyframes; gated on the reveal observer's .is-in so it fires when the section
   scrolls into view (the hero fires on load — it's above the fold). */
@media (prefers-reduced-motion: no-preference) {
  /* the container is only the observer hook now — its children carry the motion,
     so it must not also fade/rise as a block (that would double-shift everything) */
  html.js .cred__media[data-reveal] { opacity: 1; transform: none; }
  html.js .cred__media[data-reveal] .frame--main,
  html.js .cred__media[data-reveal] .frame--ghost,
  html.js .cred__media[data-reveal] .cred__namecard { opacity: 0; }

  html.js .cred__media.is-in .frame--main {
    animation: hero-rise 0.7s var(--ease-out) both;
    animation-delay: 0.05s;                 /* portrait lands first */
  }
  html.js .cred__media.is-in .frame--ghost {
    animation: hero-panel 0.66s var(--ease-out) both;
    animation-delay: 0.24s;                 /* panel slides out from behind it */
  }
  html.js .cred__media.is-in .cred__stage:nth-child(2) .frame--main { animation-delay: 0.22s; }
  html.js .cred__media.is-in .cred__stage:nth-child(2) .frame--ghost { animation-delay: 0.4s; }
  html.js .cred__media.is-in .cred__stage:nth-child(2) .cred__namecard { animation-delay: 0.52s; }
  html.js .cred__media.is-in .cred__namecard {
    animation: hero-pop 0.5s var(--ease-out) both;
    animation-delay: 0.46s;                 /* name plate pops in last */
  }
}

/* ---------------- FAQ ---------------------------------------------------- */
.faq__grid { display: grid; grid-template-columns: 0.8fr 1.2fr; gap: clamp(2rem, 5vw, 4rem); align-items: start; }
/* the head pins while the (long) accordion scrolls past it; the section carries
   section--flow so .section's overflow:clip doesn't kill the sticky */
.faq__grid .section__head { margin-bottom: 0; position: sticky; top: calc(var(--header-h) + var(--space-5)); align-self: start; }

/* ---------------- Closing CTA ------------------------------------------- */
.cta {
  position: relative;
  text-align: center;
  padding: clamp(3rem, 4vw, 5rem) var(--container-pad);
  border-radius: var(--radius-xl);
  background: var(--grad-deep);
  color: var(--brand-white);
  overflow: clip;
  /* light top edge + soft ambient depth so the card lifts off its section
     (reads on both white and dark grounds) */
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.18), 0 26px 64px -28px rgba(0,0,0,0.6);
}
.cta .halftone { inset: 0; opacity: 0.12; color: var(--brand-white); }
.cta__inner { position: relative; max-width: 48rem; margin-inline: auto; }
.cta h2 { font-size: var(--text-3xl); font-weight: var(--fw-extra); letter-spacing: var(--tracking-tight); overflow-wrap: break-word; }
.cta p { margin-top: var(--space-4); max-width: var(--measure-narrow); margin-inline: auto; color: rgba(255,255,255,0.86); font-size: var(--text-lg); }
.cta .btn { margin-top: var(--space-8); background-image: none; background-color: var(--brand-white); color: var(--color-primary-deep); box-shadow: var(--shadow-lg); }
.cta .btn::after { content: none; } /* opt out of the blue overlay; stays white */
.cta .btn:hover { background-color: var(--color-on-dark); }
/* .btn is nowrap everywhere else, but the longest closing label ("Schedule a
   30-Minute Capacity Preview") is wider than the card at phone widths and runs
   straight off its rounded edge. This one button is allowed to wrap; above the
   breakpoint there is room, so it still sets on one line. */
.cta .btn,
.hero__actions .btn { max-width: 100%; }
@media (max-width: 700px) {
  .cta .btn,
  .hero__actions .btn { white-space: normal; line-height: 1.3; }
}

/* ---------------- Responsive -------------------------------------------- */
@media (max-width: 880px) {
  .hero__grid, .cred__grid, .faq__grid { grid-template-columns: 1fr; }
  .faq__grid .section__head { position: static; }
  .triad { grid-template-columns: 1fr; }

  /* Composites FILL the column. A fixed px cap here (this used to be 480px)
     leaves dead space beside the photo at tablet widths, which reads as broken.
     Height comes from the ratio instead, kept wide so a full-bleed image
     doesn't become a slab; there's no copy alongside to stretch to. */
  .hero__media { max-width: none; width: 100%; height: auto; min-height: 0; }
  .hero__stage { height: auto; aspect-ratio: 3 / 2; }

  /* lead with the faces, and sit the two founders side by side rather than stacked.
     width/justify-self, NOT margin-inline: auto — auto margins on a grid item kill
     stretch and collapse the track to fit-content (0 with absolute children). */
  .cred__media { order: -1; height: auto; width: 100%;
                 grid-template-rows: none; grid-template-columns: 1fr 1fr;
                 gap: clamp(0.85rem, 3vw, 1.75rem); }
  .cred__stage { height: auto; aspect-ratio: 4 / 5; max-width: none; width: 100%; min-height: 0; --peek: 1rem; }
  /* namecard shrinks with the frame and is inset so it can't overhang a narrow column */
  .cred__namecard { left: 5%; right: 5%; bottom: 5%; padding: 0.4rem 0.65rem; }
  .cred__namecard-name { font-size: var(--text-sm); }
  .cred__namecard-role { font-size: 0.66rem; line-height: 1.25; }
}
/* Smallest phones: the column is narrow enough that a taller crop reads well
   again, and the namecard has to stay a caption, not a slab over the portrait. */
@media (max-width: 560px) {
  .hero__stage { aspect-ratio: 5 / 4; }
  .cred__namecard { padding: 0.35rem 0.5rem; }
  .cred__namecard-name { font-size: 0.82rem; }
  .cred__namecard-role { font-size: 0.6rem; white-space: nowrap; }
}
/* below ~360 the card is too narrow to hold the role on one line */
@media (max-width: 374px) {
  .cred__namecard-role { white-space: normal; }
}

/* ---------------- Ways to take it (ledger row sold by format) ------------ */
/* Hallmark · component: ways · system: CT Innovates (locked tokens)
 * The middle ledger row has no rate by design. Left in .price it rendered a
 * label above an absent figure, which reads as a failed render rather than a
 * deliberate omission. Same column, same label idiom, same right alignment --
 * three real lines instead of one caption. */
.ways { --price-align: end; text-align: right; align-self: end; display: grid; gap: var(--space-2); }
.ways__label {
  font-size: var(--text-xs);
  font-weight: var(--fw-bold);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--color-primary-deep);
}
.ways__list { display: grid; gap: var(--space-1); list-style: none; }
.ways__list li { font-size: var(--text-sm); line-height: 1.5; color: var(--color-ink); }
.on-dark .ways__label { color: var(--brand-blue-400); }
.on-dark .ways__list li { color: var(--color-on-dark); }
@media (max-width: 880px) { .ways { text-align: left; --price-align: start; } }

/* ---------------- Yours to keep: give the list its own rhythm ------------ */
/* The head column runs tall and the list ran short and loose, so the two sides
   of the strip read as unrelated. Hairlines turn the list into a ledger that
   holds its own vertical weight against the copy beside it. */
.keep-strip__list { gap: 0; }
.keep-strip__list li { padding-block: var(--space-4); align-items: center; }
.keep-strip__list li + li { border-top: 1px solid var(--color-line-dark); }
.keep-strip__list li:first-child { padding-top: 0; }
.keep-strip__list li:last-child { padding-bottom: 0; }
