/* =================================================================
   SECTIONS - page chrome, ATF, the process loop, CTA

   Sections are white modules floating on the tinted page. That
   separation is the modularity; the shadow is the depth.
   ================================================================= */

/* -- SECTION MODULE --------------------------------------------------- */

.section {
  max-width: var(--page-max);
  margin: 0 auto var(--sp-4);
  padding: var(--sp-7) var(--gutter);
  background: var(--surface);
  border: 1px solid var(--border);
  border-bottom-color: var(--border-bottom);
  border-radius: var(--radius-lg);
  box-shadow: var(--e3), var(--highlight-top);
  scroll-margin-top: 76px;
}

@media (min-width: 768px) {
  .section { padding: var(--sp-8) var(--sp-8); }
}

/* ATF is not a module - it's the page opening onto the tint. */
.section--open {
  background: transparent;
  border: 0;
  box-shadow: none;
  padding-top: var(--sp-4);
}

.section__head {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  margin-bottom: var(--sp-6);
  /* Wrap is for the tagged heads only: on a narrow screen the pill
     drops to its own line rather than crushing the heading. */
  flex-wrap: wrap;
}

/* The gradient index badge - one per section. */
.section__index {
  flex: none;
  display: grid;
  place-items: center;
  width: 38px; height: 38px;
  border-radius: var(--radius-sm);
  background: var(--grad-brand-solid);
  color: var(--text-on-brand);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  font-weight: 600;
  box-shadow: var(--e-brand);
}

.section__heading { margin: 0; }

/* The section's short name, pushed to the far end of the head row
   opposite the heading. The heading says what the section does; the
   pill carries the word the menu uses, so the two stay findable
   from each other. Grey, not brand — a name tag, not an accent, and
   an opaque fill so it reads as a chip on the white surface. */
.section__tag {
  margin-left: auto;
  flex: none;
  padding: var(--sp-2) var(--sp-4);
  background: var(--surface-sunken);
  border: 0.5px solid var(--border-strong);
  border-radius: var(--radius-pill);
  font-size: var(--fs-small);
  line-height: 1.5;
  color: var(--text-muted);
}

/* -- BLOCKS INSIDE A SECTION ------------------------------------------- */

.block { margin-top: var(--sp-8); }
.block:first-of-type { margin-top: 0; }

.block__head { margin-bottom: var(--sp-4); }

/* Short gradient keyline under a block heading. */
.block__heading {
  position: relative;
  padding-bottom: var(--sp-3);
  margin-bottom: var(--sp-3);
}
.block__heading::after {
  content: '';
  position: absolute;
  left: 0; bottom: 0;
  width: 44px; height: 3px;
  border-radius: var(--radius-pill);
  background: var(--grad-brand-line);
}

.block__label {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--brand-deep);
  margin: var(--sp-6) 0 var(--sp-3);
}

.block > .framework { margin-top: var(--sp-4); }
.block > .prose { margin-top: var(--sp-4); }

/* -- SCROLL NAV ----------------------------------------------------------- */

.scrollnav {
  position: sticky;
  top: var(--sp-3);
  z-index: 30;
  display: flex;
  gap: var(--sp-1);
  width: max-content;
  max-width: calc(100% - var(--gutter) * 2);
  margin: 0 auto var(--sp-4);
  padding: var(--sp-2);
  overflow-x: auto;
  background: rgba(255, 255, 255, 0.82);
  backdrop-filter: blur(14px);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  box-shadow: var(--e2), var(--highlight-top);
  scrollbar-width: none;
}
.scrollnav::-webkit-scrollbar { display: none; }

.scrollnav a {
  flex: none;
  padding: var(--sp-2) var(--sp-4);
  border-radius: var(--radius-pill);
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--text-secondary);
  transition: background var(--dur-fast) var(--ease),
              color var(--dur-fast) var(--ease);
}
.scrollnav a:hover {
  background: var(--surface-brand-tint);
  color: var(--brand-deep);
}
.scrollnav a[aria-current="true"] {
  background: var(--grad-brand-solid);
  color: var(--text-on-brand);
  box-shadow: var(--e1);
}

/* =================================================================
   PROCESS — circular loop navigator (14 Aug build spec)

   Case Study merged into Process: one component, a 5-stage ring with
   a Case study / Framework lens toggle. #process overrides the
   sitewide .section radius (20px) down to the spec's 12px; surface,
   border, shadow, and scroll-margin all stay inherited from .section.

   Ring is desktop-only, list is mobile-only — both exist in the DOM
   always, toggled purely by the breakpoint below. Node clicks and
   lens clicks share one {stage, lens} state, read from data
   attributes on `.loopnav` — see render.js's wireLoopNav().
   ================================================================= */

#process.section { border-radius: 12px; }

/* Holds only the lens toggle now — the section head above it is the
   standard "02 Process" badge + heading, same as every other
   section. Superseded with the headline: .loopnav__eyebrow,
   .loopnav__title and .loopnav__subhead. */
.loopnav__head {
  display: flex;
  justify-content: flex-end;
  align-items: flex-start;
  gap: var(--sp-5);
}

/* Lens toggle — visually secondary on purpose: small type, muted
   inactive state, no accent fill competing with the ring itself. */
.loopnav__lens {
  flex: none;
  display: flex;
  gap: 2px;
  padding: 3px;
  background: var(--surface-sunken);
  border-radius: var(--radius-pill);
  box-shadow: var(--e-sunken);
}
.loopnav__lens-btn {
  padding: 6px 14px;
  border-radius: var(--radius-pill);
  font-size: var(--fs-micro);
  font-weight: 600;
  color: var(--text-muted);
  transition: background var(--dur-base) var(--ease), color var(--dur-base) var(--ease);
}
.loopnav__lens-btn[aria-selected="true"] {
  background: var(--surface);
  color: var(--text-primary);
  box-shadow: var(--e1);
}

