/* ==========================================================================
   Corepath Advisory — Premium layer
   ==========================================================================

   Loaded LAST, after pages.css, so everything here refines what is already
   there rather than replacing it. Nothing in this file is required for the
   site to be readable or navigable — it is depth, motion and surface.

   Sources, and what was taken from each:

   - ui-ux-pro-max (nextlevelbuilder)  — the design system this was checked
     against: pattern "Trust & Authority + Conversion", style "Accessible &
     Ethical", colours "Professional navy + blue CTA". Its ANTI-PATTERN list
     is the reason there is no purple/pink gradient, no playful geometry and
     no emoji anywhere below.
   - motion-primitives (ibelick)      — spotlight, border-trail, progressive
     blur, infinite slider and animated number, ported from React/Framer to
     CSS + one rAF loop. Mechanics kept, dependency not.
   - 21st.dev                         — hero trust strip and the masthead
     footer composition.
   - ui.watermelon.sh                 — landing section rhythm: every screen
     opens on an index/eyebrow and closes on a next-step.
   - haikei.app                       — the mesh-gradient and grain grounds,
     generated here as CSS/SVG so there is no exported PNG to keep in sync.

   None of these ship as a library. A WordPress theme has no build step, so
   each pattern is reimplemented in plain CSS driven by the theme's existing
   token set. No external request is added.

   CONTENTS
     1.  Atmosphere — mesh grounds and grain
     2.  Spotlight surfaces
     3.  Border trail
     4.  Marquee + progressive blur
     5.  Proof band
     6.  Card refinement
     7.  Header refinement
     8.  Footer rebuild
     9.  Section rhythm + page heads
     10. Reduced motion
   ========================================================================== */


/* ==========================================================================
   1. ATMOSPHERE — mesh grounds and grain
   ==========================================================================
   Haikei's mesh-gradient and grain-texture generators produce a raster you
   export and ship. Two problems with that here: the file has to be regenerated
   every time a brand colour moves, and a full-bleed PNG is a real payload on a
   page that already carries photography.

   Both are built from the theme's own tokens instead — the mesh as layered
   radial-gradients, the grain as one inline feTurbulence. They cost no request,
   they follow the palette automatically, and they scale to any viewport.
   ========================================================================== */

:root {
  --cp-grain: none;
}

/* ---- The ground itself -------------------------------------------------
   Clean, performant static gradients without heavy filter blur or keyframe loops. */

.cp-atmos {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
  z-index: -1;
}

.cp-atmos::before,
.cp-atmos::after {
  content: "";
  position: absolute;
  border-radius: 50%;
  pointer-events: none;
}

/* The primary glow: azure, top-left */
.cp-atmos::before {
  width: 60vmax;
  height: 60vmax;
  top: -20vmax;
  left: -15vmax;
  background: radial-gradient(circle at center, rgba(17, 120, 199, 0.22), transparent 70%);
}

/* The counterweight: bottom-right */
.cp-atmos::after {
  width: 50vmax;
  height: 50vmax;
  right: -20vmax;
  bottom: -20vmax;
  background: radial-gradient(circle at center, rgba(101, 184, 237, 0.14), transparent 70%);
}

.cp-atmos__grain {
  display: none;
}

.cp-atmos--light::before {
  background: radial-gradient(circle at center, rgba(17, 120, 199, 0.08), transparent 70%);
}
.cp-atmos--light::after {
  background: radial-gradient(circle at center, rgba(200, 229, 213, 0.18), transparent 70%);
}

.cp-atmos--faint::before { opacity: 0.4; }
.cp-atmos--faint::after  { opacity: 0.3; }

.cp-has-atmos { position: relative; isolation: isolate; }


/* ==========================================================================
   2. SPOTLIGHT SURFACES (Clean CSS hover)
   ========================================================================== */

.cp-spot {
  position: relative;
  isolation: isolate;
  overflow: hidden;
}

.cp-spot > * { position: relative; z-index: 1; }


