/* ScreenQube COMPONENTS — extends what tokens.css already owns (.btn, .tile, .chip, .figure, .bento, :focus-visible, reduced-motion) and never redeclares it */

/* ── Button extensions ───────────────────────────────────────────────── */
/* 44px floor, not 40px — the nav's primary CTA uses this size. */
.btn--sm{ padding:11px 18px; font-size:var(--t-xs); min-height:44px }
.btn--lg{ padding:16px 30px; font-size:var(--t-body) }
.btn--wide{ width:100% }
.btn svg{ width:17px; height:17px; stroke:currentColor; stroke-width:2;
          fill:none; stroke-linecap:round; stroke-linejoin:round; flex:none }

/* Micro-copy under a CTA. It removes one specific fear, and it must be true. */
.btn-note{ font-size:var(--t-xs); color:var(--ink-2); margin-top:var(--s2); line-height:1.5 }

.cta-pair{ display:flex; flex-wrap:wrap; gap:var(--s3); margin-top:var(--s6) }
.cta-pair--center{ justify-content:center }

/* ── Icons ───────────────────────────────────────────────────────────── */
/* Ember is soft: round caps and joins, 1.8 stroke, fixed 24x24 viewBox. */
.icon{
  width:21px; height:21px; flex:none;
  stroke:currentColor; stroke-width:1.8; fill:none;
  stroke-linecap:round; stroke-linejoin:round;
}
.tile--dark .chip{ background:rgba(255,255,255,.12); color:var(--white) }
.tile--wash .chip{ background:rgba(255,255,255,.7) }

/* ── Tile extensions ─────────────────────────────────────────────────── */
.tile h3{ margin-bottom:var(--s2) }
.tile--dark .sm,.tile--dark .xs{ color:rgba(255,255,255,.72) }
.tile--dark h3,.tile--dark h2{ color:var(--white) }
.tile--flush{ padding:0; overflow:hidden }
.tile--link{ text-decoration:none; color:inherit; display:block }
.tile--link:hover{ color:inherit }

/* On page-ground sections a white tile is a ~1.2% luminance step with a ~1.1:1 hairline — effectively edgeless. The next shadow up makes them read as surfaces. */
.plate:not(.plate--sand):not(.plate--blush) > .wrap .tile,
.plate:not(.plate--sand):not(.plate--blush) > .wrap .banner{
  box-shadow:var(--sh-2); border-color:var(--line-2);
}

/* ── Pill badge — sits above a headline ──────────────────────────────── */
.badge{
  display:inline-flex; align-items:center; gap:var(--s2);
  background:var(--white);
  border:1px solid var(--line);
  border-radius:var(--r-pill);
  box-shadow:var(--sh-1);
  padding:7px 16px 7px 10px;
  font-size:var(--t-xs); font-weight:600; color:var(--ink-2);
}
.badge::before{
  content:""; width:7px; height:7px; border-radius:50%; flex:none;
  background:var(--red); box-shadow:0 0 0 3px var(--red-wash);
}

/* ── Scroll progress ─────────────────────────────────────────────────── */
/* Driven by transform, never width — width forces layout on the hottest path on the page. */
.progress{
  position:fixed; inset:0 auto auto 0;
  height:3px; width:100%;
  transform:scaleX(0); transform-origin:0 50%;
  background:var(--grad);
  border-radius:0 var(--r-pill) var(--r-pill) 0;
  z-index:var(--z-prog);
  pointer-events:none;
}

/* ── Navigation ──────────────────────────────────────────────────────── */
/* The pill spans the container CONTENT box: at --max it matched .wrap's outer edge, so the wordmark sat 31px left of the page content above 1366px and 25px right below it — an offset that flipped direction mid-range. */
.site-nav{
  position:sticky; top:var(--s3);
  z-index:var(--z-nav);
  margin:var(--s3) auto 0;
  max-width:calc(var(--max) - (var(--pad) * 2));
  width:calc(100% - (var(--pad) * 2));
}
.site-nav__in{
  display:flex; align-items:center; gap:var(--s4);
  padding:10px 10px 10px var(--s5);
  background:rgba(255,255,255,.86);
  border:1px solid var(--line);
  border-radius:var(--r-pill);
  box-shadow:var(--sh-2);
  transition:box-shadow var(--dur) var(--e), background var(--dur) var(--e);
}
/* The only blurred element on the site, and switched OFF while a mega panel is open: measured over 200 frames on real GPU, the live blur cost 26% dropped frames and a 48ms p95 against 0% and 18ms without. The open panel is opaque, so nothing is lost. */
@supports (backdrop-filter: blur(14px)) or (-webkit-backdrop-filter: blur(14px)){
  .site-nav__in{ -webkit-backdrop-filter:blur(14px); backdrop-filter:blur(14px) }
  .site-nav.is-mega-open .site-nav__in{
    -webkit-backdrop-filter:none; backdrop-filter:none;
    background:rgba(255,255,255,.97);
  }
}
.site-nav.is-stuck .site-nav__in{ box-shadow:var(--sh-3); background:rgba(255,255,255,.94) }

.brand{
  display:inline-flex; align-items:center; gap:var(--s2);
  font-size:var(--t-body); font-weight:800; letter-spacing:-.03em;
  color:var(--ink); text-decoration:none; white-space:nowrap;
  flex:0 1 auto; min-width:0;
}
.brand:hover{ color:var(--ink) }
.brand__word{ white-space:nowrap }   /* one flex item, so the gap cannot split it */
.brand b{ color:var(--red); font-weight:800 }         /* the Qube half of the word */
/* The viewBox is cropped to the artwork, so height alone sizes it. 26px, not 22px: the smallest panel is 18/50ths of the height, and under 1px its outline greys out on a 1x display. */
.brand__mark{ display:inline-flex; align-items:center; flex:none }
.brand__mark svg{ height:26px; width:auto }
/* One hue, three strengths — the signal getting stronger left to right. The old hollow outline read as a stray empty checkbox, and --ink-2 is the palette's DISABLED grey. */
.brand__mark .mark__a{ fill:var(--red); opacity:.30 }
.brand__mark .mark__b{ fill:var(--red); opacity:.60 }
.brand__mark .mark__c{ fill:var(--red) }
.brand__mark .mark__d{ fill:var(--white) }

