/* RunnerTag one-pager. base.css supplies the frame (.wrap), the grid helper
   (.cols → min-width:0 children), buttons, and the .section-light token flip.
   Everything here is page-specific.

   Palette note: no RunnerTag red. The mark runs all-white on dark and
   all-black on .section-light; accents resolve through --accent, which
   base.css flips from electric green to field green inside .section-light. */

/* Sections carry vertical rhythm only — the horizontal gutter is on .wrap. */
.rt-hero,
.rt-sponsor,
.rt-feat,
.rt-integrations,
.rt-products,
.rt-close { padding: 14vh 0; }

.rt-h2  { font-size: clamp(30px, 3.8vw, 54px); max-width: 20ch; }
.rt-sub { margin-top: 18px; max-width: 60ch; color: var(--dim); font-size: 17px; line-height: 1.6; }

/* ---- Hero ------------------------------------------------------------- */
/* 12vh, not 22vh, and the photo column is the narrower of the two. At 1fr 1fr
   with 22vh above, the frame came out 756px tall and the hero 1080 — so the
   bottom of the photo and the event mark sat below the fold on a laptop. The
   image column at .85fr gives a 643px frame and an ~877px hero, which clears a
   900px viewport. Narrowing the column rather than re-cutting the photo keeps
   the hex coordinates locked to the file (see the note in runnertag.html). */
.rt-hero { padding-top: 12vh; }
.rt-hero-split {
  grid-template-columns: 1.15fr .85fr;
  gap: clamp(40px, 6vw, 88px);
  align-items: center;
}

/* Photo frame. aspect-ratio MUST match the image file (941×1176 = 4/5) — the
   hex overlay's viewBox is in the image's own pixel space, so any mismatch
   makes object-fit crop the photo while the hexes stay put, and the tags slide
   off their targets. Re-cut the image if this needs to change. */
.rt-shot {
  position: relative;
  aspect-ratio: 4 / 5;
  border-radius: 10px;
  overflow: hidden;
  background: var(--bg-2);
}
.rt-shot-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.rt-shot-hexes {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  overflow: visible;
}
/* non-scaling-stroke keeps the weight identical at every breakpoint, matching
   .iq-hex-stroke rather than thinning out as the frame shrinks. */
.rt-hex-tag {
  fill: none;
  stroke: #B6F500;
  stroke-width: 3;
  stroke-linejoin: round;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}
.rt-hex-tag--faint { stroke: rgba(182, 245, 0, .45); stroke-width: 2; }

/* Tag labels. Positioned in % of the frame, which is safe only because the
   frame and file share an aspect ratio (see above). Both sit to the left of
   their hex — the hexes are hard right in the frame, so a label on the right
   would run off the edge. */
.rt-shot-tag {
  position: absolute;
  z-index: 3;
  padding: 5px 9px;
  border-radius: 4px;
  background: rgba(5, 6, 7, .82);
  color: #B6F500;
  font-size: 10px;
  white-space: nowrap;
}
/* Each `right` is set from its hex's measured left edge — face hex starts at
   59.7% of the frame and centres 21.9% down, bib hex starts at 60.5% — leaving
   a few percent for the leader line. Pushed further left they get clipped by
   the frame's overflow:hidden, which is what happened at right:82%. */
.rt-shot-tag--face { top: 20%; right: 45%; }
.rt-shot-tag--bib  { top: 51.5%; right: 44%; }
/* Leader line from label to hex, so each label reads as attached to its tag
   rather than floating. */
.rt-shot-tag::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 100%;
  width: 14px;
  height: 1px;
  background: rgba(182, 245, 0, .55);
}

.rt-shot-event {
  position: absolute;
  z-index: 3;
  left: 5%;
  bottom: 4.5%;
  display: block;
  padding: 8px 12px;
  border-radius: 5px;
  background: rgba(255, 255, 255, .92);
}
.rt-shot-event img { display: block; width: clamp(100px, 11vw, 148px); height: auto; }
.rt-hero-logo { width: clamp(220px, 26vw, 380px); height: auto; display: block; }
.rt-eyebrow { display: block; margin-top: 28px; }
.rt-h1 {
  margin-top: 18px;
  font-size: clamp(42px, 6.4vw, 96px);
  line-height: .98;
  max-width: 17ch;
}
.rt-lead {
  margin-top: 26px;
  max-width: 54ch;
  color: var(--dim);
  font-size: 18px;
  line-height: 1.55;
}
.rt-cta-row { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 38px; }

