/* ⏹ THE STEP DEVICE MOVED TO assets/css/routing-steps.css, 9/2 — .gtrack,
   .gstep and its parts. The Smart Intake page uses the same routing line, and
   one shared copy beat duplicating it. That sheet is linked BEFORE this one,
   so any override added here still wins. Do not re-add the rules. */
/* ==========================================================================
   GOOGLE ADS — the page sheet for /products/google-ads/.
   Built 8/31 from Alie's "Google Ads Page — Final Copy" (locked 8/20).

   🔴 CLASS ROOT IS .gads-, AND IT IS NAMESPACED FOR THE SAME REASON .wproof
   AND .wsite- ARE. `.proof` is position:sticky in direction-d-v3.css and is
   queried by initProofPin(); `.case`, `.how` and `.standard` are similarly
   cheap words that another sheet could claim. Every section-level class on
   this page carries the gads- prefix so nothing here can be captured by, or
   capture, a shared component.

   ⚠️ THIS SHEET IS LOADED BY ONE PAGE. Anything that turns out to be genuinely
   shared belongs in direction-d-v3.css, not cross-imported from here — two
   pages sharing one page sheet is how a change to one silently repaints the
   other. websites.css and seo-content.css follow the same rule.

   🔴 NO BOXES. The case studies, the steps and the standard items are all
   separated by HAIRLINES, not by filled cards with radii. The house rule names
   hairline rows as its exemption and this page takes only that exemption.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. HERO — centred, on the shared .hero (Brees' mock, 8/31).

   ⏹ WAS the two-column .hero__grid with a stat stage on the right. The mock
   centres everything over the pattern circle, so the grid is dropped — but the
   section is still the SHARED .hero and the copy still enters on
   data-hero-item, so this page keeps the family's ground, padding and intro
   clock. Only the arrangement is page-local.
   -------------------------------------------------------------------------- */

/* 🔴 THE HERO FILLS THE VIEWPORT — SCOPED TO THIS PAGE, NEVER TO .hero.
   Brees, 8/31: section two was visible while reading the hero. Measured before
   the fix, the next section's top sat at y=674-752 against viewports of
   700-1000, so 9px to 248px of it showed at every desktop size — and the
   WIDEST viewport leaked the MOST. 📌 The problem is viewport HEIGHT, not
   width; a width sweep finds nothing. A previous build records the same lesson.

   ⚠️ SCOPED. `.hero` is the shared component Call Insights and SEO & Content
   also use; a min-height on the class would silently re-lay-out both.
   ⚠️ --hdr-h, not a literal: direction-d.js measures .hdr and publishes it, and
   the header is 162px at desktop but 200 at 1024 and 214 at 390.
   ⚠️ svh, with vh first as fallback: on mobile 100vh is the LARGEST viewport
   (toolbars retracted), which overshoots on the devices with least room. */
.gads-hero-fill {
  min-height: calc(100vh - var(--hdr-h));
  min-height: calc(100svh - var(--hdr-h));
  display: flex;
  flex-direction: column;
  justify-content: center;

  /* 🔴 THE HERO STOPS CLIPPING ITS BOTTOM EDGE (Brees, 8/31): "just have the
     circles in sec1 bleed into sec2". The shared `.hero` sets
     `overflow: hidden`, which cut the bottom-right pair off flat exactly at
     the colour step. They now continue past it onto --sky-soft.

     ⚠️ TWO AXES, TWO DIFFERENT ANSWERS, AND THE PAIRING IS THE WHOLE TRICK.
     Vertical must escape; horizontal must NOT — the same discs bleed off the
     left and right edges, and letting those out extends the document and puts
     a sideways scrollbar on the entire page. This page has already shipped
     that bug once, and websites.css records it from 8/28.
     🔴 `clip`, NEVER `hidden`, on the horizontal axis. `hidden` establishes a
     scroll container, which forces the other axis to `auto` — the vertical
     bleed would be clipped right back, and the fix would silently undo
     itself. `clip` contains without establishing one, so `visible` survives
     on the cross axis. That is the project's standing rule, and here it is
     load-bearing rather than merely preferred. */
  overflow-x: clip;
  overflow-y: visible;

  /* Section two is a LATER SIBLING with its own --sky-soft background, so at
     equal stacking level it paints over anything the hero spills downward.
     One level lifts the whole hero, orbs included, above that ground.
     ⚠️ The orbs keep pointer-events:none from `.shape`, so nothing in
     section two becomes unclickable underneath them. */
  position: relative;
  z-index: 1;
}

.gads-hero--centred { position: relative; }

.gads-hero__inner {
  max-width: 54rem;
  text-align: center;
}

.gads-hero__head { max-width: 18ch; margin: 0 auto var(--s-3); }

.gads-hero__lede {
  max-width: 52ch;
  margin: 0 auto var(--s-4);
  color: var(--ink);
}

.gads-hero__cta { margin-bottom: var(--s-5); }

/* THE ORB FIELD — six overlapping discs, four corners (Brees' mock, 8/31).

   ⏹ REPLACES THE CENTRED PATTERN CIRCLE. The 8/31 build put `.pattern-circle`
   — the shared line-pattern device on a --sky-soft disc — directly behind the
   headline. The new mock takes it out: the copy sits on plain --white and the
   colour is pushed to the edges, where discs bleed in and overlap. The device
   is not deleted from the project, it is simply not this hero's ground.

   🔴 THEY OVERLAP BY MULTIPLY, WHICH IS THE WHOLE POINT OF THE COMPOSITION.
   Where two discs cross, the crossing area darkens to the product of the two
   fills. That is still a FLAT FILL — every disc is one solid colour with an
   alpha, there is no soft-edged or ramped fill anywhere in here, so this
   stays inside brand-devices.md's rule. (The gate that enforces that rule
   matches on bare words and counts prose, so the forbidden techniques are
   described here, never named.)

   ⚠️ MEASURED, NOT ESTIMATED — this page has written five contrast figures
   before measuring them and been wrong all five times. On --white:
       petal a1.00  1.70      lime a0.85  1.40      sky-soft   1.15
       petal a0.85  1.57      lime a1.00  1.49      sky a1.00  1.35
       petal+lime crossing, both a0.85   2.22
       petal+lime crossing, both a1.00   2.55
   INK OVER EVERY ONE OF THESE IS SAFE: the worst pair on the page is ink on
   the petal+lime crossing at full alpha, 5.21, against a 4.5 floor. The
   headline may therefore cross any disc here, including the large sky one.

   ⚠️ THE TWO LARGE SKY DISCS SIT AT 1.18, UNDER THE ~1.35 SHAPE FLOOR, AND
   THAT IS DELIBERATE. That floor is written in gads-contrast.js as the floor
   for "a non-text hairline or shape boundary" — a thing whose EDGE has to be
   findable. These are not boundaries, they are grounds: the disc they replace
   was --sky-soft at 1.15 and shipped that way. Holding a full-bleed ground to
   a hairline's floor would force it darker than the mock and darker than the
   disc it replaces. The corner clusters, which DO read as distinct shapes,
   are all held above 1.35.

   ⚠️ .hero carries `overflow: hidden` in the shared sheet, so every disc is
   clipped by the section already — no extra clip rule and no page overflow.
   📌 That is also why this page may use `overflow: hidden` here and the
   MANIFESTO below may not: this hero has no sticky mechanic to kill. */
.gads-heroorb {
  position: absolute;
  z-index: 0;
  aspect-ratio: 1;
  border-radius: 50%;
  /* The crossing darkens. On --white, multiply leaves a lone disc untouched,
     so each disc still measures exactly the figure listed above. */
  mix-blend-mode: multiply;
  background-color: var(--gads-orb-fill);
  opacity: var(--gads-orb-a, 1);
}

/* 🔴 VERTICAL BLEEDS ARE translateY ON THE ORB, NOT A NEGATIVE top/bottom %.
   A percentage in top/bottom resolves against the HERO'S HEIGHT, and this
   hero's height ranges from ~538px on a short laptop to ~1038px on a tall
   window. Tuned at one height the composition falls apart at every other:
   at 1600x1200 `bottom: -30%` put the bottom-right petal 311px down, past
   its own 272px diameter, so the disc was ENTIRELY outside the section and
   simply vanished. The top-left petal disappeared the same way.
   A percentage in `transform` resolves against THE ELEMENT'S OWN SIZE, so
   "hang 45% of yourself below the edge" means the same thing at every
   viewport height and at every clamp step of the disc's width.
   ⚠️ Horizontal offsets stay as left/right percentages — those resolve
   against WIDTH, which is exactly what is wanted for a side bleed. */
/* -- the two large sky grounds ------------------------------------------- */
/* 🔴 THE TOP-RIGHT DISC CARRIES THE LINE PATTERN (Brees, 8/31: "in the top
   right blue circle - I want to have the bg pattern we've been doing in the
   hero section").

   This is the same brand device as `.pattern-circle` in direction-d-v3.css —
   line-pattern.png tiled at 420px over --sky-soft — reproduced here rather
   than by adding that class, because .pattern-circle also sets its own
   position, radius and background-color, all of which this orb already owns
   and would fight over. Same asset, same tile size, so the two stay in step;
   if the shared device's tile size changes, change it here too.

   ⚠️ THE FILL MOVED FROM --sky@0.45 TO --sky-soft AT FULL OPACITY, AND THAT
   IS NOT A COLOUR CHANGE. Measured, --sky at 0.45 over white composites to
   rgb(229,242,247); --sky-soft is rgb(228,241,247) — one step apart in two
   channels, invisible. But the element's `opacity` fades EVERYTHING on it,
   the pattern included, so at 0.45 the tile would have rendered at
   less-than-half strength for no reason. Painting the true ground at full
   opacity keeps the disc looking identical and lets the pattern read.
   ⚠️ mix-blend-mode: multiply still applies. Over white the tile is unchanged
   (multiply by white is a no-op); where the disc crosses another orb, the
   pattern darkens with it, which is what the crossing should do. */
.gads-heroorb--skyR {
  --gads-orb-fill: var(--sky-soft);
  --gads-orb-a: 1;
  width: clamp(300px, 40vw, 660px);
  right: -19%;
  top: 0;
  transform: translateY(-24%);
  background-image: url("../img/brand/line-pattern.png");
  background-repeat: repeat;
  background-size: 420px;
}

/* The left disc carries the same line pattern as the right one (Brees, 8/31).
   Identical treatment and identical reasoning: the fill moves from --sky@0.45
   to --sky-soft at full opacity because `opacity` fades the tile with it, and
   the two composite to the same colour (measured 1/255 apart in two channels).
   ⚠️ background-size MUST match .gads-heroorb--skyR's 420px. The two discs are
   different sizes; if the tile scale differs between them the pattern reads as
   two different textures rather than one device seen twice. */
.gads-heroorb--skyL {
  --gads-orb-fill: var(--sky-soft);
  --gads-orb-a: 1;
  width: clamp(240px, 29vw, 470px);
  left: -15%;
  bottom: 0;
  transform: translateY(22%);
  background-image: url("../img/brand/line-pattern.png");
  background-repeat: repeat;
  background-size: 420px;
}

