/* ==========================================================================
   Page components: hero, tabs, carousel, accordion, scroll reveals.
   ========================================================================== */

/* ---- Scroll reveal ------------------------------------------------------- */

/* Progressive enhancement: content is visible by default and only starts
   hidden once JS has confirmed it can reveal it, by putting .js-reveal on
   <html>. Before this, a JS error or a slow script left whole pages blank,
   which is exactly how the generated pages first looked. */
.js-reveal [data-reveal] {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 0.65s var(--ease), transform 0.65s var(--ease);
}
.js-reveal [data-reveal].is-visible { opacity: 1; transform: none; }

/* ---- Hero ---------------------------------------------------------------- */

/* The design's hero rhythm: a little more above than below, both scaling with
   the --sp density multiplier like every other band. */
.hero { padding: calc(var(--section-pad) * 1.08) 0 calc(var(--section-pad) * 0.89); }

.hero__inner {
  display: grid;
  grid-template-columns: 1fr 1.22fr;
  gap: clamp(32px, 4vw, 60px);
  align-items: center;
}

.hero__media { border-radius: var(--radius-card); overflow: hidden; }
.hero__media img { width: 100%; }

.hero h1 {
  margin-bottom: 18px;
  /* One clamp rather than Showit's two stylesheets either side of 768px. The
     ceiling is the V2 design's 4rem, down from the live site's 78px. */
  font-size: var(--fs-title);
}
/* Mobile: step the hero headline down alongside the base h1/h2 rule (base.css).
   The heading container is viewport-bound at phone widths, so a smaller size
   keeps long two-colour second lines from stranding a single word. */
@media (max-width: 430px) {
  .hero h1 { font-size: 1.75rem; }
}
.hero__body { font-size: var(--fs-body-lg); line-height: 1.7; max-width: 34em; }
.hero__body strong { font-weight: 700; color: var(--navy); }
/* Hero pictogram. Drawn as a mask so it obeys the colour rule: navy on the
   light child-page heroes, white on the dark franchises photo band. */
.hero__icon {
  display: block;
  width: clamp(60px, 7vw, 84px);
  height: clamp(60px, 7vw, 84px);
  margin-bottom: clamp(14px, 1.8vw, 22px);
  background: var(--navy);
  -webkit-mask: var(--icon) no-repeat left center / contain;
  mask: var(--icon) no-repeat left center / contain;
}
.section__head--center .hero__icon {
  margin-inline: auto;
  -webkit-mask-position: center;
  mask-position: center;
}
.hero--dark .hero__icon { background: var(--white); }

@media (max-width: 900px) {
  .hero__inner { grid-template-columns: 1fr; }
  .hero__media { order: -1; }
}

/* A hero that sits on a dark band rather than on white: /services and
   /industries/franchises both open this way, over a photograph. */
.hero--dark { background: var(--deep-navy); color: var(--white); }
/* Both hero photographs have bright patches right behind the headline, and the
   pink accent line loses against them. A navy scrim over the photo keeps the
   type crisp without darkening the whole band. */
.hero--dark.section--photo::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(0, 35, 63, 0.42), rgba(0, 35, 63, 0.7));
  pointer-events: none;
}
.hero--dark h1, .hero--dark h2, .hero--dark p, .hero--dark .subheading { color: var(--white); }
.hero--dark .eyebrow { color: var(--arctic); }
/* .hero__body strong is navy by default, which is invisible on a navy band. */
.hero--dark .hero__body strong { color: var(--white); }
/* Light copy on the dark band: was 0.66 white, which read as grey. Now matches
   the site's other on-dark body text (~0.9) so it stays clearly light on dark.
   margin-inline:0 keeps it on the same left edge as the left-aligned heading. */
.hero--dark .hero__body { max-width: 46em; margin-inline: 0; color: rgba(255, 255, 255, 0.9); }

/* ---- Decorative artwork -------------------------------------------------- */

/* The paper plane, machinery and rocket graphics are pure decoration bolted to
   a section corner. They are aria-hidden and are dropped on small screens
   rather than allowed to crowd the copy. */
.deco {
  position: absolute;
  z-index: 0;
  pointer-events: none;
  user-select: none;
}
.deco--plane { top: 0; left: 0; width: clamp(150px, 20vw, 258px); }
.section--has-deco { position: relative; overflow: hidden; }
.section--has-deco > .container { position: relative; z-index: 1; }

@media (max-width: 900px) {
  .deco { display: none; }
}

/* The /careers hero plane. Live pins it to the far left of the band, nose at the
   photograph, trail off the page. What live actually shows there is only the
   container's own side margin, 24px of it at 1200px, which is why on the current
   site it reads as a stray pink wedge rather than as a plane.

   So the offsets here are on the plane's nose rather than on the edge of the PNG:
   the plane occupies the right-hand 41% of the file and the dashed trail the rest,
   so the trail is what runs off the page and the plane stays whole. The nose sits
   a little way onto the corner of the photograph, over the pale ceiling at the top
   of that frame rather than anything with detail, with a floor that stops the tail
   being cut off below about 1290px, where the page margin becomes narrower than
   the plane is long. */
.hero--plane { position: relative; overflow: hidden; }

.hero-plane {
  --plane-graphic: clamp(250px, 31vw, 430px);
  /* The photograph's left edge is the container's left content edge. */
  --photo-left: max(var(--gutter), 50% - var(--container) / 2 + var(--gutter));
  /* How far the nose reaches past that edge, and the floor: 41% of the graphic is
     the plane's own length, less 12px of tail allowed off the page, which is
     enough of a cut to read as flying in from somewhere. */
  --nose: max(
    var(--photo-left) + clamp(34px, 5vw, 76px),
    0.408 * var(--plane-graphic) - 12px
  );
  position: absolute;
  z-index: 1;
  top: clamp(56px, 8vw, 120px);
  /* The nose is at x = 0.982 of the graphic. */
  left: calc(var(--nose) - 0.982 * var(--plane-graphic));
  display: block;
  width: var(--plane-graphic);
  height: auto;
  pointer-events: none;
  user-select: none;
}

@media (max-width: 900px) {
  /* Same call as .deco. The hero stacks here and there is no room beside the
     photograph for a plane to fly in from. */
  .hero-plane { display: none; }
}

/* Decoration set beside a heading rather than pinned to a section corner, which
   is what /services does with the paper plane. Unlike .deco this one is in the
   flow, so it survives on small screens: it shrinks and the row wraps to keep
   the plane and the heading on separate lines instead of squeezing the words. */
.heading-deco-row {
  --deco-w: clamp(96px, 12vw, 168px);
  --deco-gap: clamp(10px, 1.6vw, 26px);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--deco-gap);
  margin-bottom: clamp(16px, 1.8vw, 24px);
}
.heading-deco {
  flex: 0 0 auto;
  width: var(--deco-w);
  height: auto;
  user-select: none;
}

/* The heading is what has to read as centred, not the heading-plus-plane pair.
   Pulling the plane's own width and gap back out of the flex line leaves the
   line exactly as wide as the heading, so the heading centres in the container
   and the plane overhangs into the space to its left.

   Desktop only. Narrow viewports have no space to overhang into, so there the
   row keeps wrapping and the plane sits centred above the heading instead. */
@media (min-width: 901px) {
  .heading-deco-row { flex-wrap: nowrap; }
  .heading-deco-row > .heading-deco {
    margin-left: calc(-1 * (var(--deco-w) + var(--deco-gap)));
  }
}

/* ---- Ribbon-tagged promo card -------------------------------------------- */

/* DropMail, QuickMail, NurtureMail and BirthdayMail each hang a coloured
   bookmark over the top-right of their card with a small glyph inside it. */
/* The top padding is a variable because the ribbon gutter below is expressed
   as "how far the bookmark hangs past it", and the two must not drift apart. */
.promo { position: relative; --promo-pad-top: clamp(56px, 6vw, 76px); padding-top: var(--promo-pad-top); }
.promo__logo { height: clamp(38px, 3.4vw, 51px); width: auto; margin-bottom: 20px; }
/* Scoped past `.card h3`, which would otherwise pin this at 22px. */
.promo .promo__kicker {
  display: block;
  margin-bottom: 10px;
  font-size: clamp(1.15rem, 1.7vw, 1.35rem);
  font-weight: 700;
  line-height: var(--lh-snug);
}

.ribbon {
  position: absolute;
  top: -34px;
  right: 40px;
  display: block;
  width: 61px;
  height: 143px;
}
.ribbon--sm { top: -26px; right: 42px; width: 49px; height: 114px; }
.ribbon > img:first-child { width: 100%; height: 100%; }
.ribbon__glyph {
  position: absolute;
  top: 46px;
  left: 50%;
  width: 18px;
  height: 20px;
  transform: translateX(-50%);
}
.ribbon--sm .ribbon__glyph { top: 36px; }

/* A gutter the bookmark hangs in, so no line of text can run under it.

   Nudging the ribbon sideways cannot fix this. The text column and the bookmark
   share the card's width, so a heading long enough will always reach whichever
   side the bookmark is on: with it on the left it covered the first word of
   every title on /campaign-types and /partner-program, and once moved right,
   /partner-program's four-up "BirthdayMail" still ran under it from 920px to
   1080px and every /campaign-types title did at 320px.

   A float is the right tool because the problem is a line-box problem. Only the
   lines that sit beside the bookmark are shortened; the moment the text clears
   its bottom edge it takes the full width back, so the card keeps its
   proportions instead of growing a band of dead space across the top.

   Height is the part of the hang that reaches past the card's own top padding:
   the bookmark is 143px tall pulled up 34px, so it ends 109px below the padding
   box, and --ribbon--sm 114px pulled up 26px, so it ends at 88px. Width is the
   ribbon's right offset plus its width plus a gap. The ::after contains the
   float, which a plain block card would otherwise let escape its bottom edge. */