/* ==========================================================================
   3. BORDER TRAIL
   ==========================================================================
   A direct port of motion-primitives' <BorderTrail>, and the one component that
   comes across almost unchanged — it was already animating a CSS property.

   The React version animates `offsetDistance` 0%→100% along
   `offset-path: rect(0 auto auto 0 round Npx)` and clips the result to the
   border box with mask-composite. Both are plain CSS. Framer is only supplying
   the tween, which @keyframes does for free.

   Applied to ONE element per page — the primary CTA. A travelling light is a
   focal device; on two elements it is decoration, and on a professional
   services site that is the wrong read.
   ========================================================================== */

.cp-trail {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  overflow: hidden;
  z-index: 0;
}

.cp-trail__dot {
  position: absolute;
  /* At the reference 4.5rem the dot is taller than the button it runs around,
     so it reads as a bright smudge parked on one edge rather than as a light
     travelling the rim. Sized under the button's own height instead. */
  width: 2.5rem;
  aspect-ratio: 1;
  border-radius: 50%;
  /* A tight core with a fast falloff. A wide falloff at this size just tints
     the whole corner. */
  background: radial-gradient(circle at center, rgba(154, 209, 245, 0.85), rgba(101, 184, 237, 0.30) 32%, transparent 58%);
  /* `round` matches the pill radius so the light turns the corner instead of
     cutting it. Kept in px because offset-path does not accept a percentage. */
  offset-path: rect(0 auto auto 0 round 999px);
  offset-distance: 0%;
  animation: cp-trail-run 6s linear infinite;
  opacity: 0.62;
}

@keyframes cp-trail-run {
  from { offset-distance: 0%; }
  to   { offset-distance: 100%; }
}

/* offset-path is unsupported in older Safari and Firefox ESR. Without a guard
   the dot would sit motionless in the top-left corner of the button, which
   looks like a rendering fault. Only draw it where it can actually travel. */
@supports not (offset-path: rect(0 auto auto 0 round 999px)) {
  .cp-trail { display: none; }
}

/* overflow:hidden clips the travelling dot to the pill, so it reads as a light
   on the rim rather than a ball orbiting outside the button.

   .cp-btn__fill is deliberately NOT touched here. It is authored as
   `position: absolute; inset: 0; z-index: -1`, and an earlier version of this
   rule set `position: relative; z-index: 1` on it to lift it over the trail.
   That took it out of flow-position entirely: it collapsed to a zero-width
   inline box, so the hover sweep still ran and still reported
   transform: scaleX(1) while covering nothing. The button stayed navy with a
   navy label on hover — measured at 3.2:1, and invisible to any check reading
   computed styles rather than pixels.

   No lift is needed. The fill at -1 and the trail at 0 are both below the
   label, and the trail fades out on hover anyway, so the two never overlap in a
   state where either is visible. */
.cp-btn--trail { position: relative; overflow: hidden; }

/* The trail must never compete with the hover state — the fill sweeping in is
   the feedback that matters, and two moving things at once reads as noise. */
.cp-btn--trail:hover .cp-trail,
.cp-btn--trail:focus-visible .cp-trail { opacity: 0; transition: opacity var(--cp-dur-xs) var(--cp-ease); }


/* ==========================================================================
   4. MARQUEE + PROGRESSIVE BLUR
   ==========================================================================
   motion-primitives' <InfiniteSlider> measures its children and animates x by
   the measured width. Measuring in JS means a layout read on every resize.

   The CSS equivalent duplicates the track and translates by exactly -50%: the
   copy reaches the original's start position at the moment the animation loops,
   so the seam is mathematically invisible with no measurement at all. The
   duplicate is aria-hidden so the content is announced once.

   The fade at each edge is <ProgressiveBlur> reduced to its useful core. The
   React version stacks eight backdrop-filter layers; that is eight composited
   passes on a strip most visitors never look directly at. Two layers plus a
   mask gets the same read for a quarter of the cost.
   ========================================================================== */