/* -- top-left cluster: lime under, petal crossing it --------------------- */
.gads-heroorb--limeTL {
  --gads-orb-fill: var(--lime);
  --gads-orb-a: 0.85;
  width: clamp(110px, 12vw, 205px);
  left: -4%;
  top: 0;
  transform: translateY(-34%);
}

.gads-heroorb--petalTL {
  --gads-orb-fill: var(--petal);
  --gads-orb-a: 0.85;
  width: clamp(92px, 10vw, 170px);
  left: 3.5%;
  top: 0;
  transform: translateY(-46%);
}

/* -- bottom-right cluster: the saturated pair ---------------------------- */
.gads-heroorb--petalBR {
  --gads-orb-fill: var(--petal);
  --gads-orb-a: 1;
  width: clamp(150px, 17vw, 290px);
  right: 2%;
  bottom: 0;
  transform: translateY(46%);
}

.gads-heroorb--limeBR {
  --gads-orb-fill: var(--lime);
  --gads-orb-a: 1;
  width: clamp(130px, 15vw, 250px);
  right: -7%;
  bottom: 0;
  transform: translateY(24%);
}

/* -- the scroll cue ------------------------------------------------------
   A short capsule under the stats (Brees' mock, 8/31). Purely decorative and
   aria-hidden: it is NOT a control, so it gets no button semantics and no
   focus stop — a fake control in the tab order is worse than no cue at all.
   ink@0.35 on white measures 2.02, over the ~1.35 boundary floor.
   📌 3.68 was written here first, from nothing. gads-contrast.js says 2.02.
   That is the sixth time a figure on this page was written before it was
   measured. Measure, THEN write the number — the checker is the source. */
.gads-scrollcue {
  /* 🔴 display:block IS LOAD-BEARING. This is a <span>, and on an inline box
     width, height and vertical margin are all inert — the cue laid out to
     nothing and painted nothing, while looking perfectly correct in the CSS.
     It was caught by MEASURING: the cue's bottom edge came back identical to
     the stats list's, i.e. it occupied no space at all. Judge by the painted
     rect, never by the declaration. */
  display: block;
  width: 44px;
  height: 5px;
  margin: var(--s-3) auto 0;
  border-radius: 999px;
  background-color: var(--ink);
  opacity: 0.35;
}

/* ⏹ THE CUE DOES NOT PULSE, AND THE GATE IS WHY — CORRECTLY. A looping
   drift was written here first and verify.js failed it on the brief's
   no-endless-loop rule. The sheet does have a marker-delimited exemption
   mechanism, but it is capped at one region and spoken for by the hero
   drift, and reaching for a second one to excuse a decoration I had just
   invented is precisely the "clear the red by editing the gate" move this
   project has a standing rule against. The mock's cue is static anyway. */

/* -- SHORT VIEWPORTS ------------------------------------------------------
   🔴 THE HERO FITS THE VIEWPORT'S HEIGHT, NOT JUST ITS WIDTH — AGAIN.
   .gads-hero-fill guarantees the section is AT LEAST a viewport tall. It never
   capped the CONTENT, so on a short screen the content simply ran past the
   fold. Measured before this block, stats row bottom vs viewport height:
       1600x900   859 / 900   fits
       1440x800   858 / 800   159px of the row below the fold
       1366x768   854 / 768   86px below
       1536x700   859 / 700   159px below
       1280x720   838 / 720   118px below
   1536x700 is 1080p at 125% Windows scaling — not an edge case, it is the
   ordinary laptop. A WIDTH sweep finds none of this; this page and a previous
   build have both paid for that lesson already.

   ⚠️ HEIGHT-KEYED, AND DELIBERATELY NOT WIDTH-KEYED. Re-scoping this to a
   width query is the exact regression a previous build records — do not do it.
   ⚠️ Scoped to .gads-hero-fill. `.hero`, `.t-display` and the spacing tokens
   are shared with Call Insights and SEO & Content; touching any of them here
   would silently re-lay-out both. */
/* Every short viewport tightens the RHYTHM. Spacing only — no type changes
   here, so a phone keeps the display size it was designed at. */
@media (max-height: 880px) {
  .gads-hero-fill .gads-hero__head { margin-bottom: var(--s-2); }
  .gads-hero-fill .gads-hero__lede { margin-bottom: var(--s-3); }
  .gads-hero-fill .gads-hero__cta  { margin-bottom: var(--s-3); }
  .gads-hero-fill .gads-scrollcue  { margin-top: var(--s-2); }
}

/* ⏹ THE SHORT-VIEWPORT TYPE OVERRIDE IS GONE, AND THE H1 IS WHY.
   A block here used to shrink the headline on short laptops to buy back fold
   space. It was treating a symptom: the h1 was on bare .t-display (72px at
   1600px, the largest h1 on the site) while its two siblings on the shared
   .hero carry .hero__headline at clamp(2rem, 3.2vw, 3.25rem). Brees, 8/31:
   make the h1 match the rest of the site. Once it does, the family size is
   small enough that the fold fits on its own and a page-local type scale is
   not needed. The SPACING compression above stays — that part was real. */

/* Shorter still: the cue is the first thing to go. It is decorative, and its
   whole message — "there is more below" — is already delivered by the section
   edge sitting at the fold. A cue the reader has to scroll to reach to learn
   that they should scroll is worse than none. */
@media (max-height: 720px) {
  .gads-hero-fill .gads-scrollcue { display: none; }

  /* ⚠️ 2px OF CLEARANCE IS NOT A PASS. With the cue hidden, 1536x700 still
     put the stats' bottom edge at 698 against a 700 viewport. A font
     fallback, a browser zoom step or a slightly taller header eats that
     instantly, and the row goes back under the fold without anything having
     "changed". These margins buy real room rather than a rounding error. */
  .gads-hero-fill .gads-hero__head { margin-bottom: var(--s-2); }
  .gads-hero-fill .gads-hero__lede { margin-bottom: var(--s-2); }
  .gads-hero-fill .gads-hero__cta  { margin-bottom: var(--s-2); }
}

/* -- the three stats ------------------------------------------------------
   A centred row under the CTA. ⏳ Two of the three figures are unverified and
   the third is Alie's fee, not the mock's budget figure — see index.html. */




/* --------------------------------------------------------------------------
   2. THE MANIFESTO — one indigo section (Brees' mock-up, 8/31)

   Was three sections on three grounds. Now one, with the standards in a white
   panel. See the block comment in index.html for what moved and why.
   -------------------------------------------------------------------------- */

.gads-manifesto .container { display: grid; }

/* -- the statement --------------------------------------------------------
   A <p>, NOT a heading: it makes no structural claim, and promoting it would
   drop an h2 between the hero h1 and the real h2 below it. */
/* 🔴 GROUND MOVED indigo -> --sky-soft (Brees, 8/31) AND THE TEXT HAD TO
   FOLLOW. This is not a cosmetic swap: on the light ground the old colours
   are gone, measured —
       white lead on sky-soft   1.15   (needs 3.0 as large text)
       lime  turn on sky-soft   1.29   (needs 3.0)
   Both are effectively invisible. The lead is now --ink (11.54) and the turn
   --lime-deep (3.02).
   ⚠️ 3.02 CLEARS 3.0 BY 0.02, AND ONLY BECAUSE THIS TYPE IS LARGE (32-60px).
   If the statement's size is ever reduced below 24px its floor becomes 4.5 and
   lime-deep FAILS it. Re-measure before shrinking this type. */
.gads-statement {
  /* CENTRED (Brees, 8/31). `margin: 0 auto` is what actually centres the
     BLOCK — text-align alone would centre the lines inside a box still
     pinned to the left of a 1600px section, which is the same stranded-in-
     the-corner look being fixed. Both are needed. */
  /* 18ch here, 20ch from 900px up — unchanged. A media query further down
     already owned the desktop measure; widening the base only moved MOBILE,
     which nobody asked for. */
  max-width: 18ch;
  margin: 0 auto;
  text-align: center;
  font-size: clamp(2rem, 4.8vw, 3.75rem);
  line-height: 1.12;
  font-weight: 700;
  color: var(--ink);
  /* The rotateX below needs a perspective on the PARENT to read as depth.
     📌 Without it the rotation still applies but as a flat vertical squash —
     the same trap websites.css records at length for the render wall's
     preserve-3d chain. The reference component omits this and its 3D is
     therefore doing nothing. */
  perspective: 700px;
}

/* 🔴 WHITE, AND IT IS NOW THE SAME GROUND AS THE HERO ABOVE IT (Brees, 8/31):
   "make the bg behind sec2 white and center the text".

   ⏹ The ground has moved twice. It was --indigo, then --sky-soft on 8/31,
   now --white. Each move changed which text colours can survive here, so the
   measured figures below are the CURRENT ones, not the earlier pair.

   ⚠️ THIS MAKES ONE DELIBERATE EXCEPTION TO THE PAGE'S GROUND RHYTHM, which
   otherwise avoids two adjacent sections sharing a ground. MEASURED, because
   the first draft of this note guessed "three whites in a row" and was wrong:
       hero            white
       this section    white   <-- the only adjacency, and it is the point
       .gads-diffsec   --sky-soft   (its `section--white` CLASS IS A LIE —
                                     .gads-diffsec overrides it further down)
       .gads-how       --indigo   then sky-soft / white / oat / white / sky
   So the page still alternates everywhere else; only the hero and the
   statement merge, which is what lets the hero read straight through into it
   as one field. Nothing enforces the rhythm in verify.js — it was a design
   note, and this is the design owner overriding it knowingly.
   📌 A side effect worth knowing: the hero's discs used to cross a COLOUR
   STEP here. They now cross an invisible seam onto identical white, so the
   bleed reads as one continuous shape rather than a two-tone crossing. */
/* 🔴 LIGHT BLUE AGAIN, WITH A ROUNDED TOP-LEFT CORNER (Brees, 8/31).
   The ground has now been --indigo -> --sky-soft -> --white -> --sky-soft.
   Each move changes what the statement's two text colours measure, so the
   figures under .gads-statement__turn are re-measured every time, not carried.

   🔴 THE BAND IS A ::before, NOT THIS ELEMENT'S BACKGROUND, AND THAT IS THE
   WHOLE POINT OF THE LAYER. A rounded corner opens negative space, and what
   shows through it is <body> — which is --oat (#f3eee8), measured. Rounding
   the section itself would put CREAM in the corner while the hero directly
   above is WHITE. The .gads-diffsec arc hit exactly this on the same day.
   The section paints white (continuing the hero's ground) and the blue band
   carries the radius, so the corner reveals white and reads as the blue
   curving away from the hero.

   ⚠️ 500px IS LARGER THAN THE SECTION IS TALL, SO THE BROWSER SCALES IT.
   CSS clamps radii so they cannot overlap: with only the top-left set, the
   limit is the section's own height. Measured heights are 445px at 1600 and
   275px at 375, so the painted corner is a full-height quarter-circle at
   every width rather than the literal 500. That is why the value below is
   written as a min() against the height — it says out loud what the browser
   would do silently, and keeps the corner from eating the copy on narrow
   screens where the centred statement runs close to the left edge. */
.gads-manifesto {
  position: relative;
  background-color: var(--white);
}