.promo:has(.ribbon)::before {
  content: '';
  float: right;
  width: 113px;
  height: calc(109px - var(--promo-pad-top));
}
.promo:has(.ribbon--sm)::before {
  width: 103px;
  height: calc(88px - var(--promo-pad-top));
}
.promo:has(.ribbon)::after { content: ''; display: block; clear: both; }

/* ---- "Coming soon" corner tag -------------------------------------------- */

/* Marks NurtureMail and BirthdayMail, which are announced but not orderable
   yet, on the three pages that list them beside DropMail and QuickMail. Without
   it the four cards read as four equally available products, and only the two
   that ship are links, which is far too quiet a signal.

   The tag takes the card's own radius on the corner it shares with it and stays
   square where it meets the card's edges, so it reads as part of the card
   rather than a sticker sitting on top of one. */
.card:has(> .badge-soon) { position: relative; }

/* -1.5px, not 0, on both axes. Absolute offsets resolve against the padding
   box, so top/left: 0 would leave the card's 1.5px border showing as a hairline
   between the tag and the card's outer edge. The matching --radius-card on the
   shared corner then lands exactly on the card's own outer curve. */
.badge-soon {
  position: absolute;
  top: -1.5px;
  left: -1.5px;
  padding: 4px 11px 5px;
  background: var(--pink);
  color: var(--white);
  border-radius: var(--radius-card) 0 var(--radius) 0;
  font-size: 0.6rem;
  font-weight: 800;
  letter-spacing: 0.12em;
  line-height: 1.5;
  text-transform: uppercase;
  white-space: nowrap;
  z-index: 2;
}

/* The tag is ~24px tall but a plain card's top padding shrinks to 24px, so at
   some widths the heading runs straight into it: at 981px, where this grid is
   still four across, the two collide exactly. A fixed floor guarantees the
   clearance the fluid padding cannot. The badged cards' headings therefore sit
   a few px lower than their unbadged neighbours' in the same row, which is the
   cheaper of the two costs. .promo cards are exempt: their 56-76px of top
   padding, there for the bookmark ribbon, already clears the tag. */
.card:has(> .badge-soon):not(.promo) { padding-top: 36px; }

/* The bookmark ribbon also hangs from the top right (right: 42px) and is ~104px
   wide once the tag is there too, so the two cannot share the corner.

   The TAG moves, not the ribbon. Moving the ribbon left was the first attempt
   and it put the bookmark straight through the card's heading: the heading
   starts at the card's left padding, ~29px in, while the ribbon sat at 42px and
   hangs 88-109px down, so it covered the first word of every title on
   /campaign-types and /partner-program. The card pads its top for the ribbon
   but never its left, so there is nothing on that side to move the text clear.
   The top-left corner, by contrast, is empty above the heading on every card
   that carries a tag, which is why the tag can go there and the ribbon cannot.

   The tag sits left on every card, not only the ones sharing a row with a
   ribbon, so the component reads the same on /services as it does here. */

/* ---- Pull-quote card with a headshot ------------------------------------- */

.quote-card {
  position: relative;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: clamp(20px, 3vw, 40px);
  align-items: center;
  padding: clamp(24px, 3vw, 40px);
  background: var(--off-white);
  border-radius: var(--radius-card);
}
.quote-card__photo {
  width: clamp(96px, 11vw, 140px);
  height: clamp(96px, 11vw, 140px);
  border-radius: 50%;
  object-fit: cover;
}
.quote-card blockquote { margin: 0; }
.quote-card p { font-size: clamp(1rem, 1.3vw, 1.1rem); }
.quote-card footer {
  display: block;
  margin-top: 12px;
  color: var(--pink-text);
  font-size: var(--fs-body);
  font-weight: 700;
}
/* The two comma glyphs the live design floats around the card, at the block's
   top-left and bottom-right. Wrap any testimonial block in .quote-marks and add
   the two spans; every testimonial on the site does this.

   The artwork is white at 35%, which disappears on the off-white slide and on
   the light bands, so it is drawn as a mask and takes a tint instead (same trick
   as .card__icon--tint). The mask comes from img/local/, not the vendored Showit
   mirror: the vendored files carry fill-opacity="0.35", which caps the mask's
   alpha and multiplies the opacity below down to a third of its value — still
   invisible, which is what Owen reported on 2026-07-29. The local copies are
   full-alpha so `opacity` is the only thing setting the glyph's weight.

   Colour is per-band, not global: --marks-color/--marks-opacity default to navy
   on the light bands and are flipped to white on the teal, pink and navy ones by
   the rules below. Do not hardcode a colour on the spans.

   Layering: the glyphs sit BEHIND the card (z-index 0 against the card's 1), so
   the part that laps the card is occluded by the card's own opaque fill and no
   glyph can ever sit over the quote copy. That is what makes them read as
   background rather than as a watermark, which is the distinction Owen drew on
   2026-07-29. Because the occlusion does the work, the lap can be generous
   without costing legibility.

   Geometry. --marks-pad reserves the visible part of each glyph inside the
   block, so the glyph never spills into the neighbouring section:

     glyph height = width x 167/225        (the artwork's aspect ratio)
     --marks-pad  = height - lap          (the part that shows)

   so the open glyph's bottom crosses the card's top edge by exactly --marks-lap
   and the close glyph's top crosses the card's bottom edge by the same. Change
   --marks-w and both follow automatically; the two are tied together on purpose,
   because the earlier version kept them as independent clamps that had to be
   recomputed by hand whenever either moved.

   No horizontal bleed. left/right are flush with the card's own edges: on the
   .split--lead bands the block is the right-hand column, and a leftward bleed
   would put a glyph behind the heading column's copy, which has no fill of its
   own to occlude it. */
.quote-marks {
  --marks-w: clamp(84px, 10vw, 150px);
  --marks-h: calc(var(--marks-w) * 167 / 225);
  /* How far each glyph tucks behind the card. */
  --marks-lap: clamp(16px, 2.4vw, 36px);
  --marks-pad: calc(var(--marks-h) - var(--marks-lap));
  /* Gap between the card's bottom edge and this block's content bottom. The
     carousel spends it on its controls row (46px arrows + 24px margin-top);
     .quote-card has nothing below it, so the card bottom IS the content
     bottom. */
  --marks-card-offset: 0px;
  --marks-color: var(--navy);
  --marks-opacity: 0.18;
  position: relative;
  padding-block: var(--marks-pad);
}
.quote-marks:has(.carousel__controls) { --marks-card-offset: 70px; }

/* Per-band contrast. Navy on the light bands, white on the dark ones. */
.section--deep .quote-marks,
.section--navy .quote-marks,
.hero--dark .quote-marks {
  --marks-color: var(--white);
  --marks-opacity: 0.5;
}

.quote-marks__open,
.quote-marks__close {
  position: absolute;
  width: var(--marks-w);
  aspect-ratio: 225 / 167;
  background-color: var(--marks-color);
  opacity: var(--marks-opacity);
  pointer-events: none;
  z-index: 0;
  -webkit-mask: no-repeat center / contain;
  mask: no-repeat center / contain;
}
/* Everything that is not a glyph is the card, and the card goes in front. */
.quote-marks > :not(.quote-marks__open):not(.quote-marks__close) {
  position: relative;
  z-index: 1;
}
.quote-marks__open {
  top: 0;
  left: 0;
  -webkit-mask-image: url('../img/local/quote-mark-open.svg');
  mask-image: url('../img/local/quote-mark-open.svg');
}
.quote-marks__close {
  /* Resolves to the card's bottom edge minus --marks-lap; see the note above. */
  bottom: var(--marks-card-offset);
  right: 0;
  -webkit-mask-image: url('../img/local/quote-mark-close.svg');
  mask-image: url('../img/local/quote-mark-close.svg');
}

@media (max-width: 768px) {
  .quote-card { grid-template-columns: 1fr; justify-items: center; text-align: center; }
}

/* ---- Checklist with the circle-check glyph -------------------------------- */

.checklist.checklist--check li { padding-left: 38px; }
.checklist.checklist--check li::before {
  top: 4px;
  left: 0;
  width: 22px;
  height: 22px;
  border: 0;
  transform: none;
  background: var(--pink);
  /* The vendored circle-check.svg, used as a mask so it can take the band's
     accent colour instead of shipping one file per colour. */
  -webkit-mask: url('../img/GA7DOKkBeA-JKLErtVlGrA/shared/circle-check.svg') no-repeat center / contain;
  mask: url('../img/GA7DOKkBeA-JKLErtVlGrA/shared/circle-check.svg') no-repeat center / contain;
}
.section--navy .checklist.checklist--check li::before,
.section--deep .checklist.checklist--check li::before { background: var(--white); }

/* ---- Three points band --------------------------------------------------- */

.points {
  position: relative;
  /* Derived from --section-pad, like .hero, rather than an independent clamp:
     this band shares the site's one section rhythm and honours the --sp density
     control. The 1.15 keeps it a touch airier than a standard band, which is the
     breathing room the old clamp (up to 88px) was reaching for. */
  padding: calc(var(--section-pad) * 1.15) 0;
  background: var(--navy);
  color: var(--white);
  overflow: hidden;
}
/* The live site uses a machinery photo at 8% opacity behind this band. */
.points__bg {
  position: absolute;
  inset: 0;
  object-fit: cover;
  width: 100%;
  height: 100%;
  opacity: 0.08;
  pointer-events: none;
}
.points__grid { position: relative; }
/* Left-aligned so every line starts at the same edge; the icon sits at that
   same left edge rather than centred over the text. */