.nav__spacer{ flex:1 1 auto; min-width:var(--s2) }

/* DOM order is brand → actions → links so Tab from the toggle enters the panel it just opened; desktop puts the links back in the middle with `order`. Reordering the DOM instead was the original bug (WCAG 2.4.3). */
/* 16px, not 24: five top-level items now, and four 24px gaps was what pushed Pricing onto a second row. */
.nav__links{ display:flex; align-items:center; gap:var(--s4); flex-wrap:wrap }
/* `> a`, not ` a`: the mega panels live INSIDE .nav__links, so a descendant selector is (0,1,1) and out-ranks every panel class rule. Only the Pricing link and the mobile CTA are ever direct children. */
.nav__links > a{
  display:inline-flex; align-items:center;
  min-height:44px; padding-inline:var(--s1);
  font-size:var(--t-sm); font-weight:600; color:var(--ink-2);
  text-decoration:none; white-space:nowrap;
  transition:color var(--dur) var(--e);
}
.nav__links > a:hover,.nav__links > a[aria-current="page"]{ color:var(--red) }

.nav__actions{ display:flex; align-items:center; gap:var(--s3); flex:none }
.nav__login{
  display:inline-flex; align-items:center; min-height:44px;
  font-size:var(--t-sm); font-weight:600; color:var(--ink);
  text-decoration:none; white-space:nowrap; padding-inline:var(--s3);
}
.nav__login:hover{ color:var(--red) }

.nav__toggle{ display:none }
.nav__toggle svg{ width:22px; height:22px; stroke:currentColor; stroke-width:2;
                  fill:none; stroke-linecap:round }

@media (min-width:1100px){
  .nav__links  { order:1 }
  .nav__spacer { order:2 }
  .nav__actions{ order:3 }
}

/* Below 1100px the links collapse behind a button, but only when JS is there to operate it. Measured: brand 151 + five links 544 + two actions 225 + two 16px gaps = 952px, against an inner width of 0.92·viewport − 34 that reaches 952 at 1072 — so at the old 960 the pill stood two storeys tall. */
@media (max-width:1099.98px){
  .site-nav__in{ flex-wrap:wrap; row-gap:var(--s3); padding-inline:var(--s4) }
  .nav__links{ width:100%; gap:var(--s4); padding-top:var(--s3);
               border-top:1px solid var(--line) }

  .js .nav__toggle{
    display:grid; place-items:center;
    width:44px; height:44px; border-radius:var(--r-pill);
    color:var(--ink); background:var(--white);
    border:1px solid var(--line); box-shadow:var(--sh-1);
  }
  .js .nav__links{ display:none }
  .js .site-nav.is-open .nav__links{ display:flex; flex-direction:column; align-items:flex-start }
  .js .site-nav.is-open .nav__links > a{ font-size:var(--t-body) }
  .js .nav__login{ display:none }
  .js .site-nav.is-open .nav__login{ display:inline-flex; padding-left:0 }
}