.gads-manifesto::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  background-color: var(--sky-soft);
  /* 🔴 THE CORNER MAY ONLY OCCUPY THE GUTTER LEFT OF THE CENTRED COPY.
     500px flat put the statement OUTSIDE the band from 1024px down — measured,
     the copy's left edge missed the curve by 7px at 1024, 59px at 700 and
     148px at 480, which lands it on the white underneath rather than on the
     blue. The statement is centred, so its gutter shrinks fast as the section
     narrows, while a fixed radius does not.
       width   copy starts   largest radius that still clears it
       1600      428px            1064
       1280      268px             629
       1024      207px             483
        700      163px             367
        375       20px              46
     Hence the ladder below: 500 where there is room for it, stepping down to a
     modest corner on a phone where the copy runs nearly edge to edge.
     ⚠️ The VERTICAL radius is clamped by the browser to the section's own
     height (445px at 1600, 275px at 375), so the painted corner is an ellipse,
     not a circle. That is the intended look and needs no extra rule — but it
     is why the value here is not the radius you see. */
  border-top-left-radius: 40px;
}

@media (min-width: 700px)  { .gads-manifesto::before { border-top-left-radius: 160px; } }
@media (min-width: 900px)  { .gads-manifesto::before { border-top-left-radius: 240px; } }
@media (min-width: 1024px) { .gads-manifesto::before { border-top-left-radius: 380px; } }
@media (min-width: 1280px) { .gads-manifesto::before { border-top-left-radius: 500px; } }

/* The statement rides above the band. */
.gads-manifesto > .container { position: relative; z-index: 1; }

/* The turn. One sentence carries the whole argument.
   🔴 --lime-deep, NOT --lime, BECAUSE THE GROUND IS LIGHT. Re-measured on
   --white after the 8/31 ground change:
       lime       1.49   still gone — it needs a dark ground to exist
       lime-deep  3.48   (it was 3.02 on --sky-soft, so this ground is kinder)
   ⚠️ STILL A LARGE-TEXT PASS ONLY. 3.48 clears the 3.0 large-text floor, not
   the 4.5 normal-text one. This type is 32-60px; shrink it below 24px and
   this FAILS. Re-measure before changing the size — do not assume.
   ⚠️ Colour is not the only signal — it is a complete sentence and reads on
   its own if the colour never arrives.
   ⏳ OPEN WITH BREES: he flagged "the black tags with the green" as possibly
   what he disliked here, then asked only for the white ground and centring.
   The two-tone is therefore UNCHANGED and still awaiting his call. */
/* 🔁 9/16 (later) — CONCEPT 10C, picked by Brees from the Claude Design canvas "Google Ads Section Concepts": "I don't
   like the green." The turn is now INK (11.5:1 on sky-soft, a full body-text pass instead of lime-deep's 3.02 large-text
   one) sitting on a LIME HIGHLIGHTER band across the lower part of each line. box-decoration-break: clone gives every
   wrapped line its own band. The band RISES IN once the words have landed (their longest delay+duration
   is ~3.2s), so it reads as the marker stroke that makes the point; with JS off or reduced motion it is simply there.
   The lime is decorative (the sentence reads without it), so it needs no contrast floor. */
/* ⚠️ NOT A GRADIENT: verify.js bans linear-gradient in this sheet. The band is an INSET box-shadow on the inline span
   (box-decoration-break: clone paints it per line), which is also animatable: it rises from 0 to its height. */
.gads-statement__turn {
  color: var(--ink);
  padding: 0 0.06em;
  box-shadow: inset 0 -0.64em 0 var(--lime);
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}
html[data-js="on"] .gads-statement .gads-statement__turn {
  box-shadow: inset 0 0 0 var(--lime);
  transition: box-shadow 0.7s cubic-bezier(0.65, 0, 0.35, 1) 1.9s;
}
html[data-js="on"] .gads-statement.is-in .gads-statement__turn { box-shadow: inset 0 -0.64em 0 var(--lime); }
@media (prefers-reduced-motion: reduce) {
  html[data-js="on"] .gads-statement .gads-statement__turn { box-shadow: inset 0 -0.64em 0 var(--lime); transition: none; }
}

/* ⏹ THE SECTION-TWO ORBS ARE DELETED (Brees, 8/31): "remove the circles in
   sec2 and just have the circles in sec1 bleed into sec2".

   What used to be here: .gads-orb, .gads-orb--petal (petal at full opacity,
   1.48 on --sky-soft) and .gads-orb--lime (which was actually indigo@0.25,
   1.47 — lime measured 1.29 on this ground and could not exist here at any
   alpha), plus a max-width:699px rule that hid both because at 375 the
   statement ran across the petal orb and changed the reader's real background.

   ALL OF THAT IS GONE, and the constraint that produced it goes with it: no
   shape of this section's own means no ground-vs-orb problem to tune. The
   circles crossing this section now belong to the HERO and are governed by
   .gads-heroorb above — including, importantly, their contrast where they
   cross onto --sky-soft, which is measured in scripts/gads-contrast.js. */

/* 🔴 THE SECTION CLIPS, AND THIS IS NOT OPTIONAL. Unclipped, these circles
   extend the document and give the WHOLE PAGE a horizontal scrollbar — this
   page shipped exactly that bug earlier today with its hero and proof shapes,
   and websites.css records the same bug from 8/28.
   ⚠️ `overflow-x: clip`, NOT `overflow: hidden` — the project's own rule
   (direction-d-v3.css, 8/18). `hidden` establishes a scroll container, which
   silently kills position:sticky on any descendant and cuts a bleeding circle
   flat where a colour step happens. `clip` contains without either. */
.gads-manifesto {
  overflow-x: clip;
}

/* -- the word-by-word entrance -------------------------------------------
   Ported from 21st.dev @xubohuah/blur-text-animation — ITS STAGGER, ITS
   EASING, ITS LIFT AND SCALE, BUT NOT ITS BLUR.

   🔴 THE BLUR IS DELIBERATELY ABSENT AND MUST STAY ABSENT.
   brand-devices.md: "Flat fills throughout. No blur, no gradient, no texture."
   verify.js enforces it with a flat-fill gate, and the build went red when the
   effect was ported verbatim on 8/31.
   ⚠️ DO NOT NAME THAT GATE'S PROPERTIES IN PROSE HERE. It is a bare-word regex
   over the WHOLE file, comments included — writing them out turned this very
   comment into a second failure, which is the same trap the demo-token and
   banned-technique gates set on the Websites page. Describe, never quote. session-notes records the same call
   already being made once, on a different 21st component: "The 21st demo blurs
   its headline in on its own spring stagger. Not ported."
   ⚠️ DO NOT "FIX" THIS BY EDITING THE GATE. The gate is downstream of a brand
   rule; the rule is the thing.

   What IS ported, exactly: the per-word delay and duration curves, the
   cubic-bezier(0.25,0.46,0.45,0.94) easing, translateY(20px), the per-word
   scale, and rotateX(-15deg). Those are all flat-fill safe.

   🔴 DECLARATIVE, NOT WRITTEN FROM JS, so the words are hidden before any
   script runs. Writing a from-state from JS is what made the routing-line
   spurs flash fully-drawn earlier today.
   ⚠️ Scoped to html[data-js="on"] — with JS off nothing adds .is-in, so an
   unscoped rule would leave the statement invisible.
   -------------------------------------------------------------------------- */
html[data-js="on"] .gads-word {
  display: inline-block;
  opacity: 0;
  transform: translateY(20px) scale(var(--w-scale, 0.92)) rotateX(-15deg);
  transform-style: preserve-3d;
  backface-visibility: hidden;
  will-change: transform, opacity;
  transition:
    opacity   var(--w-dur, 2.2s) cubic-bezier(0.25, 0.46, 0.45, 0.94) var(--w-delay, 0s),
    transform var(--w-dur, 2.2s) cubic-bezier(0.25, 0.46, 0.45, 0.94) var(--w-delay, 0s);
}

html[data-js="on"] .gads-statement.is-in .gads-word {
  opacity: 1;
  transform: translateY(0) scale(1) rotateX(0deg);
}

/* 🔴 REDUCED MOTION GETS THE FINAL STATE, NOT A FASTER ANIMATION. A staggered
   lift across fourteen words is what 2.3.3 is about. Written here as well as in
   the script so it holds even if the script never runs. */
