/* ==========================================================================
   Homepage v2 — built on Skynet UI (https://skynetui.com)
   Only page-specific layout lives here; components come from skynet-ui.css.
   Every color below is a Skynet UI token so the page follows the theme.
   ========================================================================== */

/* Palettes live in public/css/themes-v2.css — one copy for all six
   themes, loaded before this file. What stays here is this page's own
   layout, which is not a colour and does not change with the theme. */

/* Skynet UI declares `.hidden` before its component display rules, so a
   hidden `.sk-card` / `.sk-btn` would still render. Scope a hard override to
   this page — same quirk leaderboard-v2.css works around. */
.hv2 .hidden,
.hv2 [hidden] {
  display: none !important;
}

/* `.sk-btn` is ~37px and `.sk-btn-sm` ~28px; this page is touch-first. */
.hv2 .sk-btn {
  min-height: 44px;
}
/* A round button needs the floor on both axes, or min-height alone turns it
   into a 40x44 ellipse that still misses the 44px target on the short side. */
.hv2 .sk-btn-icon {
  min-width: 44px;
  min-height: 44px;
}
/* --sk-primary is ~3.1:1 on a card surface; the -text variant clears AA. */
.hv2 :focus-visible {
  outline-color: var(--sk-primary-text);
}
/* Inline links inherit --sk-primary, which measures 3.47:1 on the page
   background and 3.14:1 on a card — both short of AA for body text. The
   lighter -text token clears it on every surface this page uses. Buttons
   opt out: they carry their own foreground on a filled background. */
.hv2 a:not(.sk-btn) {
  color: var(--sk-primary-text);
}
/* The site header is fixed, so an anchor jump has to clear it or the target
   lands underneath. */
#hv2-main,
.hv2-section {
  scroll-margin-top: 76px;
}
body.has-partnership-widget #hv2-main,
body.has-partnership-widget .hv2-section {
  scroll-margin-top: 120px;
}
/* Skynet UI puts its toast container at z-index 400, well under the fixed
   header at 10000 — a top-anchored toast would be invisible. */
.hv2 .sk-toast-container {
  z-index: 10100;
}

/* ---------- motion ----------
   Everything here is scoped to `html.hv2-anim`, which ONLY public/js/index-v2.js
   sets, and which it never sets when the visitor has asked for reduced motion.
   So: no JavaScript, or reduced motion, means no hidden content — not a blank
   page waiting for a script that is not coming. Nothing below animates a
   property other than transform and opacity. */
.hv2-anim [data-hv2-reveal] {
  opacity: 0;
  transform: translateY(12px);
  transition: opacity 0.5s ease, transform 0.5s cubic-bezier(0.22, 1, 0.36, 1);
  /* Staggered children set --hv2-i to their index. */
  transition-delay: calc(var(--hv2-i, 0) * 70ms);
}
.hv2-anim [data-hv2-reveal][data-hv2-shown] {
  opacity: 1;
  transform: none;
}

/* The hero is above the fold, so it plays on load rather than on scroll — a
   scroll reveal for content already on screen is a flash of nothing. Pure CSS,
   so there is no script to wait for and no hidden state to get stuck in. */