/* ---- Hero entrance ------------------------------------------------------
   Ported from the Solutions pages so this hero opens the same way theirs do:
   each element wipes in left-to-right, and the headline's words rise on top
   of its own wipe. Runs on load, not on scroll — the hero is already in view.

   Only the RIGHT edge animates. The other three sit at a negative inset so
   the settled state leaves room for glyph overshoot: Oswald's ink box is
   taller than its line box and .rt-h1 sits at line-height .98, so a settled
   `inset(0 0 0 0)` would clip the caps. In `em` so it scales with the clamped
   hero sizes. clip-path cannot transition to `none`, hence the inset. */
@keyframes rtHeroIn {
  from { clip-path: inset(-0.4em 100% -0.4em -0.4em); transform: translateX(-18px); }
  to   { clip-path: inset(-0.4em);                    transform: translateX(0); }
}
@keyframes rtHeroWordRise {
  from { opacity: 0; transform: translateY(0.5em); }
  to   { opacity: 1; transform: none; }
}
/* The headline's two halves are their own lines — the parallel construction
   depends on the break, so it is structural here rather than a <br>. */
.rt-h1-line { display: block; }

.rt-hero-logo,
.rt-eyebrow,
.rt-h1-line,
.rt-lead,
.rt-cta-row {
  animation: rtHeroIn .7s cubic-bezier(.16,1,.3,1) both;
}
.rt-hero-logo                { animation-delay: .15s; }
.rt-eyebrow                  { animation-delay: .28s; }
.rt-h1-line:nth-child(1)     { animation-delay: .40s; }
.rt-h1-line:nth-child(2)     { animation-delay: .52s; }
.rt-lead                     { animation-delay: .80s; }
.rt-cta-row                  { animation-delay: .94s; }

/* Word rise layered over the line wipe; each line's words start at that
   line's own delay. js/runnertag.js builds the .hw spans and their --i. */
.rt-h1-line .hw {
  display: inline-block;
  animation: rtHeroWordRise .6s cubic-bezier(.16,1,.3,1) both;
}
.rt-h1-line:nth-child(1) .hw { animation-delay: calc(.40s + var(--i) * 70ms); }
.rt-h1-line:nth-child(2) .hw { animation-delay: calc(.52s + var(--i) * 70ms); }

/* The photo prints in behind the copy, with a lit edge tracking the reveal.
   Applied to the whole figure, not just the img, so the hex tags and the
   event plate arrive with the frame rather than floating over a blank box. */
@keyframes rtHeroPrint {
  from { clip-path: inset(0 100% 0 0); }
  to   { clip-path: inset(0 0 0 0); }
}
@keyframes rtHeroPrintBar {
  0%   { left: 0;   opacity: 0; }
  10%  { opacity: .55; }
  90%  { opacity: .55; }
  100% { left: 100%; opacity: 0; }
}
.rt-shot { animation: rtHeroPrint 1.5s cubic-bezier(.45,0,.12,1) .5s both; }
.rt-shot::after {
  content: "";
  position: absolute; top: 0; bottom: 0; left: 0;
  width: 1px;
  background: var(--accent);
  box-shadow: 0 0 7px 0 rgba(182,245,0,.35);
  opacity: 0;
  pointer-events: none;
  z-index: 3;
  animation: rtHeroPrintBar 1.5s cubic-bezier(.45,0,.12,1) .5s both;
}

/* ---- How it works -------------------------------------------------------
   Its own dark section between the cream proof band and the cream features
   grid, which is what gives the page dark/light alternation the whole way
   down. Steps themselves are styled further down with .rt-step*. */
.rt-how { padding: 14vh 0; }
.rt-how .rt-steps { margin-top: 52px; }

