/* Edvantis Transit landing, on payments.edvantis.com's design system (its tokens, type, glass icons, cards,
   accordions, story bars and form, taken as they are there).
   Order: tokens, base, layout, shared components, page sections (top to bottom), responsive. */

/* ---------- tokens ---------- */
:root {
  --brand: #6244bb; /* transit's own colour, the second of edvantis.com's (payments.edvantis.com is green) */
  --brand-ink: #4b3196;
  --mint: #f1edfc;
  --mint-soft: #f8f6fe;
  --mint-faint: #f6f3fe;
  /* green only where something says yes: a valid ticket, a tap accepted, online, live, sold */
  --ok: #00BF63;
  --ok-ink: #00874A;
  --ok-soft: #E8FFF4;

  --black: #000;
  --ink: #1d1d1d;
  --text: #474747;
  --muted: #565c7c;
  --faint: #9aa1b4;

  --line: #e4e6ee;
  --line-strong: #cdd2df;
  --line-dashed: #d5d9e3;
  --hairline: rgba(0, 0, 0, .08);
  --hairline-strong: rgba(0, 0, 0, .10);

  --ground: #f7f7f7;
  --white: #fff;
  --clutch: #f0643c; /* Clutch review stars and labels, as on edvantis.com */
  --error: #d3294a; /* form errors, declines */
  --warn: #d99a00; /* a reroute: handled, but worth a look */

  --font-display: 'Century Gothic', 'Questrial', sans-serif;
  --font-body: 'Open Sans', Helvetica, Arial, sans-serif;
  --font-mono: 'Geist Mono', ui-monospace, monospace;

  --header-h: 68px;
  --content-w: 1280px;
  --gutter: clamp(20px, 4vw, 32px);
  /* the three areas' grid: 12 columns, --grid-gap apart; --side is the width of the first 4 (see .svc) */
  --grid-gap: 32px;
  --side: calc((100% - 2 * var(--grid-gap)) / 3);
  --section-y: clamp(44px, 5vw, 64px);
  --ease-out: cubic-bezier(.2, .8, .2, 1);
  /* motion: springs sampled from a damped spring, for the pictures. --spring for a shape changing into another (it
     overshoots by 1.5 %), --pop for a small thing arriving (a card at a reader, a tick: 10 %), --settle for content
     coming in (no overshoot), --exit for things going (quick, out of the way of what comes) */
  --spring: linear(0, .069, .221, .396, .562, .701, .81, .89, .945, .98, 1, 1.011, 1.015, 1.015, 1.013, 1.011, 1.008, 1.006, 1.004, 1.002, 1.001, 1.001, 1);
  --pop: linear(0, .089, .29, .524, .738, .906, 1.019, 1.082, 1.106, 1.102, 1.083, 1.058, 1.035, 1.015, 1.001, .993, .989, .989, .99, .993, .996, .998, 1);
  --settle: linear(0, .075, .228, .391, .537, .657, .751, .822, .874, .912, .939, .958, .971, .98, .987, .991, .994, .996, .998, 1);
  --exit: cubic-bezier(.4, 0, 1, 1);
}
/* where linear() easing is not known, the springs fall back to the plain ease out */
@supports not (transition-timing-function: linear(0, 1)) { :root { --spring: var(--ease-out); --pop: var(--ease-out); --settle: var(--ease-out); } }

/* ---------- fonts ---------- */
/* Century Gothic is edvantis.com's licensed web font, loaded from its own server (which allows other sites to use
   it), so Mac and phone visitors see it too, not only Windows machines that happen to have it. Regular for headings
   and big numbers, bold for amounts. Questrial (Google Fonts) stands in until it arrives. */
@font-face {
  font-family: "Century Gothic";
  font-weight: 400;
  font-display: swap;
  src: url("https://www.edvantis.com/wp-content/themes/edvantis/fonts/century/6005230/f511511a-63a8-45a4-8f43-959006da1991.woff2") format("woff2");
}
@font-face {
  font-family: "Century Gothic";
  font-weight: 700;
  font-display: swap;
  src: url("https://www.edvantis.com/wp-content/themes/edvantis/fonts/century/6005276/b12fce6d-1212-4e0a-8d70-d15379749cb9.woff2") format("woff2");
}

/* ---------- base ---------- */
*, *::before, *::after { box-sizing: border-box; }
b, strong { font-weight: 600; } /* semibold, never bold: the page has two weights, 400 and 600 */

html, body {
  margin: 0;
  background: var(--white);
  color: var(--ink);
  font-family: var(--font-body);
  -webkit-font-smoothing: antialiased;
  scroll-behavior: smooth;
}

a { color: var(--brand-ink); text-decoration: none; }
a:hover { color: var(--black); }

button, input, textarea { font-family: inherit; }

img { max-width: 100%; }

/* Safari's tap box over whatever is pressed is not ours: every control shows its own pressed state, and the keyboard
   still gets the focus ring below */
html { -webkit-tap-highlight-color: transparent; }

:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

@media (prefers-reduced-motion: reduce) {
  html, body { scroll-behavior: auto; }
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

/* ---------- layout ---------- */
.site { min-height: 100vh; overflow-x: clip; background: var(--white); }

.container {
  max-width: var(--content-w);
  margin: 0 auto;
  padding: 0 var(--gutter);
}

.section { padding: var(--section-y) 0; scroll-margin-top: var(--header-h); }

/* ---------- shared components ---------- */
.kicker {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 16px;
  font-size: 14px;
  font-weight: 600;
  color: var(--muted);
}

.h2 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(30px, 2.8vw, 40px); /* the hero title (about 50 px on desktops) stays a clear step above */
  line-height: 1.1;
  color: var(--black);
  text-wrap: balance;
}

.text-brand { color: var(--brand); }

.section-lead {
  margin: 0;
  max-width: 640px;
  font-size: 16px;
  line-height: 1.6;
  color: var(--text);
  text-wrap: pretty;
}

.label {
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
}

.tag {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--muted);
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: 5px;
  padding: 3px 8px;
  white-space: nowrap;
}

.badge {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--muted);
  border: 1px solid var(--line-strong);
  border-radius: 99px;
  padding: 3px 10px;
}

/* area number (01-03), optionally with a badge next to it; scales down like .h2 */
.area-num { margin-bottom: 14px; font-family: var(--font-display); font-size: clamp(24px, 2.2vw, 30px); line-height: 1; color: var(--brand); }
.kicker > .area-num { margin: 0; font-size: 16px; font-weight: 400; } /* a block's number and name on one line, one label above its heading */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  height: 52px;
  padding: 0 26px;
  border: 1px solid var(--brand);
  border-radius: 6px;
  font-size: 15px;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition: all .2s ease-in;
}

.btn--primary { background: var(--brand); color: var(--white); }
.btn--primary:hover { background: var(--white); color: var(--brand); }
/* the quieter second action next to a primary one */
.btn--ghost { background: var(--white); border-color: var(--line-strong); color: var(--ink); }
.btn--ghost:hover { border-color: var(--ink); color: var(--black); }

.btn__arrow { display: inline-flex; transition: transform .25s var(--ease-out); }
.btn:hover .btn__arrow--down { transform: translateY(3px); }
.btn:hover .btn__arrow--right { transform: translateX(3px); }

.text-link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  font-weight: 600;
}

.text-link:hover { color: var(--brand); }
.text-link--ink { color: var(--ink); }
.text-link--ink:hover { color: var(--brand-ink); }

/* Accordion ("what we build"): one open item per group, the first one open from the start, so it shows there is more
   inside; the panel animates from 0fr to 1fr (main.js toggles .is-open). Quiet rows under the block's heading
   (.build-title): hairlines across the column, titles a step below the heading, a thin plus. The open item is marked
   the way the pictures mark their current step: a short green line on top and a green title. */
.acc__item { position: relative; border-top: 1px solid var(--line); }
.acc__item:last-child { border-bottom: 1px solid var(--line); }
.acc__item::before {
  content: "";
  position: absolute;
  left: 0;
  top: -1px;
  width: 0;
  height: 2px;
  background: var(--brand);
  transition: width .35s var(--ease-out);
}
.acc__item.is-open::before { width: 48px; }

.acc__btn {
  width: 100%;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 24px;
  padding: 22px 0;
  border: 0;
  background: none;
  cursor: pointer;
  text-align: left;
  font-size: 16px;
  font-weight: 600; /* the type's two weights: 400 for text, 600 for what is named (as the cards' titles) */
  line-height: 1.4;
  letter-spacing: 0;
  color: var(--ink);
  transition: color .2s ease;
}
.is-open > .acc__btn { color: var(--brand-ink); }
@media (hover: hover) { .acc__btn:hover { color: var(--brand-ink); } } /* a tap must not leave a row lit */

.acc__icon {
  display: inline-flex;
  flex: none;
  color: var(--faint);
  transition: transform .25s ease, color .2s;
}
.is-open > .acc__btn .acc__icon { color: var(--brand-ink); }
@media (hover: hover) { .acc__btn:hover .acc__icon { color: var(--brand-ink); } }
.is-open > .acc__btn .acc__icon { transform: rotate(45deg); }

.acc__panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows .3s var(--ease-out);
}

.is-open > .acc__panel { grid-template-rows: 1fr; }
.acc__panel > div { overflow: hidden; }

.acc__body {
  max-width: 680px;
  margin-top: -6px;
  padding: 0 0 24px;
  font-size: 15px;
  line-height: 1.6;
  color: var(--text);
  text-wrap: pretty;
}

/* the heading of each area's "what we build": the page's display face, a step below the area's own heading, so the
   order reads heading, lead, then the rows */
.build-title {
  margin: 0 0 14px;
  font-family: var(--font-display);
  font-size: 28px;
  font-weight: 400;
  line-height: 1.15;
  letter-spacing: -.01em;
  color: var(--black);
  text-wrap: balance;
}

/* Scroll reveal: only hidden when JS runs (html.js), so the page reads fine without it. */
.js .reveal {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity .45s ease var(--reveal-delay, 0s), transform .45s var(--ease-out) var(--reveal-delay, 0s);
}

.js .reveal.is-in { opacity: 1; transform: none; }
.reveal--d1 { --reveal-delay: .1s; }
.reveal--d2 { --reveal-delay: .12s; }

/* ---------- header ---------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgba(255, 255, 255, .88);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--hairline);
}

.site-header__inner {
  max-width: var(--content-w);
  height: var(--header-h);
  margin: 0 auto;
  padding: 0 var(--gutter);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
}

.site-logo, .site-logo:hover { display: flex; align-items: center; gap: 14px; color: var(--ink); }
.site-logo img { display: block; height: 24px; width: auto; }

.site-logo__unit {
  padding-left: 14px;
  border-left: 1px solid var(--line-strong);
  font-size: 14px;
  font-weight: 600;
  color: var(--muted);
}

.site-nav { display: flex; gap: 28px; align-items: center; font-size: 14px; font-weight: 600; }
.site-nav a { color: var(--ink); white-space: nowrap; }
.site-nav a:hover { color: var(--brand-ink); }
.site-nav .site-nav__ext { display: inline-flex; align-items: center; gap: 4px; padding-left: 28px; border-left: 1px solid var(--line); color: var(--muted); font-weight: 500; } /* the way out to edvantis.com, quieter than the page sections */
.site-nav .site-nav__ext:hover { color: var(--brand-ink); }
@media (max-width: 1180px) { .site-nav { gap: 20px; } .site-nav .site-nav__ext { padding-left: 20px; } } /* air between the logo and the sections just above the menu breakpoint */
/* while the menu is in the bar it sits on the page's centre line (between the grid's 6th and 7th columns, where the
   hero splits), whatever the widths of the logo and the button: they get equal sides. Where a side is too narrow
   for the logo and its air (32 px at the narrowest, 48 px on wide screens), that side grows and the menu gives way a
   little, rather than crowd the logo. */
@media (min-width: 1001px) {
  .site-header__inner { display: grid; grid-template-columns: 1fr auto 1fr; column-gap: clamp(24px, 4vw - 8px, 48px); }
  .site-logo { justify-self: start; width: max-content; } /* the link stays the logo's size: not its side's, never squeezed */
  .header-cta { justify-self: end; }
}
/* wide screens: the menu starts where the areas' main column does (after the grid's side of 4 columns: the
   accordions), so the bar lines up with the page under it. Narrower still, the menu would not
   fit after the side and the button, so it stays on the centre line as above */
@media (min-width: 1120px) {
  .site-header__inner { grid-template-columns: var(--side) minmax(0, 1fr) auto; column-gap: var(--grid-gap); }
}

.header-cta {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 42px;
  padding: 0 20px;
  border: 1px solid var(--brand);
  border-radius: 6px;
  color: var(--brand);
  font-size: 14px;
  font-weight: 600;
  white-space: nowrap;
  transition: all .2s ease-in;
}

.header-cta:hover { background: var(--brand); color: var(--white); }

.burger {
  display: none;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  margin-right: -10px;
  border: 0;
  background: none;
  cursor: pointer;
  color: var(--ink);
}

.burger[aria-expanded="true"] .burger__open,
.burger[aria-expanded="false"] .burger__close { display: none; }

/* a full-height sheet under the bar: the sections, then the way out, then the call to action at the bottom */
.mobile-menu {
  position: absolute;
  left: 0;
  right: 0;
  top: 100%;
  height: calc(100dvh - var(--header-h));
  overflow-y: auto;
  overscroll-behavior: contain;
  display: flex;
  flex-direction: column;
  padding: 12px var(--gutter) 28px;
  background: var(--white);
  animation: menuIn .22s ease-out;
}

.mobile-menu[hidden] { display: none; }
html.menu-open { overflow: hidden; } /* the page stays put under the sheet */
html.menu-open .site-header { background: var(--white); } /* one solid sheet with the bar, no page showing through the glass */

@keyframes menuIn { from { opacity: 0; transform: translateY(-6px); } }

.mobile-menu__link {
  display: flex;
  align-items: center;
  padding: 20px 0;
  border-bottom: 1px dashed var(--line);
  font-size: 16px;
  font-weight: 600;
  color: var(--ink);
}

.mobile-menu__link:hover, .mobile-menu__ext:hover { color: var(--brand-ink); }

.mobile-menu__ext {
  display: inline-flex;
  align-self: flex-start;
  align-items: center;
  gap: 5px;
  margin-top: 24px;
  font-size: 14px;
  color: var(--muted);
}

.mobile-menu__cta { margin-top: auto; align-self: center; } /* pinned to the bottom of the sheet */
@media (max-width: 560px) { .mobile-menu__cta { align-self: stretch; } } /* full width under the thumb on phones */

/* ---------- hero ---------- */
.hero {
  position: relative;
  min-height: min(calc(100svh - var(--header-h)), 860px); /* fills the first screen, but on tall screens stops short, so the figures below come into view instead of a band of empty space */
  display: flex;
  flex-direction: column;
  background: var(--white);
  isolation: isolate;
  overflow-x: clip;
}

.hero__field { position: absolute; left: 0; top: 0; z-index: -1; pointer-events: none; }

/* on the page's grid: the same edges as the header and the areas, the copy on 6 columns and the story on the other 6,
   so the split falls on the page's centre line, under the menu (one column below 1075 px) */