@media (prefers-reduced-motion: no-preference) {
  .hv2-hero-copy > *,
  .hv2-hero-figure {
    animation: hv2-rise 0.6s cubic-bezier(0.22, 1, 0.36, 1) both;
  }
  .hv2-hero-copy > :nth-child(2) { animation-delay: 0.06s; }
  .hv2-hero-copy > :nth-child(3) { animation-delay: 0.12s; }
  .hv2-hero-copy > :nth-child(4) { animation-delay: 0.18s; }
  .hv2-hero-figure { animation-delay: 0.22s; }
}
@keyframes hv2-rise {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

/* A slow drifting glow behind the hero. Decorative, pointer-events:none, and
   painted on its own layer so it never touches layout. */
.hv2-hero::before {
  content: "";
  position: absolute;
  /* The glow is inset 6% and the drift below scales it to 1.08 and shifts it
     2%, so its widest excursion is ~99.5% of the container — it can never
     reach the edge. Two earlier versions of this rule did: a negative
     horizontal inset, then a full-width box that scale(1.08) pushed 4% past
     each side. Both took the whole page sideways, and because this is a
     PSEUDO-ELEMENT neither showed up in a DOM sweep for overflowing elements.
     Measure documentElement.scrollWidth instead; that is how both were found. */
  inset: -20% 6% auto 6%;
  height: 26rem;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(40% 55% at 22% 28%, rgba(147, 51, 234, 0.22), transparent 70%),
    radial-gradient(36% 50% at 78% 18%, rgba(56, 189, 248, 0.14), transparent 70%);
  filter: blur(6px);
}
@media (prefers-reduced-motion: no-preference) {
  .hv2-hero::before {
    animation: hv2-drift 24s ease-in-out infinite alternate;
  }
}
@keyframes hv2-drift {
  from { transform: translate3d(-2%, 0, 0) scale(1); }
  to   { transform: translate3d(2%, 2%, 0) scale(1.08); }
}

/* The live dot earns its name. */
@media (prefers-reduced-motion: no-preference) {
  .hv2-live-dot {
    animation: hv2-pulse 2.4s ease-in-out infinite;
  }
}
@keyframes hv2-pulse {
  0%, 100% { box-shadow: 0 0 0 3px var(--sk-success-soft); }
  50%      { box-shadow: 0 0 0 6px transparent; }
}

/* Last line of defence: if any rule above is ever added without its own
   guard, this switches the whole page back to still. */
@media (prefers-reduced-motion: reduce) {
  .hv2 *,
  .hv2 *::before,
  .hv2 *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---------- page rhythm ---------- */
.hv2-section {
  padding-block: clamp(2.5rem, 1.5rem + 4vw, 4.5rem);
}
.hv2-section + .hv2-section {
  border-top: 1px solid var(--sk-border);
}
.hv2-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin: 0 0 0.5rem;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--sk-primary-text);
}
.hv2-h2 {
  margin: 0 0 0.5rem;
  font-size: clamp(1.5rem, 1.15rem + 1.6vw, 2.15rem);
  line-height: 1.2;
  letter-spacing: -0.01em;
}
.hv2-intro {
  max-width: 60ch;
  margin: 0 0 2rem;
  color: var(--sk-text-2);
}
/* Numerals carry the emphasis; `text-primary` (--sk-primary) fails AA here. */
.hv2-num {
  color: var(--sk-primary-text);
}

/* Skip link: the site header is position:fixed at z-index 10000, so the
   classic page's skip link is invisible when focused. Sit above it.

   Selector deliberately carries `.hv2 a` — `.hv2 a:not(.sk-btn)` above is more
   specific than a bare `.hv2-skip` and was winning, so the label rendered as
   the accent's -text token ON the accent fill: 2.2:1 in dark and 1.4:1 in
   light. A skip link is the one control a keyboard user has no way around, so
   it gets the white it asks for. */
.hv2 a.hv2-skip {
  position: fixed;
  left: 1rem;
  top: 0.75rem;
  z-index: 10050;
  padding: 0.65rem 1rem;
  border-radius: var(--sk-radius);
  background: var(--sk-primary);
  color: #fff;
  font-weight: 600;
  text-decoration: none;
  transform: translateY(-200%);
  transition: transform var(--sk-transition);
}
.hv2 a.hv2-skip:focus-visible,
.hv2 a.hv2-skip:focus {
  transform: translateY(0);
}