/* -- View switch: ring desktop, list mobile — dropped, not shrunk --
   Breakpoint is 1200px, not the sitewide 768px: the ring's interior
   frame only reaches the width its content actually fits (~588px)
   once .loop2 itself is ~1050px wide. Below that the frame gets
   squeezed into a tall, narrow well faster than the ring shrinks,
   which forced a scrollbar inside it. The list view has no fixed box
   and reads fine at any width, so it now owns the whole tablet range
   too. */
.loopnav__ring-view { display: none; }
.loopnav__list-view { display: block; }

@media (min-width: 1200px) {
  .loopnav__ring-view { display: block; }
  .loopnav__list-view { display: none; }
}

/* -- The ring ------------------------------------------------------------
   .loop2 spans the section's full content width; the ring drawn inside
   it (2×RING_R, r=46.5 in render.js) is 93% of that box, leaving the
   other 7% as room for labels to sit outside the stroke without
   crossing the section's own edge. */
.loop2 {
  position: relative;
  width: 100%;
  aspect-ratio: 1 / 1;
  margin: var(--sp-7) auto var(--sp-6);
}

/* Stroke widths here are in viewBox USER UNITS, not pixels — the
   viewBox is 0 0 100 100 scaled up to the ring's rendered size, so
   1 unit ≈ 10.5px at desktop. Hence the sub-1 values.

   Neither may use `vector-effect: non-scaling-stroke`. On the progress
   ring it is actively broken: it renders the stroke, dash pattern
   included, in device pixels, so a user-unit dasharray tiles ~5x
   around the circle and dashoffset slides those tiles rather than
   growing one arc. The background circle stays consistent with it so
   both strokes scale together. */
.loop2__ring { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.loop2__ring-bg { fill: none; stroke: var(--border); stroke-width: 0.12; }

/* One dash and one gap, each a full turn of the circle (set from the
   measured length in initProgressRing()), so the only thing that ever
   moves is where that single dash starts. Ease-in-out rather than the
   sitewide ease-out (or a flat linear sweep) — the arc eases into the
   move and settles into the next node instead of snapping at a
   constant speed or lunging then crawling. */
.loop2__ring-progress {
  fill: none;
  stroke: var(--brand-indigo);
  stroke-width: 0.3;
  stroke-linecap: butt;
  transition: stroke-dashoffset 450ms ease-in-out;
}

.loop2__nodes { position: absolute; inset: 0; }

/* Solid fill, not the sitewide gradient — see the block comment at
   the top of renderProcess() in render.js for why: a transition
   between two different gradients doesn't tween, it just snaps, which
   is what made the highlight read as "not animating" before. Solid
   colour transitions cleanly, so the click-through motion is now
   actually visible instead of an instant colour swap. */
.loop2__node {
  position: absolute;
  left: var(--x); top: var(--y);
  transform: translate(-50%, -50%);
  width: 44px; height: 44px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--text-secondary);
  box-shadow: var(--e2);
  transition: background-color 420ms var(--ease),
              box-shadow var(--dur-base) var(--ease),
              transform var(--dur-base) var(--ease);
}
.loop2__node:hover { transform: translate(-50%, -50%) scale(1.06); }
.loop2__node-num {
  font-family: var(--font-mono);
  font-size: var(--fs-small);
  font-weight: 700;
  color: var(--text-on-brand);
  transition: color 420ms var(--ease);
}

/* Active reads brightest (glow); passed is the same accent fill,
   just without the glow, so the two stay legible apart without
   relying on colour alone. */
.loop2__node.is-active, .loop2__node.is-passed {
  background-color: var(--brand-indigo);
}
.loop2__node.is-active { box-shadow: var(--e-brand); }

/* Label anchors outward from its own node (render.js sets --cos/--sin/
   --shift — see the comment there) rather than sitting on a separate
   fixed-width radius, which is what pushed labels outside the
   container before. Weight/size/tracking now match the sitewide h4 —
   same treatment as every other section heading, not a one-off. */
.loop2__node-label {
  position: absolute;
  left: var(--x); top: var(--y);
  transform: translate(calc(var(--shift) + var(--cos) * 34px), calc(-50% + var(--sin) * 34px));
  width: auto;
  white-space: nowrap;
  font-size: var(--fs-body);
  font-weight: 640;
  letter-spacing: -0.015em;
  color: var(--text-primary);
  pointer-events: none;
  transition: color 420ms var(--ease), font-weight var(--dur-base) var(--ease);
}
.loop2__node-label.is-active, .loop2__node-label.is-passed {
  color: var(--brand-indigo);
}
.loop2__node-label.is-active { font-weight: 680; }

/* -- Interior well — the artifact renders INSIDE the ring, no caption
   underneath it now — the frame is the whole zone.

   Sizing math (at ~1050px, the section's typical desktop content
   width): the ring radius is 46.5% (r≈488px); with no caption to
   budget for, the only margin kept is a flat ~18px gap to the ring
   itself (the "15-20px from the edge" ask), leaving a safe corner
   radius of ~470px. The largest 4:5 rectangle inscribed in a circle
   of that radius solves to w ≈ 587px, i.e. 56% of .loop2 — this is a
   corner-to-edge distance, not a node-clearance one, so the frame's
   own rounded corners (below) are what keep it from visually
   crunching into the Script/Produce nodes, whose angle happens to
   sit close to the rectangle's corner angle. */
.loop2__well {
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: 56%;
  display: grid;
  justify-items: center;
}
.loop2__well-panel[hidden] { display: none; }
.loop2__well-panel {
  display: grid;
  justify-items: center;
  gap: var(--sp-3);
  width: 100%;
  opacity: 1;
  transition: opacity 225ms ease-in-out;
}
/* Cross-fade driven by render.js swapWellPanels() — 225ms out, then
   225ms back in once the incoming panel is unhidden, totalling the
   same 450ms as the ring's own stroke-dashoffset transition so the
   content finishes changing right as the arc settles. */
.loop2__well-panel--fading { opacity: 0; }