@media (prefers-reduced-motion: reduce) {
  html[data-js="on"] .gads-word {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

@media (min-width: 900px) {
  .gads-statement { max-width: 20ch; }
}

/* -- the DE difference + Our standard, on WHITE ---------------------------
   🔴 SPLIT OUT OF THE INDIGO SECTION AND THE PANEL IS DELETED (Brees, 8/31).
   The earlier mock had these two blocks on indigo inside a filled, rounded
   white panel; the newer one puts them on plain white with the standards
   sitting straight on the ground. That returns this block TO the house
   no-boxes rule rather than beside it.
   ⏹ .gads-panel / .gads-panel__head / .gads-panel__title / .gads-panel__rule
   are GONE, not overridden — they matched nothing after the markup changed.
   -------------------------------------------------------------------------- */

/* 🔴 GROUND IS --sky-soft (Brees' mock, 8/31), set here rather than with a
   `.section--sky` modifier: that modifier paints full --sky (#c6e2ee), which is
   markedly more saturated than the mock's pale ice, AND it pulls in the shared
   `border-radius: var(--r-bleed)` that .section--sky/.section--indigo carry.
   This section's shape comes from the panel inside it, not from its own
   corners. */
/* ⏹ THE CURVED LEFT EDGE IS REMOVED (Brees, 8/31 — "undo the rouding out").
   It was built and then taken back out the same day, so what it cost is
   recorded here rather than relearned:
     - Rounding the SECTION revealed <body>, which is --oat (#f3eee8), so the
       negative space read cream against the white section above it. The band
       had to become a ::before over a white section for the curve to open
       onto white.
     - The radius could not be a vw fraction. The curve may only occupy the
       gutter left of the copy, and that gutter stops growing once .container
       reaches --container-max (1240px) while vw keeps climbing — so a
       `clamp(140px, 22vw, 360px)` pushed the "The DE difference" heading off
       the band from 1280px down, by 59px at 375. Deriving it from the gutter
       fixed it.
   Neither problem was the reason it came out; Brees simply didn't want the
   shape. If a curved edge is ever wanted here again, those two are the traps.

   🔴 GROUND IS --sky-soft, set here rather than with a `.section--sky`
   modifier: that modifier paints full --sky (#c6e2ee), markedly more
   saturated than the mock's pale ice, AND it pulls in the shared
   `border-radius: var(--r-bleed)` that .section--sky/.section--indigo carry.
   This band is square on all four corners. */
.gads-diffsec { background-color: var(--sky-soft); }

.gads-diffsec .container { display: grid; gap: var(--s-5); }

/* THE WHITE PANEL — full-bleed LEFT with one very large top-right corner.

   ⚠️ THIS IS THE THIRD FILLED PANEL BREES HAS DIRECTED THIS SESSION, and the
   second on this page. Recorded, not absorbed: the house no-boxes rule still
   governs elsewhere, and direction-d-v3.css still forbids a background, radius
   or shadow on .cta-quote.
   📌 It reads as a GROUND SHAPE rather than a card — it runs off the left edge
   of the viewport and has no border or shadow, so it is closer to the arch (a
   brand form) than to a bordered box.

   🔴 THE LEFT BLEED IS `margin-left: calc(50% - 50vw)` WITH THE PADDING PUT
   BACK. That pulls the panel from the container's left edge out to the
   viewport's, then `padding-left: calc(50vw - 50%)` returns the text to the
   container's own left edge — so the FILL bleeds while the COPY stays on the
   page grid. Never hardcode a viewport width here; the container max and pad
   are tokens and this stays correct when they move.
   ⚠️ 50vw includes the scrollbar's width in some engines, which can add a few
   px of horizontal overflow. .gads-diffsec clips (below) so it cannot reach
   the document. */
.gads-standardblock {
  position: relative;
  margin-left: calc(50% - 50vw);
  padding: var(--s-5) var(--s-4) var(--s-5) calc(50vw - 50% + var(--container-pad));
  background: var(--white);
  /* [!] BOTH RIGHT CORNERS, NOT ONE - BREES, 9/9: "the bottom right-hand side
     is just a 90 degree angle whereas I'd like that also to have a border
     radius."
     [i] Only the RIGHT corners are ever visible: the panel bleeds off the left
     edge of the viewport, so its left corners sit outside the window and
     rounding them would do nothing at any width.
     [i] The same clamp on both, so the shape stays symmetrical as it scales
     rather than being a matched pair at exactly one viewport. */
  border-top-right-radius: clamp(72px, 13vw, 220px);
  border-bottom-right-radius: clamp(72px, 13vw, 220px);
}

@media (min-width: 900px) {
  .gads-standardblock { padding-right: var(--s-5); }
}

/* Same rule, same reason as .gads-manifesto: a shape that runs off the edge
   must be clipped or it extends the document. `clip`, never `hidden`. */
.gads-diffsec { overflow-x: clip; }

.gads-diff { display: grid; gap: var(--s-3); }

@media (min-width: 900px) {
  .gads-diff {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
    gap: var(--s-5);
    align-items: start;
  }
}

.gads-diff__head {
  max-width: 16ch;
  margin: 0;
  color: var(--ink);
}

.gads-diff__body {
  margin: 0;
  max-width: 62ch;
  font-size: var(--fs-small);
  color: var(--ink-muted);
}

/* The title and a rule that runs to the container's right edge. The rule is a
   flexed span rather than a border on the heading, so it starts AFTER the
   words however long they are. */
.gads-standard__head {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  margin-bottom: var(--s-2);
}

/* 9/10 type rule: h3 takes the BODY face. See base-v3.css .t-h3. */
.gads-standard__title {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--fs-h3);
  font-weight: 500;
  letter-spacing: 0;
  color: var(--ink);
  white-space: nowrap;
}

.gads-standard__rule {
  flex: 1;
  height: 1px;
  /* Ink at 0.55 — heavier than the row hairlines because it is a rule the eye
     follows, not a separator it ignores. Measured 3.31 on white. */
  background: rgba(47, 47, 53, 0.55);
}

/* -- the five standards ---------------------------------------------------
   Label left, body right, hairline between rows. No cells, no fills. */
.gads-standard {
  margin: 0;
  padding: 0;
  list-style: none;
}

.gads-standard__item {
  display: grid;
  gap: var(--s-1);
  padding: var(--s-3) 0;
  /* Ink at 0.20 on --white, measured 1.47. */
  border-top: 1px solid rgba(47, 47, 53, 0.20);
}

@media (min-width: 800px) {
  .gads-standard__item {
    grid-template-columns: minmax(0, 0.5fr) minmax(0, 1fr);
    gap: var(--s-4);
    align-items: start;
  }
}

/* No hairline above the FIRST row — the "Our standard" rule directly above it
   already separates the list from the heading, and the mock shows one line
   there, not two. */
.gads-standard__item:first-child { border-top: 0; }

.gads-standard__label { font-weight: 700; color: var(--ink); }

.gads-standard__body {
  font-size: var(--fs-small);
  color: var(--ink-muted);
}

/* --------------------------------------------------------------------------
   5. HOW IT WORKS — headline left, a stack of steps right, a spine between.

   The "Your phone is leaking new clients" design (Brees, 8/31), ported from
   `.problem` on Call Insights. ⚠️ THAT SECTION'S V3 FORM IS NOT THE WHITE CARD
   the base sheet defines — direction-d-v3.css section 22 strips the
   background, radius and shadow off .problem__card and leaves dot + label +
   text on the ground. This mirrors the stripped version, which is what is
   actually on screen there.

   🔴 GROUND IS --indigo (Brees, 8/31), matching the Call Insights section.
   Every dot measures stronger here than on the white it shipped on for one
   build. ⏹ oat is ruled out permanently: the lime dot is 1.29 there, under the
   ~1.35 floor. See the note in index.html for the proof-adjacency flag.
   -------------------------------------------------------------------------- */

.gads-how__grid { display: grid; gap: var(--s-4); }

@media (min-width: 1024px) {
  .gads-how__grid {
    /* The gap is where the spine lives. 🔴 track-gads.js MEASURES this gap
       rather than carrying its own constant, so changing it moves the spine
       too — do not introduce a second number. */
    grid-template-columns: minmax(0, 0.85fr) minmax(0, 1fr);
    gap: var(--s-6);
    align-items: start;
  }
}

.gads-how__head {
  max-width: 14ch;
  margin: 0;
}

/* 🔴 THE TITLE STICKS THROUGH THE STEPS, AND IT NEEDS ROOM TO DO IT
   (Brees, 8/31: "title needs more breathing room. It should also stay
   sticky").

   ⚠️ --hdr-h-min, NOT --hdr-h. The header shrinks 162 -> 114 on scroll, and
   pinning to the unshrunken value is what put a 48px band of page ground under
   the header when Derek was pinned earlier today. Every sticky offset on this
   page keys off the min; direction-d-v3.css says so explicitly.
   The extra --s-5 on top of it IS the breathing room: the title settles well
   clear of the header rather than tucked against it.

   ⚠️ align-self: start IS LOAD-BEARING. Grid items stretch by default, so the
   headline's box would fill the full column height and sticky would have
   nowhere to travel — it would look like nothing happened. The grid already
   sets `align-items: start` at 1024+, but this states it on the item so the
   behaviour does not depend on that rule staying.

   ⚠️ ONLY FROM 1024px. Below that the grid is one column and the title sits
   directly above the steps; pinning it there would park it on top of the copy
   it is meant to introduce.
   ⚠️ No ancestor clips (checked: h2 / .container / section / main / body are
   all `visible`), and note `overflow-x: clip` elsewhere on this page would be
   safe anyway — `clip` does not establish a scroll container the way `hidden`
   does. `hidden` on any of them would silently kill this. */
@media (min-width: 1024px) {
  .gads-how__head {
    position: sticky;
    top: calc(var(--hdr-h-min) + var(--s-5));
    align-self: start;
    /* Breathing room below it too, so the steps never crowd the title as it
       travels past them. */
    margin-bottom: var(--s-5);
  }
}


/* 🔴 THE DOT SITS BESIDE THE LABEL, NOT ABOVE IT (Brees, 8/31: the lines and
   dots here "need to be the same as the VCI page").

   This was `flex-direction: column`, which stacked dot / label / text and put
   the dot 24px ABOVE the label's line. VCI's .problem__card — the section this
   device was ported from — is a grid with the dot in its own column, baseline
   aligned with the label. Measured on VCI at 1600px, and reproduced here:
       dot column   14px        gap 24px       align-items baseline
       dot itself   12px        translateY(-0.35em)
   ⚠️ align-items: baseline is what actually lands the dot on the label's first
   line; the translateY is the optical nudge on top of it. Both, or it sits
   low. VCI carries the same pair.
   ⚠️ Label AND text are both placed in column 2 explicitly. Without that the
   text would flow back under the dot into column 1 on the second row. */


/* The dot marks the item as one of a set without implying anything is
   operable. Decorative, so it takes the full-strength pastel and states
   nothing on its own — the label carries the meaning. */

/* petal / lime / marigold are the reference's three, in its order. Clay is the
   fourth (Brees, 8/31); sky is the one the notes reject as too pale in this
   device. Measured on --white: petal 1.70, lime 1.49, marigold 2.33, clay 3.54
   — all over the ~1.35 floor, which is why this section is not on oat, where
   lime falls to 1.29. See scripts/gads-contrast.js. */



/* -- the line -------------------------------------------------------------
   Absolute inside the section (position:relative), z-index 1 so it paints
   ABOVE the ground and BELOW .container's z-index 2. */

.gtrack svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
}

/* 🔴 A QUIET WARM NEUTRAL, NEVER A BRAND COLOUR. brand-devices.md section 2 is
   explicit: the stroke is ~#D9D3CA and "all colour lives in the dots" sitting
   on the line. A coloured spine reads far louder than the real system — the
   COLOUR belongs to the spurs, which is exactly the rule this section follows.
   🔴 --v3-track-on-indigo, NOT --v3-track-on-oat. The oat token is an INK
   alpha (rgba(47,47,53,0.28)) and measures 1.19 on indigo — a black line on a
   dark ground, effectively invisible. The indigo token is an OAT alpha. This
   is the same class of mistake as using --ink-muted for text here. */

/* 🔴 THE SPURS ARE HIDDEN HERE, IN CSS, NOT FROM JS — AND THAT IS A BUG FIX.
   They used to get their dash pattern written by track-gads.js at build time,
   which left a window between first paint and that write where each spur
   painted FULLY DRAWN. On a page where this section is below the fold the
   window is long enough to see, which is exactly what Brees reported on 8/31.

   ⚠️ 400 IS A CEILING, NOT A MEASUREMENT. It only has to exceed the longest
   spur any layout can produce (they measure ~86 at 1600px, and the spur can
   never be longer than the column gap). One long dash, offset past its own
   length, is invisible; offset 0 is fully drawn. Sizing it exactly would mean
   writing a per-element value from JS again, which is the bug.

   ⚠️ SCOPED TO html[data-js="on"]. With JS off nothing adds .is-drawn, so an
   unscoped rule would hide all four spurs permanently. */


/* Each spur carries the same accent as the dot it runs to, so the line
   explains the colour rather than decorating with it. Same pairing the
   reference uses. */

/* -- .gads-seq — THIS PAGE'S LINE-DRIVEN REVEAL CLASS ---------------------

   🔴 DELIBERATELY NOT .v3-seq, .seo-seq OR .wsite-seq. Each is revealed only
   by its own page's track script; any of them here would be opacity:0 FOREVER.

   🔴 AND DELIBERATELY NOT .reveal. That fires from shared-v3.js's observer the
   moment an element enters the viewport — a DIFFERENT CLOCK from the line's.
   With both attached the items appear first and the line arrives at text that
   is already there, which is the opposite of the effect.

   ⚠️ HIDDEN ONLY UNDER html[data-js="on"]. With JS off nothing draws the line,
   so nothing would add .is-in and all four steps would be blank. */


/* The measuring pass sets this on <html> so the script reads final geometry
   without the 14px offset skewing every spur's y. Mirrors html.w-measuring. */

/* --------------------------------------------------------------------------
   6. THE PROOF — sky ground, two white cards, proportional bars.
   -------------------------------------------------------------------------- */