/* ---------- S1 hero ---------- */
.hv2-hero {
  display: grid;
  gap: 2rem;
  align-items: center;
  padding-block: clamp(1.75rem, 1rem + 3vw, 3.5rem);
  /* Anchors the decorative ::before glow, which is z-index:-1 and therefore
     needs a positioned ancestor or it escapes to the page background. */
  position: relative;
  /* Backstop for the same glow: clip horizontally so no decorative child can
     widen the page, while vertical bleed still works. `clip` rather than
     `hidden` because `hidden` would make this a scroll container. */
  overflow-x: clip;
}
.hv2-hero-copy {
  min-width: 0;
}
.hv2-hero h1 {
  margin: 0 0 0.75rem;
  font-size: clamp(2rem, 1.4rem + 2.8vw, 3.25rem);
  line-height: 1.05;
  letter-spacing: -0.02em;
}
.hv2-hero-sub {
  max-width: 56ch;
  margin: 0 0 1.5rem;
  font-size: clamp(1rem, 0.95rem + 0.3vw, 1.15rem);
  color: var(--sk-text-2);
}
.hv2-hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-bottom: 1.25rem;
}
.hv2-hero-actions .sk-btn {
  flex: 1 1 15rem;
  justify-content: center;
}
/* Below 1024 the trust bullets sit under the artifact, so the CTA stays on
   the first screen at 320x568. */
.hv2-trust {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.25rem;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 0.875rem;
  color: var(--sk-text-2);
}
.hv2-trust li {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}
.hv2-trust i {
  color: var(--sk-success-text);
}
.hv2-hero-figure {
  min-width: 0;
  order: 2;
}
.hv2-hero-trust {
  order: 3;
}
@media (min-width: 1024px) {
  /* Two columns, two rows: copy over bullets on the left, the figure spanning
     both on the right. Placing them explicitly keeps the bullets tucked under
     the CTAs — leaving them to flow put a full column gap between the two. */
  .hv2-hero {
    grid-template-columns: 1.05fr 1fr;
    column-gap: 3rem;
    row-gap: 1.25rem;
  }
  .hv2-hero-copy {
    grid-column: 1;
    grid-row: 1;
  }
  .hv2-hero-trust {
    grid-column: 1;
    grid-row: 2;
    order: 0;
  }
  .hv2-hero-figure {
    grid-column: 2;
    grid-row: 1 / span 2;
    align-self: center;
    order: 0;
  }
}

/* ---------- Discord message ----------
   The shape of a real Discord embed, because these carry real killfeed rows:
   a coloured bar down the left, then title, description, fields and footer.
   The accent is the bot's own colour for that event type, set once on the
   <figure> by utils/killfeedEmbeds.js and inherited by everything below. */
.hv2-embed {
  margin: 0;
  min-width: 0;
}
[data-hv2-accent="danger"] {
  --hv2-accent: var(--sk-danger);
  --hv2-accent-text: var(--sk-danger-text);
}
[data-hv2-accent="success"] {
  --hv2-accent: var(--sk-success);
  --hv2-accent-text: var(--sk-success-text);
}
[data-hv2-accent="warning"] {
  --hv2-accent: var(--sk-warning);
  --hv2-accent-text: var(--sk-warning-text);
}
[data-hv2-accent="info"] {
  --hv2-accent: var(--sk-info);
  --hv2-accent-text: var(--sk-info-text);
}
/* The bot's real Discord avatar, sized to match the `sk-avatar-sm` circle it
   replaces so the header does not shift when Discord answers. */