.points__item { text-align: left; }
.points__item .icon-circle { margin-left: 0; }
.points__item h3 {
  margin-bottom: 12px;
  color: var(--white);
  font-size: clamp(1.15rem, 1.7vw, 1.4rem);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}
.points__item p { color: var(--white); font-size: var(--fs-body); margin: 0; }

/* ---- Trust / "By the Numbers" -------------------------------------------
   A dominance-driven redesign of the homepage stats band, scoped to .trust so
   nothing else inherits it. An asymmetric split on the deep-navy band: a
   left-aligned narrative rail balanced against a proof stack where one figure
   ("1 Billion+") leads at display scale and the other two support beneath a
   hairline. Pink is spent only on the dominant "+" and the CTA. Emphasis comes
   from scale, weight and one italic subheading, per the design mantras. */
.trust__inner {
  display: grid;
  grid-template-columns: 0.85fr 1.15fr;
  gap: clamp(40px, 6vw, 96px);
  align-items: center;
}

/* Narrative rail — everything left-aligned to the container edge. */
.trust__rail { text-align: left; }
.trust__rail h2 { color: var(--white); margin-bottom: 12px; }
.trust__subheading {
  margin: 0 0 var(--space-lg);
  color: var(--white);
  font-size: var(--fs-subheading);
  font-weight: 500;
  font-style: italic;          /* synthesized oblique: Proxima Nova ships no italic face */
  line-height: var(--lh-snug);
  letter-spacing: 0;
}
.trust__rail .lead {
  max-width: 34em;
  margin: 0 0 var(--space-2xl);
  color: var(--white);
  text-align: left;            /* overrides the old centred lead */
}

/* Proof stack — left-aligned, sharing one left edge with the rail's grid line. */
.trust__stats { text-align: left; }
.trust__figure {
  display: flex;
  align-items: flex-start;
  gap: 0.06em;
  margin: 0;
}
.trust__stat--lead .stat__value {
  font-size: clamp(3.4rem, 8vw, 6.4rem);
  line-height: 0.92;
  color: var(--white);
}
.trust__stat--lead .stat__label {
  margin-top: 14px;
  font-size: 0.74rem;
}
/* The lone pink accent in the block: a raised "+" that count-up never touches. */
.trust__plus {
  color: var(--pink);
  font-size: clamp(2rem, 4.4vw, 3.4rem);
  font-weight: 900;
  line-height: 1;
}

/* Supporting facts: two-up beneath a hairline that establishes the rhythm. */
.trust__secondary {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(24px, 3vw, 44px);
  margin-top: var(--space-2xl);
  padding-top: var(--space-2xl);
  border-top: 1px solid rgba(255, 255, 255, 0.14);
}
.trust__secondary .stat__value {
  font-size: clamp(1.6rem, 2.6vw, 2.2rem);
  color: var(--white);
}

@media (max-width: 900px) {
  .trust__inner { grid-template-columns: 1fr; gap: var(--space-3xl); }
}
@media (max-width: 560px) {
  .trust__secondary { grid-template-columns: 1fr; gap: var(--space-xl); }
}

/* ---- Tabs (Plan / Produce / Deliver) ------------------------------------- */

.tabs__list {
  display: flex;
  gap: 10px;
  margin: 0 0 28px;
  padding: 6px;
  background: var(--off-white);
  border-radius: var(--radius);
  list-style: none;
}

/* The flex items are the <li>s, not the buttons, so the equal-width rule has
   to live here. Without it the three tabs size to their labels and the grey
   strip runs on past "Deliver" as an empty box. */
.tabs__list > li { flex: 1 1 0; min-width: 0; display: flex; }

.tabs__tab {
  flex: 1 1 auto;
  width: 100%;
  padding: 15px 18px;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--navy);
  font-family: var(--font);
  font-size: var(--fs-body);
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background-color var(--t-base) var(--ease), color var(--t-base) var(--ease);
}
.tabs__tab:hover { color: var(--pink); }
.tabs__tab.is-active { background: var(--pink); color: var(--white); }

.tabs__panel[hidden] { display: none; }
.tabs__panel {
  animation: tab-in 0.4s var(--ease);
}
@keyframes tab-in {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: none; }
}

/* Payoff line above each tab's checklist: states the benefit before the feature
   list, giving the panel a clear lead-then-support hierarchy and carrying the
   page's power-word emphasis into this section. */
.tabs__lead {
  margin: 0 0 var(--space-lg);
  max-width: 30em;
  font-size: var(--fs-body-lg);
  line-height: 1.4;
  color: var(--ink);   /* near-black body ink so the navy .pop word stands out */
}

/* Bulleted feature list with a chevron marker, as the live site uses. */
.checklist { margin: 0; padding: 0; list-style: none; }
.checklist li {
  position: relative;
  padding: 0 0 12px 30px;
  font-size: var(--fs-body);
}
.checklist li::before {
  content: '';
  position: absolute;
  left: 4px;
  top: 9px;
  width: 7px;
  height: 7px;
  border-right: 2.5px solid var(--pink);
  border-bottom: 2.5px solid var(--pink);
  transform: rotate(-45deg);
}

@media (max-width: 768px) {
  .tabs__list { flex-direction: column; }
  .tabs__tab { width: 100%; }
}

/* ---- Carousel ------------------------------------------------------------ */

.carousel { position: relative; }
.carousel__viewport { overflow: hidden; border-radius: var(--radius); }
.carousel__track {
  display: flex;
  transition: transform 0.55s var(--ease);
}
.carousel__slide {
  flex: 0 0 100%;
  min-width: 100%;
  padding: clamp(28px, 3.4vw, 48px);
}

.quote {
  margin: 0;
  font-size: clamp(1.05rem, 1.5vw, 1.2rem);
  line-height: 1.55;
}
.quote p { margin-bottom: 18px; }
.quote footer, .quote cite {
  display: block;
  color: var(--pink-text);
  font-size: var(--fs-small);
  font-weight: 700;
  font-style: normal;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.carousel__controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 18px;
  margin-top: 24px;
}

.carousel__arrow {
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  border: 2px solid var(--navy);
  border-radius: 50%;
  background: transparent;
  color: var(--navy);
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.carousel__arrow:hover { background: var(--pink); border-color: var(--pink); color: var(--white); }
.carousel__arrow svg { width: 17px; height: 17px; fill: currentColor; }

.carousel__dots { display: flex; gap: 9px; }
.carousel__dot {
  width: 10px;
  height: 10px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--border-dark);
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease), transform var(--t-fast);
}
.carousel__dot.is-active { background: var(--pink); transform: scale(1.35); }

.section--navy .carousel__arrow { border-color: var(--white); color: var(--white); }
.section--navy .carousel__arrow:hover { background: var(--white); color: var(--navy); }
.section--navy .quote footer { color: var(--sky); }

/* ---- Image gallery ------------------------------------------------------- */

/* The same carousel machinery carrying photographs instead of quotes, as the
   mail-product gallery on /services and /industries does. The slides are
   unpadded so the photo fills the viewport edge to edge, and every slide is
   boxed to one aspect ratio so the arrows and dots do not jump as you click
   through products that were shot at different sizes. */
.gallery .carousel__slide {
  display: block;
  margin: 0;
  padding: 0;
}
.gallery__slide img {
  display: block;
  width: 100%;
  aspect-ratio: 10 / 7;
  object-fit: cover;
  background: var(--off-white);
}
.gallery__slide figcaption {
  padding: 14px 4px 0;
  color: var(--navy);
  font-size: 0.88rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-align: center;
  text-transform: uppercase;
}
.gallery .carousel__controls { margin-top: 16px; }

/* ---- Accordion ----------------------------------------------------------- */

.accordion { border-top: 1px solid var(--line); }
.accordion__item { border-bottom: 1px solid var(--line); }

.accordion__heading { margin: 0; }
.accordion__trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  width: 100%;
  padding: 22px 4px;
  border: 0;
  background: none;
  color: var(--navy);
  font-family: var(--font);
  font-size: 1.05rem;
  font-weight: 800;
  letter-spacing: -0.01em;
  line-height: 1.4;
  text-align: left;
  cursor: pointer;
  transition: color var(--t-fast) var(--ease);
}
.accordion__trigger:hover { color: var(--pink); }
.accordion__trigger:hover .accordion__icon { border-color: var(--pink); }

.accordion__icon {
  flex: 0 0 auto;
  position: relative;
  width: 26px;
  height: 26px;
  border: 2px solid var(--line);
  border-radius: 50%;
  color: var(--pink);
  transition: transform var(--t-base) var(--ease),
              background-color var(--t-base) var(--ease),
              border-color var(--t-base) var(--ease),
              color var(--t-base) var(--ease);
}
.accordion__icon::before,
.accordion__icon::after {
  content: '';
  position: absolute;
  /* Inset from the ring rather than spanning it, so the glyph reads as a plus
     inside a circle instead of a crossed-out one. */
  inset: 50% 6px auto 6px;
  height: 2.5px;
  margin-top: -1.25px;
  background: currentColor;
  border-radius: 2px;
}
.accordion__icon::after { transform: rotate(90deg); }
/* The whole ring turns, which takes the plus to a cross and fills it pink. */
.is-open .accordion__icon {
  transform: rotate(45deg);
  background: var(--pink);
  border-color: var(--pink);
  color: var(--white);
}