/* Carries the real per-stage case-study breakdown (render.js's
   caseStudyWell()) — no longer an empty decorative box. Content
   length varies wildly stage to stage (Research runs to eight
   fields, Produce is two lines), so overflow scrolls INSIDE the
   frame rather than resizing it: the 4:5 box is what the ring's
   node-clearance math up above was solved for, and that math goes
   stale the moment the box grows with its content. */
.loop2__artifact-frame {
  position: relative;
  width: 100%;
  aspect-ratio: 4 / 5;
  border-radius: var(--radius-lg);
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  box-shadow: var(--e2);
  overflow-y: auto;
  padding: var(--sp-4);
  text-align: left;
}
/* Header row — index badge left, "Next" right. A flex row rather than
   absolute positioning so "Next" still lands correctly on the mobile
   list, where the index badge is hidden (below) and there'd be
   nothing to position "top-right of" otherwise: the index carries its
   own `margin-right: auto`, so it's the one that pushes "Next" to the
   edge when present, and `justify-content: flex-end` on the row is
   what keeps "Next" there when the index is gone. */
.loop2__case-head {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--sp-2);
  margin-bottom: var(--sp-2);
}
/* Special-styled index badge — the stage number in mono brand-indigo,
   the name in bold near-black, so the frame is self-identifying even
   scrolled to mid-content. Hidden on the mobile list, which already
   prints its own numbered h3 immediately above this same well (see
   .loopnav__list-body). */
.loop2__case-index {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  margin-right: auto;
}
.loop2__case-index-num {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  font-weight: 700;
  color: var(--brand-indigo);
}
.loop2__case-index-label {
  font-size: var(--fs-small);
  font-weight: 700;
  color: var(--text-primary);
}
.loopnav__list-well .loop2__case-index { display: none; }

/* "Next" — the only other way to move through the ring is clicking a
   node, and nothing about the nodes themselves signals "click me."
   Sits in the frame's header row (above), not stapled to the bottom
   of whatever content happens to end there. No arrow glyph — the
   pill shape and corner position already say "forward" without one. */
.loop2__case-next {
  flex: none;
  padding: 6px var(--sp-4);
  border-radius: var(--radius-pill);
  background: var(--surface-brand-tint);
  border: 1px solid var(--border-brand);
  box-shadow: var(--e2);
  font-size: var(--fs-micro);
  font-weight: 700;
  color: var(--brand-deep);
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease),
              box-shadow var(--dur-fast) var(--ease);
}
.loop2__case-next:hover { background: var(--brand-indigo-a12); }
.loop2__case-next:focus-visible {
  outline: 2px solid var(--brand-indigo);
  outline-offset: 2px;
}

/* Brief-link pill (Script/Produce headers) — same 6px vertical padding
   and micro font-size as `.loop2__case-next` above, so the two sit at
   identical height in the row, immediately next to each other. */
.loop2__case-brief {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px 6px 8px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--border-strong);
  background: var(--surface);
  font-size: var(--fs-micro);
  font-weight: 600;
  color: var(--text-secondary);
  text-decoration: none;
  white-space: nowrap;
  transition: border-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.loop2__case-brief:hover { border-color: var(--brand-indigo); color: var(--brand-indigo); }
.loop2__case-brief:focus-visible {
  outline: 2px solid var(--brand-indigo);
  outline-offset: 2px;
}
.loop2__case-brief img { display: block; width: 16px; height: 16px; flex: none; object-fit: contain; }
.loop2__case-brief svg {
  width: 12px; height: 12px; flex: none;
  fill: none; stroke: currentColor; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
}
.loop2__case-title {
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--text-primary);
  margin: 0 0 var(--sp-3);
}

/* -- Hero: one visualised finding per stage, 21 Aug 2026 revision --
   Sits between the title and the collapsed evidence rows below. Each
   type is its own small component; `.loop2__hero` just supplies the
   shared bottom margin so every variant sits the same distance from
   the fields underneath it. */
.loop2__hero { margin-bottom: var(--sp-4); }

/* Script: the beat spine — a vertical rail with a dot per beat and
   the line that carries out of it, in the beat's own small quote. */
.loop2__hero--beats {
  position: relative;
  display: grid;
  gap: var(--sp-3);
  margin: 0 0 var(--sp-4);
  padding: 0 0 0 var(--sp-4);
  list-style: none;
}
.loop2__hero--beats::before {
  content: '';
  position: absolute;
  left: 3px; top: 6px; bottom: 6px;
  width: 1px;
  background: var(--border-strong);
}
.loop2__beat { position: relative; }
.loop2__beat::before {
  content: '';
  position: absolute;
  left: calc(-1 * var(--sp-4) + 0px);
  top: 5px;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--brand-indigo);
}
.loop2__beat-name {
  display: block;
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--text-primary);
}
.loop2__beat-transition {
  display: block;
  margin-top: 2px;
  font-size: var(--fs-micro);
  font-style: italic;
  color: var(--text-secondary);
}

/* Produce: the brief as a document, not padded-out bullets — a sparse
   card is correct here, the stage genuinely was this thin. */
.loop2__hero--doc { display: flex; justify-content: center; }
.loop2__doc-card {
  display: grid;
  justify-items: center;
  gap: var(--sp-2);
  width: 100%;
  padding: var(--sp-5) var(--sp-4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  text-align: center;
}
.loop2__doc-mark { width: 28px; height: 28px; }
.loop2__doc-title {
  margin: 0;
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--text-primary);
}
.loop2__doc-status { margin: 0; font-size: var(--fs-micro); color: var(--text-secondary); }

/* Review: the retention curve — one steep segment coloured and
   labelled, since that span is the whole diagnosis below it. */
.loop2__hero--curve { display: grid; gap: var(--sp-2); }
.loop2__curve { display: block; width: 100%; height: 90px; overflow: visible; }
.loop2__curve-line { fill: none; stroke: var(--text-faint); stroke-width: 1.4; }
.loop2__curve-line--hi { stroke: var(--brand-indigo); stroke-width: 2; }
.loop2__curve-dot { fill: var(--brand-indigo); }
.loop2__curve-labels {
  display: flex;
  justify-content: space-between;
  gap: var(--sp-2);
  font-size: 10px;
  color: var(--text-secondary);
}
.loop2__curve-labels span:first-child { text-align: left; }
.loop2__curve-labels span:last-child { text-align: right; }
.loop2__curve-callout {
  justify-self: center;
  padding: 3px var(--sp-2);
  background: var(--surface-brand-tint);
  border-radius: var(--radius-pill);
  font-size: var(--fs-micro);
  font-weight: 600;
  color: var(--brand-deep);
}

