/* ==========================================================================
   Free Website Audit landing page
   --------------------------------------------------------------------------
   Page-specific styles for /free-website-audit/. Hand-authored, in the same
   spirit as assets/css/policy.css: not part of the vendor bundle, never
   touched by build.js or purge-css.js.

   Must load AFTER theme.css so the --th-* semantic tokens exist and so these
   rules can beat theme.css's global form and .c-section overrides.

   THE DEVICE
   The product is a screen recording, and a recording has one honest
   structural device: the timeline. The four checks happen in that order, on
   tape, every time (see docs/client-acquisition-playbook.md). So timecodes
   carry the section structure instead of decorative eyebrows or 01/02/03
   numerals, which encoded nothing. Mono type appears only where it marks time.

   Red (--accent, normally this site's error colour) is promoted here to the
   recording indicator, and appears in exactly two places: the hero REC line
   and one dot on the chapter rail (statically parked on 0:00; in browsers
   with scroll-driven animations it is the record head that travels the rail).
   Never on text, borders, or anything interactive, so it never competes with
   the form's real error state.

   Written mobile-first. Base rules are the 390px layout; min-width queries
   add the desktop composition.

   TYPE
   Raleway is a variable font (100-900, roman + italic) already preloaded, and
   Loretto ships 100-900 ROMAN ONLY - never set it italic, the browser would
   synthesise a slant. The page whispers big and stamps small: display type
   runs light (Raleway 280-300), the functional layer runs heavy (Raleway
   700-800 labels, 700 mono timecodes). Weight, not size alone, carries the
   hierarchy. Raleway italic appears in exactly one place: the client quote,
   because italic means reported speech.

   Optical tracking rules: >=40px use -0.015em; 22-32px use -0.02em at weight
   >=700 but only -0.01em at <=300 (light weights carry their own air);
   <=12px uppercase use +0.10 to +0.16em; mono timecodes always +0.04em with
   tabular-nums.

   Root font-size is 62.5%, so 1rem = 10px.
   ========================================================================== */

/* A typed custom property, so the weight axis interpolates smoothly. An
   untyped --fwa-wght would be a plain token and would jump between keyframes
   rather than animating through them. */
@property --fwa-wght {
  syntax: "<number>";
  initial-value: 400;
  inherits: false;
}

.fwa-page {
  --fwa-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  --fwa-rec: var(--accent);
  --fwa-pad: 5.6rem;
}

/* --------------------------------------------------------------------------
   1. Section shell
   -------------------------------------------------------------------------- */

.fwa-section.c-section {
  padding-block: var(--fwa-pad);
  padding-inline: var(--gutter);
  background: transparent;
}

.fwa-inner.c-container {
  width: 100%;
  max-width: 108rem;
  margin-inline: auto;
  align-items: stretch;
}

#audit-form {
  scroll-margin-top: 11rem;
}

/* The shared footer sells a $499/mo plan directly under a page whose promise
   is "it costs nothing", and adds ~2 screens on mobile. Hidden here only. */
.fwa-page ~ #bx-footer .cta-section {
  display: none;
}

/* --------------------------------------------------------------------------
   2. Type
   -------------------------------------------------------------------------- */

.fwa-h1 {
  font-family: "Raleway", sans-serif;
  font-size: clamp(4.2rem, 11vw, 7.2rem);
  font-weight: 280;
  font-variation-settings: "wght" 280;
  line-height: 1.04;
  letter-spacing: -0.01em;
  color: var(--th-text);
  margin: 0 0 2rem;
  max-width: 15ch;
}

/* The one display move: a single serif word inside the geometric sans
   headline. Loretto is this site's rare-display face (homepage
   .solutions__lede strong) and is already self-hosted. */
.fwa-h1__word {
  font-family: "Loretto", Georgia, serif;
  font-style: normal; /* Loretto has no italic cut */
  font-weight: 700;
}

.fwa-h2 {
  font-family: "Raleway", sans-serif;
  font-size: clamp(3.2rem, 7.5vw, 4.6rem);
  font-weight: 300;
  font-variation-settings: "wght" 300;
  line-height: 1.08;
  letter-spacing: -0.01em;
  color: var(--th-text);
  margin: 0 0 1.2rem;
  /* ACSS sets --heading-text-wrap: pretty globally, which only guards against
     orphans. These headings are short enough for the balancer, and balance
     evens the lines instead: the proof heading sets 240/242 at 390px. Note
     that balance only picks the best break the copy allows - the earlier
     "Audits that turned into projects" could only break 255/175, so that
     one was fixed in the copy, not here. It is capped at a few lines by the
     browser, so it is a no-op on the single-line headings here. */
  text-wrap: balance;
}

.fwa-lede {
  font-size: 1.8rem;
  font-weight: 300;
  line-height: 1.55;
  color: var(--th-text-mid);
  margin: 0 0 3.2rem;
  max-width: 46ch;
}

.fwa-sub {
  font-size: 1.6rem;
  font-weight: 300;
  line-height: 1.65;
  color: var(--th-text-mid);
  margin: 0 0 4rem;
  max-width: 54ch;
}

/* --------------------------------------------------------------------------
   3. Links (never a default browser underline)
   -------------------------------------------------------------------------- */

.fwa-link {
  color: var(--th-text);
  text-decoration-line: underline;
  text-decoration-color: var(--th-border-mid);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.35em;
  transition: color 0.2s ease, text-decoration-color 0.2s ease;
}

.fwa-link:hover,
.fwa-link:focus-visible {
  color: var(--th-accent);
  text-decoration-color: var(--th-accent);
}

.fwa-textlink {
  display: inline-flex;
  align-items: center;
  padding-block: 1rem; /* clears a 44px tap target */
  font-size: 1.6rem;
  font-weight: 500;
  color: var(--th-text-mid);
  text-decoration: none;
  transition: color 0.2s ease;
}

.fwa-textlink::after {
  content: "";
  width: 0.6em;
  height: 0.6em;
  margin-left: 0.5em;
  border-top: 1.5px solid currentColor;
  border-right: 1.5px solid currentColor;
  transform: rotate(45deg);
  transition: transform 0.2s ease;
}

.fwa-textlink:hover,
.fwa-textlink:focus-visible { color: var(--th-accent); }
.fwa-textlink:hover::after { transform: translateX(0.25em) rotate(45deg); }

/* --------------------------------------------------------------------------
   4. Hero
   -------------------------------------------------------------------------- */

.fwa-hero.c-section {
  padding-block: 6.4rem 4.8rem;
}

.fwa-hero__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1.6rem 2.8rem;
  margin-bottom: 2.8rem;
}

/* REC line. Replaces the stat ticker; states the one fact that matters
   before someone commits to watching something. */
.fwa-rec {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  margin: 0;
  font-family: var(--fwa-mono);
  font-size: 1.2rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  font-variant-numeric: tabular-nums;
  color: var(--th-text-muted);
}

.fwa-rec__dot {
  width: 0.8rem;
  height: 0.8rem;
  flex: none;
  border-radius: var(--radius-50);
  background: var(--fwa-rec);
}

@media (prefers-reduced-motion: no-preference) {
  .fwa-rec__dot { animation: fwa-blink 2s ease-in-out infinite; }
}

@keyframes fwa-blink {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.45; }
}

/* Desktop-only chapter preview in the hero's second column. */
.fwa-hero__runsheet { display: none; }

/* --------------------------------------------------------------------------
   5. Chapters - the signature
   -------------------------------------------------------------------------- */

.fwa-chapters {
  position: relative;
  list-style: none;
  margin: 0;
  padding: 0 0 0 2.4rem;
  border-left: 1px solid var(--th-border-mid);
  display: grid;
  gap: 4rem;
}

/* Film stock. Three layered patterns on ONE out-of-flow pseudo, because the
   ol is a grid (in-flow pseudos would become grid items) and because ::after
   is already spoken for by the scroll-driven ink fill.

   Layer 1, right column: major ruling - every fifth mark runs long, the way a
   frame counter's seconds-marks outrank its frame-marks. 9rem pitch.
   Layer 2, right column: minor ruling, 1px marks at a 1.8rem pitch.
   Layer 3, left column: sprocket perforations as actual round holes (radial
   dots, 0.48rem across) at a 3.6rem pitch - exactly twice the ruling pitch,
   so minor marks and holes lock instead of beating. The majors land every
   18rem, the LCM of all three.

   The played-portion fill in 5b re-inks layers 2-3 at the SAME phase (its
   background-position-y offsets match this pseudo's 1.4rem top inset), so
   stock crossing the record head darkens in place instead of swapping to a
   different pattern.

   One paint, no extra elements, no image request. */