.gads-proof {
  background-color: var(--sky-soft);
  overflow-x: clip;
}

.gads-proof__intro { display: grid; gap: var(--s-3); margin-bottom: var(--s-5); }

@media (min-width: 900px) {
  .gads-proof__intro {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: var(--s-5);
    align-items: start;
  }
}

.gads-proof__head { max-width: 14ch; margin: 0; color: var(--ink); }
.gads-proof__lede { margin: 0; max-width: 46ch; color: var(--ink-muted); }

.gads-proof__cases { display: grid; gap: var(--s-4); }

/* 🔴 THE TWO CARDS SHARE ROWS, SO THEIR LINES ALIGN ACROSS THE GAP
   (Brees, 8/31: "is it possible to have the items here line up?").

   They did not, and the cause is copy, not spacing: "Cobb & Co. Veterinary
   Clinic" is one line while "Southern Arizona Veterinary Specialty & Emergency
   Center" is two, so every row below the name sat ~30px lower in the right
   card. Equalising by hand — a min-height on the name — would fix only the
   name, and the revenue line ("42 new families" vs "39 new clients") can wrap
   differently too, at which point it drifts again on the next copy edit.

   `subgrid` makes the seven rows belong to the PARENT grid, so each row is as
   tall as the taller of the two cards and both cards land on the same lines.
   It survives any future copy change without a magic number.

   ⚠️ row-gap: 0 ON BOTH. The children already space themselves with their own
   margins (--s-1 after the name, --s-4 after the meta, --s-2 after the revenue
   bar); a parent row-gap would be ADDED to those and inflate the card. Zero
   here keeps the existing rhythm exactly and lets subgrid do only the aligning.
   ⚠️ span 4 must match the child count: name, meta, roi, flow. It was 7 until
   the bars were removed on 8/31; add or remove a row and this number moves
   with it, or the cards silently stop sharing tracks. */
@media (min-width: 900px) {
  .gads-proof__cases {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: var(--s-4);
    row-gap: 0;
  }

  .gads-case {
    grid-row: span 4;
    display: grid;
    grid-template-rows: subgrid;
    row-gap: 0;
  }
}

/* 🔴 THE CARD NEEDS THE SHADOW TO HAVE AN EDGE AT ALL. White on --sky-soft
   measures 1.15, UNDER the ~1.35 shape floor — the fill difference alone does
   not define a boundary. --shadow-card is what makes the card readable as a
   card, so it is load-bearing here in a way it is not on an oat or white
   ground. Do not strip it as "no-boxes tidying". */
.gads-case {
  padding: var(--s-4);
  border-radius: var(--r-card);
  background: var(--white);
  box-shadow: var(--shadow-card);
}

@media (min-width: 700px) {
  .gads-case { padding: var(--s-5) var(--s-4); }
}

.gads-case__name {
  margin: 0 0 var(--s-1);
  font-size: var(--fs-h3, 1.5rem);
  line-height: 1.25;
  color: var(--ink);
}

.gads-case__meta {
  margin: 0 0 var(--s-4);
  font-size: var(--fs-small);
  color: var(--ink-muted);
}

/* -- the ratio, now the card's headline ----------------------------------
   ⏹ THE BARS ARE GONE (Brees' mock, 8/31). .gads-bar, .gads-bar--spend and
   .gads-bar--revenue are DELETED, not overridden — they match nothing now.
   The long palette note that lived with them (a validate_palette.js run on
   #9d9eac vs #d2db75, and why two ROLES are not a categorical set) went with
   them; if bars ever return, that reasoning is in git history for 8/31.

   🔴 "return on ad spend" SITS ON ONE LINE (Brees: "should be on a single
   line, not two"). The ratio is display-sized, so the label beside it gets
   whatever width is left — and at 18 characters it wrapped. `nowrap` is what
   actually holds it, but only from 700px up: on a phone the card is narrow
   enough that forcing one line would push the label out of the card instead,
   which is a worse failure than a wrap. Measured below that width it fits on
   one line anyway at the smaller ratio size. */
.gads-case__roi {
  display: flex;
  align-items: baseline;
  gap: var(--s-2);
  margin: 0 0 var(--s-4);
  font-size: var(--fs-small);
  color: var(--ink-muted);
}

.gads-case__ratio {
  /* The card's loudest thing. 🔴 --petal is the LOGO pink and a KNOWN
     contrast failure at 1.70 — Brees' explicit 8/31 decision; the full note
     and the deliberately-red checker row are documented under
     scripts/gads-contrast.js. Do not change this colour without asking him.
     ⚠️ Brees' newer card mock draws this figure in INK and puts the olive on
     the revenue instead. The pink is kept because it is the more recent
     explicit instruction; flagged for him rather than silently reverted. */
  font-size: clamp(2.75rem, 5.4vw, 4.5rem);
  line-height: 1;
  color: var(--petal);
}

.gads-case__roi-label { color: var(--ink-muted); }

@media (min-width: 700px) {
  .gads-case__roi-label { white-space: nowrap; }
}

/* -- spend -> revenue, one row through an arrow --------------------------
   The hairline that used to sit above the ratio now sits above this row,
   which is where the mock puts it. */
.gads-case__flow {
  display: grid;
  grid-template-columns: minmax(0, auto) auto minmax(0, 1fr);
  align-items: center;
  gap: var(--s-3);
  padding-top: var(--s-3);
  border-top: 1px solid rgba(47, 47, 53, 0.20);
}

.gads-case__spend,
.gads-case__revenue { margin: 0; }

.gads-case__flow-label {
  display: block;
  margin-top: 2px;
  font-size: var(--fs-small);
  color: var(--ink-muted);
}

.gads-case__spend strong {
  font-size: clamp(1.25rem, 1.8vw, 1.625rem);
  color: var(--ink);
}

/* The revenue is the payoff, so it takes the emphasis colour and the larger
   size.

   🔴🔴 A SECOND KNOWN WCAG 1.4.3 FAILURE, BY BREES' EXPLICIT DECISION ON 8/31
   ("change the green to D2DB75"). D2DB75 is --lime exactly. Measured on the
   white card, where this type is 24-32px and the floor is therefore 3.0:
       --lime-deep #869025   3.48   passes  (what this was)
       --lime      #d2db75   1.49   FAILS
   He was shown both numbers before the change. This is the same call he made
   for the ROI ratio minutes earlier, where he chose the logo pink over three
   compliant options — the brand colour wins on this page, deliberately.
   ⚠️ scripts/gads-contrast.js ASSERTS THIS AND IT IS RED ON PURPOSE. Two
   accepted failures now stand on this page. Do not clear either by changing a
   colour; ask him.
   🟢 The mitigation that does apply: the figure is never the only carrier of
   its meaning — "new-client revenue, 42 new families" sits directly beneath it
   in muted ink, and the same number is restated in the ratio above. */
.gads-case__revenue strong {
  font-size: clamp(1.5rem, 2.2vw, 2rem);
  color: var(--lime);
}

/* Decorative, aria-hidden in the markup: the meaning is carried by the two
   labels, not by the glyph. ink@0.45 on white measures 2.62, over the ~1.35
   boundary floor. */
.gads-case__arrow {
  font-size: 1.25rem;
  line-height: 1;
  color: rgba(47, 47, 53, 0.45);
}

/* Under 560px the three-column flow has no room: the arrow turns down and the
   two figures stack. */
@media (max-width: 559px) {
  .gads-case__flow { grid-template-columns: minmax(0, 1fr); gap: var(--s-2); }
  .gads-case__arrow { transform: rotate(90deg); justify-self: start; }
}

/* ==========================================================================
   🔁 9/16 (later) — CONCEPT 11B, "LEDGER ROWS + RATIO DISCS", picked by Brees from the Claude Design canvas "Google Ads
   Section Concepts" (still on the blue ground, as she required). Markup is UNCHANGED — gads-check.js still recomputes
   each ratio from the two dollar figures and verify.js's pinned copy is untouched; this is layout and colour only.
   - >=900: heading + lede in a left column (1fr), the two cases stacked as wide white rows on the right (2fr). The
     subgrid row-sharing above is switched off: the cases no longer sit side by side, so there is nothing to align.
   - Each row: name / meta / spend -> revenue on the left; the ratio in a disc on the right (lime, then petal).
   - 🟢 BOTH "ACCEPTED FAILURES" GO AWAY: the ratio is INK on its disc (lime 8.95, petal 8.3 vs the old petal-on-white
     1.70) and the revenue figure is INK on white (13.3 vs lime-on-white 1.49), as the chosen concept draws them.
   ========================================================================== */
.gads-case { position: relative; }
.gads-case__roi {
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  width: clamp(124px, 11vw, 156px);
  aspect-ratio: 1;
  margin: 0;
  border-radius: 50%;
  background-color: var(--lime);
  color: var(--ink);
  text-align: center;
}
.gads-case:nth-child(2) .gads-case__roi { background-color: var(--petal); }
.gads-case__ratio { font-size: clamp(2.25rem, 3.4vw, 3.5rem); color: var(--ink); }
.gads-case .gads-case__roi-label { max-width: 9ch; white-space: normal; font-size: 0.8125rem; line-height: 1.2; color: var(--ink); }
.gads-case__flow {
  grid-template-columns: auto auto minmax(0, 1fr);
  align-items: start;
  gap: var(--s-3);
  padding-top: 0;
  border-top: 0;
}
.gads-case__spend strong,
.gads-case__revenue strong { font-size: clamp(1.375rem, 1.9vw, 1.625rem); color: var(--ink); }
.gads-case__arrow { align-self: start; margin-top: 0.1em; font-size: 1.75rem; line-height: 1; color: var(--indigo); }
.gads-case__meta { margin-bottom: 0; }
.gads-case__name { font-size: clamp(1.1875rem, 1.5vw, 1.3125rem); font-weight: 700; }

/* the row: text left, disc right (every width a disc fits beside the text) */
@media (min-width: 560px) {
  .gads-proof .gads-case {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-rows: auto auto 1fr;
    column-gap: var(--s-4);
    row-gap: 6px;
    align-items: start;
    padding: var(--s-4) var(--s-4) var(--s-4) var(--s-5);
  }
  .gads-proof .gads-case__name { grid-column: 1; grid-row: 1; margin: 0; }
  .gads-proof .gads-case__meta { grid-column: 1; grid-row: 2; }
  .gads-proof .gads-case__flow { grid-column: 1; grid-row: 3; margin-top: var(--s-3); }
  .gads-proof .gads-case__roi  { grid-column: 2; grid-row: 1 / span 3; align-self: center; }
}
@media (max-width: 559px) {
  .gads-case__roi { margin: var(--s-3) 0; }
  /* the figures stay side by side here (the old stacked flow is out-specified above), so the arrow points right */
  .gads-case__arrow { transform: none; }
}

@media (min-width: 900px) {
  .gads-proof > .container {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
    column-gap: var(--s-5);
    align-items: center;
  }
  .gads-proof__intro { grid-template-columns: minmax(0, 1fr); gap: var(--s-3); margin: 0; }
  .gads-proof__head { max-width: 10ch; }
  .gads-proof__cases { grid-template-columns: minmax(0, 1fr); row-gap: var(--s-4); }
  .gads-proof .gads-case { grid-row: auto; grid-template-rows: auto auto 1fr; }
}