/* Fields are collapsible `.expand` rows now (render.js), not a dl —
   the label lives in `.expand__trigger`'s own brand-indigo/bold
   styling, so there's no separate muted label colour to darken.
   `.loop2__case-part` is one named sub-field inside a grouped row
   (Script's "Language & VOC" / "Narrative craft") — same body markup,
   one indent level, a small label instead of its own trigger. */
.loop2__case-fields { display: grid; min-width: 0; }
.loop2__case-fields .expand:first-child { border-top: none; margin-top: 0; }
.loop2__case-part + .loop2__case-part { margin-top: var(--sp-3); }
.loop2__case-part-label {
  margin: 0 0 2px;
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.loop2__case-list { display: grid; gap: var(--sp-1); margin: 0; padding: 0; }
.loop2__case-list li {
  min-width: 0;      /* li is itself a grid item of the list above —
                         same shrink-to-fit fix as the concept cells */
  padding-left: var(--sp-4);
  position: relative;
}
.loop2__case-list li::before {
  content: '';
  position: absolute;
  left: 2px; top: 0.55em;
  width: 4px; height: 4px;
  border-radius: 50%;
  background: var(--brand-sky);
}
/* Research's pill accordion (render.js wireAccordionGroups) — a
   dedicated `.expand--pill` variant of the plain `.expand` list row,
   scoped to the Research stage only. Each field is its own rounded,
   bordered card instead of a bordered-top list stack; the open one
   lifts onto the brand tint with a stronger border and shadow so it
   reads as "selected" against its closed siblings, not just "taller".
   Exactly one is open at all times — see the JS for why clicking the
   open row is a no-op. */
.loop2__case-accordion {
  display: grid;
  gap: var(--sp-2);
}
/* Concept's cards (render.js caseFieldsCards()) — all four fields
   visible at once, each its own rounded, bordered container, stacked
   full-width rather than Research's single-open accordion (there's
   nothing here worth hiding). The hover treatment is the sitewide
   `.card` idiom (components.css) scaled down for a nested list item:
   same border-color step and gradient top-edge reveal, no lift — one
   universal hover style, applied identically to every card here. */
.loop2__concept-cards { display: grid; gap: var(--sp-2); }
.loop2__concept-card {
  position: relative;
  min-width: 0;
  overflow: hidden;
  padding: var(--sp-3);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-xs);
  box-shadow: var(--e1);
  transition: border-color var(--dur-base) var(--ease), box-shadow var(--dur-base) var(--ease);
}
.loop2__concept-card::before {
  content: '';
  position: absolute;
  inset: 0 0 auto 0;
  height: 2px;
  background: var(--grad-brand-line);
  opacity: 0;
  transition: opacity var(--dur-base) var(--ease);
}
.loop2__concept-card:hover {
  border-color: var(--border-strong);
  box-shadow: var(--e2);
}
.loop2__concept-card:hover::before { opacity: 1; }
.loop2__concept-card .loop2__concept-label {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-secondary);
}
/* Per-card index — the same gradient-badge idiom as `.section__index`
   (sections.css), scaled down for an inline label instead of a
   section head. Circle, not the section badge's rounded square, so
   it doesn't read as a second one of those at a smaller size. */
.loop2__concept-num {
  flex: none;
  display: grid;
  place-items: center;
  width: 18px; height: 18px;
  border-radius: var(--radius-pill);
  background: var(--grad-brand-solid);
  color: var(--text-on-brand);
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0;
  text-transform: none;
}
.loop2__concept-card p { margin: 0; font-size: var(--fs-small); color: var(--text-primary); }
.loop2__concept-card .loop2__case-list { font-size: var(--fs-small); color: var(--text-primary); }
.expand--pill {
  position: relative;
  margin-top: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--e1);
  overflow: hidden;
  transition: background var(--dur-base) var(--ease),
              border-color var(--dur-base) var(--ease),
              box-shadow var(--dur-base) var(--ease);
}
.expand--pill .expand__trigger {
  padding: var(--sp-3) var(--sp-4);
  color: var(--text-primary);
  font-weight: 600;
  cursor: pointer;
}
.expand--pill .expand__trigger:hover { color: var(--brand-deep); }
.expand--pill .expand__trigger:focus-visible {
  outline: 2px solid var(--brand-indigo);
  outline-offset: -2px;
  border-radius: var(--radius-sm);
}
.expand--pill .expand__trigger::after { background-color: var(--surface-sunken); }
.expand--pill .expand__inner > * { padding: 0 var(--sp-4) var(--sp-4); }
.expand--pill[data-open="true"] {
  background: var(--surface-brand-tint);
  border-color: var(--border-brand);
  box-shadow: var(--e-brand);
}
.expand--pill[data-open="true"] .expand__trigger { color: var(--brand-deep); }
.expand--pill[data-open="true"] .expand__trigger::after {
  background-color: var(--surface);
  box-shadow: inset 0 0 0 1px var(--border-brand);
}

/* The artifact link now sits at the end of real scrolling content
   (Produce/Review only) rather than floating over an empty frame —
   still the same tinted pill, just in flow instead of an absolute
   corner overlay. */
.loop2__artifact-frame .loopnav__artifact-link {
  position: static;
  display: inline-flex;
  margin-top: var(--sp-4);
}
.loop2__well-bullets {
  display: grid;
  gap: var(--sp-2);
  width: 100%;
  font-size: var(--fs-small);
  color: var(--text-secondary);
  text-align: left;
}
.loop2__well-bullets li {
  min-width: 0;    /* li is a grid item of the list above — without
                       this it won't shrink to fit and can overflow
                       the well on narrow widths (same fix as the
                       case-study fields; see the comment there) */
  padding-left: var(--sp-4);
  position: relative;
}
.loop2__well-bullets li::before {
  content: '';
  position: absolute;
  left: 2px; top: 0.6em;
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--brand-sky);
}
/* One level of nesting — Research's "Segment themes analysis" is the
   first bullet to use it. Same list language, indented and a step
   smaller so it reads as detail under the parent line. */