.fwa-chapters::before {
  content: "";
  position: absolute;
  left: -1.9rem;
  top: 1.4rem;
  bottom: 1.4rem;
  width: 2.5rem;
  background-image:
    repeating-linear-gradient(
      to bottom,
      var(--th-border-mid) 0,
      var(--th-border-mid) 1px,
      transparent 1px,
      transparent 9rem
    ),
    repeating-linear-gradient(
      to bottom,
      var(--th-border-mid) 0,
      var(--th-border-mid) 1px,
      transparent 1px,
      transparent 1.8rem
    ),
    radial-gradient(
      circle 0.24rem at 50% 50%,
      var(--th-border-mid) 98%,
      transparent
    );
  background-size: 1rem 100%, 0.6rem 100%, 0.55rem 3.6rem;
  background-position: right center, right center, left center;
  background-repeat: repeat-y, repeat-y, repeat-y;
  opacity: 0.75;
  pointer-events: none;
}

/* The record head. Hidden by default; the scroll-driven layer at the end of
   this section turns it into the red dot that travels the rail. An li so the
   ol stays valid HTML; absolutely positioned so the grid never sees it. */
.fwa-chapters__head {
  display: none;
}

.fwa-chapter {
  position: relative;
}

/* The rail reads as tape already rolling: the first segment is "played"
   (solid, full ink), the rest stays hairline. Content-driven height rather
   than a hard-tuned pixel value, so it survives reflow. Runs from the tick's
   optical centre into the gap below. */
.fwa-chapter--first::after {
  content: "";
  position: absolute;
  left: -2.4rem;
  margin-left: -1px;
  top: 1.25rem;
  height: calc(100% + 4rem - 1.25rem);
  width: 2px;
  background: var(--th-text);
}

/* The tick on the rail. Vertically centred on the timecode's cap height
   (1.5rem mono in a 2.475rem line box puts the glyph centre near 1.25rem),
   not on the line box - the eye reads the tick against the numbers. */
.fwa-chapter::before {
  content: "";
  position: absolute;
  left: -2.85rem;
  top: 0.8rem;
  width: 0.9rem;
  height: 0.9rem;
  border-radius: var(--radius-50);
  background: var(--th-bg);
  border: 1px solid var(--th-border-mid);
}

/* Desktop: the timecode grows to 1.8rem and sits baseline-aligned with the
   3.2rem title, so the tick centre rides lower. (Left offset stays with the
   composition rules in section 11.) */
@media (min-width: 768px) {
  .fwa-chapter::before { top: 1.35rem; }
}

.fwa-chapter--first::before {
  width: 1rem;
  height: 1rem;
  background: var(--fwa-rec);
  border-color: transparent;
  box-shadow: 0 0 0 3px var(--th-bg), 0 0 0 4.5px var(--fwa-rec);
  z-index: 1;
}

/* The rail terminates on an end-of-reel mark: a double bar, the way film
   leaders and tape boxes mark the end. Closes the claim the hero REC line
   opens ("about 3 minutes") and gives the device an ending. */
.fwa-chapter--end::before {
  border-radius: 0;
  width: 0.9rem;
  height: 0.9rem;
  top: 0.8rem;
  background: linear-gradient(
    to bottom,
    var(--th-text) 0 2px,
    transparent 2px 5px,
    var(--th-text) 5px 7px
  );
  border: 0;
}

.fwa-chapter--end {
  display: flex;
  align-items: baseline;
  gap: 1.2rem;
}

.fwa-chapter__cut {
  font-family: "Raleway", sans-serif;
  font-style: italic;
  font-weight: 300;
  font-size: 1.6rem;
  color: var(--th-text-muted);
}

.fwa-chapter__time {
  display: block;
  margin-bottom: 0.8rem;
  font-family: var(--fwa-mono);
  font-size: 1.5rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  font-variant-numeric: tabular-nums;
  color: var(--th-text);
}

/* The number stamps, the heading breathes. These previously shared weight 700
   at adjacent sizes, so they read as one lump. Now they differ on all four
   axes at once: mono vs sans, small vs large, heavy vs light, tracked out vs
   tracked in. This also un-inverts the hierarchy - chapter titles were heavier
   than the h2 sitting above them. */
.fwa-chapter__title {
  font-family: "Raleway", sans-serif;
  font-size: 2.6rem;
  font-weight: 400;
  font-variation-settings: "wght" 400;
  line-height: 1.12;
  letter-spacing: -0.015em;
  color: var(--th-text);
  margin: 0 0 1rem;
}

.fwa-chapter__body {
  font-size: 1.6rem;
  font-weight: 400;
  line-height: 1.65;
  color: var(--th-text-mid);
  margin: 0;
  max-width: 52ch;
}