.cp-marquee {
  position: relative;
  overflow: hidden;
  /* Measured: over the proof band's mesh the strip's brightest ground reached
     rgb(50,99,140), which put the item colour at 4.24:1 — under AA. Darkening
     the image far enough to fix it would have flattened the mesh everywhere, so
     the strip carries its own ground instead and the mesh keeps its range.
     Same reasoning as the glass panel behind the Why Corepath columns.

     A later "failure" here at 4.15:1 was NOT this scrim: the checker was
     sampling the item's own azure ::before bullet as if it were the ground.
     Raising the scrim to 0.80 moved the number by 0.05, which is what proved
     it. Left at the measured-correct values. */
  background: linear-gradient(180deg, rgba(8, 18, 42, 0.55), rgba(8, 18, 42, 0.62));
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}

.cp-marquee__track {
  display: flex;
  width: max-content;
  animation: cp-marquee-run var(--cp-marquee-dur, 46s) linear infinite;
}

/* Pause on hover and on keyboard focus. The WCAG requirement is a mechanism to
   stop moving content that starts automatically and runs over five seconds —
   focus-within is what makes that reachable without a pointer. */
.cp-marquee:hover .cp-marquee__track,
.cp-marquee:focus-within .cp-marquee__track { animation-play-state: paused; }

.cp-marquee__group {
  display: flex;
  align-items: center;
  gap: clamp(2.5rem, 1.5rem + 3vw, 5rem);
  padding-right: clamp(2.5rem, 1.5rem + 3vw, 5rem);
  flex: 0 0 auto;
}

@keyframes cp-marquee-run {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}

.cp-marquee__item {
  display: inline-flex;
  align-items: center;
  gap: 0.7em;
  white-space: nowrap;
  font-size: var(--cp-step--1);
  letter-spacing: var(--cp-track-wide);
  text-transform: uppercase;
  /* --cp-on-dark-faint (0.68 alpha) is the tone this strip wants, and it does
     not clear AA over the band. One step up. */
  color: var(--cp-on-dark-soft);
  transition: color var(--cp-dur-sm) var(--cp-ease);
}

.cp-marquee__item:hover { color: var(--cp-on-dark); }

.cp-marquee__item::before {
  content: "";
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--cp-azure-bright);
  opacity: 0.7;
  flex: 0 0 auto;
}

.cp-marquee--light { background: none; }
.cp-marquee--light .cp-marquee__item { color: var(--cp-ink-faint); }
.cp-marquee--light .cp-marquee__item:hover { color: var(--cp-ink); }


/* ==========================================================================
   5. PROOF BAND
   ==========================================================================
   The design system's section order is Hero > Proof > Solution > CTA, and this
   is the Proof step. It sits directly under the hero.

   Every figure here is a Customizer value. Nothing is hard-coded, nothing has a
   default, and a stat with no number is not rendered on the public site — the
   same rule the rest of the theme applies to the ABN and the phone number. An
   advisory firm's credibility claims are exactly the thing that must not be
   invented, so the band renders with as many stats as have been supplied, and
   disappears entirely at zero.
   ========================================================================== */

.cp-proof {
  position: relative;
  isolation: isolate;
  background: var(--cp-navy-deep);
  border-bottom: 1px solid var(--cp-navy-line);
  padding-block: clamp(3rem, 2rem + 3.5vw, 5rem);
}

.cp-proof__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: clamp(1.75rem, 1rem + 2.5vw, 3.5rem);
}

.cp-proof__item {
  position: relative;
  padding-left: clamp(1.25rem, 0.8rem + 1.4vw, 2rem);
  border-left: 1px solid var(--cp-rule-dark);
}

/* The first item's rule would sit on the shell's left edge and read as a page
   border rather than a divider between figures. */
.cp-proof__item:first-child { border-left: 0; padding-left: 0; }

@media (max-width: 40rem) {
  .cp-proof__item { border-left: 0; padding-left: 0; }
}

.cp-proof__figure {
  display: block;
  font-family: var(--cp-font-display);
  font-size: var(--cp-step-4);
  line-height: 1;
  color: var(--cp-on-dark);
  letter-spacing: var(--cp-track-tight);
  /* Tabular figures so a counter ticking 0>9 does not reflow the label under
     it — proportional digits in Newsreader change width mid-count. */
  font-variant-numeric: tabular-nums;
}

