/* Event Transit Platform — marketing site
   Static, dependency-free. One accent hue; everything else is ink + surface. */

:root {
  --ink:        #10151f;
  --ink-2:      #3d4757;
  --ink-3:      #6b7688;
  --surface:    #ffffff;
  --surface-2:  #f6f8fb;
  --surface-3:  #eaeef5;
  --line:       #dbe2ec;

  /* Sampled from the logo: pin gradient #5c86a4 -> #19243b, "IQ" #2b7397. */
  --accent:     #1f6a8f;   /* 5.97:1 with white text */
  --accent-ink: #16506e;
  --accent-wash:#ebf3f8;

  /* Near-complement of the accent (hue 5° against its 199°) with a matched
     saturation, so it reads as a sibling rather than a warning sticker.
     5.26:1 on its own wash. Reserved for problem framing — never a series colour. */
  --alert:      #b23a2f;
  --alert-wash: #fdeeec;

  /* The accent is too dark to sit on the navy surfaces (2.63:1). This is the
     same hue (201° vs the accent's 199°) lifted until it carries: 8.3:1 on
     --night, 6.6:1 on --night-2, 4.5:1 even under the hero's radial highlight.
     Every accent-coloured mark on a dark background uses this, not --accent. */
  --accent-on-dark: #8cc4e2;

  --night:      #16233a;
  --night-2:    #22354c;
  --night-ink:  #a8b8cc;

  --radius: 14px;
  --radius-sm: 8px;
  --maxw: 1120px;
  --pad: clamp(20px, 5vw, 40px);

  /* Swap "Inter" for "Manrope" or "Plus Jakarta Sans" for a more geometric feel. */
  --sans: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }

/* Nothing may force the page wider than the viewport. */
html, body { max-width: 100%; overflow-x: clip; }
img, svg, table { max-width: 100%; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  font-family: var(--sans);
  color: var(--ink);
  background: var(--surface);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  font-feature-settings: "cv11", "ss01";  /* Inter: single-storey a, humanist forms */
}

h1, h2, h3 { line-height: 1.15; letter-spacing: -0.02em; margin: 0 0 .5em; }
h1 { font-size: clamp(2.1rem, 5.2vw, 3.6rem); font-weight: 780; }
h2 { font-size: clamp(1.6rem, 3.4vw, 2.4rem); font-weight: 720; }
h3 { font-size: 1.12rem; font-weight: 680; }
p  { margin: 0 0 1em; }
a  { color: var(--accent); }

.wrap { max-width: var(--maxw); margin: 0 auto; padding-inline: var(--pad); }
.section { padding-block: clamp(56px, 9vw, 104px); }
.section--tint { background: var(--surface-2); border-block: 1px solid var(--line); }

.eyebrow {
  font-size: .78rem; font-weight: 700; letter-spacing: .13em; text-transform: uppercase;
  color: var(--accent); margin-bottom: .9em;
}
/* Both dark contexts, so the hero and the dark sections can't drift apart. */
.hero .eyebrow,
.section--dark .eyebrow { color: var(--accent-on-dark); }

.lede { font-size: clamp(1.02rem, 1.6vw, 1.2rem); color: var(--ink-2); max-width: 62ch; }

/* ---------- header ---------- */
.nav {
  position: sticky; top: 0; z-index: 20;
  background: rgba(255,255,255,.86); backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
}
.nav__inner { display: flex; align-items: center; gap: 28px; height: 72px; }
.nav__brand { margin-right: auto; display: flex; align-items: center; text-decoration: none; flex: 0 0 auto; }
.brandLogo { height: 38px; width: auto; display: block; flex: 0 0 auto; }
.nav__links { display: flex; gap: 24px; }
.nav__links a { color: var(--ink-2); text-decoration: none; font-size: .93rem; font-weight: 550; }
.nav__links a:hover { color: var(--accent); }
@media (max-width: 1040px) { .nav__links { gap: 18px; } .nav__links a { font-size: .9rem; } }
@media (max-width: 880px) { .nav__links { display: none; } }
@media (max-width: 420px) {
  .nav__inner { gap: 12px; }
  .brandLogo { height: 30px; }
  .nav .btn { padding: 9px 14px; font-size: .85rem; }
}