.loop2__well-bullets--sub {
  margin-top: var(--sp-2);
  padding-left: var(--sp-4);
  font-size: var(--fs-micro);
}
.loop2__well-bullets--sub li::before { background: var(--text-faint); }
.loopnav__principle-line {
  margin: 0;
  padding: var(--sp-3) var(--sp-4);
  background: var(--surface-brand-tint);
  border: 1px solid var(--border-brand);
  border-radius: var(--radius-sm);
  font-size: var(--fs-small);
  font-weight: 500;
  color: var(--brand-deep);
  text-align: center;
}
/* Overlaid in the frame's own bottom-right corner — a tinted pill on
   the flat sunken frame, not extra height stacked below it. */
.loopnav__artifact-link {
  position: absolute;
  right: var(--sp-3);
  bottom: var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--radius-pill);
  background: var(--surface);
  box-shadow: var(--e1);
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--brand-indigo);
}
.loopnav__artifact-link:hover { color: var(--brand-deep); }

/* -- Mobile: vertical numbered list, ring dropped entirely -------------- */
.loopnav__list { display: grid; gap: var(--sp-6); margin-top: var(--sp-5); }
.loopnav__list-item { display: grid; grid-template-columns: 28px 1fr; gap: var(--sp-4); }
.loopnav__list-num {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  font-weight: 700;
  color: var(--brand-deep);
}
.loopnav__list-body h3 { margin-bottom: var(--sp-3); }
.loopnav__list-well[hidden] { display: none; }
.loopnav__list-well {
  display: grid;
  justify-items: start;
  gap: var(--sp-3);
  width: 220px;
  max-width: 60%;
  opacity: 1;
  transition: opacity 225ms ease-in-out;
}
.loopnav__list-well.loop2__well-panel--fading { opacity: 0; }
.loopnav__list-well .loop2__well-bullets { width: 100%; max-width: none; }
.loopnav__list-well .loopnav__principle-line { width: 100%; text-align: left; }
/* The case-study frame carries real paragraphs now — the 220px/60%
   box above was sized for an empty decorative square, not readable
   text. Widen it to the full column and drop the fixed 4:5 ratio —
   list view has no ring geometry to protect, so the frame just grows
   to fit its content instead of capping height and scrolling
   internally (a 360px cap forced an inner scrollbar on every stage
   but Produce once list view started covering 768-1199px too). */
.loopnav__list-well:has(.loop2__artifact-frame) { width: 100%; max-width: none; }
.loopnav__list-well .loop2__artifact-frame {
  width: 100%;
  aspect-ratio: auto;
  max-height: none;
  overflow-y: visible;
}

/* -- Script stage — timeline rail + single-open act rows ----------------
   Bespoke to this one stage (render.js scriptStageBody/wireScriptStage),
   script-stage-spec.md 25 Aug 2026. Still lives inside the shared
   `.loop2__artifact-frame` (sunken background, internal scroll on the
   ring; grows free on the mobile list — see the `:has()` rule above),
   so its own background stays transparent throughout. */
.script-stage { text-align: left; }
.script-stage__body {
  display: grid;
  grid-template-columns: 32px minmax(0, 1fr);
  gap: 0 var(--sp-3);
}

/* Rail: a hairline line from act 01's node centre to act 07's, plus a
   second accent-coloured overlay clipped to the travelled height —
   `--script-progress` (set by wireScriptStage's reposition()) is the
   distance from the first node centre to the active one, so the
   overlay's own height IS the progress indicator, no separate JS
   drawing needed. Node/line positions are all `top` values in JS
   pixels (render.js measures each header's real box — collapsed row
   heights vary with excerpt/analysis line count, so a fixed per-row
   spacing would drift out of sync with the actual rows next to it). */
.script-rail { position: relative; }
.script-rail__line {
  position: absolute;
  left: 50%;
  width: 1px;
  transform: translateX(-50%);
  background: var(--border-strong);
}
.script-rail__line::after {
  content: '';
  position: absolute;
  left: 0; top: 0;
  width: 1px;
  height: var(--script-progress, 0px);
  background: var(--brand-indigo);
}
.script-rail__node {
  position: absolute;
  left: 50%;
  width: 7px; height: 7px;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  border: 1px solid var(--border-strong);
  background: var(--surface-sunken);
  transition: width var(--dur-fast) var(--ease), height var(--dur-fast) var(--ease),
              background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.script-rail__node[data-state="visited"] { background: var(--border-strong); }
.script-rail__node[data-state="active"] {
  width: 9px; height: 9px;
  border-color: var(--brand-indigo);
  background: var(--brand-indigo);
}

.script-acts { display: grid; }
.script-act + .script-act { border-top: 1px solid var(--border); }
.script-act__header {
  display: block;
  width: 100%;
  padding: var(--sp-2) 0;
  background: none;
  border: none;
  text-align: left;
  cursor: pointer;
}
.script-act__header:focus-visible {
  outline: 2px solid var(--brand-indigo);
  outline-offset: 2px;
  border-radius: var(--radius-xs);
}
/* Label + line-count sit on one row now (25 Aug 2026) — the count was
   a verbose "Full act — N lines" row of its own at the bottom, adding
   a full extra line of padding to every collapsed row for no reading
   value. `+N`/`−` here is deliberately terse: noticeable, not a
   sentence. */
.script-act__toprow {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-2);
  margin-bottom: var(--sp-2);
}
.script-act__label {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  color: var(--brand-indigo);
}
.script-act__count {
  flex: none;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  color: var(--text-muted);
  transition: color var(--dur-fast) var(--ease);
}
.script-act[data-open="true"] .script-act__count { color: var(--brand-indigo); }
.script-act__excerpt {
  margin: 0 0 var(--sp-2);
  padding-left: var(--sp-3);
  border-left: 2px solid var(--brand-indigo-a20);
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-primary);
}
/* Act 03's excerpt — the line the ad hinges on — gets the full-strength
   rule instead of the tint every other act uses. */