/* --------------------------------------------------------------------------
   5b. Chapters - scroll-driven playback
   --------------------------------------------------------------------------
   In browsers with native scroll-driven animations, the rail literally plays.
   A "playhead line" is fixed 55vh down the viewport; as the list scrolls
   through it, an ink fill tracks it exactly, the red record head rides the
   fill's leading edge, ticks flip from hollow to ink the moment the head
   passes, and each chapter rises in as it enters the viewport.

   The tracking math is exact, not eyeballed: for a view() timeline, cover
   0% puts the subject's top at the viewport bottom, so the head is level
   with a line 55vh from the top when the subject has travelled 45vh past
   cover start - hence `cover 45vh` - and the subject's *bottom* reaches
   that same line at `cover calc(100% - 55vh)`. Both moving parts share one
   range, so fill edge and head never drift apart.

   Everything runs off the main thread and animates only transform/opacity.
   No JS, no libraries. Outside this block (Firefox today, reduced motion,
   or anything older) the static design above stands on its own: played 0:00
   segment, parked red dot, hollow rail.
   -------------------------------------------------------------------------- */

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {

    /* Retire the static "already played" affordances; playback takes over. */
    .fwa-chapter--first::before {
      width: 0.9rem;
      height: 0.9rem;
      background: var(--th-bg);
      border: 1px solid var(--th-border-mid);
      box-shadow: none;
      z-index: auto;
    }

    /* The played portion: not just an inked edge but DEVELOPED stock. As the
       rail plays, exposed frames appear between the ruling marks, the sprocket
       holes punch through to full ink, and the hairline edge becomes 2px of
       ink - the unplayed tape ahead stays raw stock. Three background layers
       on one pseudo, phase-matched to the gutter (the 1.4rem position offset
       equals ::before's top inset, so holes and frames land on the same grid).

       The reveal is clip-path, not scaleY: a pitched pattern must be uncovered
       at natural scale, never squashed. inset() clips are compositor-friendly,
       so the only per-frame work is re-clipping one 2.5rem column. */
    .fwa-chapters::after {
      content: "";
      position: absolute;
      left: -1.9rem;
      top: 0;
      height: 100%;
      width: 2.5rem;
      background-image:
        /* sprocket holes, played: same holes, full ink, same phase */
        radial-gradient(
          circle 0.24rem at 50% 50%,
          var(--th-text) 98%,
          transparent
        ),
        /* exposed frames: one frame band per ruling cell, nested between
           the 1px marks */
        repeating-linear-gradient(
          to bottom,
          transparent 0,
          transparent 0.3rem,
          color-mix(in srgb, var(--th-text) 78%, transparent) 0.3rem,
          color-mix(in srgb, var(--th-text) 78%, transparent) 1.5rem,
          transparent 1.5rem,
          transparent 1.8rem
        ),
        /* the inked rail edge */
        linear-gradient(var(--th-text), var(--th-text));
      background-size: 0.55rem 3.6rem, 1.05rem 1.8rem, 2px 100%;
      background-position: left top 1.4rem, left 0.7rem top 1.4rem, right 0.5rem top;
      background-repeat: repeat-y, repeat-y, no-repeat;
      clip-path: inset(0 0 100% 0);
      pointer-events: none;
      animation: fwa-play 1s linear both;
      animation-timeline: view(block);
      animation-range: cover 45vh cover calc(100% - 55vh);
    }

    /* The record head. Full rail height, so translateY(100%) is exactly one
       rail length and the head's travel maps 1:1 onto the fill's edge. */
    .fwa-chapters__head {
      display: block;
      position: absolute;
      left: 0;
      top: 0;
      bottom: 0;
      width: 0;
      z-index: 2;
      pointer-events: none;
      animation: fwa-head 1s linear both;
      animation-timeline: view(block);
      animation-range: cover 45vh cover calc(100% - 55vh);
    }

    /* The head is a carriage, not a dot: a head block straddling the tape,
       with the single red indicator centred in it like a record-head lamp.
       The page-bg fill lets it occlude the pattern seam between raw and
       developed stock as it travels. Exactly one red mark on the rail. */
    .fwa-chapters__head::before {
      content: "";
      position: absolute;
      left: -1.15rem;
      top: -0.7rem;
      width: 2.2rem;
      height: 1.4rem;
      border-radius: 0.25rem;
      border: 1px solid var(--th-text);
      background:
        radial-gradient(
          circle 0.35rem at 50% 50%,
          var(--fwa-rec) 96%,
          transparent
        ),
        var(--th-bg);
    }

    /* Crosshair whiskers left and right of the carriage, marking the exact
       scan line against the ruling. They stay inside the gutter and the
       ol's padding, so they never touch text. */
    .fwa-chapters__head::after {
      content: "";
      position: absolute;
      left: -1.9rem;
      top: 0;
      width: 3.8rem;
      height: 1px;
      background: linear-gradient(
        to right,
        var(--th-text) 0 0.75rem,
        transparent 0.75rem 2.95rem,
        var(--th-text) 2.95rem 3.8rem
      );
      opacity: 0.72;
    }

    /* Ticks flip to ink as the head passes. The lit state is a second dot
       stacked on the hollow one, faded/scaled in over the final 6rem of the
       head's approach, so only opacity and transform ever change. */
    .fwa-chapter:not(.fwa-chapter--end)::after {
      content: "";
      position: absolute;
      left: -2.85rem;
      margin-left: 0;
      top: 0.8rem;
      width: 0.9rem;
      height: 0.9rem;
      border-radius: var(--radius-50);
      background: var(--th-text);
      opacity: 0;
      animation: fwa-lit 1s linear both;
      animation-timeline: view(block);
      animation-range: cover calc(45vh - 6rem) cover 45vh;
    }

    /* The tick ring anticipates the head: its border inks from border-mid to
       full text colour over the same approach range, so the circle darkens
       just before the lit dot lands. border-color interpolates natively; the
       painted area is six 0.9rem circles, so the paint cost is trivial. */
    .fwa-chapter::before {
      animation: fwa-ring 1s linear both;
      animation-timeline: view(block);
      animation-range: cover calc(45vh - 6rem) cover 45vh;
    }

    /* The tape writes as it plays: each timecode inks in from light to heavy
       as the record head reaches it, then stays heavy. Locked to the SAME
       animation-range as the tick above, so the weight change and the tick
       lighting are one event and cannot drift apart.

       Deliberately limited to .fwa-chapter__time - five four-character
       strings. font-variation-settings re-rasterises text rather than
       compositing it, so titles and body copy are left alone. */
    .fwa-chapter__time {
      --fwa-wght: 200;
      font-variation-settings: "wght" var(--fwa-wght);
      color: var(--th-text-muted);
      animation: fwa-ink 1s linear both;
      animation-timeline: view(block);
      animation-range: cover calc(45vh - 6rem) cover 45vh;
    }

    /* Chapters rise as they enter the viewport. Ends at "fully entered", so
       nothing readable ever sits on screen at reduced contrast. */
    .fwa-chapter {
      animation: fwa-chapter-in 1s linear both;
      animation-timeline: view(block);
      animation-range: entry 5% entry 90%;
    }

    /* The ending lands: "cut." inks from light to heavy on Raleway's weight
       axis as the head reaches the end of tape. This is the one true
       variable-axis move added here - a single four-character word, chosen
       because font-variation-settings re-rasterises text and the cost stays
       near zero. (The timecodes ride the same axis but are ui-monospace,
       which ships no wght axis; there the registered property only carries
       the colour crossfade.) */
    .fwa-chapter__cut {
      --fwa-wght: 300;
      font-variation-settings: "wght" var(--fwa-wght);
      animation: fwa-cut 1s linear both;
      animation-timeline: view(block);
      animation-range: cover calc(45vh - 6rem) cover 45vh;
    }

    @media (min-width: 768px) {
      .fwa-chapter:not(.fwa-chapter--end)::after { left: -3.65rem; top: 1.35rem; }

      /* The head starts level with the first tick, whose centre sits lower
         on desktop - so the travel needs its own start offset here. */
      .fwa-chapters__head { animation-name: fwa-head-w; }
    }

    /* Section 9's dark rules would otherwise re-park a red dot on 0:00 (they
       come later and outrank the reset above). Playback mode has exactly one
       red dot: the head. */
    html[data-theme="dark"] .fwa-chapters .fwa-chapter--first::before {
      background: var(--th-bg);
      border-color: var(--th-border-mid);
    }
  }
}

/* clip-path, not scaleY: the fill carries a pitched pattern now, and a clip
   reveals it at natural scale from the top down. A scale would squash the
   frames mid-travel and break phase with the static gutter pattern. */
@keyframes fwa-play {
  from { clip-path: inset(0 0 100% 0); }
  to   { clip-path: inset(0 0 0 0); }
}

/* The head starts centred on the 0:00 tick (tick top 0.8rem + half its
   0.9rem height = 1.25rem) and ends centred on the end-of-reel mark. */
@keyframes fwa-head {
  from { transform: translateY(1.25rem); }
  to   { transform: translateY(calc(100% - 1.1rem)); }
}

/* Desktop start: tick top 1.35rem + 0.45rem = 1.8rem. */
@keyframes fwa-head-w {
  from { transform: translateY(1.8rem); }
  to   { transform: translateY(calc(100% - 1.1rem)); }
}

/* font-weight, not just the variation axis. The mono stack resolves to a
   non-variable face (Consolas on Windows), so font-variation-settings is
   inert there - verified by rendering identical ink at "wght" 200 and 800.
   font-weight does work, because that face ships a real bold cut; it snaps to
   the nearest available weight rather than interpolating, which for a stamped
   timecode is arguably the better read. The axis is kept for any variable
   mono a visitor's system does supply. */
@keyframes fwa-ink {
  from { --fwa-wght: 200; font-weight: 400; color: var(--th-text-muted); }
  to   { --fwa-wght: 800; font-weight: 700; color: var(--th-text); }
}

@keyframes fwa-lit {
  from { opacity: 0; transform: scale(0.4); }
  to   { opacity: 1; transform: none; }
}

@keyframes fwa-ring {
  from { border-color: var(--th-border-mid); }
  to   { border-color: var(--th-text); }
}

@keyframes fwa-cut {
  from { --fwa-wght: 300; }
  to   { --fwa-wght: 700; }
}

@keyframes fwa-chapter-in {
  from { opacity: 0; transform: translateY(1.6rem); }
  to   { opacity: 1; transform: none; }
}

/* --------------------------------------------------------------------------
   6. Form - the band is a strip of film crossing the page
   --------------------------------------------------------------------------
   The chapter rail above is film running vertically past a record head; the
   conversion band is the same stock laid horizontally. Sprocket perforations
   run along its top and bottom edges and the card sits in the strip like the
   frame being exposed. The holes are rounded-rect perforations, not the
   rail's round dots, so the two never read as one element rotated.
   -------------------------------------------------------------------------- */

/* Layer 1: the tonal band. Gives mobile its first real surface change at
   exactly the conversion moment, at no length cost.
   The dark selector is not redundant: theme.css:660 flattens every .c-section
   to transparent in dark mode and outranks a two-class selector. */
.fwa-form-section.c-section,
html[data-theme="dark"] .fwa-form-section.c-section {
  position: relative;
  background: var(--th-surface);
  border-block: 1px solid var(--th-border);
}

/* Perforated edges. One pseudo per edge, each painting a single row of
   rounded-rect holes at a 2.6rem pitch plus the soft shade that seats the
   strip. The rows live inside the band's own 5.6rem padding-block, so they
   never touch content, add no height, and are paint-only (one pseudo each,
   no extra elements, no image request). */