/* ---------- buttons ---------- */
.btn {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 11px 20px; border-radius: 999px; font-weight: 640; font-size: .95rem;
  text-decoration: none; border: 1px solid transparent; cursor: pointer; white-space: nowrap;
  transition: transform .12s ease, box-shadow .12s ease, background .12s ease;
}
.btn--primary { background: var(--accent); color: #fff; box-shadow: 0 1px 2px rgba(16,21,31,.16); }
.btn--primary:hover { background: var(--accent-ink); transform: translateY(-1px); }
.btn--ghost { border-color: rgba(255,255,255,.28); color: #fff; }
.btn--ghost:hover { background: rgba(255,255,255,.08); }
.btn--quiet { border-color: var(--line); color: var(--ink); background: var(--surface); }
.btn--quiet:hover { border-color: var(--accent); color: var(--accent); }

/* ---------- hero ---------- */
.hero {
  background:
    radial-gradient(1100px 520px at 78% -12%, rgba(60,124,160,.38), transparent 60%),
    linear-gradient(180deg, var(--night) 0%, var(--night-2) 100%);
  color: #fff;
}
.hero__inner { padding-block: clamp(64px, 10vw, 116px); display: grid; gap: 46px; grid-template-columns: 1.05fr .95fr; align-items: center; }
@media (max-width: 940px) { .hero__inner { grid-template-columns: 1fr; } }
.hero h1 { color: #fff; }
.hero__sub { font-size: clamp(1.04rem, 1.7vw, 1.22rem); color: #c6d2e8; max-width: 56ch; }
.hero__cta { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 26px; }
.hero__note { margin-top: 18px; font-size: .87rem; color: #8e9dba; }

/* Product-level differentiators — deliberately not event-specific numbers.
   Styled as prose with tick marks; pills read as buttons and invited clicks. */
.benefits { list-style: none; display: flex; flex-wrap: wrap;
  gap: 9px 24px; margin: 28px 0 0; padding: 0; max-width: 58ch; }
.benefits li { position: relative; padding-left: 24px; font-size: .93rem; color: #c6d2e8; }
.benefits li::before {
  content: ""; position: absolute; left: 0; top: .48em; width: 13px; height: 7px;
  border-left: 2px solid var(--accent-on-dark); border-bottom: 2px solid var(--accent-on-dark);
  transform: rotate(-45deg);
}
@media (max-width: 560px) { .benefits { gap: 8px 18px; } }
.shot--hero .shot__frame { background: rgba(255,255,255,.05); border-color: rgba(255,255,255,.28); color: var(--night-ink); margin-inline: auto; }
.shot--hero .shot__tag { background: rgba(255,255,255,.10); border-color: rgba(255,255,255,.2); color: #9fb6ea; }

/* ---------- device mocks ----------
   Device chrome drawn in CSS so a capture needs no bezel baked in.
   --screen-ratio is the capture's own width/height, so nothing is cropped.
   Shared shell; the modifiers below only set size, bezel and corner radius. */
.device {
  --bezel: 11px;
  --radius: 40px;
  width: var(--device-w);
  margin-inline: auto;
  position: relative;
  padding: var(--bezel);
  background: linear-gradient(160deg, #39434f 0%, #1a212b 42%, #2c343f 100%);
  border-radius: var(--radius);
  box-shadow:
    0 0 0 1px rgba(255,255,255,.13) inset,
    0 26px 60px -12px rgba(0,0,0,.62),
    0 6px 18px rgba(0,0,0,.4);
}
.device__screen {
  position: relative;
  aspect-ratio: var(--screen-ratio);
  border-radius: calc(var(--radius) - var(--bezel));
  overflow: hidden;
  background: #eceff3;
  display: block;
}
.device__media { width: 100%; height: 100%; object-fit: cover; object-position: top center; display: block; }

.device--phone { --screen-ratio: 0.459; --bezel: 11px; --radius: 40px; --device-w: min(320px, 100%); }
/* No dynamic island: the capture starts at the app's own header, so an island
   would sit on top of live UI and clip the title rather than empty status bar. */
/* Side buttons */
.phone__btn { position: absolute; width: 2px; background: #464f5b; border-radius: 2px; }
.phone__btn--power { right: -2px; top: 118px; height: 54px; }
.phone__btn--vol   { left: -2px;  top: 96px;  height: 30px; }
.phone__btn--vol2  { left: -2px;  top: 134px; height: 30px; }
/* Clear of the device's drop shadow, which otherwise darkens the ground the
   caption sits on and eats its contrast. The shadow (0 26px 60px -12px) reaches
   26 + 60/2 - 12 = 44px below the frame, so anything less than that sits in it. */
.phone__caption { margin-top: 30px; text-align: center; font-size: .85rem; color: #8ea3c2; }
/* WCAG 2.2.2: looping motion longer than 5s needs a way to stop it. */
.phone__toggle {
  margin-left: 10px; padding: 3px 10px; font: inherit; font-size: .78rem; cursor: pointer;
  color: #b9cbe6; background: rgba(255,255,255,.07); border: 1px solid rgba(255,255,255,.18);
  border-radius: 999px; transition: background .15s ease, color .15s ease;
}
.phone__toggle:hover { background: rgba(255,255,255,.14); color: #fff; }
.phone__toggle:focus-visible { outline: 2px solid #7aa2ff; outline-offset: 2px; }

/* ---------- portrait signage display ----------
   A monitor rotated to portrait on a floor/counter stand, which is how the
   departures board is actually mounted at a venue. */
.device--kiosk {
  --screen-ratio: 0.7128;
  --bezel: 13px;
  --radius: 16px;
  --device-w: min(340px, 100%);
  padding-bottom: 30px;            /* chin below the panel */
}
.device--kiosk .device__screen { background: #0b0e13; }
/* Status LED on the chin */
.device--kiosk::after {
  content: "";
  position: absolute; bottom: 13px; left: 50%; transform: translateX(-50%);
  width: 5px; height: 5px; border-radius: 50%;
  background: #5ad07f; box-shadow: 0 0 7px rgba(90,208,127,.85);
}
.kioskStand { width: min(340px, 100%); margin-inline: auto; display: flex; flex-direction: column; align-items: center; }
.kioskStand__neck {
  width: 52px; height: 40px;
  background: linear-gradient(180deg, #333c47 0%, #1b222a 100%);
  clip-path: polygon(16% 0, 84% 0, 100% 100%, 0 100%);
}
.kioskStand__base {
  width: 168px; height: 11px; border-radius: 3px 3px 7px 7px;
  background: linear-gradient(180deg, #3c4653 0%, #151b22 100%);
  box-shadow: 0 16px 26px -10px rgba(0,0,0,.7);
}
.kioskFig { margin: 0; }
.kioskFig figcaption { margin-top: 22px; text-align: center; font-size: .85rem; color: #8ea3c2; }

/* A screenshot standing on its own, no device chrome. The border keeps a
   light-UI capture from bleeding into a light page, and carries enough weight
   to hold its edge against the dark section too. */
.shotImg {
  width: 100%; height: auto; display: block;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  box-shadow: 0 18px 40px -16px rgba(16,21,31,.35);
}
.section--dark .shotImg {
  border-color: rgba(255,255,255,.18);
  box-shadow: 0 26px 54px -18px rgba(0,0,0,.7);
}

/* ---------- acrylic sign holders ----------
   A counter-top holder: a translucent panel slightly larger than the print, a
   specular streak across the face, and a foot to ground it. The pair is tilted
   a degree apart so they read as two objects, not one image. */
.signs { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; align-items: end; }
.signHolder--a { transform: rotate(-1.2deg); }
.signHolder--b { transform: rotate(1.2deg); }
.signHolder__panel {
  position: relative;
  padding: 9px 9px 20px;
  border-radius: 7px;
  background: linear-gradient(155deg, rgba(255,255,255,.9), rgba(212,227,240,.55));
  border: 1px solid rgba(255,255,255,.9);
  box-shadow:
    0 0 0 1px rgba(16,21,31,.08),
    0 22px 36px -18px rgba(16,21,31,.5),
    inset 0 1px 0 rgba(255,255,255,.95);
}
.signHolder__panel img {
  display: block; width: 100%; height: auto;
  border-radius: 2px; box-shadow: 0 1px 4px rgba(16,21,31,.2);
}
/* Specular streak across the acrylic face. */
.signHolder__panel::after {
  content: ""; position: absolute; inset: 0; border-radius: 7px; pointer-events: none;
  background: linear-gradient(118deg,
    rgba(255,255,255,.5) 0 11%, rgba(255,255,255,.06) 21% 43%,
    rgba(255,255,255,.34) 49% 55%, rgba(255,255,255,0) 67%);
}
.signHolder__foot {
  display: block; width: 52%; height: 9px; margin: 0 auto;
  background: linear-gradient(180deg, rgba(228,238,247,.95), rgba(166,185,204,.85));
  border-radius: 0 0 7px 7px;
  box-shadow: 0 10px 16px -8px rgba(16,21,31,.55);
}
@media (max-width: 520px) {
  .signs { grid-template-columns: 1fr; gap: 30px; }
  .signHolder--a, .signHolder--b { transform: none; }
}

/* ---------- fanned report pages ----------
   Three sheets stacked in one grid cell, splayed with transforms. The point is
   to read as a printed document rather than a dashboard export, so the type is
   deliberately too small to read — it is a texture, not a screenshot. */
.pages {
  display: grid;
  place-items: center;
  padding: 26px 0 34px;
  perspective: 1200px;
}
.pages__sheet {
  grid-area: 1 / 1;
  width: min(300px, 58%);
  height: auto;
  border-radius: 3px;
  background: #fff;
  border: 1px solid rgba(16,21,31,.10);
  box-shadow: 0 20px 40px -14px rgba(16,21,31,.34), 0 3px 10px rgba(16,21,31,.10);
  transition: transform .35s cubic-bezier(.22,.61,.36,1);
}
.pages__sheet--left  { transform: rotate(-8deg)  translate(-30%, 1%); z-index: 1; }
.pages__sheet--right { transform: rotate(7.5deg) translate(30%, 2%);  z-index: 2; }
.pages__sheet--front { transform: rotate(-1.5deg);                    z-index: 3; }
/* Fan a little wider on hover — the whole point is that there are several. */
.pages:hover .pages__sheet--left  { transform: rotate(-11deg) translate(-38%, 0); }
.pages:hover .pages__sheet--right { transform: rotate(10deg)  translate(38%, 1%); }
.pages:hover .pages__sheet--front { transform: rotate(-1.5deg) translateY(-6px); }
@media (prefers-reduced-motion: reduce) {
  .pages__sheet, .pages:hover .pages__sheet { transition: none; }
}
/* Narrow columns cannot hold the full spread without pushing the page wide. */
@media (max-width: 560px) {
  .pages__sheet { width: min(230px, 54%); }
  .pages__sheet--left  { transform: rotate(-7deg) translate(-24%, 1%); }
  .pages__sheet--right { transform: rotate(6.5deg) translate(24%, 2%); }
  .pages:hover .pages__sheet--left  { transform: rotate(-7deg) translate(-24%, 1%); }
  .pages:hover .pages__sheet--right { transform: rotate(6.5deg) translate(24%, 2%); }
}

/* ---------- pricing estimator ---------- */
.estimator {
  display: grid; grid-template-columns: 1.1fr .9fr;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface); overflow: hidden;
}
.estimator[hidden] { display: none; }
.estimator__form { padding: 28px 30px; }
.estimator__form h3 { margin-bottom: .3em; }
.estimator__controls { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; margin-top: 22px; }
.field > label, .field legend {
  display: block; font-size: .84rem; font-weight: 640; color: var(--ink-2);
  margin-bottom: 6px; padding: 0;
}
.field input[type="number"] {
  width: 100%; padding: 9px 11px; font: inherit; color: var(--ink);
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius-sm);
}
fieldset.field { border: 0; margin: 0; padding: 0; min-width: 0; }
.field--radios label, .field--check label {
  display: flex; align-items: center; gap: 8px; margin-bottom: 5px;
  font-size: .9rem; font-weight: 400; color: var(--ink-2);
}
.field--check { grid-column: 1 / -1; }
/* Routes takes the whole row so the two tracker controls — which are one
   decision — land side by side beneath it. The input keeps a sane width. */
.field--wide { grid-column: 1 / -1; }
.field--wide input[type="number"] { max-width: 220px; }
.estimator input:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.field input[aria-invalid="true"] { border-color: var(--alert); }
#estQuote[hidden] { display: none; }
.estimator__over { margin: 0; color: var(--accent-ink); font-weight: 600; }
.estimator__over[hidden] { display: none; }

.estimator__result {
  padding: 28px 30px; background: var(--accent-wash);
  display: flex; flex-direction: column; justify-content: center;
}
.estimator__lead, .estimator__for { margin: 0; font-size: .9rem; color: var(--ink-2); }
#estDeviceField[hidden] { display: none; }

/* Caveats under the figure. Hanging indent matches .ticks so the icon sits in
   the margin like a bullet rather than pushing the first line in. */
.infoNotes { list-style: none; margin: 18px 0 0; padding: 0; display: grid; gap: 10px; }
.infoNotes li {
  position: relative; padding-left: 27px;
  font-size: .85rem; line-height: 1.5; color: var(--ink-2);
}
.infoNotes li[hidden] { display: none; }
.infoNotes li::before {
  content: "i";
  position: absolute; left: 0; top: .12em;
  width: 16px; height: 16px; border-radius: 50%;
  border: 1.5px solid var(--accent); color: var(--accent);
  font-size: .64rem; font-weight: 800; line-height: 15px; text-align: center;
}
.estimator__range {
  margin: .12em 0; font-size: clamp(1.5rem, 3.4vw, 2.15rem); font-weight: 760;
  letter-spacing: -.02em; line-height: 1.1; color: var(--accent-ink);
}
.estimator__result .btn { margin-top: 20px; align-self: flex-start; }

@media (max-width: 820px) { .estimator { grid-template-columns: 1fr; } }
@media (max-width: 560px) {
  .estimator__controls { grid-template-columns: 1fr; }
  .estimator__form, .estimator__result { padding: 22px 20px; }
}

/* ---------- asset-type band ---------- */
.beyond {
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface); padding: 30px 32px;
}
.beyond__head { max-width: 68ch; }
.beyond__head h3 { font-size: clamp(1.2rem, 2vw, 1.42rem); margin-bottom: .45em; }
.beyond__head p { color: var(--ink-2); }
.beyond__grid {
  list-style: none; margin: 26px 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 22px;
}
.beyond__grid li {
  font-size: .89rem; color: var(--ink-2);
  padding-top: 15px; border-top: 2px solid var(--accent-wash);
}
.beyond__grid strong { display: block; color: var(--ink); font-weight: 650; margin-bottom: 5px; }
@media (max-width: 900px) { .beyond__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .beyond__grid { grid-template-columns: 1fr; } .beyond { padding: 24px 20px; } }

/* Media beside copy; stacks under 820px so neither column gets squeezed. */
.kioskBand { display: grid; grid-template-columns: minmax(0,.85fr) minmax(0,1fr); gap: 48px; align-items: center; }
.kioskBand h3 { font-size: clamp(1.3rem, 2.2vw, 1.62rem); margin-bottom: .5em; }
@media (max-width: 820px) { .kioskBand { grid-template-columns: 1fr; gap: 40px; } }

/* ---------- stat tiles (hero numbers, not charts) ---------- */
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(148px, 1fr)); gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.stat { background: var(--surface); padding: 20px 18px; }
.stat__value { font-size: clamp(1.6rem, 3vw, 2.1rem); font-weight: 760; letter-spacing: -.03em; line-height: 1.05; }
/* em, not px, so the gap tracks the clamped value size instead of closing up
   as the number scales. Roughly a thin space. */
.stat__unit { font-size: .62em; font-weight: 620; color: var(--ink-3); margin-left: .22em; }
.stat__label { font-size: .82rem; color: var(--ink-3); margin-top: 6px; }
/* Hero tiles sit in a narrow column — fix to 2×2 so a 4th tile never orphans. */
.stats--pair { grid-template-columns: repeat(2, 1fr); }
.stats--onDark { background: rgba(255,255,255,.14); border-color: rgba(255,255,255,.16); }
.stats--onDark .stat { background: rgba(255,255,255,.05); }
.stats--onDark .stat__value { color: #fff; }
.stats--onDark .stat__label,
.stats--onDark .stat__unit { color: var(--night-ink); }

/* ---------- generic grids ---------- */
.grid { display: grid; gap: 22px; }
.grid--3 { grid-template-columns: repeat(auto-fit, minmax(min(268px, 100%), 1fr)); }
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr)); }

/* Phone mock beside its feature list; collapses rather than forcing page width. */
.riderGrid { display: grid; gap: 44px; grid-template-columns: 290px minmax(0, 1fr); align-items: start; }
@media (max-width: 760px) { .riderGrid { grid-template-columns: minmax(0, 1fr); } }

.card {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 26px 24px;
}
.card--flat { background: transparent; border: 0; padding: 0; }
.card h3 { margin-bottom: .45em; }
.card p:last-child { margin-bottom: 0; }
.card__ico {
  width: 38px; height: 38px; border-radius: 10px; display: grid; place-items: center;
  background: var(--accent-wash); color: var(--accent); margin-bottom: 16px;
}
.card__ico svg { width: 20px; height: 20px; }
/* Problem framing: a circular alert badge. The heading states the problem in
   words, so the colour is reinforcement, never the only signal. */
.card__ico--alert { border-radius: 50%; background: var(--alert-wash); color: var(--alert); }

/* ---------- feature list ---------- */
.ticks { list-style: none; margin: 0; padding: 0; display: grid; gap: 11px; }
.ticks li { position: relative; padding-left: 27px; color: var(--ink-2); }
.ticks li::before {
  content: ""; position: absolute; left: 0; top: .52em; width: 15px; height: 8px;
  border-left: 2px solid var(--accent); border-bottom: 2px solid var(--accent);
  transform: rotate(-45deg);
}
.ticks strong { color: var(--ink); font-weight: 640; }

/* ---------- screenshot placeholders ---------- */
.shot { margin: 0; }
.shot__frame {
  position: relative; border: 2px dashed #b9c4d6; border-radius: var(--radius);
  background:
    repeating-linear-gradient(135deg, rgba(26,79,216,.045) 0 12px, transparent 12px 24px),
    var(--surface-2);
  display: grid; place-content: center; text-align: center; gap: 8px; padding: 30px 24px;
  min-height: 210px; color: var(--ink-3);
}
.shot__frame[data-device="phone"] { min-height: 400px; width: 100%; max-width: 290px; border-radius: 26px; }
.shot__frame[data-device="wide"]  { min-height: 300px; }
.shot__frame[data-device="tall"]  { min-height: 360px; }
.shot__tag {
  display: inline-block; font-family: var(--mono); font-size: .68rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--accent); background: var(--surface);
  border: 1px solid var(--line); border-radius: 999px; padding: 3px 11px; justify-self: center;
}
.shot__note { font-size: .87rem; max-width: 40ch; margin: 0 auto; line-height: 1.5; }
.shot figcaption { font-size: .85rem; color: var(--ink-3); margin-top: 10px; }
/* Needs two classes to outrank `.shot figcaption` above — a bare
   `.device + figcaption` ties on specificity and loses on source order.
   The device shadow reaches ~44px below the frame, and it is far more visible
   on the light tint here than on the dark hero. */
.shot .device + figcaption { margin-top: 44px; }
/* --ink-3 is a light-surface ink; on navy it drops to ~2:1. */
.section--dark .shot figcaption { color: var(--night-ink); }

/* ---------- audience cards ---------- */
.aud { display: grid; gap: 0; border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.aud__col { padding: 28px 26px; background: var(--surface); border-right: 1px solid var(--line); }
.aud__col:last-child { border-right: 0; }
.aud__kicker { font-size: .74rem; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3); }
.aud__col h3 { margin-top: 10px; }
.aud__ex { font-size: .87rem; color: var(--ink-3); border-top: 1px solid var(--line); margin-top: 18px; padding-top: 14px; }

/* ---------- comparison table ---------- */
.tablewrap { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); }
table { border-collapse: collapse; width: 100%; min-width: 620px; font-size: .93rem; }
/* Top-aligned so the rating circles line up across a row regardless of how
   many lines each cell's text wraps to — that alignment is what makes the
   column scannable. */
th, td { text-align: left; padding: 14px 18px; border-bottom: 1px solid var(--line); vertical-align: top; }
thead th { background: var(--surface-2); font-weight: 660; font-size: .82rem; letter-spacing: .04em; text-transform: uppercase; color: var(--ink-3); }
tbody tr:last-child td { border-bottom: 0; }
td { color: var(--ink-3); }
td.col-ours { color: var(--accent-ink); font-weight: 620; }

/* Completeness ratings, Consumer-Reports style. Fill fraction carries the
   meaning, so it survives greyscale and colour-blindness; the cell text and the
   aria-label say the same thing, so it is never shape-alone. */
.rate { display: flex; align-items: flex-start; gap: 9px; }
.ball {
  /* Own colour, not the cell's: the muted body ink is too faint to read a
     fill fraction at this size. */
  color: #56657a;
  position: relative;
  width: 14px; height: 14px; border-radius: 50%;
  border: 1.5px solid currentColor; background-clip: padding-box;
  flex: 0 0 auto; margin-top: 3px;
}
/* Full marks get a tick inside the filled circle, so "complete" reads as an
   affirmative rather than just the darkest step on a ramp. */
.ball--100::after {
  content: "";
  position: absolute; left: 50%; top: 47%;
  width: 3px; height: 6.5px;
  border: solid #fff; border-width: 0 1.6px 1.6px 0;
  transform: translate(-50%, -55%) rotate(45deg);
}
.col-ours .ball { color: var(--accent-ink); }
/* Diverging scale: --alert (hue 5°) and --accent (hue 199°) are near
   complements, with a neutral grey midpoint — bad ← neutral → good. Colour
   only reinforces the fill fraction, which carries the meaning on its own. */
.ball--0   { color: var(--alert);  background: none; }
.ball--25  { color: var(--alert);  background: conic-gradient(currentColor 0 25%, transparent 25%); }
.ball--50  { color: #6b7688;       background: conic-gradient(currentColor 0 50%, transparent 50%); }
.ball--75  { color: var(--accent); background: conic-gradient(currentColor 0 75%, transparent 75%); }
.ball--100 { color: var(--accent); background: currentColor; }
.ballKey {
  display: flex; flex-wrap: wrap; gap: 8px 22px;
  font-size: .82rem; color: var(--ink-3);
}
.ballKey > span { display: flex; align-items: center; gap: 7px; }
.ballKey .ball { margin-top: 0; }
.col-ours { background: var(--accent-wash); }
thead th.col-ours { background: #e2e9ff; color: var(--accent-ink); }

/* Below this width four columns cannot hold a readable line length, so the
   table restacks: each row becomes a card, the row header spans it as a
   heading, and every cell carries its own column name from data-col. This
   beats horizontal scrolling, which hides the comparison being made. */
@media (max-width: 720px) {
  .tablewrap { overflow-x: visible; border: 0; background: none; border-radius: 0; }
  table { display: block; min-width: 0; }
  thead { display: none; }
  tbody { display: block; }
  /* Flex, not block, so Relay can lead each card. Stacked, the desktop
     setup→payoff build doesn't survive: burying the answer under two
     competitor cells means many readers never scroll to it. Desktop column
     order is untouched, and every cell names its own column via data-col, so
     the sequence stays comprehensible to a screen reader. */
  tbody tr {
    display: flex; flex-direction: column; margin-bottom: 14px; overflow: hidden;
    border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface);
  }
  tbody tr > th[scope="row"] {
    order: -2; background: var(--surface-2);
    font-size: .95rem; border-bottom: 1px solid var(--line);
  }
  /* Dividers run top-down, so the hoisted cell doesn't double the heading's
     border and the visually last cell doesn't double the card's. */
  tbody td { display: block; border-bottom: 0; border-top: 1px solid var(--line); }
  tbody td.col-ours { order: -1; border-top: 0; }
  tbody td::before {
    content: attr(data-col);
    display: block; margin-bottom: 5px;
    font-size: .7rem; font-weight: 680; letter-spacing: .05em;
    text-transform: uppercase; color: var(--ink-3);
  }
}
/* The brand mark replaces the column label, so it sits on the cap-height of the
   surrounding uppercase headers rather than towering over them. */
.th-logo { height: 21px; width: auto; display: block; }

/* ---------- dark section ---------- */
.section--dark { background: var(--night); color: #fff; }
.section--dark h2 { color: #fff; }
.section--dark .lede { color: #c6d2e8; }
.section--dark .card { background: rgba(255,255,255,.045); border-color: rgba(255,255,255,.12); }
.section--dark .card h3 { color: #fff; }
.section--dark .card p, .section--dark .ticks li { color: var(--night-ink); }
.section--dark .ticks strong { color: #fff; }
.section--dark .ticks li::before { border-color: var(--accent-on-dark); }

/* ---------- callout ---------- */
.callout {
  border: 1px solid var(--line); border-left: 3px solid var(--accent);
  border-radius: var(--radius); background: var(--accent-wash);
  padding: 24px 26px; color: var(--ink-2);
}
.callout__k { font-size: .76rem; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: var(--accent-ink); margin-bottom: .7em; }
.callout strong { color: var(--ink); }

/* ---------- quote ---------- */
.quote { border-left: 3px solid var(--accent); padding-left: 22px; font-size: 1.12rem; color: var(--ink-2); max-width: 60ch; }
.quote cite { display: block; margin-top: 10px; font-size: .87rem; font-style: normal; color: var(--ink-3); }

/* ---------- pricing ---------- */
.price { display: grid; gap: 22px; grid-template-columns: 1.25fr 1fr; align-items: start; }
@media (max-width: 860px) { .price { grid-template-columns: 1fr; } }
.price__box { border: 1px solid var(--line); border-radius: var(--radius); padding: 28px 26px; background: var(--surface); }
.price__box--lead { border-color: var(--accent); box-shadow: 0 8px 30px rgba(26,79,216,.10); }
.price__tag { font-size: .8rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--accent); }
.price__headline { font-size: 1.45rem; font-weight: 720; letter-spacing: -.02em; margin: 8px 0 4px; }
.price__meta { font-size: .9rem; color: var(--ink-3); }

/* ---------- parent-company colophon ----------
   A step darker than --night so it reads as beneath the site rather than part
   of it, full-bleed, and centred as a self-contained credit. */
.colophon { background: #0d1524; padding-block: 34px; font-size: .9rem; }
.colophon__inner {
  display: flex; align-items: center; justify-content: center; gap: 22px;
  text-align: left;
}
/* Already white-and-blue for a dark ground, so no knockout variant is needed
   the way the Relay wordmark needs one. */
.colophon__logo { height: 62px; width: auto; flex: 0 0 auto; display: block; }
.colophon__name { margin: 0 0 6px; color: #fff; font-size: .95rem; }
.colophon__name strong { font-weight: 680; }
.colophon__blurb { margin: 0; max-width: 62ch; color: var(--night-ink); }
@media (max-width: 620px) {
  .colophon__inner { flex-direction: column; text-align: center; gap: 16px; }
  .colophon__logo { height: 52px; }
  .colophon__blurb { max-width: none; }
}

.small { font-size: .84rem; color: var(--ink-3); }
.mt-l { margin-top: 34px; }
.mt-m { margin-top: 22px; }

/* ---------- contact dialog ----------
   Native <dialog>: focus trapping, Esc-to-close and the backdrop come free. */
.modal {
  width: min(560px, calc(100vw - 32px));
  padding: 30px 32px 26px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
  box-shadow: 0 30px 70px -20px rgba(16,21,31,.5);
}
.modal::backdrop { background: rgba(10,16,26,.55); backdrop-filter: blur(2px); }
.modal__x { position: absolute; top: 10px; right: 12px; margin: 0; }
.modal__x button {
  border: 0; background: none; cursor: pointer;
  font-size: 1.6rem; line-height: 1; color: var(--ink-3); padding: 6px 8px;
  border-radius: var(--radius-sm);
}
.modal__x button:hover { color: var(--ink); background: var(--surface-2); }
.modal__title { margin: 0 0 4px; font-size: 1.5rem; }
.modal__sub { margin: 0 0 20px; color: var(--ink-3); font-size: .92rem; }

.modal__grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.modal .field--wide { grid-column: 1 / -1; }
.modal .field > label {
  display: block; font-size: .84rem; font-weight: 640; color: var(--ink-2); margin-bottom: 6px;
}
.field__opt { font-weight: 400; color: var(--ink-3); }
.modal input[type="text"], .modal input[type="email"], .modal input[type="tel"], .modal textarea {
  width: 100%; padding: 10px 12px; font: inherit; color: var(--ink);
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius-sm);
}
.modal textarea { resize: vertical; min-height: 110px; }
.modal input:focus-visible, .modal textarea:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 1px;
}

/* Off-screen rather than display:none — bots skip hidden fields. */
.modal__hp {
  position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden;
}

.modal__estimate {
  margin: 18px 0 0; padding: 10px 12px;
  background: var(--accent-wash); color: var(--accent-ink);
  border-radius: var(--radius-sm); font-size: .85rem;
}
.modal__estimate[hidden] { display: none; }

.modal__status { margin: 14px 0 0; font-size: .88rem; min-height: 1.2em; color: var(--ink-2); }
.modal__status--good { color: var(--accent-ink); font-weight: 620; }
.modal__status--bad { color: var(--alert); font-weight: 600; }

.modal__actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 18px; }
.modal__actions .btn:disabled { opacity: .6; cursor: default; transform: none; }

/* Must share the breakpoint with the full-screen sheet rules below: when these
   two disagreed, 521-560px got full-width buttons still laid out in a row, so
   their labels sat left of centre. */
@media (max-width: 560px) {
  .modal { padding: 26px 20px 20px; }
  .modal__grid { grid-template-columns: 1fr; }
  .modal__actions { flex-direction: column-reverse; }
  .modal__actions .btn { justify-content: center; }
}

/* Invalid fields are marked, not just described in the status line. */
.modal [aria-invalid="true"] { border-color: var(--alert); box-shadow: 0 0 0 3px rgba(178,58,47,.12); }

/* Inline link-button: the estimate summary needs a way back to the estimator. */
.linkBtn {
  border: 0; background: none; padding: 0; cursor: pointer;
  font: inherit; color: var(--accent-ink); font-weight: 640;
  text-decoration: underline; text-underline-offset: 2px;
  white-space: nowrap;
}
.linkBtn:hover { color: var(--accent); }
.linkBtn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 3px; }

/* ---------- laptop mock ----------
   Dense admin tables were illegible at half-column width; one large screen
   that crossfades between views reads far better than two small stills. */
.laptop { width: 100%; }
.laptop__lid {
  padding: 14px;
  background: linear-gradient(160deg, #39434f 0%, #1a212b 45%, #2c343f 100%);
  border-radius: 14px 14px 5px 5px;
  box-shadow:
    0 0 0 1px rgba(255,255,255,.12) inset,
    0 30px 60px -22px rgba(16,21,31,.55);
}
.laptop__screen {
  position: relative;
  aspect-ratio: 2000 / 1114;   /* the capture's own ratio, so nothing crops */
  border-radius: 4px;
  overflow: hidden;
  background: #0b0e13;
}
.laptop__shot {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover; object-position: top center;
  opacity: 0; transition: opacity .5s ease;
}
.laptop__shot.is-on { opacity: 1; }
/* The base is wider than the lid — that overhang is what reads as a laptop. */
.laptop__base {
  position: relative;
  width: 112%; margin-left: -6%; height: 13px;
  border-radius: 0 0 12px 12px;
  background: linear-gradient(180deg, #3b4553 0%, #1b222a 100%);
  box-shadow: 0 18px 28px -14px rgba(16,21,31,.6);
}
.laptop__base::after {
  content: ""; position: absolute; left: 50%; top: 0; transform: translateX(-50%);
  width: 92px; height: 5px; border-radius: 0 0 6px 6px; background: rgba(255,255,255,.16);
}

.shotTabs { display: flex; gap: 8px; justify-content: center; margin-top: 24px; }
/* Selected is filled, unselected is an outline. A pale wash on a white chip
   read as the *less* prominent of the two, which inverted the meaning. */
.shotTab {
  border: 1px solid var(--line); background: transparent; color: var(--ink-3);
  border-radius: 999px; padding: 6px 16px; cursor: pointer;
  font: inherit; font-size: .85rem; font-weight: 620;
  transition: background .15s ease, color .15s ease, border-color .15s ease;
}
.shotTab:hover { background: var(--surface); border-color: var(--accent); color: var(--accent); }
/* No pointer and no hover response on the active one — there is nothing to do. */
.shotTab.is-on,
.shotTab.is-on:hover {
  background: var(--accent); color: #fff; border-color: var(--accent);
  cursor: default;
}
.shotTab:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.shot figcaption#opsCaption { text-align: center; }

@media (prefers-reduced-motion: reduce) {
  .laptop__shot { transition: none; }
}

/* Problem cards: icon beside the heading rather than stranded on its own line,
   with the body text hanging under the heading so the badge sits in the margin. */
.card--alert {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: 13px;
  align-items: center;
}
.card--alert .card__ico { margin-bottom: 0; }
.card--alert h3 { margin: 0; }
.card--alert p { grid-column: 2 / -1; margin: 8px 0 0; }
/* The glyph carries the whole message at this size, so give it more of the badge. */
.card--alert .card__ico svg { width: 25px; height: 25px; }

/* ---------- dialog on small screens ----------
   The form was taller than a phone viewport before the keyboard even appeared,
   so iOS scrolled and zoomed to reach the focused field. Cap the height, let
   the dialog scroll internally, and shrink the parts that cost the most rows.
   dvh (not vh) so the cap tracks Safari's collapsing toolbar. */
.modal { max-height: 88vh; max-height: 88dvh; overflow-y: auto; }

@media (max-width: 560px) {
  .modal { padding: 22px 18px 18px; }
  .modal__title { font-size: 1.28rem; }
  .modal__sub { margin-bottom: 16px; font-size: .88rem; }
  .modal__grid { gap: 12px; }
  .modal textarea { min-height: 84px; }
  .modal__actions { margin-top: 14px; }
}

/* ---------- full-screen dialog on phones ----------
   A centred dialog fights iOS: when the keyboard opens Safari pans the visual
   viewport, but the dialog is fixed, so you end up looking at one corner of it.
   Filling the screen removes anything to pan to, and the sheet scrolls
   internally instead. */
@media (max-width: 560px) {
  .modal {
    inset: 0;
    width: 100%;
    max-width: none;
    height: 100dvh;
    max-height: none;
    margin: 0;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    padding: 20px 18px calc(20px + env(safe-area-inset-bottom));
    padding-top: calc(20px + env(safe-area-inset-top));
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }
  .modal__x { top: calc(6px + env(safe-area-inset-top)); right: 8px; }
  .modal__x button { font-size: 2rem; padding: 4px 10px; }
  /* Keep a focused field clear of the top edge when the sheet scrolls to it. */
  .modal input, .modal textarea { scroll-margin: 18px; }
  /* Full-width buttons read as a sheet footer rather than a dialog's corner. */
  .modal__actions .btn { width: 100%; }
}

/* Never below 16px: anything smaller makes iOS Safari zoom the page on focus. */
.modal input[type="text"], .modal input[type="email"],
.modal input[type="tel"], .modal textarea { font-size: max(16px, 1rem); }