.script-act__excerpt--strong { border-left-color: var(--brand-indigo); }
.script-act__analysis {
  margin: 0;
  font-size: 12px;
  color: var(--text-secondary);
}

/* Height animates via a JS-measured max-height (180ms, matches every
   other timed motion on the page) rather than `height:auto`, which
   can't transition. Always in the DOM with `hidden` toggled once the
   animation settles — never conditionally rendered — so the full act
   text stays searchable and indexable even collapsed. */
.script-act__panel {
  overflow: hidden;
  max-height: 0;
  transition: max-height 180ms ease-out;
}
.script-act__full { padding-top: var(--sp-2); padding-bottom: var(--sp-3); }
.script-act__line {
  margin: 0 0 var(--sp-1);
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-secondary);
}
.script-act__line.is-excerpt { color: var(--brand-indigo); }

@media (max-width: 600px) {
  .script-rail__line { display: none; }
}

/* -- Produce stage — brief link, primary cut, build chain ---------------
   Bespoke to this one stage (render.js produceStageBody/wireProduceStage),
   produce-stage-spec.md 25 Aug 2026. Same shared frame shell as Script
   (see caseFrameShell) — only the body is stage-specific. Reuses the
   sitewide `.frame`/`.frame__inner`/`.case__video`/`.case__play` video
   player unchanged; only the sizing/badges wrapped around it here are
   new. */
.produce-stage { text-align: left; }

/* Primary — the shipped cut, deliberately the largest moving element
   on the stage. Frame width is fixed (not a grid fraction) so it stays
   small beside the copy even as the column widens on desktop. */
.produce-primary {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-4);
  margin-bottom: var(--sp-6);
}
.produce-primary__frame { flex: none; width: 190px; }
.produce-primary__copy { flex: 1; min-width: 0; padding-top: var(--sp-1); }
.produce-primary__heading {
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-small);
  font-weight: 700;
  color: var(--text-primary);
}
.produce-primary__body {
  margin: 0;
  font-size: var(--fs-small);
  color: var(--text-secondary);
}

/* Chain label — same treatment as Script's act labels (sections.css
   .script-act__label): 11px, accent, letter-spaced. */
.produce-stage__chain-label {
  margin: 0 0 var(--sp-3);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: 0.06em;
  color: var(--brand-indigo);
}

.produce-chain {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--sp-4);
}
.produce-panel--final {
  cursor: pointer;
  border-radius: var(--radius-xs);
}
.produce-panel--final:focus-visible {
  outline: 2px solid var(--brand-indigo);
  outline-offset: 2px;
}
/* Fixed small width, not a full grid-column fill — 9:16 at "roughly
   175px tall" per spec is ~100px wide, well short of a 190px column,
   so it sits at its own size with the caption running the column's
   full width underneath rather than stretching the media to match. */
.produce-panel__frame {
  position: relative;
  width: 100px;
  aspect-ratio: 9 / 16;
  margin-bottom: var(--sp-2);
}
.produce-panel__frame .frame__inner { height: 100%; }
.produce-panel__frame .case__video,
.produce-panel__media {
  width: 100%; height: 100%;
  object-fit: cover;
}
/* Marks panel 03 as the chain's outcome, not another input. */
.produce-panel__frame--outline {
  outline: 1.5px solid var(--brand-indigo);
  outline-offset: 1px;
}
.produce-panel__badge {
  position: absolute;
  top: 6px; left: 6px;
  z-index: 1;
  padding: 1px 6px;
  border-radius: var(--radius-pill);
  background: rgba(13, 21, 38, 0.65);
  color: var(--text-on-brand);
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
}
.produce-panel__duration {
  position: absolute;
  bottom: 6px; right: 6px;
  z-index: 1;
  padding: 1px 6px;
  border-radius: var(--radius-pill);
  background: rgba(13, 21, 38, 0.65);
  color: var(--text-on-brand);
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
}
.produce-panel__heading {
  margin: 0 0 2px;
  font-size: 12px;
  font-weight: 500;
  color: var(--text-primary);
}
.produce-panel__body {
  margin: 0;
  font-size: 12px;
  color: var(--text-secondary);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

@media (max-width: 600px) {
  .produce-primary { flex-direction: column; }
  .produce-primary__frame { width: 140px; }
  .produce-chain { grid-template-columns: 1fr; }
}

/* -- Footer — the loop closing, stated plainly -------------------------- */
.loopnav__footer {
  margin-top: var(--sp-6);
  padding-top: var(--sp-5);
  border-top: 1px solid var(--border);
  text-align: center;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.06em;
  color: var(--text-muted);
}

@media (max-width: 767px) {
  .loopnav__head { flex-direction: column; }
  .loopnav__lens { width: 100%; }
  .loopnav__lens-btn { flex: 1 1 0; }
}

/* =================================================================
   BACKGROUND — overview open, everything else collapsed

   Last section before the CTA, so it has to close short. Only the
   Overview is ever visible on load: two paragraphs, then the two
   photos side by side under them. Training / Software / Other are
   collapsible rows built on the sitewide .expand, whose border-top
   is what draws the divider between them — no separate rule
   element, and no second accordion component on the page.
   ================================================================= */

/* Two columns on desktop: heading + copy left, photos top-right,
   riding up level with the heading. The section head lives inside
   the left column for exactly that reason — hoisting it out to the
   section root would push the photo column down below it.

   Mobile-first, so the default here is the stacked single column and
   the split only switches on at the breakpoint. */
.bgtop { display: grid; gap: var(--sp-6); }
.bgtop__copy { max-width: 62ch; }

/* Deliberately capped well under the section width. Two portrait
   photos stretched across a 1100px module would outweigh the ads
   above them; at this size they read as supporting evidence, which
   is what a background section is for. Side by side at every
   breakpoint — they never stack. */
.bgphotos {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-4);
  max-width: 520px;
}

