/* =============================================================================
   AUTO BUMP — landing page
   ========================================================================== */

/* ------------------------------------------------------------------- header */

.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  transition: background 0.25s ease, border-color 0.25s ease, backdrop-filter 0.25s ease;
  border-bottom: 1px solid transparent;
}

.site-header.stuck {
  background: rgba(4, 7, 14, 0.82);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border-bottom-color: var(--line);
}

.site-nav { display: flex; align-items: center; gap: 0.3rem; }

.site-nav a.nav-link {
  padding: 0.45rem 0.8rem;
  border-radius: 999px;
  color: var(--ink-dim);
  font-size: 0.9rem;
  font-weight: 500;
  transition: color 0.15s ease, background 0.15s ease;
}
.site-nav a.nav-link:hover { color: var(--ink); background: rgba(255, 255, 255, 0.05); }

.header-actions { display: flex; align-items: center; gap: 0.5rem; }

.nav-toggle {
  display: none;
  width: 42px;
  height: 42px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line);
  background: transparent;
  color: var(--ink);
  cursor: pointer;
}

@media (max-width: 900px) {
  .site-nav { display: none; }
  .nav-toggle { display: grid; place-items: center; }
  .site-nav.open {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    position: absolute;
    top: 68px;
    left: 0;
    right: 0;
    padding: 1rem;
    gap: 0.2rem;
    background: rgba(6, 10, 20, 0.98);
    border-bottom: 1px solid var(--line);
    backdrop-filter: blur(16px);
  }
  .site-nav.open a.nav-link { padding: 0.7rem 0.9rem; }
}

/* --------------------------------------------------------------------- hero */

.hero { position: relative; padding: clamp(3rem, 7vw, 5.5rem) 0 clamp(3rem, 6vw, 5rem); }

#hero-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: -1;
  opacity: 0.5;
  mask-image: radial-gradient(70% 70% at 50% 40%, #000, transparent);
  -webkit-mask-image: radial-gradient(70% 70% at 50% 40%, #000, transparent);
}

.hero-grid {
  display: grid;
  grid-template-columns: 1.15fr 0.85fr;
  gap: clamp(2rem, 5vw, 4rem);
  align-items: center;
  /*
   * Above the flight, which is decoration and must never sit on top of words.
   *
   * `.flight` is a fixed 1020x740 box anchored to the hero's right edge, so the
   * screen position of its endpoints is `heroWidth - 1020 + offset` — it slides
   * one-for-one with the window. At ~2007px and wider the origin marker landed
   * on the supported-applications card; at narrower widths it crossed the trust
   * pill. Both were reported, and both are the same fault: a decorative layer
   * whose position is a function of viewport width will eventually collide with
   * something, so the answer is ordering rather than a magic offset.
   *
   * The trail and the plane now pass behind the panels, which reads as depth.
   */
  position: relative;
  z-index: 2;
}

@media (max-width: 980px) {
  .hero-grid { grid-template-columns: 1fr; }
  .hero-console { order: 2; }
}

.hero-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.4rem 0.9rem 0.4rem 0.5rem;
  border-radius: 999px;
  border: 1px solid var(--line-strong);
  background: var(--grad-soft);
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.18em;
  margin-bottom: 1.5rem;
  color: var(--ink);
}

.hero-badge .pip {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--grad);
  display: grid;
  place-items: center;
  font-size: 0.6rem;
  color: #04060c;
  font-weight: 800;
}

.hero h1 {
  font-size: clamp(2.5rem, 7.2vw, 4.7rem);
  letter-spacing: -0.035em;
  margin-bottom: 1.1rem;
  white-space: pre-line;
}

.hero-sub {
  font-size: clamp(1rem, 1.6vw, 1.16rem);
  color: var(--ink-dim);
  max-width: 54ch;
  margin-bottom: 2rem;
}

.hero-cta { display: flex; gap: 0.8rem; flex-wrap: wrap; margin-bottom: 2.6rem; }

.hero-stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--r);
  overflow: hidden;
}

.hero-stat { padding: 1rem 1.1rem; background: rgba(6, 10, 20, 0.7); }
.hero-stat .v {
  font-size: clamp(1.3rem, 2.6vw, 1.8rem);
  font-weight: 800;
  background: var(--grad);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  line-height: 1.1;
}
.hero-stat .l {
  font-family: var(--mono);
  font-size: 0.62rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* Terminal readout panel */
.hero-console { padding: 0; overflow: hidden; box-shadow: 0 30px 80px rgba(0, 0, 0, 0.5); }

.console-bar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.7rem 1rem;
  border-bottom: 1px solid var(--line);
  background: rgba(255, 255, 255, 0.02);
}

.console-bar .lamp { width: 8px; height: 8px; border-radius: 50%; }
.console-bar .lamp:nth-child(1) { background: var(--red); }
.console-bar .lamp:nth-child(2) { background: var(--amber); }
.console-bar .lamp:nth-child(3) { background: var(--lime); }
.console-bar .title {
  margin-left: auto;
  font-family: var(--mono);
  font-size: 0.62rem;
  letter-spacing: 0.24em;
  color: var(--ink-faint);
}

.console-body {
  padding: 1.1rem 1.2rem;
  font-family: var(--mono);
  font-size: 0.8rem;
  line-height: 1.85;
  min-height: 13rem;
  color: var(--ink-dim);
}

.console-body .line { display: block; white-space: pre-wrap; word-break: break-word; }
.console-body .caret {
  display: inline-block;
  width: 7px;
  height: 0.95em;
  background: var(--cyan);
  vertical-align: -0.15em;
  animation: blink 1.05s step-end infinite;
}
@keyframes blink { 50% { opacity: 0; } }

.console-foot {
  padding: 0.65rem 1.2rem;
  border-top: 1px solid var(--line);
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--mono);
  font-size: 0.62rem;
  letter-spacing: 0.2em;
  color: var(--lime);
  background: rgba(125, 255, 155, 0.04);
}

/* ----------------------------------------------------------------- marquee */

.marquee {
  border-block: 1px solid var(--line);
  background: rgba(6, 10, 20, 0.6);
  overflow: hidden;
  padding: 0.85rem 0;
  display: flex;
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}

.marquee-track {
  display: flex;
  gap: 3rem;
  padding-right: 3rem;
  flex: 0 0 auto;
  animation: slide 32s linear infinite;
}
.marquee:hover .marquee-track { animation-play-state: paused; }

.marquee-item {
  font-family: var(--mono);
  font-size: 0.75rem;
  letter-spacing: 0.24em;
  color: var(--ink-dim);
  display: flex;
  align-items: center;
  gap: 0.8rem;
  white-space: nowrap;
}
.marquee-dot { color: var(--cyan); font-size: 0.55rem; }

/* ---------------------------------------------------------------------------
   The strip's little machines.

   Each mark animates the thing its line claims. Deliberately slow and small —
   the strip already moves, and seven icons competing with it would be noise
   rather than detail. Everything pauses for anyone who asks for reduced motion.
--------------------------------------------------------------------------- */
.mq { color: var(--cyan); flex: none; overflow: visible; }
.mq .mq-shell { opacity: 0.85; }

/* Shield: a scan line sweeping down the face. */
@keyframes mq-scan { 0%, 100% { transform: translateY(-3px); opacity: 0; } 50% { transform: translateY(4px); opacity: 1; } }
.mq-scan { animation: mq-scan 2.6s ease-in-out infinite; }

/* Jitter: the trace drifts, never on the beat. */
@keyframes mq-jitter { 0% { transform: translateX(0); } 22% { transform: translateX(1.4px); } 41% { transform: translateX(-1px); } 63% { transform: translateX(1.8px); } 85% { transform: translateX(-0.6px); } 100% { transform: translateX(0); } }
.mq-trace { animation: mq-jitter 1.9s steps(1, end) infinite; }

/* Failsafe: one node hands over to the other. */
@keyframes mq-hand { 0%, 45% { opacity: 0.25; } 55%, 100% { opacity: 1; } }
@keyframes mq-hand-b { 0%, 45% { opacity: 1; } 55%, 100% { opacity: 0.25; } }
.mq-node { animation: mq-hand-b 2.4s ease-in-out infinite; }
.mq-node-b { animation: mq-hand 2.4s ease-in-out infinite; }
.mq-arc { stroke-dasharray: 2 2; animation: mq-dash 1.2s linear infinite; }
@keyframes mq-dash { to { stroke-dashoffset: -8; } }

/* No macros: the bar through it flashes. */
@keyframes mq-slash { 0%, 70% { opacity: 1; } 80% { opacity: 0.2; } 90% { opacity: 1; } }
.mq-slash { stroke: var(--red); animation: mq-slash 3s ease-in-out infinite; }

/* Swarm: satellites go round the core. */
@keyframes mq-spin { to { transform: rotate(360deg); } }
.mq-orbit { transform-origin: 12px 12px; animation: mq-spin 6s linear infinite; fill: currentColor; stroke: none; }
.mq-core { opacity: 0.9; }

/* Engine: exhaust leaving the nozzle, staggered. */
@keyframes mq-flame { 0% { opacity: 0; transform: translateX(2px); } 35% { opacity: 1; } 100% { opacity: 0; transform: translateX(-3px); } }
.mq-flame { stroke: var(--lime); animation: mq-flame 1.1s linear infinite; }
.mq-f2 { animation-delay: 0.18s; }
.mq-f3 { animation-delay: 0.36s; }

/* Trial: the hand sweeps the dial. */
.mq-hand { transform-origin: 12px 12px; animation: mq-spin 4s linear infinite; }
.mq-hand-b { animation-duration: 12s; opacity: 0.55; }

@media (prefers-reduced-motion: reduce) {
  .mq * { animation: none !important; }
}

@keyframes slide { to { transform: translateX(-100%); } }

/* ---------------------------------------------------------------- features */

.feature-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
  gap: 1rem;
  margin-top: 2.8rem;
}

.feature {
  padding: 1.6rem;
  border-radius: var(--r);
  border: 1px solid var(--line);
  background: var(--panel);
  position: relative;
  overflow: hidden;
  transition: transform 0.22s ease, border-color 0.22s ease, box-shadow 0.22s ease;
}

.feature::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(20rem 12rem at var(--mx, 50%) var(--my, 0%), rgba(34, 224, 255, 0.1), transparent 70%);
  opacity: 0;
  transition: opacity 0.25s ease;
}

.feature:hover { transform: translateY(-4px); border-color: var(--line-strong); box-shadow: 0 20px 50px rgba(0, 0, 0, 0.4); }
.feature:hover::before { opacity: 1; }

.feature-icon {
  width: 42px;
  height: 42px;
  border-radius: 11px;
  display: grid;
  place-items: center;
  background: var(--grad-soft);
  border: 1px solid var(--line-strong);
  margin-bottom: 1.1rem;
  color: var(--cyan);
}
.feature-icon svg { width: 21px; height: 21px; }

.feature h3 { font-size: 1.08rem; margin-bottom: 0.5rem; }
.feature p { color: var(--ink-dim); font-size: 0.92rem; margin: 0; }

/* ------------------------------------------------------------------- steps */

.steps {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: 1rem;
  margin-top: 2.8rem;
  counter-reset: step;
}

.step {
  position: relative;
  padding: 1.5rem 1.4rem 1.4rem;
  border-radius: var(--r);
  border: 1px solid var(--line);
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.035), transparent);
  counter-increment: step;
}

.step::before {
  content: "0" counter(step);
  font-family: var(--mono);
  font-size: 2.1rem;
  font-weight: 700;
  background: var(--grad);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  display: block;
  margin-bottom: 0.5rem;
  opacity: 0.85;
}

.step h3 { font-size: 1rem; margin-bottom: 0.35rem; }
.step p { color: var(--ink-dim); font-size: 0.88rem; margin: 0; }

/* ------------------------------------------------------------------ safety */

.safety-layout {
  display: grid;
  grid-template-columns: 1fr 0.9fr;
  gap: clamp(1.5rem, 4vw, 3rem);
  margin-top: 2.6rem;
  align-items: start;
}
@media (max-width: 900px) { .safety-layout { grid-template-columns: 1fr; } }