.hv2-msg-avatar {
  flex: none;
  width: 2rem;
  height: 2rem;
  border-radius: 999px;
  object-fit: cover;
  background: var(--sk-surface-2);
}
.hv2-embed-card {
  position: relative;
  margin-top: 0.5rem;
  /* Discord's 4px accent bar, and its squared-off outer corners. */
  border-inline-start: 4px solid var(--hv2-accent, var(--sk-primary));
  border-radius: 4px;
  background: var(--sk-bg);
  padding: 0.7rem 0.85rem;
  min-width: 0;
}
.hv2-embed-title {
  font-weight: 700;
  font-size: 0.9rem;
  line-height: 1.3;
  color: var(--hv2-accent-text, var(--sk-primary-text));
}
.hv2-embed-desc,
.hv2-embed-detail {
  margin: 0.35rem 0 0;
  font-size: 0.85rem;
  line-height: 1.45;
  /* A gamertag has no spaces to break at and the card is 320px wide on a
     phone; without this one long name takes the page sideways with it. */
  overflow-wrap: anywhere;
}
.hv2-embed-detail {
  color: var(--sk-text-2);
}
/* The bot masks player names as links and the surrounding markdown bolds them;
   the anchor branch in the template cannot also be a <strong>, so the weight
   comes from here. */
.hv2-embed-desc a {
  font-weight: 700;
}
.hv2-embed-fields {
  display: grid;
  gap: 0.6rem;
  margin-top: 0.7rem;
  min-width: 0;
}
/* Discord lays inline fields out side by side and gives a non-inline field the
   whole row. `auto-fit` does both from one rule: an inline field asks for a
   6rem-minimum column, a full-width one spans every column there is. */
@media (min-width: 26em) {
  .hv2-embed-fields {
    grid-template-columns: repeat(auto-fit, minmax(6rem, 1fr));
  }
  .hv2-embed-field:not(.hv2-embed-field-inline) {
    grid-column: 1 / -1;
  }
}
.hv2-embed-field {
  min-width: 0;
}
.hv2-embed-field-name {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--sk-muted);
}
.hv2-embed-field-value {
  font-size: 0.82rem;
  line-height: 1.5;
  overflow-wrap: anywhere;
}
.hv2-embed-key {
  color: var(--sk-muted);
}
/* Discord floats the thumbnail top-right of the embed body and flows the text
   around it. Below 26em there is no room for both, so it drops out rather than
   squeezing the title into two words a line. */
.hv2-embed-thumb {
  display: none;
}
@media (min-width: 26em) {
  .hv2-embed-thumb {
    display: block;
    position: absolute;
    top: 0.7rem;
    right: 0.85rem;
    width: 3.25rem;
    height: 3.25rem;
    object-fit: contain;
  }
  /* Keep the title and description clear of it. */
  .hv2-has-thumb .hv2-embed-title,
  .hv2-has-thumb .hv2-embed-desc {
    padding-right: 3.75rem;
  }
}
/* `embed.set_image()` — full width across the bottom, as Discord renders it.
   Capped in height so a tall gun cannot push the hero past the fold. */
.hv2-embed-image {
  display: block;
  width: 100%;
  max-width: 20rem;
  max-height: 4.5rem;
  object-fit: contain;
  object-position: left center;
  margin-top: 0.7rem;
}
.hv2-embed-powered {
  margin: 0.7rem 0 0;
  font-size: 0.75rem;
  color: var(--sk-text-2);
}
.hv2-embed-footer {
  margin: 0.5rem 0 0;
  padding-top: 0.5rem;
  border-top: 1px solid var(--sk-border);
  font-size: 0.7rem;
  font-variant-numeric: tabular-nums;
  color: var(--sk-muted);
}
.hv2-embed figcaption {
  margin-top: 0.6rem;
  font-size: 0.75rem;
  color: var(--sk-muted);
}
.hv2-embed-grid {
  display: grid;
  gap: 1rem;
  min-width: 0;
}

/* ---------- killfeed ticker ----------
   A marquee of real events. The track holds the list twice and translates
   -50%, so it lands exactly where it started and loops seamlessly. */
.hv2-tickbar {
  border-block: 1px solid var(--sk-border);
  background: var(--sk-surface);
}
.hv2-tick {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  min-width: 0;
}
.hv2-tick-label {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  flex: none;
  padding-block: 0.6rem;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--sk-text-2);
}
/* Fade both ends so entries arrive and leave rather than popping at a hard
   edge. `mask-image` needs the -webkit- prefix for Safari. */