.cp-proof__suffix { color: var(--cp-azure-bright); }

.cp-proof__label {
  display: block;
  margin-top: 0.75rem;
  font-size: var(--cp-step--1);
  line-height: 1.5;
  color: var(--cp-on-dark-soft);
  max-width: 16rem;
}

.cp-proof__rule {
  display: block;
  width: 2rem;
  height: 1px;
  margin-top: 1rem;
  background: var(--cp-azure-bright);
  opacity: 0.55;
  transform-origin: left;
}

/* The hidden-until-seen state is gated on `.js`, the same way every reveal in
   layout.css is. Without that gate the rule would be scaled to zero in markup
   and nothing would ever restore it for a visitor with scripts blocked — a
   decorative element, but the theme's rule is that no effect may leave anything
   permanently invisible, and a hairline that never appears is a broken hairline
   rather than an absent one. */
.js .cp-proof__rule {
  transform: scaleX(0);
  transition: transform var(--cp-dur-lg) var(--cp-ease-out) calc(var(--i, 0) * var(--cp-stagger));
}

.js .cp-proof.is-seen .cp-proof__rule { transform: scaleX(1); }

/* The marquee closes the band. It runs the full viewport width rather than
   sitting inside the shell — a strip that stops at the gutter reads as a
   component, and this is meant to read as the band's own bottom edge. */
.cp-proof__marquee {
  margin-top: clamp(2.5rem, 1.8rem + 2.5vw, 4rem);
  padding-top: clamp(1.5rem, 1.1rem + 1.4vw, 2.25rem);
  border-top: 1px solid var(--cp-rule-dark);
}

/* Marquee-only: the band collapses to a strip and the rule goes, because there
   is nothing above it for the rule to separate. Set from PHP (--strip) rather
   than with a positional selector — the atmosphere layer is also a div and
   sits first, so :first-of-type matches that instead. */
.cp-proof--strip { padding-block: 0; }

.cp-proof--strip .cp-proof__marquee {
  margin-top: 0;
  padding-block: clamp(1.1rem, 0.9rem + 0.9vw, 1.6rem);
  border-top: 0;
}


/* ==========================================================================
   6. CARD REFINEMENT
   ==========================================================================
   The existing cards are flat white with a hairline. That is correct, and it is
   also where the site stops feeling expensive — at this price point a surface is
   expected to acknowledge the pointer.

   Applied to the real card classes rather than to a new wrapper class, so every
   card on every page is covered without editing seven templates and without a
   second class to remember on the next one.

   The surfaces, and what each one is:
     .cp-audience__item About / who we work with — icon cards
     .cp-accordion__item FAQ                  — hairline rows
   ========================================================================== */

.cp-audience__item {
  /* Named explicitly rather than `all`, so the reveal module's own transform
     transition is not restarted every time one of these repaints. */
  transition:
    transform var(--cp-dur-md) var(--cp-ease-out),
    box-shadow var(--cp-dur-md) var(--cp-ease-out),
    border-color var(--cp-dur-md) var(--cp-ease-out);
}

.cp-audience__item:hover {
  transform: translate3d(0, -4px, 0);
  box-shadow: var(--cp-shadow);
  border-color: rgba(17, 120, 199, 0.28);
}

/* ---- Spotlight surfaces ------------------------------------------------
   The same list is what premium.js queries (CARD_SELECTOR). If a class is
   added here it must be added there too, or the glow will have no pointer
   position to follow. --------------------------------------------------- */

.cp-audience__item {
  position: relative;
  isolation: isolate;
  overflow: hidden;
}

/* The card's own content. */
.cp-audience__item > * { position: relative; z-index: 1; }

/* ---- Drawn top accent --------------------------------------------------
   A hairline that draws in from the left. scaleX from a left origin, so it
   reads as being drawn rather than fading up.                             */