.fwa-form-section::before,
.fwa-form-section::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 2rem;
  pointer-events: none;
  background-image:
    radial-gradient(
      0.62rem 0.36rem at 50% 50%,
      rgba(79, 79, 125, 0.20) 96%,
      transparent
    );
  background-size: 2.6rem 0.9rem;
  background-position: 1.3rem center;
  background-repeat: repeat-x;
}

.fwa-form-section::before {
  top: 0;
  box-shadow: inset 0 12px 16px -14px rgba(20, 16, 50, 0.35);
}

.fwa-form-section::after {
  bottom: 0;
  box-shadow: inset 0 -12px 16px -14px rgba(20, 16, 50, 0.35);
}

/* The generic .fwa-h2 margin is 1.2rem, which works everywhere else because a
   .fwa-sub follows and carries its own 4rem. Here the checklist butts straight
   up against a 3.2rem heading, so the heading needs its own breathing room. */
.fwa-form-aside .fwa-h2 {
  margin-bottom: 2.4rem;
}

.fwa-checklist {
  margin: 0 0 3.2rem;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 1.2rem;
}

.fwa-checklist li {
  position: relative;
  padding-left: 2.8rem;
  font-size: 1.6rem;
  font-weight: 400;
  line-height: 1.6;
  color: var(--th-text-mid);
}

.fwa-checklist li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.5em;
  width: 1.4rem;
  height: 0.7rem;
  border-left: 2px solid var(--th-accent);
  border-bottom: 2px solid var(--th-accent);
  transform: rotate(-45deg);
}

/* Layer 3: the one truly elevated object on the page. The inset top highlight
   is the honest version of "light comes from above" - no glass, no gradient
   border. Now that the section is a film strip, the card reads as the frame
   being exposed. */
.wp-audit-card {
  position: relative;
  padding: 2.4rem;
  border: 1px solid var(--th-border);
  border-radius: var(--radius-l);
  background: var(--th-card-bg);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.9),
    0 1px 2px rgba(20, 16, 50, 0.06),
    0 8px 24px -8px rgba(20, 16, 50, 0.14),
    0 24px 48px -20px rgba(20, 16, 50, 0.12);
}

/* Viewfinder brackets. While any field holds focus the camera has found its
   subject: four corner marks parked 1.1rem off the card corners (outside
   every hit target), drawn as four gradient slivers on two pseudos. They
   fade in with intent and never decorate an idle card. */
.wp-audit-card::before,
.wp-audit-card::after {
  content: "";
  position: absolute;
  left: -1.1rem;
  right: -1.1rem;
  height: 1.8rem;
  pointer-events: none;
  opacity: 0;
  background-image:
    linear-gradient(var(--th-text-mid), var(--th-text-mid)),
    linear-gradient(var(--th-text-mid), var(--th-text-mid)),
    linear-gradient(var(--th-text-mid), var(--th-text-mid)),
    linear-gradient(var(--th-text-mid), var(--th-text-mid));
  background-size: 1.8rem 2px, 2px 1.8rem, 1.8rem 2px, 2px 1.8rem;
  background-position: left top, left top, right top, right top;
  background-repeat: no-repeat;
}

.wp-audit-card::before { top: -1.1rem; }
.wp-audit-card::after  { bottom: -1.1rem; }

.wp-audit-card:focus-within::before,
.wp-audit-card:focus-within::after { opacity: 1; }

.wp-audit-card .wp-field {
  display: flex;
  flex-direction: column;
  margin-bottom: 2rem;
}

/* The label and field do real work together: the label carries a tally dash
   that inks in while its field is live (the slate marker for the current
   shot), wakes from mid grey to full ink, and earns a drawn check once the
   field holds a value. Label text keeps a constant 1.5rem indent so nothing
   shifts sideways as the dash appears - it aligns with the input's text,
   not the input's box edge. */
.wp-audit-card label {
  display: flex;
  align-items: center;
  margin-bottom: 0.8rem;
  font-family: "Raleway", sans-serif;
  font-size: 1.1rem;
  font-weight: 800;
  font-variation-settings: "wght" 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--th-text-mid);
}

.wp-audit-card label::before {
  content: "";
  width: 0.9rem;
  height: 2px;
  margin-right: 0.6rem;
  flex: none;
  background: var(--th-accent);
  transform: scaleX(0);
  transform-origin: left center;
}

/* The check echoing the checklist's marks, shown once a field holds a value.
   :has() only gates the ornament; the field tint below works everywhere
   :placeholder-shown does. */
.wp-audit-card .wp-field:has(input:not(:placeholder-shown):not(.wp-invalid)) label::after {
  content: "";
  width: 0.9rem;
  height: 0.5rem;
  margin-left: 0.8rem;
  flex: none;
  border-left: 2px solid var(--th-accent);
  border-bottom: 2px solid var(--th-accent);
  transform: rotate(-45deg) translate(1px, -1px);
}

.wp-audit-card .wp-field:focus-within label { color: var(--th-text); }

.wp-audit-card .wp-field:focus-within label::before {
  transform: scaleX(1);
}

/* An invalid field's tally runs red: the error state owns red here, exactly
   as the file header promises. Ordered after the focus rule so it wins an
   invalid-but-focused field. #d2241b on the white card measures ~5.2:1. */
.wp-audit-card .wp-field:has(.wp-invalid) label { color: var(--accent); }

.wp-audit-card .wp-field:has(.wp-invalid) label::before {
  background: var(--accent);
  transform: scaleX(1);
}

.wp-audit-card .wp-hint {
  margin: 0.8rem 0 0;
  font-size: 1.4rem;
  font-weight: 300;
  line-height: 1.5;
  color: var(--th-text-muted);
}

.wp-audit-card input {
  width: 100%;
  min-height: 5.2rem;
  padding: 1.5rem 1.6rem;
  font-family: "Roboto", sans-serif;
  font-size: 1.6rem;
  font-weight: 300;
  color: var(--th-text);
  caret-color: var(--th-accent);
  background: var(--th-input-bg);
  border: 1px solid var(--th-input-border);
  border-radius: var(--radius-s);
  transition: border-color 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease;
}

.wp-audit-card input::placeholder { color: var(--th-text-muted); }

/* Filled: the frame is exposed. A whisper of the cyan wash "develops" the
   field and the border firms up; #1e1c3a on the 93% white mix still
   measures ~14:1, so text contrast is untouched. */
.wp-audit-card input:not(:placeholder-shown) {
  background: color-mix(in srgb, var(--th-input-bg) 93%, var(--th-accent) 7%);
  border-color: var(--th-border-mid);
}

/* Focus: the 2px outline stays (it is the a11y guarantee), and a soft halo
   plus caret in the same cyan make the live field unmistakable. The halo is
   color-mix so it tracks the theme instead of pinning a fixed rgba. */
.wp-audit-card input:focus-visible {
  outline: 2px solid var(--th-accent);
  outline-offset: 2px;
  border-color: var(--th-accent);
  box-shadow: 0 0 0 5px color-mix(in srgb, var(--th-accent) 14%, transparent);
}

.wp-audit-card .wp-invalid {
  border-color: var(--accent);
  box-shadow:
    0 0 0 1px var(--accent),
    0 0 0 5px color-mix(in srgb, var(--accent) 12%, transparent);
  background: color-mix(in srgb, var(--th-input-bg) 96%, var(--accent) 4%);
}

/* A focused-but-invalid field keeps the red ring - cyan would say "fine". */
.wp-audit-card .wp-invalid:focus-visible {
  outline-color: var(--accent);
  border-color: var(--accent);
  box-shadow:
    0 0 0 1px var(--accent),
    0 0 0 5px color-mix(in srgb, var(--accent) 16%, transparent);
}

.wp-audit-card .wp-hp {
  position: absolute;
  left: -9999px;
  height: 0;
  overflow: hidden;
}

/* The CTA pill itself is the sitewide component and is deliberately not
   restyled here beyond making it full-bleed on a narrow screen. */
.wp-audit-card .wp-contact_submit {
  width: 100%;
  margin-top: 0.8rem;
  cursor: pointer;
}

.wp-audit-card .wp-contact_submit[aria-disabled="true"] {
  cursor: progress;
  opacity: 0.75;
}

.wp-audit-card .wp-microcopy {
  margin: 1.6rem 0 0;
  font-family: var(--fwa-mono);
  font-size: 1.2rem;
  letter-spacing: 0.04em;
  color: var(--th-text-muted);
}