.hv2-tick-view {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 3%, #000 97%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 3%, #000 97%, transparent);
}
.hv2-tick-track {
  display: flex;
  width: max-content;
}
.hv2-tick-group {
  display: flex;
  align-items: center;
  gap: 1.75rem;
  margin: 0;
  padding: 0.6rem 0.9rem;
  list-style: none;
}
.hv2-tick-ev {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  white-space: nowrap;
  font-size: 0.82rem;
  color: var(--sk-text-2);
}
.hv2-tick-ev strong {
  color: var(--sk-text);
  font-weight: 600;
}
.hv2-tick-arrow {
  color: var(--sk-danger);
  font-weight: 700;
}
.hv2-tick-ev code {
  font-size: 0.72rem;
  color: var(--sk-muted);
  background: var(--sk-surface-2);
  border: 1px solid var(--sk-border);
  border-radius: 6px;
  padding: 0.1rem 0.4rem;
}
/* Each kind reads at a glance, and never by colour alone — the words
   "connected", "disconnected" and "died" carry it too. */
.hv2-tick-ev[data-hv2-ev="connect"] strong,
.hv2-tick-ev[data-hv2-ev="connect"] .hv2-tick-verb {
  color: var(--sk-success-text);
}
.hv2-tick-ev[data-hv2-ev="disconnect"] strong,
.hv2-tick-ev[data-hv2-ev="disconnect"] .hv2-tick-verb {
  color: var(--sk-danger-text);
}
.hv2-tick-ev[data-hv2-ev="env"] code {
  color: var(--sk-info-text);
  border-color: var(--sk-info-soft);
}

/* The scroll itself is opt-in on motion. Without this block the track sits
   still and the strip is a plain row of the newest events — which is why the
   overflow below is made reachable rather than simply hidden. */
@media (prefers-reduced-motion: no-preference) {
  .hv2-tick-track {
    animation: hv2-marquee 48s linear infinite;
  }
  /* Stop it to read one, and stop it for anyone driving by keyboard. */
  .hv2-tick:hover .hv2-tick-track,
  .hv2-tick:focus-within .hv2-tick-track {
    animation-play-state: paused;
  }
}
@keyframes hv2-marquee {
  to {
    transform: translateX(-50%);
  }
}
/* With motion off the entries never come round, so the strip has to be
   reachable by hand instead: it scrolls, and the duplicate track is dropped
   so there is nothing to scroll through twice. */
@media (prefers-reduced-motion: reduce) {
  .hv2-tick-view {
    overflow-x: auto;
  }
  .hv2-tick-track {
    width: auto;
  }
  .hv2-tick-group[aria-hidden="true"] {
    display: none;
  }
}

/* ---------- S2 proof band ---------- */
/* The numbers are the hero's evidence, so they sit closer to it than a full
   section break would put them. */
#hv2-proof {
  padding-block: clamp(1.25rem, 0.9rem + 1.6vw, 2.25rem);
}
.hv2-band {
  /* The numeral size lives here so the value row can reserve exactly its line
     box (below) and the labels line up across every tile — including the bot
     tile, whose "value" is a badge roughly half the height of a numeral. */
  --hv2-band-num: clamp(1.1rem, 0.75rem + 2.2vw, 1.6rem);
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.6rem;
}
/* Each figure sits in its own tile. Four numbers reading straight off the page
   background had nothing grouping them, so the band read as loose text rather
   than a set of statistics — and the bot's badge, being a different shape from
   a numeral, looked like it had wandered in from somewhere else. */