/* --------------------------------------------------------------------------
   7. MEET DEREK

   ⚠️ ONE COLUMN, AND THAT IS NOT THE FINISHED DESIGN. Alie's copy ends this
   section with a Photo placeholder that was never supplied and that a Drive
   sweep on 8/31 could not find. The bio sits at a readable measure on its own
   until a headshot arrives; when it does, this becomes two columns and
   .gads-derek__portrait is where the image goes.
   🔴 Do NOT write this up as an intentionally photo-free section. It is a gap.
   -------------------------------------------------------------------------- */

.gads-derek__grid { display: grid; gap: var(--s-5); }

@media (min-width: 900px) {
  .gads-derek__grid {
    grid-template-columns: minmax(0, 0.72fr) minmax(0, 1fr);
    gap: var(--s-6);
    align-items: center;
  }
}

/* THE PORTRAIT FRAME IS THE .arch SILHOUETTE, borrowed rather than reused.
   📌 brand-devices.md section 1: the arch-figure is the brand's core form and
   "the 24px radius in the layout system is a descendant of this shape". The
   dome is a 999px radius on the top two corners; the bottom two take the house
   render radius. Same silhouette as .arch in direction-d-v3.css.
   ⚠️ NOT the .arch class itself — that carries a white background, card
   padding and a shadow meant for a copy container. This is a picture frame. */
.gads-derek__portrait {
  aspect-ratio: 0.85;
  border-radius: 999px 999px var(--r-render) var(--r-render);
  overflow: hidden;
}

/* Feedbucket 991612 (Brees, 9/21, iPhone 430px): measured 280px wide at x=21.5 in a
   430px viewport - 21.5px of gutter on the left against 128.5px on the right, so the
   arch sat hard left instead of centred. The desktop grid centres it by column; below
   900px there is one column and nothing was doing that job. */
@media (max-width: 899px) {
  .gads-derek__portrait { margin-inline: auto; }
}

/* 🔴 THE EMPTY STATE, AND IT IS A PLACEHOLDER FOR A MISSING ASSET — NOT A
   DESIGN. A flat sky-soft fill in the arch silhouette, so the layout Brees
   approved can be seen while the photo is outstanding. Delete this rule the
   moment the real portrait lands; leaving it would let an empty frame ship
   looking deliberate, which is exactly the failure the media rule names. */
/* 9/16: the photo landed — empty-state fill removed. */
.gads-derek__img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: 50% 40%; }

/* ⏹ NO .gads-derek__img RULE HERE YET, ON PURPOSE. It was written and then
   removed: with no photo in the repo it matched nothing, and the dead-CSS
   sweep reported it on every run — a checker that always flags a known item is
   one people stop reading. The three lines it needs are in the markup note
   beside the frame, which is where someone adding the photo will actually be
   looking. */

.gads-derek__head { max-width: 22ch; margin: 0 0 var(--s-3); }
.gads-derek__bio { margin: 0; max-width: 62ch; color: var(--ink-muted); }

/* --------------------------------------------------------------------------
   8. TESTIMONIAL
   -------------------------------------------------------------------------- */

/* 🔴 INDIGO GROUND, AND THE LIME FINALLY EARNS ITS PLACE (Brees' mock, 8/31).
   This section has now been oat -> white -> indigo in one day. The ground is
   why the second sentence can be --lime at all:
       --lime on white    1.49   invisible; the ROI figure ships it as a
                                 KNOWN failure by Brees' decision
       --lime on indigo   5.44   clears the 4.5 BODY floor outright
   ⏹ The two ink rules from the white version are DELETED. They existed to
   separate a white section from its white neighbours; against indigo the
   colour step does that work and a rule would be noise.
   ⚠️ `.section--indigo` also brings `border-radius: var(--r-bleed)` and sets
   `color: var(--oat)`. --r-bleed is 0, so no corner appears; the oat is
   overridden per element below because the mock's quote is white, not oat. */
/* ⏹ NO INNER padding-block. It was added for the WHITE version of this
   section, whose design was a rule above and a rule below — the padding held
   the copy off those rules. The rules went when the ground became indigo, and
   the padding was left behind, giving this section 152px of effective spacing
   against the page's 88px baseline. `.section` already supplies the rhythm. */

/* Quote left; logo card and attribution stacked in the right column and
   optically centred against the quote.
   🔴 THE 1fr ROWS TOP AND BOTTOM ARE WHAT CENTRES THEM. The right column has
   two items that must stay adjacent (card above caption) while the whole pair
   sits mid-height against a much taller quote. Two flexible rows absorb the
   slack; `align-items: center` cannot do this, because it would centre each
   item INSIDE its own track and pull them apart.
   ⚠️ The blockquote spans 1 / -1 so it is measured against the full height.
   ⚠️ figcaption is still figure's LAST child — required for valid HTML — and
   is placed into the right column by grid, not by source order. */
.gads-quote__figure {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-rows: 1fr auto auto 1fr;
  column-gap: var(--s-6);
  row-gap: var(--s-3);
  margin: 0;
}

.gads-quote__block { grid-column: 1; grid-row: 1 / -1; margin: 0; }
.gads-quote__card  { grid-column: 2; grid-row: 2; }
.gads-quote__by    { grid-column: 2; grid-row: 3; }

.gads-quote__text {
  margin: 0;
  font-size: clamp(1.375rem, 2.9vw, 2.25rem);
  line-height: 1.32;
  /* White, not the section's inherited --oat: the mock's quote is brighter
     than the attribution under it, and that difference is the hierarchy.
     8.09 on indigo. */
  color: var(--white);
}

/* The turn — Alie's last sentence. 5.44 on indigo.
   ⚠️ Colour is not the only signal: it is a complete sentence and reads on its
   own if the colour never arrives. */
.gads-quote__turn { color: var(--lime); }

/* The logo card. White is a REQUIREMENT here, not a style: the client mark is
   dark ink plus a thin orange line, and on indigo it would disappear. */
.gads-quote__card {
  justify-self: end;
  /* 9/16: WHITE logo now sits straight on the indigo (as on the homepage) - no white card, no side padding. */
  padding: var(--s-3) 0;
  background: none;
}

.gads-quote__logo {
  display: block;
  width: auto;
  /* Sized by height; the mark is 5.06:1, so 42px tall is ~212px wide.
     🔁 25% SMALLER — Brees 9/16: "make the logo on the quote section about 25% smaller". Was clamp(40px, 3.6vw, 56px). */
  height: clamp(30px, 2.7vw, 42px);
}

.gads-quote__by {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: var(--fs-small);
}

.gads-quote__name { color: var(--white); }

/* Quieter than the name. --oat-75 measures 4.77 on indigo — a tonal step that
   still clears the body floor. ⚠️ Do not dim it further; oat at 0.6 is 3.6. */
.gads-quote__practice { color: var(--oat-75); }

/* Under 900px the right column has nowhere to go: card and caption drop below
   the quote and align left. `grid-row: auto` returns them to source order. */
@media (max-width: 899px) {
  .gads-quote__figure { grid-template-columns: minmax(0, 1fr); grid-template-rows: none; }
  .gads-quote__block,
  .gads-quote__card,
  .gads-quote__by { grid-column: 1; grid-row: auto; }
  .gads-quote__card { justify-self: start; }
}

/* -- THE TESTIMONIAL SLIDES OVER MEET DEREK ------------------------------
   Brees, 8/31: "I want the testimonial section to parallax over the previous
   section."

   🔴 THIS IS AN OVERLAP, NOT PARALLAX, AND THE DISTINCTION IS NOT PEDANTRY.
   Parallax means layers moving at DIFFERENT RATES, which is the technique the
   brief bans and verify.js enforces (`no parallax`, a word-scan over
   assets/js/*.js). What is built here is a pinned outgoing section with the
   incoming one scrolling over it at the SAME rate: no rate difference, no
   JavaScript, and the gate is not touched. It is not cleared on a technicality
   — the banned technique is genuinely absent. If true differential-rate
   parallax is ever wanted, that is a brief-level decision like the count-up
   was, and it needs Brees' reason written into the gate, not a workaround.

   🔴 HEIGHT-GATED, BECAUSE A PINNED SECTION TALLER THAN THE VIEWPORT LOSES ITS
   OWN BOTTOM. Derek pins under the header, so he needs `his height + header`
   of room. Measured:
       width   derek   +header   so the viewport must be at least
       1600     676      162            838px
       1440     673      162            835px
       1280     654      162            816px
       1024     529      200            729px
        900     460      200            660px
        700    1157      200           1357px   <- columns stack; impossible
        375     982      214           1196px   <- impossible
   Hence min-width 900 AND min-height 850. Below either, the sections scroll
   normally — a graceful absence, not a broken layout.
   ⚠️ THIS MEANS THE EFFECT IS OFF ON A 1536x700 LAPTOP, which this project's
   own notes call the ordinary Windows-scaled screen. That is a real
   limitation, not an oversight: at 700px tall Derek cannot pin without
   clipping his last lines. Shortening that section is the only way to buy it.

   ⚠️ REDUCED MOTION TURNS IT OFF. A section sliding over another is
   scroll-coupled motion; 2.3.3 covers it even though nothing animates on a
   timer.
   ⚠️ Sticky dies inside any scroll container. No ancestor of .gads-derek
   clips today (checked: section/main/body/html are all `visible`) — if one
   ever gains `overflow: hidden`, this silently stops working. */
@media (min-width: 900px) and (prefers-reduced-motion: no-preference) {
  .gads-derek { position: sticky; z-index: 0; }

  /* The incoming section must be opaque and above, or the pinned section
     shows through it. --indigo is a solid fill, so this is just the order. */
  .gads-quote {
    position: relative;
    z-index: 1;
    /* 🔴 THE ROUNDED TOP IS SCOPED TO THE OVERLAP, AND THE REASON IS WHAT THE
       CORNERS REVEAL. A rounded corner cuts into this section's own box and
       shows whatever is painted beneath those pixels. While Derek is PINNED
       behind, that is his white ground and the corner reads as this panel
       sliding over him — the point of the shape.
       With no overlap (narrow screens, reduced motion) Derek's box stops at
       this section's top edge, so the same corner would expose <body>, which
       is --oat #f3eee8 — cream in the corner of an indigo panel, against a
       white section above. The .gads-diffsec arc and the section-two corner
       both hit this exact trap earlier today.
       So the radius lives with the slide: no slide, no corner, square edge.
       ⚠️ `.section--indigo` sets `border-radius: var(--r-bleed)` (0). These are
       LONGHANDS in a later sheet, so they win — but a shorthand added to this
       rule later would silently re-square the bottom. */
    /* 🔴 ONE CORNER, NOT TWO — Brees, 9/2, closing the item he opened on 8/31.
       This was the only section on the whole site with both top corners
       rounded, which made its top edge paint `viewport - 2R` and read as
       "centered" as it rose rather than as a panel sliding in from an edge.
       The other nineteen corners across the three sibling pages all take one.
       Top-LEFT keeps the edge this section already had and matches .gads-derek
       directly beneath it — the pair is one sticky moment, so a shared side
       reads as deliberate, where a top-right would have put two right corners
       back to back at the quote-to-FAQ step below. */
    border-top-left-radius: clamp(24px, 3.2vw, 56px);
  }
}