@media (min-width: 768px) {
  .bgtop {
    grid-template-columns: minmax(0, 1fr) 360px;
    gap: var(--sp-7);
    align-items: start;   /* photos hold the top edge, never stretch */
  }
  .bgphotos { max-width: none; }
}

.bgphoto {
  margin: 0;
  overflow: hidden;   /* clips the image to the radius */
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  border-bottom-color: var(--border-bottom);
  border-radius: var(--radius);
  box-shadow: var(--e2);
}

/* One shared 4:5 window. Both sources land near it already (3:4 and
   ~4:4.9), so cover crops a sliver rather than reframing either
   shot, and the pair still lines up to the pixel. */
.bgphoto img {
  width: 100%;
  height: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
}

/* The headshot's subject sits high in frame — biasing the crop
   upward keeps the face off the bottom edge under 4:5. */
.bgphoto--face img { object-position: center 38%; }

/* -- The collapsible rows -------------------------------------------- */

.bgrows { margin-top: var(--sp-7); }

/* .expand draws its own top rule; the stack needs a closing one so
   it reads as a bounded list instead of trailing off into the CTA. */
.bgrows .expand:last-child { border-bottom: 1px solid var(--border); }

/* The row's whole body is one child of .expand__inner, so it takes
   the shared bottom padding and small type in a single hit rather
   than every paragraph inside it picking them up separately. */
.bgrow__lead {
  margin-bottom: var(--sp-3);
  font-weight: 640;
  letter-spacing: -0.015em;
  color: var(--text-primary);
}
.bgrow__terms { margin-bottom: 0; }

/* -- Taskanchor: app icon + product shots ---------------------------- */

.tanchor__head {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  margin-bottom: var(--sp-3);
}
/* The lead's own bottom margin would push the name off the icon's
   centre line — the flex row owns the spacing here. */
.tanchor__head .bgrow__lead { margin-bottom: 0; }

/* No border, radius or plate of our own: the source is an app icon
   with its squircle and transparent corners already baked in, so
   anything we draw around it would just be a second, wronger edge. */
.tanchor__logo {
  flex: none;
  width: 56px; height: 56px;
}

/* Wider columns than the sitewide carousel — these are landscape app
   screenshots, and at the default 272px their UI is unreadable. */
@media (min-width: 768px) {
  .carousel.shots { grid-auto-columns: minmax(440px, 1fr); }
}

.shot {
  display: block;
  width: 100%;
  padding: 0;
  overflow: hidden;
  background: var(--surface-shot);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--e2);
  cursor: zoom-in;
  transition: transform var(--dur-base) var(--ease),
              box-shadow var(--dur-base) var(--ease);
}
.shot:hover { transform: translateY(var(--lift)); box-shadow: var(--e4); }

/* contain, not cover: the seven shots run from 1.5:1 to 2.2:1, and
   cropping them to one ratio would cut UI off the edges. The ground
   behind them is sampled from the screenshots themselves, so the
   letterboxing is invisible rather than a band of the wrong dark. */
.shot img {
  width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: contain;
}

/* -- CTA BAR ----------------------------------------------------------------- */

.ctabar {
  max-width: var(--page-max);
  margin: 0 auto var(--sp-6);
  padding: var(--sp-8) var(--gutter);
  text-align: center;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--e3), var(--highlight-top);
  position: relative;
  overflow: hidden;
  /* Same offset .section carries — the sticky scrollnav would
     otherwise sit over the heading whenever anything jumps here,
     and the ATF button now does exactly that. */
  scroll-margin-top: 76px;
}

/* The page's deepest gradient moment - a soft aura behind the CTA. */
.ctabar::before {
  content: '';
  position: absolute;
  inset: -40% -10% auto -10%;
  height: 160%;
  background: radial-gradient(50% 50% at 50% 0%,
    rgba(28, 87, 237, 0.10) 0%, transparent 70%);
  pointer-events: none;
}

.ctabar > * { position: relative; }

/* Spec calls for an ~80ms stagger here, wider than the page-wide
   30ms default — five zones read as a sequence, not a grid of cards. */
.ctabar .reveal { --stagger: 80ms; }

/* Five stacked zones — headline, ideal fit, selector, form, then the
   next-steps + direct-email pair. Same zone rule the ATF puts
   between its own zones: air alone didn't read as five, so a
   hairline carries the break. */
.ctabar > * + * {
  margin-top: var(--sp-6);
  padding-top: var(--sp-6);
  border-top: 0.5px solid var(--border-strong);
}

.cta2__head h2 { max-width: none; margin: 0 auto; }
.cta2__sub {
  margin: var(--sp-3) auto 0;
  max-width: 46ch;
  font-size: var(--fs-lead);
  color: var(--text-secondary);
}

/* Held to a reading measure and centred inside the card so the block
   keeps the CTA's existing centred silhouette rather than turning
   into a left-aligned section. Rhythm is the ATF's: label, then
   body, one step of air between zones. */
.ctablock {
  max-width: 62ch;
  margin: 0 auto;
}

/* Left, with the body under it — a label and its body are one unit,
   and a centred label over left-aligned copy reads as a mistake.
   The heading and the email pill stay centred. */
.ctablock__label {
  display: block;
  text-align: left;
  margin-bottom: var(--sp-2);
  font-family: var(--font-mono);
  font-size: calc(var(--fs-micro) * 1.4);   /* 12px -> 16.8px */
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.ctablock__body {
  font-size: var(--fs-body);
  color: var(--text-secondary);
  text-align: left;
}

/* The one gradient element in this card — grad-brand-solid, not the
   full ramp, because that's the variant biased to the dark ends so
   white text clears contrast (design-rules §2, CTA button fills).
   The number pills below stay a flat tint so this stays the only
   ramp in the group. */
.ctablock__email {
  display: inline-block;
  padding: var(--sp-3) var(--sp-5);
  border-radius: var(--radius-pill);
  background: var(--grad-brand-solid);
  box-shadow: var(--e-brand);
  font-family: var(--font-mono);
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--text-on-brand);
  transition: box-shadow var(--dur-base) var(--ease),
              translate var(--dur-base) var(--ease);
}
.ctablock__email:hover {
  color: var(--text-on-brand);
  box-shadow: var(--e-brand-hover);
  translate: 0 var(--lift);
}