.wp-audit-card .wp-contact-msg {
  margin: 1.2rem 0 0;
  font-size: 1.4rem;
  line-height: 1.5;
  color: var(--th-text-mid);
}

/* contact.js clears the text but leaves the empty p; without this its
   margin and line box add a permanent phantom gap under the microcopy. */
.wp-audit-card .wp-contact-msg:empty { display: none; }

/* The failure line is a callout, not just red text: a full-height bar
   (currentColor, so it follows the light/dark error colour for free). */
.wp-audit-card .wp-contact-msg.is-error {
  display: flex;
  gap: 1rem;
  color: var(--accent);
  font-weight: 500;
}

.wp-audit-card .wp-contact-msg.is-error::before {
  content: "";
  flex: none;
  width: 2px;
  border-radius: 2px;
  background: currentColor;
}

/* The fallback contact line is the card's footer strip, set off by a
   hairline so it reads as "not the form" rather than as a fourth field. */
.wp-audit-card .wp-contact_alt {
  margin: 2rem 0 0;
  padding-top: 1.6rem;
  border-top: 1px solid var(--th-border);
  font-size: 1.4rem;
  font-weight: 300;
  line-height: 1.6;
  color: var(--th-text-muted);
}

.wp-audit-card .wp-contact_alt a { padding-block: 0.4rem; }

/* Success panel swapped in by contact.js: the delivery postmark. The icon
   gets a double ring (border + stepped shadow = stamped circle), the title
   carries a mono machine stamp that stays true on both code paths ("received"
   is what both the verified and the manual-review copy say), and the whole
   panel gets one short entrance. */
.wp-audit-card .wp-contact-success { padding: 2.8rem 0 2rem; color: var(--th-text); }

.wp-audit-card .wp-cs-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 6.4rem;
  height: 6.4rem;
  margin-bottom: 1.6rem;
  font-size: 2.8rem;
  line-height: 1;
  color: var(--th-accent);
  border: 1px solid var(--th-border-mid);
  border-radius: var(--radius-50);
  background: var(--th-surface);
  box-shadow: 0 0 0 3px var(--th-card-bg), 0 0 0 4px var(--th-border-mid);
}

.wp-audit-card .wp-cs-title {
  font-family: "Raleway", sans-serif;
  font-size: 2.4rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  margin: 0 0 0.8rem;
  color: var(--th-text);
}

.wp-audit-card .wp-cs-title::before {
  content: "received · recording queued";
  display: block;
  margin-bottom: 1rem;
  font-family: var(--fwa-mono);
  font-size: 1.1rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--th-text-muted);
}

.wp-audit-card .wp-cs-body {
  font-size: 1.6rem;
  font-weight: 300;
  line-height: 1.7;
  color: var(--th-text-mid);
  margin: 0;
  max-width: 44ch;
}

@media (prefers-reduced-motion: no-preference) {
  .wp-audit-card .wp-contact-success {
    animation: fwa-cs-in 0.45s cubic-bezier(0.16, 1, 0.3, 1) backwards;
  }
}

@keyframes fwa-cs-in {
  from { opacity: 0; transform: translateY(1rem); }
  to   { opacity: 1; transform: none; }
}

/* --------------------------------------------------------------------------
   6b. Form - scroll-driven arrival
   --------------------------------------------------------------------------
   Same proven pattern as 5b: view() timelines, transform/opacity only, and
   everything below simply never exists in browsers without support, under
   reduced motion, or in Firefox today - the static design above is complete
   on its own. */

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    /* Aside first, card a beat later: the pitch lands, then the object. */
    .fwa-form-aside {
      animation: fwa-chapter-in 1s linear both;
      animation-timeline: view(block);
      animation-range: entry 0% entry 70%;
    }

    .wp-audit-card {
      animation: fwa-chapter-in 1s linear both;
      animation-timeline: view(block);
      animation-range: entry 5% entry 85%;
    }

    /* The checklist ticks itself off as each item scrolls in - the tape
       confirming its own promises. Each li is its own view() subject, so the
       stagger falls out of their positions for free. */
    .fwa-checklist li::before {
      animation: fwa-tick 1s linear both;
      animation-timeline: view(block);
      animation-range: entry 30% entry 95%;
    }
  }
}

/* rotate(-45deg) must appear in both frames or the check would un-rotate as
   it scales in - the resting state above carries the rotation, the keyframes
   override the whole transform while running. */
@keyframes fwa-tick {
  from { opacity: 0; transform: rotate(-45deg) scale(0); }
  to   { opacity: 1; transform: rotate(-45deg) scale(1); }
}

/* --------------------------------------------------------------------------
   7. Proof - the contact sheet at the end of the tape
   --------------------------------------------------------------------------
   The form band is film being exposed; this band is what comes back from the
   lab. The case studies are developed frames (raised strips with a frame
   rebate, warming like prints in developer on hover), the quote is the one
   human voice and is set as a pull-quote with a watermark mark, and the 3:00
   runtime fills in as the visitor scrolls it into view - the tape running
   out, on purpose. */

.fwa-proof.c-section,
html[data-theme="dark"] .fwa-proof.c-section {
  position: relative;
  /* clip-path, NOT overflow:hidden: overflow makes the section its own
     scroll container, and every view() timeline inside it (7b) would bind to
     that dead scroller and freeze at its static position. clip-path clips
     the runtime bleed identically without creating a scroll container. */
  clip-path: inset(0);
  background-color: #15151f;
  border-block: 1px solid rgba(255, 255, 255, 0.08);
  /* Directional sheen at the top, a floor of darkness at the bottom: the
     band reads as a lit interior, not a flat fill. */
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.07),
    inset 0 24px 48px -24px rgba(255, 255, 255, 0.04),
    inset 0 -56px 72px -56px rgba(0, 0, 0, 0.6);
}

/* The runtime as a back wall. Same device as the rail, at architectural
   scale: the page opens on 0:00 and closes the band on 3:00. The scroll-
   driven fill that makes it "run out" lives at the end of this section. */
.fwa-proof__runtime {
  position: absolute;
  right: -0.05em;
  bottom: -0.14em;
  z-index: 0;
  font-family: var(--fwa-mono);
  font-size: clamp(12rem, 20vw, 22rem);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  color: rgba(255, 255, 255, 0.045);
  pointer-events: none;
  user-select: none;
}

@supports (-webkit-text-stroke: 1px white) {
  .fwa-proof__runtime {
    color: transparent;
    -webkit-text-stroke: 1px rgba(255, 255, 255, 0.1);
  }
}

.fwa-proof .fwa-inner { position: relative; z-index: 1; }

html[data-theme="dark"] .fwa-proof.c-section { background-color: #1f1f30; }

/* Same exception as .fwa-form-aside: the generic 1.2rem assumes a .fwa-sub
   follows and carries its own 4rem. Here the card list butts straight up
   against the heading - and against a two-line one at 390px - so it needs
   the same 2.4rem of its own. */
.fwa-proof .fwa-h2 {
  color: #fff;
  margin-bottom: 2.4rem;
}

.fwa-cases {
  list-style: none;
  margin: 0 0 4rem;
  padding: 0;
  display: grid;
  gap: 1.6rem;
}

/* A developed frame, not a container. At 390px the card is a lab index
   entry: the mounted frame rides left at a fixed 40% and its caption sits
   beside it, so all three stay legible without adding a screen of height.
   From 768px they become the contact sheet proper - three columns, frame
   over caption (section 11). */
.fwa-case {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 1.6rem;
  /* height, not flex tricks: the li stretches in the grid row, so the card
     fills it and all three silhouettes stay flush while the exposures
     inside differ. No-op at 390px, where each row is its own height. */
  height: 100%;
  padding: 1.6rem;
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: var(--radius-m);
  background: rgba(255, 255, 255, 0.03);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.05),
    0 14px 28px -18px rgba(0, 0, 0, 0.55);
  text-decoration: none;
  transition: background 0.25s ease, border-color 0.25s ease, box-shadow 0.25s ease;
}

/* Hover is not a tint: the frame warms like a print under projector light.
   Cream (--action, the palette's fixed warm point) replaces the plain white
   lift, the keyline brightens, the shadow deepens, and the image itself
   opens back up to full exposure. The band is dark in BOTH themes, so the
   fixed rgba() cream is safe. */