.safety-list { display: grid; gap: 0.9rem; }

.safety-item {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 1rem;
  padding: 1.1rem 1.2rem;
  border-radius: var(--r);
  border: 1px solid var(--line);
  background: rgba(6, 10, 20, 0.5);
  transition: border-color 0.2s ease, background 0.2s ease;
}
.safety-item:hover { border-color: var(--line-strong); background: rgba(10, 16, 32, 0.7); }

.safety-check {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: rgba(125, 255, 155, 0.12);
  border: 1px solid rgba(125, 255, 155, 0.4);
  color: var(--lime);
  flex: 0 0 auto;
}
.safety-check svg { width: 14px; height: 14px; }

.safety-item h4 { font-size: 0.98rem; margin-bottom: 0.25rem; }
.safety-item p { color: var(--ink-dim); font-size: 0.88rem; margin: 0; }

.guarantee {
  padding: 1.8rem;
  border-radius: var(--r-lg);
  border: 1px solid rgba(34, 224, 255, 0.3);
  background:
    radial-gradient(24rem 18rem at 100% 0%, rgba(139, 92, 246, 0.18), transparent 65%),
    linear-gradient(160deg, rgba(14, 22, 40, 0.9), rgba(6, 10, 20, 0.9));
  position: sticky;
  top: 6rem;
}

.guarantee-seal {
  width: 54px;
  height: 54px;
  border-radius: 15px;
  background: var(--grad);
  display: grid;
  place-items: center;
  color: #04060c;
  margin-bottom: 1.1rem;
  box-shadow: var(--glow-cyan);
}
.guarantee-seal svg { width: 27px; height: 27px; }

.guarantee h3 { font-size: 1.3rem; }
.guarantee p { color: var(--ink-dim); font-size: 0.95rem; }
.guarantee .note {
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.1em;
  color: var(--ink-faint);
  margin: 0;
  padding-top: 0.9rem;
  border-top: 1px solid var(--line);
}

/* ----------------------------------------------------------------- pricing */

.price-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
  gap: 1.2rem;
  margin-top: 2.8rem;
  max-width: 54rem;
}

.price-grid.cols-3 { max-width: 100%; }
@media (min-width: 1100px) { .price-grid.cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

.price-card {
  padding: 1.8rem;
  border-radius: var(--r-lg);
  border: 1px solid var(--line);
  background: var(--panel);
  position: relative;
  display: flex;
  flex-direction: column;
}

.price-card.featured {
  border-color: rgba(34, 224, 255, 0.4);
  background:
    radial-gradient(22rem 16rem at 120% -10%, rgba(34, 224, 255, 0.16), transparent 65%),
    linear-gradient(170deg, rgba(16, 24, 44, 0.95), rgba(6, 10, 20, 0.95));
  box-shadow: 0 24px 70px rgba(0, 0, 0, 0.45);
}

/* Priority tier: magenta edge so Ultra reads as a different thing rather than
   just a bigger number. */
.price-card.priority {
  border-color: rgba(255, 45, 146, 0.45);
  background:
    radial-gradient(22rem 16rem at 120% -10%, rgba(255, 45, 146, 0.14), transparent 65%),
    linear-gradient(170deg, rgba(26, 14, 34, 0.95), rgba(6, 10, 20, 0.95));
}
.price-card.priority .price-name { color: var(--magenta); }
.price-card.priority .price-features svg { color: var(--magenta); }
.price-card.priority .ribbon { background: var(--magenta); }
.price-card.priority .btn:hover { border-color: var(--magenta); }

.ribbon {
  position: absolute;
  top: 1.2rem;
  right: 1.2rem;
  padding: 0.25rem 0.65rem;
  border-radius: 999px;
  background: var(--grad);
  color: #04060c;
  font-family: var(--mono);
  font-size: 0.58rem;
  letter-spacing: 0.18em;
  font-weight: 800;
}

.price-name {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--cyan);
  margin-bottom: 0.9rem;
}

.price-amount { display: flex; align-items: baseline; gap: 0.4rem; margin-bottom: 0.4rem; }
.price-amount .n { font-size: clamp(2.4rem, 5vw, 3.2rem); font-weight: 800; letter-spacing: -0.04em; }
.price-amount .p { color: var(--ink-faint); font-size: 0.86rem; }

.price-blurb { color: var(--ink-dim); font-size: 0.9rem; margin-bottom: 1.3rem; }

.price-features { list-style: none; margin: 0 0 1.6rem; padding: 0; display: grid; gap: 0.6rem; }
.price-features li {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.65rem;
  font-size: 0.9rem;
  color: var(--ink-dim);
  align-items: start;
}
.price-features svg { width: 15px; height: 15px; color: var(--cyan); margin-top: 0.28em; }

.price-card .btn { margin-top: auto; }