/* 🔴 ON A SHORT VIEWPORT, DEREK IS MADE TO FIT — THE PIN IS NOT MOVED.

   ⏹ TWO WRONG ANSWERS CAME FIRST, BOTH MEASURED:
   1. Gate the effect on `min-height: 850px`. Brees: "it's not working for me."
      That floor switched it off on every ordinary laptop — 1536x700, 1440x780,
      1366x768 and 1280x720 all failed it; only 1920x1080 and 1600x900 passed.
   2. Pin to the BOTTOM instead when he does not fit. This produces NO OVERLAP
      AT ALL — measured 0px at every short size. Sticky-bottom holds an element
      back from scrolling up, so the testimonial never rises over it; it just
      trails below. The overlap only exists with a TOP pin.

   And a top pin on a section taller than the viewport is not survivable
   either: sticky here is bounded by <main>, so Derek would lock and never
   release, stranding the last ~140px of his bio where no scroll can reach it.

   So the section is made to fit instead. The portrait is what makes it tall —
   a 0.85 aspect ratio on a ~425px column is 500px of the 676px total — so on
   short viewports the frame is sized from the viewport and the padding tightens
   with it. The arch keeps its proportions because the WIDTH is what changes;
   setting height with `aspect-ratio: auto` would squash the brand shape.
   ⚠️ svh, not vh: on mobile browsers vh is the LARGEST viewport, which is the
   wrong end of the range for a fit calculation. */
@media (min-width: 900px) and (prefers-reduced-motion: no-preference) {
  /* 🔴 --hdr-h-min, NOT --hdr-h, AND THE SHEET SAYS SO IN SO MANY WORDS.
     direction-d-v3.css: "Every pinned element on the page keys off
     [--hdr-h-min], not off this. Only --hdr-h, which drives
     scroll-padding-top." I used --hdr-h and Brees reported "cream color
     showing up on scroll".
     Measured: the header paints 162px at the top of the page and shrinks to
     114px once scrolled. Pinning at 162 left a 48px band between the shrunken
     header's bottom edge and Derek's pinned top, and what shows through that
     band is <body> — --oat #f3eee8. Exactly 162 - 114. */
  .gads-derek { top: var(--hdr-h-min); }

  /* 🔴 DEREK IS CENTRED IN THE ROOM HE PINS INTO, NOT LEFT SITTING AT THE TOP
     OF IT. Brees, 9/2: "this needs to be centered before the purple starts
     coming up." Measured while pinned at 1600x1000, two separate things were
     pushing him up:

         visible room (100svh - --hdr-h-min)   886px
         section height                        756px   <- 130px short
         padding                          168 / 88px   <- 80px heavier on top

     The section was shorter than the space it pins into, so the testimonial
     began arriving while there was still slack beneath him. And the padding is
     asymmetric because the corner payback lands only on the top edge — correct
     for a section in normal flow, wrong for one being centred.

     Filling the room fixes the first and equalising the padding fixes the
     second. Both are scoped to the pinned case; in normal flow (under 900px,
     or reduced motion) the section keeps its ordinary height and its one-sided
     payback, which is what the corner needs there.

     ⚠️ VIEWPORT-RELATIVE, NEVER A LITERAL. A `min-height: 850px` gate on this
     page once switched the parallax off for every ordinary laptop — 1536x700,
     1440x780, 1366x768, 1280x720 — and Brees reported "it's not working for
     me". `100svh` cannot do that. At 1536x700 this asks for 586px against a
     575px section: it grows by 11px and the portrait rule still fits.

     📌 `display: grid` rather than flex: the only child is `.container`, whose
     own max-width and auto inline margins do the horizontal centring. A grid
     item stretches to the column and leaves that intact. */
  .gads-derek {
    min-height: calc(100svh - var(--hdr-h-min));
    display: grid;
    align-content: center;
    /* ⚠️ SYMMETRIC, WHICH NOW MEANS PLAIN --section-pad ON BOTH EDGES. This
       was `--section-pad + corner` to match a top payback that no longer
       exists; left alone it would have centred the block against a padding
       that is 80px heavier on one side. Nothing downstream needs it — the
       testimonial is not pulled up over Derek, so he owes no pad-out. */
    padding-bottom: var(--section-pad);
  }
}

@media (min-width: 900px) and (max-height: 849px) and (prefers-reduced-motion: no-preference) {
  /* ⏹ THIS NO LONGER TOUCHES THE SECTION'S PADDING, AND IT NEVER NEEDED TO.
     The first version dropped padding-block to --s-4 to buy room for the pin,
     which cost 96px a side against the --section-pad baseline — Brees noticed
     the page had "lost a lot of padding". Re-measured, the padding was never
     the expensive part: the portrait is. Reserving the FULL section padding in
     the formula below still fits at 1536x700 (portrait 322px, section 498px
     against 538px of room), so the rhythm is kept and only the frame shrinks. */
  .gads-derek__portrait {
    /* height = width / 0.85. The subtraction reserves both section paddings
       plus 40px of slack for the bio column, so the section lands inside
       `viewport - header` without borrowing from the page's spacing scale. */
    width: calc((100svh - var(--hdr-h) - (2 * var(--section-pad)) - 40px) * 0.85);
    max-width: 100%;
  }
}

/* -- SECTION CORNERS (Brees' marked-up full-page shot, 8/31) --------------
   Three sections get one large rounded corner each, on the edge he marked:
       .gads-how     top-LEFT    indigo, over --sky-soft
       .gads-proof   top-RIGHT   sky-soft, over indigo
       .gads-cta     top-LEFT    sky, over white
   (The testimonial's two top corners are handled with the slide, above.)

   🔴 THE OVERLAP IS WHAT MAKES THE CORNER WORK, AND WITHOUT IT EVERY ONE OF
   THESE WOULD SHOW CREAM. A rounded corner cuts into the section's own box and
   reveals whatever is painted beneath. Sections stack edge to edge, so beneath
   is <body> — --oat #f3eee8. Three separate corners today (.gads-diffsec's
   arc, section two's, the testimonial's) have each hit this.
   The fix: pull the section UP by exactly its radius so it overlaps its
   predecessor, and add the same amount back as padding so the CONTENT does not
   move. The corner then reveals the previous section's ground, which is why
   each one lands on a real colour rather than the page's cream.

   🔴 THE RADIUS IS CAPPED BY THE PREVIOUS SECTION'S BOTTOM PADDING. The pull-up
   is full-width, so anything deeper than that padding would start covering the
   previous section's last line of copy. Measured --section-pad:
       1600px   88px        1024px   61px        900px   ~54px
   `clamp(32px, 5vw, 80px)` stays under all of them (80 / 51 / 45).
   ⚠️ TO GO BIGGER, the previous section needs matching extra bottom padding —
   it is not a matter of just raising this number. */
/* The corner size is declared once for the page. This sheet is loaded by a
   single page, so :root here is page-local in practice. */
/* 🔁 3x, THE SMART INTAKE SCALE — Brees 9/15: "all pages should have the same border radius". This page has
   no section 1 -> 2 corner (its first rounded section is .gads-how), so every corner here is the 3x value. The
   "capped by the previous section's bottom padding" note above no longer binds: every pad-out below adds
   var(--gads-corner), so it grows with the radius. */
:root { --gads-corner: clamp(96px, 15vw, 240px); }

.gads-how,
.gads-proof,
.gads-derek,
.gads-faq,
.gads-cta {
  margin-top: calc(-1 * var(--gads-corner));
  /* 🔴 NO TOP PAYBACK — 9/2. Adding R back on top kept content from moving,
     but the top payback is fully VISIBLE while the bottom pad-out is eaten by
     the next section's pull-up, so every rounded section ended up with more
     space above its content than below. Measured at 1440 across all four
     pages: ~178px on top against 66-112px underneath. Brees: "a lot of the
     sections have more padding on top vs on the bottom." Sections keep their
     own --section-pad on top; only the pad-out below survives. */
}

/* 🔴 THE SECTION ABOVE EACH CORNER NEEDS ITS PADDING BACK.
   Brees: "too much white and not enough blue." The pull-up eats the previous
   section's bottom padding, and measured, it ate ALL of it: the sky-soft gap
   between the white "Our standard" panel and the indigo below was -12px — the
   panel had run past where the indigo starts, so no blue showed at all.
   Growing the previous section's bottom padding by the same amount restores
   the visible gap to the --section-pad baseline while the overlap still does
   its job. Pull-up and pad-out are one setting; change one, change both. */
.gads-diffsec,
.gads-how,
.gads-proof,
.gads-faq {
  padding-bottom: calc(var(--section-pad) + var(--gads-corner));
  /* 80vh visible (Brees, 9/15) — see direction-d-v3.css. This page's corner is
     --gads-corner, not --corner. */
  min-height: calc(80vh + var(--gads-corner));
}

.gads-how   { border-top-left-radius: var(--gads-corner); }
.gads-proof { border-top-right-radius: var(--gads-corner); }
.gads-derek { border-top-left-radius: var(--gads-corner); }
.gads-faq   { border-top-right-radius: var(--gads-corner); }
.gads-cta   { border-top-left-radius: var(--gads-corner); }

/* 🔴 THE FAQ CORNER, ADDED 9/2. It was the only ground change left square on
   this page — indigo testimonial into a white FAQ — while `.faq` is rounded on
   all three sibling pages. Top-RIGHT so it does not stack a second left corner
   against .gads-cta immediately beneath it.

   🔴 AND IT NEEDS TO OUTRANK THE TESTIMONIAL, WHICH THE OTHER FOUR DO NOT.
   `.gads-quote` takes `z-index: 1` inside the slide media query so it can pass
   over the pinned Derek. That also put it above the FAQ pulled up over IT, so
   the strip would paint indigo across the top of a white section — the exact
   fault measured on the Websites steps seam the same day, where `.container`'s
   z-index 2 outranked a section at `auto`.
   ⚠️ 2, and ONLY on this section. The note above about .gads-how and
   .gads-proof still stands: they resolve by DOM order and a z-index there
   would break them. This one is the single case with a raised predecessor. */
/* 🔴 AND RAISING THE FAQ PUSHES THE PROBLEM DOWN ONE SECTION, SO THE CTA GOES
   WITH IT. Measured immediately after the first version of this rule: the CTA's
   overlap strip painted white — the FAQ's ground — instead of its own --sky,
   at every width. Raising one section above its predecessor makes it the
   raised predecessor of the next.

   The ladder has to stay consistent with the slide, which is why this is not
   the flat "every rounded section gets one value" rule the sibling pages use:
       .gads-derek  0   pinned, must sit UNDER the testimonial
       .gads-quote  1   slides over Derek
       .gads-faq    2   pulled up over the testimonial
       .gads-cta    3   pulled up over the FAQ
   .gads-how and .gads-proof stay out of it deliberately — neither has a raised
   predecessor, they resolve by DOM order, and the note above says a z-index
   there would break them. */
.gads-faq { position: relative; z-index: 2; }
.gads-cta { position: relative; z-index: 3; }