.hv2-band > * {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  padding: 0.7rem 0.8rem;
  border: 1px solid var(--sk-border);
  border-radius: 12px;
  background: var(--sk-surface);
}
.hv2-band .sk-stat-value {
  color: var(--sk-primary-text);
  font-variant-numeric: tabular-nums;
  /* "4,820,113" at the stock stat size is wider than a 320px half-column and
     pushes the page sideways. Scale the numeral with the viewport instead. */
  font-size: var(--hv2-band-num);
  line-height: 1.15;
  /* Reserve the numeral's line box whatever the tile holds, so the badge tile's
     label sits on the same line as the others'. */
  display: flex;
  align-items: center;
  min-height: calc(var(--hv2-band-num) * 1.15);
}
.hv2-band .sk-stat-label {
  line-height: 1.3;
}
/* Four across from 640px, not 1024. At 768 — an ordinary tablet — the band was
   still two columns with an eighth of the row empty between them. */
@media (min-width: 40em) {
  .hv2-band {
    grid-template-columns: repeat(var(--hv2-band-cols, 4), minmax(0, 1fr));
    gap: 0.75rem;
    /* Four columns at 640px are ~143px wide, and the old curve put a 26px
       numeral in them — "4,494,079" is about 124px of that before padding.
       This one grows more slowly so the widest figure always clears its tile. */
    --hv2-band-num: clamp(1rem, 0.45rem + 1.7vw, 1.75rem);
  }
}

/* ---------- alternating feature rows ---------- */
.hv2-row {
  display: grid;
  gap: 2rem;
  align-items: center;
}
.hv2-row > * {
  min-width: 0;
}
@media (min-width: 1024px) {
  .hv2-row {
    grid-template-columns: 1fr 1fr;
    gap: 3rem;
  }
  /* Visual left, copy right — DOM order stays copy-first for screen readers. */
  .hv2-alt .hv2-row-copy {
    order: 2;
  }
}
.hv2-bullets {
  margin: 1.25rem 0 1.5rem;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 0.6rem;
}
.hv2-bullets li {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  color: var(--sk-text-2);
}
.hv2-bullets i {
  margin-top: 0.2rem;
  color: var(--sk-primary-text);
}

/* ---------- tables on a phone ----------
   Below `sm` the top-five table shows three of its five columns, and the rank
   column was taking a fixed share of the row — leaving a gap between "#" and
   the player's name wide enough to park the K/D column in. Shrink the rank to
   what a single digit needs and give the slack back to the name. */
@media (max-width: 40em) {
  .hv2 .sk-table th,
  .hv2 .sk-table td {
    padding-inline: 0.5rem;
  }
  .hv2 .sk-table th:first-child,
  .hv2 .sk-table td:first-child {
    width: 1.5rem;
    padding-inline-end: 0;
  }
}

/* ---------- S5 live marker ---------- */
.hv2-live {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
}
.hv2-live-dot {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 999px;
  background: var(--sk-success);
  box-shadow: 0 0 0 3px var(--sk-success-soft);
}

/* ---------- top weapons ----------
   A ranked bar list. The bar is a decorative track behind real numbers, so it
   is aria-hidden and the kill count carries the value. */
.hv2-wep {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.6rem;
}
.hv2-wep-row {
  display: grid;
  /* rank · picture · name · bar · kills */
  grid-template-columns: 1.5rem 2.75rem minmax(0, 1fr) auto;
  grid-template-areas:
    "rank pic name kills"
    "bar  bar bar  bar";
  align-items: center;
  gap: 0.5rem 0.75rem;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--sk-border);
  border-radius: 10px;
  background: var(--sk-surface);
  min-width: 0;
}
@media (min-width: 48em) {
  .hv2-wep-row {
    grid-template-columns: 1.75rem 3.25rem minmax(0, 12rem) minmax(0, 1fr) auto;
    grid-template-areas: "rank pic name bar kills";
  }
}
.hv2-wep-rank {
  grid-area: rank;
  color: var(--sk-faint);
  font-size: 0.85rem;
  text-align: right;
}
.hv2-wep-pic {
  grid-area: pic;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 1.9rem;
}
.hv2-wep-pic img {
  max-width: 100%;
  max-height: 1.9rem;
  object-fit: contain;
}
.hv2-wep-name {
  grid-area: name;
  font-weight: 600;
  font-size: 0.9rem;
  overflow-wrap: anywhere;
}
.hv2-wep-track {
  grid-area: bar;
  height: 0.45rem;
  border-radius: 999px;
  background: var(--sk-surface-2);
  overflow: hidden;
  min-width: 0;
}
.hv2-wep-fill {
  display: block;
  height: 100%;
  width: var(--hv2-wep-pct, 0%);
  border-radius: inherit;
  background: linear-gradient(90deg, var(--sk-primary), var(--sk-info));
}
/* Grows to the server-rendered width when the chart scrolls into view. The
   width is real either way — this only animates the arrival. */
