/* ============================================================
   SkinSignal / the landing hero
   index.html #signalHero: the cinematic entry and the feature rail,
   then the floor (the stats line and the example ticker).

   THE COMPOSITION, back to front:

     the ground      near black #05090f, a faint blue atmosphere behind
                     the art and a gold whisper under it. Blue is the CTA
                     and a few accents; gold is prestige. Never a wash.
     the figure      the rank emblem at full size (Set 1 is Diamond Hands,
                     assets/landing/prestige-hero), large, emerging from
                     the right and bleeding toward the centre, with a soft
                     fade into the page below
     the mask        solid behind the words and gone by ~72% across, so
                     the copy reads perfectly and the art becomes the page
                     rather than a picture placed on it
     the cards       three real calling cards floating in front, 3:1 and
                     never stretched, the centre one forward and largest,
                     each with a hairline of gold. ABOVE the mask, so the
                     fade never dims them
     the rank name   top right of the art: the tier and its name.
                     The emblem, the cards and the name turn through four
                     sets together (js/hero-showcase.js)
     the copy        eyebrow, the four line headline, body, the one door
                     (Sign in with Steam), the trust row

   THE CARDS SIT ABOVE THE MASK BECAUSE .lhero__art NEVER BECOMES A
   STACKING CONTEXT. It carries no z-index, no transform and no opacity,
   so its children join the section's own stack: figure 1, mask 2,
   cards 3, copy 10. The load motion therefore animates the figure and
   the cards themselves, never their container.

   MOTION, only when asked for: the headline rises (400ms), the art
   fades and settles (700ms), the cards arrive 60ms apart, and nothing
   loops. The CTA does not pulse.
   ============================================================ */