/* ---- Credit model ------------------------------------------------------
   A strip at the foot of How it works, not a pricing section of its own —
   Evan asked for mechanics only for launch, with the Competitor / Elite /
   Enterprise tiers following later this year. Sits on the dark ground, so it
   inherits --hair and --dim from the root tokens rather than .section-light. */
.rt-pricing {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(28px, 4vw, 64px);
  margin-top: clamp(48px, 6vw, 72px);
  padding-top: clamp(28px, 3vw, 40px);
  border-top: 1px solid var(--hair);
}
.rt-pricing > * { min-width: 0; }
.rt-pricing-item p {
  margin-top: 12px;
  max-width: 46ch;
  color: var(--dim);
  font-size: 17px;
  line-height: 1.55;
}
.rt-pricing-item strong { color: var(--text); font-weight: 600; }
.rt-pricing-link {
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px solid rgba(182, 245, 0, .35);
  transition: border-color .28s var(--ease);
}
.rt-pricing-link:hover { border-bottom-color: var(--accent); }
/* Plain link, so it needs its own ring — base.css only covers .btn. */
.rt-pricing-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* ---- Event ticker ------------------------------------------------------
   A band rather than a section: proof should be quiet and quick here, so the
   padding is a fraction of a normal section's 14vh and there's no display
   headline above it — just a mono label and the marks. It runs straight into
   Features below, which is also .section-light, so the two read as one cream
   stretch with the logos at the top of it. */
.rt-proof { padding: 7vh 0 5vh; }
.rt-proof .mono { color: var(--dim); }

/* Full-bleed: this block sits outside .wrap on purpose. margin-top is 28px,
   not the 56 it carried under a display headline — it now hangs off a single
   mono label and needs to sit close to it. */
.rt-ticker { margin-top: 28px; overflow: hidden; position: relative; }
.rt-ticker::before,
.rt-ticker::after {
  content: "";
  position: absolute;
  top: 0; bottom: 0;
  width: 14vw;
  z-index: 2;
  pointer-events: none;
}
.rt-ticker::before { left: 0;  background: linear-gradient(to right, var(--bg), transparent); }
.rt-ticker::after  { right: 0; background: linear-gradient(to left,  var(--bg), transparent); }

.rt-ticker-row {
  display: flex;
  align-items: center;
  width: max-content;
  animation: rt-marquee 64s linear infinite;
}
.rt-ticker-row:hover { animation-play-state: paused; }
@keyframes rt-marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }

.rt-mark {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 clamp(24px, 3.5vw, 56px);
}
/* Third-party marks: never recolored, only scaled. Height-capped so wide and
   square logos land on the same optical weight.
   Left in full color on purpose — this row is the proof, and these are
   recognizable consumer race brands. The site's usual gray→color hover
   (see .sol-img) desaturates them into mush and pushes the already-weak
   Dubai Run mark past invisible. */
.rt-mark img {
  height: clamp(56px, 7vw, 88px);
  width: auto;
  max-width: none;          /* overrides the global img rule; the cap is height */
  object-fit: contain;
  opacity: .88;
  transition: opacity .3s var(--ease), transform .3s var(--ease);
}
.rt-mark img:hover { opacity: 1; transform: scale(1.04); }

/* ---- Sponsor value ------------------------------------------------------
   Copy column left, four boxes as a 2×2 on the right. The headline runs to
   three lines at desktop, so a square block of cards balances it better than
   the full-width row of four this replaced. */
.rt-sponsor-split {
  grid-template-columns: 1fr 1fr;
  gap: clamp(40px, 6vw, 96px);
  align-items: center;
}
/* ---- Integrations ------------------------------------------------------
   Copy left, partner marks right in two labelled groups. On .section-light
   because most of these logos are dark ink; njuko is the exception and needs a
   dark-ink file (noted in the markup).

   Marks are height-capped and never recolored — same rule as the event ticker.
   Grayscale is deliberately not used: these are partner brands and the whole
   point is that they're recognizable. */
/* Copy left, illustration right. The art is 1408x736, so in a half column it
   renders about 600x314 — which puts each partner mark near 85px wide, the same
   scale as the clamp(60px, 6.2vw, 88px) the old phone layout used. */