.hv2-anim .hv2-wep-fill {
  width: 0;
  transition: width 0.9s cubic-bezier(0.22, 1, 0.36, 1);
  transition-delay: calc(var(--hv2-wep-i, 0) * 80ms);
}
.hv2-anim [data-hv2-filled] .hv2-wep-fill {
  width: var(--hv2-wep-pct, 0%);
}
.hv2-wep-kills {
  grid-area: kills;
  font-size: 0.85rem;
  white-space: nowrap;
}

/* ---------- S9 testimonials ---------- */
/* The UA stylesheet indents <blockquote> by 40px. Inside a card on a 390px
   phone that left the quote about 60px in from the card edge and cut the line
   to six or seven words, so a three-line quote ran to eight. The quotation
   marks and the card already mark it as a quote; the indent only cost width. */
.hv2 blockquote {
  margin-inline: 0;
}

/* ---------- S6 dashboard frame ---------- */
.hv2-frame {
  border: 1px solid var(--sk-border-2);
  border-radius: var(--sk-radius-lg);
  background: var(--sk-surface);
  overflow: hidden;
}
.hv2-frame-bar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.6rem 0.9rem;
  border-bottom: 1px solid var(--sk-border);
  background: var(--sk-surface-2);
}
.hv2-frame-dots {
  display: inline-flex;
  gap: 0.3rem;
}
.hv2-frame-dots i {
  width: 0.55rem;
  height: 0.55rem;
  border-radius: 999px;
  background: var(--sk-border-2);
}
/* The mock may be wider than the column; the page may not. */
.hv2-frame-body {
  padding: 1rem;
  /* Safety net only. `.hv2-frame-inner` has no width floor any more, so there
     is nothing left to scroll — see below. */
  overflow-x: auto;
}
/* The mock REFLOWS at every width; it has no width floor at all.
   `.hv2-frame-inner` used to carry `min-width: 30rem` (480px), which with the
   body's padding wanted 512px. A phone gave it ~340px, so it scrolled sideways
   inside its own box: the third tile sliced down the middle, three of the six
   bars off the right edge, every percentage invisible. And it was not only a
   phone problem — between 1024px and ~1150px the two-column row hands this
   side ~472px, so the Bans tile and the percentages were clipped there too.

   Nobody drags a decorative illustration sideways to see the rest of it: the
   mock is `inert aria-hidden` and there is nothing in there to go and read.
   Since `.hv2-frame-inner` is a block, dropping the floor makes it exactly as
   wide as the space it is given at every width, which is the whole fix — the
   tiles shrink with `minmax(0, 1fr)` and go two-up below 34em. */
.hv2-frame-tiles {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.6rem;
  margin-bottom: 1rem;
}
@media (min-width: 34em) {
  .hv2-frame-tiles {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 0.75rem;
  }
}
.hv2-frame-tile {
  padding: 0.7rem 0.8rem;
  border: 1px solid var(--sk-border);
  border-radius: var(--sk-radius-sm);
  background: var(--sk-surface-2);
  min-width: 0;
}
.hv2-frame-tile .sk-stat-value {
  font-size: 1.25rem;
  font-variant-numeric: tabular-nums;
}
/* Two-up on a phone means half the width for the same label: let the smaller
   ones sit on one line rather than breaking "KILLS / TODAY" across two. */