.fwa-case:hover,
.fwa-case:focus-visible {
  background: rgba(241, 221, 177, 0.07);
  border-color: rgba(241, 221, 177, 0.35);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.09),
    0 18px 36px -18px rgba(0, 0, 0, 0.65);
}

/* The chain is not decoration: automatic-bricks.css:6 pins a cyan outline
   on every :focus-visible element at (0,3,1) via
   body.cmp-is-frontend.cmp-is-frontend, so a plain .fwa-case:focus-visible
   (0,2,0) never wins. (0,4,0) beats it outright and keeps the ring cream -
   the same warm keyline the card already gets on intent, and the band is
   dark in both themes. */
.fwa-cases .fwa-case.fwa-case:focus-visible {
  outline: 2px solid rgba(241, 221, 177, 0.7);
  outline-offset: 2px;
}

/* The mount: a deep rebate that seats the bright screenshot in the dark
   band, with its own keyline and inner shade, so the image reads as a frame
   set INTO the card rather than a thumbnail pasted onto it. The rebate is
   darker than the band in both themes (#15151f light, #1f1f30 dark), which
   is what a mount is: the shadow the frame sits in. */
.fwa-case__frame {
  display: block;
  /* 40% here, widened to 48% from 360px. At 320px the caption clears
     "TjamesonTax" - an unbreakable 11-character token - with exactly 0px
     to spare, so the wider frame has to start above that width. */
  flex: 0 0 40%;
  min-width: 0;
  padding: 0.7rem;
  border: 1px solid rgba(255, 255, 255, 0.10);
  border-radius: var(--radius-s);
  background: #0c0c14;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.04),
    inset 0 10px 18px -14px rgba(0, 0, 0, 0.85);
  transition: border-color 0.25s ease;
}

/* The developed image. At rest it sits stopped down and slightly
   desaturated - a print under safelight, not a lit screen, so it never
   glares against the dark band. On intent it returns to full exposure; the
   warming is the filter lifting, not an overlay, so the pixels stay the
   client's real work in every state. */
.fwa-case__img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid rgba(255, 255, 255, 0.12);
  filter: brightness(0.8) saturate(0.85);
  transition: filter 0.35s ease, border-color 0.25s ease;
}

.fwa-case:hover .fwa-case__frame,
.fwa-case:focus-visible .fwa-case__frame {
  border-color: rgba(241, 221, 177, 0.45);
}

.fwa-case:hover .fwa-case__img,
.fwa-case:focus-visible .fwa-case__img {
  border-color: rgba(241, 221, 177, 0.35);
  filter: brightness(1.02) saturate(1.02);
}

/* Edge print: the frame's machine stamp in the rebate below the image.
   Mono, because mono on this page only ever marks time or the apparatus;
   numbered in sheet order. The stamps are aria-hidden in the markup so the
   link's accessible name stays the client name plus note. */
.fwa-case__edge {
  /* Hidden at 390px, where a 1.05rem stamp beside a 139px frame is noise
     competing with the client name for the same narrow card. It returns
     from 768px (section 11), where the frame runs full width and the
     stamp has the rebate to itself. */
  display: none;
  padding: 0.7rem 0.2rem 0.1rem;
  font-family: var(--fwa-mono);
  font-size: 1.05rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  /* 0.5, not the usual 0.4 whisper: at 1.05rem on the #0c0c14 rebate that
     would measure ~3.9:1; this lands ~5.4:1, inside AA, in both themes. */
  color: rgba(255, 255, 255, 0.5);
}

/* At 390px a 40% frame develops the screenshot at 113x65, too small to read
   as the client's actual site - the one job the image has here. 48% lands it
   at 139x80 for 12px more list height. Past 48% the caption starts losing
   lines faster than the print gains. */
@media (min-width: 360px) {
  .fwa-case__frame { flex: 0 0 48%; }
}

/* The caption strip: beside the frame at 390px, under it from 768px. */
.fwa-case__cap {
  display: block;
  min-width: 0;
  padding-top: 0.5rem;
}

/* The name steps up from Loretto 600 to the heavy cut and carries the
   link's one moving part: the same drawn chevron the page's text links
   use, revealed on intent now that a frame occupies the card's top-right. */
.fwa-case__name {
  display: block;
  font-family: "Loretto", Georgia, serif;
  font-size: 2.3rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.15;
  color: #fff;
  margin-bottom: 0.5rem;
  transition: color 0.25s ease;
}

.fwa-case__name::after {
  content: "";
  display: inline-block;
  width: 0.42em;
  height: 0.42em;
  margin-left: 0.32em;
  vertical-align: 0.08em;
  border-top: 1.5px solid rgba(241, 221, 177, 0.9);
  border-right: 1.5px solid rgba(241, 221, 177, 0.9);
  transform: rotate(45deg);
  opacity: 0;
  transition: opacity 0.25s ease;
}

.fwa-case:hover .fwa-case__name,
.fwa-case:focus-visible .fwa-case__name { color: rgba(241, 221, 177, 0.95); }

.fwa-case:hover .fwa-case__name::after,
.fwa-case:focus-visible .fwa-case__name::after { opacity: 1; }

.fwa-case__note {
  display: block;
  font-size: 1.5rem;
  font-weight: 300;
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.6);
  transition: color 0.25s ease;
}

.fwa-case:hover .fwa-case__note,
.fwa-case:focus-visible .fwa-case__note { color: rgba(255, 255, 255, 0.75); }

/* The one piece of reported speech on the page is set as testimony on the
   timeline: a cream rail down the left with a single developed tick at its
   head - the rail's own language (a line, a dot), spoken in the palette's
   warm point, no red, no glyph watermarks. */
.fwa-quote {
  position: relative;
  margin: 0 0 3.2rem;
  padding: 0 0 0 2.6rem;
  border: 0;
}

.fwa-quote::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.5rem;
  bottom: 0.5rem;
  width: 2px;
  background: rgba(241, 221, 177, 0.35);
}

.fwa-quote::after {
  content: "";
  position: absolute;
  left: 1px;
  margin-left: -0.45rem;
  top: 0.3rem;
  width: 1rem;
  height: 1rem;
  border-radius: var(--radius-50);
  background: rgba(241, 221, 177, 0.9);
}

.fwa-quote__text {
  font-family: "Raleway", sans-serif;
  font-style: italic;
  font-size: 2.2rem;
  font-weight: 350;
  font-variation-settings: "wght" 350;
  line-height: 1.45;
  letter-spacing: -0.005em;
  color: #fff;
  margin: 0 0 1.6rem;
}

.fwa-quote__cite {
  display: block;
  font-family: "Raleway", sans-serif;
  font-size: 1.2rem;
  font-weight: 700;
  font-style: normal;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.72);
}

.fwa-proof__sig {
  margin: 0;
  padding-top: 2.8rem;
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  font-size: 1.7rem;
  font-weight: 300;
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.78);
  max-width: 56ch;
}

/* --------------------------------------------------------------------------
   7b. Proof - scroll-driven development
   --------------------------------------------------------------------------
   Additive only. Without view() support or under reduced motion: static
   frames, static quote, outline-only 3:00. All transform/opacity/clip. */

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    /* Frames rise in order as the row enters. Each li is its own subject;
       the stagger is three slightly offset ranges, not a delay. */
    .fwa-cases li {
      animation: fwa-chapter-in 1s linear both;
      animation-timeline: view(block);
      animation-range: entry 0% entry 55%;
    }

    .fwa-cases li:nth-child(2) { animation-range: entry 6% entry 62%; }
    .fwa-cases li:nth-child(3) { animation-range: entry 12% entry 70%; }

    .fwa-quote {
      animation: fwa-chapter-in 1s linear both;
      animation-timeline: view(block);
      animation-range: entry 5% entry 80%;
    }

    /* The numeral fills as it travels up the viewport: a solid copy stacked
       on the outline, clipped from the bottom edge upward like a counter
       running to end of tape. clip-path only, main-thread free. */
    .fwa-proof__runtime::after {
      content: "3:00";
      position: absolute;
      inset: 0;
      color: rgba(255, 255, 255, 0.1);
      -webkit-text-stroke: 0 transparent;
      clip-path: inset(100% 0 0 0);
      animation: fwa-runtime-fill 1s linear both;
      animation-timeline: view(block);
      animation-range: cover 10% cover 70%;
    }
  }
}

@keyframes fwa-runtime-fill {
  from { clip-path: inset(100% 0 0 0); }
  to   { clip-path: inset(0 0 0 0); }
}