/* The in-panel CTA is hidden except in an open sheet, and must out-specify `.nav__links a` (0,1,1) or it renders inside the desktop nav on top of the real CTA. */
.nav__links > a.nav__cta-mobile{ display:none; margin-block-start:var(--s2); color:#fff; }

/* THE ACTION LADDER — the pill's links are nowrap, so outgrowing it wraps the bar to two storeys. Inner width is 0.92·viewport − 34 capped at 1134, and brand + 5 links + 3 actions needs 1063, so three actions only fit from ~1250 up. Each step drops the lowest-commitment action first, leaving the partner application last. */

@media (max-width:1279.98px) and (min-width:1100px){
  .nav__actions .btn--ghost{ display:none }
}

@media (max-width:1099.98px){
  .js .nav__actions .btn--ghost{ display:none }
}

/* Below 480 the pill needs 341px of the 305px a 375px phone gives it, so every button goes — the only step where the sheet has to carry the CTA itself. */
@media (max-width:479.98px){
  .js .nav__actions > .btn{ display:none }
  .js .site-nav.is-open .nav__links > a.nav__cta-mobile{ display:inline-flex }
}

/* MEGA MENU — modelled on Pickcel's product nav, with three deliberate differences: it opens on hover AND focus AND click (hover alone fails WCAG 2.1.1 and is unreachable on touch); shut is `visibility:hidden`, not `display:none`, so it leaves the tab order and can still animate; and without JS every panel renders inline as a plain list. */

/* The pill is the positioning context for every panel. */
.site-nav__in{ position:relative }

.nav__item{ position:static }          /* panels centre on the pill, not on the item */

/* The trigger reads as a nav link, not a button. */
.nav__trigger{
  display:inline-flex; align-items:center; gap:6px;
  min-height:44px; padding-inline:var(--s1);
  font-family:inherit; font-size:var(--t-sm); font-weight:600;
  color:var(--ink-2); white-space:nowrap;
  transition:color var(--dur) var(--e);
}
.nav__trigger:hover,
.nav__item.is-open .nav__trigger{ color:var(--red) }

.nav__caret{
  width:15px; height:15px; flex:none;
  stroke:currentColor; stroke-width:2.2; fill:none;
  stroke-linecap:round; stroke-linejoin:round;
  transition:rotate var(--dur) var(--e);
}
.nav__item.is-open .nav__caret{ rotate:180deg }

/* ── The panel ─────────────────────────────────────────────────────────── */
.mega{
  position:absolute; top:calc(100% + 10px); left:50%;
  z-index:var(--z-nav);

  /* Width is a percentage of the PILL, not the viewport: 100vw includes the scrollbar gutter, and the panel's containing block is the pill, which is narrower by 2×--pad. */
  width:min(1000px, 100%);

  /* A panel taller than the window cannot be scrolled to — it is absolutely positioned inside a sticky bar. dvh, not vh, which mobile reports URL-bar-collapsed and over-measures by ~60px. */
  max-height:calc(100vh - var(--s10));
  max-height:calc(100dvh - var(--s10));

  /* `hidden auto`, not a bare overflow-y: the featured card's --sand ground runs to the panel edge and needs the radius clip, and with x left visible the spec computes it as auto anyway. */
  overflow:hidden auto;
  overscroll-behavior:contain;   /* stops the page scrolling behind the panel */

  background:var(--white);
  border:1px solid var(--line);
  border-radius:var(--r-lg);
  box-shadow:var(--sh-4);

  /* Closed: nudged 6px up so opening settles downward. `visibility`, not `display`, keeps it out of the tab order while still allowing the fade. */
  translate:-50% -6px;
  opacity:0; visibility:hidden; pointer-events:none;
  transition:opacity var(--dur) var(--e),
             translate var(--dur) var(--e),
             visibility 0s linear var(--dur);
}
.nav__item.is-open .mega{
  translate:-50% 0;
  opacity:1; visibility:visible; pointer-events:auto;
  transition-delay:0s;
}

.mega__in{ display:grid; grid-template-columns:1fr 320px }
/* One-column variant: the two-column shape assumes a 320px feature card, and a panel with nothing to put there would just hold a hollow gap. */
.mega--narrow{ width:min(420px, 100%) }
.mega--narrow .mega__in{ grid-template-columns:1fr }
.mega--narrow .mega__cols{ grid-template-columns:1fr }

/* ── Grouped columns ───────────────────────────────────────────────────── */
.mega__cols{
  display:grid; grid-template-columns:repeat(2,1fr);
  gap:var(--s5) var(--s7);
  padding:var(--s6) var(--s6) var(--s5);
}
.mega__label{
  font-size:var(--t-lab); font-weight:700;
  letter-spacing:.09em; text-transform:uppercase;
  color:var(--ink-3);
  margin-bottom:var(--s3);
}
.mega__label + .mega__list{ margin-bottom:var(--s5) }
.mega__list{ display:grid; gap:2px }

.mega__list a{
  display:flex; align-items:center; gap:var(--s3);
  min-height:40px; padding:6px var(--s3) 6px var(--s2);
  margin-inline:calc(var(--s2) * -1);
  border-radius:var(--r-sm);
  font-size:var(--t-sm); font-weight:600; color:var(--ink);
  text-decoration:none;
  transition:background var(--dur-fast) var(--e), color var(--dur-fast) var(--e);
}
.mega__list a:hover{ background:var(--mist); color:var(--red) }
.mega__list a:hover .mega__ico{ color:var(--red) }

.mega__ico{
  width:19px; height:19px; flex:none; color:var(--ink-3);
  transition:color var(--dur-fast) var(--e);
}
.mega__ico svg{
  width:100%; height:100%;
  stroke:currentColor; stroke-width:1.8; fill:none;
  stroke-linecap:round; stroke-linejoin:round;
}

/* A constraint stated in the menu itself rather than discovered later — Feature-Claims §5: the player is Android only. */
.mega__note{
  font-size:var(--t-xs); color:var(--ink-3);
  padding-inline:var(--s2); margin-top:calc(var(--s2) * -1);
}

/* The column-foot link — Pickcel's "View all Players →". */
.mega__more{
  display:inline-flex; align-items:center; gap:7px;
  min-height:40px; margin-top:var(--s3);
  padding-top:var(--s3); border-top:1px solid var(--line);
  width:100%;
  font-size:var(--t-sm); font-weight:700; color:var(--red);
  text-decoration:none;
}
.mega__more svg{ width:15px; height:15px; stroke:currentColor; stroke-width:2;
                 fill:none; stroke-linecap:round; stroke-linejoin:round;
                 transition:translate var(--dur) var(--e) }
.mega__more:hover{ color:var(--red-deep) }
.mega__more:hover svg{ translate:3px 0 }

/* ── The featured card ─────────────────────────────────────────────────── */
.mega__feature{
  display:block; padding:var(--s6);
  background:var(--sand);
  border-left:1px solid var(--line);
  text-decoration:none; color:inherit;
}
.mega__feature:hover{ color:inherit }
.mega__shot{
  display:block; border-radius:var(--r-sm); overflow:hidden;
  border:1px solid var(--line-2); background:var(--white);
  box-shadow:var(--sh-1);
  margin-bottom:var(--s4);
  /* The capture is from a near-empty test system, so a 16/9 thumbnail is mostly blank. Crop to the band carrying the tiles; re-measure when the screenshots are retaken. */
  aspect-ratio:1904 / 620;
}
.mega__shot img,.mega__shot video{
  width:100%; height:100%;
  object-fit:cover; object-position:top center;
  transition:scale var(--dur-slow) var(--e);
}
.mega__feature:hover .mega__shot img{ scale:1.03 }

.mega__ftitle{
  display:flex; align-items:center; justify-content:space-between; gap:var(--s3);
  font-size:var(--t-h3); font-weight:700; letter-spacing:-.02em; color:var(--ink);
}
.mega__ftitle svg{ width:16px; height:16px; flex:none;
                   stroke:currentColor; stroke-width:2.2; fill:none;
                   stroke-linecap:round; stroke-linejoin:round;
                   transition:translate var(--dur) var(--e) }
.mega__feature:hover .mega__ftitle{ color:var(--red) }
.mega__feature:hover .mega__ftitle svg{ translate:3px 0 }
.mega__fdesc{ display:block; font-size:var(--t-sm); color:var(--ink-2); line-height:1.55; margin-top:var(--s2) }

/* ── Narrow: the panel becomes part of the mobile sheet ────────────────── */
@media (max-width:1039.98px){
  .mega__in{ grid-template-columns:1fr }
  .mega__feature{ border-left:0; border-top:1px solid var(--line) }
}

@media (max-width:1099.98px){
  .nav__item{ width:100% }
  .nav__trigger{ width:100%; justify-content:space-between; font-size:var(--t-body) }

  /* Inside the sheet the panel is an accordion, not an overlay, and max-height is released — the SHEET scrolls, not each panel, or one gesture meets two scrollbars. */
  .mega{
    position:static; translate:none; width:100%;
    max-height:none; overflow:visible;
    border:0; border-radius:0; box-shadow:none; background:transparent;
    display:none; opacity:1; visibility:visible; pointer-events:auto;
    transition:none;
  }
  .nav__item.is-open .mega{ display:block; translate:none }
  .mega__cols{ grid-template-columns:1fr; padding:var(--s3) 0 var(--s4); gap:var(--s4) }
  .mega__feature{ display:none }   /* the sheet is for navigating, not browsing */

  /* The sheet itself scrolls: the bar is position:sticky, so anything past the fold was unreachable — the page cannot scroll a sticky element's overflow into view. */
  .js .site-nav.is-open .nav__links{
    max-height:calc(100vh - var(--s9));
    max-height:calc(100dvh - var(--s9));
    overflow-y:auto;
    overscroll-behavior:contain;
    -webkit-overflow-scrolling:touch;
  }

  /* A 999px radius reads as a pill on a 40px bar and as a mistake on a 500px sheet, where the curve eats the first and last rows. */
  .js .site-nav.is-open .site-nav__in{ border-radius:var(--r-xl) }
}

/* ── No JavaScript: every panel renders inline, nothing is unreachable ─── */
html:not(.js) .mega{
  position:static; translate:none; width:100%;
  opacity:1; visibility:visible; pointer-events:auto;
  box-shadow:none; border:0; border-radius:0;
  transition:none;
}
html:not(.js) .nav__caret{ display:none }
html:not(.js) .mega__feature{ display:none }

/* ── Browser frame — sells "this is a real web app" ──────────────────── */
.frame{
  border-radius:var(--r-xl); overflow:hidden;
  background:var(--white);
  border:1px solid var(--line);
  box-shadow:var(--sh-4);
}
.frame--sm{ border-radius:var(--r-lg); box-shadow:var(--sh-3) }
.frame--flat{ box-shadow:var(--sh-3) }
.frame__bar{
  display:flex; align-items:center; gap:7px;
  padding:12px var(--s4);
  background:var(--sand);
  border-bottom:1px solid var(--line);
}
.frame__bar i{ width:9px; height:9px; border-radius:50%; background:var(--line-2); flex:none }
.frame__bar i:first-child{ background:var(--red-soft) }
.frame__url{
  margin-left:var(--s2); flex:1;
  font-family:var(--f-mono); font-size:var(--t-xs); color:var(--ink-quiet);
  background:var(--white); border:1px solid var(--line);
  border-radius:var(--r-pill); padding:5px 14px;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.frame__shot{ position:relative; overflow:hidden; background:var(--white) }
/* <picture> is inline; without this the product screenshots sat on a text baseline and left a few pixels of ground under them. */
.frame__shot picture,.laptop__screen picture{ display:block }
.frame__shot img,.frame__shot video{ width:100%; display:block }

/* Console screenshots are 1904x1064 from a nearly empty system: shown whole the product reads as unfinished, and the old 1904/480 sliced through "Apps". 660 lands just below "Settings". Still the wrong fix — the right one is a capture against a populated account. */
.frame__shot--crop img{
  aspect-ratio:1904 / 660;
  height:auto;
  object-fit:cover; object-position:top center;
}
/* Matches the real My Plan capture's own crop (1904x990); the old 1904/620 sliced the plan card and forced the hotspot markers onto live text. */
.frame__shot--tall img{ aspect-ratio:1904 / 990 }

/* ── Stat ────────────────────────────────────────────────────────────── */
/* .figure (tokens.css) carries the gradient mechanics; this adds only what is specific to a stat block. */
.stat{ font-size:clamp(2.6rem,5vw,3.9rem) }
.stat__label{ display:block; font-size:var(--t-sm); color:var(--ink-2); margin-top:var(--s3) }

/* ── FAQ — real <details>, so it works with JS disabled ──────────────── */
.faq{ display:grid; gap:var(--s3); max-width:80ch }
.faq details{
  background:var(--white);
  border:1px solid var(--line);
  border-radius:var(--r);
  box-shadow:var(--sh-1);
  transition:box-shadow var(--dur) var(--e);
}
.faq details[open]{ box-shadow:var(--sh-2) }
.faq summary{
  display:flex; align-items:center; justify-content:space-between; gap:var(--s4);
  padding:var(--s4) var(--s5);
  font-size:var(--t-sm); font-weight:600; color:var(--ink);
  cursor:pointer; list-style:none; min-height:56px;
  border-radius:var(--r);
}
/* No overflow:hidden on the details — it clipped the focus ring on three sides and left five closed items with no visible indicator at all (WCAG 2.4.7). */
.faq summary:focus-visible{ outline-offset:-3px }
.faq summary::-webkit-details-marker{ display:none }
.faq summary::after{
  content:""; flex:none; width:11px; height:11px;
  border-right:2px solid var(--red); border-bottom:2px solid var(--red);
  transform:rotate(45deg) translate(-2px,-2px);
  transition:transform var(--dur) var(--e);
}
.faq details[open] summary::after{ transform:rotate(-135deg) translate(-2px,-2px) }
.faq summary:hover{ color:var(--red) }
.faq__a{ padding:0 var(--s5) var(--s5); color:var(--ink-2); font-size:var(--t-sm); max-width:var(--measure) }
.faq__a p + p{ margin-top:var(--s3) }

/* "View More" expander. The extra questions are real markup, so with no JS they are all visible and the toggle is not. */
.faq__more{ display:grid; gap:var(--s3) }
html.js .faq__more{ display:none }
html.js .faq__more.is-open{ display:grid; margin-top:var(--s3) }

.faq__toggle{
  display:inline-flex; align-items:center; gap:var(--s2);
  margin-top:var(--s4); padding:10px 18px; min-height:44px;
  background:var(--white); border:1px solid var(--line-2); border-radius:var(--r-pill);
  font-family:var(--f); font-size:var(--t-xs); font-weight:600; color:var(--ink-2);
  cursor:pointer;
  transition:color .2s ease, border-color .2s ease, background .2s ease;
}
.faq__toggle svg{
  width:16px; height:16px; fill:none; stroke:currentColor; stroke-width:2;
  stroke-linecap:round; stroke-linejoin:round;
  transition:transform .2s ease;
}
.faq__toggle:hover{ color:var(--red); border-color:var(--red-soft); background:var(--red-wash) }
.faq__toggle[aria-expanded="true"] svg{ transform:rotate(180deg) }
html:not(.js) .faq__toggle{ display:none }

/* ── Dark closing panel — the page's one dark element ────────────────── */
.cta-panel{
  position:relative; overflow:hidden;
  background:var(--ink); color:var(--white);
  border-radius:var(--r-2xl);
  padding:clamp(var(--s7),6vw,var(--s9)) var(--pad);
  text-align:center;
}
.cta-panel::before{
  content:""; position:absolute; top:-55%; left:50%;
  transform:translateX(-50%);
  width:min(900px,120%); height:420px; border-radius:50%;
  background:radial-gradient(closest-side,rgba(217,39,63,.5),transparent 70%);
  pointer-events:none;
}
.cta-panel > *{ position:relative }
.cta-panel h2{ color:var(--white) }
.cta-panel .accent{ color:var(--red-soft) }
.cta-panel .body{ color:rgba(255,255,255,.78); margin-inline:auto }
.cta-panel .btn--ghost{
  background:transparent; color:var(--white);
  border-color:rgba(255,255,255,.4); box-shadow:none;
}
.cta-panel .btn--ghost:hover{ background:rgba(255,255,255,.1); color:var(--white) }
.cta-panel .btn-note{ color:rgba(255,255,255,.7) }

/* ── One-line routing banner ─────────────────────────────────────────── */
/* space-between, not the default: .banner__text stops growing at 52ch, so without it the button sat mid-card with a third of the row empty. Wrapped, each child is alone on its line and this is a no-op. */
.banner{
  display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between; gap:var(--s4);
  background:var(--white);
  border:1px solid var(--line);
  border-radius:var(--r-lg);
  box-shadow:var(--sh-1);
  padding:var(--s5) var(--s6);
}
.banner__text{ flex:1 1 22ch; max-width:52ch; font-size:var(--t-sm); color:var(--ink-2) }
.banner__text b{ color:var(--ink); font-weight:700 }

/* ── Footer ──────────────────────────────────────────────────────────── */
.site-foot{
  background:var(--sand);
  border-top:1px solid var(--line);
  padding-block:var(--s7) var(--s6);
}
.site-foot__cols{
  display:grid; gap:var(--s7) var(--s6);
  grid-template-columns:repeat(2,1fr);
}
.site-foot__brand{ grid-column:1 / -1 }

.site-foot ul{ display:grid; gap:var(--s1); list-style:none; margin:0; padding:0 }
/* A group entry with no page behind it yet renders as text, not a dead link. */
.site-foot li > span{
  display:inline-flex; align-items:center; min-height:30px;
  font-size:var(--t-sm); line-height:1.4; color:var(--ink-2);
}
/* 44px is the touch-target floor. The breakpoints below tighten it and MUST come after this rule — same specificity, so above it the base won and every override was dead. */
.site-foot li a{
  display:inline-flex; align-items:center; min-height:44px;
  font-size:var(--t-sm); line-height:1.4; color:var(--ink-2);
  text-decoration:none;
  transition:color .18s ease;
}
.site-foot li a:hover{
  color:var(--red);
  text-decoration:underline; text-decoration-color:var(--red-soft);
  text-underline-offset:3px;
}

@media (min-width:720px){
  .site-foot__cols{ grid-template-columns:repeat(3,1fr) }
  .site-foot li a{ min-height:30px }
}

/* A brand block holding the left edge with four link columns beside it. The brand occupies ONE row: pinning it across two forced an empty second row that still drew its full 64px row-gap. */
@media (min-width:1000px){
  .site-foot__cols{
    grid-template-columns:minmax(230px,1.15fr) repeat(4,1fr);
    column-gap:var(--s6); row-gap:var(--s7);
    align-items:start;
  }
  .site-foot__brand{ grid-column:1; grid-row:1 }
}

/* Sentence case at reading size, not a 12px uppercase micro-label — that made every heading weigh the same as its links and the block read as one undifferentiated list. */
.site-foot h2{
  font-size:1.06rem; font-weight:700; letter-spacing:-.02em;
  text-transform:none; color:var(--ink);
  margin:0 0 var(--s3);
}

/* Two tracks carry a pair of short groups, buying every other column ~25px without adding a row. Both lead with a three-entry group so the lower headings align for free rather than by padding the shorter one. */
.site-foot__stack{ display:grid; gap:var(--s6); align-content:start }

/* Six link groups beside the brand — seven tracks in a 1168px box, so this row only exists once there is width to pay for it. --t-xs because 150px tracks cannot carry 15px labels. */
@media (min-width:1200px){
  /* auto, not 1fr: equal-width columns sized every group to the widest one, so "Blog" carried the same 150px as "Safety communication" and the short columns read as drifting apart. */
  .site-foot__cols{
    grid-template-columns:minmax(180px,1fr) repeat(6,auto);
    column-gap:var(--s5); row-gap:var(--s7);
  }
  /* .brand keeps its wordmark on one line, so the first track has to clear it outright — a narrower track overlaps Product rather than wrapping the word. */
  .site-foot__brand{ grid-column:1; grid-row:1; padding-right:var(--s6) }
  .site-foot h2{ font-size:.9rem; margin-bottom:var(--s2) }
  .site-foot li a,
  .site-foot li > span{ font-size:var(--t-xs); min-height:26px; line-height:1.35 }
}

.site-foot__slogan{
  margin-top:var(--s3);
  font-size:var(--t-sm); font-weight:700; letter-spacing:.02em;
  color:var(--ink);
}
.site-foot__legal{
  margin-top:var(--s6); padding-top:var(--s5);
  border-top:1px solid var(--line-2);
  display:flex; flex-wrap:wrap; align-items:center; gap:var(--s3) var(--s6);
  font-size:var(--t-xs); color:var(--ink-quiet);
}
.site-foot__legal img{ display:block; width:110px; height:auto }
/* "Powered by" and the mark are one unit, so the legal row's 32px gap falls between them and the address, not between the words and the logo. */
.site-foot__by{ display:inline-flex; align-items:center; gap:var(--s2); white-space:nowrap }
.site-foot__legal a{
  color:var(--ink-3); text-decoration:none;
  transition:color .18s ease;
}
.site-foot__legal a:hover{
  color:var(--red);
  text-decoration:underline; text-decoration-color:var(--red-soft);
  text-underline-offset:3px;
}

/* Contact details in the brand column — an address and an inbox a buyer can act on without opening the contact page. */
.site-foot .site-foot__contact{
  display:grid; gap:var(--s3);
  margin:var(--s5) 0 0; padding:0; list-style:none;
}
.site-foot .site-foot__contact li{
  display:flex; align-items:flex-start; gap:var(--s3);
  font-size:var(--t-sm); color:var(--ink-2); line-height:1.5;
  text-wrap:pretty;
}
.site-foot .site-foot__contact svg{
  width:17px; height:17px; margin-top:2px; flex:none;
  fill:none; stroke:var(--red); stroke-width:1.7;
  stroke-linecap:round; stroke-linejoin:round;
}
.site-foot .site-foot__contact a{
  color:var(--ink-2); text-decoration:none; min-height:0;
  transition:color .18s ease;
}
.site-foot .site-foot__contact a:hover{
  color:var(--red);
  text-decoration:underline; text-decoration-color:var(--red-soft);
  text-underline-offset:3px;
}

/* Scoped under .site-foot because `.site-foot ul` and `.site-foot li a` above would otherwise win on specificity and force these lists back into the column grid. */
.site-foot .site-foot__copy{ margin:0 }

/* In the brand column now, under the slogan — not in the bottom bar. */
.site-foot .site-foot__social{
  display:flex; flex-flow:row nowrap; align-items:center;
  gap:var(--s3);
  margin:var(--s5) 0 0; padding:0; list-style:none;
}
.site-foot .site-foot__social a{
  display:grid; place-items:center;
  width:44px; height:44px; min-height:0; border-radius:12px;
  border:1px solid var(--line);
  background:var(--white); color:var(--ink-2);
  text-decoration:none;
  transition:color .2s ease, border-color .2s ease, background .2s ease;
}
.site-foot .site-foot__social svg{
  width:18px; height:18px;
  fill:none; stroke:currentColor; stroke-width:1.7;
  stroke-linecap:round; stroke-linejoin:round;
}
.site-foot .site-foot__social a:hover{
  color:var(--red); border-color:var(--red-soft); background:var(--red-wash);
}

/* Category filter — hidden without JS, because the unfiltered list is the correct fallback and a row of buttons that filter nothing is not. */
.filter{ display:none }
html.js .filter{
  display:flex; flex-wrap:wrap; align-items:center; gap:var(--s2);
  margin-bottom:var(--s6);
}
.filter__tab{
  display:inline-flex; align-items:center; min-height:40px;
  padding:8px 16px;
  background:var(--white); border:1px solid var(--line-2); border-radius:var(--r-pill);
  font-family:var(--f); font-size:var(--t-xs); font-weight:600; color:var(--ink-2);
  cursor:pointer; white-space:nowrap;
  /* Background and border ease; the LABEL colour switches instantly, or there is a frame of white-on-white nobody can read. */
  transition:border-color .18s ease, background .18s ease;
}
.filter__tab:hover{ color:var(--red); border-color:var(--red-soft); background:var(--red-wash) }
/* Selected state is carried by fill AND weight, not colour alone. */
.filter__tab[aria-pressed="true"]{
  background:var(--ink); border-color:var(--ink); color:var(--white); font-weight:700;
}
.filter__count{
  margin-left:auto; font-size:var(--t-xs); color:var(--ink-2);
}
@media (max-width:640px){
  .filter__count{ margin-left:0; flex-basis:100% }
}

/* ── Placeholder marking ─────────────────────────────────────────────── */
/* Drawn in --red, not --red-soft: at 1.7:1 the old treatment was invisible, and a marking nobody can see is not a marking. The pre-launch gate is `grep -rn data-placeholder`. */
[data-placeholder]{
  text-decoration:underline dotted var(--red);
  text-underline-offset:.28em;
  text-decoration-thickness:2px;
}
.tile--dark [data-placeholder],
.cta-panel [data-placeholder]{ text-decoration-color:var(--red-soft) }

/* A visible banner for a page whose copy is not real yet. */
.notice{
  display:flex; gap:var(--s4); align-items:flex-start;
  background:var(--blush);
  border:1px solid var(--red-soft);
  border-radius:var(--r);
  padding:var(--s4) var(--s5);
  font-size:var(--t-sm); color:var(--ink-2);
  margin-bottom:var(--s6);
}
.notice b{ color:var(--red) }

/* Consent notice — bottom-anchored and NOT a full-screen overlay: blackening the page and trapping focus is pressure to agree, which is the thing the law aims at. Reject and Accept are the same control, styled identically. */
.cc{
  position:fixed; z-index:var(--z-modal);
  left:var(--s4); right:var(--s4); bottom:var(--s4);
  display:flex; justify-content:center;
  pointer-events:none;                 /* only the card itself is interactive */
}
/* Kept deliberately short: it is fixed-position, so every pixel of height covers the page — at 209px desktop and 280px mobile it sat on top of the sign-in button. */
.cc__in{
  pointer-events:auto;
  width:min(520px,100%);
  background:var(--white);
  border:1px solid var(--line-2);
  border-radius:var(--r-lg);
  box-shadow:var(--sh-4);
  padding:var(--s4) var(--s5);
  animation:cc-in 320ms var(--e) both;
}
@keyframes cc-in{ from{ opacity:0; translate:0 12px } to{ opacity:1; translate:0 0 } }
@media (prefers-reduced-motion: reduce){ .cc__in{ animation:none } }

.cc__title{ font-size:var(--t-sm); font-weight:700; letter-spacing:-.02em; margin-bottom:3px }
.cc__desc{ font-size:var(--t-xs); color:var(--ink-2); line-height:1.5; max-width:none }

.cc__opts{ margin-top:var(--s3); border-top:1px solid var(--line); padding-top:var(--s3) }
.cc__opts fieldset{ border:0; padding:0; margin:0; display:grid; gap:var(--s2) }
.cc__row{ display:flex; gap:var(--s3); align-items:flex-start; cursor:pointer }
.cc__row input{ margin-top:3px; width:16px; height:16px; accent-color:var(--red); flex:none; cursor:pointer }
.cc__row b{ display:block; font-size:var(--t-xs); font-weight:700; color:var(--ink) }
.cc__row em{ display:block; font-size:var(--t-xs); font-style:normal; color:var(--ink-3); line-height:1.5 }
.cc__row--fixed{ cursor:default; opacity:.75 }
.cc__row--fixed input{ cursor:not-allowed }

.cc__acts{
  display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between;
  gap:var(--s3); margin-top:var(--s4);
}
.cc__pair{ display:flex; gap:var(--s3); flex:1; justify-content:flex-end }
.cc__btn{
  flex:0 1 auto; min-width:104px;
  padding:9px var(--s4);
  border-radius:var(--r-pill);
  border:1px solid var(--red);
  background:var(--white); color:var(--red);
  font-size:var(--t-sm); font-weight:700;
  cursor:pointer;
  transition:background var(--dur-fast) var(--e), color var(--dur-fast) var(--e);
}
.cc__btn:hover{ background:var(--red); color:var(--white) }
.cc__link{
  padding:6px 0;
  font-size:var(--t-xs); font-weight:600;
  color:var(--ink-2); text-decoration:underline; text-underline-offset:.2em;
  cursor:pointer; background:none; border:0;
}
.cc__link:hover{ color:var(--ink) }
.cc__btn:focus-visible,.cc__link:focus-visible{ outline:2px solid var(--red); outline-offset:2px }

/* Both actions go full width and stack below the buttons rather than beside them, so neither is the one your thumb lands on by default. */
@media (max-width:479.98px){
  .cc{ left:0; right:0; bottom:0 }
  .cc__in{ border-radius:var(--r-lg) var(--r-lg) 0 0; padding:var(--s4) }
  .cc__acts{ flex-direction:column-reverse; align-items:stretch }
  .cc__pair{ justify-content:stretch }
  .cc__btn{ flex:1 }
}

/* Back to top — appears once the hero scrolls out (initBackToTop in ui.js), using visibility not just opacity so a hidden button cannot eat a tab stop. bottom reads --cc-h, the height the consent notice publishes. */
.btt{
  position:fixed; z-index:var(--z-float);
  /* Sits above the chat launcher: 48px launcher + 12px gap, with --cc-h still lifting the whole stack over the consent notice. */
  right:var(--s4); bottom:calc(var(--s4) + var(--cc-h,0px) + 60px);
  width:48px; height:48px; border:0; border-radius:var(--r-pill);
  display:grid; place-items:center;
  background:var(--grad); color:#fff; box-shadow:var(--sh-red);
  cursor:pointer;
  opacity:0; translate:0 16px; visibility:hidden; pointer-events:none;
  transition:opacity var(--dur) var(--e), translate var(--dur) var(--e),
             visibility 0s linear var(--dur), transform var(--dur) var(--e-spring),
             box-shadow var(--dur) var(--e), bottom var(--dur) var(--e);
}
.btt.is-visible{
  opacity:1; translate:none; visibility:visible; pointer-events:auto;
  transition:opacity var(--dur) var(--e), translate var(--dur) var(--e),
             transform var(--dur) var(--e-spring), box-shadow var(--dur) var(--e),
             bottom var(--dur) var(--e);
}
.btt:hover{ transform:translateY(-2px); box-shadow:var(--sh-red-hover); }
.btt:active{ transform:translateY(0); }

/* Help launcher — a floating button and a NON-modal popup: it does not cover the page or trap focus, and Escape returns focus to the launcher. Everything inside is a real link. */
.chat{ position:fixed; z-index:var(--z-float); right:var(--s4); bottom:calc(var(--s4) + var(--cc-h,0px)) }

/* Same 48px as .btt directly above it — two floating buttons that differ by 8px read as a mistake, not a hierarchy. */
.chat__launcher{
  display:grid; place-items:center;
  width:48px; height:48px; border:0; border-radius:var(--r-pill);
  background:var(--grad); color:#fff; box-shadow:var(--sh-red);
  cursor:pointer;
  transition:transform var(--dur) var(--e-spring), box-shadow var(--dur) var(--e);
}
.chat__launcher:hover{ transform:translateY(-2px); box-shadow:var(--sh-red-hover) }
.chat__launcher:active{ transform:translateY(0) }
.chat__glyph{
  grid-area:1/1; width:22px; height:22px;
  fill:none; stroke:currentColor; stroke-width:1.9;
  stroke-linecap:round; stroke-linejoin:round;
  transition:opacity var(--dur) var(--e), transform var(--dur) var(--e);
}
/* Two glyphs stacked in one grid cell and cross-faded, so the button never changes size as its meaning flips. */
.chat__glyph--shut{ opacity:0; transform:rotate(-90deg) }
.chat__launcher[aria-expanded="true"] .chat__glyph--open{ opacity:0; transform:rotate(90deg) }
.chat__launcher[aria-expanded="true"] .chat__glyph--shut{ opacity:1; transform:none }

.chat__panel{
  position:absolute; right:0; bottom:calc(48px + var(--s3));
  width:min(340px, calc(100vw - var(--s4) * 2));
  background:var(--white);
  border:1px solid var(--line-2); border-radius:var(--r-lg);
  box-shadow:var(--sh-3);
  padding:var(--s5);
  transform-origin:100% 100%;
  /* transform only — opacity is deliberately not animated, so a transition that never runs leaves a panel 8px low rather than invisible. */
  transition:transform var(--dur) var(--e);
}
.chat__panel[hidden]{ display:none }
.chat__panel:focus{ outline:none }
/* The entry animation is a STARTING state, not a class a rAF callback removes — when that callback did not land the panel unhid at opacity 0 and the button looked dead. */
@starting-style{
  .chat__panel{ transform:translateY(8px) scale(.98) }
}

.chat__head{ display:flex; align-items:center; justify-content:space-between; gap:var(--s3) }
.chat__title{ margin:0; font-size:1.06rem; font-weight:800; letter-spacing:-.02em; color:var(--ink) }
.chat__close{
  display:grid; place-items:center; flex:none;
  width:32px; height:32px; margin-right:calc(var(--s2) * -1);
  border:0; border-radius:var(--r-sm); background:transparent; color:var(--ink-2);
  cursor:pointer; transition:color .18s ease, background .18s ease;
}
.chat__close svg{ width:17px; height:17px; fill:none; stroke:currentColor; stroke-width:1.9; stroke-linecap:round }
.chat__close:hover{ color:var(--red); background:var(--red-wash) }

.chat__lead{ margin:var(--s2) 0 var(--s4); font-size:var(--t-xs); color:var(--ink-2); line-height:1.5 }

.chat__routes{ display:grid; gap:var(--s2); margin:0; padding:0; list-style:none }
.chat__routes a{
  display:flex; align-items:center; gap:var(--s3);
  padding:var(--s3); border-radius:var(--r-sm);
  color:var(--ink); text-decoration:none;
  transition:background .18s ease;
}
.chat__routes a:hover{ background:var(--sand) }
.chat__routes b{ display:block; font-size:var(--t-sm); font-weight:700 }
/* The second line is metadata, so it takes --ink-2 rather than the quiet token, which fails AA at this size. */
.chat__routes span span{ display:block; font-size:var(--t-xs); color:var(--ink-2); line-height:1.4 }
.chat__ico{
  display:grid; place-items:center; flex:none;
  width:34px; height:34px; border-radius:var(--r-sm);
  background:var(--red-wash); color:var(--red);
}
.chat__ico svg{ width:17px; height:17px; fill:none; stroke:currentColor; stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round }

@media (max-width:420px){
  .chat__panel{ width:calc(100vw - var(--s4) * 2) }
}
@media (prefers-reduced-motion: reduce){
  .chat__panel, .chat__glyph, .chat__launcher{ transition:none }
  @starting-style{ .chat__panel{ transform:none } }
}
.btt svg{ width:22px; height:22px; stroke:currentColor; stroke-width:2;
          fill:none; stroke-linecap:round; stroke-linejoin:round; }

@media print{ .btt{ display:none !important } }

/* Content card — hub grids and the home page. Lived in showcase.css until index.html needed it, and that sheet is 14 KB of hub styling this page does not load. */
.cards{ display:grid; gap:var(--s4); grid-template-columns:1fr }
@media (min-width:660px){ .cards{ grid-template-columns:repeat(2,1fr) } }
@media (min-width:1040px){ .cards{ grid-template-columns:repeat(3,1fr) } }

.card{
  display:flex; flex-direction:column; overflow:hidden;
  background:var(--white);
  border:1px solid var(--line-2);
  border-radius:var(--r-lg);
  box-shadow:var(--sh-2);
  text-decoration:none; color:var(--ink);
  transition:transform 350ms var(--e), box-shadow 350ms var(--e);
}
.card:hover{ transform:translateY(-4px); box-shadow:var(--sh-3); color:var(--ink) }
.card__art{
  display:block; background:var(--ink);
  border-bottom:1px solid var(--line);
  overflow:hidden;
}
.card__art img{
  width:100%; display:block;
  aspect-ratio:1000 / 562; object-fit:cover;
  transition:scale var(--dur-slow) var(--e);
}
.card:hover .card__art img{ scale:1.03 }
.card__body{ padding:var(--s5); display:flex; flex-direction:column; flex:1; gap:var(--s2) }
.card__title{
  display:flex; align-items:center; justify-content:space-between; gap:var(--s3);
  font-size:var(--t-h2); font-weight:700; letter-spacing:-.025em;
}
.card__title svg{
  width:17px; height:17px; flex:none; color:var(--red);
  stroke:currentColor; stroke-width:2.2; fill:none;
  stroke-linecap:round; stroke-linejoin:round;
  transition:translate var(--dur) var(--e);
}
.card:hover .card__title svg{ translate:3px 0 }
.card__desc{ font-size:var(--t-sm); color:var(--ink-2); line-height:1.55; margin-bottom:auto }
.card__flag{
  align-self:flex-start; margin-top:var(--s3);
  padding:4px 11px; border-radius:var(--r-pill);
  background:var(--blush); color:var(--red);
  border:1px solid var(--red-soft);
  font-size:var(--t-lab); font-weight:700;
  letter-spacing:.07em; text-transform:uppercase;
}

/* ── Partner application ─────────────────────────────────────────────── */

.site-foot__cta{ display:inline-flex; margin-top:var(--s4) }

/* Native <dialog> so the focus trap, inert background and Escape are the browser's job. */
.pmodal{
  width:min(920px, calc(100vw - var(--s4) * 2));
  max-width:none; max-height:calc(100dvh - var(--s5) * 2);
  padding:0; border:0; border-radius:var(--r-lg);
  background:var(--white); box-shadow:var(--sh-4);
  overflow:hidden;
}
.pmodal::backdrop{ background:rgba(25,20,22,.55) }
.pmodal__in{ display:flex; flex-direction:column; max-height:calc(100dvh - var(--s5) * 2) }
.pmodal__bar{
  display:flex; align-items:center; justify-content:space-between; gap:var(--s3);
  padding:var(--s4) var(--s4) var(--s4) var(--s5);
  border-bottom:1px solid var(--line);
}
.pmodal__title{ font-size:var(--t-sm); font-weight:700; letter-spacing:-.02em; color:var(--ink) }
.pmodal__close{
  display:grid; place-items:center;
  width:40px; height:40px; border-radius:var(--r-sm);
  border:1px solid var(--line-2); background:var(--white); color:var(--ink-2);
  cursor:pointer;
  transition:color var(--dur-fast) var(--e), border-color var(--dur-fast) var(--e),
             background var(--dur-fast) var(--e);
}
.pmodal__close svg{
  width:18px; height:18px; fill:none; stroke:currentColor; stroke-width:1.9;
  stroke-linecap:round; stroke-linejoin:round;
}
.pmodal__close:hover{ color:var(--red); border-color:var(--red-soft); background:var(--red-wash) }

/* 720px is the height the form is authored against; it shrinks rather than scrolling the dialog. */
.pmodal__frame{ display:block; width:100%; height:min(720px, calc(100dvh - 190px)); border:0 }

/* showModal() makes the page inert but does not stop it scrolling behind. */
html.pmodal-open{ overflow:hidden }

/* The same frame in a page rather than an overlay — /partners/join/, where the buttons land without JS. */
.pembed{
  border:1px solid var(--line-2); border-radius:var(--r-lg);
  background:var(--white); box-shadow:var(--sh-2); overflow:hidden;
}
.pembed iframe{ display:block; width:100%; height:720px; border:0 }