/* Conditions — requirements, not benefits. Equal-weight tiles, no
   tick marks, no accent colour, nothing that could read as a
   feature list. Three-up or one-up, never auto-fit: at these widths
   auto-fit lands on 2+1, and an orphaned third tile stops reading as
   equal weight, which is the one thing these have to be. */
.ctaconds {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-3);
  margin-top: var(--sp-4);
  text-align: left;
  counter-reset: cond;
}
@media (min-width: 700px) {
  .ctaconds { grid-template-columns: repeat(3, 1fr); }
}
/* Pill on its own line above the requirement. Inline, it ate 41px of
   a 201px tile and left a ~128px text column that wrapped two of the
   three requirements onto three ragged lines. */
.ctacond {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4);
  background: var(--surface-sunken);
  border: 0.5px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: var(--fs-small);
  line-height: 1.5;
  color: var(--text-secondary);
}

/* Numbered by counter, not by copy — the digits belong to the
   ordering, not to the requirement. Flat brand tint, never the ramp:
   three gradient pills in one card would fight the email pill above,
   which is the group's one gradient element. */
.ctacond::before {
  counter-increment: cond;
  content: counter(cond, decimal-leading-zero);
  flex: none;
  padding: 1px var(--sp-2);
  border-radius: var(--radius-pill);
  background: var(--surface-brand-tint);
  color: var(--brand-deep);
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  line-height: 1.6;
}

/* -- CTA: SELECTOR ------------------------------------------------------- */

/* Single-select radiogroup, two cards. Side by side once there's
   room; full-width stack below it. Card treatment matches the
   deliver rows in "What I do" — 12px radius, hairline border, flat
   white surface, no shadow of its own. */
.cta2__selector {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-4);
  text-align: left;
}
@media (min-width: 768px) {
  .cta2__selector { grid-template-columns: repeat(2, 1fr); }
}

/* Selected state is border colour and weight only — no background
   or text change, no shadow, per the build spec. Both cards read as
   equally live at all times. */
.cta2__opt {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  min-height: 44px;
  padding: var(--sp-5);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  cursor: pointer;
  transition: border-color var(--dur-base) var(--ease);
}
.cta2__opt:hover { border-color: var(--border-brand); }
.cta2__opt:focus-visible {
  outline: 2px solid var(--brand-indigo);
  outline-offset: 2px;
}
.cta2__opt.is-selected {
  border-color: var(--brand-indigo);
  border-width: 1.5px;
  padding: calc(var(--sp-5) - 0.5px);   /* border grew 0.5px, hold the box still */
}

.cta2__opt-title {
  font-size: var(--fs-lead);
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--text-primary);
}
.cta2__opt-body {
  font-size: var(--fs-small);
  color: var(--text-secondary);
}

/* -- CTA: FORM ------------------------------------------------------------ */

/* Always rendered, never gated behind a selection — a hidden form
   means a skimmer sees no ask at all (build spec §3). */
.cta2__form {
  max-width: 62ch;
  margin: 0 auto;
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: var(--sp-5);
}

.cta2__field {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

.cta2__label {
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--text-primary);
}

.cta2__input {
  min-height: 44px;
  padding: var(--sp-3) var(--sp-4);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  color: var(--text-primary);
  transition: border-color var(--dur-base) var(--ease),
              box-shadow var(--dur-base) var(--ease);
}
.cta2__input::placeholder { color: var(--text-faint); }
.cta2__input:focus {
  outline: none;
  border-color: var(--brand-indigo);
  box-shadow: 0 0 0 3px var(--brand-indigo-a12);
}

.cta2__hint {
  font-size: var(--fs-micro);
  color: var(--text-muted);
}

/* Visually hidden, not display:none — a screen reader still needs to
   skip it, but display:none honeypots get stripped by some bots. */
.cta2__hp {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.cta2__submit-row {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  flex-wrap: wrap;
}
.cta2__submit:disabled { opacity: 0.6; cursor: default; }

.cta2__error {
  font-size: var(--fs-small);
  color: var(--error);
}

.cta2__success {
  font-size: var(--fs-lead);
  color: var(--text-primary);
}
.cta2__success strong { color: var(--brand-deep); }

/* -- CTA: NEXT STEPS + DIRECT EMAIL ---------------------------------------- */

.cta2__foot {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-6);
  text-align: center;
}
.cta2__next { width: 100%; }

.cta2__steps {
  display: grid;
  gap: var(--sp-3);
  margin-top: var(--sp-4);
  text-align: left;
  counter-reset: step;
}
.cta2__steps li {
  position: relative;
  padding-left: var(--sp-7);
  min-height: 32px;
  display: flex;
  align-items: center;
  font-size: var(--fs-small);
  color: var(--text-secondary);
}
/* Same numbered-tile idiom as .ctacond — genuine sequence, so the
   numbering is justified here rather than decorative. */
.cta2__steps li::before {
  counter-increment: step;
  content: counter(step, decimal-leading-zero);
  position: absolute;
  left: 0;
  top: 0;
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  border-radius: var(--radius-xs);
  background: var(--surface-brand-tint);
  color: var(--brand-deep);
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
}

.cta2__direct-copy {
  margin-bottom: var(--sp-3);
  font-size: var(--fs-body);
  color: var(--text-secondary);
}

/* -- FOOTER --------------------------------------------------------------- */
.footer {
  max-width: var(--page-max);
  margin-inline: auto;
  padding: 0 var(--gutter) var(--sp-7);
  font-size: var(--fs-micro);
  color: var(--text-faint);
  text-align: center;
}