@media (max-width: 34em) {
  .hv2-frame-tile .sk-stat-label {
    font-size: 0.65rem;
    letter-spacing: 0.06em;
  }
  .hv2-frame-tile .sk-stat-value {
    font-size: 1.1rem;
  }
}

/* ---------- S4 steps ---------- */
/* `sk-step-dot` renders muted outside a `.sk-steps` wizard. */
.hv2-stepnum {
  background: var(--sk-primary-soft);
  border-color: var(--sk-primary);
  color: var(--sk-primary-text);
  margin-bottom: 0.75rem;
}

/* viewport-fit=cover lets the page under the notch, so the side insets have
   to be paid back too — in landscape on a notched phone, 1rem of gutter is
   behind the sensor housing. sk-container ships 1rem, so max() never reduces
   it. */
.hv2 .sk-container,
.hv2 .hv2-stickycta {
  padding-left: max(1rem, env(safe-area-inset-left));
  padding-right: max(1rem, env(safe-area-inset-right));
}

/* ---------- chrome ---------- */
.hv2-stickycta {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 9500;
  padding: 0.75rem 1rem calc(0.75rem + env(safe-area-inset-bottom));
  border-top: 1px solid var(--sk-border-2);
  background: var(--sk-surface);
  box-shadow: var(--sk-shadow-lg);
}
@media (min-width: 768px) {
  .hv2-stickycta {
    display: none !important;
  }
}
/* Reserve the bar's height under the footer so a fixed overlay can never be
   the thing covering the last row of links. */
@media (max-width: 767px) {
  .hv2 .sk-footer {
    padding-bottom: calc(5.5rem + env(safe-area-inset-bottom));
  }
}
.hv2-totop {
  position: fixed;
  right: 1rem;
  bottom: 1rem;
  z-index: 9400;
}
@media (max-width: 1023px) {
  .hv2-totop {
    display: none !important;
  }
}

/* ---------- the app ("Skynet in your pocket") ----------
   Copy on the left, one card per platform on the right; stacked on a phone.
   What each card offers comes from utils/appInstall.js on the server. */
.hv2-app-grid {
  display: grid;
  gap: 2rem;
  align-items: start;
}
.hv2-app-grid > *,
.hv2-app-stores > * {
  min-width: 0;
}
@media (min-width: 1024px) {
  .hv2-app-grid {
    grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
    gap: 3rem;
  }
}
.hv2-app-points {
  display: grid;
  gap: 0.75rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.hv2-app-points li {
  display: flex;
  gap: 0.75rem;
  align-items: baseline;
  color: var(--sk-text-2);
  overflow-wrap: anywhere;
}
.hv2-app-points i {
  flex: 0 0 1.25rem;
  text-align: center;
  color: var(--sk-primary-text);
}
.hv2-app-stores {
  display: grid;
  gap: 1rem;
}
@media (min-width: 34em) {
  .hv2-app-stores {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .hv2-app-share {
    grid-column: 1 / -1;
  }
}
.hv2-app-store .sk-card-body {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  height: 100%;
}
.hv2-app-store .sk-card-title {
  margin: 0;
}
.hv2-app-store p {
  flex: 1 1 auto;
  margin: 0 0 0.5rem;
}
.hv2-app-icon {
  display: inline-grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: var(--sk-radius, 0.75rem);
  background: var(--sk-primary-soft, var(--sk-surface-2));
  color: var(--sk-primary-text);
  font-size: 1.35rem;
}
.hv2-app-soon {
  align-self: flex-start;
}
.hv2-app-share {
  margin: 0;
  font-size: 0.9rem;
  color: var(--sk-text-2);
  overflow-wrap: anywhere;
}
.hv2-app-share a:not(.sk-btn) {
  color: var(--sk-primary-text);
}