.price-foot { margin-top: 1.6rem; font-size: 0.82rem; color: var(--ink-faint); max-width: 52ch; }
/* How many more of a kind the pool can staff right now. */
.price-slots { margin: 0.6rem 0 0; font-size: 0.8rem; text-align: center; color: var(--lime, #b6f23a); }
.price-slots.none { color: var(--amber, #f5b942); }
/* New sign-ups paused: no accounts free to staff another server. */
.price-paused {
  margin: 0 0 1.4rem;
  padding: 0.85rem 1.1rem;
  max-width: 68ch;
  border: 1px solid color-mix(in srgb, var(--amber, #f5b942) 45%, transparent);
  border-radius: 12px;
  background: color-mix(in srgb, var(--amber, #f5b942) 8%, transparent);
  color: var(--ink);
  font-size: 0.92rem;
  line-height: 1.5;
}

/* ----------------------------------------------------------------- reviews */

.review-rail {
  position: relative;
  overflow: hidden;
  margin-top: 2.6rem;
  padding: 0.4rem 0;
  mask-image: linear-gradient(90deg, transparent, #000 5%, #000 95%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 5%, #000 95%, transparent);
}
.review-track { display: flex; gap: 1rem; width: max-content; animation: roll 46s linear infinite; }
.review-rail:hover .review-track { animation-play-state: paused; }
@keyframes roll { to { transform: translateX(-50%); } }

.review {
  width: 23rem;
  flex: 0 0 auto;
  padding: 1.3rem;
  border-radius: var(--r);
  border: 1px solid var(--line);
  background: var(--panel);
}
.review:hover { border-color: var(--line-strong); }

.review-top { display: flex; align-items: center; gap: 0.75rem; margin-bottom: 0.8rem; }
.review-av {
  width: 42px; height: 42px;
  border-radius: 50%;
  border: 1px solid var(--line-strong);
  object-fit: cover;
  background: rgba(255, 255, 255, 0.05);
  flex: 0 0 auto;
}
.review-name { font-weight: 700; font-size: 0.95rem; line-height: 1.2; }
.review-handle { font-size: 0.75rem; color: var(--ink-faint); }
.review-mark { margin-left: auto; color: #5865f2; }
.review-mark svg { width: 20px; height: 20px; }
.review-text { font-size: 0.9rem; line-height: 1.65; color: var(--ink-dim); margin: 0; }
.review-foot {
  margin-top: 0.9rem;
  padding-top: 0.7rem;
  border-top: 1px solid var(--line);
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  font-family: var(--mono);
  font-size: 0.62rem;
  letter-spacing: 0.12em;
  color: var(--ink-faint);
}

.review-empty {
  margin-top: 2.4rem;
  padding: 2.5rem;
  text-align: center;
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-lg);
  color: var(--ink-faint);
}

/* ------------------------------------------------------------------- about */

.about-layout {
  display: grid;
  grid-template-columns: 1.3fr 0.7fr;
  gap: clamp(1.5rem, 4vw, 3rem);
  margin-top: 2.4rem;
  align-items: start;
}
@media (max-width: 900px) { .about-layout { grid-template-columns: 1fr; } }

.about-copy p { color: var(--ink-dim); font-size: 1rem; }

.about-facts { display: grid; gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
.about-fact { padding: 1.1rem 1.2rem; background: rgba(6, 10, 20, 0.7); }
.about-fact .v { font-size: 1.5rem; font-weight: 800; }
/* The Servers Bumped figure counts up once when it scrolls into view: a small
   nudge on every step while it climbs, then one firmer landing thump. The
   global prefers-reduced-motion rule in theme.css collapses both to nothing. */
.about-fact .v.bumping { animation: fact-bump 200ms ease-out infinite; }
.about-fact .v.bumped { animation: fact-land 520ms cubic-bezier(0.2, 1.6, 0.35, 1) 1; }

@keyframes fact-bump {
  0%, 100% { transform: translateY(0) scale(1); }
  40% { transform: translateY(-3px) scale(1.03); }
}

@keyframes fact-land {
  0% { transform: translateY(0) scale(1); text-shadow: none; }
  35% { transform: translateY(-10px) scale(1.14); text-shadow: 0 0 18px rgba(125, 255, 155, 0.55); }
  100% { transform: translateY(0) scale(1); text-shadow: none; }
}

.about-fact .l {
  font-family: var(--mono);
  font-size: 0.62rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* --------------------------------------------------------------------- faq */

.faq-list { margin-top: 2.4rem; display: grid; gap: 0.7rem; max-width: 52rem; }

.faq-item {
  border-radius: var(--r);
  border: 1px solid var(--line);
  background: rgba(6, 10, 20, 0.5);
  overflow: hidden;
}

.faq-q {
  width: 100%;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  padding: 1.1rem 1.3rem;
  background: transparent;
  border: 0;
  color: var(--ink);
  font: inherit;
  font-weight: 600;
  font-size: 0.98rem;
  text-align: left;
  cursor: pointer;
}
.faq-q:hover { color: var(--cyan); }

.faq-q .mark {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 1px solid var(--line-strong);
  display: grid;
  place-items: center;
  font-family: var(--mono);
  font-size: 0.9rem;
  line-height: 1;
  transition: transform 0.25s ease, background 0.2s ease, color 0.2s ease;
}
.faq-item.open .faq-q .mark { transform: rotate(45deg); background: var(--grad); color: #04060c; border-color: transparent; }

.faq-a { max-height: 0; overflow: hidden; transition: max-height 0.3s ease; }
.faq-a p { padding: 0 1.3rem 1.2rem; margin: 0; color: var(--ink-dim); font-size: 0.92rem; }

/* --------------------------------------------------------------------- cta */

.cta-block {
  margin: clamp(2rem, 5vw, 4rem) 0;
  padding: clamp(2.4rem, 6vw, 4.5rem) clamp(1.4rem, 4vw, 3rem);
  border-radius: var(--r-lg);
  border: 1px solid var(--line-strong);
  text-align: center;
  position: relative;
  overflow: hidden;
  background:
    radial-gradient(40rem 20rem at 50% 0%, rgba(34, 224, 255, 0.2), transparent 65%),
    radial-gradient(30rem 18rem at 80% 100%, rgba(255, 45, 146, 0.16), transparent 65%),
    linear-gradient(160deg, rgba(14, 22, 40, 0.9), rgba(6, 10, 20, 0.95));
}

.cta-block h2 { font-size: clamp(1.8rem, 5vw, 3rem); }
.cta-block p { color: var(--ink-dim); font-size: 1.05rem; margin-bottom: 1.8rem; }

/* ------------------------------------------------------------------ footer */

.site-footer { border-top: 1px solid var(--line); padding: 3rem 0 2rem; margin-top: 2rem; }

.footer-top {
  display: grid;
  grid-template-columns: 1.4fr repeat(auto-fit, minmax(9rem, 1fr));
  gap: 2rem;
  margin-bottom: 2.4rem;
}

.footer-blurb { color: var(--ink-dim); font-size: 0.9rem; max-width: 34ch; margin-top: 1rem; }

.footer-col h4 {
  font-family: var(--mono);
  font-size: 0.64rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: 0.9rem;
}
.footer-col a { display: block; color: var(--ink-dim); font-size: 0.9rem; padding: 0.22rem 0; }
.footer-col a:hover { color: var(--cyan); }

.footer-bottom {
  padding-top: 1.4rem;
  border-top: 1px solid var(--line);
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  font-size: 0.78rem;
  color: var(--ink-faint);
}
.footer-bottom p { margin: 0; max-width: 70ch; }

/* --------------------------------------------------------------- reveal fx */

.reveal {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 0.6s cubic-bezier(0.2, 0.8, 0.3, 1), transform 0.6s cubic-bezier(0.2, 0.8, 0.3, 1);
}
.reveal.in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; }
}

/* ------------------------------------------------------------- brand block
   Shared with the dashboard and admin panel, which also load this file.
   -------------------------------------------------------------------------- */

.header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  height: 68px;
}

/*
 * At phone widths the row (logo + Log in + Try free + menu button) is about
 * 22px wider than the gutter leaves room for, and every item is already at its
 * min-content width, so flex-shrink cannot save it — the menu button was being
 * clipped off the right edge. Reclaiming the gap and the gutter fits all four
 * without dropping a control, which matters because the menu button is the only
 * way to the nav on mobile.
 */
@media (max-width: 420px) {
  .header-inner { gap: 0.4rem; }
  .wrap.header-inner { padding-left: 12px; padding-right: 12px; }
  .logo { gap: 0.45rem; }
}

.logo { display: flex; align-items: center; gap: 0.7rem; color: var(--ink); }

.logo-mark {
  width: 34px;
  height: 34px;
  border-radius: 9px;
  background: var(--grad);
  display: grid;
  place-items: center;
  box-shadow: var(--glow-cyan);
  flex: 0 0 auto;
}
.logo-mark svg { width: 20px; height: 20px; color: #04060c; }

.logo-text { display: flex; flex-direction: column; line-height: 1.05; }
.logo-name { font-weight: 800; letter-spacing: 0.14em; font-size: 0.95rem; }
.logo-tag { font-family: var(--mono); font-size: 0.56rem; letter-spacing: 0.26em; color: var(--ink-faint); }

/* ------------------------------------------------------------------- promo
   The price strip across the very top. Sits above the sticky header and
   scrolls away with the page, so it announces itself once without following
   the reader around.
   -------------------------------------------------------------------------- */

.promo {
  position: relative;
  background: linear-gradient(100deg, var(--btn-green), var(--btn-green-2));
  color: #04170c;
  z-index: 101;
}

.promo-inner {
  max-width: var(--max);
  margin-inline: auto;
  padding: 0.6rem clamp(1rem, 4vw, 2rem);
  display: flex;
  align-items: center;
  gap: 0.85rem;
  flex-wrap: wrap;
  justify-content: center;
  text-align: center;
}

.promo-flash {
  font-family: var(--mono);
  font-size: 0.7rem;
  font-weight: 800;
  letter-spacing: 0.18em;
  padding: 0.2rem 0.5rem;
  border-radius: 3px;
  background: rgba(4, 23, 12, 0.82);
  color: #eaffe9;
  flex: 0 0 auto;
}

.promo-text {
  font-weight: 900;
  font-size: clamp(1rem, 2.4vw, 1.25rem);
  letter-spacing: 0.01em;
  line-height: 1.1;
}

.promo-sub {
  font-size: 0.85rem;
  font-weight: 600;
  opacity: 0.82;
}

.promo-cta {
  margin-left: 0.2rem;
  padding: 0.4rem 0.9rem;
  border: 0;
  border-radius: 999px;
  background: #04170c;
  color: #eaffe9;
  font: inherit;
  font-size: 0.82rem;
  font-weight: 700;
  cursor: pointer;
  flex: 0 0 auto;
  transition: transform 0.16s cubic-bezier(0.22, 1, 0.36, 1), background 0.16s;
}
.promo-cta:hover { background: #0b2e17; transform: translateY(-1px); }

@media (max-width: 640px) {
  .promo-sub { display: none; }
  .promo-inner { gap: 0.6rem; padding: 0.5rem 1rem; }
}

/* The support modal is reachable from the landing page, so it needs the
   Discord button styling that otherwise lives in panel.css. */
.dc-btn { background: #5865f2; border-color: transparent; color: #fff; }
.dc-btn:hover { background: #4752c4; border-color: transparent; color: #fff; }

.code-box {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem;
  padding: 0.9rem 1rem;
  border-radius: var(--r-sm);
  border: 1px dashed var(--cyan);
  background: rgba(34, 224, 255, 0.07);
  font-family: var(--mono);
  font-size: 1.05rem;
  letter-spacing: 0.12em;
  margin-bottom: 1rem;
  word-break: break-all;
}

/* ------------------------------------------------------------- trust strip
   Social proof between the hero buttons and the stat row. Sits above the fold
   so the count-up is seen without scrolling.
   -------------------------------------------------------------------------- */

.trust-strip {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  flex-wrap: wrap;
  margin: -1.4rem 0 2rem;
  padding: 0.55rem 1rem 0.55rem 0.6rem;
  border-radius: 999px;
  border: 1px solid rgba(0, 255, 156, 0.28);
  background: linear-gradient(100deg, rgba(0, 255, 156, 0.1), rgba(0, 255, 156, 0.03));
}

.trust-live {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-family: var(--mono);
  font-size: 0.66rem;
  font-weight: 800;
  letter-spacing: 0.18em;
  color: var(--btn-green);
  padding: 0.2rem 0.55rem;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.35);
}

.trust-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--btn-green);
  animation: trust-pulse 2s ease-in-out infinite;
}

@keyframes trust-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}

.trust-text {
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--ink-dim);
}

.trust-number {
  font-size: 1.35rem;
  font-weight: 900;
  color: var(--btn-green);
  /* Digits are different widths; tabular figures stop the line jittering
     while the number counts up. */
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}

@media (max-width: 560px) {
  .trust-strip { margin: -0.8rem 0 1.6rem; }
  .trust-text { font-size: 0.86rem; }
}

@media (prefers-reduced-motion: reduce) {
  .trust-dot { animation: none; }
}

/* ============================================================ hero ad panel
   Replaces the console when hero.ad.show is on.

   The two logos each trace the same ellipse half a cycle apart, so they pass
   in front of and behind one another rather than orbiting a fixed ring. Doing
   it as a path rather than a rotating parent means the artwork never tumbles —
   a spinning logo reads as a loading spinner — and it needs no counter-
   rotation to stay upright. Scale carries the depth: smaller at the top of the
   path where it reads as further away, larger at the bottom. */
.hero-ad {
  display: flex;
  flex-direction: column;
  padding: 1.6rem 1.4rem 0;
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.5);
  position: relative;
  overflow: hidden;
}

.ad-badge {
  align-self: flex-start;
  font-family: var(--mono);
  font-size: 0.62rem;
  letter-spacing: 0.2em;
  padding: 0.25rem 0.55rem;
  border-radius: 999px;
  color: var(--bg);
  background: var(--grad);
  font-weight: 700;
}

/* ------------------------------------------------------------ the cluster
   Fifteen real service avatars, floating as a loose swarm. Each tile drifts on
   its own hashed period so the group never pulses together, and the whole set
   reveals in a quick stagger keyed off --i. A soft count badge sits over it. */
.ad-stage {
  position: relative;
  /* min-height, not a fixed height: when the panel narrows the cluster wraps
     to more rows and the stage must grow with it. A fixed height let the extra
     rows overflow down onto the headline, and pinned the tally mid-cluster. */
  min-height: 208px;
  margin: 0.6rem 0 0.2rem;
  /* Flex, not grid: a grid item under place-items:center is sized to its
     content, so the cluster's width:100% collapsed to two tiles per row. In a
     flex row, width:100% fills as intended. */
  display: flex;
  align-items: center;
  justify-content: center;
}
.ad-stage::after {
  content: '';
  position: absolute;
  inset: 0;
  margin: auto;
  width: 230px;
  height: 230px;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(34, 224, 255, 0.13), rgba(139, 92, 246, 0.08) 55%, transparent 72%);
  pointer-events: none;
}

.ad-cluster {
  position: relative;
  /* Fill the panel (never wider than it — the old fixed 260px overflowed a
     narrower card) and grow tall as rows wrap. */
  width: 100%;
  max-width: 264px;
  margin: 0 auto;
  display: flex;
  flex-wrap: wrap;
  align-content: center;
  justify-content: center;
  gap: 0.5rem 0.55rem;
  /* Bottom padding reserves the corner the tally floats in, so at narrow
     widths (a full last row) the badge sits below the avatars, not on them. */
  padding: 0 0.6rem 1.6rem;
}

.ad-tile {
  flex: 0 0 auto;
  width: 46px;
  height: 46px;
  border-radius: 13px;
  display: grid;
  place-items: center;
  overflow: hidden;
  background: var(--panel-solid);
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(120, 190, 255, 0.16);
  will-change: transform;
  /* Two animations: a one-shot staggered reveal (delayed by index) and the
     perpetual float (its own per-tile period from --dur). */
  animation: ad-tile-in 0.5s ease-out both,
             ad-float var(--dur, 6s) ease-in-out infinite;
  animation-delay: calc(var(--i) * 55ms), calc(var(--flo, 0s) + 0.5s);
}
.ad-tile-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.ad-tile.is-fallback {
  font-weight: 800;
  font-size: 1.1rem;
  color: #fff;
  background: var(--grad);
}

.ad-tally {
  position: absolute;
  right: 6px;
  bottom: 2px;
  display: flex;
  align-items: baseline;
  gap: 0.3rem;
  padding: 0.35rem 0.7rem;
  border-radius: 999px;
  background: rgba(8, 12, 22, 0.82);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(120, 190, 255, 0.22);
  backdrop-filter: blur(6px);
}
.ad-tally b {
  font-size: 1.25rem;
  font-weight: 800;
  background: var(--grad);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.ad-tally span {
  font-size: 0.68rem;
  color: var(--ink-faint);
  letter-spacing: 0.04em;
}

@keyframes ad-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-6px); }
}
@keyframes ad-tile-in {
  from { opacity: 0; transform: translateY(10px) scale(0.9); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

.ad-headline {
  margin: 0.2rem 0 0;
  font-size: 1.28rem;
  line-height: 1.4;
  font-weight: 800;
  text-align: center;
}

.ad-mark {
  background: var(--grad);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* A sentence, not a status tag — so the wide tracking of the old console
   footer is dialled back. At 0.18em the 44 characters needed every pixel of
   the panel and wrapped to three lines as soon as it narrowed. */
.ad-foot {
  margin: 1.2rem -1.4rem 0;
  padding: 0.7rem 1.4rem;
  border-top: 1px solid var(--line);
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--mono);
  font-size: 0.7rem;
  line-height: 1.5;
  letter-spacing: 0.04em;
  color: var(--lime);
}
.ad-foot .dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex: none; }

@media (max-width: 900px) { .hero-ad { order: 2; } }

@media (prefers-reduced-motion: reduce) {
  .ad-orb { animation: none; }
  .ad-ring { animation: none; }
  .ad-orb-a { translate: -60px 0; }
  .ad-orb-b { translate: 60px 0; }
}

/* ------------------------------------------------------------- the 6-7 toss
   After the drift, two palms come in and throw the logos in the alternating
   up-down rhythm of the meme: one hand punches up while the other drops, then
   they swap. The logo leaves the hand slightly late and lands slightly early,
   which is what sells it as a throw rather than two things moving together. */
.ad-hand {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 64px;
  height: 64px;
  font-size: 44px;
  line-height: 64px;
  text-align: center;
  opacity: 0;
  pointer-events: none;
  translate: var(--x) 62px;
  transition: opacity 0.4s ease;
}
.ad-hand-a { --x: -60px; }
/* Mirrored so the pair read as a left and a right hand. */
.ad-hand-b { --x: 60px; scale: -1 1; }

/* Park the logos at their side positions before the bouncing starts. */
.ad-settling .ad-orb {
  animation: none;
  translate: var(--x) 0;
  scale: 1;
  transition: translate 0.5s cubic-bezier(0.3, 0.9, 0.3, 1), scale 0.5s ease;
}
.ad-settling .ad-ring { opacity: 0; transition: opacity 0.5s ease; }
.ad-settling .ad-hand { opacity: 1; }

.ad-tossing .ad-orb {
  transition: none;
  animation: ad-toss 0.86s cubic-bezier(0.33, 0, 0.4, 1) infinite;
}
.ad-tossing .ad-orb-b { animation-delay: -0.43s; }

.ad-tossing .ad-hand { animation: ad-hand-push 0.86s cubic-bezier(0.33, 0, 0.4, 1) infinite; }
.ad-tossing .ad-hand-b { animation-delay: -0.43s; }

@keyframes ad-toss {
  0%   { translate: var(--x) 18px;  scale: 1.04 0.94; }  /* squashed, in the hand */
  18%  { translate: var(--x) -6px;  scale: 0.96 1.06; }  /* launch, stretched */
  50%  { translate: var(--x) -52px; scale: 1 1; }        /* apex */
  82%  { translate: var(--x) -6px;  scale: 0.97 1.05; }
  100% { translate: var(--x) 18px;  scale: 1.04 0.94; }
}

@keyframes ad-hand-push {
  0%   { translate: var(--x) 62px; rotate: -6deg; }
  18%  { translate: var(--x) 34px; rotate: 4deg; }       /* the push */
  50%  { translate: var(--x) 58px; rotate: -2deg; }      /* drops back, waiting */
  82%  { translate: var(--x) 40px; rotate: 2deg; }       /* rises to catch */
  100% { translate: var(--x) 62px; rotate: -6deg; }
}

@media (prefers-reduced-motion: reduce) {
  .ad-hand { display: none; }
}

/* ------------------------------------------------------- compliance stickers
   Five badges that "slap" onto the wall one by one, left of the hero.

   Layout has two modes on purpose. The rail only floats in the gutter when the
   gutter genuinely exists (viewport wider than --max plus the rail plus air);
   below that it becomes a centred strip under the hero instead of overlapping
   the copy. Nothing is ever hidden, so the claims stay readable on a phone.
   -------------------------------------------------------------------------- */

.compliance-rail {
  width: min(100%, var(--max));
  margin: clamp(1.75rem, 4vw, 2.75rem) auto 0;
  padding-inline: clamp(1rem, 4vw, 2rem);
  display: flex;
  flex-wrap: wrap;
  gap: 0.55rem;
  justify-content: center;
  align-items: flex-start;
}

.sticker {
  position: relative;
  display: flex;
  gap: 0.6rem;
  align-items: flex-start;
  width: 232px;
  padding: 0.62rem 0.7rem;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: var(--panel);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  cursor: default;
  opacity: 0;
  transform: scale(1.45) rotate(0deg);
  filter: blur(7px);
}

.sticker.in {
  animation: sticker-slap 0.52s cubic-bezier(0.2, 1.3, 0.35, 1) forwards;
}

/* The impact ring: a hard edge that expands and dies the instant it lands. */
.sticker.in::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  border: 1px solid var(--line-strong);
  opacity: 0;
  animation: sticker-impact 0.5s ease-out 0.18s forwards;
  pointer-events: none;
}

@keyframes sticker-slap {
  0%   { opacity: 0; transform: translateY(-18px) scale(1.45) rotate(0deg); filter: blur(7px); }
  55%  { opacity: 1; transform: translateY(0) scale(0.945) rotate(var(--tilt)); filter: blur(0); }
  78%  { transform: translateY(0) scale(1.028) rotate(var(--tilt)); }
  100% { opacity: 1; transform: translateY(0) scale(1) rotate(var(--tilt)); filter: blur(0); }
}

@keyframes sticker-impact {
  0%   { opacity: 0.85; transform: scale(1); }
  100% { opacity: 0; transform: scale(1.14); }
}


.sticker-body { min-width: 0; }

.sticker-title {
  margin: 0;
  font-size: 0.735rem;
  line-height: 1.28;
  font-weight: 600;
  letter-spacing: 0.005em;
  color: var(--ink);
}

/* Full wording stays in the DOM for screen readers and is revealed on hover or
   keyboard focus — the rail is too narrow to show five paragraphs at once. */

.sticker:hover,
.sticker:focus-visible {
  border-color: var(--line-strong);
  outline: none;
}



@media (prefers-reduced-motion: reduce) {
  .sticker { opacity: 1; transform: rotate(var(--tilt)); filter: none; }
  .sticker.in { animation: none; }
  .sticker.in::after { animation: none; opacity: 0; }
}

/* ------------------------------------------------------------- origin badge */
.origin-badge {
  display: flex;
  justify-content: center;
  margin: 1.6rem 0 0.2rem;
}
.origin-badge img {
  width: min(230px, 60vw);
  height: auto;
  opacity: 0.85;
}

/* ============================================================== certificates
   These are certification marks, so they are built like one: a round seal at
   the top, the standard's name centred beneath it, a rule, then the detail.

   The shape is drawn on ::before rather than with clip-path on the element
   itself. clip-path clips every descendant, which is what cut the body text
   off mid-sentence when it expanded — the detail can now overflow the notched
   outline freely. */
.sticker {
  display: block;
  width: 100%;
  padding: 0.95rem 0.85rem 1rem;
  text-align: center;
  border: 0;
  border-radius: 0;
  background: none;
  backdrop-filter: none;
  box-shadow: none;
  clip-path: none;
  overflow: visible;
}

/* The badge outline: corners clipped at all four, so it reads as a stamped
   plate rather than a rounded card. */
.sticker::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(180deg, rgba(16, 25, 44, 0.96), rgba(8, 13, 24, 0.96));
  border: 1px solid var(--line);
  clip-path: polygon(
    12px 0, calc(100% - 12px) 0, 100% 12px,
    100% calc(100% - 12px), calc(100% - 12px) 100%,
    12px 100%, 0 calc(100% - 12px), 0 12px
  );
  box-shadow: 0 14px 32px rgba(0, 0, 0, 0.45);
}

/* Hairline ring inside the plate, the way a seal is double-struck. */
.sticker::after {
  content: '';
  position: absolute;
  inset: 5px;
  z-index: -1;
  border: 1px solid rgba(120, 190, 255, 0.13);
  clip-path: polygon(
    9px 0, calc(100% - 9px) 0, 100% 9px,
    100% calc(100% - 9px), calc(100% - 9px) 100%,
    9px 100%, 0 calc(100% - 9px), 0 9px
  );
}


.sticker-title {
  margin: 0;
  font-size: 0.78rem;
  line-height: 1.32;
  letter-spacing: 0.01em;
}

.sticker-rule {
  display: block;
  width: 34px;
  height: 1px;
  margin: 0.5rem auto;
  background: linear-gradient(90deg, transparent, var(--line-strong), transparent);
}

.sticker-note {
  font-size: 0.7rem;
  line-height: 1.5;
  color: var(--ink-dim);
}


.sticker:hover::before,
.sticker:focus-visible::before,
.sticker:focus-within::before { border-color: var(--line-strong); }

/* ------------------------------------------------------ certificate cluster
   Two, two, then one centred beneath. Wide enough that the detail wraps to a
   readable measure rather than two words a line. Only floats into the left
   gutter where that gutter is genuinely wider than the cluster. */
.compliance-rail {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.6rem;
  width: min(430px, calc(100% - 2rem));
  margin-inline: auto;
  padding-inline: 0;
  align-items: start;
}

.sticker:nth-child(5) {
  grid-column: 1 / -1;
  width: calc(50% - 0.3rem);
  justify-self: center;
}

/* Wide screens: the cluster leaves the flow and becomes a compact band across
   the top-left, tucked under the header and clear of the content column.

   The width is measured off the gutter itself rather than guessed, and the
   columns are auto-fit, so as the gutter narrows the band steps down from five
   across to four to two instead of ever reaching into the copy. Everything
   inside is scaled down to match — these read as small marks up there, not as
   the full-size certificates the centred cluster shows. */
@media (min-width: 1900px) {
  .compliance-rail {
    position: absolute;
    /* Pulled up out of the hero so the band sits directly under the promo bar,
       level with the header rather than below it. The hero is the offset
       parent and starts where the header ends, so this is negative by the
       header's 69px less an 8px gap under the green. Nothing on the way up
       clips: header, main and hero are all overflow: visible, and the header's
       own background is transparent — only its logo and nav paint above this,
       and those sit in the content column, well clear of the band. */
    top: -61px;
    left: 1.5rem;
    transform: none;
    margin: 0;
    z-index: 2;
    width: min(624px, calc((100% - var(--max)) / 2 - 3rem));
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 0.55rem;
  }

  /* The odd-one-out rule belongs to the 2+2+1 cluster only. */
  .compliance-rail .sticker:nth-child(5) {
    grid-column: auto;
    width: 100%;
    justify-self: stretch;
  }

  .compliance-rail .sticker { padding: 0.78rem 0.6rem 0.82rem; }
  .compliance-rail .sticker::before {
    clip-path: polygon(
      8px 0, calc(100% - 8px) 0, 100% 8px,
      100% calc(100% - 8px), calc(100% - 8px) 100%,
      8px 100%, 0 calc(100% - 8px), 0 8px
    );
  }
  .compliance-rail .sticker::after {
    inset: 4px;
    clip-path: polygon(
      6px 0, calc(100% - 6px) 0, 100% 6px,
      100% calc(100% - 6px), calc(100% - 6px) 100%,
      6px 100%, 0 calc(100% - 6px), 0 6px
    );
  }

  .compliance-rail .rosette { width: 53px; height: 64px; margin-bottom: 0.45rem; }
  .compliance-rail .rosette-seal { width: 46px; height: 46px; }
  .compliance-rail .rosette-face { width: 33px; height: 33px; }
  .compliance-rail .rosette-face svg { width: 17px; height: 17px; }
  .compliance-rail .rosette-tails { top: 25px; width: 33px; height: 38px; }
  .compliance-rail .rosette-tails::before,
  .compliance-rail .rosette-tails::after { width: 14px; }

  .compliance-rail .sticker-title { font-size: 0.7rem; line-height: 1.3; }
  .compliance-rail .sticker-rule { width: 28px; margin: 0.42rem auto; }
  .compliance-rail .sticker-note { font-size: 0.665rem; line-height: 1.5; }
}

/* ------------------------------------------------------------- origin badge */
.origin-badge { display: flex; justify-content: center; margin: 1.6rem 0 0.2rem; }
.origin-badge img { width: min(230px, 60vw); height: auto; opacity: 0.85; }

/* ================================================================== rosette
   An award rosette rather than a flat disc: a scalloped gold seal sitting over
   two ribbon tails, the shape a certification mark actually takes.

   The scallop is a 22-point polygon alternating between two radii. It is on the
   seal only — the plate behind the whole badge keeps its own outline, and
   neither clips the text, which is what cut the detail off before. */
.rosette {
  position: relative;
  display: block;
  width: 64px;
  height: 78px;
  margin: 0 auto 0.55rem;
}

/* Two tails, nicked at the bottom like cut ribbon, angled apart. */
.rosette-tails {
  position: absolute;
  left: 50%;
  top: 30px;
  width: 40px;
  height: 46px;
  transform: translateX(-50%);
}
.rosette-tails::before,
.rosette-tails::after {
  content: '';
  position: absolute;
  top: 0;
  width: 17px;
  height: 100%;
  background: linear-gradient(180deg, #3b6fd4, #1e3f8f);
  clip-path: polygon(0 0, 100% 0, 100% 100%, 50% 74%, 0 100%);
}
.rosette-tails::before { left: 0; transform: rotate(-9deg); transform-origin: top center; }
.rosette-tails::after  { right: 0; transform: rotate(9deg);  transform-origin: top center; }

/* The seal. Gold, scalloped, with a struck rim. */
.rosette-seal {
  position: absolute;
  left: 50%;
  top: 0;
  width: 56px;
  height: 56px;
  transform: translateX(-50%);
  background: linear-gradient(145deg, #f7e39b 8%, #d9ae4e 38%, #a9791f 62%, #f0d489 92%);
  clip-path: polygon(50.0% 0.0%, 56.1% 7.4%, 64.1% 2.0%, 67.9% 10.9%, 77.0% 7.9%, 78.2% 17.5%, 87.8% 17.3%, 86.2% 26.8%, 95.5% 29.2%, 91.3% 37.9%, 99.5% 42.9%, 93.0% 50.0%, 99.5% 57.1%, 91.3% 62.1%, 95.5% 70.8%, 86.2% 73.2%, 87.8% 82.7%, 78.2% 82.5%, 77.0% 92.1%, 67.9% 89.1%, 64.1% 98.0%, 56.1% 92.6%, 50.0% 100.0%, 43.9% 92.6%, 35.9% 98.0%, 32.1% 89.1%, 23.0% 92.1%, 21.8% 82.5%, 12.2% 82.7%, 13.8% 73.2%, 4.5% 70.8%, 8.7% 62.1%, 0.5% 57.1%, 7.0% 50.0%, 0.5% 42.9%, 8.7% 37.9%, 4.5% 29.2%, 13.8% 26.8%, 12.2% 17.3%, 21.8% 17.5%, 23.0% 7.9%, 32.1% 10.9%, 35.9% 2.0%, 43.9% 7.4%);
  display: grid;
  place-items: center;
}

/* Inner disc, so the scallops read as a rim around a face rather than as noise. */
.rosette-face {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  color: #6b4c12;
  background: radial-gradient(circle at 38% 30%, #fdf3cf, #e6c368 55%, #c79a37);
  box-shadow: inset 0 0 0 1px rgba(120, 84, 20, 0.55);
}

@media (prefers-reduced-motion: no-preference) {
  .sticker:hover .rosette-seal,
  .sticker:focus-within .rosette-seal {
    transform: translateX(-50%) rotate(-6deg);
    transition: transform 0.3s cubic-bezier(0.3, 1.3, 0.4, 1);
  }
}

/* -------------------------------------------------------- click to open
   Title only until asked. Opening is a click, not a hover: hover cannot be
   done on a phone, which is what left the text half-shown and clipped before.
   The plate outline lives on ::before and is inset:0, so it grows with the
   card and never cuts the text once open. */
.sticker { cursor: pointer; }

.sticker-note {
  margin: 0;
  max-height: 0;
  opacity: 0;
  overflow: hidden;
  font-size: 0.7rem;
  line-height: 1.5;
  color: var(--ink-dim);
  transition: max-height 0.34s ease, opacity 0.26s ease, margin-top 0.34s ease;
}

.sticker.open .sticker-note {
  max-height: 24rem;
  opacity: 1;
  margin-top: 0.15rem;
}

/* The affordance: a chevron that turns when the card is open, so a title-only
   card still reads as something you can act on. */
.sticker-rule { position: relative; }
.sticker-rule::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 6px;
  width: 6px;
  height: 6px;
  border-right: 1px solid var(--ink-faint);
  border-bottom: 1px solid var(--ink-faint);
  transform: translateX(-50%) rotate(45deg);
  transition: transform 0.3s ease, border-color 0.3s ease;
}
.sticker.open .sticker-rule::after {
  transform: translateX(-50%) rotate(-135deg);
  border-color: var(--cyan);
}

.sticker:hover .sticker-rule::after,
.sticker:focus-visible .sticker-rule::after { border-color: var(--cyan); }

.sticker:focus-visible::before { border-color: var(--cyan); }

/* ============================================================== delivery run
   The plane lifts /bump off the data centre, flies it down the hero, and lands
   it on your server, which jumps and says so.

   Every part is keyed to percentages of one shared duration (--flight-dur), so
   the arrival, the jump and the success line cannot drift apart when the timing
   is tuned. One curve, --flight-path, carries the trail, the plane and the
   banner. Rather than a negative delay for the tow — which made the banner wrap
   early and reappear at the origin — the banner has its own keyframes that
   simply reach the end slightly later. */
.flight {
  --flight-dur: 9s;
  position: absolute;
  top: 0;
  right: 0;
  width: 1020px;
  height: 740px;
  pointer-events: none;
  z-index: 1;
}

.flight-trail {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* --------------------------------------------------------------- endpoints */
.flight-node {
  position: absolute;
  display: grid;
  justify-items: center;
  gap: 0.3rem;
  width: 120px;
  text-align: center;
}
/* Anchored to the two ends of the path: the command starts at the data centre
   down on the left and is delivered to your server up on the right. */
.flight-origin { left: 16px; top: 662px; }
.flight-dest { left: 890px; top: 46px; }

.flight-node-mark {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 12px;
  color: var(--ink-dim);
  background: rgba(10, 16, 32, 0.9);
  border: 1px solid var(--line);
}

.flight-node-label {
  font-family: var(--mono);
  font-size: 0.58rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-faint);
  white-space: nowrap;
}

/* The Discord mark takes the delivery, so it is the one that reacts. */
.flight-discord {
  color: #7d8cff;
  border-color: rgba(125, 140, 255, 0.4);
  animation: flight-land var(--flight-dur) ease-in-out infinite;
}

.flight-success {
  position: absolute;
  bottom: 100%;
  margin-bottom: 8px;
  padding: 3px 9px;
  border-radius: 999px;
  font-size: 0.66rem;
  font-weight: 600;
  white-space: nowrap;
  color: #04170d;
  background: var(--lime);
  opacity: 0;
  transform: translateY(4px);
  animation: flight-cheer var(--flight-dur) ease-out infinite;
}

/* ------------------------------------------------------------ the aircraft */
.flight-plane,
.flight-banner {
  position: absolute;
  top: 0;
  left: 0;
  offset-path: var(--flight-path);
  offset-rotate: auto;
  will-change: offset-distance;
}

.flight-plane {
  width: 24px;
  height: 24px;
  margin: -12px 0 0 -12px;
  color: var(--cyan);
  filter: drop-shadow(0 0 7px rgba(34, 224, 255, 0.5));
  animation: flight-fly var(--flight-dur) cubic-bezier(0.45, 0, 0.55, 1) infinite;
}

/* Fixed to the aircraft rather than towed. It runs the same keyframes as the
   plane, so the two are at the identical point on the curve at every instant
   and the chip sits at a constant offset from it — carried, not dragged. It
   still does not rotate: inheriting offset-rotate:auto turned the wordmark
   upside down once the climb passed vertical. */
.flight-banner {
  offset-rotate: 0deg;
  animation: flight-fly var(--flight-dur) cubic-bezier(0.45, 0, 0.55, 1) infinite;
}

.flight-tag {
  display: block;
  margin: 11px 0 0 -23px;
  padding: 2px 8px;
  border-radius: 999px;
  font-family: var(--mono);
  font-size: 0.6rem;
  letter-spacing: 0.06em;
  color: var(--bg);
  background: linear-gradient(90deg, var(--cyan), var(--violet));
  white-space: nowrap;
}

/* Wait at the data centre, fly, then hold at the server while it celebrates. */
@keyframes flight-fly {
  0%, 8%   { offset-distance: 0%;   opacity: 0; }
  12%      { opacity: 1; }
  64%      { offset-distance: 100%; opacity: 1; }
  72%      { offset-distance: 100%; opacity: 0; }
  100%     { offset-distance: 100%; opacity: 0; }
}

/* Squash, then two decreasing hops — the delivery landing on it. */
@keyframes flight-land {
  0%, 64%   { transform: translateY(0) scale(1, 1); }
  68%       { transform: translateY(3px) scale(1.12, 0.86); }
  74%       { transform: translateY(-14px) scale(0.94, 1.08); }
  80%       { transform: translateY(0) scale(1.06, 0.94); }
  85%       { transform: translateY(-6px) scale(0.98, 1.02); }
  90%, 100% { transform: translateY(0) scale(1, 1); }
}

@keyframes flight-cheer {
  0%, 70%   { opacity: 0; transform: translateY(4px); }
  76%       { opacity: 1; transform: translateY(0); }
  92%       { opacity: 1; transform: translateY(0); }
  97%, 100% { opacity: 0; transform: translateY(-3px); }
}

/* Not enough room beside the copy below this. */
@media (max-width: 1560px) { .flight { display: none; } }

@media (prefers-reduced-motion: reduce) {
  .flight-plane, .flight-banner { animation: none; offset-distance: 55%; opacity: 1; }
  .flight-discord, .flight-success { animation: none; }
  .flight-success { opacity: 1; transform: none; }
}

/* ------------------------------------------------------------------ exhaust
   Vapour off the tail. Each puff rides the same curve on the same keyframes as
   the plane but starts a fraction later, so it sits that much further back
   along the path — the spacing comes from the delay rather than from guessing
   pixel offsets, which means it stays correct wherever the curve bends. */
.flight-puff {
  position: absolute;
  top: 0;
  left: 0;
  width: var(--s);
  height: var(--s);
  margin: calc(var(--s) / -2) 0 0 calc(var(--s) / -2);
  border-radius: 50%;
  background: radial-gradient(circle, rgba(34, 224, 255, 0.55), rgba(139, 92, 246, 0.12) 70%, transparent);
  offset-path: var(--flight-path);
  offset-rotate: 0deg;
  animation: flight-puff var(--flight-dur) cubic-bezier(0.45, 0, 0.55, 1) infinite;
  animation-delay: var(--d);
  will-change: offset-distance, opacity;
}

@keyframes flight-puff {
  0%, 8%   { offset-distance: 0%;   opacity: 0; }
  16%      { opacity: var(--o); }
  62%      { offset-distance: 100%; opacity: var(--o); }
  68%      { offset-distance: 100%; opacity: 0; }
  100%     { offset-distance: 100%; opacity: 0; }
}

@media (prefers-reduced-motion: reduce) { .flight-puff { display: none; } }

/* ---------------------------------------------------------------------------
   The Trustpilot ask.

   Sits under the review marquee, and is deliberately quieter than it: the
   reviews above are the proof, this is the invitation. Plain links rather than
   Trustpilot's own widget — that is a paid feature on the current plan, and
   embedding it would put the site's first third-party script on every page.
--------------------------------------------------------------------------- */
.tp-block {
  margin: 1.6rem auto 0;
  max-width: 44rem;
  padding: 1.1rem 1.3rem;
  border: 1px solid var(--line);
  border-radius: var(--r, 10px);
  background: color-mix(in srgb, var(--panel-solid) 55%, transparent);
  text-align: center;
}
.tp-head { display: flex; align-items: center; justify-content: center; gap: 0.45rem; color: var(--lime); }
.tp-title { font-size: 0.78rem; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink); }
.tp-body { margin: 0.55rem 0 0.9rem; font-size: 0.85rem; line-height: 1.6; color: var(--ink-dim); }
.tp-actions { display: flex; gap: 0.5rem; justify-content: center; flex-wrap: wrap; }
@media (max-width: 480px) { .tp-actions .btn { width: 100%; } }

/* ---------------------------------------------------------------------------
   Support chat.

   The launcher sits above the Discord button rather than replacing it: one is
   "I have a question now", the other is "I want to talk to the team". The AI
   tag is deliberately plain and always present — a badge somebody has to hunt
   for is the same as no badge.
--------------------------------------------------------------------------- */
.chat-fab {
  position: fixed; right: 1.1rem; bottom: 5.2rem; z-index: 60;
  width: 52px; height: 52px; border-radius: 50%;
  display: grid; place-items: center;
  border: 1px solid var(--line-strong);
  background: var(--panel-solid); color: var(--cyan);
  cursor: pointer; box-shadow: 0 6px 24px rgba(0, 0, 0, 0.45);
}
.chat-fab:hover { color: var(--ink); border-color: var(--cyan); }

/* Docked bottom-right, above the launcher — a chat sits beside the page rather
   than in front of it. Becomes a near-full sheet on a phone, where a 24rem
   panel in the corner would be unusable. */
.chat-panel {
  position: fixed; right: 1.1rem; bottom: 10.4rem; z-index: 61;
  width: min(24rem, calc(100vw - 2.2rem));
  max-height: min(34rem, calc(100vh - 12rem));
  display: flex; flex-direction: column; gap: 0.55rem;
  padding: 0.9rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--r, 12px);
  background: var(--panel-solid);
  box-shadow: 0 18px 50px rgba(0, 0, 0, 0.6);
}
.cw-head { display: flex; align-items: flex-start; gap: 0.5rem; }
.cw-head-text { min-width: 0; flex: 1; }
.cw-head h2 { margin: 0; font-size: 1rem; }
.cw-x {
  border: 0; background: none; color: var(--ink-faint);
  font-size: 1.2rem; line-height: 1; cursor: pointer; padding: 0 0.15rem;
}
.cw-x:hover { color: var(--ink); }
.cw-foot { display: flex; flex-direction: column; gap: 0.4rem; }

@media (max-width: 560px) {
  .chat-panel {
    right: 0.6rem; left: 0.6rem; bottom: 0.6rem;
    width: auto; max-height: 80vh;
  }
}
.cw-head-text .sub { margin: 0.2rem 0 0; font-size: 0.8rem; color: var(--ink-dim); }

.cw-log {
  flex: 1;
  display: flex; flex-direction: column; gap: 0.5rem;
  min-height: 9rem; overflow-y: auto;
  padding: 0.6rem; border: 1px solid var(--line); border-radius: var(--r, 10px);
  background: rgba(8, 13, 24, 0.6);
}
.cw-msg { max-width: 88%; }
.cw-msg.cw-visitor { align-self: flex-end; }
.cw-who { display: flex; align-items: center; gap: 0.35rem; margin-bottom: 0.15rem; font-size: 0.62rem; color: var(--ink-faint); }
.cw-tag {
  font-family: var(--mono); font-size: 0.5rem; letter-spacing: 0.12em;
  padding: 0.05rem 0.25rem; border-radius: 3px;
  border: 1px solid var(--cyan); color: var(--cyan);
}
.cw-body {
  padding: 0.45rem 0.6rem; border-radius: var(--r-sm, 8px);
  font-size: 0.82rem; line-height: 1.5;
  border: 1px solid var(--line); background: var(--panel-solid); color: var(--ink);
  white-space: pre-wrap; word-break: break-word;
}
.cw-visitor .cw-body { background: color-mix(in srgb, var(--cyan) 14%, var(--panel-solid)); }
.cw-typing .cw-body { color: var(--ink-faint); font-style: italic; }
.cw-note {
  align-self: stretch; padding: 0.45rem 0.6rem; font-size: 0.74rem; line-height: 1.5;
  border-left: 2px solid var(--amber); color: var(--ink-dim);
}
.cw-disclaimer { margin: 0; font-size: 0.66rem; line-height: 1.45; color: var(--ink-faint); }
.cw-form { display: flex; gap: 0.4rem; align-items: stretch; }
/* min-width:0 so the input may shrink inside the flex row instead of forcing
   the row wider than the panel and clipping its own placeholder. */
.cw-form .cw-input { flex: 1 1 auto; min-width: 0; }
.cw-form .btn { flex: 0 0 auto; }
.cw-human { align-self: flex-start; }

@media (max-width: 480px) { .chat-fab { bottom: 4.8rem; } .cw-msg { max-width: 95%; } }

/* ---------------------------------------------------------------------------
   The system cards: one clan, six members.

   Cyber-samurai rather than six literal pictograms. Everything shares a
   vocabulary so the grid reads as one world:

     the crest   a kamon ring draws itself around every mark on hover
     the accent  exactly one crimson element per sigil against the cyan, which
                 is the whole neon-on-lacquer contrast this idiom runs on
     the draw    a blade-flash crosses the tile — the unsheathe, shared by all

   Each sigil still means its card: the shuriken never spins true, the guard
   parries, the mask goes dark, the clones arrive one behind another, the gate
   simply stands, the coin turns over.

   Idle is deliberately still. The page already has a moving strip, and six
   cards animating at rest would be a fairground.
--------------------------------------------------------------------------- */

.sg { color: var(--cyan); overflow: visible; }
.sg-body { opacity: 0.9; }
/* The single crimson accent, shared by every member of the set. */
.sg-hot { stroke: #ff4d5e; opacity: 0.95; }

/* --- the crest: a kamon ring that resolves on hover ----------------------- */
.sg-ring {
  opacity: 0;
  stroke: var(--cyan);
  /* 1.2 rather than 0.9: the sigil renders at 22px, where a sub-pixel line
     disappears entirely. Measured on the live page before settling on it. */
  stroke-width: 1.2;
  stroke-dasharray: 69;
  stroke-dashoffset: 69;
  transition: opacity 0.25s ease;
}
@keyframes sg-crest { to { stroke-dashoffset: 0; } }
.feature:hover .sg-ring { opacity: 0.6; animation: sg-crest 0.7s ease-out forwards; }

/* --- the draw: a blade of light across the tile --------------------------- */
.feature-icon { position: relative; overflow: hidden; }
.feature-icon svg { position: relative; z-index: 1; }
.feature-icon::after {
  content: "";
  position: absolute; inset: -20%;
  background: linear-gradient(115deg, transparent 42%, rgba(255, 255, 255, 0.55) 50%, transparent 58%);
  transform: translateX(-140%) skewX(-12deg);
}
@keyframes sg-draw { to { transform: translateX(140%) skewX(-12deg); } }
.feature:hover .feature-icon::after { animation: sg-draw 0.55s cubic-bezier(0.4, 0, 0.2, 1); }

/* --- the card edge: the blade's own edge light ---------------------------- */
.feature::after {
  content: "";
  position: absolute;
  inset: -1px;
  border-radius: inherit;
  padding: 1px;
  background: conic-gradient(from var(--edge, 0deg), transparent 0deg, var(--cyan) 30deg, #ff4d5e 48deg, transparent 96deg);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  opacity: 0;
  transition: opacity 0.3s ease;
  pointer-events: none;
}
@property --edge { syntax: '<angle>'; initial-value: 0deg; inherits: false; }
@keyframes sg-edge { to { --edge: 360deg; } }
.feature:hover::after { opacity: 0.9; animation: sg-edge 3.2s linear infinite; }

/* --- each member's own motion -------------------------------------------- */

/* Shuriken: spins, but never true — the jitter is the whole claim, so the
   steps are uneven on purpose. A smooth rotation would contradict the copy. */
@keyframes sg-throw {
  0%   { transform: rotate(0deg); }
  18%  { transform: rotate(84deg); }
  34%  { transform: rotate(150deg); }
  57%  { transform: rotate(262deg); }
  76%  { transform: rotate(310deg); }
  100% { transform: rotate(360deg); }
}
.feature:hover .fx-cpu .sg-body,
.feature:hover .fx-cpu .sg-hot { transform-origin: 12px 12px; animation: sg-throw 2.2s steps(1, end) infinite; }

/* Parry: the guard takes the strike and holds. */
@keyframes sg-parry { 0%, 55%, 100% { transform: scale(1); } 62% { transform: scale(0.82); } 70% { transform: scale(1.14); } }
@keyframes sg-spark { 0%, 58%, 100% { opacity: 0.95; } 66% { opacity: 0.25; filter: drop-shadow(0 0 6px #ff4d5e); } }
.feature:hover .fx-shield .sg-hot { transform-origin: 12px 7.5px; animation: sg-parry 2.6s ease-in-out infinite, sg-spark 2.6s ease-in-out infinite; }

/* Mempo: the mask goes dark. Only the eye-slits stay lit. */
@keyframes sg-shadow { 0%, 100% { opacity: 0.9; } 50% { opacity: 0.12; } }
.feature:hover .fx-link .sg-body { animation: sg-shadow 2.6s ease-in-out infinite; }

/* Kage bunshin: they arrive one behind the other, never together. */
@keyframes sg-clone { 0%, 100% { opacity: 0.25; } 30% { opacity: 1; } }
.feature:hover .fx-pulse .sg-c1 { animation: sg-clone 1.8s ease-in-out infinite; }
.feature:hover .fx-pulse .sg-c2 { animation: sg-clone 1.8s ease-in-out infinite 0.22s; }
.feature:hover .fx-pulse .sg-c3 { animation: sg-clone 1.8s ease-in-out infinite 0.44s; }

/* Torii: the gate does not move. The lantern under it simply does not go out. */
@keyframes sg-lantern {
  0%, 100% { opacity: 0.95; filter: drop-shadow(0 0 2px #ff4d5e); }
  50% { opacity: 1; filter: drop-shadow(0 0 7px #ff4d5e); }
}
.feature:hover .fx-lock .sg-lamp { animation: sg-lantern 2.8s ease-in-out infinite; }

/* Mon: the pierced coin turns over and settles. */
@keyframes sg-turn { 0%, 58%, 100% { transform: rotateY(0deg); } 24% { transform: rotateY(180deg); } 44% { transform: rotateY(360deg); } }
.feature:hover .fx-coin .sg { transform-style: preserve-3d; }
.feature:hover .fx-coin svg { animation: sg-turn 3.4s ease-in-out infinite; transform-style: preserve-3d; }

@media (prefers-reduced-motion: reduce) {
  .feature:hover::after,
  .feature:hover .feature-icon::after,
  .feature:hover .sg,
  .feature:hover .sg *,
  .feature:hover .feature-icon svg { animation: none !important; }
}


/* ===========================================================================
   The bump-channel panel, and the certifications that made room for it.

   Both live in the hero's left margin, which only exists at 1900px and up —
   the same threshold the certification rail already used. Below that the
   margin is gone, so the panel is not shown and the certifications go back to
   being an ordinary grid in the page rather than an ornament beside it.
   =========================================================================== */

/*
 * Below the wide breakpoint there is no left margin to hang it in, so it drops
 * into the hero's flow instead of disappearing. It is the most persuasive thing
 * on the page — the product actually doing its job — and hiding it from every
 * phone to save a layout branch was the wrong trade.
 */
/* The compact effect has no gutter to play in, so it takes a band of its own
   under the stats — without it the sequence drew straight over the
   "Now supports…" card that sits directly beneath them. The class is set by
   the same code that picks the layout, so the two cannot disagree. */
.hero-stats.has-fx-band { margin-bottom: 15.5rem; }

.chan-panel {
  display: flex;
  flex-direction: column;
  /* Inset to the same gutter as the rest of the page. At width:100% it ran
     edge to edge while every other block sat 16px in, so it read as hanging
     off both sides of the screen. */
  width: min(calc(100% - 2rem), 34rem);
  margin: 2.5rem auto 0;
  border: 1px solid var(--line);
  border-radius: var(--r-lg, 14px);
  background: linear-gradient(180deg, rgba(12, 18, 32, 0.92), rgba(7, 11, 20, 0.92));
  overflow: hidden;
}

@media (min-width: 1900px) {
  .chan-panel {
    position: absolute;
    /*
     * Centred in the band between the page edge and the figure on the button,
     * which starts roughly 150px into the content column — so the band is the
     * left margin plus that much. Vertically centred on the hero rather than
     * pinned to its top, which puts it level with the headline instead of
     * floating up by the promo bar.
     */
    --chan-w: 330px;
    /*
     * The band runs from the page edge to where the figure actually begins,
     * which is the content edge plus a little — measured at 424px on a 2000px
     * viewport, i.e. content-left + 24. Sizing the band from the content edge
     * plus a guessed 150px put the panel 23px into her.
     */
    --chan-band: calc((100vw - var(--max)) / 2 + 24px);
    top: 50%;
    transform: translateY(-50%);
    left: calc((var(--chan-band) - var(--chan-w)) / 2);
    width: var(--chan-w);
    display: flex;
    flex-direction: column;
    border: 1px solid var(--line);
    border-radius: var(--r-lg, 14px);
    background: linear-gradient(180deg, rgba(12, 18, 32, 0.92), rgba(7, 11, 20, 0.92));
    backdrop-filter: blur(8px);
    overflow: hidden;
    z-index: 2;
  }

  /* The certifications drop to the band of margin beside the system section. */
  #system { position: relative; }
  .compliance-rail {
    top: 3.5rem;
    bottom: auto;
    left: 1.5rem;
    width: min(430px, calc((100vw - var(--max)) / 2 - 3rem));
  }

}

/*
 * Exactly one card exists in the layout at a time.
 *
 * The first version layered all five absolutely at the same spot and faded
 * between them, which is what read as "stacked": five cards of different
 * heights sharing one corner, the container sized for the tallest, and the
 * outgoing card's outline still catching the light as the next arrived.
 * `display: none` is unambiguous — there is nothing behind the visible card
 * to see, and the rail is exactly as tall as whatever is showing.
 */
/* One card at a time everywhere; taken out of flow only on the wide layout,
   where it is a margin ornament. In the narrow layout it stays in the page, or
   it escapes its section and widens the document. */
.compliance-rail.is-solo { display: block; }
@media (min-width: 1900px) {
  .compliance-rail.is-solo { position: absolute; }
}
.compliance-rail.is-solo .sticker { display: none; }
.compliance-rail.is-solo .sticker.is-shown {
  display: block;
  /*
   * The base .sticker rests at opacity 0, scale 1.45 and blur(7px) — the
   * "slap on" animation clears all three via the .in class. The rotation
   * here uses .is-shown instead, so without restating them the card sat
   * permanently blurred: legible enough to look intentional, far too soft
   * to actually read, which is exactly how it was reported.
   */
  opacity: 1;
  filter: none;
  animation: cert-arrive 0.62s cubic-bezier(0.2, 0.9, 0.24, 1) both;
}
.compliance-rail.is-solo .sticker.is-leaving {
  display: block;
  pointer-events: none;
  animation: cert-leave 0.42s cubic-bezier(0.4, 0, 1, 1) both;
}

/* Now that one card owns the corner there is room to actually read it. The
   detail was 0.665rem — about ten pixels — which is why tapping one told
   you nothing. */
.compliance-rail .sticker { padding: 1.15rem 1rem 1.2rem; }
.compliance-rail .sticker-title { font-size: 0.95rem; line-height: 1.32; }
.compliance-rail .sticker-note { font-size: 0.84rem; line-height: 1.62; color: var(--ink-dim); }
.compliance-rail .sticker-rule { width: 34px; margin: 0.6rem auto; }
.compliance-rail .rosette { width: 62px; height: 74px; margin-bottom: 0.6rem; }
.compliance-rail .rosette-seal { width: 54px; height: 54px; }
.compliance-rail .rosette-face { width: 39px; height: 39px; }



@keyframes cert-arrive {
  from { opacity: 0; filter: blur(5px); transform: translateY(20px) scale(0.9) rotate(var(--tilt)); }
  to   { opacity: 1; filter: blur(0);    transform: translateY(0) scale(1) rotate(var(--tilt)); }
}
@keyframes cert-leave {
  from { opacity: 1; transform: translateY(0) scale(1) rotate(var(--tilt)); }
  to   { opacity: 0; transform: translateY(-16px) scale(0.95) rotate(var(--tilt)); }
}
@media (prefers-reduced-motion: reduce) {
  .compliance-rail.is-solo .sticker.is-shown,
  .compliance-rail.is-solo .sticker.is-leaving { animation: none; }
}

.chan-head {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.8rem 1rem;
  border-bottom: 1px solid var(--line);
  font-size: 0.9rem;
  font-weight: 600;
}
.chan-hash { color: var(--ink-faint); font-weight: 400; font-size: 1.05rem; }
.chan-chan { color: var(--ink-dim); }
.chan-clock {
  margin-inline-start: auto;
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}

.chan-body {
  position: relative;
  min-height: 216px;
  padding: 0.5rem 0;
  overflow: hidden;
  /* The oldest message is usually half out of frame. Hard-clipping it looked
     like a rendering fault; fading it reads as scrollback. */
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 40px);
  mask-image: linear-gradient(180deg, transparent, #000 40px);
}
.chan-stack {
  position: absolute;
  inset-inline: 0;
  bottom: 0.4rem;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}

.chan-group {
  padding: 0.26rem 1rem;
  opacity: 0;
  transform: translateY(12px);
  transition: opacity 0.5s ease, transform 0.5s cubic-bezier(0.2, 0, 0, 1);
}
.chan-group.in { opacity: 1; transform: none; }

.chan-int {
  display: flex;
  align-items: center;
  gap: 0.36rem;
  margin-bottom: 0.26rem;
  padding-left: 1.85rem;
  font-size: 0.74rem;
  color: var(--ink-faint);
}
.chan-user { font-weight: 600; }
.chan-cmd {
  color: #9db4ff;
  background: rgba(139, 92, 246, 0.18);
  border-radius: 4px;
  padding: 0.04rem 0.3rem;
  font-weight: 600;
}

.chan-msg { display: flex; gap: 0.65rem; }
.chan-av {
  flex: 0 0 auto;
  width: 28px; height: 28px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  overflow: hidden;
  font-size: 0.7rem;
  font-weight: 800;
  color: #fff;
  background: var(--panel-solid);
}
.chan-av-img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Only the monogram fallback wears the gradient chip. */
.chan-av.is-fallback { background: linear-gradient(140deg, #5865f2, #8b5cf6); }
.chan-main { min-width: 0; }
.chan-name-row { display: flex; align-items: baseline; gap: 0.4rem; line-height: 1.2; }
.chan-name { font-size: 0.85rem; font-weight: 600; color: var(--ink); }
.chan-badge {
  background: var(--violet);
  color: #fff;
  font-size: 0.55rem;
  font-weight: 800;
  letter-spacing: 0.04em;
  padding: 0.07rem 0.26rem;
  border-radius: 3px;
  transform: translateY(-1px);
}
.chan-time { font-size: 0.67rem; color: var(--ink-faint); font-variant-numeric: tabular-nums; }

.chan-embed {
  margin-top: 0.32rem;
  border-left: 3px solid #3ba55c;
  border-radius: 0 4px 4px 0;
  background: rgba(255, 255, 255, 0.03);
  padding: 0.48rem 0.66rem;
  font-size: 0.8rem;
  line-height: 1.5;
  color: var(--ink-dim);
}
.chan-embed.is-wait { border-left-color: var(--amber); }
.chan-embed b { color: var(--ink); }
.chan-embed .chan-sub { display: block; margin-top: 0.1rem; font-size: 0.72rem; color: var(--ink-faint); }

.chan-foot { padding: 0.8rem 1rem; border-top: 1px solid var(--line); }
.chan-track { position: relative; height: 3px; border-radius: 2px; background: rgba(120, 190, 255, 0.12); }
.chan-fill {
  position: absolute; inset-block: 0; left: 0; width: 0;
  border-radius: 2px;
  background: var(--grad);
  transition: width 0.7s cubic-bezier(0.2, 0, 0, 1);
}
.chan-tick {
  position: absolute; top: -2px;
  width: 2px; height: 7px;
  border-radius: 1px;
  background: var(--btn-green);
  box-shadow: 0 0 6px var(--btn-green);
  transform: translateX(-1px) scaleY(0);
  transition: transform 0.3s cubic-bezier(0.3, 1.6, 0.5, 1);
}
.chan-tick.in { transform: translateX(-1px) scaleY(1); }
.chan-foot-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-top: 0.55rem;
  font-size: 0.73rem;
  color: var(--ink-faint);
}
.chan-foot-row b { color: var(--ink); font-size: 0.9rem; font-variant-numeric: tabular-nums; }

@media (prefers-reduced-motion: reduce) {
  .chan-group { opacity: 1; transform: none; transition: none; }
  .chan-tick { transform: translateX(-1px) scaleY(1); transition: none; }
  .chan-fill { transition: none; }
}

/* ===========================================================================
   The figure on the trial button.

   Sized and placed from the sprite itself: beachgirl.webp is 276x520, and her
   hip line — where her planted hands meet the surface — measured at 63.1% of
   its height. Landing her on the button is therefore arithmetic rather than
   nudging, which is what kept going wrong before.
   =========================================================================== */

:root {
  --bg-girl-w: 112px;
  --bg-girl-h: 211px;   /* 112 * 520/276, so she is never stretched */      /* 132 * 520/276, so she is never stretched */
  --bg-girl-seat: 0.631;
  --bg-girl-overlap: 54px; /* how far she sits ONTO the button */
}

.hero-cta { position: relative; }

.bgirl {
  position: absolute;
  left: 0;
  /*
   * Her seat line sits on the button's top edge, solved rather than nudged:
   *   bottom = buttonHeight - (1 - seat) * girlHeight
   * With a 55px button, a 249px figure and her hips 63.1% down, that is
   * 55 - 0.369 * 249 = -37px. Change any of the three and this follows.
   */
  bottom: calc(55px - (1 - var(--bg-girl-seat)) * var(--bg-girl-h));
  /* her hip centre, so `left` places the part that touches the button */
  margin-left: calc(var(--bg-girl-w) * -0.5 + 44px);
  width: var(--bg-girl-w);
  height: var(--bg-girl-h);
  background: url('/assets/hero/beachgirl.webp') no-repeat bottom left / contain;
  pointer-events: none;
  z-index: 3;
  filter: drop-shadow(0 8px 18px rgba(0, 0, 0, 0.5));
  animation: bgirl-breathe 4.4s ease-in-out infinite;
}
@keyframes bgirl-breathe { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-3px); } }

@media (min-width: 1101px) {
  /* Room for her: she overlaps the button's left end, and the label starts
     after her so nothing is covered. */
  /*
   * Clearance measured, not guessed: she stands 157px above the button's top
   * edge (249px tall, hips 63.1% down), and at 5.6rem she still overlapped the
   * paragraph by 67px. 5.6 + 67/16 = 9.8rem.
   */
  /*
   * She sits ON the button, not beside it. Her hip centre is at 0.50 of the
   * sprite's width (measured off the alpha channel), and with the old spacing
   * that landed 12px to the LEFT of the button's edge — so she read as perched
   * on the corner rather than sitting on it.
   *
   * The button keeps its natural width. It had grown 55px to hold her clear of
   * the label, which made it noticeably wider than the ghost button beside it;
   * a small nudge is enough now that she is smaller.
   */
  .hero-cta { padding-left: 26px; margin-top: 9rem; }
  .hero-cta .btn-primary { padding-left: 2.6rem; }
  /* Her feet hang 37px below the button. The trust strip sits on a negative
     margin by design, which put the "LIVE" pill directly under them — measured
     at 5px of overlap across her full width. */
  .trust-strip { margin-top: -0.2rem; }
}

/* Below this the hero runs edge to edge and there is nowhere for her to be
   that is not on top of the copy, so she goes rather than being shrunk into a
   smudge. */
/*
 * She ships to phones as well, just smaller. The button goes full-width there,
 * so there is room on its left end for her to sit even without a gutter.
 */
@media (max-width: 1100px) {
  :root { --bg-girl-w: 84px; --bg-girl-h: 158px; --bg-girl-overlap: 40px; }
  /* She is 84px wide and starts at the row's left edge, so the label has to
     begin past her: 20px of row inset + 2rem was still 32px short. */
  .hero-cta { padding-left: 20px; margin-top: 6.2rem; }
  .hero-cta .btn-primary { padding-left: 5rem; }
  .bgirl { bottom: calc(52px - (1 - var(--bg-girl-seat)) * var(--bg-girl-h)); margin-left: 0; }
}
/* Narrower than this the button stacks and the copy runs edge to edge; there
   is genuinely nowhere for her to be that is not on top of it. */
@media (max-width: 380px) { .bgirl { display: none; } }
@media (prefers-reduced-motion: reduce) { .bgirl { animation: none; } }

/* ===========================================================================
   The shadowban figure, under fire.

   The effects are rendered light on pure black, composited with `plus-lighter`
   — true additive blending, so black adds nothing and disappears. That is how
   film VFX elements are comped, and it is why none of these need an alpha
   channel: the glow is the only part that survives the blend. `screen` is the
   fallback for anything that has not shipped plus-lighter.
   =========================================================================== */

.hero-stats { position: relative; }

.lz-stage {
  position: absolute;
  display: block;
  z-index: 1;
    /* Position and size are written by JS from the stat card's own rect: the
       barrier has to wrap that card, so the stage must span the gutter AND the
       card. The row clips, so this layer cannot live inside it.

       z-index 1 puts it behind the bump-channel panel (z-index 2) but still
       above the page background, so the beam passes BEHIND that panel instead
       of painting across it — which reads as depth rather than as an overlay
       drawn on top of the interface. It stays in front of the stats row, whose
     positioned ancestor is z-index auto. */
  pointer-events: none;
  /* A hard guarantee: whatever the layout does, no part of the effect can
     escape its own box and end up off the side of a phone. */
  overflow: hidden;
}

.lz-emitter {
  position: absolute;
  left: 0; top: 0;
  width: 54px; height: 54px;
  --charge: 0;
  --present: 0;
  perspective: 300px;
  /* Position, bank and scale are written per frame by the flight path; only
     the fade is left to CSS. */
  opacity: var(--present);
  will-change: opacity, transform;
}

/* Rim light — a backlight behind the object, which is what stops a dark mark
   dissolving into a near-black page. */
.lz-glow {
  position: absolute;
  inset: -34%;
  border-radius: 50%;
  background: radial-gradient(circle,
    rgba(150, 165, 255, calc(0.30 + var(--charge) * 0.45)) 0%,
    rgba(88, 101, 242, 0.14) 46%,
    transparent 72%);
  filter: blur(6px);
  pointer-events: none;
}

/*
 * The mark as a solid object. The extrusion is a short stack of hard
 * box-shadows stepping down and darkening — the earlier version used eight
 * layers at 86px, which turned a logo into a chunky slab. Three layers at 54px
 * reads as depth without reading as a brick.
 */
.lz-cube {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  border-radius: 15px;
  color: #fff;
  background: linear-gradient(150deg, #8b95ff 0%, #5865f2 50%, #4650d6 100%);
  transform: rotateY(-13deg) rotateX(7deg);
  box-shadow:
    1px 2px 0 #4450d2,
    2px 4px 0 #3a44b6,
    3px 6px 0 #313a9b,
    5px 9px 16px rgba(0, 0, 0, 0.55),
    inset 0 1.5px 0 rgba(255, 255, 255, 0.5),
    inset -1.5px -2px 0 rgba(0, 0, 0, 0.2);
}
.lz-cube::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 15px;
  background: linear-gradient(142deg, rgba(255,255,255,0.3) 0%, rgba(255,255,255,0.05) 24%, transparent 50%);
  pointer-events: none;
}
.lz-cube svg { position: relative; z-index: 1; filter: drop-shadow(0 1px 2px rgba(0,0,0,0.35)); }

/* Angry: two brows, angled inwards over the eyes. A face reads as hostile from
   the brows long before anything else. */
.lz-brow {
  position: absolute;
  z-index: 2;
  top: 15px;
  width: 11px; height: 3px;
  border-radius: 2px;
  background: #fff;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
}
.lz-brow-l { left: 12px; transform: rotate(20deg); }
.lz-brow-r { right: 12px; transform: rotate(-20deg); }

/* The beams leave from here, so these must line up with EYE_OFF in site.js. */
.lz-eye {
  position: absolute;
  top: 27px;
  width: 11px; height: 11px;
  margin-top: -5.5px;
  border-radius: 50%;
  pointer-events: none;
  background: radial-gradient(circle, rgba(255,255,255,1) 0%, rgba(255,110,70,0.95) 34%, rgba(255,40,20,0) 70%);
  opacity: calc(0.12 + var(--charge) * 0.88);
  transform: scale(calc(0.55 + var(--charge) * 0.75));
}
.lz-eye-l { left: 23px; margin-left: -5.5px; }
.lz-eye-r { left: 31px; margin-left: -5.5px; }

/*
 * The gun.
 *
 * Built as parts rather than as a rounded box: a heavy breech at the back, a
 * tapered barrel with heat vents, three charge coils that light in sequence,
 * and a pair of focusing prongs that the shot forms between. Angular
 * throughout — clip-path rather than border-radius — because a rounded
 * rectangle with a label on it reads as a remote control, not a weapon.
 *
 * Everything is laid out along the +x axis and the whole assembly is then
 * rotated to aim, so the geometry below is readable as a side elevation.
 */
.lz-gun {
  position: absolute;
  /* left/top and --aim are written by JS from the layout it is serving. */
  --present: 0;
  --charge: 0;
  --aim: 115deg;
  width: 0; height: 0;
  opacity: var(--present);
  transform: rotate(var(--aim)) scale(calc(0.94 + var(--present) * 0.06));
  transform-origin: 0 0;
  pointer-events: none;
  will-change: opacity, transform;
}

/* Scaled down where the whole stage is only as wide as the stats row. */
.lz-gun.is-compact { --gun-scale: 0.72; transform: rotate(var(--aim)) scale(calc(var(--gun-scale) * (0.94 + var(--present) * 0.06))); }

.lz-gun-breech {
  position: absolute;
  left: -138px; top: -30px;
  width: 118px; height: 60px;
  background: linear-gradient(168deg, #33405c 0%, #18203354 22%, #131a29 60%, #0b1018 100%);
  border: 1px solid rgba(120, 190, 255, 0.3);
  /* A chamfered block: flat back, angled shoulders into the barrel. */
  clip-path: polygon(0 16%, 10% 0, 100% 0, 100% 100%, 10% 100%, 0 84%);
  box-shadow: inset 0 2px 0 rgba(190, 230, 255, 0.2), 0 12px 28px rgba(0, 0, 0, 0.65);
}
/* Counter-rotated, so the plate stays level whatever the barrel is aimed at. */
.lz-gun-plate {
  position: absolute;
  /* Centred over the breech, but outside it, so the clip cannot reach it. */
  left: -138px; top: -30px;
  width: 118px; height: 60px;
  display: grid;
  align-content: center;
  justify-items: center;
  gap: 2px;
  transform: rotate(calc(-1 * var(--aim)));
}
.lz-gun-plate b {
  font-family: var(--mono);
  font-size: 0.5rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: #dff0ff;
  white-space: nowrap;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8);
}
.lz-gun-plate i {
  font-family: var(--mono);
  font-style: normal;
  font-size: 0.45rem;
  letter-spacing: 0.26em;
  color: rgba(120, 195, 255, 0.8);
}

.lz-gun-barrel {
  position: absolute;
  left: -22px; top: -16px;
  width: 84px; height: 32px;
  background: linear-gradient(180deg, #3c4a66 0%, #1d2739 46%, #0d131e 100%);
  border-top: 1px solid rgba(150, 210, 255, 0.26);
  /* Tapers towards the muzzle. */
  clip-path: polygon(0 0, 100% 22%, 100% 78%, 0 100%);
}
.lz-gun-vent {
  position: absolute;
  top: 34%;
  width: 12px; height: 3px;
  background: rgba(10, 16, 26, 0.9);
  box-shadow: 0 5px 0 rgba(10, 16, 26, 0.9);
}
.lz-gun-vent:nth-of-type(1) { left: 22px; }
.lz-gun-vent:nth-of-type(2) { left: 42px; }

/* Charge coils: they light from the breech forwards, so the shot visibly
   travels up the barrel before it leaves. */
.lz-gun-coil {
  position: absolute;
  width: 5px;
  border-radius: 2px;
  background: linear-gradient(180deg, #6fd8ff, #1d7fd0);
  box-shadow: 0 0 calc(2px + var(--charge) * 10px) rgba(120, 220, 255, 0.9);
}
.lz-gun-coil.c1 { left: -12px; top: -17px; height: 34px; opacity: calc(0.2 + var(--charge) * 0.8); }
.lz-gun-coil.c2 { left: 10px;  top: -14px; height: 28px; opacity: calc(0.15 + max(0, var(--charge) - 0.25) * 1.1); }
.lz-gun-coil.c3 { left: 32px;  top: -12px; height: 24px; opacity: calc(0.1 + max(0, var(--charge) - 0.55) * 1.6); }

/* Focusing prongs — the shot forms in the gap between them. */
.lz-gun-prong {
  position: absolute;
  left: 58px;
  width: 30px; height: 13px;
  background: linear-gradient(180deg, #46567a, #141c2b);
  border: 1px solid rgba(140, 205, 255, 0.28);
}
.lz-gun-prong.up { top: -19px; clip-path: polygon(0 0, 100% 42%, 100% 100%, 0 100%); }
.lz-gun-prong.dn { top: 6px;   clip-path: polygon(0 0, 100% 0, 100% 58%, 0 100%); }

.lz-gun-core {
  position: absolute;
  left: 74px; top: -17px;
  width: 34px; height: 34px;
  border-radius: 50%;
  background: radial-gradient(circle,
    rgba(255,255,255, calc(0.3 + var(--charge) * 0.7)) 0%,
    rgba(110, 215, 255, calc(0.25 + var(--charge) * 0.65)) 36%,
    transparent 72%);
  filter: blur(calc(1px + var(--charge) * 3px));
  transform: scale(calc(0.35 + var(--charge) * 1.05));
}

/*
 * The verdict, printed beside the shot.
 *
 * Not on the beam's midpoint: the beam passes BEHIND the bump-channel panel,
 * and a label that did the same would be half-hidden.
 */
.lz-verdict {
  position: absolute;
  /* At the kill, not beside the beam. Below the bump-channel panel (which ends
     at stage y 479) and well left of the content column, so it collides with
     nothing — and it reads better where the thing actually died. */
  left: 246px;
  top: 556px;
  padding: 0.3rem 0.7rem;
  border-radius: 3px;
  border: 1px solid rgba(120, 215, 255, 0.45);
  background: rgba(6, 20, 34, 0.86);
  color: #d8f3ff;
  font-family: var(--mono);
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  text-shadow: 0 0 10px rgba(120, 215, 255, 0.7);
}
.lz-verdict.is-live { animation: lz-verdict 2.4s cubic-bezier(0.2, 0, 0, 1) forwards; }
@keyframes lz-verdict {
  0%   { opacity: 0; transform: translateX(-10px) scale(0.9); letter-spacing: 0.4em; }
  10%  { opacity: 1; transform: translateX(0) scale(1); letter-spacing: 0.16em; }
  70%  { opacity: 1; }
  100% { opacity: 0; transform: translateY(-14px); }
}

/* Losing its temper: it shakes, and the rim light goes hot. */
.lz-emitter.is-angry .lz-glow {
  background: radial-gradient(circle,
    rgba(255, 110, 90, 0.5) 0%, rgba(230, 60, 40, 0.2) 46%, transparent 72%);
}
.lz-emitter.is-angry .lz-cube { background: linear-gradient(150deg, #ff8f86 0%, #e2453c 50%, #b52a24 100%); }
.lz-emitter.is-angry .lz-brow { height: 4px; width: 13px; }
.lz-emitter.is-angry .lz-brow-l { transform: rotate(30deg); }
.lz-emitter.is-angry .lz-brow-r { transform: rotate(-30deg); }

/* What the barrier says as it absorbs a hit. */
.lz-callout {
  position: absolute;
  --cx: -100%;
  transform: translate(var(--cx), -50%);
  padding: 0.26rem 0.55rem;
  border-radius: 999px;
  border: 1px solid rgba(120, 230, 255, 0.35);
  background: rgba(8, 24, 38, 0.82);
  color: #cdf4ff;
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.06em;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
}
.lz-callout.to-right { --cx: 0%; }
.lz-callout.is-live { animation: lz-say 2.1s cubic-bezier(0.2, 0, 0, 1) forwards; }
@keyframes lz-say {
  0%   { opacity: 0; transform: translate(var(--cx), -40%) scale(0.86); }
  14%  { opacity: 1; transform: translate(var(--cx), -60%) scale(1); }
  60%  { opacity: 1; transform: translate(var(--cx), -120%) scale(1); }
  100% { opacity: 0; transform: translate(var(--cx), -185%) scale(0.98); }
}

.lz-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

/* The card reacting is what ties the overlay to the page — the difference
   between a picture drawn on top and something actually hitting it. */
@keyframes lz-jolt {
  0%, 100% { transform: translateX(0); }
  24% { transform: translateX(3px); }
  58% { transform: translateX(-2px); }
}
.hero-stat.is-hit { animation: lz-jolt 0.32s ease-out; }

@media (prefers-reduced-motion: reduce) {
  .hero-stat.is-hit { animation: none; }
}