.accordion__panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.26s var(--ease);
}
.accordion__panel-inner { padding: 0 4px 24px; max-width: 68em; }
.accordion__panel-inner p:last-child { margin-bottom: 0; }

.accordion__group-heading {
  margin: 44px 0 4px;
  font-size: 0.88rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--pink-text);
}
.accordion__group-heading:first-child { margin-top: 0; }

/* ---- Accent hooks --------------------------------------------------------- */

/* The live design cycles pink, navy, teal and light blue across a row and uses
   the same accent for a card's rule, badge, heading and footer bar. Custom
   properties carry it, so a card only has to declare its accent once.

   Three properties, not one, because a fill and a piece of type in the same hue
   cannot be the same value. Turquoise and arctic are light: as a badge or a rule
   they are the brand colour and they look right, and as 18px type on white they
   are 2.3:1 and 1.6:1 and they are not there. So:

     --accent       the FILL: badges, dots, bars, rules. True brand colour.
     --accent-text  TYPE in the same hue. The legible cut. See tokens.css.
     --accent-on    type sitting ON the fill: white on the dark accents,
                    deep navy on the light ones. */
.accent-pink {
  --accent: var(--pink);
  --accent-text: var(--pink-text);
  --accent-on: var(--white);
}
.accent-navy {
  --accent: var(--navy);
  --accent-text: var(--navy);
  --accent-on: var(--white);
}
.accent-teal {
  --accent: var(--turquoise);
  --accent-text: var(--teal-text);
  --accent-on: var(--deep-navy);   /* 6.9:1 on the turquoise fill */
}
.accent-sky {
  --accent: var(--arctic);
  --accent-text: var(--arctic-text);
  --accent-on: var(--deep-navy);   /* 10.4:1 on the arctic fill */
}

.pill {
  display: inline-block;
  margin-bottom: 14px;
  padding: 4px 14px;
  border-radius: var(--radius-sm);
  background: var(--accent, var(--pink));
  color: var(--accent-on, var(--white));
  font-size: var(--fs-eyebrow);
  font-weight: 700;
  letter-spacing: 0.08em;
  line-height: var(--lh-snug);
  text-transform: uppercase;
}

/* ---- Overlapping photo collage ------------------------------------------- */

/* Three photographs the live site scatters on its absolute canvas: one wide
   across the top, then a tall one lifted into it and a third dropped below. */
.collage { display: grid; grid-template-columns: repeat(12, 1fr); }
.collage img {
  position: relative;
  width: 100%;
  border-radius: var(--radius);
  object-fit: cover;
}
.collage img:nth-child(1) { grid-area: 1 / 3 / 2 / 13; aspect-ratio: 16 / 10; }
.collage img:nth-child(2) { grid-area: 2 / 1 / 3 / 7; aspect-ratio: 3 / 4; margin-top: -16%; z-index: 1; }
.collage img:nth-child(3) { grid-area: 2 / 8 / 3 / 13; aspect-ratio: 7 / 6; margin-top: 14%; }

/* ---- Era timeline --------------------------------------------------------- */
/* The live row is four disconnected columns of bare text, which does not read
   as a progression. One continuous rail runs through all four era markers
   instead of giving each column its own border-top.

   Pure CSS on purpose: a rail plus four dots, no images, no extra script, and
   nothing that has to be measured at run time. The staggered arrival of the
   items is the existing [data-reveal-group] on the list, so the sequence is
   already animated without anything new being loaded. */

.timeline {
  --rail: 3px;
  --dot: 15px;
  /* Colour of the ring that punches the rail out from behind each marker, so
     it has to match the band the timeline sits on. Overridable per placement. */
  --timeline-bg: var(--white);
  position: relative;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: clamp(20px, 3vw, 36px);
  margin: 0;
  padding: 0;
  list-style: none;
}
/* The rail. It runs past the last marker and fades rather than stopping dead,
   because the last era is "Today" and the story is still going. */