.cp-audience__item::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 2px;
  z-index: 2;
  background: linear-gradient(90deg, var(--cp-azure-vivid), var(--cp-azure-bright));
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--cp-dur-md) var(--cp-ease-out);
}

.cp-audience__item:hover::before,
.cp-audience__item:focus-within::before { transform: scaleX(1); }

/* ---- FAQ rows ----------------------------------------------------------
   An accordion row is not a card and must not lift — the panel below it would
   move with it. It gets the ground tint only.                             */

.cp-accordion__item { transition: background-color var(--cp-dur-sm) var(--cp-ease); }
.cp-accordion__item:hover { background-color: rgba(17, 120, 199, 0.03); }

/* ==========================================================================
   7. HEADER REFINEMENT
   ==========================================================================
   The white header gains a slightly more defined bottom edge once it is stuck,
   plus the existing reading-progress hairline.
   ========================================================================== */

.cp-header::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(15, 109, 180, 0.18) 12%, rgba(15, 109, 180, 0.18) 88%, transparent);
  opacity: 0;
  transition: opacity var(--cp-dur-sm) var(--cp-ease);
}

.cp-header.is-stuck::after { opacity: 1; }

/* Reading progress. Sits on the header's own bottom edge rather than as a
   separate bar at the top of the viewport, where it would collide with the
   admin bar for logged-in users. */
.cp-progress-rail {
  position: absolute;
  left: 0;
  bottom: 0;
  height: 2px;
  width: 100%;
  transform: scaleX(var(--cp-progress, 0));
  transform-origin: left;
  background: linear-gradient(90deg, var(--cp-azure-vivid), var(--cp-azure-bright));
  opacity: 0;
  transition: opacity var(--cp-dur-sm) var(--cp-ease);
  pointer-events: none;
}

.cp-header.is-stuck .cp-progress-rail { opacity: 1; }


/* ==========================================================================
   8. FOOTER
   ==========================================================================
   Measured before this rewrite: **807px** on a 900px viewport, for a logo, one
   sentence, one button, four short lists and a copyright line. It filled the
   screen and read as a second page rather than the end of one.

   Where the height was going:

     112px  dead padding above the masthead
     147px  a four-line blurb repeating the hero lede
     267px  the masthead as a two-column grid — brand left, action right, and a
            void across the middle at any wide viewport
     112px  padding above and below the columns
      81px  the legal bar

   Fixed by changing the masthead's shape rather than by shrinking type. It was
   a 2-column grid holding three things, so one of them had to sit in a column
   with something else and the row inherited the tallest item's height. It is a
   single horizontal band now — mark, closing line, action — which is the shape
   the content actually has, and it holds that shape without a fixed height.

   The blurb is gone. It repeated the hero lede verbatim, and the closing line
   beside it already says the same thing in six words.
   ========================================================================== */

.cp-footer__inner {
  /* Was --cp-space-xl (up to 112px). The blue CTA band directly above already
     provides the separation this was trying to create. */
  padding-top: clamp(2.5rem, 1.8rem + 2.4vw, 3.75rem);
}

/* ---- Masthead band ----------------------------------------------------- */

.cp-footer__top {
  display: flex;
  align-items: center;
  gap: clamp(1.5rem, 0.8rem + 2.6vw, 3.5rem);
  padding-bottom: clamp(1.75rem, 1.3rem + 1.6vw, 2.75rem);
  border-bottom: 1px solid var(--cp-rule-dark);
}

/* The closing line takes the slack, so the mark sits hard left and the action
   hard right at every width without either being pushed off its edge.

   Centred, not right-aligned. Right-aligned it stacked against the button and
   left a ~380px void between the mark and the type — the same emptiness the old
   two-column masthead had, just moved along the row. Centred, the line sits in
   the middle of the gap it is filling and the band reads as one thing. */
.cp-footer__statement {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  font-family: var(--cp-font-display);
  /* Was --cp-step-2 inside a 20rem box, which wrapped to two lines and set the
     height of the whole row. One step down, and given the room to stay on one
     line at desktop widths. */
  font-size: var(--cp-step-1);
  line-height: var(--cp-lh-snug);
  color: var(--cp-on-dark-soft);
  text-align: center;
  max-width: none;
}