.rt-integrations-split {
  grid-template-columns: 1fr 1fr;
  gap: clamp(40px, 6vw, 96px);
  align-items: center;
}

/* --- Stage -------------------------------------------------------------
   One fixed-aspect box. The route SVG's viewBox (700x520) matches this box's
   aspect, and the logos are positioned inside it, so the whole illustration
   scales as a single unit — the same approach as the hero hex overlay. Let
   these reflow independently and the routes drift off their logos. */
.rt-stage {
  position: relative;
  aspect-ratio: 1408 / 736;
  overflow: hidden;       /* this is what crops the phone */
}
.rt-integration-art {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 1;
}
/* Endpoint dots, the three bib nodes and the band labels. All tokens: --accent
   is field green inside .section-light, and the node ring is the section's own
   ground so a connector passing beneath a node reads as passing behind it. */
.rt-route-dots circle { fill: var(--accent); opacity: .55; }
.rt-route-nodes .node-fill { fill: var(--accent); }
.rt-route-nodes .node-ring { fill: none; stroke: var(--bg); stroke-width: 2; }
/* Sized in user units, so these scale with the viewBox. The art renders at
   about 0.43 in a half column, so 28 lands near 12px — matching the small mono
   labels elsewhere on the page. At 17 it came out 7.3px, which was unreadable. */
.rt-int-labels text {
  font-family: var(--condensed);
  font-size: 28px;
  letter-spacing: 3px;
  fill: var(--dim);
}
/* The accessible / small-screen list of the same eight marks. Hidden while the
   art is showing, which is why the art carries a <title>. */
.rt-partners { display: none; }
.rt-route-g path {
  fill: none;
  stroke: var(--accent);
  stroke-width: 1.25;
  opacity: .5;
  vector-effect: non-scaling-stroke;
}



.rt-partner-group .mono { color: var(--dim); }
.rt-partner-row {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: clamp(12px, 1.6vw, 20px);
  margin-top: 14px;
}
.rt-partner-row li {
  display: flex;
  align-items: center;
  width: clamp(60px, 6.2vw, 88px);
  height: clamp(24px, 2.4vw, 32px);
}
.rt-partner-row img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
  opacity: .9;
  transition: opacity .3s var(--ease);
}
.rt-partner-row img:hover { opacity: 1; }

/* Numbered claims. Reuses the outlined drop-cap from the How it works steps
   (originally .seq-numeral on platform.html) rather than bordered cards —
   three short claims with no body copy made the cards the plainest block on
   the page. Hairlines carry the rhythm here, so unlike .rt-step-num these drop
   the accent dash: three stacked dashes fought with the rules. */
.rt-claims { list-style: none; }
.rt-claim {
  display: grid;
  grid-template-columns: max-content 1fr;
  column-gap: clamp(18px, 2vw, 28px);
  align-items: center;
  padding: clamp(20px, 2.4vw, 30px) 0;
  border-top: 1px solid var(--hair);
}
.rt-claim:last-child { border-bottom: 1px solid var(--hair); }
.rt-claim-num {
  font-family: 'Oswald', sans-serif;
  font-weight: 600;
  font-size: clamp(34px, 3.2vw, 50px);
  line-height: .84;
  letter-spacing: -.022em;
  color: transparent;
  /* Static accent — see .rt-step-num. */
  -webkit-text-stroke: 1px var(--accent);
          text-stroke: 1px var(--accent);
  user-select: none;
}
.rt-claim p {
  min-width: 0;
  font-family: var(--condensed);
  font-weight: 500;
  font-size: 20px;
  line-height: 1.28;
  color: var(--text);
}

/* ---- Dashboard features ----------------------------------------------- */
.rt-feature-list { margin-top: 32px; list-style: none; }
.rt-feature-list li {
  position: relative;
  padding: 16px 0 16px 30px;
  border-top: 1px solid var(--hair);
  color: var(--dim);
  font-size: 17px;
  line-height: 1.5;
}
.rt-feature-list li:last-child { border-bottom: 1px solid var(--hair); }
/* Flat-top hex bullet — the brand's container language, at list scale. */
.rt-feature-list li::before {
  content: "";
  position: absolute;
  left: 0; top: 23px;
  width: 12px; height: 11px;
  background: var(--accent);
  clip-path: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%);
}