/* --------------------------------------------------------------------------
   8. FAQ
   -------------------------------------------------------------------------- */

/* Rows with hairlines rather than five identical floating cards. Cards were
   the uniform-card pattern in miniature; this reads as a printed Q&A and
   matches the editorial language the rail sets. */
/* The FAQ sat transparent over the page background, and in dark mode the
   footer's first band is that same #0c0c14, so the two merged into one
   continuous field with no boundary. Giving the FAQ its own surface separates
   it from both the page and the footer, and keeps the band rhythm alternating
   after the dark proof section. The dark selector is required because
   theme.css:660 flattens .c-section backgrounds in dark and outranks a
   two-class selector. */
.fwa-faq-section.c-section,
html[data-theme="dark"] .fwa-faq-section.c-section {
  background: var(--th-surface);
  border-block-start: 1px solid var(--th-border);
}

.fwa-faq {
  display: grid;
  gap: 0;
  margin-bottom: 3.2rem;
  border-top: 1px solid var(--th-border);
}

.fwa-faq__item {
  position: relative;
  border-bottom: 1px solid var(--th-border);
  background: transparent;
}

/* The open marker is a rule in the gutter, echoing the chapter rail's ticks
   rather than inventing another device. */
.fwa-faq__item::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 2px;
  background: var(--th-accent);
  transform: scaleY(0);
  transform-origin: top center;
  transition: transform 0.28s cubic-bezier(0.16, 1, 0.3, 1);
}

.fwa-faq__item[open]::before { transform: scaleY(1); }

.fwa-faq__q {
  display: flex;
  align-items: center;
  gap: 1.6rem;
  min-height: 5.6rem;
  padding: 1.8rem 1.6rem 1.8rem 1.8rem;
  cursor: pointer;
  list-style: none;
  font-family: "Raleway", sans-serif;
  font-size: 1.7rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--th-text);
  transition: color 0.2s ease, padding-left 0.28s cubic-bezier(0.16, 1, 0.3, 1);
}

.fwa-faq__q:hover::after { color: var(--th-accent); }
.fwa-faq__item[open] .fwa-faq__q { padding-left: 2.6rem; }

.fwa-faq__q::-webkit-details-marker { display: none; }

.fwa-faq__q:focus-visible {
  outline: 2px solid var(--th-accent);
  outline-offset: -2px;
  border-radius: inherit;
}

/* Real heading for the outline, but it inherits the summary's type. */
.fwa-faq__q .fwa-h3 {
  margin: 0;
  font-size: inherit;
  font-weight: inherit;
  letter-spacing: inherit;
  color: inherit;
  font-family: inherit;
}

.fwa-faq__q::after {
  content: "";
  margin-left: auto;
  flex: none;
  width: 1.2rem;
  height: 1.2rem;
  background:
    linear-gradient(currentColor, currentColor) center / 100% 1.5px no-repeat,
    linear-gradient(currentColor, currentColor) center / 1.5px 100% no-repeat;
  color: var(--th-text-muted);
  transition: background-size 0.28s cubic-bezier(0.16, 1, 0.3, 1), color 0.2s ease;
}

/* Plus collapses to minus by shrinking the vertical arm to nothing. Rotating
   instead would just stand the remaining line back up. */
.fwa-faq__item[open] .fwa-faq__q::after {
  background-size: 100% 1.5px, 1.5px 0;
  color: var(--th-accent);
}

.fwa-faq__a {
  margin: 0;
  padding: 0 1.6rem 2.4rem 2.6rem;
  font-size: 1.6rem;
  font-weight: 400;
  line-height: 1.7;
  color: var(--th-text-mid);
  max-width: 62ch;
}

/* A .fwa-link on its own line is a control, not prose, so it needs a real
   tap target. Links inside a sentence are the WCAG 2.5.8 inline exception. */
.fwa-link--block {
  display: inline-flex;
  align-items: center;
  min-height: 4.4rem;
}

/* --------------------------------------------------------------------------
   8b. Progressive polish
   --------------------------------------------------------------------------
   Two enhancements that are additive only: browsers without support get the
   instant-toggle and static card they already had.
   -------------------------------------------------------------------------- */

/* Animate the disclosure to its intrinsic height. block-size does cost layout,
   but only on a deliberate user toggle of a five-item list, and it is the only
   way to reach `auto` without measuring in JS. */
@supports selector(::details-content) and (interpolate-size: allow-keywords) {
  @media (prefers-reduced-motion: no-preference) {
    .fwa-page { interpolate-size: allow-keywords; }

    .fwa-faq__item::details-content {
      block-size: 0;
      overflow: clip;
      opacity: 0;
      transition:
        block-size 0.32s cubic-bezier(0.16, 1, 0.3, 1),
        opacity 0.22s ease,
        content-visibility 0.32s allow-discrete;
    }

    .fwa-faq__item[open]::details-content {
      block-size: auto;
      opacity: 1;
    }
  }
}

/* The form card lifts while it is being filled in. Focus-within is the one
   state change on the page that responds to intent rather than pointer. The
   lift is light, not motion: border firms up and the shadow stack deepens. */
.wp-audit-card:focus-within {
  border-color: var(--th-border-mid);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.9),
    0 1px 2px rgba(20, 16, 50, 0.07),
    0 12px 32px -8px rgba(20, 16, 50, 0.18),
    0 32px 64px -20px rgba(20, 16, 50, 0.16);
}

@media (prefers-reduced-motion: no-preference) {
  /* Transitions live here so reduced motion gets instant state changes.
     Box-shadow transitions repaint a single card - trivial area, deliberate
     user action, no scroll involvement. */
  .wp-audit-card {
    transition: border-color 0.3s ease, box-shadow 0.3s ease;
  }

  .wp-audit-card::before,
  .wp-audit-card::after {
    transition: opacity 0.3s ease;
  }

  .wp-audit-card label {
    transition: color 0.2s ease;
  }

  .wp-audit-card label::before {
    transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1);
  }

  .wp-audit-card label::after {
    animation: fwa-tick-check 0.3s cubic-bezier(0.16, 1, 0.3, 1) backwards;
  }

  /* The hover lift: movement is gated here, the colour work above is not. */
  .fwa-case {
    transition:
      background 0.25s ease, border-color 0.25s ease,
      box-shadow 0.25s ease, transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);
  }

  .fwa-case:hover,
  .fwa-case:focus-visible { transform: translateY(-3px); }

  /* The chevron's slide. rotate(45deg) is pinned in the resting rule, so
     the transition only ever adds the translate. */
  .fwa-case__name::after {
    transition: opacity 0.25s ease, transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);
  }

  .fwa-case:hover .fwa-case__name::after,
  .fwa-case:focus-visible .fwa-case__name::after {
    transform: translateX(0.35rem) rotate(45deg);
  }
}

/* rotate(-45deg) pinned in both frames, same reason as fwa-tick above. */
@keyframes fwa-tick-check {
  from { opacity: 0; transform: rotate(-45deg) scale(0.4); }
  to   { opacity: 1; transform: rotate(-45deg) translate(1px, -1px) scale(1); }
}

/* --------------------------------------------------------------------------
   9. Dark theme
   -------------------------------------------------------------------------- */

html[data-theme="dark"] .fwa-page {
  --fwa-rec: var(--accent-medium);
}

html[data-theme="dark"] .fwa-chapter::before {
  background: var(--th-bg);
}

html[data-theme="dark"] .fwa-chapter--first::before {
  background: var(--fwa-rec);
  border-color: var(--fwa-rec);
}

/* On near-black a shadow is invisible, so dark-mode elevation is carried by
   surface lightness plus a hairline instead. */
html[data-theme="dark"] .wp-audit-card {
  background: var(--th-surface-elevated, #1f1f30);
  border-color: var(--th-border-mid);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.06),
    0 12px 32px -12px rgba(0, 0, 0, 0.6);
}

/* Film-strip perforations, re-inked for the dark surface. */
html[data-theme="dark"] .fwa-form-section::before,
html[data-theme="dark"] .fwa-form-section::after {
  background-image:
    radial-gradient(
      0.62rem 0.36rem at 50% 50%,
      rgba(255, 255, 255, 0.10) 96%,
      transparent
    );
}

html[data-theme="dark"] .fwa-form-section::before {
  box-shadow: inset 0 12px 16px -14px rgba(0, 0, 0, 0.7);
}