.cp-footer__top .cp-btn { flex: 0 0 auto; }

.cp-footer__brand { flex: 0 0 auto; }

/* Below the breakpoint the three stack and the closing line returns to the left
   edge — right-aligned type in a narrow single column reads as a mistake. */
@media (max-width: 60rem) {
  .cp-footer__top {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--cp-space-md);
  }
  .cp-footer__statement {
    text-align: left;
    font-size: var(--cp-step-2);
    max-width: 22ch;
  }
}

/* ---- Columns ------------------------------------------------------------ */

.cp-footer__grid {
  /* Was --cp-space-xl top and bottom — up to 112px each side of four short
     lists. The masthead's own rule already separates them from it. */
  padding-top: clamp(2rem, 1.5rem + 1.8vw, 3rem);
  padding-bottom: clamp(2rem, 1.5rem + 1.8vw, 3rem);
  gap: clamp(1.75rem, 1.2rem + 2vw, 3rem) var(--cp-space-lg);
}

/* components.css goes single-column below 40rem, which stacks all four lists
   and made the footer 1096px on a 375px screen — roughly two and a half
   phone screens of links. Two-up from 26rem instead: the two long lists pair
   off and the two short ones pair off, so nothing is stranded on its own row. */
/* Upper bound is essential. premium.css loads last, so an unbounded
   `min-width: 26rem` here beats the `min-width: 62rem` four-column rule in
   components.css at every width above it — the first attempt took the desktop
   footer from 536px back up to 689px by forcing two columns everywhere. */
@media (min-width: 22rem) and (max-width: 39.999rem) {
  .cp-footer__grid { grid-template-columns: repeat(2, 1fr); }
}

.cp-footer__title {
  padding-bottom: 0.7rem;
  margin-bottom: 0.9rem;
  border-bottom: 1px solid var(--cp-rule-dark);
}

.cp-footer__list li + li { margin-top: 0.45rem; }

/* Links get a real hover: the arrow slides out from nothing rather than the
   colour simply changing. */
.cp-footer__list a {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0;
  transition: gap var(--cp-dur-sm) var(--cp-ease), color var(--cp-dur-sm) var(--cp-ease);
}

.cp-footer__list a::after {
  content: "\2192";
  width: 0;
  opacity: 0;
  overflow: hidden;
  transition: width var(--cp-dur-sm) var(--cp-ease), opacity var(--cp-dur-sm) var(--cp-ease);
}

.cp-footer__list a:hover::after,
.cp-footer__list a:focus-visible::after { width: 1em; opacity: 1; }
.cp-footer__list a:hover { gap: 0.4em; }

/* ---- Contact column ----------------------------------------------------- */

.cp-footer address { line-height: 1.6; }

.cp-footer__direct { margin-top: 0.75rem; }

.cp-footer__hours {
  margin-top: var(--cp-space-sm);
  font-size: var(--cp-step--1);
  line-height: 1.6;
  color: var(--cp-on-dark-soft);
}

.cp-footer__hours-label {
  display: block;
  font-size: 0.72rem;
  letter-spacing: var(--cp-track-wide);
  text-transform: uppercase;
  color: var(--cp-on-dark-faint);
  margin-bottom: 0.3rem;
}

.cp-footer__social {
  display: flex;
  gap: 0.6rem;
  margin-top: var(--cp-space-sm);
}

.cp-footer__social a {
  display: grid;
  place-items: center;
  width: 44px;              /* the 44x44 minimum target from the UX ruleset */
  height: 44px;
  border: 1px solid var(--cp-rule-dark);
  border-radius: 50%;
  color: var(--cp-on-dark-soft);
  transition: border-color var(--cp-dur-sm) var(--cp-ease), color var(--cp-dur-sm) var(--cp-ease), transform var(--cp-dur-sm) var(--cp-ease-out);
}