.hero__grid {
  flex: 1;
  width: 100%;
  max-width: var(--content-w);
  margin: 16px auto 0;
  padding: 56px var(--gutter) 40px;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 40px var(--grid-gap);
  align-items: center;
}
@media (min-width: 1075px) { .hero__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.hero__eyebrow { display: flex; align-items: center; gap: 10px; margin-bottom: 30px; font-size: 14px; font-weight: 600; color: var(--muted); }

.hero__title {
  margin: 0 0 28px;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(44px, 5vw, 72px);
  line-height: 1.02;
  letter-spacing: -.01em;
  color: var(--black);
  text-wrap: balance;
}

/* two columns: the title takes three lines, its size set by the copy's width (the longest line, "to the AFC
   back-office.", is about 11.4 em); on narrower desktops it stops at 44 px and runs to four. The columns stand a
   little further apart than the page grid, so the title doesn't run into the picture */
@media (min-width: 1075px) {
  .hero__grid { column-gap: 64px; }
  .hero__copy { container-type: inline-size; }
  .hero__title { font-size: clamp(44px, 100cqi / 11.6, 64px); }
}

.hero__eyebrow, .hero__title, .hero__lead { text-shadow: 0 0 2px var(--white), 0 0 6px var(--white), 0 0 14px var(--white), 0 0 24px var(--white); } /* a white halo round the letters: the line map runs on behind, but never touches a word */
.hero__lead { margin: 0 0 40px; max-width: 480px; font-size: 18px; line-height: 1.6; color: var(--text); text-wrap: pretty; }
.hero__actions { display: flex; gap: 14px; flex-wrap: wrap; align-items: center; }
.hero__actions .btn { padding: 0 22px; }
/* where the two buttons only just fit beside the copy, they share the line evenly, and fill it one under the other
   if they wrap, rather than standing at two different widths */
@media (min-width: 1075px) and (max-width: 1180px) { .hero__actions > .btn { flex: 1 1 auto; } } /* two columns, narrow copy */

.hero__visual { min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 18px; } /* min-width: the stage's fixed board must not widen the column; it is zoomed to it */

/* The hero story (main.js plays it): one trip, from the app to the back-office, as two things (A and B) that keep
   changing into the next scene's. The stage is laid out in fixed pixels on a 440 x 380 board and scaled to its
   column with zoom (--hv-k, set by main.js, up to 1.2). Set by main.js on .hv: data-scene (0-3) gives A and B their
   size, corners, colour and place, and they glide there; data-show is the scene whose pictures (.hv__l, data-l) are
   shown, once the shapes have settled; data-p is how far the scene has gone: in, act, ok. The scenes: 0 the
   passenger's app finds the route and sells the day pass; 1 the same phone is tapped at a validator, which accepts
   it; 2 an inspector's phone scans the pass; 3 the AFC back-office, the taps flowing in from the devices and each
   operator settled. No prices: the trip, not the payment. */
.hv { position: relative; width: 100%; max-width: 528px; min-width: 0; --hv-ease: cubic-bezier(.65, 0, .35, 1); }
/* the picture's pause, in its corner: quiet until wanted (main.js shows it when the picture moves) */
.hv__pp { position: absolute; right: 0; bottom: 0; z-index: 5; display: grid; place-items: center; width: 32px; height: 32px; padding: 0; border: 1px solid var(--line); border-radius: 50%; background: rgba(255, 255, 255, .85); color: var(--muted); cursor: pointer; opacity: .55; transition: opacity .2s, color .2s, border-color .2s; }
.hv__pp[hidden] { display: none; }
.hv__pp:hover, .hv__pp:focus-visible { opacity: 1; color: var(--brand-ink); border-color: var(--line-strong); }
.hv__pp svg { grid-area: 1 / 1; width: 14px; height: 14px; }
.hv__pp-p path { fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; }
.hv__pp-g path { fill: currentColor; }
.hv__pp-g, .hv__pp[aria-pressed="true"] .hv__pp-p { display: none; }
.hv__pp[aria-pressed="true"] .hv__pp-g { display: block; }
.hv.is-paused * { animation-play-state: paused !important; }
.hv__fit { width: 100%; }
@media (max-width: 560px) { .hv__fit { width: calc(100% + 2 * var(--gutter)); margin: 0 calc(-1 * var(--gutter)); } } /* on phones the board takes the gutters too: its words a size larger */
.hv__stage { position: relative; width: 440px; height: 380px; zoom: var(--hv-k, 1); }

/* A and B share one look of real devices: a dark outline, a body lit from the top left, and a layered shadow (a
   tight one where it meets the page, a soft one far below) */
.hv__a, .hv__b {
  position: absolute;
  border: 2px solid #1b1e2b;
  background-color: #1b1e2b;
  background-image: linear-gradient(150deg, rgba(255, 255, 255, 0) 40%, rgba(20, 24, 40, .06));
  box-shadow: 0 1px 2px rgba(13, 14, 22, .08), 0 14px 26px -14px rgba(13, 14, 22, .3), 0 44px 70px -34px rgba(13, 14, 22, .4);
  transition-property: left, top, width, height, border-radius, border-width, background-color, border-color, transform, opacity, box-shadow;
  transition-duration: .9s;
  transition-timing-function: var(--spring); /* a shape changing into the next: a spring, settling with a hint of give */
}
/* A: the passenger's phone (the app, then the pass at the validator and for the inspector), then the back-office */
.hv__a { z-index: 1; left: 140px; top: 14px; width: 160px; height: 336px; border-radius: 30px; border-color: #23262f; background-color: var(--white); }
.hv[data-scene="1"] .hv__a { z-index: 3; left: 40px; top: 92px; width: 124px; height: 248px; border-radius: 24px; transform: rotate(-8deg); } /* over the validator when it is held to it */
.hv[data-scene="1"][data-p="act"] .hv__a { transform: translate(184px, 64px) rotate(-14deg); } /* to the reader, and back once it has answered */
.hv[data-scene="2"] .hv__a { left: 52px; top: 62px; width: 134px; height: 268px; border-radius: 26px; transform: rotate(-7deg); }
.hv[data-scene="3"] .hv__a { left: 118px; top: 62px; width: 190px; height: 248px; border-radius: 14px; }
/* B: the validator, which comes in beside the phone; the inspector's phone in its orange work bumper; then that
   phone small beside the back-office */
.hv__b { z-index: 2; left: 250px; top: 44px; width: 174px; height: 270px; border-radius: 18px; border-color: #23262f; background-color: var(--white); opacity: 0; transform: scale(.92); }
.hv[data-scene="1"] .hv__b { opacity: 1; transform: none; box-shadow: inset -9px 0 14px -10px rgba(13, 14, 22, .22), 0 1px 2px rgba(13, 14, 22, .08), 0 14px 26px -14px rgba(13, 14, 22, .3), 0 44px 70px -34px rgba(13, 14, 22, .4); } /* the housing's curve */
.hv[data-scene="2"] .hv__b { opacity: 1; left: 196px; top: 74px; width: 142px; height: 280px; border-radius: 28px; border-width: 4px; border-color: #e8833a; background-color: #23262f; transform: translate(84px, 26px) rotate(14deg); box-shadow: 0 0 0 2px #1b1e2b, 0 14px 26px -14px rgba(13, 14, 22, .3), 0 44px 70px -34px rgba(13, 14, 22, .4); } /* the orange work bumper, in the family's dark outline */
.hv[data-scene="2"]:not([data-p="in"]) .hv__b { transform: rotate(6deg); } /* the inspector brings it up to the ticket */
.hv[data-scene="3"] .hv__b { opacity: 1; left: 31px; top: 239px; width: 32px; height: 58px; border-radius: 8px; border-width: 3px; border-color: #e8833a; background-color: #23262f; transform: none; box-shadow: 0 10px 18px -12px rgba(13, 14, 22, .4); } /* it shrinks down to its small self by the back-office */

/* the pictures: in once the shapes have settled, out before they move */
.hv__l { position: absolute; inset: 0; border-radius: inherit; opacity: 0; visibility: hidden; transform: scale(.97); transition: opacity .18s var(--exit), transform .18s var(--exit), visibility 0s .18s; } /* out quickly, before the shape moves */
.hv[data-show="0"] [data-l~="0"], .hv[data-show="1"] [data-l~="1"], .hv[data-show="2"] [data-l~="2"], .hv[data-show="3"] [data-l~="3"],
.hv[data-scene="1"] .hv__pass, .hv[data-scene="2"] .hv__pass { opacity: 1; visibility: visible; transform: none; transition: opacity .35s var(--settle), transform .5s var(--settle); } /* in softly once the shape has settled; the pass stays on the phone from the validator to the inspector */
.hv__scr { inset: 4px; isolation: isolate; border-radius: 22px; overflow: hidden; background: #f7f8fa; box-shadow: inset 0 0 0 1px rgba(13, 14, 22, .06); }
.hv__scr::after { content: ""; position: absolute; left: 50%; top: 7px; z-index: 5; width: 40px; height: 10px; border-radius: 5px; background: #23262f; transform: translateX(-50%); } /* the camera */
.hv__scr::before { content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none; background: linear-gradient(120deg, rgba(255, 255, 255, .45), rgba(255, 255, 255, 0) 34%); } /* the glass, under what the screen shows */
/* the parts around the back-office, in its scene only */
.hv [data-for] { opacity: 0; visibility: hidden; transition: opacity .3s, visibility 0s .3s; }
.hv[data-show="3"] [data-for="3"] { opacity: 1; visibility: visible; transition: opacity .4s .1s; }

.hv__tick { display: grid; place-items: center; width: 30px; height: 30px; border-radius: 50%; background: var(--ok); }
.hv__vs-ok .hv__tick, .afc__vs > div .afc__tick { transform: scale(.5); transition: transform .5s var(--pop); } /* a tick pops in with its answer */
.hv[data-show="1"][data-p="ok"] .hv__vs-ok .hv__tick, .afc[data-v="ok"] .afc__vs-ok .afc__tick, .afc[data-v="deny"] .afc__vs-deny .afc__tick, .afc[data-v="sync"] .afc__vs-sync .afc__tick { transform: none; }
.hv__tick svg { width: 20px; height: 20px; }
.hv__tick path, .hv__got path { fill: none; stroke: var(--white); stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round; }
.hv__code rect { fill: var(--ink); }

/* 0: the map app: the route draws, the ride's ticket comes up, it is tapped, then bought */
.hv__mapbg { position: absolute; inset: 0; width: 100%; height: 100%; }
.hv__mroute { stroke-dasharray: 280; stroke-dashoffset: 280; transition: stroke-dashoffset 1s var(--hv-ease) .2s; }
.hv[data-show="0"] .hv__mroute { stroke-dashoffset: 0; }
.hv__mbus { opacity: 0; transition: opacity .3s; } /* the bus, along the route */
.hv[data-show="0"] .hv__mbus { opacity: 1; transition-delay: 1s; }
.hv__msearch { position: absolute; left: 10px; right: 10px; top: 26px; display: flex; align-items: center; gap: 8px; height: 28px; padding: 0 10px; border-radius: 14px; background: var(--white); box-shadow: 0 6px 14px -8px rgba(13, 14, 22, .4); font-size: 11px; font-weight: 600; color: var(--ink); }
.hv__msearch i { width: 8px; height: 8px; border-radius: 50%; background: var(--brand); }
.hv__sheet { position: absolute; left: 0; right: 0; bottom: 0; display: flex; flex-direction: column; gap: 10px; padding: 8px 12px 16px; border-radius: 18px 18px 0 0; background: var(--white); box-shadow: 0 -10px 24px -14px rgba(13, 14, 22, .45); transform: translateY(105%); transition: transform .65s var(--spring); }
.hv[data-show="0"]:not([data-p="in"]) .hv__sheet { transform: none; }
.hv__grab { align-self: center; width: 30px; height: 4px; border-radius: 2px; background: #d3d8e1; }
.hv__sride { display: flex; align-items: center; gap: 6px; font-size: 11px; color: var(--ink); }
.hv__sride svg { width: 22px; height: 22px; }
.hv__sride span { margin-left: auto; color: var(--muted); }
/* the ticket: what it is, and under it the button, the width of the card */
.hv__sticket { display: flex; flex-direction: column; gap: 8px; padding: 9px 10px 10px; border: 1.5px solid var(--brand); border-radius: 12px; background: var(--mint-soft); }
.hv__srow { display: flex; flex-direction: column; gap: 1px; }
.hv__sticket b { font-size: 10px; color: var(--ink); }
.hv__sticket span { font-size: 10px; color: var(--muted); white-space: nowrap; }
.hv__sticket em { display: flex; align-items: center; justify-content: center; gap: 4px; height: 26px; border-radius: 8px; background: var(--brand); font-size: 11px; font-style: normal; font-weight: 600; color: var(--white); }
.hv__got { display: none !important; }
.hv__sticket .hv__got { background: var(--ok-soft); color: var(--ok-ink); } /* bought: a status, not a button */
.hv__got path { stroke: var(--ok-ink); }
.hv__got svg { width: 13px; height: 13px; }
.hv[data-show="0"][data-p="ok"] .hv__buy { display: none; }
.hv[data-show="0"][data-p="ok"] .hv__got { display: flex !important; }
/* the passenger's tap on Buy, once the sheet is up */
.hv__touch { position: absolute; left: 59px; bottom: 12px; width: 34px; height: 34px; border: 2px solid rgba(255, 255, 255, .9); border-radius: 50%; background: rgba(98, 68, 187, .35); opacity: 0; transform: scale(.6); pointer-events: none; }
.hv[data-show="0"][data-p="act"] .hv__touch { animation: hvTouch .45s ease-out .9s forwards; }
@keyframes hvTouch { 40% { opacity: 1; transform: scale(1); } 100% { opacity: 0; transform: scale(1.3); } }

/* 1, 2: the pass, on the passenger's phone: held to the validator, then shown to the inspector */
.hv__pass { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; background: var(--white); }
.hv__pass-op { display: flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 600; color: var(--ink); }
.hv__pass-op i { display: grid; place-items: center; width: 20px; height: 20px; border-radius: 6px; background: var(--mint); }
.hv__pass-op svg { width: 16px; height: 16px; }
.hv__pass b { margin-top: 4px; font-family: var(--font-display); font-size: 19px; font-weight: 400; color: var(--black); }
.hv__pass em { font-size: 10px; font-style: normal; color: var(--muted); }
.hv__pass .hv__code { width: 84px; height: 84px; margin: 6px 0 4px; }

/* 1: the validator: a dark glass display, the reader, the QR window */
.hv__led { position: absolute; left: 12px; right: 12px; top: 10px; height: 5px; border-radius: 3px; background: #c3c8d2; transition: background .3s, box-shadow .3s; }
.hv[data-show="1"][data-p="act"] .hv__led { background: #f2c94c; box-shadow: 0 0 8px rgba(242, 201, 76, .8); }
.hv[data-show="1"][data-p="ok"] .hv__led { background: var(--ok); box-shadow: 0 0 8px rgba(0, 191, 99, .8); }
.hv__vs { position: absolute; left: 12px; right: 12px; top: 24px; height: 112px; overflow: hidden; border: 1px solid #0b0c10; border-radius: 14px; background: linear-gradient(160deg, #262a35, #101217); box-shadow: inset 0 1px 0 rgba(255, 255, 255, .08); }
.hv__vs::after { content: ""; position: absolute; inset: 0; background: linear-gradient(120deg, rgba(255, 255, 255, .12), rgba(255, 255, 255, 0) 40%); pointer-events: none; }
.hv__vs > div { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px; text-align: center; transition: opacity .3s; }
.hv__vs-wait { gap: 8px !important; font-size: 12px; font-weight: 600; color: rgba(255, 255, 255, .6); }
.hv__vs-wait svg { width: 22px; height: 22px; }
.hv__vs-wait path { fill: none; stroke: rgba(255, 255, 255, .75); stroke-width: 2; stroke-linecap: round; }
.hv__reader path { fill: none; stroke: #23262f; stroke-width: 2; stroke-linecap: round; }
.hv__vs-ok { opacity: 0; }
.hv__vs-ok .hv__tick { box-shadow: 0 0 16px rgba(0, 191, 99, .6); }
.hv__vs-ok b { margin-top: 4px; font-family: var(--font-display); font-size: 22px; font-weight: 400; line-height: 1; color: var(--white); }
.hv__vs-ok span { font-size: 11px; color: rgba(255, 255, 255, .6); }
.hv[data-show="1"][data-p="ok"] .hv__vs-wait { opacity: 0; }
.hv[data-show="1"][data-p="ok"] .hv__vs-ok { opacity: 1; }
.hv__reader { position: absolute; left: 49px; top: 148px; width: 72px; height: 72px; display: grid; place-items: center; border: 1.5px solid var(--line); border-radius: 50%; background: radial-gradient(circle, #fff 55%, #eef0f4); box-shadow: inset 0 2px 4px rgba(13, 14, 22, .06); transition: border-color .3s; }
.hv__reader svg { width: 26px; height: 26px; }
.hv[data-show="1"][data-p="act"] .hv__reader { border-color: #f2c94c; box-shadow: 0 0 0 4px rgba(242, 201, 76, .35); }
.hv[data-show="1"][data-p="ok"] .hv__reader { border-color: var(--ok); animation: hvRing 1.4s ease-out infinite; }
@keyframes hvRing { 0% { box-shadow: 0 0 0 0 rgba(0, 191, 99, .5); } 100% { box-shadow: 0 0 0 18px rgba(0, 191, 99, 0); } }
.hv__window { position: absolute; left: 45px; top: 232px; width: 80px; height: 24px; overflow: hidden; border-radius: 8px; background: linear-gradient(#2b2f37, #16181e); }
.hv__window i { position: absolute; left: 7px; right: 7px; top: 11px; height: 2px; border-radius: 1px; background: #5a6070; opacity: .85; transition: background .3s, box-shadow .3s; }
.hv[data-show="1"][data-p="ok"] .hv__window i { background: var(--ok); box-shadow: 0 0 6px rgba(0, 191, 99, .8); }
.hv__val::after { content: ""; position: absolute; left: 50%; bottom: -34px; width: 44px; height: 32px; border-radius: 0 0 8px 8px; background: linear-gradient(90deg, #2b2f37, #16181e 70%); transform: translateX(-50%); } /* its mount: a validator stands on a pole, it is not a phone */

/* a bank card's parts, for 02's cards at its validator */
.hv__chip { position: absolute; left: 16px; top: 36px; width: 24px; height: 18px; border-radius: 4px; background: linear-gradient(135deg, #ecd08a, #b98c3a); }
.hv__pan { position: absolute; left: 16px; bottom: 13px; font-family: var(--font-mono); font-size: 10px; letter-spacing: .08em; color: rgba(255, 255, 255, .85); }
.hv__brand { position: absolute; right: 13px; bottom: 12px; font-size: 10px; font-weight: 600; font-style: italic; color: rgba(255, 255, 255, .6); }

/* 2: the inspector's phone: its camera finds the code (seen at an angle, as through a real camera), a line runs
   over it, then the whole screen turns green and answers */
.hv__insp { background: radial-gradient(circle at 50% 42%, #3b4152, #12141a 72%); }
.hv__iapp { position: absolute; left: 0; right: 0; top: 26px; z-index: 4; text-align: center; font-size: 11px; font-weight: 600; color: rgba(255, 255, 255, .85); }
.hv__ihint { position: absolute; left: 0; right: 0; bottom: 26px; text-align: center; font-size: 10px; color: rgba(255, 255, 255, .55); }
.hv__vf { position: absolute; left: 50%; top: 66px; width: 100px; height: 100px; transform: translateX(-50%); }
.hv__vf-code { position: absolute; inset: 14px; padding: 5px; border-radius: 6px; background: var(--white); box-shadow: 0 8px 18px -8px rgba(0, 0, 0, .6); transform: rotate(-5deg); opacity: 0; transition: opacity .35s; }
.hv[data-show="2"]:not([data-p="in"]) .hv__vf-code { opacity: 1; transition-delay: .5s; } /* in sight once the phone is there */
.hv__vf-code .hv__code { display: block; width: 100%; height: 100%; }
.hv__vf-c { /* the viewfinder's corners */
  position: absolute;
  inset: 0;
  --g: linear-gradient(var(--white), var(--white));
  background: var(--g) 0 0 / 18px 3px, var(--g) 0 0 / 3px 18px, var(--g) 100% 0 / 18px 3px, var(--g) 100% 0 / 3px 18px,
    var(--g) 0 100% / 18px 3px, var(--g) 0 100% / 3px 18px, var(--g) 100% 100% / 18px 3px, var(--g) 100% 100% / 3px 18px;
  background-repeat: no-repeat;
  transition: transform .45s var(--pop); /* locking on: a small snap */
}
.hv[data-show="2"]:not([data-p="in"]) .hv__vf-c { transform: rotate(-5deg) scale(.9); transition-delay: .7s; } /* it locks on: the corners close round the code, at its angle */
.hv__vf-line { position: absolute; left: 8px; right: 8px; top: 12px; height: 2px; border-radius: 1px; background: var(--ok); box-shadow: 0 0 12px 2px rgba(0, 191, 99, .7); opacity: 0; transition: opacity .25s; }
.hv[data-show="2"][data-p="act"] .hv__vf-line { opacity: 1; animation: hvVf 1.3s ease-in-out infinite alternate; }
@keyframes hvVf { to { transform: translateY(74px); } }
.hv__iok { position: absolute; inset: 0; z-index: 3; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px; padding: 0 10px; text-align: center; color: var(--white); background: linear-gradient(165deg, #10cf73, #00874a); clip-path: circle(0 at 50% 45%); transition: clip-path .6s var(--settle); }
.hv[data-show="2"][data-p="ok"] .hv__iok { clip-path: circle(150% at 50% 45%); }
.hv__ibig { display: grid; place-items: center; width: 54px; height: 54px; margin-bottom: 8px; border-radius: 50%; background: var(--white); box-shadow: 0 10px 20px -8px rgba(0, 0, 0, .35); }
.hv__ibig svg { width: 30px; height: 30px; }
.hv__ibig path { fill: none; stroke: var(--ok-ink); stroke-width: 2.8; stroke-linecap: round; stroke-linejoin: round; }
.hv__iok b { font-family: var(--font-display); font-size: 24px; font-weight: 400; line-height: 1.1; }
.hv__iok span { font-size: 10px; opacity: .9; }
.hv__iok em { margin-top: 10px; padding: 3px 10px; border-radius: 999px; background: rgba(255, 255, 255, .2); font-size: 10px; font-style: normal; font-weight: 600; }

/* 3: the back-office, in one pass: the taps glow in along the lines from the devices of the scenes before; then, one
   after another, what the back-office does with them (the trips drawn, the daily cap filled, clearing split); then
   each operator, settled. Then it rests */
.hv__bo-bar { position: absolute; left: 0; right: 0; top: 0; height: 26px; display: flex; align-items: center; gap: 5px; padding: 0 10px; border-bottom: 1px solid var(--line); border-radius: 12px 12px 0 0; background: #f7f8fa; }
.hv__bo-bar i { width: 7px; height: 7px; border-radius: 50%; }
.hv__bo-bar i:first-child { background: #ff6b5e; } .hv__bo-bar i:nth-child(2) { background: #f5c04a; } .hv__bo-bar i:nth-child(3) { background: #4fcf6d; }
.hv__bo-bar b { margin-left: 8px; font-size: 10px; color: var(--ink); }
.hv__job { position: absolute; left: 10px; right: 10px; top: calc(36px + var(--i) * 70px); height: 62px; padding: 8px 10px; border: 1px solid var(--line); border-radius: 10px; background: var(--white); }
.hv__job > span { display: block; font-size: 10px; font-weight: 600; color: var(--ink); }
/* trips: three taps joined into rides */
.hv__job-trip { position: relative; display: flex; justify-content: space-between; margin: 14px 4px 0; }
.hv__job-trip::before { content: ""; position: absolute; left: 4px; right: 4px; top: 4px; height: 2px; background: var(--brand); transform: scaleX(0); transform-origin: left; transition: transform .6s var(--settle); }
.hv__job-trip i { position: relative; width: 10px; height: 10px; border: 2px solid var(--brand); border-radius: 50%; background: var(--white); }
.hv[data-show="3"] .hv__job-trip::before { transform: none; transition-delay: .9s; }
/* the cap: the day's rides fill up to it and stop */
.hv__job-cap { display: flex; align-items: center; gap: 8px; margin-top: 12px; }
.hv__job-cap i { position: relative; flex: 1; height: 8px; overflow: hidden; border-radius: 4px; background: #e8ebf1; }
.hv__job-cap i::after { content: ""; position: absolute; inset: 0; border-radius: 4px; background: var(--brand); transform: scaleX(0); transform-origin: left; transition: transform .8s var(--settle); }
.hv[data-show="3"] .hv__job-cap i::after { transform: none; transition-delay: 1.4s; }
.hv__job-cap b { font-size: 11px; color: var(--ink); }
.hv__split { display: flex; gap: 3px; margin-top: 14px; }
.hv__split i { width: var(--w); height: 10px; border-radius: 4px; background: var(--c); transform: scaleX(0); transform-origin: left; transition: transform .5s var(--ease-out); }
.hv[data-show="3"] .hv__split i { transform: none; transition-delay: 1.9s; }
.hv__flows { position: absolute; left: 0; top: 0; width: 440px; height: 380px; overflow: visible; }
.hv__flows path { fill: none; stroke: var(--line-strong); stroke-width: 1.5; stroke-dasharray: 3 4; }
.hv__flows .hv__lit { stroke: var(--brand); stroke-width: 2.5; stroke-linecap: round; stroke-dasharray: 16 220; stroke-dashoffset: 16; filter: drop-shadow(0 0 3px rgba(98, 68, 187, .6)); }
.hv[data-show="3"] .hv__lit { animation: hvLit 1s var(--hv-ease) var(--d) both; } /* once, each time the scene comes */
@keyframes hvLit { to { stroke-dashoffset: -70; } } /* a 16 px glow along a line and off its end (the gap is longer than any of them) */
/* the devices, small, as they were in their scenes */
.hv__mini { position: absolute; border: 2px solid #23262f; border-radius: 8px; background: var(--white); box-shadow: 0 10px 18px -12px rgba(13, 14, 22, .4); }
.hv__mini i { position: absolute; }
.hv__mini--val { left: 30px; top: 75px; width: 34px; height: 58px; }
.hv__mini--val i:first-child { left: 4px; right: 4px; top: 5px; height: 16px; border-radius: 3px; background: #1b1e26; }
.hv__mini--val i:last-child { left: 8px; top: 27px; width: 14px; height: 14px; border: 2px solid var(--ok); border-radius: 50%; }
.hv__mini--app { left: 32px; top: 157px; width: 30px; height: 58px; }
.hv__mini--app i { left: 6px; right: 6px; top: 12px; height: 26px; border-radius: 3px; background: var(--white) linear-gradient(var(--ink), var(--ink)) 50% 60% / 12px 12px no-repeat; box-shadow: inset 0 0 0 1.5px var(--line-strong); } /* the pass, its code */
.hv__mlbl { position: absolute; left: 4px; width: 86px; text-align: center; font-size: 10px; font-weight: 600; color: var(--muted); } /* what each small device is, under it */
.hv__bmini i { position: absolute; left: 6px; top: 16px; width: 14px; height: 14px; border: 2px solid var(--white); border-radius: 2px; } /* B, small: the inspector's viewfinder */
/* the operators, each settled */
.hv__op { position: absolute; left: 340px; top: var(--y); width: 94px; height: 50px; display: grid; grid-template-columns: 26px 1fr; column-gap: 7px; align-content: center; padding: 0 9px; border: 1.5px solid var(--line); border-radius: 12px; background: var(--white); box-shadow: 0 10px 20px -16px rgba(22, 30, 60, .4); }
.hv__op svg { grid-row: span 2; width: 26px; height: 26px; align-self: center; }
.hv__op span { font-size: 10px; color: var(--muted); }
.hv__op b { font-size: 11px; color: var(--ok-ink); opacity: 0; transition: opacity .3s; }
.hv[data-show="3"] .hv__op b { opacity: 1; transition-delay: 2.8s; } /* settled, once its share has glowed out to it */

.stats-band { border-top: 1px solid var(--hairline); background: var(--white); }
.stats-band__inner { max-width: var(--content-w); margin: 0 auto; padding: 30px var(--gutter) 34px; }
.stats-band__clip { overflow: hidden; }
.stats { display: flex; flex-wrap: wrap; row-gap: 24px; margin: 0 0 0 -1px; padding: 0; list-style: none; }

.stat {
  flex: 1 1 120px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 6px 20px;
  border-left: 1px solid var(--line);
}

.stat__value {
  display: flex;
  align-items: baseline;
  font-family: var(--font-display);
  font-size: clamp(30px, 2.8vw, 40px); /* as .h2: figures never outrank the headings */
  line-height: 1;
  letter-spacing: -.01em;
  color: var(--black);
}

.stat__unit { margin-left: 2px; font-size: .7em; color: var(--brand); }
.stat__label { font-size: 14px; color: var(--muted); text-wrap: balance; } /* a label that wraps, wraps evenly, not one word on its own */
/* where the figures stand narrow (two to a row on phones, five in a tight row on tablets) every label takes two lines,
   its last word under the rest, so no label runs on while its neighbour wraps */
@media (max-width: 1000px) { .stat__label > span { display: block; } }

/* digit roll used by the count-up (main.js) */
.roll { display: inline-flex; }
.roll__digit { display: inline-block; height: 1em; line-height: 1; overflow: hidden; }
.roll__col { display: flex; flex-direction: column; align-items: center; transition: transform 1.1s var(--ease-out); }
.roll__col > span { height: 1em; line-height: 1; }

/* ---------- overview ---------- */
.overview__head { margin-bottom: 28px; }
.overview__head .h2 { max-width: 720px; }

/* 4 columns, then 2 below 880px, then 1 below 440px (container-width switch, no media query) */
.area-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(clamp(calc((100% - 48px) / 4), (880px - 100%) * 999, clamp(calc((100% - 16px) / 2), (440px - 100%) * 999, 100%)), 1fr));
  gap: 16px;
}

.area-card {
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-height: 250px;
  padding: 26px;
  border-radius: 16px;
  background: var(--ground);
  border: 1px solid var(--ground);
  color: var(--ink);
  transition: transform .35s var(--ease-out), border-color .25s, background .25s, box-shadow .35s;
}

.area-card:hover {
  transform: translateY(-2px);
  color: var(--ink);
  border-color: var(--brand);
  background: var(--white);
  box-shadow: 0 1px 2px rgba(13, 14, 22, .05), 0 10px 24px -12px rgba(13, 14, 22, .18);
}

.area-card__num { font-family: var(--font-display); font-size: 36px; line-height: 1; color: var(--brand); }
.area-card__title { margin-top: 18px; font-size: 18px; line-height: 1.25; font-weight: 600; text-wrap: balance; }
/* what is inside the area, by the names its "What we build" uses: the block's own lead says what it is, so the card
   doesn't say it twice */
.area-card__list { margin: 0; padding: 0; list-style: none; font-size: 14px; line-height: 1.45; color: var(--text); }
.area-card__list li { padding: 9px 0; border-top: 1px solid var(--line); }
.area-card__more { margin-top: auto; display: flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 600; color: var(--brand-ink); }

.cta-band {
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 22px;
  min-height: 210px;
  margin-top: var(--section-y); /* as far from the last area as every block from the next */
  padding: 48px clamp(24px, 5vw, 72px);
  border-radius: 8px;
  background: var(--brand);
}

.cta-band__lines { position: absolute; right: clamp(0px, 4vw, 100px); bottom: 0; width: clamp(110px, 32%, 260px); height: auto; pointer-events: none; }

.cta-band__title {
  position: relative;
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(24px, 2.6vw, 34px);
  line-height: 1.15;
  color: var(--white);
  text-wrap: balance;
}

.cta-band__btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  height: 48px;
  padding: 0 22px;
  border: 1px solid var(--white);
  border-radius: 6px;
  color: var(--white);
  font-size: 15px;
  font-weight: 600;
  white-space: nowrap;
  transition: background .2s ease-in, color .2s ease-in;
}

.cta-band__btn:hover { background: var(--white); color: var(--brand-ink); }

/* ---------- services 01-03 ---------- */

/* The three areas share one grid of 12 columns with --grid-gap between them: a side of 4 columns (the label and
   lead of "what we build") and a main side of 8 (the accordion), so all their text starts on the same two lines.
   The pictures run across all 12. */
.svc {
  display: grid;
  grid-template-columns: var(--side) minmax(0, 1fr);
  gap: 28px var(--grid-gap);
  align-items: start;
  padding: var(--section-y) 0; /* as the sections themselves: every block on the page stands as far from the next (128 px on a wide screen) */

  scroll-margin-top: 96px;
}
.svc:first-of-type { padding-top: 0; } /* the services section already opens with its own room */

/* each area opens the same way: number, name, a two-part heading and a lead, across both columns */
.svc__head { grid-column: 1 / -1; max-width: 960px; margin-bottom: 12px; } /* 40 px to the picture */
.svc__head .h2 { margin-bottom: 14px; }
/* the areas' two-part headings: the green part always starts its own line, however long the first part runs */
.svc__head .h2 > .text-brand { display: block; }
.svc__head .section-lead { max-width: 780px; }

/* service picture card (each one is an illustrated .dia--art, below) */
.dia { padding: 22px; border-radius: 16px; background: var(--ground); } /* 22 px in, so its words line up with the rows below */
.dia__foot { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-top: 16px; padding-top: 12px; border-top: 1px dashed var(--line-dashed); }
.dia__foot .label { margin-right: 4px; }
/* service pictures: a soft gradient with the hero's dotted grid behind frosted cards of real-looking product data */
.dia--art {
  background:
    radial-gradient(circle, rgba(154, 161, 180, .32) 1px, transparent 1.3px) 0 0 / 22px 22px,
    radial-gradient(120% 80% at 15% 0%, #efebfb 0%, rgba(239, 235, 251, 0) 60%),
    radial-gradient(90% 70% at 100% 100%, #e8ecf4 0%, rgba(232, 236, 244, 0) 65%),
    #f6f7f9;
}
.dia--art .dia__foot { border-top-color: rgba(0, 0, 0, .07); }

/* the live dot that sits in a picture's caption */
/* story bars after a panel's caption, as payments.edvantis.com's: one segment per item, the current one fills while it
   shows, then the next item comes (main.js); a segment picks its item */
.story { display: flex; gap: 4px; width: 180px; margin-left: 8px; }
.story button { flex: 1; display: flex; align-items: center; height: 24px; touch-action: manipulation; padding: 0; border: 0; background: none; cursor: pointer; }
.story i { position: relative; flex: 1; height: 3px; overflow: hidden; border-radius: 2px; background: #d3d8e1; transition: height .2s; }
.story i::after { content: ""; position: absolute; inset: 0; background: var(--brand); transform: scaleX(var(--p, 0)); transform-origin: left; }
.story button[aria-current] i { background: color-mix(in srgb, var(--brand) 30%, #d3d8e1); }
.story button:hover i { height: 5px; }
/* phones: the bars on a line of their own; the dot stays by its words, even when they take two lines */
@media (max-width: 600px) {
  .story { grid-column: 1 / -1; width: 100%; margin: 2px 0 0; }
}

/* an area whose picture runs the full width: head, picture, then what we build (its label and lead on one side, the
   accordion on the other) */
.svc--wide .dia { grid-column: 1 / -1; }
.svc--wide .svc__text {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: var(--side) minmax(0, 1fr);
  gap: 20px var(--grid-gap);
  align-items: start;
}
/* under the heading, the lead: quieter and narrower, so the heading leads and the rows follow */
.svc--wide .svc__text .section-lead { margin: 0; max-width: 340px; color: var(--muted); }
@media (min-width: 861px) {
  /* side by side, the heading's first line sits level with the first row's title (their middles) */
  .svc--wide .svc__text > div:first-child { padding-top: 19px; }
  /* a picture to its "what we build": 80 px, so the two read as two parts, not a picture and its caption */
  .svc .svc__text { margin-top: 52px; }
  /* one rule across both columns opens "what we build": the accordion's top line, drawn under the heading too (the
     first row's green mark sits on it). Nothing closes the block but the accordion's last line; the areas stand apart
     by their space and numbers alone */
  .svc--wide .svc__text { padding-top: 0; border-top: 1px solid var(--line); }
  .svc--wide .svc__text .acc > .acc__item:first-child { border-top: 0; }
}
/* one column: the divider stands above the label and lead (side by side, the rule above both columns does this) */
@media (max-width: 860px) {
  .svc--wide .svc__text { padding-top: 28px; border-top: 1px solid var(--line); }
}

/* the "try it" line under an area's lead */
.try-note { display: flex; align-items: center; gap: 8px; margin: 12px 0 0; font-size: 14px; font-weight: 600; color: var(--brand-ink); }
.try-note svg { flex: none; }
.try-note__m { display: none; }
@media (max-width: 980px) { .try-note__d { display: none; } .try-note__m { display: inline; } } /* on phones the picture is what you tap */

/* the interactive pictures are pressed, not read: a long press or a double tap on a phone must not select them, or
   the text beside them */
.hv__stage { -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }

/* the switches inside the pictures, as payments.edvantis.com's: a segmented control (a grey track, the picked one a
   white key on it) for what changes the whole picture, pill picks for a setting or an item */
.seg { display: inline-flex; gap: 2px; padding: 3px; border: 1px solid rgba(0, 0, 0, .05); border-radius: 12px; background: rgba(214, 219, 229, .55); }
.seg button {
  padding: 8px 16px;
  border: 0;
  border-radius: 9px;
  background: none;
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  color: var(--muted);
  white-space: nowrap;
  cursor: pointer;
  transition: background-color .2s, color .2s, box-shadow .2s;
}
.seg button:hover { color: var(--ink); }
.seg button[aria-pressed="true"] { background: #fff; color: var(--ink); box-shadow: 0 1px 2px rgba(22, 30, 60, .1), 0 6px 14px -8px rgba(22, 30, 60, .35); }
.pick {
  padding: 6px 13px;
  border: 1px solid rgba(255, 255, 255, .9);
  border-radius: 999px;
  background: rgba(255, 255, 255, .8);
  box-shadow: 0 6px 14px -10px rgba(22, 30, 60, .45);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
  white-space: nowrap;
  cursor: pointer;
  transition: border-color .2s, color .2s, box-shadow .2s;
}
.pick:hover { border-color: var(--line-strong); }
.pick[aria-pressed="true"] { border-color: var(--brand); color: var(--brand-ink); box-shadow: 0 0 0 3px rgba(98, 68, 187, .14), 0 6px 14px -10px rgba(22, 30, 60, .45); }
@media (max-width: 600px) {
  .seg { display: flex; }
  .seg button { flex: 1; padding: 8px 6px; font-size: 13px; }
}

/* a panel's fine print */
.dia__fine { margin-left: auto; font-size: 12px; color: var(--faint); }

/* 02 and 03's panels (.app): the picture, and beside it the steps, the one on show with what we build behind it
   (main.js switches them). 01 is the ride demo, styled in ride/ride.css */
.app__sig { width: 17px; height: 11px; fill: #23262f; }
.app__bat { position: relative; width: 22px; height: 11px; border: 1.5px solid #23262f; border-radius: 3px; }
.app__bat::after { content: ""; position: absolute; inset: 1.5px 5px 1.5px 1.5px; border-radius: 1px; background: #23262f; }
/* a route's badge: its number on its colour */
.app__badge { display: grid; font-style: normal; place-items: center; width: 30px; height: 22px; padding: 0; border-radius: 7px; background: var(--c); font-size: 11.5px; font-weight: 600; color: var(--white); }

/* the panel as a stage: no dot grid, a soft light behind the picture, and the picture and its words as one piece in
   the middle of it */
.app.dia--art { background: radial-gradient(30% 58% at 70% 50%, rgba(98, 68, 187, .2), rgba(98, 68, 187, 0) 72%), radial-gradient(55% 70% at 20% 18%, #fff, rgba(255, 255, 255, 0) 70%), linear-gradient(160deg, #f5f7f9, #eaedf2); }
.app__stage { display: grid; grid-template-columns: minmax(0, 380px) minmax(0, 680px); justify-content: center; align-items: center; gap: 32px 64px; margin: 18px 0 30px; } /* the words on the left, the picture on the right */

/* beside the picture: the steps (each a pick, with back and on), what the one on show is and what we build behind it */
.app__top { display: none; }
.app__info { order: -1; max-width: 400px; min-height: 300px; } /* as tall as its tallest step (a two-line name, four lines of words), so the steps do not move as they change */
.app .dia__foot .tag { padding: 0; border: 0; background: none; font: 400 13px var(--font-body); color: var(--muted); }
.app .dia__foot .tag + .tag::before { content: "·"; margin: 0 8px 0 2px; color: var(--faint); } /* Built on: plain words, not code */
/* the steps: their numbers, the one on show with a line under it, then back and on */

.app__name { margin: 0 0 12px; font-family: var(--font-display); font-size: 36px; font-weight: 400; line-height: 1.12; color: var(--black); }
.app__txt { margin: 0; min-height: 4.8em; font-size: 18px; line-height: 1.6; color: var(--muted); text-wrap: pretty; }

@media (max-width: 980px) {
  /* the panel gives way to the film, on the page itself: the label and the bars, the picture, the words under it */
  .app.dia { padding: 0; border: 0; background: none; box-shadow: none; }
  .app::before, .app::after { display: none; }
  .app__top { display: flex; align-items: center; gap: 10px; font-size: 13px; white-space: nowrap; }
  .app__top .story { flex: 1; width: auto; margin: 0; }
  .app__top .story button { height: 44px; margin: -10px 0; } /* a thumb's height to tap, the bar still 3px */
  .app__stage { display: flex; flex-direction: column; gap: 12px; margin-top: 4px; }
  .app__info { order: 2; max-width: none; min-height: 0; padding: 0; border: 0; background: none; box-shadow: none; } /* under the film */
  .app .dia__foot { column-gap: 14px; }
  .app .dia__foot .tag + .tag::before { display: none; } /* where the words wrap, a dot would start a line */
  .app .dia__fine { flex-basis: 100%; margin: 4px 0 0; font-size: 12px; } /* on a line of its own, not at a ragged line's end */
  .app__name { margin: 0 0 6px; font-size: 26px; }
  .app__txt { min-height: 4.5em; font-size: 15px; line-height: 1.5; }
}

/* 02, a day on the network (main.js plays it): the words on the left, as 01's, and on the right a validator and the
   operator's console, joined by the link. The scene is laid out in fixed pixels on a 680 x 500 board, zoomed to its
   column (--k, set by main.js). On the panel: data-screen (the step, 0-4), data-act (its moment: tap, ok, off, sync),
   data-v (the validator's screen), data-link (on, off, sync), data-tab (the console's view), data-synced */
.afc .app__stage { grid-template-columns: minmax(0, 380px) minmax(0, 680px); gap: 32px 64px; }
.afc.dia--art { background-position: 0 0; background-image: radial-gradient(30% 58% at 68% 50%, rgba(98, 68, 187, .16), rgba(98, 68, 187, 0) 72%), radial-gradient(55% 70% at 20% 18%, #fff, rgba(255, 255, 255, 0) 70%), linear-gradient(160deg, #f5f7f9, #eaedf2); } /* the light behind the devices, on the right here */
.afc__fit { width: 100%; min-width: 0; }
.afc__scene { position: relative; width: 680px; height: 500px; zoom: var(--k, 1); -webkit-user-select: none; user-select: none; }

/* the validator, in the hero's look */
.afc__val { position: absolute; left: 96px; top: 60px; width: 172px; height: 336px; border: 2px solid #23262f; border-radius: 30px; background: var(--white) linear-gradient(150deg, rgba(255, 255, 255, 0) 40%, rgba(20, 24, 40, .06)); box-shadow: inset -9px 0 14px -10px rgba(13, 14, 22, .22), 0 1px 2px rgba(13, 14, 22, .08), 0 18px 30px -16px rgba(13, 14, 22, .3), 0 44px 70px -34px rgba(13, 14, 22, .4); transition: opacity .4s; }
.afc__led { position: absolute; left: 50%; top: 12px; width: 44px; height: 5px; border-radius: 3px; background: #c3c8d2; transform: translateX(-50%); transition: background .3s, box-shadow .3s; }
.afc__vs { position: absolute; left: 13px; right: 13px; top: 26px; height: 128px; overflow: hidden; border: 1px solid #0b0c10; border-radius: 16px; background: linear-gradient(160deg, #262a35, #101217); }
.afc__vs::after { content: ""; position: absolute; inset: 0; background: linear-gradient(120deg, rgba(255, 255, 255, .12), rgba(255, 255, 255, 0) 40%); pointer-events: none; }
.afc__vs > div { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px; text-align: center; opacity: 0; transition: opacity .3s; }
.afc__vs-wait { gap: 8px !important; font-size: 12px; font-weight: 600; color: rgba(255, 255, 255, .6); }
.afc__vs-wait svg { width: 24px; height: 24px; }
.afc__vs-wait path, .afc__reader path { fill: none; stroke: rgba(255, 255, 255, .75); stroke-width: 2; stroke-linecap: round; }
.afc__reader path { stroke: #23262f; }
.afc__vs b { margin-top: 4px; font-family: var(--font-display); font-size: 23px; font-weight: 400; line-height: 1; color: var(--white); }
.afc__vs span { font-size: 11px; color: rgba(255, 255, 255, .62); }
.afc__tick { display: grid; place-items: center; width: 30px; height: 30px; border-radius: 50%; background: var(--ok); box-shadow: 0 0 16px rgba(0, 191, 99, .6); }
.afc__tick svg { width: 20px; height: 20px; }
.afc__tick--no { background: #e5484d; box-shadow: 0 0 16px rgba(229, 72, 77, .55); }
.afc__tick path { fill: none; stroke: var(--white); stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round; }
.afc__dot-off { display: inline-block; width: 6px; height: 6px; margin-right: 5px; border-radius: 50%; background: var(--warn); vertical-align: 1px; }
.afc__reader { position: absolute; left: 50%; top: 172px; width: 82px; height: 82px; display: grid; place-items: center; border: 1.5px solid var(--line); border-radius: 50%; background: radial-gradient(circle, #fff 55%, #eef0f4); transform: translateX(-50%); transition: border-color .3s; }
.afc__reader svg { width: 28px; height: 28px; }
.afc__window { position: absolute; left: 50%; top: 276px; width: 92px; height: 26px; overflow: hidden; border-radius: 8px; background: linear-gradient(#2b2f37, #16181e); transform: translateX(-50%); }
.afc__window i { position: absolute; left: 8px; right: 8px; top: 12px; height: 2px; border-radius: 1px; background: #5a6070; opacity: .85; transition: background .3s, box-shadow .3s; } /* the scanner's line: dark at rest, lit by the answer */
.afc[data-v="ok"] .afc__window i { background: var(--ok); box-shadow: 0 0 6px rgba(0, 191, 99, .8); }
.afc[data-v="deny"] .afc__window i { background: #e5484d; box-shadow: 0 0 6px rgba(229, 72, 77, .8); }
.afc__vname { position: absolute; left: 0; right: 0; top: 346px; text-align: center; font-size: 12px; font-weight: 600; color: var(--muted); }
/* what the screen says (data-v, set by main.js): waiting, the fare (offline, stored), refused, synced */
.afc[data-v="wait"] .afc__vs-wait, .afc[data-v="ok"] .afc__vs-ok, .afc[data-v="deny"] .afc__vs-deny, .afc[data-v="sync"] .afc__vs-sync { opacity: 1; }
.afc[data-v="deny"] .afc__led { background: #e5484d; box-shadow: 0 0 8px rgba(229, 72, 77, .8); }
.afc[data-v="deny"] .afc__reader { border-color: #e5484d; box-shadow: 0 0 0 4px rgba(229, 72, 77, .2); }
.afc[data-act="tap"] .afc__led { background: #f2c94c; box-shadow: 0 0 8px rgba(242, 201, 76, .8); }
.afc[data-v="ok"] .afc__led, .afc[data-v="sync"] .afc__led { background: var(--ok); box-shadow: 0 0 8px rgba(0, 191, 99, .8); }
.afc[data-act="tap"] .afc__reader { border-color: #f2c94c; box-shadow: 0 0 0 4px rgba(242, 201, 76, .35); }
.afc[data-screen="0"][data-v="ok"] .afc__reader { border-color: var(--ok); animation: hvRing 1.4s ease-out infinite; }

/* the cards, each in its step: at rest on the left, to the reader for the tap, back after; the second one is on the
   deny-list */
.afc__card { position: absolute; left: -44px; top: 340px; z-index: 2; width: 132px; height: 84px; border-radius: 10px; background: #1b1e26 radial-gradient(circle at 88% 0, rgba(0, 191, 99, .4), transparent 58%); box-shadow: 0 20px 34px -18px rgba(13, 14, 22, .55); transform: rotate(-12deg); transition: transform .6s var(--spring), opacity .4s; }
.afc__card .hv__chip { left: 14px; top: 30px; width: 20px; height: 15px; }
.afc__card .hv__pan { left: 14px; bottom: 11px; font-size: 8.5px; }
.afc__card .hv__brand { right: 11px; bottom: 10px; font-size: 8.5px; }
.afc[data-act="tap"] .afc__card { transform: translate(156px, -116px) rotate(-4deg); } /* at rest clear of the validator, to its reader for the tap */
.afc[data-screen="4"] .afc__val, .afc[data-screen="4"] .afc__link { opacity: .4; } /* the day is the back-office's now: the validator waits, quietly */
.afc[data-screen="4"] .afc__net { border-color: rgba(0, 191, 99, .4); color: rgba(29, 29, 29, .4); } .afc[data-screen="4"] .afc__net i { opacity: .4; } /* the pill fades its colours, not itself: its white stays whole over the line */
.afc__link { transition: opacity .4s; }
.afc__card { opacity: 0; }
.afc[data-screen="0"] .afc__card:not(.afc__card--deny), .afc[data-screen="1"] .afc__card--deny { opacity: 1; }
.afc__card--deny { background: #3b4a8f radial-gradient(circle at 88% 0, rgba(255, 255, 255, .22), transparent 58%); }

/* the link: off (grey, its 4G amber) while the validator is on its own, green once it is back, the stored taps flying
   up it */
.afc__link { position: absolute; left: 0; top: 0; width: 680px; height: 500px; overflow: visible; pointer-events: none; }
.afc__link path { fill: none; stroke: var(--line-strong); stroke-width: 2; stroke-dasharray: 4 5; }
.afc__link .afc__link-lit { stroke: var(--brand); stroke-dasharray: none; stroke-width: 2.5; transition: opacity .3s; }
.afc[data-link="off"] .afc__link-lit { opacity: 0; }
.afc__packets { opacity: 0; transition: opacity .3s; }
.afc__packets circle { fill: var(--brand); }
.afc[data-link="sync"] .afc__packets { opacity: 1; }
.afc__net { position: absolute; left: 299px; top: 150px; display: flex; align-items: center; gap: 5px; padding: 3px 9px; border: 1.5px solid var(--ok); border-radius: 999px; background: var(--white); font-size: 11px; font-weight: 600; color: var(--ok-ink); transform: translate(-50%, -50%); transition: border-color .3s, color .3s, opacity .4s; }
.afc__net i { width: 6px; height: 6px; border-radius: 50%; background: var(--ok); }
.afc[data-link="off"] .afc__net { border-color: var(--warn); color: #8a6100; }
.afc[data-link="off"] .afc__net i { background: var(--warn); }

/* the console */
.afc__con { position: absolute; left: 330px; top: 40px; width: 350px; height: 400px; overflow: hidden; border: 2px solid #23262f; border-radius: 16px; background: var(--white); box-shadow: 0 1px 2px rgba(13, 14, 22, .08), 0 18px 30px -16px rgba(13, 14, 22, .25), 0 44px 70px -34px rgba(13, 14, 22, .32); }
.afc__bar { display: flex; align-items: center; gap: 5px; height: 34px; padding: 0 12px; border-bottom: 1px solid var(--line); background: #f7f8fa; }
.afc__bar i { width: 8px; height: 8px; border-radius: 50%; }
.afc__bar i:first-child { background: #ff6b5e; } .afc__bar i:nth-child(2) { background: #f5c04a; } .afc__bar i:nth-child(3) { background: #4fcf6d; }
.afc__bar b { margin-left: 8px; font-size: 11.5px; color: var(--ink); }
.afc__status { display: flex; align-items: center; gap: 5px; margin-left: auto; padding: 3px 8px; border-radius: 999px; background: var(--ok-soft); font-size: 11px; font-weight: 600; white-space: nowrap; color: var(--ok-ink); transition: background .3s, color .3s; }
.afc__status em { width: 6px; height: 6px; border-radius: 50%; background: var(--ok); }
.afc__status.is-off { background: #fff4d6; color: #8a6100; }
.afc__status.is-off em { background: var(--warn); }
.afc__tabs { display: flex; gap: 4px; padding: 10px 12px 0; border-bottom: 1px solid var(--line); }
.afc__tabs span { padding: 7px 10px 9px; border-bottom: 2px solid transparent; font-size: 12px; font-weight: 600; color: var(--faint); transition: color .3s, border-color .3s; }
.afc[data-tab="taps"] .afc__tabs [data-t="taps"], .afc[data-tab="devices"] .afc__tabs [data-t="devices"], .afc[data-tab="settle"] .afc__tabs [data-t="settle"] { border-color: var(--brand); color: var(--ink); }
.afc__view { position: absolute; left: 0; right: 0; top: 80px; bottom: 0; padding: 12px 14px; opacity: 0; transform: translateY(8px); transition: opacity .3s, transform .5s var(--settle); }
.afc[data-tab="taps"] .afc__view[data-t="taps"], .afc[data-tab="devices"] .afc__view[data-t="devices"], .afc[data-tab="settle"] .afc__view[data-t="settle"] { opacity: 1; transform: none; }

/* live taps: the stored ones come in at the top once synced */
.afc__taps ul { display: flex; flex-direction: column; margin: 0; padding: 0; list-style: none; }
.afc__taps li { display: grid; grid-template-columns: 42px 30px 1fr 48px 58px; gap: 8px; align-items: center; padding: 8px 2px; border-bottom: 1px solid var(--line); font-size: 13px; } /* one set of columns for every row, the status last, so the amounts line up */
.afc__taps li b { font-family: var(--font-mono); font-size: 12px; font-weight: 500; color: var(--muted); }
.afc__taps li em { font-style: normal; font-weight: 600; text-align: right; font-variant-numeric: tabular-nums; }
.afc__taps li small.is-no { background: #fdecec; color: #c23a3f; }
.afc__taps li small { justify-self: end; padding: 2px 7px; border-radius: 999px; background: var(--ok-soft); font-size: 10.5px; font-weight: 600; color: var(--ok-ink); }
.afc__taps .is-new { display: none; }
.afc[data-synced] .afc__taps .is-new { display: grid; }
.afc[data-link="sync"] .afc__taps .is-new { animation: afcIn .5s var(--settle) backwards; animation-delay: calc(.6s + var(--i) * .35s); }
@keyframes afcIn { from { opacity: 0; transform: translateY(-8px); background: var(--mint-soft); } }

/* devices: the fleet as an operator sees it, each validator, gate and handheld with where it is and when it was last
   heard from; one needing a look */
.afc__drow { display: grid; grid-template-columns: 58px 1fr 54px 48px; gap: 8px; align-items: center; padding: 8px 2px; border-bottom: 1px solid var(--line); font-size: 12.5px; color: var(--ink); }
.afc__drow b { font-family: var(--font-mono); font-size: 12px; font-weight: 500; color: var(--muted); }
.afc__drow span:nth-child(3) { font-variant-numeric: tabular-nums; color: var(--muted); }
.afc__drow em { justify-self: end; padding: 2px 8px; border-radius: 999px; background: var(--ok-soft); font-size: 10.5px; font-style: normal; font-weight: 600; color: var(--ok-ink); }
.afc__drow.is-warn em { background: #fff4d6; color: #8a6100; }
.afc[data-tab="devices"] .afc__drow.is-warn { animation: afcWarn 1.6s ease-out 2; }
@keyframes afcWarn { 40% { background: #fffaf0; } }
.afc__drow--h { padding-top: 0; font-size: 10.5px; font-weight: 600; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); }
.afc__alert { display: flex; margin-top: 12px; gap: 10px; align-items: flex-start; padding: 10px 12px; border: 1px solid #f3dfa6; border-radius: 12px; background: #fffaf0; }
.afc__alert i { flex: none; width: 8px; height: 8px; margin-top: 5px; border-radius: 50%; background: var(--warn); }
.afc__alert div { display: flex; flex-direction: column; gap: 2px; }
.afc__alert b { font-size: 12.5px; color: var(--ink); }
.afc__alert span { font-size: 11.5px; color: var(--muted); }

/* settlement: the day per operator, each sent in turn */
.afc__row { display: grid; grid-template-columns: 1.3fr .8fr 1fr .8fr; gap: 6px; align-items: center; padding: 10px 2px; border-bottom: 1px solid var(--line); font-size: 12.5px; font-variant-numeric: tabular-nums; }
.afc__row span:first-child { display: flex; align-items: center; gap: 8px; font-weight: 600; }
.afc__row--h { padding-top: 2px; font-size: 10.5px; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
.afc__row em { padding: 2px 8px; border-radius: 999px; background: var(--ok-soft); font-size: 10.5px; font-style: normal; font-weight: 600; color: var(--ok-ink); opacity: 0; transition: opacity .3s; }
.afc[data-tab="settle"] .afc__row em { opacity: 1; transition-delay: calc(.5s + var(--i) * .4s); }
.afc__sum { display: flex; justify-content: space-between; align-items: baseline; padding: 14px 2px 10px; }
.afc__sum span { font-size: 12px; font-weight: 600; color: var(--muted); }
.afc__sum b { font-family: var(--font-display); font-size: 26px; font-weight: 400; color: var(--black); }
.afc__bank { display: flex; align-items: center; gap: 10px; padding: 10px 12px; border-radius: 12px; background: #f6f7f9; font-size: 11.5px; color: var(--muted); }
.afc__bank svg { flex: none; width: 30px; height: 30px; }

/* phones and portrait tablets: the same scene as a film, through a camera. The board keeps its size and a window of
   the column's width looks at what the step is about: the validator and the card for the taps, the whole board as
   the link comes back, the console for the fleet and the settlement. --w is the window's width and --s its scale
   (main.js); --cx is the point of the board it centres on and --cs how close it stands */
@media (max-width: 980px) {
  .afc.dia.dia--art { padding: 0; background: none; } /* as 01: the film on the page itself */
  .afc__fit { order: 1; height: calc(430px * var(--s, 1)); overflow-x: clip; cursor: pointer; touch-action: pan-y pinch-zoom; }
  .afc__fit * { pointer-events: none; } /* a picture here: a tap or a swipe moves the film */
  .afc__scene { --cx: 128; --cs: calc(var(--s, 1) * .9); zoom: 1; transform-origin: 0 0; transform: translate(calc(var(--w, 350) * .5px - var(--cx) * var(--cs) * 1px), calc(215px * var(--s, 1) - 240px * var(--cs))) scale(var(--cs)); transition: transform .8s var(--ease-out); }
  .afc[data-screen="2"] .afc__scene { --cx: 315; --cs: min(calc(var(--w, 350) / 750), calc(var(--s, 1) * .86)); } /* the whole board, and never taller than the window *
  .afc[data-screen="3"] .afc__scene, .afc[data-screen="4"] .afc__scene { --cx: 505; --cs: var(--s, 1); }
  .afc__con { box-shadow: 0 1px 2px rgba(13, 14, 22, .08), 0 14px 22px -16px rgba(13, 14, 22, .3); } /* a shadow that ends inside the window, so its edge never shows */
  .afc .app__info { order: 2; min-height: 132px; } /* its tallest step (a two-line name), so the page under it stays put */
}
/* portrait tablets: the column takes the whole board, so the camera stands back and stays there */
@media (min-width: 740px) and (max-width: 980px) {
  .afc[data-screen] .afc__scene { --cx: 315; --cs: min(calc(var(--w, 700) / 750), calc(var(--s, 1) * .86)); }
}

/* a ticket's passport for the country's standard: what it carries (one of an Aztec code, a QR code, an NFC mark, a
   bank card, as data-fmt on the panel says), the standard's name and the line under it */
.mx__pp { display: flex; align-items: center; gap: 10px; padding: 8px; border-radius: 10px; background: var(--white); color: var(--ink); }
.mx__pp > span:last-child { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.mx__pp b { font-size: 12.5px; color: var(--black); }
.mx__pp small { font-size: 10px; line-height: 1.3; color: var(--muted); }
.mx__fmt { position: relative; flex: none; display: grid; place-items: center; width: 40px; height: 40px; }
.mx__fmt > * { display: none; }
.mx__aztec, .mx__qr { width: 38px; height: 38px; }
.mx__aztec rect, .mx__qr rect { fill: #111318; }
.mx__nfc { width: 26px; height: 26px; fill: none; stroke: var(--brand-ink); stroke-width: 2.2; stroke-linecap: round; }
.mx__bank { width: 36px; height: 24px; border-radius: 4px; background: #1b1e26 radial-gradient(circle at 88% 0, rgba(0, 191, 99, .45), transparent 60%); box-shadow: inset 6px 8px 0 -4px #d9b25f; }
@keyframes mxSwap { 35% { transform: scale(.95); } }

/* 03, one fare and where it is sold, a step at a time (main.js plays it): the words as 01's and 02's on the left, in
   02's columns; on the right a scene laid out on a 560 x 480 board, zoomed to its column (--k, set by main.js). The
   ticket stays; the shape around it (.mz__box) changes on a spring into the next step's (data-screen): the
   back-office's window, a phone, a browser, a newsagent's till, a ring of countries; each step's picture (.mz__l)
   comes in once the shape has settled (data-show), then its moment (data-act: press, ok). data-fmt says what the
   ticket carries for the country picked: aztec, qr, nfc, bank */
.mz .app__stage { grid-template-columns: minmax(0, 380px) minmax(0, 680px); gap: 32px 64px; }
.mz.dia--art { background-position: 0 0; background-image: radial-gradient(24% 44% at 70% 52%, rgba(98, 68, 187, .1), rgba(98, 68, 187, 0) 72%), radial-gradient(55% 70% at 20% 18%, #fff, rgba(255, 255, 255, 0) 70%), linear-gradient(160deg, #f5f7f9, #eaedf2); } /* the light behind the ticket, on the right */
.mz__fit { width: 100%; min-width: 0; }
.mz__scene { position: relative; width: 560px; height: 480px; margin: 0 auto; zoom: var(--k, 1); -webkit-user-select: none; user-select: none; }

/* the shape, step by step: one family with 01's phone and 02's console, a 2px dark line */
.mz__box {
  position: absolute;
  left: 0;
  top: 30px;
  width: 560px;
  height: 420px;
  border: 2px solid #23262f;
  border-radius: 14px;
  background: var(--white);
  box-shadow: 0 1px 2px rgba(13, 14, 22, .08), 0 18px 30px -16px rgba(13, 14, 22, .26), 0 40px 64px -34px rgba(13, 14, 22, .34);
  transition-property: left, top, width, height, border-radius, border-color, background-color, box-shadow;
  transition-duration: .9s;
  transition-timing-function: var(--spring);
}
.mz[data-screen="1"] .mz__box { left: 165px; top: 0; width: 230px; height: 480px; border-radius: 38px; }
.mz[data-screen="2"] .mz__box { left: 0; top: 50px; width: 560px; height: 380px; border-radius: 14px; }
.mz[data-screen="3"] .mz__box { left: 140px; top: 0; width: 280px; height: 440px; border-radius: 24px; }
.mz[data-screen="4"] .mz__box { left: 75px; top: 35px; width: 410px; height: 410px; border-radius: 205px; background-color: rgba(255, 255, 255, .45); box-shadow: none; }

/* each step's picture, in board coordinates: in once the shape has settled, out before it moves */
.mz__l { position: absolute; inset: 0; opacity: 0; visibility: hidden; pointer-events: none; transition: opacity .18s var(--exit), visibility 0s .18s; }
.mz[data-show="0"] [data-l="0"], .mz[data-show="1"] [data-l="1"], .mz[data-show="2"] [data-l="2"], .mz[data-show="3"] [data-l="3"], .mz[data-show="4"] [data-l="4"] { opacity: 1; visibility: visible; pointer-events: auto; transition: opacity .3s var(--settle); }
.mz__l > * { position: absolute; }
.mz[data-show] .mz__l:not([data-l="4"]) > * { transform: translateY(6px); transition: transform .5s var(--settle); }
.mz[data-show="0"] .mz__l[data-l="0"] > *, .mz[data-show="1"] .mz__l[data-l="1"] > *, .mz[data-show="2"] .mz__l[data-l="2"] > *, .mz[data-show="3"] .mz__l[data-l="3"] > * { transform: none; } /* as specific as the rule above, so it wins */

/* the window's bar, as 02's console */
.mz__bar { left: 2px; right: 2px; display: flex; align-items: center; gap: 5px; height: 32px; padding: 0 12px; border-bottom: 1px solid var(--line); border-radius: 12px 12px 0 0; background: #f7f8fa; }
.mz__bar i { width: 8px; height: 8px; border-radius: 50%; }
.mz__bar i:first-child { background: #ff6b5e; } .mz__bar i:nth-child(2) { background: #f5c04a; } .mz__bar i:nth-child(3) { background: #4fcf6d; }
.mz__bar b { margin-left: 8px; font-size: 11.5px; color: var(--ink); }
.mz__url { display: flex; align-items: center; gap: 5px; height: 20px; margin: 0 auto; padding: 0 12px; border-radius: 7px; background: var(--white); box-shadow: inset 0 0 0 1px var(--line); font-size: 11px; color: var(--muted); }
.mz__url svg { width: 11px; height: 11px; fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; }
.mz__brand { display: flex; align-items: center; gap: 7px; font-size: 12.5px; font-weight: 600; color: var(--ink); }
.mz__brand i { width: 16px; height: 16px; border-radius: 5px; background: var(--c); }
.mz__fields small, .mz__outs small, .mz__rows small, .mz__prev, .mz__till, .mz__pick { font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); }

/* a button, pressed (data-act="press"), then done (data-act="ok"); the back-office's state line changes the same way */
.mz__cta { display: grid; place-items: center; height: 40px; overflow: hidden; border-radius: 11px; background: #23262f; font-size: 12.5px; font-style: normal; font-weight: 600; color: var(--white); transition: transform .3s var(--pop), background .3s; }
.mz__cta > span, .mz__state > span { grid-area: 1 / 1; display: flex; align-items: center; gap: 5px; transition: opacity .2s, transform .35s var(--settle); }
.mz__cta svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round; }
.mz__cta-b { opacity: 0; transform: translateY(10px); }
.mz[data-act="press"] .mz__cta { transform: scale(.95); }
.mz[data-act="ok"] .mz__cta { background: var(--ok); }
.mz[data-act="ok"] .mz__cta-a { opacity: 0; transform: translateY(-10px); }
.mz[data-act="ok"] .mz__cta-b { opacity: 1; transform: none; }

/* 1: the back-office */
.mz__bo .mz__bar { top: 32px; }
.mz__fields { left: 24px; top: 84px; width: 250px; display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.mz__fields span { display: flex; flex-direction: column; gap: 2px; padding: 9px 11px; border: 1px solid var(--line); border-radius: 10px; font-size: 13px; font-weight: 600; color: var(--ink); }
.mz__outs { left: 24px; top: 278px; width: 250px; display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.mz__outs small { flex-basis: 100%; margin-bottom: 2px; }
.mz__outs i { padding: 4px 11px; border: 1.5px solid var(--line); border-radius: 999px; font-size: 12px; font-style: normal; font-weight: 600; color: var(--muted); transition: border-color .3s, color .3s, background .3s; }
.mz[data-show="0"][data-act="ok"] .mz__outs i { border-color: var(--ok); background: var(--ok-soft); color: var(--ok-ink); }
.mz[data-show="0"][data-act="ok"] .mz__outs i:nth-of-type(2) { transition-delay: .12s; } .mz[data-show="0"][data-act="ok"] .mz__outs i:nth-of-type(3) { transition-delay: .24s; }
.mz__prev { left: 296px; top: 84px; }
.mz__foot { left: 2px; right: 2px; top: 382px; display: flex; align-items: center; height: 66px; padding: 0 22px; border-top: 1px solid var(--line); border-radius: 0 0 12px 12px; background: #fafbfc; }
.mz__state { display: grid; font-size: 12.5px; font-weight: 600; color: var(--muted); }
.mz__state i { width: 7px; height: 7px; border-radius: 50%; background: var(--ok); box-shadow: 0 0 0 3px rgba(0, 191, 99, .18); }
.mz__state .mz__cta-b { color: var(--ok-ink); }
.mz__bo .mz__cta { left: 336px; top: 395px; width: 200px; }

/* 2: a MaaS app, a phone as 01's: the camera, the status bar, the trip, its legs */
.mz__cam { left: 243px; top: 12px; width: 74px; height: 22px; border-radius: 11px; background: #23262f; }
.mz__status { left: 190px; top: 12px; width: 180px; display: flex; justify-content: space-between; align-items: center; height: 22px; font-size: 12px; color: var(--ink); }
.mz__status span { display: flex; align-items: center; gap: 4px; }
.mz__app .mz__brand { left: 186px; top: 50px; }
.mz__trip { left: 182px; top: 78px; width: 196px; display: flex; flex-direction: column; gap: 1px; padding: 10px 12px; border-radius: 12px; background: #f3f5f8; }
.mz__trip b { font-size: 13px; color: var(--ink); }
.mz__trip small { font-size: 11px; color: var(--muted); }
.mz__route { left: 200px; top: 162px; height: 184px; border-left: 2px dashed var(--line-strong); }
.mz__leg { left: 186px; width: 190px; display: flex; align-items: center; gap: 8px; font-size: 12px; font-weight: 600; color: var(--ink); }
.mz__leg em { margin-left: auto; font-style: normal; color: var(--muted); }
.mz__leg--bus { top: 142px; }
.mz__leg--bike { top: 346px; }
.mz__mode { display: grid; place-items: center; width: 30px; height: 24px; border-radius: 8px; background: #e7f6ee; }
.mz__mode svg { width: 18px; height: 18px; }
.mz__bike { background: #e8f0ff; }
.mz__bike svg { width: 17px; height: 17px; fill: none; stroke: #3b6fd8; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.mz__app .mz__cta { left: 182px; top: 414px; width: 196px; }

/* 3: a partner's web shop */
.mz__web .mz__bar { top: 52px; }
.mz__web .mz__brand { left: 30px; top: 98px; }
.mz__rows { left: 30px; top: 292px; width: 240px; display: flex; flex-direction: column; }
.mz__rows span, .mz__sum, .mz__tot { display: flex; justify-content: space-between; align-items: center; padding: 11px 0; border-bottom: 1px solid var(--line); font-size: 13px; color: var(--ink); }
.mz__rows span { font-weight: 600; }
.mz__h { left: 300px; top: 92px; font-family: var(--font-display); font-size: 26px; color: var(--black); }
.mz__sum { left: 300px; top: 140px; width: 230px; border-top: 1px solid var(--line); color: var(--muted); }
.mz__sum b { color: var(--ink); }
.mz__tot { left: 300px; top: 184px; width: 230px; font-weight: 600; }
.mz__card { left: 300px; top: 248px; width: 230px; display: flex; align-items: center; gap: 10px; padding: 10px 12px; border: 1px solid var(--line); border-radius: 10px; font-size: 13px; font-weight: 600; color: var(--ink); }
.mz__card .mx__bank { display: block; width: 30px; height: 20px; }
.mz__web .mz__cta { left: 300px; top: 358px; width: 230px; }

/* 4: a newsagent's till: its screen, then the printer at its foot; once sold, the ticket comes out */
.mz__kiosk::after { content: ""; position: absolute; left: 142px; top: 372px; width: 276px; height: 66px; border-top: 1px solid var(--line); border-radius: 0 0 22px 22px; background: #f3f5f8; }
.mz__kiosk .mz__brand { left: 162px; top: 28px; }
.mz__till { left: 362px; top: 31px; }
.mz__seg { left: 160px; top: 238px; width: 240px; display: grid; grid-template-columns: 1fr 1fr; padding: 3px; border-radius: 10px; background: #eef0f4; font-size: 12px; font-weight: 600; text-align: center; color: var(--muted); }
.mz__seg > * { padding: 7px 0; border-radius: 8px; }
.mz__seg b { background: var(--white); box-shadow: 0 1px 3px rgba(13, 14, 22, .14); color: var(--ink); }
.mz__kiosk .mz__cta { left: 160px; top: 296px; width: 240px; height: 44px; }
.mz__slot { left: 220px; top: 400px; z-index: 1; width: 120px; height: 6px; border-radius: 3px; background: #23262f; }
.mz__paper { left: 228px; top: 403px; z-index: 1; width: 104px; height: 74px; overflow: hidden; }
.mz__paper i { display: block; height: 70px; border: 1px solid var(--line); border-top: 0; border-radius: 0 0 4px 4px; background: var(--white) repeating-linear-gradient(180deg, transparent 0 12px, #e3e6ec 12px 14px) 14px 10px / 60px 100% no-repeat; box-shadow: 0 8px 14px -8px rgba(13, 14, 22, .3); transform: translateY(-100%); transition: transform .2s var(--exit); }
.mz[data-show="3"][data-act="ok"] .mz__paper i { transform: none; transition: transform .9s .15s var(--settle); }

/* 5: the countries, round, on a ring */
.mz__pick { left: 180px; top: 332px; width: 200px; text-align: center; }
.mz__c { left: var(--x); top: var(--y); width: 52px; height: 52px; margin: -26px 0 0 -26px; display: grid; place-items: center; padding: 0; border: 1.5px solid var(--line); border-radius: 50%; background: var(--white); box-shadow: 0 10px 20px -14px rgba(22, 30, 60, .45); font: 600 14px var(--font-body); letter-spacing: .02em; color: var(--muted); cursor: pointer; transform: scale(.6); opacity: 0; transition: transform .5s var(--pop), opacity .3s, border-color .25s, color .25s, background .25s, box-shadow .25s; }
.mz[data-show="4"] .mz__c { transform: none; opacity: 1; }
.mz[data-show="4"] .mz__c:nth-of-type(2) { transition-delay: .05s; } .mz[data-show="4"] .mz__c:nth-of-type(3) { transition-delay: .1s; } .mz[data-show="4"] .mz__c:nth-of-type(4) { transition-delay: .15s; }
.mz[data-show="4"] .mz__c:nth-of-type(5) { transition-delay: .2s; } .mz[data-show="4"] .mz__c:nth-of-type(6) { transition-delay: .25s; }
.mz__c[aria-pressed="true"] { border-color: var(--brand); background: var(--mint); color: var(--brand-ink); box-shadow: 0 0 0 4px rgba(98, 68, 187, .14), 0 10px 20px -14px rgba(22, 30, 60, .45); }
@media (hover: hover) {
  .mz[data-show="4"] .mz__c:hover { transform: translateY(-3px); border-color: var(--line-strong); color: var(--ink); box-shadow: 0 14px 24px -14px rgba(22, 30, 60, .55); transition-delay: 0s; }
  .mz__c[aria-pressed="true"]:hover { border-color: var(--brand); color: var(--brand-ink); }
}

/* the ticket: one, moving to where each step holds it */
.mz__tkt { position: absolute; left: 296px; top: 106px; z-index: 2; width: 240px; display: flex; flex-direction: column; padding: 14px 16px 15px; border-radius: 16px; background: var(--brand-ink) radial-gradient(circle at 100% 0, rgba(255, 255, 255, .2), transparent 55%); color: var(--white); box-shadow: 0 1px 2px rgba(13, 14, 22, .08), 0 20px 34px -18px rgba(75, 49, 150, .65); transition: left .9s var(--spring), top .9s var(--spring), width .9s var(--spring); }
.mz[data-screen="1"] .mz__tkt { left: 182px; top: 182px; width: 196px; }
.mz[data-screen="2"] .mz__tkt { left: 30px; top: 134px; }
.mz[data-screen="3"] .mz__tkt { left: 160px; top: 70px; }
.mz[data-screen="4"] .mz__tkt { left: 160px; top: 136px; }
.mz__via { align-self: flex-start; margin-bottom: 10px; padding: 3px 9px; border-radius: 999px; background: rgba(255, 255, 255, .18); font-size: 11px; font-weight: 600; white-space: nowrap; transition: opacity .25s; }
.mz__via:empty { display: none; }
.mz__op { display: flex; align-items: center; gap: 7px; font-size: 12px; font-weight: 600; }
.mz__op i { display: grid; place-items: center; width: 20px; height: 20px; border-radius: 6px; background: var(--white); }
.mz__op svg { width: 16px; height: 16px; }
.mz__tkt > b { margin-top: 10px; font-family: var(--font-display); font-size: 28px; font-weight: 400; line-height: 1.1; white-space: nowrap; }
.mz__tkt > small { margin-top: 6px; font-size: 12px; opacity: .85; }
/* its passport, in the last step only */
.mz__pp { max-height: 0; margin-top: 0; padding-top: 0; padding-bottom: 0; overflow: hidden; opacity: 0; transition: max-height .5s var(--settle), margin-top .5s var(--settle), padding .5s var(--settle), opacity .3s; }
.mz[data-show="4"] .mz__pp { max-height: 70px; margin-top: 12px; padding-top: 8px; padding-bottom: 8px; opacity: 1; }
.mz[data-fmt="aztec"] .mx__aztec, .mz[data-fmt="qr"] .mx__qr, .mz[data-fmt="nfc"] .mx__nfc, .mz[data-fmt="bank"] .mx__bank { display: block; }
.mz__tkt.is-swap { animation: mxSwap .55s var(--pop); }

.mz__say { display: none; margin: 16px 0 0; font-size: 15px; line-height: 1.6; color: var(--muted); text-wrap: pretty; }
.mz__say b { color: var(--brand-ink); }
.mz[data-screen="4"] .mz__say { display: block; }

@media (max-width: 980px) {
  .mz.dia.dia--art { background: none; } /* as 01 and 02: the film on the page itself */
  .mz__fit { order: 1; cursor: pointer; touch-action: pan-y pinch-zoom; }
  .mz__ring .mz__c::after { content: ""; position: absolute; inset: -14px; } /* a thumb's reach around each country: the scene is small here */
  .mz .app__info { order: 2; height: auto; min-height: 152px; } /* its tallest step (the standard's line), so the page under it stays put */
  /* in the last step the standard's line takes the words' place, so the panel keeps its height and the page under it stays put */
  .mz[data-screen="4"] .app__txt { display: none; }
  .mz__say { margin: 0; font-size: 15px; line-height: 1.5; }
}
@media (max-width: 380px) {
  .mz .app__info { min-height: 180px; }
}

/* ---------- cases ---------- */
.cases__head { display: flex; justify-content: space-between; align-items: end; gap: 24px; flex-wrap: wrap; margin-bottom: 24px; }
.cases__head > div { max-width: 760px; }
.cases__list { border-top: 1px solid var(--hairline-strong); }
.case { border-bottom: 1px solid var(--hairline-strong); }

.case__row,
.case__panel-grid {
  display: grid;
  grid-template-columns: minmax(150px, .9fr) minmax(150px, .9fr) minmax(0, 2fr) 32px;
  gap: 24px;
}

.case__row {
  align-items: center;
  width: 100%;
  padding: 26px 12px;
  border: 0;
  background: transparent;
  text-align: left;
  color: var(--ink);
  cursor: pointer;
  transition: background .2s;
}

.case__row:hover, .case.is-open > .case__row { background: var(--mint-soft); }

.case__num { font-family: var(--font-display); font-size: clamp(30px, 2.5vw, 36px); line-height: 1; color: var(--black); font-variant-numeric: tabular-nums; }
.case__num-label { margin-top: 6px; font-size: 13px; line-height: 1.3; color: var(--brand-ink); }
.case__brand { height: 40px; display: flex; align-items: center; } /* the logos sized by eye to one weight, centred on one line, so the words under them line up */
.case__logo { display: block; max-width: 100%; object-fit: contain; object-position: left center; }
.case__domain { margin-top: 10px; font-size: 13px; color: var(--muted); }
.case__title { font-size: 16px; line-height: 1.5; color: var(--text); text-wrap: pretty; }
.case__icon { display: flex; justify-content: flex-end; color: var(--brand-ink); }
.case__icon svg { transition: transform .25s ease; } /* rotate the icon itself, not the wider cell, so it turns in place */
.case.is-open .case__icon svg { transform: rotate(45deg); }

.case > .acc__panel { transition: grid-template-rows .35s var(--ease-out), background .2s; }
.case.is-open > .acc__panel { background: var(--mint-soft); }

.case__panel-grid { padding: 4px 12px 32px; }
.case__aside { grid-column: 1 / span 2; display: flex; flex-direction: column; gap: 24px; min-width: 0; }
.case__meta { display: flex; flex-direction: column; gap: 16px; min-width: 0; padding-top: 2px; }
.case__field { display: flex; flex-direction: column; gap: 4px; }
.case__field-value { font-size: 14px; line-height: 1.45; color: var(--ink); }
.case__stack { font-family: var(--font-mono); font-size: 12px; line-height: 1.7; color: var(--muted); }

.case__figure { width: 140px; margin: 0; display: flex; flex-direction: column; gap: 8px; }
.case__figure img { display: block; width: 100%; height: auto; aspect-ratio: 275 / 305; object-fit: contain; }
.case__figure figcaption { font-size: 12px; line-height: 1.45; color: var(--muted); }

.case__story { grid-column: 3; display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.case__facts { display: flex; flex-direction: column; gap: 14px; margin: 0; }
.case__kv { display: grid; grid-template-columns: 96px minmax(0, 1fr); gap: 14px; align-items: baseline; }
.case__kv dt { font-size: 13px; font-weight: 600; color: var(--brand-ink); }
.case__kv dd { margin: 0; font-size: 14px; line-height: 1.6; color: var(--text); text-wrap: pretty; }
.case__kv--result { padding-top: 14px; border-top: 1px solid var(--hairline); }
.case__kv--result dd { font-size: 15px; line-height: 1.55; font-weight: 600; color: var(--ink); }

.case__links { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 24px; margin-top: 2px; padding-left: 110px; }

/* the way over to payments.edvantis.com, under the cases: one quiet row, a card's glass icon, the words, the address */
.sibling { display: flex; align-items: center; gap: 16px; margin-top: 32px; padding: 18px 22px; border: 1px solid var(--line); border-radius: 16px; color: var(--ink); transition: border-color .25s, box-shadow .35s; }
.sibling:hover { color: var(--ink); border-color: var(--brand); box-shadow: 0 1px 2px rgba(13, 14, 22, .05), 0 10px 24px -12px rgba(13, 14, 22, .18); }
.sibling__ic { flex: none; width: 40px; height: 40px; }
.sibling__text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.sibling__text b { font-size: 16px; font-weight: 600; }
.sibling__text span { font-size: 14px; line-height: 1.5; color: var(--muted); }
.sibling__go { display: inline-flex; align-items: center; gap: 6px; margin-left: auto; font-size: 14px; font-weight: 600; color: var(--brand-ink); white-space: nowrap; }
/* phones: the words beside the icon, the address under them */
@media (max-width: 600px) {
  .sibling { display: grid; grid-template-columns: 40px minmax(0, 1fr); gap: 10px 16px; align-items: start; }
  .sibling__go { grid-column: 2; margin-left: 0; }
}

/* ---------- why ---------- */
.why__head { display: flex; justify-content: space-between; align-items: flex-end; flex-wrap: wrap; gap: 24px 48px; margin-bottom: 40px; }
.why__head > div { max-width: 760px; }
.why__lead { max-width: none; margin-top: 14px; text-wrap: pretty; } /* beside the rating, as wide as the heading */

/* Clutch stars: grey track with an orange fill clipped to the rating (--rating: 0-5, halves included).
   Each star is 16px wide with a 2px gap, so the fill width is rating * 18px - 1px. */
.stars {
  --star: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='16' viewBox='0 0 18 16'%3E%3Cpath fill='%23dfe2ea' d='M8 .6l2.35 4.76 5.25.77-3.8 3.7.9 5.23L8 12.6l-4.7 2.46.9-5.23-3.8-3.7 5.25-.77z'/%3E%3C/svg%3E");
  --star-on: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='16' viewBox='0 0 18 16'%3E%3Cpath fill='%23f0643c' d='M8 .6l2.35 4.76 5.25.77-3.8 3.7.9 5.23L8 12.6l-4.7 2.46.9-5.23-3.8-3.7 5.25-.77z'/%3E%3C/svg%3E");
  display: block;
  width: 88px;
  height: 16px;
  background: var(--star) repeat-x 0 0 / 18px 16px;
}

.stars__fill { display: block; width: calc(var(--rating, 5) * 18px - 1px); max-width: 100%; height: 100%; background: var(--star-on) repeat-x 0 0 / 18px 16px; }

/* overall Clutch rating next to the section title */
.rating { display: flex; align-items: center; gap: 12px; color: var(--ink); }
.rating:hover { color: var(--ink); }
.rating__score { font-family: var(--font-display); font-size: clamp(30px, 2.5vw, 36px); line-height: 1; }
.rating__meta { display: flex; flex-direction: column; gap: 6px; }
.rating__src { font-size: 13px; color: var(--muted); }
/* the company in figures, beside the rating: how its clients rate it, and how many we are */
.why__facts { display: flex; align-items: center; }
.why__facts > * + * { margin-left: 28px; padding-left: 28px; border-left: 1px solid var(--line); }
.why__fact { display: flex; align-items: center; gap: 12px; }
.why__fact .rating__score small { margin-left: 2px; font-size: .7em; color: var(--brand); }
@media (max-width: 760px) {
  .why__facts { flex-wrap: wrap; row-gap: 20px; }
  .why__facts > .rating { flex-basis: 100%; }
  .why__facts > .rating + * { margin-left: 0; padding-left: 0; border-left: 0; }
}
.rating:hover .rating__src { color: var(--clutch); }

/* client reviews: one row of three cards, wrapping on narrow screens */
.reviews {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
  gap: 16px;
  margin-bottom: 16px; /* the panel below sits in the same grid as the cards */
}

.review { margin: 0; padding: 24px; background: var(--white); border: 1px solid var(--line); border-radius: 16px; }
/* the head: photo on the left; stars and the Clutch link on the first line, then name and role across the full width,
   so narrow cards don't squeeze them beside the link */
.review__head { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; column-gap: 14px; row-gap: 2px; align-items: center; margin-bottom: 18px; }
.review__head > :first-child { grid-row: 1 / span 3; align-self: start; } /* the photo, framed or not */
.review__who { display: contents; }
.review__who .stars { grid-column: 2; justify-self: start; margin-bottom: 4px; }
.review__name, .review__role { grid-column: 2 / -1; }
.review__head > .review__src { grid-column: 3; grid-row: 1; }
.review__name { font-size: 15px; font-weight: 600; line-height: 1.3; color: var(--ink); }
.review__role { font-size: 13px; line-height: 1.4; color: var(--muted); }
.review__src { display: inline-flex; align-items: center; gap: 3px; font-size: 13px; color: var(--muted); transition: color .2s; } /* quiet: the rating above already says Clutch */
.review__src:hover { color: var(--clutch); }
.review__quote { margin: 0; }
.review__quote p { margin: 0; font-size: 16px; line-height: 1.55; color: var(--ink); text-wrap: pretty; }
/* below three columns (1000px): one row to swipe instead of 2 + 1, the next card peeking in from the edge; the row runs
   to the screen edges and snaps to each card. The cards show at once, since a card off to the side would otherwise
   only fade in mid-swipe. */
@media (max-width: 1000px) {
  .reviews { display: flex; gap: 12px; margin: 0 calc(-1 * var(--gutter)) 16px; padding: 0 var(--gutter); overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x mandatory; scroll-padding: 0 var(--gutter); scrollbar-width: none; }
  .reviews::-webkit-scrollbar { display: none; }
  .review { flex: 0 0 min(420px, 84%); scroll-snap-align: start; }
  @media (min-width: 600px) { .review { flex-basis: calc(50% - 30px); } } /* two whole cards, the third peeking */
  .js .reviews .reveal { opacity: 1; transform: none; }
}

.avatar { flex: none; display: block; border-radius: 50%; object-fit: cover; }

/* portraits shot on pure white: multiply them onto a light tint so the white reads as a soft circle, not as a hole */
.avatar-frame { flex: none; display: block; border-radius: 50%; background: #eceef3; isolation: isolate; }
.avatar--blend { mix-blend-mode: multiply; }
/* no photo yet: the initials on the page's mint, the size of a photo */
.avatar--initials { display: grid; place-items: center; width: 52px; height: 52px; background: var(--mint); font-family: var(--font-display); font-size: 18px; color: var(--brand-ink); }
/* a quote with no rating (from a case study, not a review): the name takes the stars' line */
.review__who:not(:has(.stars)) .review__name { grid-column: 2; grid-row: 1; }

/* 4 columns, then 2 below 1000px, then 1 below 560px */
.reasons {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(clamp(calc((100% - 120px) / 4), (1000px - 100%) * 999, clamp(calc((100% - 40px) / 2), (560px - 100%) * 999, 100%)), 1fr));
  gap: 48px 40px;
}

/* the reasons and the certificates share one panel under the reviews: the service pictures' soft gradient without
   their dot grid (this one holds text); each reason opens with one of edvantis.com's own duotone icons */
.why__panel {
  padding: 36px 32px 24px;
  border-radius: 16px;
  background:
    radial-gradient(120% 80% at 15% 0%, #efebfb 0%, rgba(239, 235, 251, 0) 60%),
    radial-gradient(90% 70% at 100% 100%, #e8ecf4 0%, rgba(232, 236, 244, 0) 65%),
    #f6f7f9;
}
.reason { display: flex; flex-direction: column; gap: 10px; }
.reason__ico { display: block; width: 36px; height: 36px; margin-bottom: 6px; }
.reason h3 { margin: 0; font-size: 18px; line-height: 1.2; font-weight: 600; color: var(--black); text-wrap: balance; }
.reason p { margin: 0; font-size: 16px; line-height: 1.55; color: var(--text); text-wrap: pretty; }
/* phones: the panel runs to the screen edges like the reviews row above (its text as wide as the rest of the page,
   not inset twice), and the icon sits beside the title */
@media (max-width: 560px) {
  .why__panel { margin: 0 calc(-1 * var(--gutter)); padding: 36px var(--gutter) 24px; border-radius: 0; }
  .reasons { gap: 36px; }
  .reason { display: grid; grid-template-columns: 24px minmax(0, 1fr); align-items: center; gap: 10px 12px; }
  .reason__ico { width: 24px; height: 24px; margin: 0; }
  .reason p { grid-column: 1 / -1; }
}

.proof { display: flex; flex-wrap: wrap; align-items: center; gap: 20px 28px; margin-top: 36px; padding-top: 20px; border-top: 1px dashed rgba(0, 0, 0, .08); }
.proof__logos { display: flex; flex-wrap: wrap; align-items: center; gap: 22px; }
.proof__logos img { display: block; height: 56px; width: auto; }
.proof__standards { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-left: auto; }
.proof__standards .label { margin-right: 6px; }
.proof__standards .tag { font-size: 12px; padding: 4px 9px; background: none; }

/* ---------- contact ---------- */
/* side by side, the words and the form start level at the top (the heading with the form's edge); the rule sits 28 px
   from the lead and from the steps */
.contact__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 380px), 1fr));
  gap: 56px 80px;
  align-items: start;
}

.contact .h2 { margin-bottom: 18px; }
.contact .section-lead { max-width: 460px; margin-bottom: 28px; }
.contact__rule { width: 100%; height: 0; margin: 0; border: 0; border-top: 1px solid var(--line); }

.contact__next { display: grid; gap: 14px; margin: 28px 0 0; padding: 0; list-style: none; counter-reset: next; }
.contact__next li { position: relative; display: flex; flex-direction: column; gap: 2px; padding-left: 38px; counter-increment: next; font-size: 14px; line-height: 1.45; color: var(--text); }
.contact__next li::before { content: counter(next); position: absolute; left: 0; top: 1px; display: grid; place-items: center; width: 24px; height: 24px; border-radius: 50%; background: var(--mint); color: var(--brand-ink); font-size: 12px; font-weight: 600; }
.contact__next b { font-weight: 600; color: var(--ink); }

.form { display: flex; flex-direction: column; padding: 28px; border-radius: 16px; background: var(--ground); }
.form__fields { display: flex; flex-direction: column; gap: 12px; }
.form__fields[hidden] { display: none; }

/* Fields with floating labels: the label sits inside the empty field and moves up, small, once the field is
   focused or filled (placeholder=" " lets :placeholder-shown tell an empty field apart). An example placeholder,
   where there is one, only shows while the field is focused. 16px text so iOS doesn't zoom in on focus. */
.fl { position: relative; }
.fl__input {
  display: block;
  width: 100%;
  height: 58px;
  padding: 24px 15px 8px;
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  background: var(--white);
  color: var(--black);
  font-size: 16px;
  line-height: 1.4;
  transition: border-color .15s, box-shadow .15s;
}
textarea.fl__input { height: auto; min-height: 120px; padding-top: 28px; resize: vertical; }
.fl__input::placeholder { color: transparent; transition: color .15s; }
.fl__input:focus::placeholder { color: var(--faint); }
.fl__input:hover { border-color: #b4bacb; }
.fl__input:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px rgba(98, 68, 187, .16); }
.fl__label {
  position: absolute;
  left: 16px;
  top: 18px;
  font-size: 16px;
  line-height: 1.4;
  color: var(--muted);
  pointer-events: none;
  transform-origin: left top;
  transition: transform .18s var(--ease-out), color .15s;
}
.fl__input:focus + .fl__label,
.fl__input:not(:placeholder-shown) + .fl__label { transform: translateY(-10px) scale(.75); }
.fl__input:focus + .fl__label { color: var(--brand-ink); }
.fl__req { margin-left: 2px; color: var(--error); }

.fl__err { margin: 6px 2px 0; font-size: 13px; line-height: 1.4; color: var(--error); }
.fl__err:empty { display: none; }
.is-invalid .fl__input { border-color: var(--error); }
.is-invalid .fl__input:focus { box-shadow: 0 0 0 3px rgba(211, 41, 74, .14); }
.is-invalid .fl__label { color: var(--error); }

.form__consent { margin: 2px 0 4px; }
.check { display: flex; align-items: flex-start; gap: 10px; font-size: 13px; line-height: 1.5; color: var(--muted); cursor: pointer; }
.check input { flex: none; appearance: none; width: 18px; height: 18px; margin: 1px 0 0; border: 1px solid var(--line-strong); border-radius: 4px; background: var(--white) center / 12px no-repeat; cursor: pointer; transition: background-color .15s, border-color .15s; }
.check input:checked { border-color: var(--brand); background-color: var(--brand); background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7.5'/%3E%3C/svg%3E"); }
.check a { color: var(--ink); text-decoration: underline; text-decoration-color: var(--line-strong); text-underline-offset: 2px; }
.check a:hover { color: var(--brand-ink); text-decoration-color: currentColor; }
.is-invalid .check input { border-color: var(--error); }
.form__consent .fl__err { margin-left: 28px; }

.form__foot { display: flex; justify-content: space-between; flex-wrap: wrap; gap: 8px 16px; margin-top: 4px; font-size: 13px; color: var(--muted); }
.form__foot a { font-weight: 600; }
.form__foot a:hover { color: var(--brand); }
.form__error { margin: 0; padding: 10px 14px; border-radius: 10px; background: rgba(211, 41, 74, .07); font-size: 14px; line-height: 1.45; color: var(--error); }
.form__error a { font-weight: 600; color: inherit; text-decoration: underline; }
.form__error[hidden] { display: none; }
.form__captcha { margin: 2px 0 0; font-size: 12px; line-height: 1.45; color: var(--faint); } /* legal small print, kept quiet */
.form__captcha a { color: inherit; font-weight: 400; }
.form__captcha a:hover { text-decoration: underline; }
.grecaptcha-badge { visibility: hidden; } /* Google allows hiding it when the form carries the notice above */
.form button[type="submit"][aria-busy="true"] { opacity: .7; cursor: progress; }

/* after sending: the fields give way to a confirmation, in a card that keeps its height (main.js) */
.form:has(.form__done:not([hidden])) { background: radial-gradient(90% 60% at 50% 0%, rgba(98, 68, 187, .12), transparent 70%), var(--ground); }
.form__done { flex: 1; display: flex; flex-direction: column; justify-content: center; align-items: center; gap: 12px; padding: 24px 8px; text-align: center; font-size: 15px; line-height: 1.55; color: var(--text); }
.form__done[hidden] { display: none; }
.form__done:focus { outline: none; }
.form__done-icon { display: grid; place-items: center; width: 72px; height: 72px; margin-bottom: 8px; border-radius: 50%; background: var(--white); border: 1px solid rgba(98, 68, 187, .35); box-shadow: 0 0 0 10px rgba(98, 68, 187, .08), 0 14px 30px -14px rgba(75, 49, 150, .45); color: var(--brand); animation: doneIn .45s cubic-bezier(.2, .9, .3, 1.3) both; }
.form__done-icon path { stroke-dasharray: 1; stroke-dashoffset: 1; animation: doneTick .4s .3s ease-out forwards; }
@keyframes doneIn { from { opacity: 0; transform: scale(.6); } }
@keyframes doneTick { to { stroke-dashoffset: 0; } }
@media (prefers-reduced-motion: reduce) { .form__done-icon path { stroke-dashoffset: 0; } }
.form__done p { margin: 0; }
.form__done-title { font-family: var(--font-display); font-size: 34px; line-height: 1.15; color: var(--ink); }
.form__done-text { max-width: 340px; font-size: 16px; text-wrap: balance; }
.form__done-note { font-size: 13px; color: var(--muted); }
.form__done a { font-weight: 600; color: var(--brand-ink); }
.form__done .form__done-more { margin-top: 18px; padding: 10px 16px; border: 1px solid var(--line); border-radius: 999px; background: var(--white); color: var(--ink); }
.form__done .form__done-more:hover { border-color: var(--brand); color: var(--brand-ink); }

/* ---------- footer ---------- */
.site-footer { padding: 28px 0; border-top: 1px solid var(--hairline); }
.site-footer__inner { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 20px; font-size: 13px; color: var(--muted); }
.site-footer__brand { display: flex; align-items: center; gap: 14px; }
.site-footer__brand img { display: block; height: 20px; width: auto; }
.site-footer__links { display: flex; gap: 22px; }
.site-footer__links a { color: var(--muted); }
.site-footer__links a:hover { color: var(--black); }

/* ---------- draft copy ---------- */
/* ?drafts in the address marks the copy still to be confirmed by the team (data-draft, CONTENT-REVIEW.md) */
.show-drafts [data-draft] { outline: 2px dashed var(--warn); outline-offset: 4px; background-color: rgba(255, 214, 0, .1); }
.drafts-note { position: fixed; right: 16px; bottom: 16px; z-index: 60; padding: 8px 14px; border-radius: 999px; background: #8a6100; color: var(--white); font-size: 13px; font-weight: 600; box-shadow: 0 10px 24px -12px rgba(0, 0, 0, .5); }

/* ---------- responsive ---------- */

/* hero on short desktop screens: a little less room above the copy */
@media (min-width: 1100px) and (max-height: 828px) { .hero__grid { padding-top: 32px; } }

@media (min-width: 1001px) {
  .mobile-menu { display: none; }
}

/* below 1000 px the sections and edvantis.com don't fit in one bar: they move to the menu together,
   so no width loses a link; "Talk with us" stays in the bar until phones */
@media (max-width: 1000px) {
  .site-nav { display: none; }
  .burger { display: inline-flex; }
  .header-cta { margin-left: auto; }
}

@media (min-width: 861px) {
  .mobile-menu__cta { display: none; } /* the bar already shows it */
}

@media (max-width: 860px) {
  .site-nav, .header-cta { display: none; }
  .burger { display: inline-flex; }

  /* one column: the area's head, then the diagram as the picture of the service, then the details. The text
     column dissolves (display: contents) so its accordion can follow the diagram. */
  .svc { grid-template-columns: minmax(0, 1fr); gap: 0; padding: var(--section-y) 0; }
  .svc__head { margin-bottom: 20px; }
  .svc__text { display: contents; }
  .svc--wide .svc__text { display: grid; grid-template-columns: minmax(0, 1fr); order: 3; } /* a full-width area keeps its label and lead with its accordion */
  .svc .dia { order: 2; margin: 4px 0 24px; padding: 20px; }
  .svc .ride { margin: 4px 0 24px; } /* 01 as 02 and 03: the same room above and below its picture */
  .svc .app.dia { padding: 0; } /* the three pictures are on the page itself, at the page's gutter */
  .svc .acc { order: 3; }
  .build-title { font-size: 24px; margin-bottom: 10px; }

  /* the list runs edge to edge, so an open case's tint and the dividers reach the screen sides; text keeps the gutter */
  .cases__list { margin: 0 calc(-1 * var(--gutter)); }
  .case__row { grid-template-columns: minmax(0, 1fr) 28px; gap: 10px 16px; padding: 22px var(--gutter); }
  .case__row > * { grid-column: 1; }
  .case__row > .case__icon { grid-column: 2; grid-row: 1; }
  .case__panel-grid { grid-template-columns: minmax(0, 1fr); gap: 24px; padding: 0 var(--gutter) 28px; }
  .case__panel-grid > * { grid-column: 1 / -1; }

}

@media (max-width: 760px) {
  .hero__grid { margin-top: 0; padding: 28px var(--gutter) 36px; gap: 32px; }
  .hero__actions > .btn { flex: 1 1 100%; }
  /* the stage zooms to about .8 on a phone: the words that carry each scene a step up, so they still read at 11-12 px */
  .hv__job > span, .hv__op span { font-size: 12px; }
  .hv__op b { font-size: 12px; }
  .hv__iok span { font-size: 11px; white-space: nowrap; }
  .hv__vs-ok span { font-size: 13px; }
  .hv__iok b { font-size: 24px; }
  .hv__pass em, .hv__ihint, .hv__mlbl { font-size: 12px; }
  .hv__sticket span { font-size: 10.5px; }
  .hv__sticket b { font-size: 11px; }
  .hv__bo-bar b { font-size: 12px; }
  .hv__iok em { font-size: 11.5px; }
  .hv__msearch, .hv__sride, .hv__iapp { font-size: 12.5px; }

  .form { padding: 20px 16px; } /* more room for the fields on a phone */

  .stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); } /* the three in one row, none on its own */
  .stat { padding: 4px 10px 4px 12px; }
  .stat:first-child { padding-left: 0; border-left: 0; }
  .stat__value { font-size: 28px; }
  .stat__label { font-size: 13px; }

  .case__kv { grid-template-columns: minmax(0, 1fr); gap: 4px; }
  .case__links { padding-left: 0; }
}

/* ---------- 01: the ride demo (ride/ride.css styles it inside) ---------- */
.ride { grid-column: 1 / -1; min-width: 0; }
.ride__foot { margin-top: 18px; }
.ride__foot .tag { padding: 0; border: 0; background: none; font: 400 13px var(--font-body); color: var(--muted); }
.ride__foot .tag + .tag::before { content: "·"; margin: 0 8px 0 2px; color: var(--faint); } /* Built on: plain words, not code */
@media (max-width: 760px) { .ride__foot { column-gap: 14px; } .ride__foot .tag + .tag::before { display: none; } }

/* ---------- 02 and 03 in 01's way: the steps as stops, the picture on the page itself ---------- */
/* each step a stop, at its time of day (02) or its channel (03): the ones passed on a solid line, the ones ahead on a
   dotted one, the one on show open with its words (main.js, stopList). On phones the film and its words instead */
.stops { display: none; }
.stops__k { margin: 0 0 20px; font-size: 13px; font-weight: 600; color: var(--muted); }
.stops ol { margin: 0; padding: 0; list-style: none; }
/* a step only moves the classes, so everything eases into place, as in 01: the purple line grows over the dots to the
   stop reached, the stop's words open as the last one's close */
.stops button { position: relative; display: grid; grid-template-columns: 52px 18px minmax(0, 1fr); column-gap: 14px; align-items: start; width: 100%; padding: 0 0 22px; border: 0; background: none; font: inherit; text-align: left; color: inherit; cursor: pointer; transition: padding-bottom .45s var(--ease-out); }
.stops li:not(:last-child) button::before { content: ""; position: absolute; left: 73.5px; top: 21px; bottom: 0; width: 3px; background: radial-gradient(circle, #b4b9cb 1.2px, transparent 1.6px) 0 1px / 3px 7px repeat-y; }
.stops li:not(:last-child) button::after { content: ""; position: absolute; left: 74px; top: 21px; bottom: 0; width: 2px; background: var(--brand); transform: scaleY(0); transform-origin: top; transition: transform .45s var(--ease-out); }
.stops li.is-done button::after { transform: none; }
.stops time { padding-top: 2px; font-size: 13px; font-weight: 400; font-variant-numeric: tabular-nums; color: #70768e; transition: color .2s; }
.stops i { position: relative; z-index: 1; width: 14px; height: 14px; margin: 3px auto 0; border: 2.5px solid #c9ccda; border-radius: 50%; background: var(--white); transition: background .25s, border-color .25s, box-shadow .25s; }
.stops b { display: block; font-size: 16px; font-weight: 600; line-height: 1.35; color: #70768e; transition: color .2s; }
.stops small { display: grid; grid-template-rows: 0fr; margin-top: 0; opacity: 0; font-size: 15px; line-height: 1.55; color: var(--text); text-wrap: pretty; transition: grid-template-rows .45s var(--ease-out), margin-top .45s var(--ease-out), opacity .2s; } /* the words of the stop on show: darker than the other stops, so they read as its own */
.stops small > span { min-height: 0; overflow: hidden; }
.stops li.is-done i { border-color: var(--brand); background: var(--brand); }
.stops li.is-on i { border-color: var(--brand); box-shadow: 0 0 0 5px rgba(98, 68, 187, .16); }
.stops li.is-on b { color: var(--black); } /* the stop on show stands out by its colour, ring and room; every name keeps one weight, so nothing shifts as they change */
.stops li:has(+ li.is-on) button { padding-bottom: 30px; } .stops li.is-on button { padding-bottom: 34px; } /* room above and below the stop on show, so it reads as one block */
.stops li.is-on time { font-weight: 600; color: var(--brand-ink); }
.stops li.is-on small { grid-template-rows: 1fr; margin-top: 6px; opacity: 1; transition-delay: 0s, 0s, .12s; }
.stops button:hover b { color: var(--black); }
.stops button:focus-visible { outline: 2px solid var(--brand); outline-offset: 4px; border-radius: 8px; }
@media (min-width: 981px) {
  .stops { display: block; }
  .app.dia.dia--art { padding: 0; background: none; } /* as 01: the picture on the page itself, no grey stage */
  .app.dia .app__stage { grid-template-columns: var(--side) minmax(0, 1fr); justify-content: normal; align-items: start; gap: 32px var(--grid-gap); margin: 8px 0 28px; } /* the stops on the page's left edge, as 01's trip */
  .app.dia .afc__fit, .app.dia .mz__fit { justify-self: end; }
  .app__info, .mz .app__info { max-width: none; height: auto; min-height: 0; }
  .app__name, .app__txt { display: none; }
  .mz__say { margin-top: 4px; }
}
/* the way on, once the reader has let a step be (main.js, stopList): the dotted line to the next stop flows towards
   it, and that stop breathes; nothing written, nothing that jumps */
.stops.is-nudge li.is-on button::before { animation: stopFlow 1.1s linear infinite; }
.stops.is-nudge li.is-on + li i { border-color: var(--brand); animation: stopBreathe 2.4s ease-in-out infinite; }
.stops.is-nudge li.is-on + li b { color: var(--text); }
@keyframes stopFlow { from { background-position: 0 1px; } to { background-position: 0 8px; } }
@keyframes stopBreathe { 0%, 100% { box-shadow: 0 0 0 0 rgba(98, 68, 187, 0); } 50% { box-shadow: 0 0 0 6px rgba(98, 68, 187, .16); } }