.timeline::before {
  content: "";
  position: absolute;
  top: calc((var(--dot) - var(--rail)) / 2);
  left: 0;
  right: 0;
  height: var(--rail);
  border-radius: var(--rail);
  background: var(--border-dark);
  -webkit-mask-image: linear-gradient(90deg, #000 0, #000 80%, transparent 100%);
  mask-image: linear-gradient(90deg, #000 0, #000 80%, transparent 100%);
}
.timeline__item {
  position: relative;
  padding-top: calc(var(--dot) + 18px);
}
/* Era marker. Keeps the per-era accent the border-top used to carry, and the
   ring stops the rail showing through the middle of the dot. */
.timeline__item::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: var(--dot);
  height: var(--dot);
  border-radius: 50%;
  background: var(--accent, var(--pink));
  box-shadow: 0 0 0 4px var(--timeline-bg);
}
/* Graphite, not the era's accent. At 16.3px this is small text needing 4.5:1,
   and the lighter teal and arctic cuts only reach 3.3:1. The era still reads as
   its own colour: the dot above it and the title under it both carry the accent,
   and they are the parts that are large enough to. */
.timeline__era {
  display: block;
  color: var(--graphite);
  font-size: 1.02rem;
  font-weight: 900;
  line-height: var(--lh-snug);
}
.timeline__title {
  margin: 2px 0 10px;
  color: var(--accent-text, var(--pink-text));
  font-size: clamp(1.2rem, 1.9vw, 1.5rem);
  font-weight: 900;
  line-height: var(--lh-tight);
}
.timeline p { margin: 0; font-size: var(--fs-body); }

/* A connecting line cannot be continuous across a two-column wrap, so narrow
   viewports go straight to a single column and the rail turns vertical. */
@media (max-width: 900px) {
  .timeline { grid-template-columns: 1fr; gap: clamp(26px, 5vw, 34px); }
  .timeline::before {
    top: calc(var(--dot) / 2);
    bottom: 0;
    left: calc((var(--dot) - var(--rail)) / 2);
    right: auto;
    width: var(--rail);
    height: auto;
    -webkit-mask-image: linear-gradient(180deg, #000 0, #000 84%, transparent 100%);
    mask-image: linear-gradient(180deg, #000 0, #000 84%, transparent 100%);
  }
  .timeline__item { padding-top: 0; padding-left: calc(var(--dot) + 20px); }
  /* Centre the marker on the era line beside it: (20px * 1.2 - 15px) / 2. */
  .timeline__item::before { top: 5px; }
  .timeline::before { top: calc(5px + var(--dot) / 2); }
}

/* ---- Core-value card (the FLASH'D row) ------------------------------------ */

/* White card with a pictogram, a heading whose acronym letter is underlined,
   and a solid accent bar filling the bottom edge. */
.value-card {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: clamp(24px, 2.6vw, 30px);
  padding-bottom: clamp(52px, 4.5vw, 64px);
  background: var(--white);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card-sm);
  overflow: hidden;
}
.value-card::after {
  content: '';
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  height: 28px;
  background: var(--accent-text, var(--pink-text));
}
/* Drawn as a mask, not an <img>, so each pictogram takes its card's accent
   instead of the single colour baked into the source SVG. That is what lets the
   set stay legible when the band is navy (the two arctic cards were navy art,
   invisible there). Sized to 74px tall, native aspect, anchored bottom-left. */
.value-card__icon {
  display: block;
  width: 100%;
  height: 74px;
  margin-bottom: 16px;
  background: var(--accent-text, var(--pink-text));
  -webkit-mask: var(--icon) no-repeat left bottom / auto 100%;
  mask: var(--icon) no-repeat left bottom / auto 100%;
}
.value-card h3 {
  margin-bottom: 12px;
  color: var(--accent-text, var(--pink-text));
  font-size: var(--fs-h3);
  font-weight: 700;
}
.value-card h3 u { text-decoration-thickness: 2px; text-underline-offset: 3px; }
.value-card p { margin: 0; font-size: var(--fs-body); }

/* FLASH'D sits on a navy band but the cards stay white so they pop against it.
   Copy therefore stays graphite, and the icon, heading and bar use the legible
   --accent-text cuts (which clear 3:1 on white) rather than the true brand
   colours, matching how the rest of the site treats a white card on navy. */
.section--navy .value-card p,
.section--deep .value-card p { color: var(--ink); }

/* ---- Industry tiles ------------------------------------------------------- */

.industry-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  min-height: 230px;
  text-align: center;
}
/* Drawn as a mask so every tile icon takes the tile's accent (navy on the
   current light overlap) instead of the mixed pink/navy/teal baked into the
   source SVGs, which put turquoise on a light card. Square box, centred. */
.industry-tile__icon {
  display: block;
  width: clamp(84px, 8vw, 117px);
  height: clamp(84px, 8vw, 117px);
  background: var(--icon-color, var(--navy));
  -webkit-mask: var(--icon) no-repeat center / contain;
  mask: var(--icon) no-repeat center / contain;
}
/* The card accent modifiers colour h3; an industry tile's title is the page's
   heading level 2, so it needs its own rule. */
.industry-tile h2 { margin: 0; font-size: clamp(1.15rem, 1.9vw, 1.5rem); font-weight: 900; }
.industry-tile.card--pink h2 { color: var(--pink); }
.industry-tile.card--navy h2 { color: var(--navy); }
.industry-tile.card--teal h2 { color: var(--teal-text); }
.industry-tile.card--sky h2 { color: var(--sky-text); }

.tile-note { display: flex; flex-direction: column; justify-content: center; text-align: center; }
.tile-note .btn-row { justify-content: center; }
@media (max-width: 900px) {
  .tile-note { grid-column: auto !important; }
}

/* ---- Certification card --------------------------------------------------- */

/* Badge on the left, claim on the right. */
.cert-card {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: clamp(18px, 2.4vw, 32px);
  align-items: center;
}
.cert-card > img { width: clamp(84px, 9vw, 117px); height: auto; }
.cert-card h3 { font-size: clamp(1.3rem, 2.2vw, 1.75rem); font-weight: 900; }

@media (max-width: 560px) {
  .cert-card { grid-template-columns: 1fr; justify-items: center; text-align: center; }
}

/* Inline HIPAA + SOC 2 badges shown alongside a compliance claim in body copy. */
.compliance-badges {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: clamp(16px, 2vw, 28px);
  margin: 0 0 clamp(20px, 2.4vw, 28px);
}
.compliance-badges img { width: auto; height: clamp(76px, 8vw, 104px); }

/* The second practices row is two cards, centred under the three above. */
.practices-row-2 {
  max-width: 68%;
  margin: clamp(24px, 3vw, 40px) auto 0;
}
@media (max-width: 900px) { .practices-row-2 { max-width: none; } }

/* ---- Academy bento -------------------------------------------------------- */

/* Module list full height on the left, three shorter cards to its right. */
.academy-grid {
  grid-template-columns: 1.45fr 1fr 1fr;
  align-items: start;
}
@media (max-width: 900px) {
  .academy-grid { grid-template-columns: 1fr; }
  .academy-grid > * { grid-column: auto !important; grid-row: auto !important; }
}

.module-list {
  margin: 0;
  padding-left: 1.4em;
  font-size: var(--fs-body);
}
.module-list li { margin-bottom: 8px; }
.module-list li::marker { color: var(--pink); font-weight: 900; }

.module-bonus {
  margin-top: 22px;
  padding-top: 18px;
  border-top: 1px solid var(--border);
  font-size: var(--fs-small);
}
.module-bonus strong {
  display: inline-block;
  margin-right: 6px;
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* ---- Benefits list -------------------------------------------------------- */

/* Title-and-detail pairs, which is a description list rather than the two
   stacked paragraphs per benefit that the live page ships. */
/* Each benefit is ticked off with a navy disc and a white check. The disc is drawn
   rather than vendored, and the check is two borders rotated 45deg, the same trick
   .checklist uses for its chevron, which keeps the tick pure white on any card
   colour instead of knocking through to whatever is behind it. */
.benefits { margin: 0; }
.benefits dt {
  position: relative;
  margin-top: 22px;
  padding-left: 34px;
  color: var(--navy);
  font-size: 1.02rem;
  font-weight: 700;
  line-height: var(--lh-snug);
}
.benefits dt::before {
  content: '';
  position: absolute;
  left: 0;
  top: 1px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--navy);
}
.benefits dt::after {
  content: '';
  position: absolute;
  left: 6px;
  top: 8px;
  width: 10px;
  height: 5px;
  border-left: 2px solid var(--white);
  border-bottom: 2px solid var(--white);
  transform: rotate(-45deg);
}
.benefits dt:first-child { margin-top: 0; }
/* Indented to the same 34px so the description lines up under its own heading
   rather than under the disc. */
.benefits dd {
  margin: 4px 0 0;
  padding-left: 34px;
  color: var(--navy);
  font-size: var(--fs-body);
  line-height: 1.45;
}

/* ---- Job posting meta ----------------------------------------------------- */

/* Label/value pairs at the top of a role page (reports to, hours, pay,
   location). Two columns on desktop, stacked on narrow screens. */
.job-meta { margin: 0; display: grid; grid-template-columns: max-content 1fr; gap: 10px 24px; }
.job-meta dt {
  color: var(--muted-text);
  font-weight: 700;
  font-size: var(--fs-small);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.job-meta dd { margin: 0; color: var(--navy); font-size: var(--fs-small); line-height: 1.5; }
@media (max-width: 560px) {
  .job-meta { grid-template-columns: 1fr; gap: 2px; }
  .job-meta dd { margin-bottom: 12px; }
  .job-meta dd:last-child { margin-bottom: 0; }
}

/* ---- Team roster ---------------------------------------------------------- */

/* Square headshots on a 25px radius with the name underneath, four to a row,
   which is how the live team page lays out every department. */
/* minmax(0, 1fr) rather than 1fr: a 1fr track still respects its content's
   min-content width, so a single long name or job title widens its whole
   column and the headshots stop being the same size. */
.roster {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(22px, 2.8vw, 38px) clamp(18px, 2.2vw, 30px);
}
/* The leadership row is three then two, centred, so it flexes rather than
   leaving two items stranded at the left of a four-column grid. */
.roster--leaders {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  /* Flex rather than grid so the leadership row stays centred however many
     people are in it, instead of stranding a short last row at the left. */
  max-width: 1040px;
  margin-inline: auto;
}
.roster--leaders > * { flex: 0 1 235px; }

/* Canine Crew: five tiles as a centred 3-over-2 pyramid. Flex (not the four-column
   roster grid) so the trailing pair centres under the top three. Tiles keep the
   ~300px size they had in the four-column grid; the max-width holds three of them
   per row (3x299 + 2 gaps) so the fourth wraps to a centred second row. */
.roster--pyramid {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  max-width: 980px;
  margin-inline: auto;
}
.roster--pyramid > * { flex: 0 1 299px; }
/* Two per row on phones, matching the other rosters. */
@media (max-width: 600px) {
  .roster--pyramid > * { flex-basis: calc(50% - 12px); }
}

.roster__item { text-align: center; }
.roster__item img {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border-radius: var(--radius-card);
}
.roster__name {
  display: block;
  margin-top: 14px;
  color: var(--navy);
  font-size: clamp(1.05rem, 1.5vw, 1.25rem);
  font-weight: 900;
  line-height: var(--lh-snug);
}
/* The live page publishes names only. Titles come from the roster Owen
   confirmed, and sit under the name at body weight so the name still leads. */
.roster__role {
  display: block;
  margin-top: 4px;
  color: var(--ink);
  font-size: 0.88rem;
  font-weight: 400;
  line-height: 1.35;
}
.section--navy .roster__name { color: var(--white); }
.section--navy .roster__role { color: rgba(255, 255, 255, 0.85); }

/* A recruiting tile that sits in the grid where a headshot would. */
.roster__join {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 18px;
  padding: clamp(20px, 2.4vw, 28px);
  border-radius: var(--radius-card);
  background: var(--accent, var(--navy));
  color: var(--accent-on, var(--white));
  text-align: center;
}
.roster__join p {
  margin: 0;
  color: var(--accent-on, var(--white));
  font-size: clamp(1.05rem, 1.5vw, 1.25rem);
  font-weight: 900;
  line-height: var(--lh-snug);
}
.roster__join-sub {
  margin: 0;
  color: rgba(255, 255, 255, 0.9);
  font-size: 0.88rem;
  font-weight: 400;
  line-height: 1.4;
}
.roster__join .btn-row { margin-top: 0; }

@media (max-width: 900px) { .roster { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 600px) { .roster { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* .press-card (the static awards grid) and .logo-strip (the static partners
   grid) both lived here. /about was the only page using either, and both bands
   now run through the waterfall, so the rules went with them rather than sitting
   unused. See .wf-logo further down, and the two bands in site/pages/about.html.
   Commit history has the originals if a static logo grid is ever wanted again. */

/* ---- Photo strip --------------------------------------------------------- */

.photo-strip {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 14px;
}
.photo-strip img {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border-radius: var(--radius);
}
@media (max-width: 768px) {
  .photo-strip { grid-template-columns: repeat(2, 1fr); }
}

/* Three equal frames in a row, which is how the live block is laid out. It
   stays three across on mobile rather than dropping to the two-column rule
   above, because three photos in a two-column grid leaves a hole. Declared
   after the media query so it wins at every width.

   Portrait rather than square: three squares in half a split row left a deep
   band of empty space beside the copy, and this is the only axis the tiles can
   grow on without stealing width from the heading. */
.photo-strip--trio { grid-template-columns: repeat(3, 1fr); }
.photo-strip--trio img { aspect-ratio: 3 / 4; }

/* ---- Offset photo pair --------------------------------------------------- */

/* Two frames staggered diagonally instead of sitting flat side by side. The
   point is width: in a flat two-up row each frame can only reach just under
   half the column (265px of 544px in the /industries/franchises spotlight),
   whereas dropping the second frame into its own row lets both span 5 of 8
   columns, about 332px, and the pair still sweeps the column's full width.
   Any widening past half needs the vertical offset, because two frames wider
   than 50% cannot share one row without overlapping.

   5-of-8 with the second starting at column 4 is what sets the diagonal: the
   frames share two columns of horizontal range, so the step across reads as
   deliberate rather than as a broken row. It fits because the spotlight's copy
   column runs 926px against the media column's 432px; the taller stack closes
   that gap rather than opening a new one. */
.photo-stagger {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: clamp(14px, 1.8vw, 22px);
}
.photo-stagger img {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border-radius: var(--radius);
}
.photo-stagger img:nth-child(odd) { grid-column: 1 / span 5; }
.photo-stagger img:nth-child(even) { grid-column: 4 / span 5; }

/* ---- Brand logo plate ---------------------------------------------------- */

/* A client lockup that only exists as a white-on-transparent "logo-light" file
   needs a dark field under it or it vanishes, which is what the Youth Athletes
   United logo did on the pink spotlight band. Navy plate rather than a
   recoloured copy of the artwork, because navy is how YAU set the same lockup
   on their own site. */
.logo-plate {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(22px, 2.8vw, 34px) clamp(28px, 4vw, 52px);
  background: var(--navy);
  border-radius: var(--radius-card);
}
/* On a navy band the plate is only one step lighter than what surrounds it, so a
   hairline keeps its edge visible. It used to sit on a pink band, where the fill
   alone was separation enough. */
.section--navy .logo-plate,
.section--deep .logo-plate { box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.16); }
.logo-plate img {
  display: block;
  width: 100%;
  max-width: 260px;
  height: auto;
}

/* ---- CTA band ------------------------------------------------------------ */

.cta-band {
  /* Same rhythm source as .points and .hero: one --section-pad-derived scale for
     every band, so the closer tracks --sp instead of running on its own clamp. */
  padding: calc(var(--section-pad) * 1.15) 0;
  background: linear-gradient(135deg, var(--navy) 0%, var(--navy-deep) 100%);
  color: var(--white);
  text-align: center;
}
.cta-band > .section__bg { opacity: 0.32; }
/* Every closer on the site is this one navy gradient. The pink and teal variants
   that /campaign-types, /faq and six others used to close on are gone: a full
   band of either is exactly the use of the accent colours Owen ruled out. The
   pink stays on the CTA button inside the band, which is where it belongs. */
.cta-band h2 { color: var(--white); margin-bottom: 14px; }
.cta-band p { color: rgba(255, 255, 255, 0.88); font-size: var(--fs-body-lg); }
.cta-band .btn-row { justify-content: center; }

/* ---- Form --------------------------------------------------------------- */

.form-card {
  padding: clamp(26px, 3vw, 44px);
  background: var(--white);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
}
/* HubSpot injects its own markup; give it room and a consistent font. */
.form-card .hs-form-frame,
.form-card form { font-family: var(--font); }
.form-card iframe { width: 100%; border: 0; }

/* ---- Native form fields -------------------------------------------------- */
/* Hand-built fields, so a form can ship and be styled before the CRM embed
   exists. Same type scale and radius as the rest of the site. */

.field { display: grid; gap: 7px; }
/* display:grid overrides the hidden attribute's default display:none, so a
   conditionally revealed field would show before it is triggered. */
.field[hidden] { display: none; }
.field__label {
  color: var(--navy);
  font-size: var(--fs-eyebrow);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.field__input {
  width: 100%;
  padding: 14px 16px;
  border: 1.5px solid var(--border-dark);
  border-radius: var(--radius);
  background: var(--white);
  color: var(--ink);
  font-family: var(--font);
  font-size: var(--fs-small);
  line-height: 1.4;
  transition: border-color var(--t-fast) var(--ease),
              box-shadow var(--t-fast) var(--ease);
}
.field__input::placeholder { color: var(--muted); }
.field__input:focus {
  outline: 0;
  border-color: var(--teal);
  box-shadow: 0 0 0 3px rgba(68, 189, 169, 0.25);
}
/* Only after a failed submit, so the fields are not red before anyone types. */
.is-validated .field__input:invalid { border-color: var(--pink); }

.field__error {
  color: var(--pink-text);
  font-size: 0.82rem;
  font-weight: 700;
}
.field__error:empty { display: none; }

/* ---- Lead capture -------------------------------------------------------- */

.lead-form { margin-top: 26px; }
.lead-form__row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}
.lead-form .btn { margin-top: 18px; }
/* The fields sit under centred copy, so they hold a narrow measure of their
   own rather than stretching the full width of the card. Labels and errors
   stay left-aligned inside them: centred field labels are hard to scan. */
.lead-form--centered {
  max-width: 560px;
  margin-inline: auto;
  text-align: left;
}
.lead-form--centered .btn { display: flex; margin-inline: auto; }
.lead-form--centered .lead-form__fineprint { text-align: center; }

/* Two-by-two variant, with the submit spanning both columns underneath.
   Used by the Academy interest list. */
.lead-form__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}
.lead-form__grid > .btn {
  grid-column: 1 / -1;
  width: 100%;
  margin-top: 2px;
}
@media (max-width: 560px) { .lead-form__grid { grid-template-columns: 1fr; } }

/* A lead form dropped into a .cta-band: the band centres its text, which the
   labels and errors must not inherit. */
.form-card--lead {
  max-width: 680px;
  margin: clamp(28px, 3.5vw, 40px) auto 0;
  text-align: left;
}
.form-card--lead .lead-form { margin-top: 0; }
.lead-form__fineprint {
  margin: 12px 0 0;
  color: var(--graphite);
  font-size: 0.82rem;
}
/* ---- Text-led offer block ------------------------------------------------ */
/* No artwork, so the type does the work: a wide quiet card, a heading at
   section scale rather than card scale, and a measure narrow enough to read
   in one sweep. */

.offer { padding: clamp(36px, 4.5vw, 64px) clamp(24px, 3vw, 48px); }
.offer__copy { max-width: 760px; margin-inline: auto; }
/* Past `.card h3`, which pins card headings at 22px; this one is the point of
   the block, so it runs at the same size as a section heading. */
.offer h2 {
  margin-bottom: 16px;
  font-size: clamp(1.9rem, 3.6vw, 2.8rem);
  line-height: 1.1;
}
.offer .lead { margin-bottom: 0; color: var(--ink); }
/* A hover lift belongs on a card you can click. This one holds a form. */
.offer:hover { transform: none; box-shadow: none; }
/* The confirmation takes the place of the fields, so it takes their width too
   rather than snapping out to the full measure of the copy above. */
.offer .lead-form__done {
  max-width: 560px;
  margin-inline: auto;
  text-align: center;
}

/* Two-column variant: the pitch on the left, the form in its own soft panel on
   the right, so a wide card fills its width instead of leaving the right half
   empty. Collapses back to a stack on narrow screens. */
.offer--split {
  display: grid;
  grid-template-columns: 1.1fr 0.9fr;
  gap: clamp(32px, 5vw, 64px);
  align-items: center;
  text-align: left;
}
.offer--split .offer__copy { max-width: none; margin: 0; }
.offer__form {
  margin-top: 0;
  padding: clamp(24px, 2.6vw, 32px);
  background: var(--bg-soft);
  border-radius: var(--radius-card);
}
/* Stack the two fields in the narrower column, and let the confirmation and
   fineprint use that same left measure rather than the centred one above. */
.offer__form .lead-form__row { grid-template-columns: 1fr; }
.offer__form .lead-form__fineprint { text-align: left; }
.offer--split .lead-form__done { max-width: none; margin-inline: 0; text-align: left; }
@media (max-width: 760px) {
  .offer--split { grid-template-columns: 1fr; gap: var(--space-2xl); }
}

/* Swapped in by lead-form.js in place of the fields. */
.lead-form__done {
  padding: 18px 20px;
  border: 1px solid var(--teal);
  border-radius: var(--radius);
  background: rgba(63, 190, 172, 0.1);
  color: var(--navy);
  font-size: var(--fs-body);
  font-weight: 700;
}
.lead-form__done-msg { margin: 0; }
/* When the confirmation carries a download button (the guide offer), give it
   room under the message. */
.lead-form__done .btn { margin-top: 16px; }

@media (max-width: 768px) {
  .lead-form__row { grid-template-columns: 1fr; }
}

/* ---- Schedule A Call form ------------------------------------------------ */
/* A longer, structured form than the guide-offer captures: selects, a radio
   group, a textarea and a phone field, stacked full width with the name pair
   on one row. Left aligned, since the fields carry their own labels. */

.lead-form--schedule {
  display: grid;
  gap: 20px;
  max-width: 620px;
  margin: clamp(28px, 3.5vw, 44px) auto 0;
  text-align: left;
}
.lead-form--schedule .btn { margin-top: 6px; }

/* Selects reuse the field look but need the native chevron replaced, since the
   platform default clashes with the rest of the fields. */
select.field__input {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 42px;
  cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%230b3b60' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 16px center;
}
select.field__input:invalid { color: var(--muted); }

textarea.field__input {
  min-height: 120px;
  line-height: 1.6;
  resize: vertical;
}

/* Helper text under a field, distinct from the error slot. */
.field__help {
  margin: 0;
  color: var(--graphite);
  font-size: 0.82rem;
  line-height: 1.5;
}
.field__optional {
  color: var(--muted-text); /* AA-passing cut; --muted (2.61:1) is too light for read text */
  font-weight: 600;
  text-transform: none;
  letter-spacing: 0;
}

/* Phone: country selector then the number, collapsing to a stack on narrow
   screens so neither gets squeezed. */
.field__phone {
  display: grid;
  grid-template-columns: minmax(140px, max-content) 1fr;
  gap: 10px;
}
@media (max-width: 480px) {
  .field__phone { grid-template-columns: 1fr; }
}

/* Radio group rendered as selectable pills, matching the button radius. */
.field__radios { display: flex; flex-wrap: wrap; gap: 12px; }
.radio {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 12px 20px;
  border: 1.5px solid var(--border-dark);
  border-radius: var(--radius);
  background: var(--white);
  color: var(--navy);
  font-size: var(--fs-small);
  font-weight: 600;
  cursor: pointer;
  transition: border-color var(--t-fast) var(--ease),
              background-color var(--t-fast) var(--ease);
}
.radio input {
  width: 16px;
  height: 16px;
  margin: 0;
  accent-color: var(--pink);
}
.radio:hover { border-color: var(--navy); }
.radio:has(input:checked) {
  border-color: var(--pink);
  background: rgba(232, 31, 118, 0.06);
}
.radio:has(input:focus-visible) {
  outline: 2px solid var(--teal);
  outline-offset: 2px;
}

/* Honeypot: present in the DOM, off-screen for people and assistive tech. */
.hp-field {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

.lead-form.is-submitting .btn { opacity: 0.7; pointer-events: none; }

/* The scheduler step swapped in after a successful submit. The embed area is a
   placeholder until a scheduler is chosen and mounted through
   MW.mountScheduler. */
.schedule-next { max-width: 620px; margin: clamp(28px, 3.5vw, 44px) auto 0; }
.schedule-next:focus { outline: none; }
.schedule-next h2 { margin: 6px 0 0; }
.schedule-embed {
  margin: 20px 0;
  border-radius: var(--radius-card);
  overflow: hidden;
}
.schedule-embed iframe { display: block; width: 100%; border: 0; }
.schedule-fallback {
  margin: 0;
  color: var(--graphite);
  font-size: 0.9rem;
}
.schedule-confirm {
  margin: 14px 0 0;
  color: var(--graphite);
  font-size: 1.05rem;
  line-height: 1.55;
}

/* ---- Contact: intent router + info rail ---------------------------------- */
/* Two columns: the intent chooser / form on the left, a persistent info rail
   on the right that stays visible at both steps. */

.contact-layout {
  display: grid;
  grid-template-columns: 1.5fr 1fr;
  gap: clamp(32px, 4vw, 64px);
  align-items: start;
}
@media (max-width: 860px) {
  .contact-layout { grid-template-columns: 1fr; }
}

.contact-main__title {
  margin: 0 0 20px;
  font-size: var(--fs-h3);
}
[data-contact-step][hidden] { display: none; }

.intent-cards { display: grid; gap: 14px; }
.intent-card {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 6px 16px;
  width: 100%;
  padding: 20px 22px;
  border: 1.5px solid var(--line);
  border-radius: var(--radius-card);
  background: var(--white);
  color: var(--navy);
  text-align: left;
  cursor: pointer;
  transition: border-color var(--t-fast) var(--ease),
              box-shadow var(--t-fast) var(--ease),
              transform var(--t-fast) var(--ease);
}
.intent-card:hover {
  border-color: var(--pink);
  box-shadow: var(--shadow-navy);
  transform: translateY(-2px);
  text-decoration: none;
}
.intent-card:focus-visible { outline: 2px solid var(--teal); outline-offset: 2px; }
.intent-card__title {
  font-size: var(--fs-body-lg);
  font-weight: 800;
}
.intent-card__note {
  grid-column: 1;
  color: var(--graphite);
  font-size: var(--fs-small);
}
.intent-card__arrow {
  grid-row: 1 / 3;
  grid-column: 2;
  color: var(--pink);
  font-size: 1.4rem;
  font-weight: 700;
  transition: transform var(--t-fast) var(--ease);
}
.intent-card:hover .intent-card__arrow { transform: translateX(4px); }

.contact-back {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 16px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--pink-text);
  font-family: var(--font);
  font-size: var(--fs-small);
  font-weight: 700;
  cursor: pointer;
}
.contact-back:hover { text-decoration: underline; }
.contact-back:focus-visible { outline: 2px solid var(--teal); outline-offset: 2px; }

.lead-form--contact { display: grid; gap: 20px; margin-top: 0; }
.lead-form--contact .btn { justify-self: start; margin-top: 2px; }

/* Info rail. A quiet panel so it reads as reference, not as the main action. */
.contact-rail {
  padding: clamp(24px, 3vw, 32px);
  border-radius: var(--radius-card);
  background: var(--bg-soft);
}
.rail-item { display: flex; gap: 14px; }
.rail-item + .rail-item {
  margin-top: 22px;
  padding-top: 22px;
  border-top: 1px solid var(--line);
}
.rail-item__icon { flex: none; color: var(--navy); line-height: 0; }
.rail-item__title {
  margin: 0 0 6px;
  color: var(--navy);
  font-size: var(--fs-small);
  font-weight: 800;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.rail-item__body p { margin: 0; font-size: var(--fs-body); }
.rail-item__body a { color: var(--pink-text); font-weight: 700; }
.rail-hours {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 4px;
  color: var(--graphite);
  font-size: var(--fs-small);
}
.rail-hours strong { display: block; color: var(--navy); font-weight: 700; }

/* ---- TrustPilot rating --------------------------------------------------- */

.trustpilot {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  justify-content: center;
  margin-top: 18px;
  padding: 10px 18px;
  border: 1.5px solid var(--line);
  border-radius: var(--radius);
  background: var(--white);
  color: var(--ink);
  font-size: 0.88rem;
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.trustpilot:hover {
  text-decoration: none;
  border-color: var(--teal);
  box-shadow: var(--shadow-card-sm);
}
.trustpilot__stars { display: inline-flex; gap: 3px; }
/* TrustPilot's own brand green, so the badge reads as authentic. */
.trustpilot__stars svg { width: 20px; height: 20px; fill: var(--trustpilot-green); }
.trustpilot__text strong { color: var(--navy); font-weight: 700; }

/* ==========================================================================
   TESTIMONIAL WATERFALL

   Replaces the click-through testimonial carousel. Intro copy on the left, two
   columns of quotes to its right scrolling continuously in opposite directions,
   which stop when the pointer lands on them or anything inside takes focus.

   Two structural notes, both load-bearing:

   1. The gap between cards is a margin-bottom on each card, NOT `gap` on the
      track. The loop works by translating the (doubled) track by exactly -50%,
      and 50% of a gapped track is one set plus half a gap, so a gapped version
      jumps by half a gap on every cycle. Giving every card its own trailing
      margin makes each card's slot uniform and -50% land exactly on the start
      of the second set.

   2. The animation only runs once JS has added .is-live, which it does after
      cloning each track. Animating an uncloned track would scroll the cards
      off and leave the column empty for half the cycle, so with JS off the
      columns are simply two static lists. static/js/waterfall.js also skips
      the whole thing under prefers-reduced-motion, for the same reason: the
      global reduce rule in tokens.css kills the animation but would leave the
      duplicated cards behind if they had already been cloned.
   ========================================================================== */

/* The split favours the quote columns rather than the intro. The intro is an
   eyebrow, a short heading, two sentences and the Trustpilot badge, all of
   which sit comfortably in the smaller share; the quotes are the thing people
   actually stop to read, so the width goes to them. Both tracks stay inside
   the site's --container, so this band's edges still line up with the nav,
   the hero and every other section. */
.wf {
  display: grid;
  grid-template-columns: 0.72fr 1.28fr;
  gap: clamp(32px, 4vw, 64px);
  align-items: center;
}
/* Columns on the left, copy on the right. Only /about's awards band uses this,
   so that adopting the waterfall did not also swap the two halves of a band
   people already know. Source order is unchanged, so the copy is still read
   after the heading it belongs to. */
.wf--reverse { grid-template-columns: 1.28fr 0.72fr; }
.wf--reverse .wf__intro { order: 2; }
.wf--reverse .wf__cols { order: 1; }

.wf__intro { max-width: 46ch; }
.wf__intro h2 { margin-bottom: 0.35em; }
.wf__intro p { font-size: var(--fs-body-lg); line-height: 1.7; }

.wf__cols {
  --wf-gap: clamp(16px, 1.6vw, 22px);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--wf-gap);
  /* The band's height is set here rather than by the content, because the
     content is an infinite loop and has no natural height. */
  height: clamp(440px, 56vh, 600px);
  overflow: hidden;
  /* Fade both ends so cards dissolve rather than being guillotined by the
     band edge. This is what makes it read as a waterfall and not a clipped box. */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 8%, #000 92%, transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0, #000 8%, #000 92%, transparent 100%);
}

.wf__col { overflow: hidden; }

.wf__track {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  gap: 0;               /* see note 1 above */
  margin: 0;
  padding: 0;
  list-style: none;
}

/* --wf-dur is written per column by waterfall.js from the measured track
   height, so both columns move at the same pixels-per-second regardless of how
   much copy each one holds. */
.wf__col.is-live .wf__track {
  animation: wf-up var(--wf-dur, 44s) linear infinite;
  will-change: transform;
}
.wf__col--down.is-live .wf__track { animation-name: wf-down; }

/* Pausing is on the wrapper, so hovering either column stops both. Stopping
   only the hovered one reads as a glitch rather than as a deliberate pause. */
.wf__cols.is-paused .wf__track { animation-play-state: paused; }

@keyframes wf-up {
  from { transform: translateY(0); }
  to   { transform: translateY(-50%); }
}
@keyframes wf-down {
  from { transform: translateY(-50%); }
  to   { transform: translateY(0); }
}

.wf-card {
  flex: 0 0 auto;
  margin-bottom: var(--wf-gap);
  padding: clamp(20px, 2vw, 26px);
  background: var(--white);
  border: 1.5px solid var(--line);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card-sm);
  transition: box-shadow var(--t-base) var(--ease),
              border-color var(--t-base) var(--ease);
}
.wf-card:hover { box-shadow: var(--shadow-card); border-color: var(--border-dark); }

.wf-card blockquote { margin: 0; }
/* The design's arctic quote glyph, per card rather than the single oversized
   masked pair the carousel used. */
.wf-card blockquote::before {
  content: '\201C';
  display: block;
  margin-bottom: 6px;
  color: var(--arctic);
  font-size: 2.6rem;
  font-weight: 900;
  line-height: 0.62;
}
/* Quote copy sits at full body size, not the --fs-small used by dense cards
   elsewhere. These cards hold running prose that people read start to finish,
   and there are only five of them, so there is no density argument for
   shrinking it. The wider card absorbs the larger type: the measure comes out
   a touch longer than before, so the cards do not get taller and the band's
   fixed height still holds. */
.wf-card p {
  margin: 0;
  color: var(--graphite);
  font-size: var(--fs-body);
  line-height: 1.62;
}
.wf-card footer {
  display: block;
  margin-top: 16px;
  color: var(--pink-text);
  /* A step above --fs-eyebrow. At the eyebrow size the attribution read as an
     afterthought next to the now-larger quote; this keeps the two in
     proportion while staying clearly subordinate. */
  font-size: 0.78rem;
  font-weight: 900;
  font-style: normal;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

/* On the navy bands the cards stay white surfaces, so their copy has to be
   re-asserted against the band's white text colour. Four pages carry this band
   on --section--deep (it used to be pink or turquoise on those), and without
   this the quotes come out white on white. */
.section--navy .wf-card p,
.section--deep .wf-card p { color: var(--graphite); }

/* ---- Logo tiles in the waterfall ---------------------------------------- */

/* /about runs its awards and its partners bands through the same waterfall as
   the testimonials, with a logo per card instead of a quote. Two differences
   from .wf-card, both because a logo has no natural height:

     - min-height, so a wordmark 30px tall and an award badge 170px tall occupy
       the same slot and the column reads as an even stack.
     - a shorter band, since there is nothing to read as it passes.

   Short tiles are also why waterfall.js pads a set that does not fill its
   column; see the note there. */
.wf__cols--logos { height: clamp(340px, 44vh, 480px); }

.wf-logo {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  margin-bottom: var(--wf-gap);
  padding: clamp(14px, 1.6vw, 22px);
  min-height: clamp(92px, 10vw, 124px);
  background: var(--white);
  border: 1.5px solid var(--line);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card-sm);
  transition: box-shadow var(--t-base) var(--ease),
              border-color var(--t-base) var(--ease);
}
.wf-logo:hover { box-shadow: var(--shadow-card); border-color: var(--border-dark); }
.wf-logo img {
  display: block;
  width: auto;
  max-width: 100%;
  max-height: clamp(48px, 5.4vw, 68px);
  object-fit: contain;
}

/* The partners strip was greyscaled at 65% and came to full colour on hover.
   Kept, so nine supplier marks stay quiet while they pass: without it the band
   is nine competing colour schemes moving at once. The pause on hover is what
   makes the reveal reachable. */
.wf-logo--muted img {
  filter: grayscale(1);
  opacity: 0.7;
  transition: filter var(--t-base) var(--ease), opacity var(--t-base) var(--ease);
}
.wf-logo--muted:hover img { filter: none; opacity: 1; }

@media (max-width: 980px) {
  .wf, .wf--reverse { grid-template-columns: 1fr; gap: clamp(28px, 4vw, 40px); }
  /* Stacked, the copy leads. The reverse layout is a two-column arrangement
     only; there is no reason to put a logo band above the heading that names it. */
  .wf--reverse .wf__intro { order: 1; }
  .wf--reverse .wf__cols { order: 2; }
  .wf__intro { max-width: none; }
}

/* One column below this width: two side-by-side columns of quotes leave each
   card about 150px wide, which no amount of type scaling rescues. waterfall.js
   moves the second column's cards into the first at the same breakpoint, so a
   single column still carries all five quotes. */
@media (max-width: 700px) {
  .wf__cols { grid-template-columns: 1fr; height: clamp(400px, 70vh, 520px); }
  .wf__cols--logos { height: clamp(300px, 52vh, 400px); }
  .wf__col--down { display: none; }
}

/* waterfall.js returns before it clones or measures anything under a reduced-
   motion preference, so the columns are plain static lists. The band's fixed
   height exists only to give an infinite loop somewhere to run, and against a
   static list it just clips whatever does not fit: the tail of each column
   vanishes with no scroll and no animation to bring it back. So the band grows
   to its content instead, and the end fades go with it, since there is no longer
   an edge for cards to dissolve into. Both /about logo bands need this more than
   the quotes do, a column of five tiles being about twice the band height. */
@media (prefers-reduced-motion: reduce) {
  .wf__cols {
    height: auto;
    -webkit-mask-image: none;
    mask-image: none;
  }
}

/* ---- Pricing table ------------------------------------------------------- *
   Product types down the side, the three annual-volume bands across the top,
   one bundled per-piece rate per cell. The scroll wrapper is a keyboard-
   focusable fallback; at <=640px the table reflows to stacked cards so the
   page never scrolls sideways on mobile. */
.pricing-table__scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  border-radius: var(--radius-card);
}
.pricing-table {
  width: 100%;
  border-collapse: collapse;
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  overflow: hidden;
  font-size: 1.02rem;
}
.pricing-table th,
.pricing-table td {
  padding: var(--space-md) var(--space-lg);
  text-align: left;
  border-bottom: 1px solid var(--line);
}
.pricing-table thead th {
  background: var(--navy);
  color: var(--white);
  font-weight: 700;
  line-height: 1.25;
  vertical-align: bottom;
}
.pricing-table thead th:not(:first-child) {
  text-align: right;
}
.pricing-table__band {
  display: block;
  font-weight: 500;
  font-size: 0.8rem;
  opacity: 0.82;
  margin-top: 2px;
}
.pricing-table tbody th[scope="row"] {
  font-weight: 600;
  color: var(--navy);
  background: var(--bg-soft);
  white-space: nowrap;
}
.pricing-table tbody td {
  text-align: right;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
.pricing-table tbody tr:last-child th,
.pricing-table tbody tr:last-child td {
  border-bottom: 0;
}
/* Paper/stock column: text, not a rate, so left-align and mute it rather than
   inheriting the right-aligned tabular-nums styling of the rate cells. */
.pricing-table thead th.pricing-table__paper,
.pricing-table tbody td.pricing-table__paper {
  text-align: left;
  color: var(--muted-text);
  font-weight: 500;
  font-size: 0.9rem;
  white-space: nowrap;
  font-variant-numeric: normal;
}
/* Header sits on the navy band, so keep it white like the other column
   headers; only the body stock names below stay muted. */
.pricing-table thead th.pricing-table__paper {
  color: var(--white);
}
.pricing-table__note {
  margin: var(--space-lg) auto 0;
  max-width: 46em;
  color: var(--muted-text);
  font-size: 0.92rem;
}
/* Change 7: footnote as four scannable lines instead of one paragraph of fine
   print, at a smaller size so each disclosure reads on its own. */
.pricing-table__note--list {
  list-style: none;
  padding: 0;
  max-width: 52em;
  text-align: center;
  font-size: 0.82rem;
  line-height: 1.5;
}
.pricing-table__note--list li + li { margin-top: 0.4em; }
/* Design 5: surface the "sample formats" disclosure with a link straight under
   the table, rather than burying the "30+ products" fact in fine print. */
.pricing-table__seeall {
  margin: var(--space-lg) auto 0;
  text-align: center;
  font-size: 0.95rem;
  font-weight: 700;
}
/* A la carte price. Big, pink and tabular so the number leads the card, using
   the accessible pink text token rather than raw brand pink. Selector matches
   `.card p.price` so it outranks base.css's `.card:not(.card--solid) p` colour
   and `.card p` size rules (equal specificity, but components.css loads last). */
.card p.price {
  font-size: clamp(2rem, 3.4vw, 2.6rem);
  font-weight: 800;
  line-height: 1;
  color: var(--pink-text);
  font-variant-numeric: tabular-nums;
  margin-bottom: 12px;
}

@media (max-width: 640px) {
  /* Reflow to one card per product row; the cell's data-label supplies the
     band name so the header row can be hidden without losing meaning. */
  .pricing-table,
  .pricing-table thead,
  .pricing-table tbody,
  .pricing-table tr,
  .pricing-table th,
  .pricing-table td {
    display: block;
  }
  .pricing-table thead {
    position: absolute;
    width: 1px; height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
  }
  .pricing-table tr {
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    margin-bottom: var(--space-md);
    overflow: hidden;
  }
  .pricing-table tbody th[scope="row"] {
    white-space: normal;
    font-size: 1.05rem;
    border-bottom: 1px solid var(--line);
  }
  .pricing-table tbody td {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--space-lg);
    text-align: right;
  }
  .pricing-table tbody td::before {
    content: attr(data-label);
    font-weight: 600;
    color: var(--muted-text);
    text-align: left;
  }
}

/* ==========================================================================
   P.S. PUPPIES grid (/careers)
   The copy spans two photo-widths; five office-dog photos balance as three
   across the top row beside the copy and two centred beneath. Ten equal tracks
   let a photo span 2 (one fifth) and the copy span 4 (two fifths); the second
   row's first photo starts at column 4 so the pair sits centred in the grid.
   Collapses to a two-up gallery on phones so the photos stay large enough.
   ========================================================================== */
.puppies { grid-template-columns: repeat(10, 1fr); gap: clamp(12px, 1.4vw, 18px); }
/* Span both photo rows and centre, so the copy sits vertically centred against
   the full 3-over-2 photo group rather than only the top row. */
.puppies__copy { grid-column: span 4; grid-row: span 2; align-self: center; }
.puppies__photo {
  grid-column: span 2;
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border-radius: var(--radius);
}
/* First photo of the second row: the three top photos sit in columns 5-10, so
   starting the pair at column 6 centres the two beneath that trio for a clean
   3-over-2 pyramid (rather than under the copy block on the left). */
.puppies__photo--wrap { grid-column: 6 / span 2; }

@media (max-width: 768px) {
  .puppies { grid-template-columns: repeat(2, 1fr); }
  .puppies__copy { grid-column: 1 / -1; grid-row: auto; }
  .puppies__photo,
  .puppies__photo--wrap { grid-column: auto; }
}