.lhero {
  --hero-h: clamp(560px, 36vw, 700px);
  --pad: clamp(20px, 3.8vw, 76px);
  --hero-bg: #05090f;
  --gold: #e4ae39;
  --blue: #4c8dff;
  --ink-2: #b9bfca;
  --ink-3: #939aa7;

  position: relative;
  isolation: isolate;
  overflow: hidden;
  padding-bottom: clamp(36px, 4.4vw, 64px);
  background:
    radial-gradient(52% 62% at 70% 34%, rgba(46, 96, 196, 0.17), rgba(46, 96, 196, 0) 70%),
    radial-gradient(34% 30% at 68% 70%, rgba(228, 174, 57, 0.07), rgba(228, 174, 57, 0) 72%),
    linear-gradient(180deg, #05090f 0%, #05090f 78%, var(--bg) 100%);
}

/* ============================================================
   THE ART (right, bleeding in)
   ============================================================ */
.lhero__art {
  position: absolute;
  top: 0;
  right: -1%;
  width: 66%;
  height: var(--hero-h);
  pointer-events: none;
}

/* The faint blue atmosphere the figure emerges from. */
.lhero__atmo {
  position: absolute;
  inset: -6% 4% 6% 18%;
  z-index: 1;
  background:
    radial-gradient(38% 40% at 52% 46%, rgba(228, 174, 57, 0.13), rgba(228, 174, 57, 0) 100%),
    radial-gradient(closest-side, rgba(76, 141, 255, 0.2), rgba(76, 141, 255, 0.05) 60%, rgba(76, 141, 255, 0) 100%);
  filter: blur(8px);
}

.lhero__figure {
  position: absolute;
  z-index: 1;
  /* THE WHOLE FIGURE, IN FRAME. It was 120% of the hero and 8% above
     it, which cut the top crystal points off; it now sits inside the
     hero's height with a little air, every point visible, and the foot
     fades only at the very bottom so the lower point still reads. */
  left: 55%;
  top: 3%;
  height: 94%;
  aspect-ratio: 1 / 1;
  transform: translateX(-50%);
  -webkit-mask-image: linear-gradient(180deg, #000 84%, transparent 100%);
          mask-image: linear-gradient(180deg, #000 84%, transparent 100%);
}
/* THE STAGE AND THE EMBLEM. .lhero__figure is the stage: place, size,
   fade and drift. Each .lhero__emblem is one rank's art on it, stacked,
   and only the one marked is-on shows, so the showcase can cross-fade
   two emblems in the same place without touching the drift. */
.lhero__emblem {
  position: absolute;
  inset: 0;
  display: block;
  opacity: 0;
  scale: 0.98;
}
.lhero__emblem.is-on { opacity: 1; scale: 1; }
.lhero__emblem.is-out { opacity: 0; scale: 1.02; }
.lhero__figure-img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  filter: drop-shadow(0 30px 60px rgba(0, 0, 0, 0.55));
}

/* ============================================================
   THE READABILITY MASK
   ============================================================ */
.lhero__mask {
  position: absolute;
  z-index: 2;
  top: 0;
  left: 0;
  width: 100%;
  height: var(--hero-h);
  pointer-events: none;
  background:
    linear-gradient(90deg,
      rgba(5, 9, 15, 1) 0%,
      rgba(5, 9, 15, 0.97) 26%,
      rgba(5, 9, 15, 0.78) 40%,
      rgba(5, 9, 15, 0.32) 56%,
      rgba(5, 9, 15, 0) 72%),
    linear-gradient(180deg, rgba(5, 9, 15, 0) 74%, rgba(5, 9, 15, 0.9) 100%);
}

/* ============================================================
   THE CARDS (in front, above the mask)
   ============================================================ */
.lhero__cards { position: absolute; inset: 0; }

/* THE SLOT AND THE FACE. .lhero__card is the card's PLACE: its size,
   position, tilt and float. .lhero__face is the card IN it: the frame,
   the gold hairline and the art. The showcase turns faces inside a slot
   that never moves for it, so a turn can never disturb the tilt or the
   float, and two faces can cross-fade in the same place. */
.lhero__card {
  position: absolute;
  z-index: 3;
  margin: 0;
  aspect-ratio: 3 / 1;
}
.lhero__face {
  position: absolute;
  inset: 0;
  z-index: 1;
  border: 1px solid rgba(228, 174, 57, 0.48);
  border-radius: 7px;
  overflow: hidden;
  background: #0b0e14;
  box-shadow:
    0 22px 44px -10px rgba(0, 0, 0, 0.8),
    0 0 28px -6px rgba(228, 174, 57, 0.22);
  opacity: 0;
  translate: 0 8px;
}
.lhero__face.is-on { z-index: 2; opacity: 1; translate: 0 0; }
.lhero__face.is-out { opacity: 0; translate: 0 -6px; }
.lhero__face picture,
.lhero__face img { display: block; width: 100%; height: 100%; object-fit: cover; }

.lhero__card--left {
  /* A share of the ART BOX, not of the viewport: the box narrows
     faster than the window, so vw widths overlapped at 1024. */
  width: min(280px, 21.5%);
  left: 27%;
  bottom: 12%;
  transform: translateX(-50%) rotate(-2deg);
}
.lhero__card--centre {
  z-index: 4;
  width: min(390px, 31%);
  left: 54%;
  bottom: 10%;
  transform: translateX(-50%);
}
.lhero__card--centre .lhero__face {
  border-color: rgba(228, 174, 57, 0.62);
  box-shadow:
    0 26px 52px -10px rgba(0, 0, 0, 0.85),
    0 0 40px -6px rgba(228, 174, 57, 0.32);
}
.lhero__card--right {
  width: min(280px, 21.5%);
  left: 81%;
  bottom: 12%;
  transform: translateX(-50%) rotate(2deg);
}

/* ============================================================
   THE RANK NAME (top right of the art, above the mask)
   The set's place on the ladder and its name; the emblem itself is the
   big art. Names stack in one spot; only the one marked is-on shows.
   ============================================================ */
.lhero__ranks {
  position: absolute;
  z-index: 3;
  top: 7%;
  right: clamp(24px, 4.2vw, 84px);
}
.lhero__rank {
  position: absolute;
  top: 0;
  right: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 5px;
  white-space: nowrap;
  opacity: 0;
}
.lhero__rank.is-on { opacity: 1; }
.lhero__rank-tier {
  font-family: var(--font-display);
  font-stretch: 100%;
  font-weight: 600;
  font-size: 11px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--gold);
}
.lhero__rank-name {
  font-family: var(--font-display);
  font-stretch: 85%;
  font-weight: 700;
  font-size: clamp(18px, 1.2vw, 22px);
  line-height: 1;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  color: #f1f3f6;
}

/* ============================================================
   THE COPY (left)
   ============================================================ */
.lhero__inner {
  position: relative;
  z-index: 10;
  display: flex;
  align-items: center;
  min-height: var(--hero-h);
  padding: clamp(28px, 3vw, 48px) var(--pad);
}

.lhero__copy {
  width: 42%;
  max-width: 650px;
}

.lhero__eyebrow {
  margin: 0 0 clamp(14px, 1.4vw, 22px);
  font-family: var(--font-display);
  font-stretch: 100%;
  font-weight: 600;
  font-size: clamp(12px, 0.82vw, 15px);
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: #c6cbd4;
}

.lhero__title {
  margin: 0;
  font-family: var(--font-display);
  font-stretch: 80%;
  font-weight: 800;
  font-size: clamp(54px, 4.3vw, 82px);
  line-height: 0.93;
  letter-spacing: -0.035em;
  text-transform: uppercase;
  color: #f4f5f7;
}
.lhero__line { display: block; white-space: nowrap; }
.lhero__line--gold {
  color: var(--gold);
  background: linear-gradient(180deg, #f6d27a 0%, #e8b544 55%, #d69a2a 100%);
  -webkit-background-clip: text;
          background-clip: text;
  -webkit-text-fill-color: transparent;
}

.lhero__body {
  margin: clamp(18px, 1.6vw, 26px) 0 clamp(24px, 2.2vw, 34px);
  max-width: 500px;
  font-family: var(--font-body);
  font-weight: 400;
  font-size: clamp(15px, 0.95vw, 18px);
  line-height: 1.55;
  color: var(--ink-2);
}

/* THE ONE DOOR. The site's Steam door at its biggest (.cta--steam
   .cta--xl in css/buttons.css: the look, the real Steam icon, the arrow,
   the hover). Only its place is set here: its width, and the label
   taking the room so the arrow sits at the far edge. */
.lhero__cta { width: clamp(320px, 18vw, 350px); }
.lhero__cta-label { flex: 1; text-align: left; }

.lhero__trust {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 24px;
  margin: 18px 0 0;
  padding: 0;
  list-style: none;
  font-family: var(--font-body);
  font-size: 13.5px;
  color: var(--ink-3);
}
.lhero__trust li { display: inline-flex; align-items: center; gap: 8px; }
.lhero__trust svg { flex: none; width: 16px; height: 16px; color: var(--gold); }

/* The status line: empty until there is something to say. */
.signal-hero__note {
  margin: 14px 0 0;
  font-family: var(--font-body);
  font-size: 12.5px;
  color: var(--ink-3);
  min-height: 1.2em;
}
.signal-hero__note:empty { display: none; }
.signal-hero__note.hero__note--error { color: var(--text); }

/* ============================================================
   THE FEATURE RAIL
   ============================================================ */
.lhero__rail {
  position: relative;
  z-index: 10;
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 14px;
  margin: clamp(4px, 0.6vw, 12px) var(--pad) 0;
  padding: 0;
  list-style: none;
}

/* FIVE MODULES OF ONE SYSTEM. Each card is a raised slab, top lit and
   darker toward its foot, with layers found at three distances:
     far     a dark premium slab, one family of five
     normal  a lit top edge, a light behind the icon, the index, the title
     close   a near invisible 32px engineering grid, the machining mark at
             the foot, the product cue
   ONE ACCENT EACH, in the colour its thing already means on this site:
   value blue (the default), prestige gold, rarity violet (the epic
   colour), market green (the gain colour), profile cyan. Everything else
   about the five is identical, so they stay one family. Headings stay
   off white; the colour lives in the light, the icon and the marks.
   Quieter than the hero above: the interface emerging under it. */
.lfeat {
  --lf-accent: 61, 127, 255;
  --lf-hex: #3d7fff;
  --lf-grid: 0.012;

  position: relative;
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: clamp(220px, 12.6vw, 244px);
  padding: 30px 28px 26px;
  border: 1px solid rgba(120, 150, 205, 0.16);
  border-radius: 8px;
  background:
    radial-gradient(circle at 15% 18%, rgba(var(--lf-accent), 0.09), rgba(var(--lf-accent), 0) 28%),
    repeating-linear-gradient(90deg, transparent 0, transparent 31px, rgba(255, 255, 255, var(--lf-grid)) 31px, rgba(255, 255, 255, var(--lf-grid)) 32px),
    repeating-linear-gradient(0deg, transparent 0, transparent 31px, rgba(255, 255, 255, calc(var(--lf-grid) * 0.75)) 31px, rgba(255, 255, 255, calc(var(--lf-grid) * 0.75)) 32px),
    linear-gradient(145deg, rgba(17, 24, 38, 0.96) 0%, rgba(10, 15, 24, 0.98) 60%, rgba(7, 11, 18, 1) 100%);
  box-shadow:
    0 18px 45px rgba(0, 0, 0, 0.24),
    inset 0 1px 0 rgba(255, 255, 255, 0.035);
  transition:
    translate var(--hover-dur, 200ms) var(--ease),
    border-color var(--hover-dur, 200ms) ease,
    box-shadow var(--hover-dur, 200ms) ease;
}
.lfeat--gold   { --lf-accent: 228, 174, 57;  --lf-hex: #e4ae39; }
.lfeat--violet { --lf-accent: 163, 91, 255;  --lf-hex: #a35bff; }
.lfeat--green  { --lf-accent: 75, 214, 138;  --lf-hex: #4bd68a; }
.lfeat--cyan   { --lf-accent: 53, 198, 224;  --lf-hex: #35c6e0; }

/* The lit top edge, barely there. */
.lfeat::before {
  content: "";
  position: absolute;
  top: -1px;
  left: 12%;
  right: 12%;
  height: 1px;
  pointer-events: none;
  background: linear-gradient(90deg, transparent, rgba(var(--lf-accent), 0.24) 25%, rgba(var(--lf-accent), 0.42) 50%, rgba(var(--lf-accent), 0.16) 75%, transparent);
  filter: blur(0.6px);
  opacity: 0.85;
  transition: opacity var(--hover-dur, 200ms) ease;
}
/* The machining mark at the foot: a short line, never the full width. */
.lfeat::after {
  content: "";
  position: absolute;
  bottom: 0;
  left: 24px;
  width: 36px;
  height: 1px;
  background: var(--lf-hex);
  opacity: 0.32;
}

/* The instrument indicator: the icon in a faint light, a short rule. */
.lfeat__ind {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 36px;
}
.lfeat__ind::before {
  content: "";
  position: absolute;
  left: -10px;
  top: -10px;
  width: 56px;
  height: 56px;
  background: radial-gradient(closest-side, rgba(var(--lf-accent), 0.12), rgba(var(--lf-accent), 0));
  pointer-events: none;
  transition: opacity var(--hover-dur, 200ms) ease;
  opacity: 0.8;
}
.lfeat__ind::after {
  content: "";
  display: block;
  width: 20px;
  height: 1px;
  background: var(--lf-hex);
  opacity: 0.7;
}
.lfeat__icon {
  position: relative;
  display: block;
  width: 25px;
  height: 25px;
  color: var(--lf-hex);
  filter: drop-shadow(0 0 8px rgba(var(--lf-accent), 0.2));
}

.lfeat__idx {
  margin: 16px 0 8px;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-weight: 500;
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(var(--lf-accent), 0.6);
}

.lfeat__title {
  position: relative;
  margin: 0;
  font-family: var(--font-display);
  font-stretch: 100%;
  font-weight: 700;
  font-size: clamp(17px, 1.1vw, 21px);
  line-height: 1.02;
  letter-spacing: -0.005em;
  text-transform: uppercase;
  color: #f3f4f6;
}

.lfeat__text {
  position: relative;
  margin: 14px 0 0;
  font-family: var(--font-body);
  font-size: clamp(13.5px, 0.78vw, 15px);
  line-height: 1.55;
  color: rgba(210, 218, 232, 0.58);
}

/* The product cue, anchored at the foot. */
.lfeat__foot {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: auto 0 0;
  padding-top: 20px;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 9.5px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(180, 195, 220, 0.34);
}
.lfeat__foot::before {
  content: "";
  flex: none;
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: var(--lf-hex);
  opacity: 0.8;
}

/* Hover: the module wakes a little. No scale, no pulse, no neon. */
.lfeat:hover {
  translate: 0 var(--hover-lift, -2px);
  border-color: rgba(120, 150, 205, 0.26);
  box-shadow:
    0 24px 52px rgba(0, 0, 0, 0.32),
    inset 0 1px 0 rgba(255, 255, 255, 0.05);
}
.lfeat:hover::before { opacity: 1; }
.lfeat:hover .lfeat__ind::before { opacity: 1; }

/* ============================================================
   THE HEADER, ON THIS PAGE ONLY
   The hero runs edge to edge, so the header's logo and nav line up with
   the copy and the rail instead of sitting in the narrower content
   column. This file is loaded by index.html alone.
   ============================================================ */
.topbar .container.topbar__inner {
  max-width: none;
  padding-left: clamp(20px, 3.8vw, 76px);
  padding-right: clamp(20px, 3.8vw, 76px);
}

/* ============================================================
   THE FLOOR: the stats line and the example ticker, under the rail
   ============================================================ */
.lhero__floor {
  position: relative;
  z-index: 10;
  /* On the rail's edges rather than in the narrower content column. */
  max-width: none;
  padding-left: var(--pad);
  padding-right: var(--pad);
  margin-top: clamp(40px, 4.4vw, 64px);
  /* The raised greys this strip was measured at (it sat on the old
     hero's ground, which is the same near black). */
  --muted: #e9e7e1;
  --faint: #b6b6b0;
}

/* ---------- The floor ----------

   The hero used to end two thirds of the way down and leave the rest
   black, which made a finished composition read as unfinished and
   spent the best space on the page on nothing. The strip and the
   ticker fill it, and because they are both flat, quiet and wide they
   ground the earning moment above rather than competing with it.

   The section became a COLUMN to hold them. It was a row centring one
   child; it is a column centring two, which is the smallest change
   that puts something under the fold line without moving anything
   above it. */

.trust {
  position: relative;
  z-index: 2;
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 18px;
}

/* A soft floor under the whole strip, so it sits ON something. Same
   blue as everywhere else and weak enough that the dark stays dark. */
.trust::before {
  content: '';
  position: absolute;
  /* OFF CENTRE, following the weight. The lead figure sits left, so a
     halo centred under the block would be lighting the empty third. */
  left: -4%;
  top: -14px;
  width: 86%;
  height: 190%;
  background: radial-gradient(closest-side ellipse at 42% 40%,
    rgba(61, 127, 255, 0.12),
    rgba(61, 127, 255, 0.04) 48%,
    rgba(61, 127, 255, 0) 74%);
  pointer-events: none;
  z-index: -1;
}

/* ---------- The numbers ----------

   NO LAYOUT AT ALL, WHICH IS THE POINT. Four equal tiles was the tell;
   a lead figure with a supporting column was better but still an
   arrangement of parts. This is a sentence with numbers in it, so
   there is nothing left to recognise as a template.

   It is also the loudest thing on the floor by a wide margin, roughly
   nineteen against the ticker's twelve and a half, because two rows of
   equal weight is its own kind of auto-balance. One of them leads. */

.trust__line {
  /* SHORT OF THE EDGE ON PURPOSE. Roughly two thirds of the container,
     so the line stops well before the right margin while the ticker
     below runs the whole width. The imbalance is the composition. */
  max-width: 68ch;
  margin: 0;
  padding-bottom: 20px;
  font-family: var(--font-body);
  font-size: clamp(15px, 1.35vw, 19px);
  line-height: 1.62;
  letter-spacing: -0.005em;
  color: var(--muted);

  /* A rule that runs out rather than stopping. A border would draw a
     hard edge at both ends and put a box back into a block that has
     just had every box taken out of it. */
  background-image: linear-gradient(90deg,
    rgba(255, 255, 255, 0.13),
    rgba(255, 255, 255, 0.03) 62%,
    rgba(255, 255, 255, 0) 96%);
  background-size: 100% 1px;
  background-repeat: no-repeat;
  background-position: 0 100%;
}

/* TABULAR, like the portfolio figure, because these are the same kind
   of thing: counts somebody might check. Mono against the body face is
   also what makes them read as figures inside a sentence rather than
   as words that happen to be digits. */
.trust__line b {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  font-weight: 400;
  font-size: 0.94em;
  letter-spacing: -0.015em;
  color: var(--text);
}

/* ---------- The ticker ---------- */

.ticker {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
}

/* PINNED, NOT SCROLLING. The chip has to be readable on every frame an
   event is readable on, which it would not be if it travelled with
   them. Same treatment as the Example tag on the value readout. */
.ticker__tag {
  flex: none;
  padding: 3px 8px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 4px;
  font-family: var(--font-display);
  font-stretch: var(--display-label);
  font-size: 8.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}

/* Real events need no chip, and the renderer removes the class rather
   than anybody remembering to. */
.ticker:not(.is-preview) .ticker__tag { display: none; }

.ticker__mask {
  position: relative;
  flex: 1;
  min-width: 0;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg,
    transparent, #000 4%, #000 88%, transparent);
  mask-image: linear-gradient(90deg,
    transparent, #000 4%, #000 88%, transparent);
}

/* The list is rendered TWICE and travels exactly half its width, so
   the second copy is standing where the first started at the moment
   the loop repeats. One copy would leave a strip-wide gap. */
.ticker__track {
  display: flex;
  align-items: center;
  width: max-content;
  /* The pace is set from the distance, not picked. The track grew when
     the events did and shrank again when they were rewritten shorter,
     and holding a fixed duration through either would have changed the
     speed of the feed as a side effect of editing its words. Seventy
     seconds over this length is roughly 40px a second, which is what it
     has read at since it was built. */
  animation: tickerRun 70s linear infinite;
}

@keyframes tickerRun {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}

.ticker.is-paused .ticker__track { animation-play-state: paused; }

.ticker__item {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding-right: 34px;
  white-space: nowrap;
  font-family: var(--font-body);
  font-size: 12.5px;
  color: var(--faint);
}

/* A METRONOME IS THE OTHER TELL. Twelve events at one gap apiece reads
   as a carousel; things that actually happened do not arrive evenly
   spaced. Two offsets on a 3 and a 4 give a pattern long enough not to
   be heard as a pattern, and since twelve divides by both, the two
   rendered copies get identical rhythm and the halfway loop still
   lands on itself. */
.ticker__item:nth-child(3n) { padding-right: 48px; }
.ticker__item:nth-child(4n) { padding-right: 25px; }

/* The dot carries the kind, using colours this page has already
   spent: blue for a rank, green for a gain, the rarity colours for a
   card, silver for a read. Nothing new is introduced here. */
.ticker__dot {
  flex: none;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--faint);
}

.ticker__dot.is-rank      { background: #3d7fff; box-shadow: 0 0 7px rgba(61, 127, 255, 0.7); }
.ticker__dot.is-gain      { background: var(--gain); box-shadow: 0 0 7px rgba(31, 214, 125, 0.6); }
.ticker__dot.is-scan      { background: #c4d2e6; }
.ticker__dot.is-common    { background: #b0b8c4; }
.ticker__dot.is-rare      { background: #4a90ff; }
.ticker__dot.is-epic      { background: #a35bff; }
.ticker__dot.is-legendary { background: #f0b429; }

/* Whatever the line leads with is the bright half, and it is not
   always a person: half of these open on a stash, an index or a card
   coming out. */
.ticker__lead {
  font-weight: 400;
  color: var(--muted);
}

.ticker__rest {
  color: var(--faint);
}

@media (max-width: 900px) {
  /* The cap is in characters, so it already gets out of the way here;
     all that is left is to stop the line shouting on a small screen. */
  .trust__line { font-size: 15px; padding-bottom: 16px; }

  .trust { gap: 16px; }
}

@media (prefers-reduced-motion: reduce) {
  /* Still readable, just still. */
  .ticker__track { animation: none; }
}

/* ============================================================
   MOTION, ONLY WHEN ASKED FOR
   ============================================================ */
@media (prefers-reduced-motion: no-preference) {
  .lhero__title { animation: lheroRise 400ms cubic-bezier(0.2, 0.8, 0.2, 1) both; }
  .lhero__body, .lhero__cta, .lhero__trust { animation: lheroRise 400ms cubic-bezier(0.2, 0.8, 0.2, 1) 80ms both; }
  /* THE AMBIENT LAYER, after the entrance. Slow, a few pixels, never in
     step: the figure drifts on an 11s breath, the light behind it shifts
     over 14s, and each card floats on its own period (8.6s, 10s, 9.3s) so
     the three never move together. Everything rides `translate` (and the
     light its opacity), never `transform`, so the cards keep their -2/0/+2
     degree tilt and nothing fights the entrance, which owns opacity and
     scale. No glow pulses and nothing moves fast. */
  .lhero__figure {
    animation:
      lheroArt 700ms cubic-bezier(0.2, 0.8, 0.2, 1) both,
      lheroDrift 11s ease-in-out 700ms infinite;
  }
  .lhero__atmo { animation: lheroLight 14s ease-in-out infinite; }
  .lhero__card {
    animation:
      lheroCard 520ms cubic-bezier(0.2, 0.8, 0.2, 1) both,
      lheroFloat var(--float, 9s) ease-in-out infinite;
    animation-delay: calc(320ms + var(--i, 0) * 60ms), calc(900ms + var(--i, 0) * 1.3s);
  }
  .lhero__card--left { --float: 8.6s; }
  .lhero__card--centre { --float: 10s; }
  .lhero__card--right { --float: 9.3s; }
  /* THE TURN (js/hero-showcase.js). A cross-fade, whole in about 1.2s,
     the emblem first: the new one fades in over 0.9s as it settles from
     98% to full size, the old one fades a beat later as it grows by 2%,
     so the stage is never empty. Then the cards, left to right 90ms
     apart: each incoming card fades up from 8px below over 0.7s, the
     outgoing one lifts 6px and fades a beat later. The name fades out
     first, then the new one in. */
  .lhero__emblem {
    transition:
      opacity 900ms cubic-bezier(0.4, 0, 0.2, 1),
      scale 1100ms cubic-bezier(0.2, 0.7, 0.2, 1);
  }
  .lhero__emblem.is-out { transition-delay: 120ms, 0ms; }
  .lhero__face {
    transition:
      opacity 700ms cubic-bezier(0.4, 0, 0.2, 1),
      translate 700ms cubic-bezier(0.2, 0.7, 0.2, 1);
    transition-delay: calc(150ms + var(--i, 0) * 90ms);
  }
  .lhero__face.is-out {
    transition-duration: 600ms, 700ms;
    transition-delay: calc(300ms + var(--i, 0) * 90ms);
  }
  .lhero__rank { transition: opacity 450ms ease 250ms; }
  .lhero__rank.is-out { transition: opacity 250ms ease; }
  .lfeat { animation: lheroRise 420ms cubic-bezier(0.2, 0.8, 0.2, 1) backwards; animation-delay: calc(380ms + var(--i, 0) * 40ms); }
}

@keyframes lheroRise {
  from { opacity: 0; translate: 0 12px; }
  to   { opacity: 1; translate: 0 0; }
}
@keyframes lheroArt {
  from { opacity: 0; scale: 0.96; }
  to   { opacity: 1; scale: 1; }
}
@keyframes lheroCard {
  from { opacity: 0; translate: 0 16px; }
  to   { opacity: 1; translate: 0 0; }
}
@keyframes lheroDrift {
  0%, 100% { translate: 0 0; }
  50%      { translate: 0 -6px; }
}
@keyframes lheroFloat {
  0%, 100% { translate: 0 0; }
  50%      { translate: 0 -5px; }
}
@keyframes lheroLight {
  0%, 100% { opacity: 1;    translate: 0 0; }
  50%      { opacity: 0.82; translate: -10px 6px; }
}

/* ============================================================
   NARROWER SCREENS
   ============================================================ */
@media (max-width: 1280px) {
  .lhero { --hero-h: clamp(520px, 44vw, 600px); }
  .lhero__copy { width: 46%; }
  /* The art starts where the copy ends rather than under it. */
  .lhero__art { width: 58%; right: -4%; }
  .lhero__title { font-size: clamp(44px, 4.6vw, 60px); }
  /* The art runs 4% of the page past the right edge here (7% of its own
     width), so the plate adds that back, and sits higher and smaller to
     stay clear of the crown. */
  .lhero__ranks { top: 3%; right: calc(7% + 18px); }
  .lhero__rank-tier { font-size: 10px; }
  .lhero__rank-name { font-size: 16px; }
}

/* LARGE TABLET: the modules go three and two before they get cramped. */
@media (max-width: 1199px) {
  .lhero__rail { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* STACKED: the copy first, the art below it (never above), then the
   rail. The art becomes a block in the flow and the mask is not needed:
   nothing sits on top of it any more. */
@media (max-width: 900px) {
  .lhero { display: flex; flex-direction: column; }
  .lhero__inner { order: 1; min-height: 0; padding-top: 44px; padding-bottom: 8px; }
  .lhero__copy { width: 100%; max-width: 640px; }
  .lhero__line { white-space: normal; }
  .lhero__title { font-size: clamp(44px, 9vw, 64px); }
  .lhero__art {
    order: 2;
    position: relative;
    right: auto;
    width: 100%;
    height: clamp(340px, 86vw, 560px);
    margin-top: 12px;
  }
  .lhero__figure { left: 50%; top: 0; height: 100%; }
  .lhero__mask { display: none; }
  /* The figure fills the width here, so the rank plate would sit on its
     crown: it moves under the cards, centred, in room the art makes. */
  .lhero__art { margin-bottom: 58px; }
  .lhero__ranks { top: calc(100% + 16px); right: auto; left: 50%; }
  .lhero__rank { right: auto; left: 0; translate: -50% 0; align-items: center; }
  .lhero__card--left { left: 19%; width: min(230px, 28%); bottom: 10%; }
  .lhero__card--centre { left: 50%; width: min(320px, 38%); bottom: 6%; }
  .lhero__card--right { left: 81%; width: min(230px, 28%); bottom: 10%; }
  .lhero__rail { order: 3; grid-template-columns: repeat(2, minmax(0, 1fr)); margin-top: 20px; }
  .lhero__floor { order: 4; }
}

@media (max-width: 560px) {
  .lhero__cta { width: 100%; }
  .lhero__rail { grid-template-columns: minmax(0, 1fr); }
  .lfeat { min-height: 0; padding: 24px 22px 22px; --lf-grid: 0.007; }
}

@media (prefers-reduced-motion: reduce) {
  .lhero__title, .lhero__body, .lhero__cta, .lhero__trust, .lhero__figure, .lhero__atmo, .lhero__card, .lfeat { animation: none; }
  .lfeat, .lfeat::before, .lfeat__ind::before { transition: none; }
  .lfeat:hover { translate: none; }
  .lhero__emblem, .lhero__face, .lhero__rank { transition: none; }
}

/* ---------- Carried over from achievements.css ----------

   The landing page used to load css/achievements.css for the dashboard
   and unlock cascade it carried. Both live on dashboard.html now, and
   the only rule from that file that touched this page was the nav's
   phone spacing, so it moves here and the header does not change. */
@media (max-width: 620px) {
  .nav { gap: 14px; }
}