html[data-theme="dark"] .fwa-form-section::after {
  box-shadow: inset 0 -12px 16px -14px rgba(0, 0, 0, 0.7);
}

/* Dark-mode focus-within lift: shadow swap on the dark stack. */
html[data-theme="dark"] .wp-audit-card:focus-within {
  border-color: var(--th-border-mid);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.09),
    0 16px 40px -12px rgba(0, 0, 0, 0.75);
}

html[data-theme="dark"] .fwa-faq,
html[data-theme="dark"] .fwa-faq__item {
  border-color: var(--th-border-mid);
}

html[data-theme="dark"] .wp-audit-card input {
  background: var(--th-input-bg) !important;
  border-color: var(--th-input-border) !important;
  color: var(--th-text) !important;
}

html[data-theme="dark"] .wp-audit-card label {
  color: var(--th-text-muted) !important;
}

/* The dark label rule above carries !important, so every label-colour state
   needs its own !important dark counterpart to beat it on specificity. */
html[data-theme="dark"] .wp-audit-card .wp-field:focus-within label {
  color: var(--th-text) !important;
}

html[data-theme="dark"] .wp-audit-card .wp-field:has(.wp-invalid) label {
  color: var(--accent-medium) !important;
}

/* The dark input-state rules below must outrank theme.css:2324, which pins
   background/border/color on every dark input with !important at (0,5,2)
   via a four-:not() selector. The long chain here is not decoration: the
   trailing `input` element selector ties (0,5,2) so source order decides
   (this file loads after theme.css); :focus versions win outright. */
html[data-theme="dark"] .wp-audit-card .wp-contact-form .wp-field input:not(:placeholder-shown) {
  background: color-mix(in srgb, var(--th-input-bg) 92%, var(--th-accent) 8%) !important;
  border-color: var(--th-border-mid) !important;
}

html[data-theme="dark"] .wp-audit-card .wp-contact-form .wp-field input.wp-invalid {
  border-color: var(--accent-medium) !important;
  box-shadow:
    0 0 0 1px var(--accent-medium),
    0 0 0 5px color-mix(in srgb, var(--accent-medium) 18%, transparent);
  background: color-mix(in srgb, var(--th-input-bg) 94%, var(--accent-medium) 6%) !important;
}

/* theme.css:2337 forces a cyan focus trio onto EVERY dark-mode input with
   !important. Invalid fields must stay red, so this needs :focus (not just
   :focus-visible) and its own !important to outrank that global rule. */
html[data-theme="dark"] .wp-audit-card .wp-contact-form .wp-field input.wp-invalid:focus,
html[data-theme="dark"] .wp-audit-card .wp-contact-form .wp-field input.wp-invalid:focus-visible {
  outline-color: var(--accent-medium) !important;
  border-color: var(--accent-medium) !important;
  box-shadow:
    0 0 0 1px var(--accent-medium),
    0 0 0 5px color-mix(in srgb, var(--accent-medium) 22%, transparent) !important;
}

html[data-theme="dark"] .wp-audit-card .wp-contact-msg.is-error {
  color: var(--accent-light);
}

/* --------------------------------------------------------------------------
   10. Motion - one entrance, not a choreographed stagger
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: no-preference) {
  .fwa-hero__copy {
    animation: fwa-rise 0.6s cubic-bezier(0.16, 1, 0.3, 1) backwards;
  }
}

@keyframes fwa-rise {
  from { opacity: 0; transform: translateY(1.2rem); }
  to   { opacity: 1; transform: none; }
}

/* --------------------------------------------------------------------------
   11. Desktop composition
   -------------------------------------------------------------------------- */

@media (min-width: 768px) {
  .fwa-page { --fwa-pad: 8rem; }

  .fwa-chapters { padding-left: 3.2rem; gap: 4.8rem; }
  .fwa-chapter::before { left: -3.65rem; }
  .fwa-chapter--first::after { left: -3.2rem; height: calc(100% + 4.8rem - 0.9rem); }

  /* The timecode stops being an annotation above the title and becomes the
     measure: right-aligned in its own gutter, level with the heading. */
  .fwa-chapter {
    display: grid;
    grid-template-columns: 8rem minmax(0, 1fr);
    column-gap: 3.2rem;
    align-items: baseline;
  }
  .fwa-chapter__time { grid-column: 1; grid-row: 1; text-align: right; margin-bottom: 0; font-size: 1.8rem; }
  .fwa-chapter__title { grid-column: 2; grid-row: 1; font-size: 3.2rem; }
  .fwa-chapter__body { grid-column: 2; grid-row: 2; margin-top: 0.8rem; }
  .fwa-chapter--end { display: grid; }
  .fwa-chapter__cut { grid-column: 2; grid-row: 1; }
  .fwa-chapter__body,
  .fwa-checklist li,
  .fwa-faq__a,
  .fwa-faq__q { font-size: 1.7rem; }
  .fwa-lede { font-size: 2rem; }
  .fwa-quote__text { font-size: 2.8rem; }
  .fwa-h1 { letter-spacing: -0.015em; }

  /* The contact sheet: three columns, frame over caption. The three frames
     expose at different ratios, so the caption drops straight under its own
     frame and any slack pools inside the card's bottom edge - the cards'
     silhouettes stay flush while the exposures differ, the way a real
     sheet's frames sit under one another. */
  .fwa-cases { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 2.4rem; }
  .fwa-case {
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 2rem;
    border-top: 1px solid rgba(255, 255, 255, 0.14);
  }
  .fwa-case__frame { flex: none; width: 100%; margin-bottom: 1.6rem; }
  .fwa-case__edge { display: block; }
  .fwa-case__cap { padding-top: 0; }
  .fwa-cases li:last-child .fwa-case { border-bottom: 0; }

  /* The pull-quote measure: at 2.8rem a full-width line would run ~55ch,
     which is a paragraph measure, not a testimony measure. */
  .fwa-quote { padding-left: 3.2rem; }
  .fwa-quote__text { max-width: 26ch; }

  .wp-audit-card { padding: 3.2rem; }
  .wp-audit-card .wp-contact_submit { width: auto; }
}

@media (min-width: 992px) {
  .fwa-hero.c-section { padding-block: 10rem 7.2rem; }

  .fwa-hero__grid {
    display: grid;
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
    gap: 6.4rem;
    align-items: center;
    width: 100%;
  }

  /* The runsheet: the signature device, present on first screen at desktop. */
  /* A preview of the rail, so it must speak the rail's language: same
     hairline, same ticks, same red head on 0:00. */
  .fwa-hero__runsheet {
    display: block;
    position: relative;
    margin: 0;
    padding-left: 2.8rem;
    border-left: 1px solid var(--th-border-mid);
    list-style: none;
  }

  .fwa-hero__runsheet li {
    position: relative;
    display: grid;
    grid-template-columns: 5.2rem 1fr;
    gap: 1.6rem;
    align-items: baseline;
    padding: 1.3rem 0;
    border-bottom: 1px solid var(--th-border);
    font-size: 1.6rem;
    font-weight: 500;
    color: var(--th-text-mid);
  }

  .fwa-hero__runsheet li::before {
    content: "";
    position: absolute;
    left: -3.25rem;
    top: 2rem;
    width: 0.9rem;
    height: 0.9rem;
    border-radius: var(--radius-50);
    background: var(--th-bg);
    border: 1px solid var(--th-border-mid);
  }

  .fwa-hero__runsheet li:first-child::before {
    width: 1rem;
    height: 1rem;
    left: -3.3rem;
    background: var(--fwa-rec);
    border-color: transparent;
    box-shadow: 0 0 0 3px var(--th-bg), 0 0 0 4.5px var(--fwa-rec);
  }

  .fwa-hero__runsheet li:last-child { border-bottom: 0; }

  .fwa-hero__runsheet span {
    font-family: var(--fwa-mono);
    font-size: 1.3rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.04em;
    color: var(--th-text-mid);
  }

  .fwa-form-grid,
  .fwa-faq-grid {
    display: grid;
    grid-template-columns: minmax(0, 0.8fr) minmax(0, 1fr);
    gap: 6.4rem;
    align-items: start;
    width: 100%;
  }

  .fwa-faq-aside { position: sticky; top: 12rem; }
  .fwa-faq-aside .fwa-sub { margin-bottom: 0; }

  .fwa-chapters { max-width: 76rem; }
}