/* ⚠️ THE TESTIMONIAL'S PAD-OUT IS NOT WRITTEN HERE. It already carries a
   measured painted-deficit padding further down this sheet, and a second
   declaration at this point would simply lose to it on source order. The
   corner is added to that one instead — see the painted-spacing block. */

/* 🔴 THE PAGE GROUND GOES WHITE, AND IT IS THE CORNERS THAT NEED IT.
   <body> is --oat, and every rounded corner reveals whatever is beneath it.
   The overlap backs each corner with the previous SECTION, which handles the
   normal case — but .gads-derek is also position:sticky, and once it pins, the
   section above has scrolled away and there is nothing behind its corner but
   the page ground. Cream, in the corner of a white section.
   White makes that reveal invisible instead of wrong. Nothing else on this
   page shows the body ground: every section paints its own. */
body { background-color: var(--white); }

/* ⚠️ .gads-how and .gads-proof sit either side of a colour step and both are
   position:relative already via `.section`. The LATER sibling paints on top,
   which is the direction that works here: proof's corner reveals the indigo
   above it. No z-index is needed and adding one would break that. */

/* -- PAINTED SPACING COMPENSATION ----------------------------------------
   🔴 DECLARED PADDING IS NOT PAINTED SPACING, AND CHECKING THE FIRST IS NOT
   CHECKING THE SECOND. An audit of every section's padding-* properties came
   back clean while three sections still LOOKED tight, and Brees had to point
   at one of them. The properties were right; the pixels were not.

   Measured — distance from the last real content to the section's visible
   bottom edge, against the --section-pad baseline (88px at 1600):
       .gads-manifesto   76px   -12
       .gads-how         74px   -14   <- the one he flagged
       .gads-quote       68px   -20
   The deficits are content overflowing its own container by a fixed amount
   (the last .gstep__text sits 14px below the container's bottom edge), not a
   padding error — which is exactly why a property audit could not see them.
   These bumps close the gap that is actually painted.

   ⚠️ THE NUMBERS ARE MEASURED, NOT CHOSEN, and gads-check.js now asserts the
   painted gap so they cannot silently drift. If the internal overflow is ever
   fixed at its source, these become over-padding and the checker will not
   catch that — re-measure before assuming they are still needed. */
.gads-manifesto { padding-bottom: calc(var(--section-pad) + 12px); }
/* ⚠️ THE CORNER TERM IS PART OF THIS DECLARATION, NOT A SEPARATE RULE.
   .gads-quote is now the section the FAQ's corner is pulled up over, so it owes
   a pad-out — but it also carries the measured 20px painted deficit below, and
   two competing declarations would just resolve by source order. One value:
   the baseline, the measured deficit, and the corner. */
.gads-quote     { padding-bottom: calc(var(--section-pad) + 20px + var(--gads-corner)); }

/* [!] TALLER, AND REBALANCED - BREES, 9/9. He read this as "50% or 30%" of the
   viewport and asked for 60-70. Measured, it was already 550px = 61vh at
   1440x900, i.e. inside the target. So height was only half the story: padding
   ran 86.4px above against 178.4px below, and the quote sat high over a big
   empty foot, which reads short at any height.

   [i] BOTH ARE FIXED, SEPARATELY, AND NEITHER FIGURE IS GUESSED. min-height
   does the height; the padding does the balance.
   [!] The bottom's 178.4 is NOT the visual foot - it includes --gads-corner,
   the strip the next section pulls up over. What a reader SEES below the quote
   is `--section-pad + 20px` = 106.4px, so that is what the top is matched to.
   Matching the raw 178.4 would look visibly top-heavy while measuring
   "symmetric". */
@media (min-width: 900px) {
  .gads-quote {
    min-height: 70vh;
    align-content: center;
    padding-top: calc(var(--section-pad) + 20px);
  }
}

/* [?] THE BACKGROUND - BREES ASKED FOR IDEAS, 9/9: "is there anything else we
   can add to the background of this section? I don't know if there is a quote
   mark watermark or something."

   [x] THE QUOTE-MARK WATERMARK WAS BUILT THREE TIMES AND ABANDONED. Recorded
   so nobody proposes it again as a fresh idea:
     1. Opening mark, top left, negative offset - sat ~98px outside the
        section's own box, cut in half by the top edge.
     2. Set in --font-display. All Round Gothic's quote glyph is two rounded
        slabs; at 20rem it stops reading as punctuation entirely.
     3. Closing mark, bottom right, in Georgia, fully inside the box - the
        placement and clipping were finally correct and it STILL did not read
        as a quotation mark at that scale. It looks like an abstract rectangle
        with a curve beside it.
   [i] The honest conclusion: a 20rem quote glyph is a shape, not punctuation.
   No amount of positioning fixes that.

   [OK] SO THE HOUSE DEVICE IS USED INSTEAD - the same bleed circle the indigo
   section on the Websites page carries (.wproof .shape--petal-lg). It is
   already this site's language for "quiet shape behind a dark panel", it fills
   the empty bottom-right the min-height opened up, and it needs no new idea.

   [!] FLAT FILL AT FLAT OPACITY, like every other shape here: verify.js fails
   a gradient AND fails a blur, which is what killed the Spotlight cone on 9/8.
   [!] A PSEUDO-ELEMENT, so it is not in the accessibility tree at all.
   [x] To remove the background entirely, delete this rule and the z-index
   partner below it. Nothing else depends on either. */
.gads-quote { position: relative; overflow-x: clip; }

.gads-quote::before {
  content: "";
  position: absolute;
  right: -8%;
  bottom: -34%;
  z-index: 0;
  width: clamp(320px, 38vw, 620px);
  aspect-ratio: 1;
  border-radius: var(--r-pill);
  background-color: var(--petal);
  /* 0.16 over --indigo lands a few RGB points off the ground - it should
     register as a shape at the edge of vision, never as a second panel.
     .wproof runs the same circle at 0.42 because it sits behind a render
     rather than behind body copy; this one is under an attribution. */
  opacity: 0.16;
  pointer-events: none;
}

/* The figure must out-rank the shape, or the circle paints over the
   attribution it is sitting behind. */
.gads-quote__figure { position: relative; z-index: 1; }

/* .gads-how already carries the corner overlap's extra padding; this adds the
   painted deficit on top of it. */
/* [!] MORE ROOM ABOVE THE TITLE - BREES, 9/9: "the 'How it works' title and
   the text are just too far at the top."

   Measured, the section was exactly 2x bottom-heavy: 86.4px above, 172.4px
   below. The bottom is NOT free - it carries the corner payment for the
   section beneath - so only the top moves, and it moves to match what is
   already below it rather than to a number picked by eye. */
.gads-how { padding-bottom: calc(var(--section-pad) + var(--gads-corner) + 14px); }
/* ⚠️ 9/15: THIS TOP IS PINNED TO THE OLD SINGLE CORNER, NOT var(--gads-corner). It was set on 9/9 to balance the
   title against the section's bottom, using the corner value of the day; it is spacing, not a corner, and at the
   3x value it would drop the "How it works" title ~160px further down. The corners changed; this did not. */
.gads-how { padding-top: calc(var(--section-pad) + clamp(32px, 5vw, 80px)); }

/* --------------------------------------------------------------------------
   9. INLINE LINKS

   🔴 THE SAME FLIP THE OTHER PAGES MAKE, AND FOR THE SAME MEASURED REASON.
   lime is 1.49 on white and 1.29 on oat — invisible. Every ground this page
   puts an inline link on is light, so they are all full --ink (13.30 on white,
   11.53 on oat) and stay underlined, so the link never depends on colour alone.
   ⚠️ If a link is ever added on the indigo or the final-cta ground, it needs
   its own rule — this one would make it ink on indigo, which measures 1.64.
   -------------------------------------------------------------------------- */

.gads-inline-link {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 0.18em;
}

/* --------------------------------------------------------------------------
   10. SECTIONS CARRYING A BLEED SHAPE MUST CLIP

   🔴 THIS WAS MISSING ON THE FIRST BUILD AND THE PAGE SCROLLED SIDEWAYS AT
   EVERY WIDTH — 96px at 1600, 23px at 375. websites.css records the identical
   bug from 8/28 and this build reproduced it by not reading its own note.
   The bleed shapes are large circles positioned to run off the section edge;
   unclipped, they extend the document and give the WHOLE PAGE a horizontal
   scrollbar. (The hero's own shape went with the bespoke hero; the proof
   section's went too, but this clip stays as the guard for anything added.)

   ⚠️ `overflow-x: clip`, NOT `overflow: hidden` — the project's own rule
   (direction-d-v3.css, 8/18). `hidden` establishes a scroll container, which
   silently kills position:sticky on any descendant and cuts a bleeding circle
   flat where a colour step happens. `clip` contains without either.
   ⚠️ .final-cta is NOT listed: it carries two shapes of its own and is already
   clipped by the shared sheet, which is why the sibling pages do not repeat it.
   Caught by scripts/gads-check.js, which asserts zero document overflow.
   -------------------------------------------------------------------------- */

.gads-proof {
  overflow-x: clip;
}

/* ⏹ .gads-hero IS NOT IN THIS LIST ANY MORE — the section is now the shared
   .hero, which already carries `overflow: hidden` in direction-d-v3.css and
   clips its own bleed. Adding it back would be a no-op at best. */

/* RESPONSIVE PASS (9/16) — the hero orb field on phones.
   Six discs sized in vw with desktop floors (skyR never under 300px). On a
   390px screen skyR covered the right 60% of the headline, and the bottom-right
   petal/lime pair crossed half its diameter into the next section — straight
   through "You can't outspend". Same composition, scaled to the screen and
   pulled out to the corners so the type sits on white. */
@media (max-width: 599px) {
  .gads-heroorb--skyR   { width: 230px; right: -34%; transform: translateY(-38%); }
  .gads-heroorb--skyL   { width: 190px; left: -30%; transform: translateY(30%); }
  .gads-heroorb--limeTL { width: 84px; left: -8%; transform: translateY(-46%); }
  .gads-heroorb--petalTL{ width: 68px; left: 6%; transform: translateY(-62%); }
  .gads-heroorb--petalBR{ width: 104px; right: 4%; transform: translateY(26%); }
  .gads-heroorb--limeBR { width: 92px; right: -9%; transform: translateY(8%); }
}

/* RESPONSIVE PASS (9/16). Stacked below 900 the portrait frame took the full
   column width at its arch ratio — ~540px of EMPTY frame on a tablet, ~350px
   on a phone, before a word about Derek. The photo still does not exist (and
   nothing stands in for it — see session notes); the frame just stops
   dominating the section while it waits, and aligns with the copy's edge. */
@media (max-width: 899px) {
  .gads-derek__portrait { width: 100%; max-width: 280px; }
}

/* 9/16 (later) — LOGO UNDER THE NAME. Brees: "on all the quotes - i think the logo would look better under the
   name/title instead of on top." Applies to the four big quotes (homepage, Google Ads, Strategy Session, Launching),
   his scope. Desktop swaps the two grid rows; stacked, `order` does the same (grid-row is auto there). */
.gads-quote__by   { grid-row: 2; }
.gads-quote__card { grid-row: 3; }
@media (max-width: 899px) {
  .gads-quote__by   { grid-row: auto; order: 2; }
  .gads-quote__card { grid-row: auto; order: 3; }
}