/* ---- Hex icon tile -----------------------------------------------------
   The brand's container language is the flat-top hexagon, so the riff's
   rounded-square icon tile resolves to this. Filled --accent with a near-black
   glyph, which is the same contrast pairing .btn-primary uses (6.5:1 on field
   green) rather than white-on-green, which fails. --accent flips electric →
   field green inside .section-light, so the tile follows its section. */
.rt-sprite { position: absolute; width: 0; height: 0; overflow: hidden; }

/* One variable drives the tile: its own width, its height (via the regular
   flat-top hexagon ratio 2/√3), the glyph inside it, and the width of the grid
   column it sits in on the cards below. Resizing the hex at a breakpoint is a
   single value, and the column can never disagree with the shape. */
.rt-fcard { --hex-w: 46px; --head-col: var(--hex-w); }
/* Steps lead with an outlined numeral instead of a hex, so their head column
   is sized by the glyph. max-content rather than auto: no clip-path to distort
   here, but an auto track can still shrink a two-digit numeral into a wrap. */
.rt-step { --head-col: max-content; }

.rt-hex {
  display: grid;
  place-items: center;
  width: var(--hex-w, 46px);
  height: calc(var(--hex-w, 46px) / 1.1547);
  background: var(--accent);
  clip-path: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%);
  color: #0F0F0F;
}
.rt-ico {
  width: calc(var(--hex-w, 46px) * .43);
  height: calc(var(--hex-w, 46px) * .43);
  display: block;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.75;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Hex and title share the top row; the description spans both columns beneath.
   The first track is an explicit width rather than `auto` because an auto track
   will shrink below its content under pressure and squash the clip-path out of
   its hexagon ratio — a fixed track won't. min-width:0 on the title lets long
   words wrap instead of forcing the row wider. */
.rt-card-head {
  display: grid;
  grid-template-columns: var(--head-col) 1fr;
  column-gap: 15px;
  align-items: center;
}
.rt-card-head h3 { min-width: 0; margin-top: 0; }

/* ---- Feature cards ----------------------------------------------------- */
.rt-sec-head { max-width: 62ch; }
.rt-fcards {
  margin-top: 56px;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
}
.rt-fcard {
  padding: 30px 26px 34px;
  background: var(--bg-2);
  border: 1px solid var(--hair);
  border-radius: 10px;
  transition: border-color .28s var(--ease), transform .28s var(--ease);
}
.rt-fcard:hover { border-color: var(--accent); transform: translateY(-3px); }
.rt-fcard h3 {
  font-family: var(--condensed);
  font-weight: 500;
  font-size: 21px;
  line-height: 1.25;
  color: var(--text);
}
.rt-fcard p {
  margin-top: 18px;
  color: var(--dim);
  font-size: 16px;
  line-height: 1.5;
}

/* ---- More-from-Greenfly cards ------------------------------------------
   Feature-card chrome (.rt-fcard supplies bg, border, radius and the hover
   lift) with a full-bleed specimen on top, following platform.html's .iq-card.
   The padding moves off the card and onto .rt-pbody so the image can reach the
   card's edges without negative margins fighting the card's own padding.
   overflow:hidden lets the card's border-radius clip the image corners, so the
   image needs no radius of its own. */
.rt-pcard { padding: 0; overflow: hidden; }

/* 1/1 to match the assets (840×840). They are 2:3 masters cropped square on
   export — see _originals/ — so object-fit has nothing left to trim here and
   the framing is whatever the export chose. Change this ratio and cover starts
   cropping: on the video card that eats the caption bar, which is the whole
   point of that image. Re-export from _originals/ instead.

   Square is the floor, not a preference. In the video master the play disc sits
   at rows 506-655 and the caption bar plus logo tile run 1244-1479, so 973 of
   1024 columns-worth of height must survive — a 1.052 aspect. Going wider (4/3
   would allow only 768 rows) means dropping the play button or the caption. If
   the section needs to be shorter than this, the video mockup has to be
   re-composed as a landscape frame; it can't be solved by cropping. */
.rt-pshot {
  position: relative;          /* anchors .rt-pshot-hex */
  aspect-ratio: 1 / 1;
  background: var(--bg-2);
  border-bottom: 1px solid var(--hair);
  overflow: hidden;
}
/* Hex callout layer. The path itself reuses .rt-hex-tag from the hero, so the
   stroke colour and non-scaling weight stay in one place. */
.rt-pshot-hex {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
.rt-pshot img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.rt-pbody { padding: 26px 26px 30px; }

/* ---- How it works ------------------------------------------------------ */
.rt-rule { margin: clamp(48px, 6vw, 78px) 0; border: 0; border-top: 1px solid var(--hair); }
.rt-steps {
  list-style: none;
  grid-template-columns: repeat(4, 1fr);
  gap: clamp(24px, 3vw, 44px);
}
/* Outlined drop-cap numeral, lifted from .seq-numeral on platform.html —
   transparent fill, hairline stroke, small accent dash beneath, stroke warming
   to accent on hover. Scaled well down from the sequence bands' clamp(72px,
   8vw, 132px): those numerals own a full-width band, whereas these sit beside a
   title in a quarter-width column, where 132px would swamp the type. */
.rt-step-num {
  display: block;
  font-family: 'Oswald', sans-serif;
  font-weight: 600;
  font-size: clamp(38px, 3.6vw, 58px);
  line-height: .84;
  letter-spacing: -.022em;
  color: transparent;
  /* Accent, not --hair-strong. Nothing here is interactive, so the old
     gray-to-accent hover was an affordance for an action that doesn't exist —
     and at 1.73:1 the gray outline was too faint to read a number through.
     Electric green is 15.5:1 on this ground. */
  -webkit-text-stroke: 1px var(--accent);
          text-stroke: 1px var(--accent);
  user-select: none;
}
.rt-step-title {
  font-family: var(--condensed);
  font-weight: 500;
  font-size: 19px;
  line-height: 1.2;
  color: var(--text);
}
.rt-step-line { margin-top: 18px; color: var(--dim); font-size: 16px; line-height: 1.5; }

/* ---- Close ------------------------------------------------------------ */
.rt-close { text-align: center; }
.rt-close-logo { width: clamp(180px, 20vw, 280px); height: auto; margin: 0 auto 32px; display: block; }
.rt-close .rt-h2 { margin: 0 auto; max-width: 18ch; }
.rt-close .rt-cta-row { justify-content: center; }

/* ---- Scroll reveal ----------------------------------------------------- */
/* Matched to the four Solutions pages (40px / .8s / .9s), not the 18px / .7s
   this page used to carry. RunnerTag sits in the same nav as those pages and
   the shallower, quicker rise read as a different site.

   Fading the inner .wrap rather than the <section>, which is the fix Jazzy
   made on the Solutions pages in #76. Four of the seven reveal sections here
   are .section-light, and .section-light carries `background: var(--bg)` —
   so opacity on the section faded its cream background too, and a band
   peeking below the fold rendered as a dark gap until the observer fired
   (threshold .08, so up to 8% of a band's height). Measured before the fix:
   a cream band peeking 60px had section-opacity 0.

   .is-in still lands on the <section>, so the [data-anim="combo"] headline
   wipe and word stagger below are unaffected. Every reveal section here has
   a direct .wrap child — checked all seven. */
.reveal > .wrap {
  opacity: 0;
  transform: translateY(40px);
  transition: opacity .8s var(--ease-out), transform .9s cubic-bezier(.16,1,.3,1);
}
.reveal.is-in > .wrap { opacity: 1; transform: none; }

/* Section headline + lede wipe, ported from the Solutions pages so this page
   animates the same way. The headline clips open left-to-right while its words
   rise in sequence; js/runnertag.js wraps each word in <span class="w"> and
   assigns the --i that staggers them.

   Negative inset on the three non-animating edges: a settled `inset(0 0 0 0)`
   shaves the ink of the display headlines and of the .w spans' inline-block
   boxes. The inset is in `em` so it scales with the clamped font sizes. */
[data-anim="combo"] {
  clip-path: inset(-0.4em 100% -0.4em -0.4em);
  transition: clip-path .85s cubic-bezier(.16,1,.3,1);
}
.reveal.is-in [data-anim="combo"] { clip-path: inset(-0.4em); }

[data-anim="combo"] .w {
  display: inline-block;
  opacity: 0;
  transform: translateY(1em);
  transition: opacity .6s var(--ease-out), transform .7s cubic-bezier(.16,1,.3,1);
  transition-delay: calc(var(--i) * 70ms);
  will-change: transform, opacity;
}
.reveal.is-in [data-anim="combo"] .w { opacity: 1; transform: none; }

/* ---- Responsive -------------------------------------------------------- */
@media (max-width: 900px) {
  .rt-hero,
  .rt-how,
  .rt-sponsor,
  .rt-feat,
  .rt-integrations,
  .rt-close { padding: 11vh 0; }
  .rt-hero { padding-top: 17vh; }

  /* Phones stack here rather than at 600: three across a tablet puts each
     mockup near 210px, where the UI inside the screenshot stops being
     legible. Stacked, each one holds its 340px cap and stays readable. */
  .rt-fcards { grid-template-columns: repeat(2, 1fr); }
  .rt-steps  { grid-template-columns: repeat(2, 1fr); }
  /* Eight marks plus eight converging connectors is unreadable at phone width,
     so the art goes and the marks fall back to plain labelled rows. */
  .rt-stage { aspect-ratio: auto; overflow: visible; }
  .rt-integration-art { display: none; }
  .rt-partners {
    display: grid;
    gap: 28px;
  }
  .rt-sponsor-split  { grid-template-columns: 1fr; }
  .rt-pricing        { grid-template-columns: 1fr; }
  .rt-hero-split     { grid-template-columns: 1fr; }
  /* Stacked, a 4/5 frame at full width is enormous, so cap it and center it.
     Centre with justify-self, NOT `margin: 0 auto` — auto inline margins on a
     grid item cancel the default justify-self:stretch, and since every child
     of .rt-shot is absolutely positioned its content width is 0, so the frame
     collapsed to 0×0 and the photo vanished below 900px. width:100% keeps it
     filling the column up to the cap. */
  .rt-shot {
    width: 100%;
    max-width: 420px;
    justify-self: center;
    margin-top: 8px;
  }
  .rt-cards { margin-top: 8px; }   /* was the right column; now stacked below */
}

@media (max-width: 600px) {
  .rt-cards  { grid-template-columns: 1fr; }
  .rt-fcards { grid-template-columns: 1fr; }
  .rt-steps  { grid-template-columns: 1fr; }
  .rt-mark img { height: 52px; }
  .rt-ticker::before,
  .rt-ticker::after { width: 8vw; }

  /* Single column: no vertical rules at all, and only the final cell loses
     its bottom rule. */
}

/* WCAG 2.2.2 Pause, Stop, Hide — hover-pause doesn't help keyboard or
   touch users, so honour the OS setting: stop the marquee and let the
   lane wrap into a static grid. The duplicate lane is hidden so marks
   aren't repeated once they're all visible at once. */
@media (prefers-reduced-motion: reduce) {
  .rt-ticker-row {
    animation: none;
    width: auto;
    flex-wrap: wrap;
    justify-content: center;
    row-gap: 28px;
  }
  .rt-mark[aria-hidden="true"] { display: none; }
  .rt-ticker::before,
  .rt-ticker::after { display: none; }
  .reveal > .wrap { opacity: 1; transform: none; transition: none; }
  /* The combo wipe and its per-word rise, same guard the Solutions pages use.
     js/runnertag.js also adds .is-in immediately under reduced motion, but
     that alone still lets the transition play from its start state — these
     land the end state outright. */
  [data-anim] { opacity: 1 !important; transform: none !important; clip-path: none !important; }
  [data-anim] .w { opacity: 1 !important; transform: none !important; transition: none !important; }
  /* Hero entrance — same treatment the Solutions pages give theirs. */
  .rt-hero-logo, .rt-eyebrow, .rt-h1-line, .rt-lead, .rt-cta-row,
  .rt-h1-line .hw, .rt-shot { animation: none; }
  .rt-shot::after { display: none; }
}