.cp-footer__social a:hover {
  border-color: var(--cp-azure-bright);
  color: var(--cp-azure-bright);
  transform: translate3d(0, -2px, 0);
}

/* ---- Legal bar ---------------------------------------------------------- */

.cp-footer__bar { padding-block: var(--cp-space-sm); }

/* ---- Watermark ---------------------------------------------------------- */
/* At 15vw it ran the full width behind the columns, and it sat directly under
   the copyright line — two pieces of type occupying the same space, one of them
   a giant cropped word. That is most of what made the old footer read as noisy.

   Held down so only the shoulders of the letterforms clear the legal bar's
   rule, and taken to the point where it registers as a tone in the ground
   rather than as a word you start reading. */
.cp-footer__watermark {
  font-size: clamp(3rem, 7.5vw, 7.5rem);
  color: rgba(255, 255, 255, 0.022);
  bottom: -0.34em;
}

/* The legal bar sits over it, so it needs its own layer or the copyright line
   competes with a letterform behind it. */
.cp-footer__bar { position: relative; z-index: 1; }

/* A word bleeding off the edge needs width to read as a deliberate crop. On a
   phone only two or three letterforms fit, so it reads as a stray fragment
   under the legal links rather than as a mark. */
@media (max-width: 48rem) {
  .cp-footer__watermark { display: none; }
}

/* ==========================================================================
   9. SECTION RHYTHM + PAGE HEADS
   ==========================================================================
   watermelon's landing sections all open the same way — a small index, then the
   heading, then the lede — so a visitor scrolling fast always knows where they
   are in the argument. The theme already has an eyebrow; it just never carried
   the position.
   ========================================================================== */

.cp-eyebrow--indexed {
  display: inline-flex;
  align-items: baseline;
  gap: 0.9em;
}

.cp-eyebrow__index {
  font-variant-numeric: tabular-nums;
  opacity: 0.55;
  font-size: 0.9em;
}

/* Page heads gain the atmosphere layer. Without it the four inner pages open on
   a flat navy band that the homepage no longer has, and they read as belonging
   to an older version of the site. */
.cp-page-head { position: relative; isolation: isolate; }


/* ==========================================================================
   10. REDUCED MOTION
   ==========================================================================
   tokens.css already collapses every duration to 1ms, which handles every
   transition in this file. Keyframe animations do not read those tokens, so
   each one is stopped explicitly here.

   Note these are stopped, not hidden: the mesh still renders, the marquee still
   shows its content, the trail is simply removed. Nothing that carries meaning
   disappears when motion is turned off.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  .cp-atmos::before,
  .cp-atmos::after { animation: none; }

  .cp-marquee__track { animation: none; transform: none; }
  /* Without the animation the duplicated group is dead width. The mask fade
     would then cut the last real item, so the track wraps instead of running. */
  .cp-marquee { -webkit-mask-image: none; mask-image: none; }
  .cp-marquee__track { flex-wrap: wrap; width: 100%; }
  .cp-marquee__group[aria-hidden="true"] { display: none; }

  /* `display: none` on the wrapper does stop the dot rendering, but the child's
     own animation-name stays in its computed style, so anything auditing for
     residual motion still reports it — and it leaves the browser holding an
     animation on a subtree for no reason. Cancelled on the dot as well. */
  .cp-trail { display: none; }
  .cp-trail__dot { animation: none; offset-distance: 0%; }

  .js .cp-proof__rule { transform: scaleX(1); }

  /* The lift on hover. These are the real card classes — an earlier version of
     this block still named .cp-card / .cp-help__card / .cp-icon-card, which
     were placeholders replaced during the §6 rewrite and match nothing, so the
     lift was never actually being cancelled. */
  .cp-audience__item:hover,
  .cp-footer__social a:hover { transform: none; }

  /* The spotlight follows a pointer, which is motion the visitor is driving —
     but premium.js already returns early under reduced motion, so no position
     is ever written and the glow would sit at its 50%/0% fallback. Removed
     outright rather than left as a static highlight nothing explains. */
  .cp-audience__item::after { display: none; }
}
