/* ============================================================================
   Nexian Global — Landing page (V0-faithful)
   ============================================================================ */

/* ─────────────────────────────────────────────────────────────────────────
   ATMOSPHERE — fixed background, smoke clouds, embers, scroll-reactive overlay

   Two pause mechanisms protect the page from compositor-thrash flicker:

     body.tab-hidden …      Set by a visibilitychange listener in landing.php.
                            Pauses every heavy infinite animation while the
                            tab is in the background so the GPU isn't asked
                            to keep ticking blurred compositor layers that
                            nobody can see. On return the animations resume
                            cleanly from where they paused.

     prefers-reduced-motion Users who opted into "Reduce motion" at the OS
                            level get a static atmospheric backdrop — no
                            ken-burns pan, no smoke drift, no embers, no
                            war-glow pulse. Everything else (modals, hover
                            lifts, etc.) still animates.
   ───────────────────────────────────────────────────────────────────────── */
body.tab-hidden .landing-atmos-bg,
body.tab-hidden .smoke-cloud,
body.tab-hidden .ground-fog,
body.tab-hidden .war-glow,
body.tab-hidden .ember,
body.tab-hidden .hero-ember {
    animation-play-state: paused !important;
}

@media (prefers-reduced-motion: reduce) {
    .landing-atmos-bg,
    .smoke-cloud,
    .ground-fog,
    .war-glow,
    .ember,
    .hero-ember {
        animation: none !important;
    }
    .landing-atmos-dim {
        transition: none !important;
    }
}

.landing-atmos {
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    overflow: hidden;
}

.landing-atmos-bg {
    position: absolute;
    top: -10vh; right: 0; left: 0;
    height: 120vh;
    background-image: url('/assets/img/background-nexian.jpg');
    background-size: cover;
    background-position: center;
    filter: blur(2px);
    animation: ken-burns 60s ease-in-out infinite alternate;
}

/* Scroll-reactive dim + vignette */
.landing-atmos-dim {
    position: fixed;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    /* Reduced from 0.3 → 0.2 base; scroll JS below caps at ~0.55 (was 0.8)
       so section 2 looks less "behind dark glass". */
    background-color: rgba(2, 6, 23, 0.2);
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
    /* No transition on backdrop-filter — JS RAF-writes it on scroll, and
       transitioning compositor-heavy properties causes a paint-storm + a
       visible "catch-up smear" when the tab regains focus after throttling. */
    transition: background-color 500ms;
}

.landing-atmos-vignette {
    position: fixed;
    inset: 0;
    z-index: 2;
    pointer-events: none;
    background: radial-gradient(
        circle at center,
        rgba(0, 0, 0, 0.1) 0%,
        rgba(0, 0, 0, 0.3) 50%,
        rgba(0, 0, 0, 0.6) 100%
    );
}

/* Heavy smoke clouds */
.smoke-cloud {
    position: absolute;
    border-radius: 50%;
    filter: blur(80px);
    pointer-events: none;
    animation: smoke-drift 12s ease-in-out infinite;
}
.smoke-cloud.cloud-1 {
    width: 80rem; height: 80rem;
    top: -20%; right: -30%;
    background: radial-gradient(ellipse 80% 60%, rgba(50, 45, 40, 0.5) 0%, rgba(30, 25, 20, 0.3) 40%, transparent 70%);
}
.smoke-cloud.cloud-2 {
    width: 70rem; height: 70rem;
    top: 0; left: -25%;
    background: radial-gradient(ellipse 70% 80%, rgba(60, 55, 50, 0.45) 0%, rgba(35, 30, 25, 0.25) 50%, transparent 75%);
    animation-duration: 15s;
    animation-delay: 2s;
}
.smoke-cloud.cloud-3 {
    width: 90rem; height: 60rem;
    top: 20%; right: -10%;
    filter: blur(100px);
    background: radial-gradient(ellipse 100% 50%, rgba(45, 40, 35, 0.4) 0%, rgba(25, 22, 18, 0.2) 60%, transparent 80%);
    animation-duration: 18s;
    animation-delay: 4s;
}

/* Ground fog */
.ground-fog {
    position: absolute;
    bottom: -10%; right: 0;
    width: 100%; height: 40rem;
    filter: blur(60px);
    pointer-events: none;
    background: linear-gradient(0deg, rgba(40, 35, 30, 0.45) 0%, rgba(50, 45, 40, 0.3) 30%, rgba(60, 50, 40, 0.15) 60%, transparent 100%);
    animation: ground-fog-rise 10s ease-in-out infinite;
}

/* War fire glow at bottom */
.war-glow {
    position: absolute;
    bottom: -30%; right: -20%;
    width: 100rem; height: 50rem;
    filter: blur(120px);
    pointer-events: none;
    background: radial-gradient(ellipse 80% 40%, rgba(180, 60, 20, 0.25) 0%, rgba(120, 40, 10, 0.15) 40%, rgba(80, 20, 5, 0.08) 70%, transparent 90%);
    animation: war-glow-pulse 8s ease-in-out infinite;
}

@keyframes smoke-drift {
    0%, 100% { transform: translate(0, 0) scale(1) rotate(0); }
    50%      { transform: translate(-80px, -20px) scale(1.2) rotate(8deg); }
}
@keyframes ground-fog-rise {
    0%, 100% { transform: translateY(0); opacity: 0.4; }
    50%      { transform: translateY(-20px); opacity: 0.5; }
}
@keyframes war-glow-pulse {
    0%, 100% { transform: scale(1) translateX(0); opacity: 0.3; }
    50%      { transform: scale(1.15) translateX(-30px); opacity: 0.4; }
}

/* Rising ember particles — generated server-side, animated by CSS only */
.ember {
    position: absolute;
    border-radius: 50%;
    bottom: -30px;
    pointer-events: none;
    animation: ember-rise linear infinite;
}
.ember.small {
    width: 4px; height: 4px;
    background: radial-gradient(circle, rgba(255, 160, 20, 0.5) 0%, rgba(255, 100, 0, 0.3) 100%);
    box-shadow: 0 0 10px rgba(255, 130, 0, 0.5), 0 0 20px rgba(255, 80, 0, 0.3);
}
.ember.large {
    width: 7px; height: 7px;
    background: radial-gradient(circle at 70% 30%, rgba(255, 200, 50, 0.55) 0%, rgba(255, 120, 0, 0.45) 40%, rgba(255, 50, 0, 0.25) 100%);
    box-shadow: 0 0 15px rgba(255, 150, 0, 0.55), 0 0 30px rgba(255, 100, 0, 0.4), 0 0 45px rgba(255, 50, 0, 0.25);
}

/* ─────────────────────────────────────────────────────────────────────────
   HERO SECTION — full-screen, centered
   ───────────────────────────────────────────────────────────────────────── */
.landing-hero {
    position: relative;
    z-index: 10;
    /*
     * Hero fills the viewport precisely from navbar to fold, so the
     * section-2 legacy-box doesn't peek above the fold. The wrapping
     * <main> contributes a 2rem top padding above the hero element —
     * subtracting that means the hero ends exactly at viewport bottom.
     *
     * Content vertical centering is preserved (against the previous
     *   min-height: calc(100vh - 9rem); padding-bottom: 2rem)
     * by absorbing the extra 7rem into padding-bottom — keeps the
     * stats-pill ↔ logo ↔ CTA stack in the same on-screen position
     * while the hero block itself extends to the fold.
     */
    /* svh, not vh. On a phone `vh` is the LARGEST viewport (chrome retracted),
       so a 100vh hero is taller than the screen on load and the composition
       jumps as the address bar hides. svh is the smallest, which is stable.
       The vh line stays first as the fallback for anything that predates it. */
    min-height: calc(100vh - 2rem);
    min-height: calc(100svh - 2rem);
    margin-top: -4.25rem;
    /*
     * 4.25rem of this clears the navbar the negative margin tucks under;
     * the rest is the deliberate gap below it.
     *
     * 2026-08-22: back to `center` from `flex-start`. Top-anchoring made the
     * hero read differently at every screen height - measured 136px of dead
     * space under the CTA at 800px tall and 416px at 1080px, while a 700px
     * window pushed the CTA past the fold. The earlier objection to centring
     * ("the brand sat 98px below the navbar") was recorded BEFORE the scroll
     * hint was pinned out of flow further down this file; with 54px no longer
     * in the column the slack splits evenly and the composition holds its
     * position relative to the screen instead of to the navbar.
     * Phones keep flex-start - see the max-width: 640px block at the foot.
     */
    padding-top: 5.5rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding-right: 1rem;
    padding-left: 1rem;
    padding-bottom: 9rem;
    overflow: hidden;
}

/* Hero ember system — extra particles concentrated near hero */
.hero-embers {
    position: absolute;
    inset: 0;
    overflow: hidden;
    pointer-events: none;
    z-index: 0;
}
.hero-ember {
    position: absolute;
    border-radius: 50%;
    bottom: -20px;
    background: radial-gradient(circle, rgba(251, 146, 60, 0.8) 0%, rgba(239, 68, 68, 0.6) 50%, transparent 70%);
    box-shadow: 0 0 8px rgba(251, 146, 60, 0.6), 0 0 16px rgba(239, 68, 68, 0.4);
    filter: blur(1px);
    animation: hero-ember-rise linear infinite;
}
@keyframes hero-ember-rise {
    0%   { transform: translate(0, 0); opacity: 0; }
    10%  { opacity: 0.8; }
    80%  { opacity: 0.8; }
    100% { transform: translate(var(--drift, 0), -1000px); opacity: 0; }
}

/* Live stats pill bar */
.hero-stats-pill {
    position: relative;
    display: inline-flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    gap: 1.25rem;
    padding: 0.75rem 1.75rem;
    border-radius: 9999px;
    background: rgba(0, 0, 0, 0.6);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    box-shadow: 0 25px 80px rgba(0, 0, 0, 0.6), 0 15px 40px rgba(0, 0, 0, 0.4);
    overflow: hidden;
    z-index: 10;
}
.hero-stats-pill::before {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: 9999px;
    pointer-events: none;
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1), transparent);
    background-size: 200% 100%;
    animation: shimmer-x 8s ease-in-out infinite;
}
.hero-stats-active {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.25rem 0.625rem;
    border-radius: 9999px;
    background: rgba(52, 211, 153, 0.2);
    border: 1px solid rgba(52, 211, 153, 0.4);
    font-size: 0.8125rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: #4ADE80;
}
.hero-stats-active .dot {
    width: 0.5rem; height: 0.5rem;
    border-radius: 50%;
    background: #22C55E;
    animation: pulse-soft 2s infinite;
}
.hero-stats-sep {
    width: 1px; height: 1.25rem;
    background: rgba(var(--gold-rgb), 0.3);
}
.hero-stat-item {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.8125rem;
    color: #9CA3AF;
}
.hero-stat-item .v {
    font-size: 0.875rem;
    font-weight: 600;
    color: white;
}
.hero-stat-item .v.green   { color: #4ADE80; }
.hero-stat-item .v.discord { color: #7289DA; }

/* Countdown pill */
.hero-countdown-pill {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 0.75rem;
    margin-top: 0.5rem;
    padding: 0.5rem 1.25rem;
    border-radius: 9999px;
    background: linear-gradient(90deg, rgba(255, 100, 50, 0.15) 0%, rgba(255, 150, 50, 0.1) 50%, rgba(255, 100, 50, 0.15) 100%);
    border: 1px solid rgba(255, 150, 50, 0.3);
    backdrop-filter: blur(8px);
    overflow: hidden;
}
.hero-countdown-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    padding: 0.125rem 0.5rem;
    border-radius: 9999px;
    background: rgba(249, 115, 22, 0.25);
    font-size: 0.8125rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: #FB923C;
}
.hero-countdown-text {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    font-size: 0.8125rem;
    color: rgba(255, 200, 150, 0.8);
}
.hero-countdown-text .v {
    font-weight: 700;
    color: #FED7AA;
    letter-spacing: 0.05em;
    font-variant-numeric: tabular-nums;
    min-width: 7ch;     /* keep width stable while the seconds digit ticks */
    display: inline-block;
    text-align: right;
}
.hero-countdown-segment {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
}
.hero-countdown-sep {
    color: rgba(255, 200, 150, 0.35);
    font-weight: 400;
    padding: 0 0.5rem;
}

/* Enlarged variant — used when no realms are live so the countdown becomes
 * the hero's main focal point. Bigger pad/font, stronger glow, gentle pulse. */
.hero-countdown-pill.is-large {
    margin-top: 0.75rem;
    padding: 0.875rem 1.75rem;
    gap: 1rem;
    border-color: rgba(255, 150, 50, 0.5);
    box-shadow:
        0 0 24px rgba(251, 146, 60, 0.18),
        0 0 60px rgba(251, 146, 60, 0.10);
    animation: heroCountdownPulse 3.2s ease-in-out infinite;
}
.hero-countdown-pill.is-large .hero-countdown-badge {
    padding: 0.25rem 0.75rem;
    font-size: 0.8125rem;
    letter-spacing: 0.15em;
}
.hero-countdown-pill.is-large .hero-countdown-text {
    font-size: 1rem;
    gap: 0.5rem;
}
.hero-countdown-pill.is-large .hero-countdown-text .v {
    font-size: 1.125rem;
    color: #FFE4B5;
    text-shadow: 0 0 12px rgba(251, 146, 60, 0.45);
}
.hero-countdown-pill.is-large .hero-countdown-sep {
    font-size: 1.125rem;
    color: rgba(255, 200, 150, 0.45);
}
@keyframes heroCountdownPulse {
    0%, 100% {
        box-shadow:
            0 0 24px rgba(251, 146, 60, 0.18),
            0 0 60px rgba(251, 146, 60, 0.10);
    }
    50% {
        box-shadow:
            0 0 32px rgba(251, 146, 60, 0.28),
            0 0 80px rgba(251, 146, 60, 0.16);
    }
}

@media (max-width: 640px) {
    .hero-countdown-pill.is-large {
        padding: 0.75rem 1.25rem;
        flex-wrap: wrap;
        justify-content: center;
        text-align: center;
    }
    .hero-countdown-pill.is-large .hero-countdown-text {
        font-size: 0.875rem;
        flex-wrap: wrap;
        justify-content: center;
    }
}

/* Slogan + Logo wrapper — single hover target. V0 spec
 * (app/page.tsx:778): on hover lift 8px AND scale 1.05 over 300ms.
 * `cursor: default` because the emblem isn't a button — it's decorative.
 * `will-change` keeps the transform on its own layer so the lift is
 * janky-free even on low-end devices. */
.hero-emblem {
    display: flex;
    flex-direction: column;
    align-items: center;
    cursor: default;
    transition: transform 300ms cubic-bezier(0.4, 0, 0.2, 1);
    will-change: transform;
}
.hero-emblem:hover {
    transform: translateY(-8px) scale(1.05);
}
@media (prefers-reduced-motion: reduce) {
    .hero-emblem,
    .hero-emblem:hover { transition: none; transform: none; }
}

/*
 * The separate slogan headline is gone: the hero lockup
 * (assets/img/nexian-wordmark.webp) already carries "THE LEGACY EVOLVES"
 * under the wordmark, so drawing it twice was the old composition's whole
 * problem. The text still exists for search and screen readers as an
 * .sr-only <h2> plus the image's alt - see pages/landing.php.
 */

/* Logo image — large, centered */
/*
 * Sized by WIDTH, not height. The lockup is 656x266 (2.47:1) where the old
 * banner was 3.09:1, so holding height constant would have shrunk the mark by
 * a fifth across the fold. Width is also the axis that actually runs out on a
 * phone.
 *
 * Shadow: three stacked drop-shadows at 0.8/0.6/0.4 read as a hard slab under
 * the metal. Halved - the mark still lifts off the artwork, it no longer sits
 * on a shelf.
 */
/* Width now lives on .hero-logo-wrap (see the tagline-lift block at the foot of
   this file): the lift layer is positioned against the wrapper, so the wrapper
   has to be the element that carries the size. The image fills it. */
.hero-logo {
    height: auto;
    position: relative;
    z-index: 1;
    filter: drop-shadow(0 8px 20px rgba(0, 0, 0, 0.42))
            drop-shadow(0 4px 12px rgba(0, 0, 0, 0.28))
            drop-shadow(0 2px 5px rgba(0, 0, 0, 0.18));
}

/*
 * Background effect behind the mark. Two eased radial washes, no filter and no
 * extra layer to rasterise: a cool steel core that picks up the helmet's gem
 * and the visor highlights, and a wider gold ring underneath that ties the
 * mark to the rest of the page. Both fade to nothing well inside their box, so
 * there is no edge anywhere - the same one-layer rule the forge scrim follows.
 */
.hero-aura {
    position: absolute;
    right: 50%;
    top: 50%;
    width: 170%;
    height: 250%;
    transform: translate(50%, -50%);
    z-index: -1;
    pointer-events: none;
    background:
        radial-gradient(closest-side ellipse at 50% 50%,
            rgba(163, 214, 232, 0.17) 0%,
            rgba(140, 186, 210, 0.075) 38%,
            rgba(140, 186, 210, 0) 72%),
        radial-gradient(closest-side ellipse at 50% 56%,
            rgba(var(--gold-rgb), 0.14) 0%,
            rgba(var(--gold-rgb), 0.055) 46%,
            rgba(var(--gold-rgb), 0) 78%);
}
/* Desktop only, and off for anyone who asked for less motion. A 9s cycle is
   slow enough to read as light rather than as an animation. */
@media (min-width: 1024px) {
    .hero-aura { animation: hero-aura-breathe 9s ease-in-out infinite alternate; }
}
@keyframes hero-aura-breathe {
    from { opacity: 0.82; transform: translate(50%, -50%) scale(0.98); }
    to   { opacity: 1;    transform: translate(50%, -50%) scale(1.04); }
}
@media (prefers-reduced-motion: reduce) {
    .hero-aura { animation: none; }
}

/* Tagline */
.hero-tagline {
    margin-top: 2rem;
    margin-bottom: 2.5rem;
    max-width: 42rem;
    font-size: 1rem;
    line-height: 1.625;
    color: #D1D5DB;
}
@media (min-width: 768px) { .hero-tagline { font-size: 1.125rem; margin-bottom: 3rem; } }

/* START JOURNEY mega-CTA */
.start-journey {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.875rem 2.5rem;
    border-radius: 0.5rem;
    border: 1px solid rgba(122, 78, 6, 0.55);
    color: #2A1C00;
    font-size: 0.9375rem;
    font-weight: 900;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    cursor: pointer;
    overflow: hidden;
    /* Was #FFD700 -> #FF8F00, which lands in orange by its midpoint and is
       the only orange left on the page. This runs through the gold the rest
       of the site uses. Brightness is unchanged; only the hue moved. */
    background: linear-gradient(135deg, #FFE9A8 0%, #FBD469 22%, #F5C842 48%, #E2A92C 76%, #C98C18 100%);
    /* A struck edge rather than a flat outline: light along the top, shadow
       along the bottom, so the face reads as raised metal. */
    box-shadow: 0 0 80px rgba(245, 200, 66, 0.62),
                0 0 40px rgba(226, 169, 44, 0.46),
                0 20px 60px rgba(140, 92, 10, 0.42),
                inset 0 2px 0 rgba(255, 252, 235, 0.62),
                inset 0 -3px 10px rgba(150, 96, 8, 0.30),
                inset 0 0 0 1px rgba(255, 245, 200, 0.35);
    text-shadow: 0 1px 2px rgba(120, 80, 0, 0.3);
    transition: transform 300ms var(--ease-out);
}
@media (min-width: 640px) { .start-journey { padding: 1rem 3.5rem; font-size: 1rem; } }
@media (min-width: 768px) { .start-journey { padding: 1.25rem 3.5rem; font-size: 1.125rem; } }

.start-journey:hover {
    transform: translateY(-4px) scale(1.05);
}
.start-journey::before {
    content: '';
    position: absolute;
    inset: -4px;
    border-radius: 0.5rem;
    z-index: -1;
    background: linear-gradient(135deg, #FFD700, #FF8F00, #FFD700);
    opacity: 0.75;
    filter: blur(6px);
    animation: cta-pulse 2s ease-in-out infinite;
}
.start-journey::after {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: linear-gradient(105deg, transparent 40%, rgba(255, 255, 255, 0.6) 50%, transparent 60%);
    background-size: 200% 100%;
    animation: shimmer-x 2.5s ease-in-out infinite;
    opacity: 0.4;
}
.start-journey > svg { position: relative; z-index: 10; transition: transform 300ms var(--ease-out); }
.start-journey:hover > svg { transform: translateX(-5px); }
/* The gap opens with it, so the whole label leans forward rather than the
   arrow drifting away from stationary text. */
.start-journey { transition-property: transform, box-shadow, opacity, gap; }
.start-journey:hover { gap: 1rem; }

/* Top white highlight on CTA */
.start-journey > .top-highlight {
    position: absolute;
    top: 0; right: 0; left: 0;
    height: 2px;
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.7), transparent);
    z-index: 5;
    pointer-events: none;
}
/* The corner brackets were removed with their markup: the same dated motif
   the owner had already taken out of the manual. */

@keyframes cta-pulse {
    0%, 100% { opacity: 0.6; }
    50%      { opacity: 0.95; }
}

/* Scroll-down indicator */
.scroll-down {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
    margin-top: 2.5rem;
    cursor: pointer;
}
/* White on the artwork was the last piece of the hero speaking a different
   language from the rest of the page. */
.scroll-down svg {
    width: 1.5rem; height: 1.5rem;
    color: rgba(var(--gold-rgb), 0.85);
    animation: scroll-bounce 2s ease-in-out infinite;
}
.scroll-down span {
    font-family: var(--font-display);
    font-size: 0.9375rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.26em;
    color: rgba(232, 208, 148, 0.95);
    text-shadow: 0 2px 10px rgba(0, 0, 0, 0.9);
    transition: color 0.2s ease;
}
.scroll-down:hover span { color: #FFD700; }
@keyframes scroll-bounce {
    0%, 100% { transform: translateY(0); }
    50%      { transform: translateY(8px); }
}

/* ─────────────────────────────────────────────────────────────────────────
   SECTION 2 — Legacy Evolves premium box
   ───────────────────────────────────────────────────────────────────────── */
.legacy-box {
    position: relative;
    border-radius: 1rem;
    overflow: hidden;
    background: linear-gradient(170deg, rgba(24, 18, 8, 0.88) 0%, rgba(14, 10, 5, 0.94) 50%, rgba(20, 15, 8, 0.88) 100%);
    box-shadow: 0 0 120px rgba(var(--gold-rgb), 0.15),
                0 30px 80px rgba(0, 0, 0, 0.7),
                inset 0 2px 0 rgba(255, 248, 220, 0.06);
}
.legacy-box::before {
    content: '';
    position: absolute;
    inset: -2px;
    z-index: -1;
    border-radius: 1rem;
    background: linear-gradient(135deg, rgba(var(--gold-rgb), 0.6) 0%, rgba(180, 140, 40, 0.2) 25%, rgba(255, 215, 0, 0.5) 50%, rgba(180, 140, 40, 0.2) 75%, rgba(var(--gold-rgb), 0.6) 100%);
    background-size: 300% 300%;
    animation: shimmer-x 4s ease-in-out infinite;
    opacity: 0.8;
}

.legacy-top-shimmer {
    position: absolute;
    top: 0; inset-inline: 0;
    height: 3px;
    background: linear-gradient(90deg, transparent 0%, #9A7515 15%, #C8962E 30%, #FFD700 45%, #FFF8DC 50%, #FFD700 55%, #C8962E 70%, #9A7515 85%, transparent 100%);
    box-shadow: 0 0 30px rgba(255, 215, 0, 0.6), 0 0 60px rgba(var(--gold-rgb), 0.3);
}

.legacy-corner {
    position: absolute;
    width: 3rem; height: 3rem;
    pointer-events: none;
}
.legacy-corner.tl { top: 1.25rem; right: 1.25rem; }
.legacy-corner.tr { top: 1.25rem; left: 1.25rem; }
.legacy-corner.bl { bottom: 1.25rem; right: 1.25rem; }
.legacy-corner.br { bottom: 1.25rem; left: 1.25rem; }
.legacy-corner::before, .legacy-corner::after {
    content: '';
    position: absolute;
    background: var(--gold-400);
    box-shadow: 0 0 10px var(--gold-400);
}
.legacy-corner.tl::before { top: 0; right: 0; width: 100%; height: 2px; background: linear-gradient(90deg, var(--gold-400), transparent); }
.legacy-corner.tl::after  { top: 0; right: 0; width: 2px; height: 100%; background: linear-gradient(180deg, var(--gold-400), transparent); }
.legacy-corner.tr::before { top: 0; left: 0; width: 100%; height: 2px; background: linear-gradient(270deg, var(--gold-400), transparent); }
.legacy-corner.tr::after  { top: 0; left: 0; width: 2px; height: 100%; background: linear-gradient(180deg, var(--gold-400), transparent); }
.legacy-corner.bl::before { bottom: 0; right: 0; width: 100%; height: 2px; background: linear-gradient(90deg, var(--gold-400), transparent); }
.legacy-corner.bl::after  { bottom: 0; right: 0; width: 2px; height: 100%; background: linear-gradient(0deg, var(--gold-400), transparent); }
.legacy-corner.br::before { bottom: 0; left: 0; width: 100%; height: 2px; background: linear-gradient(270deg, var(--gold-400), transparent); }
.legacy-corner.br::after  { bottom: 0; left: 0; width: 2px; height: 100%; background: linear-gradient(0deg, var(--gold-400), transparent); }

.legacy-corner-dot {
    position: absolute;
    width: 0.5rem; height: 0.5rem;
    border-radius: 50%;
    background: var(--gold-400);
    box-shadow: 0 0 10px var(--gold-400);
}
.legacy-corner.tl .legacy-corner-dot { top: 0.25rem; right: 0.25rem; }
.legacy-corner.tr .legacy-corner-dot { top: 0.25rem; left: 0.25rem; }
.legacy-corner.bl .legacy-corner-dot { bottom: 0.25rem; right: 0.25rem; }
.legacy-corner.br .legacy-corner-dot { bottom: 0.25rem; left: 0.25rem; }

.legacy-body { position: relative; padding: 1.5rem 2rem 2rem; }
@media (min-width: 768px) { .legacy-body { padding: 2.5rem 3rem; } }

.era-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.375rem 1.25rem;
    border-radius: 9999px;
    background: linear-gradient(90deg, transparent, rgba(var(--gold-rgb), 0.15) 20%, rgba(255, 215, 0, 0.08) 50%, rgba(var(--gold-rgb), 0.15) 80%, transparent);
    border: 1px solid rgba(var(--gold-rgb), 0.4);
    box-shadow: 0 0 20px rgba(var(--gold-rgb), 0.15);
}
.era-badge-dot {
    width: 0.375rem; height: 0.375rem;
    border-radius: 50%;
    background: linear-gradient(135deg, #FFD700, var(--gold-400));
    box-shadow: 0 0 12px var(--gold-400);
}
.era-badge-text {
    font-family: var(--font-display);
    font-size: 0.8125rem;
    font-weight: 900;
    text-transform: uppercase;
    letter-spacing: 0.3em;
    color: #F4E287;
    text-shadow: 0 0 20px rgba(var(--gold-rgb), 0.5);
}

.legacy-title {
    font-family: var(--font-display);
    font-size: 1.5rem;
    font-weight: 900;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    text-align: center;
    margin: 1.25rem 0;
    background: linear-gradient(180deg, #FFFFFF 0%, #FFF8DC 20%, #FFD700 45%, var(--gold-400) 70%, #9A7515 100%);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    filter: drop-shadow(0 4px 20px rgba(var(--gold-rgb), 0.5));
}
@media (min-width: 768px)  { .legacy-title { font-size: 2.25rem; } }
@media (min-width: 1024px) { .legacy-title { font-size: 3rem; } }

.legacy-divider {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 1rem;
    margin-bottom: 1.25rem;
}
.legacy-divider .line {
    height: 2px;
    width: 3rem;
    background: linear-gradient(90deg, transparent, rgba(var(--gold-rgb), 0.6));
    box-shadow: 0 0 10px rgba(var(--gold-rgb), 0.3);
}
.legacy-divider .line.right { background: linear-gradient(270deg, transparent, rgba(var(--gold-rgb), 0.6)); }
@media (min-width: 768px) { .legacy-divider .line { width: 5rem; } }
.legacy-divider .glyph-wrap {
    position: relative;
    padding: 0.375rem;
    border-radius: 0.5rem;
    background: rgba(var(--gold-rgb), 0.1);
    border: 1px solid rgba(var(--gold-rgb), 0.3);
    color: var(--gold-400);
    filter: drop-shadow(0 0 6px rgba(var(--gold-rgb), 0.6));
}

.legacy-quote {
    position: relative;
    max-width: 56rem;
    margin: 0 auto 1.5rem;
    font-size: 0.8125rem;
    line-height: 1.7;
    text-align: center;
    color: rgba(230, 215, 175, 0.9);
}
@media (min-width: 768px)  { .legacy-quote { font-size: 0.875rem; line-height: 1.8; } }
@media (min-width: 1024px) { .legacy-quote { font-size: 1rem; } }
.legacy-quote .accent { color: #F4E287; font-weight: 600; }
.legacy-quote .ribbon {
    display: inline-block;
    padding: 0.125rem 0.5rem;
    border-radius: 0.25rem;
    background: linear-gradient(90deg, rgba(var(--gold-rgb), 0.2), rgba(var(--gold-rgb), 0.1));
    color: #FFD700;
    font-weight: 700;
}
/* Decorative quote marks intentionally removed — the user requested a clean
 * statement, not a pull-quote treatment. */

/* Feature pills row
 * Designer pass (2026-05-20): bumped pill box + text by ~10% across the
 * board so the 4-pill strip reads better against the now-larger section
 * heading above it. Every dimension below was scaled by 1.1 from its
 * previous value (rounded to a clean rem step). */
.legacy-pills {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.6875rem;                 /* was 0.625rem */
}
.legacy-pill {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.1875rem;                 /* was 0.125rem */
    padding: 0.5625rem 0.8125rem;   /* was 0.5rem 0.75rem (~10% bump; trimmed from 0.625/0.9375 to keep the mobile 2×2 wrap layout intact — "Active Community" was being forced onto its own row) */
    border-radius: 0.5rem;
    background: linear-gradient(145deg, rgba(var(--gold-rgb), 0.12) 0%, rgba(180, 140, 40, 0.06) 100%);
    border: 1px solid rgba(var(--gold-rgb), 0.25);
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.03);
    transition: transform 300ms var(--ease-out);
    text-align: center;
}
.legacy-pill:hover { transform: translateY(-2px); }
.legacy-pill-row { display: inline-flex; align-items: center; gap: 0.4375rem; }  /* was 0.375rem */
.legacy-pill-icon {
    width: 1.375rem; height: 1.375rem;  /* was 1.25rem */
    border-radius: 0.4375rem;            /* was 0.375rem */
    background: rgba(var(--gold-rgb), 0.15);
    border: 1px solid rgba(var(--gold-rgb), 0.25);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--gold-400);
}
.legacy-pill-label {
    font-family: var(--font-display);
    font-size: 0.8125rem;             /* was 0.6875rem */
    font-weight: 700;
    color: rgba(240, 225, 180, 0.95);
}
.legacy-pill-desc {
    font-size: 0.8125rem;           /* legibility pass: was 0.5625rem */
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: rgba(196, 172, 120, 0.85);
}

/* Mobile (≤480px): the +10% bump made "Active Community" wide enough to
 * push its row-mate to its own row, leaving an awkward 1+1+1+1 stack.
 * Force a stable 2×2 grid here so the four pills always pair up. */
@media (max-width: 480px) {
    .legacy-pills {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 0.5rem;
    }
    .legacy-pill {
        padding: 0.5rem 0.5rem;     /* tighter side-padding so longer labels fit the half-column */
    }
}

/* ─────────────────────────────────────────────────────────────────────────
   SECTION LABELS (used by all section dividers)
   ───────────────────────────────────────────────────────────────────────── */
.section-divider {
    display: flex;
    align-items: center;
    gap: 0.875rem;
    margin-bottom: 1.5rem;
}
.section-divider .line { flex: 1; height: 1px; }
.section-divider .line.left  { background: linear-gradient(90deg, transparent, rgba(var(--gold-rgb), 0.25)); }
.section-divider .line.right { background: linear-gradient(270deg, transparent, rgba(var(--gold-rgb), 0.25)); }
.section-divider .label {
    display: inline-flex;
    align-items: center;
    gap: 0.625rem;
}
/* Designer pass (2026-05-20): bumped from 0.625rem → 1rem, with looser
   letter-spacing so the heavier weight still feels open. Brightened
   the colour from 0.6 → 0.78 alpha so the gold reads at the new size. */
.section-divider .label-text {
    font-family: var(--font-display);
    font-size: 1rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.22em;
    color: rgba(var(--gold-rgb), 0.78);
}
.section-divider .glyph { color: rgba(var(--gold-rgb), 0.6); }
.section-divider .glyph-dot {
    width: 0.375rem; height: 0.375rem;
    border-radius: 50%;
    background: rgba(var(--gold-rgb), 0.7);
}
.section-divider .glyph-dot.live {
    background: #4ADE80;
    animation: pulse-soft 2s infinite;
}

/* ─────────────────────────────────────────────────────────────────────────
   SERVER WIDGET (Prime / Live / Coming Soon)
   ───────────────────────────────────────────────────────────────────────── */
/* Flex (not grid) so N cards always cluster around the centre. With grid +
 * `repeat(3, 1fr)`, two cards land in columns 1+2 with the third column
 * empty — left-aligned. Flex + `justify-content: center` keeps them
 * symmetric for any count. Each card has a sane min-width so it doesn't
 * shrink past readability, and a max-width so 1 card doesn't stretch huge. */
.swidget-grid {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.75rem;
}
.swidget-grid > .swcard {
    flex: 1 1 280px;
    max-width: 360px;
}
@media (max-width: 767px) {
    .swidget-grid > .swcard { flex: 1 1 100%; max-width: 28rem; }
}

.swcard {
    position: relative;
    border-radius: 0.75rem;
    overflow: hidden;
    text-align: right;
    background: linear-gradient(145deg, rgba(18, 13, 6, 0.94) 0%, rgba(10, 7, 3, 0.97) 100%);
    border: 1px solid rgba(212, 175, 55, 0.16);
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4);
    cursor: pointer;
    transition: transform var(--dur-base) var(--ease-out), border-color var(--dur-base) var(--ease-out);
}
.swcard:hover { transform: translateY(-2px); border-color: rgba(var(--gold-rgb), 0.4); }

.swcard.prime {
    background: linear-gradient(145deg, rgba(28, 20, 8, 0.98) 0%, rgba(18, 12, 4, 0.99) 100%);
    /* 1px (not 2px) gold border — visually consistent with the other cards. */
    border: 1px solid rgba(var(--gold-rgb), 0.35);
    /* Very soft halo. Inner gold accents already carry the premium feel; an
     * outer glow on top of that reads as a flash. */
    box-shadow: 0 0 18px rgba(var(--gold-rgb), 0.05), 0 8px 30px rgba(0, 0, 0, 0.45);
    /* Hover transitions: quick lift, slower shadow settle. */
    transition: transform 250ms var(--ease-out),
                box-shadow 350ms var(--ease-out),
                border-color 250ms var(--ease-out);
}
.swcard.prime::before {
    content: '';
    position: absolute;
    inset: -1px;
    z-index: -1;
    border-radius: var(--radius-md);
    background: linear-gradient(135deg, #5C4408 0%, var(--gold-600) 30%, var(--gold-400) 50%, var(--gold-600) 70%, #5C4408 100%);
    opacity: 0.25;
    /* Slow "breathe" on hover: the gold ring eases from 0.25 → 0.40 over half
     * a second. Slower than the body lift so it feels atmospheric, not snappy. */
    transition: opacity 500ms var(--ease-out);
}
/* Prime hover (option D = quiet lift + breathing ring):
 *   - translateY(-3px) scale(1.005)  → card "rises to your attention"
 *   - box-shadow's gold component STAYS the same (no flash); only the
 *     dark drop-shadow grows to sell the lift
 *   - ::before opacity 0.25 → 0.40 (the breathing ring, handled above) */
.swcard.prime:hover {
    transform: translateY(-3px) scale(1.005);
    border-color: rgba(var(--gold-rgb), 0.42);
    box-shadow: 0 0 18px rgba(var(--gold-rgb), 0.05),
                0 18px 40px rgba(0, 0, 0, 0.60);
}
/* Prime realm rides slightly above its neighbours in multi-card rows
   (desktop only — mobile stacks flush). */
@media (min-width: 768px) {
    .swidget-grid .swcard.prime { transform: translateY(-0.5rem); }
    .swidget-grid .swcard.prime:hover { transform: translateY(calc(-0.5rem - 3px)) scale(1.005); }
}
.swcard.prime:hover::before {
    opacity: 0.40;
}
/* Announced-but-unopened world (s2): full-fidelity red-accent teaser card,
   NOT a dimmed husk — players should notice it. */
.swcard.soon {
    background: linear-gradient(145deg, rgba(38, 14, 12, 0.92) 0%, rgba(16, 7, 6, 0.96) 100%);
    border: 1px solid rgba(239, 68, 68, 0.32);
    cursor: default;
}
.swcard.soon:hover { transform: none; border-color: rgba(239, 68, 68, 0.48); }
.swcard.soon .swcard-top-line {
    background: linear-gradient(90deg, transparent, rgba(239, 68, 68, 0.55), transparent);
}
.swcard.soon .swcard-stat {
    background: rgba(239, 68, 68, 0.06);
    border-color: rgba(239, 68, 68, 0.14);
}
.swcard.soon .swcard-stat-icon { color: rgba(248, 113, 113, 0.8); }
.swcard.soon .swcard-phase { color: rgba(248, 113, 113, 0.85); }

.swcard-top-line {
    position: absolute;
    top: 0; inset-inline: 0;
    height: 2px;
    background: linear-gradient(90deg, transparent, rgba(var(--gold-rgb), 0.5), transparent);
}
.swcard.prime .swcard-top-line {
    background: linear-gradient(90deg, transparent 0%, #9A7515 15%, var(--gold-400) 30%, #FFD700 50%, var(--gold-400) 70%, #9A7515 85%, transparent 100%);
    box-shadow: 0 0 20px rgba(255, 215, 0, 0.5);
}

.swcard-body { padding: 1rem; position: relative; }

.swcard-head { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 0.75rem; }
.swcard-subtitle {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    font-family: var(--font-display);
    /* Legibility pass: 0.5rem (7.2px) was unreadable; 0.6875rem ≈ 10px. */
    font-size: 0.8125rem;
    font-weight: 900;
    text-transform: uppercase;
    letter-spacing: 0.2em;
    color: rgba(var(--gold-rgb), 0.8);
}
.swcard.prime .swcard-subtitle { color: #FFD700; text-shadow: 0 0 10px rgba(255, 215, 0, 0.4); }
.swcard.soon .swcard-subtitle  { color: #F87171; }

.swcard-name {
    font-family: var(--font-display);
    font-size: 1rem;
    font-weight: 900;
    margin-top: 0.125rem;
    color: rgba(240, 220, 165, 0.95);
}
.swcard.prime .swcard-name {
    background: linear-gradient(180deg, #FFFFFF 0%, #FFF8DC 30%, #FFD700 70%, #C8962E 100%);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
}
.swcard.soon .swcard-name { color: rgba(240, 220, 165, 0.95); }

.swcard-status {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
}
.swcard-status .live-dot {
    position: relative;
    width: 0.375rem; height: 0.375rem;
    border-radius: 50%;
    background: #34D399;
}
.swcard-status .live-dot::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: 50%;
    background: #34D399;
    opacity: 0.6;
    animation: pulse-soft 1.5s infinite;
}
.swcard.prime .swcard-status .live-dot { background: #FFD700; }
.swcard.prime .swcard-status .live-dot::after { background: #FFD700; }
.swcard-status-pill {
    padding: 0.125rem 0.5rem;
    border-radius: 9999px;
    /* Short uppercase status word — sits one step below the caption tier so
       the pill stays a badge, not a headline. */
    font-size: 0.6875rem;
    font-weight: 900;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    background: rgba(52, 211, 153, 0.15);
    border: 1px solid rgba(52, 211, 153, 0.3);
    color: #34D399;
}
.swcard.prime .swcard-status-pill {
    background: linear-gradient(90deg, rgba(255, 215, 0, 0.2), rgba(var(--gold-rgb), 0.12));
    border-color: rgba(255, 215, 0, 0.4);
    color: #FFD700;
}
.swcard.soon .swcard-status-pill {
    background: rgba(239, 68, 68, 0.14);
    border-color: rgba(239, 68, 68, 0.4);
    color: #FCA5A5;
}


/* Tribe roster badge — how many tribes this round offers, beside the status
   pill. Violet is the one hue the card's status pills never use (emerald live /
   gold prime / red soon), and it is the tribe colour in the realm picker, so it
   reads as a property of the round rather than as another status. */
.swcard-tribes-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.125rem 0.5rem;
    border-radius: 9999px;
    font-size: 0.6875rem;
    font-weight: 900;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    white-space: nowrap;
    background: rgba(192, 132, 252, 0.13);
    border: 1px solid rgba(192, 132, 252, 0.34);
    color: #D8B4FE;
}
.swcard-divider {
    height: 1px;
    margin-bottom: 0.75rem;
    background: linear-gradient(90deg, rgba(var(--gold-rgb), 0.2), transparent);
}
.swcard.prime .swcard-divider { background: linear-gradient(90deg, rgba(var(--gold-rgb), 0.4), transparent); }

.swcard-stats {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 0.5rem;
    margin-bottom: 0.75rem;
}
.swcard-stat {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.125rem;
    padding: 0.375rem;
    border-radius: 0.5rem;
    background: rgba(0, 0, 0, 0.2);
    border: 1px solid rgba(255, 255, 255, 0.04);
}
.swcard.prime .swcard-stat { background: rgba(var(--gold-rgb), 0.08); border-color: rgba(var(--gold-rgb), 0.15); }
.swcard-stat-icon { color: rgba(var(--gold-rgb), 0.5); }
.swcard.prime .swcard-stat-icon { color: var(--gold-400); }
.swcard-stat-value { font-size: 0.9375rem; font-weight: 700; color: rgba(228, 210, 168, 0.95); }
.swcard.prime .swcard-stat-value { color: #F4E287; }
.swcard-stat-label {
    /* Caption tier: was 0.4375rem (6.3px, unreadable). Kept one step under
       the value so the number stays the focus of the tile. */
    font-size: 0.6875rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: rgba(172, 150, 108, 0.85);
}
.swcard.prime .swcard-stat-label { color: rgba(var(--gold-rgb), 0.85); }

.swcard-foot { display: flex; justify-content: space-between; align-items: center; }
.swcard-phase {
    font-size: 0.8125rem;
    color: rgba(190, 165, 115, 0.85);
}
.swcard.prime .swcard-phase { color: rgba(var(--gold-rgb), 0.8); }
.swcard-cta {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    font-size: 0.8125rem;
    font-weight: 700;
    color: var(--gold-400);
}
.swcard.prime .swcard-cta { color: #FFD700; }
.swcard:hover .swcard-cta { gap: 0.375rem; }

/* ─── Status pill variants (live / launching / over / dev) ────────────── */
.swcard-status-pill.status-live {
    background: rgba(52, 211, 153, 0.15);
    border-color: rgba(52, 211, 153, 0.3);
    color: #34D399;
}
.swcard.prime .swcard-status-pill.status-live {
    background: linear-gradient(90deg, rgba(255, 215, 0, 0.2), rgba(var(--gold-rgb), 0.12));
    border-color: rgba(255, 215, 0, 0.4);
    color: #FFD700;
}
.swcard-status-pill.status-launching {
    background: rgba(96, 165, 250, 0.15);
    border-color: rgba(96, 165, 250, 0.35);
    color: #60A5FA;
}
.swcard-status-pill.status-over {
    background: rgba(120, 113, 108, 0.18);
    border-color: rgba(120, 113, 108, 0.35);
    color: #A8A29E;
}
.swcard-status-pill.status-dev {
    background: rgba(251, 146, 60, 0.18);
    border-color: rgba(251, 146, 60, 0.4);
    color: #FB923C;
}

/* ─── swcard variants for non-live states ─────────────────────────────── */
.swcard.launching {
    background: linear-gradient(145deg, rgba(8, 14, 28, 0.96) 0%, rgba(4, 8, 18, 0.99) 100%);
    border: 1px solid rgba(96, 165, 250, 0.3);
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(96, 165, 250, 0.08);
}
.swcard.launching .swcard-top-line {
    background: linear-gradient(90deg, transparent, rgba(96, 165, 250, 0.6), transparent);
}
.swcard.launching:hover { border-color: rgba(96, 165, 250, 0.55); }

.swcard.over {
    background: linear-gradient(145deg, rgba(14, 12, 10, 0.92) 0%, rgba(8, 7, 6, 0.96) 100%);
    border: 1px solid rgba(120, 113, 108, 0.28);
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.45);
    opacity: 0.78;
}
.swcard.over .swcard-top-line {
    background: linear-gradient(90deg, transparent, rgba(168, 162, 158, 0.4), transparent);
}
.swcard.over .swcard-name {
    color: rgba(190, 180, 165, 0.7);
    background: none;
    -webkit-text-fill-color: rgba(190, 180, 165, 0.7);
}

.swcard.dev {
    background: linear-gradient(145deg, rgba(28, 20, 8, 0.96) 0%, rgba(18, 12, 4, 0.99) 100%);
    border: 1px solid rgba(251, 146, 60, 0.32);
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(251, 146, 60, 0.1);
}
.swcard.dev .swcard-top-line {
    background: linear-gradient(90deg, transparent, rgba(251, 146, 60, 0.6), transparent);
}
.swcard.dev:hover { border-color: rgba(251, 146, 60, 0.5); }

/* ─── Registration-closed pill (live world, no new signups) ───────────── */
.swcard-closed-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    margin-top: 0.5rem;
    padding: 0.25rem 0.625rem;
    border-radius: var(--radius-full);
    font-family: var(--font-display);
    font-size: 0.6875rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.16em;
    background: rgba(var(--gold-rgb), 0.06);
    color: rgba(var(--gold-rgb), 0.8);
    border: 1px solid rgba(var(--gold-rgb), 0.2);
    cursor: help;
}
.swcard.prime .swcard-closed-pill {
    background: rgba(255, 215, 0, 0.08);
    color: rgba(255, 215, 0, 0.75);
    border-color: rgba(255, 215, 0, 0.3);
}

/* ─────────────────────────────────────────────────────────────────────────
   NEWS WIDGET (Patch amber + Announcement purple)
   ───────────────────────────────────────────────────────────────────────── */
.nwidget-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1rem;
}
@media (min-width: 768px) { .nwidget-grid { grid-template-columns: repeat(2, 1fr); } }

.ncard {
    position: relative;
    display: block;
    border-radius: 0.75rem;
    overflow: hidden;
    text-align: right;
    text-decoration: none;
    background: linear-gradient(145deg, rgba(18, 13, 6, 0.92) 0%, rgba(10, 7, 3, 0.96) 100%);
    border: 1px solid rgba(245, 158, 11, 0.22);
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.45), inset 0 1px 0 rgba(245, 158, 11, 0.08);
    transition: border-color var(--dur-base), box-shadow var(--dur-base);
}
.ncard:hover { border-color: rgba(245, 158, 11, 0.45); }
.ncard.announce {
    background: linear-gradient(145deg, rgba(14, 10, 20, 0.92) 0%, rgba(8, 6, 14, 0.96) 100%);
    border-color: rgba(139, 92, 246, 0.22);
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.45), inset 0 1px 0 rgba(139, 92, 246, 0.08);
}
.ncard.announce:hover { border-color: rgba(139, 92, 246, 0.45); }

.ncard-top-line {
    position: absolute; top: 0; inset-inline: 0; height: 2px;
    background: linear-gradient(90deg, transparent, rgba(245, 158, 11, 0.6), transparent);
}
.ncard.announce .ncard-top-line { background: linear-gradient(90deg, transparent, rgba(139, 92, 246, 0.6), transparent); }

.ncard-body { padding: 1.25rem; }

.ncard-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.75rem; }
.ncard-head .label-row { display: inline-flex; align-items: center; gap: 0.5rem; }
.ncard-icon {
    width: 1.5rem; height: 1.5rem;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 0.375rem;
    background: rgba(245, 158, 11, 0.15);
    border: 1px solid rgba(245, 158, 11, 0.3);
    color: #F59E0B;
}
.ncard.announce .ncard-icon {
    background: rgba(139, 92, 246, 0.15);
    border-color: rgba(139, 92, 246, 0.3);
    color: #8B5CF6;
}
.ncard-label {
    font-family: var(--font-display);
    font-size: 0.8125rem;
    font-weight: 900;
    text-transform: uppercase;
    letter-spacing: 0.2em;
    color: rgba(245, 158, 11, 0.85);
}
.ncard.announce .ncard-label { color: rgba(160, 120, 250, 0.9); }

.ncard-tag {
    font-size: 0.8125rem;
    font-weight: 700;
    padding: 0.125rem 0.5rem;
    border-radius: 9999px;
    background: rgba(52, 211, 153, 0.12);
    color: #34D399;
    border: 1px solid rgba(52, 211, 153, 0.25);
}
.ncard.announce .ncard-tag {
    background: rgba(139, 92, 246, 0.12);
    color: #A78BFA;
    border-color: rgba(139, 92, 246, 0.25);
}

.ncard-version {
    font-family: var(--font-display);
    font-size: 1.125rem;
    font-weight: 900;
    color: #F4D97E;
}
.ncard.announce .ncard-version { color: #C4B5FD; }
.ncard-title-sub {
    font-size: 0.8125rem;
    line-height: 1.35;
    margin-top: 0.125rem;
    color: rgba(210, 188, 138, 0.9);
}
.ncard.announce .ncard-title-sub { color: rgba(196, 182, 232, 0.88); }

.ncard-items {
    list-style: none;
    margin: 0.75rem 0 1rem;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.375rem;
}
.ncard-item {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    font-size: 0.8125rem;
    color: rgba(198, 174, 122, 0.85);
}
.ncard.announce .ncard-item { color: rgba(186, 172, 224, 0.82); }
.ncard-item::before {
    content: '';
    margin-top: 0.375rem;
    width: 0.25rem; height: 0.25rem;
    border-radius: 50%;
    background: rgba(245, 158, 11, 0.5);
    flex-shrink: 0;
}
.ncard.announce .ncard-item::before { background: rgba(139, 92, 246, 0.5); }

.ncard-foot {
    display: flex; justify-content: space-between; align-items: center;
    padding-top: 0.75rem;
    border-top: 1px solid rgba(245, 158, 11, 0.1);
    font-size: 0.8125rem;
}
.ncard.announce .ncard-foot { border-top-color: rgba(139, 92, 246, 0.1); }
.ncard-date { color: rgba(168, 140, 84, 0.8); }
.ncard.announce .ncard-date { color: rgba(148, 128, 196, 0.8); }
.ncard-link {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    font-weight: 600;
    color: rgba(245, 158, 11, 0.85);
}
.ncard.announce .ncard-link { color: rgba(160, 120, 250, 0.85); }

/* ─────────────────────────────────────────────────────────────────────────
   EXPLORE MORE cards
   ───────────────────────────────────────────────────────────────────────── */
.explore-grid { display: grid; grid-template-columns: 1fr; gap: 1rem; }
@media (min-width: 768px) { .explore-grid { grid-template-columns: repeat(3, 1fr); } }

.explore-card {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    padding: 1.25rem;
    border-radius: 0.75rem;
    overflow: hidden;
    text-decoration: none;
    background: linear-gradient(105deg, rgba(20, 15, 8, 0.92) 0%, rgba(12, 9, 5, 0.96) 100%);
    box-shadow: 0 2px 20px rgba(0, 0, 0, 0.35);
    transition: transform var(--dur-base) var(--ease-out);
}
.explore-card:hover { transform: translateY(-2px) scale(1.02); }
.explore-card[data-c="discord"] { border: 1px solid rgba(114, 137, 218, 0.22); box-shadow: 0 2px 20px rgba(0,0,0,0.35), inset 0 1px 0 rgba(114, 137, 218, 0.1); }
.explore-card[data-c="manual"]  { border: 1px solid rgba(52, 211, 153, 0.22); box-shadow: 0 2px 20px rgba(0,0,0,0.35), inset 0 1px 0 rgba(52, 211, 153, 0.1); }
.explore-card[data-c="sd"]      { border: 1px solid rgba(96, 165, 250, 0.22); box-shadow: 0 2px 20px rgba(0,0,0,0.35), inset 0 1px 0 rgba(96, 165, 250, 0.1); }

.explore-card-accent {
    position: absolute;
    right: 0; top: 0.5rem; bottom: 0.5rem;
    width: 3px;
    border-radius: 9999px;
}
.explore-card[data-c="discord"] .explore-card-accent { background: linear-gradient(180deg, rgba(114, 137, 218, 0.9), rgba(114, 137, 218, 0.4)); }
.explore-card[data-c="manual"]  .explore-card-accent { background: linear-gradient(180deg, rgba(52, 211, 153, 0.9), rgba(52, 211, 153, 0.4)); }
.explore-card[data-c="sd"]      .explore-card-accent { background: linear-gradient(180deg, rgba(96, 165, 250, 0.9), rgba(96, 165, 250, 0.4)); }

.explore-card-head { display: flex; align-items: center; gap: 0.75rem; }
.explore-card-icon {
    width: 2.5rem; height: 2.5rem;
    border-radius: 0.5rem;
    display: inline-flex; align-items: center; justify-content: center;
    flex-shrink: 0;
}
.explore-card[data-c="discord"] .explore-card-icon { background: linear-gradient(135deg, rgba(114, 137, 218, 0.18), rgba(114, 137, 218, 0.08)); border: 1px solid rgba(114, 137, 218, 0.35); color: #7289DA; box-shadow: 0 0 16px rgba(114, 137, 218, 0.18); }
.explore-card[data-c="manual"]  .explore-card-icon { background: linear-gradient(135deg, rgba(52, 211, 153, 0.18), rgba(52, 211, 153, 0.08)); border: 1px solid rgba(52, 211, 153, 0.35); color: #34D399; box-shadow: 0 0 16px rgba(52, 211, 153, 0.18); }
.explore-card[data-c="sd"]      .explore-card-icon { background: linear-gradient(135deg, rgba(96, 165, 250, 0.18), rgba(96, 165, 250, 0.08)); border: 1px solid rgba(96, 165, 250, 0.35); color: #60A5FA; box-shadow: 0 0 16px rgba(96, 165, 250, 0.18); }

.explore-card-title {
    font-family: var(--font-display);
    font-size: 0.875rem;
    font-weight: 700;
}
.explore-card[data-c="discord"] .explore-card-title { color: #7289DA; }
.explore-card[data-c="manual"]  .explore-card-title { color: #34D399; }
.explore-card[data-c="sd"]      .explore-card-title { color: #60A5FA; }

.explore-card-arrow {
    margin-right: auto;
    color: currentColor;
    opacity: 0.3;
    flex-shrink: 0;
    transition: opacity var(--dur-base), transform var(--dur-base);
}
.explore-card:hover .explore-card-arrow { opacity: 0.8; transform: translateX(-4px); }

.explore-card-desc {
    font-size: 0.8125rem;
    line-height: 1.5;
    color: rgba(170, 155, 120, 0.75);
}

/* ─────────────────────────────────────────────────────────────────────────
   GAME GALLERY slider
   ───────────────────────────────────────────────────────────────────────── */
.gallery-feature {
    position: relative;
    border-radius: 1rem;
    overflow: hidden;
    cursor: pointer;
    background: linear-gradient(170deg, rgba(20, 15, 8, 0.9) 0%, rgba(10, 8, 4, 0.95) 100%);
    border: 2px solid rgba(var(--gold-rgb), 0.3);
    box-shadow: 0 0 60px rgba(var(--gold-rgb), 0.1), 0 20px 60px rgba(0, 0, 0, 0.5);
}
.gallery-feature-shimmer {
    position: absolute; top: 0; inset-inline: 0; height: 2px; z-index: 10;
    background: linear-gradient(90deg, transparent 0%, #C8962E 20%, #FFD700 40%, #FFF8DC 50%, #FFD700 60%, #C8962E 80%, transparent 100%);
}
.gallery-feature-frame {
    aspect-ratio: 16 / 9;
    position: relative;
    background: #0a0703;
}
.gallery-feature-frame img {
    /* All slides are stacked in the SAME box (absolute + inset:0) so the
       Alpine opacity crossfade happens in place. Without this, two images
       are briefly in normal flow during the transition and stack
       vertically — showing a sliver of the next slide. */
    position: absolute;
    inset: 0;
    width: 100%; height: 100%;
    object-fit: cover;
    display: block;
}
.gallery-feature-overlay {
    position: absolute; inset: 0;
    pointer-events: none;
    background: radial-gradient(ellipse at center, transparent 40%, rgba(0, 0, 0, 0.4) 100%);
}
.gallery-feature-caption {
    position: absolute; bottom: 0; right: 0; left: 0;
    padding: 1.5rem 2rem;
    background: linear-gradient(0deg, rgba(0, 0, 0, 0.95) 0%, rgba(0, 0, 0, 0.7) 50%, transparent 100%);
}
.gallery-feature-title {
    font-family: var(--font-display);
    font-size: 1.25rem;
    font-weight: 700;
    color: #F4E287;
    margin-bottom: 0.5rem;
}
@media (min-width: 768px) { .gallery-feature-title { font-size: 1.5rem; } }
.gallery-feature-desc {
    font-size: 0.875rem;
    color: rgba(200, 180, 140, 0.8);
    max-width: 36rem;
}

.gallery-arrow {
    position: absolute;
    top: 50%; transform: translateY(-50%);
    width: 2.5rem; height: 2.5rem;
    border-radius: 50%;
    display: inline-flex; align-items: center; justify-content: center;
    background: rgba(0, 0, 0, 0.7);
    border: 1px solid rgba(var(--gold-rgb), 0.4);
    color: var(--gold-400);
    backdrop-filter: blur(8px);
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4);
    cursor: pointer;
    transition: transform var(--dur-base);
}
.gallery-arrow:hover { transform: translateY(-50%) scale(1.15); background: rgba(var(--gold-rgb), 0.2); }
.gallery-arrow.left { right: 1rem; }
.gallery-arrow.right { left: 1rem; }

.gallery-thumbs {
    position: relative;
    margin-top: 1.5rem;
    display: flex;
    gap: 0.75rem;
    overflow-x: auto;
    padding-bottom: 0.75rem;
}
.gallery-thumbs::-webkit-scrollbar { display: none; }

.gallery-thumb {
    position: relative;
    flex-shrink: 0;
    border-radius: 0.75rem;
    overflow: hidden;
    cursor: pointer;
    width: clamp(140px, 18vw, 200px);
    aspect-ratio: 16 / 10;
    border: 1px solid rgba(var(--gold-rgb), 0.2);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
    opacity: 0.7;
    transition: all var(--dur-base) var(--ease-out);
}
.gallery-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.gallery-thumb:hover { opacity: 1; transform: translateY(-4px) scale(1.05); }
.gallery-thumb.active {
    opacity: 1;
    border: 2px solid rgba(var(--gold-rgb), 0.8);
    box-shadow: 0 0 25px rgba(var(--gold-rgb), 0.35), 0 4px 16px rgba(0, 0, 0, 0.4);
    transform: scale(1.02);
}
.gallery-thumb-caption {
    position: absolute; bottom: 0; right: 0; left: 0;
    padding: 0.5rem 0.625rem;
    background: linear-gradient(0deg, rgba(0, 0, 0, 0.95) 0%, rgba(0, 0, 0, 0.7) 70%, transparent 100%);
}
.gallery-thumb-label {
    font-family: var(--font-display);
    font-size: 0.8125rem;
    font-weight: 600;
    color: rgba(220, 200, 160, 0.9);
}
.gallery-thumb.active .gallery-thumb-label { color: #F4E287; }
.gallery-thumb-active-dot {
    position: absolute; top: 0.5rem; left: 0.5rem;
    width: 0.5rem; height: 0.5rem;
    border-radius: 50%;
    background: var(--gold-400);
    box-shadow: 0 0 8px var(--gold-400);
}
.gallery-feature-frame { cursor: zoom-in; }

/* ─────────────────────────────────────────────────────────────────────────
   GALLERY LIGHTBOX — fullscreen view, teleported to <body>
   ───────────────────────────────────────────────────────────────────────── */
.gallery-lightbox {
    position: fixed;
    inset: 0;
    z-index: 1000;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 1rem;
    padding: 2rem;
    background: rgba(0, 0, 0, 0.93);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
}
.gallery-lightbox-figure {
    margin: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
    max-width: 92vw;
}
.gallery-lightbox-img {
    max-width: 92vw;
    max-height: 80vh;
    object-fit: contain;
    border: 2px solid rgba(var(--gold-rgb), 0.4);
    border-radius: 0.5rem;
    box-shadow: 0 0 80px rgba(0, 0, 0, 0.9);
}
.gallery-lightbox-caption {
    text-align: center;
    max-width: 42rem;
}
.gallery-lightbox-title {
    display: block;
    font-family: var(--font-display);
    font-size: 1.25rem;
    font-weight: 700;
    color: #F4E287;
    margin-bottom: 0.25rem;
}
.gallery-lightbox-desc {
    display: block;
    font-size: 0.875rem;
    color: rgba(200, 180, 140, 0.85);
}
.gallery-lightbox-close {
    position: absolute;
    top: 1.5rem; left: 1.5rem;
    width: 2.75rem; height: 2.75rem;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.6);
    border: 1px solid rgba(var(--gold-rgb), 0.4);
    color: rgba(var(--gold-rgb), 0.9);
    cursor: pointer;
    transition: background 200ms var(--ease-out), color 200ms var(--ease-out);
}
.gallery-lightbox-close:hover {
    background: rgba(var(--gold-rgb), 0.2);
    color: #FFF8DC;
}
.gallery-lightbox-nav {
    flex-shrink: 0;
    width: 3rem; height: 3rem;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.6);
    border: 1px solid rgba(var(--gold-rgb), 0.4);
    color: rgba(var(--gold-rgb), 0.9);
    cursor: pointer;
    transition: background 200ms var(--ease-out), color 200ms var(--ease-out);
}
.gallery-lightbox-nav:hover {
    background: rgba(var(--gold-rgb), 0.2);
    color: #FFF8DC;
}
@media (max-width: 640px) {
    .gallery-lightbox { padding: 1rem; gap: 0.35rem; }
    .gallery-lightbox-nav { width: 2.25rem; height: 2.25rem; }
    .gallery-lightbox-img { max-height: 68vh; }
    .gallery-lightbox-close { top: 0.75rem; left: 0.75rem; }
}

/* JourneyModal styles have moved to assets/css/journey-modal.css (V0-faithful
 * rewrite). This file used to also carry .journey-* / .auth-* / .tribe-grid /
 * .pos-grid / .tribe-opt / .pos-opt — all deleted to avoid cascade conflicts
 * with the new partial. */

/* ============================================================================
   A NEW ERA BEGINS — two-column band  (v0 prototype port)
   ----------------------------------------------------------------------------
   Was a centred, gold-framed box with four corner marks. Now an open band: the
   village art on one side, the copy on the other, each sliding in from its own
   edge when the band first reaches the viewport.

   Type sizes and text colours are deliberately UNCHANGED from the previous
   design — only the layout, alignment and motion come from the prototype. The
   prototype's own contrast was not used as a reference.
   ========================================================================== */

.legacy-band {
    max-width: 78rem;
    margin: 0 auto;
    padding: 4rem 1.5rem 1.5rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2.5rem;
}
@media (min-width: 900px) {
    .legacy-band {
        flex-direction: row;
        align-items: center;
        gap: 0;
        padding: 5rem 2.5rem 2rem;
    }
}

/* ─── Art column ─────────────────────────────────────────────────────────── */
.legacy-art {
    position: relative;
    flex: 0 0 auto;
    width: min(100%, 27rem);
    display: flex;
    align-items: center;
    justify-content: center;
}
@media (min-width: 900px) { .legacy-art { width: 45%; } }

.legacy-art img {
    position: relative;
    z-index: 1;
    width: 100%;
    height: auto;
    /* The artwork is a round vignette on transparent/dark; a drop-shadow (not a
       box-shadow) follows the drawing's own silhouette rather than its bounding
       box, so the glow hugs the village instead of framing a square. */
    filter: drop-shadow(0 24px 60px rgba(0, 0, 0, 0.65));
}

/* Warm bloom behind the art, echoing the panel accent language used elsewhere. */
.legacy-art-glow {
    position: absolute;
    inset: 8% 8% 4%;
    border-radius: 50%;
    background: radial-gradient(circle at 50% 45%,
        rgba(var(--gold-rgb), 0.20) 0%,
        rgba(var(--gold-rgb), 0.07) 45%,
        transparent 72%);
    filter: blur(6px);
    pointer-events: none;
}

/* ─── Copy column ────────────────────────────────────────────────────────── */
.legacy-copy {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: center;      /* stacked layout stays centred */
    text-align: center;
}
@media (min-width: 900px) {
    .legacy-copy {
        align-items: flex-start;
        text-align: right;
        padding-right: 3.5rem;
    }
    /* The shared rules below centre these; the two-column layout wants them
       ranged left, so they are re-aligned here rather than edited in place —
       the stacked layout still uses the centred originals. */
    .legacy-copy .legacy-title  { text-align: right; }
    .legacy-copy .legacy-quote  { margin-inline: 0; text-align: right; }
    .legacy-copy .legacy-pills  { justify-content: flex-start; }
    .legacy-copy .legacy-divider { justify-content: flex-start; }
}

/* Without artwork the band collapses to the single centred column it replaced.
   ⚠ The inner elements have to be re-centred too. The two-column rules above range
   the title, quote, divider and pills to the LEFT and are equally specific, so
   centring only the container leaves its contents hanging off to one side. */
.legacy-band.is-artless .legacy-copy {
    align-items: center;
    text-align: center;
    padding-right: 0;
    max-width: 64rem;
    margin-inline: auto;
}
.legacy-band.is-artless .legacy-copy .legacy-title   { text-align: center; }
.legacy-band.is-artless .legacy-copy .legacy-quote   { text-align: center; margin-inline: auto; }
.legacy-band.is-artless .legacy-copy .legacy-pills   { justify-content: center; }
.legacy-band.is-artless .legacy-copy .legacy-divider { justify-content: center; }

/* ─── Entrance ───────────────────────────────────────────────────────────── */
/*
 * The two halves arrive from opposite edges, the copy trailing the art so they
 * read as one gesture rather than two independent slides.
 *
 * Timing note: the first pass ran 0.7s/0.9s over 3rem and was reported as barely
 * noticeable. Both dials mattered — a short travel finishes before the eye has
 * anywhere to follow it, no matter how long the duration says it is. The distance
 * is now 6rem with a 1.5s transform, and the ease is a long decelerating curve so
 * most of that time is spent in the visible part of the movement rather than in a
 * fast start nobody sees.
 *
 * Opacity resolves faster than the transform (0.9s vs 1.5s): the content becomes
 * readable early and then settles into place, instead of the text being unreadable
 * for the whole slide.
 *
 * .is-revealed is toggled, not latched — see the reveal() note in
 * assets/js/scroll-activate.js. Leaving the viewport resets it so the entrance
 * plays again on the way back.
 */
.has-reveal .legacy-art,
.has-reveal .legacy-copy {
    opacity: 0;
    transition: opacity 0.9s cubic-bezier(0.22, 0.61, 0.36, 1),
                transform 1.5s cubic-bezier(0.16, 0.84, 0.28, 1);
    will-change: transform, opacity;
}
.has-reveal .legacy-art  { transform: translate3d(-6rem, 0, 0); }
.has-reveal .legacy-copy { transform: translate3d(6rem, 0, 0); transition-delay: 0.14s; }

.has-reveal .legacy-art.is-revealed,
.has-reveal .legacy-copy.is-revealed { opacity: 1; transform: none; }

/*
 * ⚠ The start state above HIDES this content, so anything that stops the reveal
 * from running would leave the section blank. The JS covers the two cases it can
 * detect (no IntersectionObserver, reduced-motion) by adding .is-revealed
 * immediately; this block covers the third — CSS loaded, JS did not.
 */
@media (prefers-reduced-motion: reduce) {
    .legacy-art,
    .legacy-copy { opacity: 1; transform: none; transition: none; }
}

/* ─── Ground under the band ──────────────────────────────────────────────── */
/*
 * The section sat directly on the page's fixed atmosphere image, so it read as
 * floating rather than as its own chapter. This lays a darker plate under it.
 *
 * Full-bleed WITHOUT 100vw arithmetic: this is a plain block child of <main>, so
 * it is already the full content width, and the gradients simply run to its own
 * edges. `100vw` would have been a horizontal-scroll bug waiting for the first
 * visitor with a classic scrollbar, since 100vw counts the scrollbar and the
 * container does not.
 *
 * Soft-edged on purpose: hard top and bottom lines would cut the fixed background
 * into visible strips. The dark fades in and out, so the band reads as a pool of
 * shadow the content sits in rather than a box laid over the page.
 */
.legacy-backdrop {
    position: relative;
    isolation: isolate;
}
/* replaced by the shared .section-band plate */
.legacy-backdrop--legacy-plate-removed {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background:
        /* warm centre lift, so the art is not sitting in flat black */
        radial-gradient(120% 78% at 50% 46%,
            rgba(28, 20, 9, 0.55) 0%,
            rgba(12, 9, 4, 0.72) 42%,
            rgba(6, 4, 2, 0.80) 68%,
            rgba(6, 4, 2, 0) 100%),
        /* vertical fade so neither edge lands as a seam */
        linear-gradient(to bottom,
            rgba(4, 3, 1, 0) 0%,
            rgba(4, 3, 1, 0.55) 14%,
            rgba(4, 3, 1, 0.68) 50%,
            rgba(4, 3, 1, 0.55) 86%,
            rgba(4, 3, 1, 0) 100%);
}

/* Hairlines that fade out at the ends, matching the divider language used
   elsewhere on the page. Kept very low contrast — they mark the edge, they are
   not meant to be seen as lines. */
.legacy-backdrop::after {
    content: '';
    position: absolute;
    inset-inline: 0;
    top: 0;
    height: 1px;
    z-index: -1;
    pointer-events: none;
    background: linear-gradient(90deg,
        transparent 0%,
        rgba(var(--gold-rgb), 0.16) 28%,
        rgba(var(--gold-rgb), 0.26) 50%,
        rgba(var(--gold-rgb), 0.16) 72%,
        transparent 100%);
}

/* ============================================================================
   GAME WORLDS — two-column band  (v0 prototype port)
   ----------------------------------------------------------------------------
   Was two stacked, centred widgets (realm cards, then Latest Updates), each under
   a horizontal divider label. Now one band: all the text on the left, the world
   map on the right.

   Slide direction is the mirror of the band above — content from the left, art
   from the right — so scrolling the page alternates instead of repeating.
   ========================================================================== */

.worlds-backdrop { position: relative; isolation: isolate; }

/* Same soft-edged plate as the Legacy band, flipped so the warm lift sits under
   the map rather than dead centre. */
/* replaced by the shared .section-band plate */
.worlds-backdrop--legacy-plate-removed {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background:
        radial-gradient(105% 72% at 28% 44%,
            rgba(26, 19, 9, 0.50) 0%,
            rgba(12, 9, 4, 0.68) 44%,
            rgba(6, 4, 2, 0.78) 70%,
            rgba(6, 4, 2, 0) 100%),
        linear-gradient(to bottom,
            rgba(4, 3, 1, 0) 0%,
            rgba(4, 3, 1, 0.50) 12%,
            rgba(4, 3, 1, 0.64) 50%,
            rgba(4, 3, 1, 0.50) 88%,
            rgba(4, 3, 1, 0) 100%);
}

.worlds-band {
    max-width: 82rem;
    margin: 0 auto;
    padding: 3.5rem 1.5rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2.5rem;
}
@media (min-width: 1000px) {
    .worlds-band {
        flex-direction: row;
        align-items: center;
        gap: 3rem;
        padding: 4.5rem 2.5rem;
    }
}

.worlds-main { flex: 1 1 auto; min-width: 0; width: 100%; }
@media (min-width: 1000px) { .worlds-main { width: auto; } }

/* ─── Heading block ──────────────────────────────────────────────────────── */
/* Replaces the centred `.section-divider` label. Ranged left on the wide layout,
   centred when the band stacks, matching how the Legacy band behaves. */
.worlds-head { margin-bottom: 1.5rem; text-align: center; }
@media (min-width: 1000px) { .worlds-head { text-align: right; } }

.worlds-eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 0.55rem;
    margin-bottom: 0.5rem;
}
.worlds-eyebrow-line {
    width: 1.6rem;
    height: 1px;
    background: linear-gradient(90deg, transparent, rgba(var(--gold-rgb), 0.7));
}
.worlds-eyebrow-text {
    font-family: var(--font-display);
    font-size: 0.8125rem;          /* the existing eyebrow size on this page */
    font-weight: 900;
    text-transform: uppercase;
    letter-spacing: 0.3em;
    color: rgba(var(--gold-rgb), 0.85);
}

/* Same gradient and sizes as .legacy-title, so the two bands share one voice. */
.worlds-title {
    font-family: var(--font-display);
    font-size: 1.5rem;
    font-weight: 900;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    margin: 0 0 0.375rem;
    background: linear-gradient(180deg, #FFFFFF 0%, #FFF8DC 20%, #FFD700 45%, var(--gold-400) 70%, #9A7515 100%);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
}
@media (min-width: 768px)  { .worlds-title { font-size: 2.25rem; } }
@media (min-width: 1024px) { .worlds-title { font-size: 3rem; } }

.worlds-subtitle {
    margin: 0;
    font-size: 0.9375rem;
    line-height: 1.6;
    color: rgba(210, 190, 145, 0.85);
}

/* ─── Realm cards as rows ────────────────────────────────────────────────── */
/*
 * CSS-only re-layout of the SAME card markup. The component keeps its vertical
 * form everywhere else; this modifier turns it on its side for the band.
 */
.swidget-grid.is-rows {
    display: flex;
    flex-direction: column;
    gap: 0.625rem;
}
.swidget-grid.is-rows > .swcard { flex: 0 0 auto; max-width: none; width: 100%; }

@media (min-width: 640px) {
    .swidget-grid.is-rows .swcard-body {
        display: flex;
        align-items: center;
        gap: 1.25rem;
        padding: 0.875rem 1rem;
    }
    /* head becomes the name block and stops reserving space below itself */
    .swidget-grid.is-rows .swcard-head {
        flex: 1 1 auto;
        min-width: 0;
        display: block;
        margin-bottom: 0;
    }
    .swidget-grid.is-rows .swcard-status { margin-top: 0.2rem; }
    /* the rule under the head only makes sense in the stacked form */
    .swidget-grid.is-rows .swcard-divider { display: none; }

    .swidget-grid.is-rows .swcard-stats {
        flex: 0 0 auto;
        display: flex;
        gap: 1.25rem;
        margin-bottom: 0;
    }
    /* In a row the boxed stat tiles read as three buttons competing with the card
       itself, so the chrome comes off and the numbers carry it. */
    .swidget-grid.is-rows .swcard-stat {
        background: none;
        border: 0;
        padding: 0;
        min-width: 3.5rem;
    }

    .swidget-grid.is-rows .swcard-foot {
        flex: 0 0 auto;
        display: flex;
        align-items: center;
        gap: 0.5rem;
    }
    /* The phase text is already the card's status pill in this layout. */
    .swidget-grid.is-rows .swcard-phase { display: none; }
    .swidget-grid.is-rows .swcard-closed-pill { display: none; }
}

/* ─── Latest Updates ─────────────────────────────────────────────────────── */
.worlds-updates { margin-top: 1.75rem; }
.worlds-updates-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 0.75rem;
}
.worlds-updates-all {
    display: inline-flex;
    align-items: center;
    /* 20px of text was the whole target; padding-block lifts it to ~32px
       (~44px on touch) without shifting the label. */
    padding-block: 0.375rem;
    gap: 0.3rem;
    font-size: 0.8125rem;
    color: rgba(var(--gold-rgb), 0.85);
    text-decoration: none;
    white-space: nowrap;
    transition: color 0.18s ease;
}
.worlds-updates-all:hover { color: #F4E287; }

/* ─── Map column ─────────────────────────────────────────────────────────── */
.worlds-art {
    position: relative;
    flex: 0 0 auto;
    width: min(100%, 26rem);
    display: flex;
    align-items: center;
    justify-content: center;
}
@media (min-width: 1000px) { .worlds-art { width: 40%; max-width: 30rem; } }

.worlds-art img {
    position: relative;
    z-index: 1;
    width: 100%;
    height: auto;
    filter: drop-shadow(0 24px 60px rgba(0, 0, 0, 0.7));
}
.worlds-art-glow {
    position: absolute;
    inset: 10%;
    border-radius: 50%;
    background: radial-gradient(circle at 50% 45%,
        rgba(var(--gold-rgb), 0.18) 0%,
        rgba(var(--gold-rgb), 0.06) 48%,
        transparent 72%);
    filter: blur(8px);
    pointer-events: none;
}

/* ─── Entrance ───────────────────────────────────────────────────────────── */
/* Mirror of the Legacy band: content from the left, art from the right. Same
   durations and curve so the two sections feel like one system. */
.has-reveal .worlds-main,
.has-reveal .worlds-art {
    opacity: 0;
    transition: opacity 0.9s cubic-bezier(0.22, 0.61, 0.36, 1),
                transform 1.5s cubic-bezier(0.16, 0.84, 0.28, 1);
    will-change: transform, opacity;
}
.has-reveal .worlds-main { transform: translate3d(-6rem, 0, 0); }
.has-reveal .worlds-art  { transform: translate3d(6rem, 0, 0); transition-delay: 0.14s; }

.has-reveal .worlds-main.is-revealed,
.has-reveal .worlds-art.is-revealed { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
    .worlds-main, .worlds-art { opacity: 1; transform: none; transition: none; }
}

/* Stacked layout: the map leads the section rather than trailing it.
   In source order it comes last (it is the right-hand column on desktop), so
   without this it lands BELOW the news cards — 1,200px down, long after the
   content it is meant to illustrate, reading as a stray image rather than as
   part of the band. Ordering it first also matches the Legacy band above, where
   the artwork naturally leads on narrow screens. */
@media (max-width: 999px) {
    .worlds-band { flex-direction: column; }
    .worlds-art  { order: -1; }
}

/* ============================================================================
   HALL OF FAME — three-column band  (v0 prototype port)
   ----------------------------------------------------------------------------
   Was a full-width champion banner with the three boards in a row underneath,
   introduced by a centred divider label. Now: champion left, trophy and title
   centre, the round's boards right.
   ========================================================================== */

.hof-backdrop {
    position: relative;
    isolation: isolate;
    --band-a1: 0.74;
    --band-a2: 0.87;
    --band-a3: 0.94;
}
/* replaced by the shared .section-band plate */
.hof-backdrop--legacy-plate-removed {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    /* Centred lift here, unlike the two bands above — the trophy is the middle
       column, so the light belongs behind it rather than off to one side. */
    background:
        radial-gradient(85% 68% at 50% 42%,
            rgba(34, 25, 10, 0.58) 0%,
            rgba(14, 10, 5, 0.72) 46%,
            rgba(6, 4, 2, 0.80) 72%,
            rgba(6, 4, 2, 0) 100%),
        linear-gradient(to bottom,
            rgba(4, 3, 1, 0) 0%,
            rgba(4, 3, 1, 0.55) 12%,
            rgba(4, 3, 1, 0.70) 50%,
            rgba(4, 3, 1, 0.55) 88%,
            rgba(4, 3, 1, 0) 100%);
}

.hof-band {
    max-width: 84rem;
    margin: 0 auto;
    padding: 3.5rem 1.5rem;
    display: flex;
    flex-direction: column;
    gap: 2.5rem;
}
.hof-row {
    display: flex;
    flex-direction: column;
    gap: 2.5rem;
}
@media (min-width: 1100px) {
    .hof-band { padding: 4.5rem 2.5rem; gap: 2.75rem; }
    /*
     * flex-start, not center: the two round labels are the first line of
     * their own columns, so they only sit on one line together if the
     * columns share a top edge. Their matching min-height below does the
     * rest.
     */
    .hof-row { flex-direction: row; align-items: flex-start; gap: 2.5rem; }
    .hof-champion { flex: 1 1 0; min-width: 0; }
    /* The art no longer carries the title, so the middle column gives its
       spare width back to the two side columns. That is what keeps the
       champion's label on one line beside its date. */
    .hof-centre   { flex: 0 0 auto; width: 30%; max-width: 24rem; }
    .hof-boards   { flex: 1 1 0; min-width: 0; }
}

/* The two round labels share a row: same reserved height, same gap under. */
.hof-champ-head,
.hof-boards-label {
    min-height: 2.1rem;
    margin-bottom: 1.1rem;
}

/* ─── Centre column ──────────────────────────────────────────────────────── */
.hof-head { text-align: center; display: flex; flex-direction: column; align-items: center; }
.hof-head .worlds-eyebrow { justify-content: center; }
.hof-centre { display: flex; flex-direction: column; align-items: center; }
.hof-eyebrow-glyph {
    display: inline-flex;
    color: rgba(var(--gold-rgb), 0.85);
    filter: drop-shadow(0 0 6px rgba(255, 215, 0, 0.3));
}
/* the eyebrow rule is directional; the centre column wants one on each side */
.worlds-eyebrow-line.is-flipped {
    background: linear-gradient(90deg, rgba(var(--gold-rgb), 0.7), transparent);
}

.hof-title {
    font-family: var(--font-display);
    font-size: 1.5rem;
    font-weight: 900;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    margin: 0 0 0.5rem;
    background: linear-gradient(180deg, #FFFFFF 0%, #FFF8DC 20%, #FFD700 45%, var(--gold-400) 70%, #9A7515 100%);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
}
@media (min-width: 768px)  { .hof-title { font-size: 2.25rem; } }
@media (min-width: 1024px) { .hof-title { font-size: 3rem; } }

.hof-subtitle {
    margin: 0 0 1.25rem;
    font-size: 0.9375rem;
    line-height: 1.6;
    color: rgba(210, 190, 145, 0.85);
}

/* The art is portrait and already carries its own depth and firelight, so
   it runs wider than the old square cup did and drops the drop-shadow: a
   shadow traced around a soft alpha edge only muddies it, and it is an
   expensive filter over an image this size. */
/* The art carries transparent headroom above the crest so its top edge can
   fade instead of cutting; the negative margin reclaims most of that empty
   strip so the helm does not drift down the column. */
.hof-trophy { position: relative; width: min(100%, 24rem); margin-top: -2.5rem; }
.hof-trophy img {
    position: relative;
    z-index: 1;
    width: 100%;
    height: auto;
}
/* Sits low and warm, under the battle rather than behind the helm, so it
   reads as the glow of the fires carrying past the faded edge of the art
   instead of a gold disc showing through it. */
.hof-trophy-glow {
    position: absolute;
    inset: 30% 4% 6%;
    border-radius: 50%;
    background: radial-gradient(circle at 50% 62%,
        rgba(196, 96, 30, 0.20) 0%,
        rgba(var(--gold-rgb), 0.08) 44%,
        transparent 74%);
    filter: blur(22px);
    pointer-events: none;
}

/* ─── Champion column ────────────────────────────────────────────────────── */
/*
 * Stated as a headline rather than framed as a card. Everything is set on the
 * plate itself: an eyebrow line, the name at display size, the alliance, then
 * the numbers. Nothing here has a border — the bars' own gradients carry the
 * structure, which is what keeps the column from competing with the trophy.
 */
.hof-champ-head {
    display: flex;
    align-items: center;
    gap: 0.55rem;
}
.hof-champ-crown {
    display: inline-flex;
    color: #F0CB55;
    filter: drop-shadow(0 0 7px rgba(255, 215, 0, 0.45));
}
.hof-champ-eyebrow {
    font-family: var(--font-display);
    font-size: 0.9375rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.24em;
    line-height: 1.2;
    color: rgba(230, 201, 133, 0.95);
}
/* Pushed to the far edge, as in the prototype: it dates the round without
   competing with the title of it. */
.hof-champ-date {
    margin-inline-start: auto;
    padding-inline-start: 1rem;
    font-size: 0.875rem;
    letter-spacing: 0.06em;
    white-space: nowrap;
    color: rgba(170, 147, 98, 0.8);
}
/* The round's speed, tucked under the label row (which has no width to spare
   beside the date). Same chip as the Hall of Fame page: every number in the
   band means something different at x7 and at x1M. */
.hof-champ-speed {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    margin: -0.55rem 0 0.8rem;
    padding: 0.18rem 0.6rem;
    border-radius: 0.3rem;
    background: rgba(var(--gold-rgb), 0.16);
    font-size: 0.8125rem;
    letter-spacing: 0.06em;
    white-space: nowrap;
    color: rgba(219, 199, 152, 0.95);
}
.hof-champ-speed svg { color: #FFD700; filter: drop-shadow(0 0 4px rgba(255, 215, 0, 0.35)); }
.hof-champ-speed-val {
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    color: #F4E287;
}

.hof-champ-name {
    display: block;
    margin: 0 0 0.7rem;
    font-family: var(--font-display);
    /* Cinzel renders lowercase as small caps, which is what gives the
       prototype's "IRONFURY" its two-height look — no transform needed. */
    font-size: clamp(2.5rem, 5.2vw, 4rem);
    font-weight: 900;
    line-height: 1.02;
    letter-spacing: 0.005em;
    text-decoration: none;
    overflow-wrap: anywhere;
    background: linear-gradient(180deg, #FFF7DD 0%, #F3D68C 32%, #DCAE41 66%, #A87B18 100%);
    -webkit-background-clip: text;
            background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
    filter: drop-shadow(0 6px 20px rgba(0, 0, 0, 0.55));
    transition: filter 0.3s ease;
}
.hof-champ-name:hover,
.hof-champ-name:focus-visible {
    filter: drop-shadow(0 6px 24px rgba(255, 200, 60, 0.3));
}

.hof-champ-guild {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    flex-wrap: wrap;
    margin: 0 0 1.35rem;
    font-size: 0.9375rem;
}
.hof-champ-guild-name {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-weight: 600;
    color: rgba(219, 195, 143, 0.95);
}
.hof-champ-guild-name svg { color: rgba(var(--gold-rgb), 0.75); }
.hof-champ-members { color: rgba(160, 139, 95, 0.85); }
.hof-champ-members::before {
    content: '·';
    margin-inline-end: 0.55rem;
    color: rgba(160, 139, 95, 0.5);
}

/* Bars, not boxes: the fill starts at the label and is gone by the time it
   reaches the value, so a column of them reads as a chart rather than a stack
   of cards. */
.hof-champ-stats {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    margin: 0;
}
.hof-champ-stat {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.7rem;
    padding: 0.8rem 1.1rem;
    border: 0;
    border-radius: 0.5rem;
    overflow: hidden;
    background: linear-gradient(90deg,
        rgba(var(--gold-rgb), 0.17) 0%,
        rgba(var(--gold-rgb), 0.085) 40%,
        rgba(var(--gold-rgb), 0.025) 72%,
        rgba(var(--gold-rgb), 0) 100%);
}
.hof-champ-stat::before {
    content: '';
    position: absolute;
    inset-block: 0;
    inset-inline-start: 0;
    width: 2px;
    background: linear-gradient(180deg, rgba(255, 213, 96, 0.9), rgba(var(--gold-rgb), 0.25));
}
.hof-champ-stat-icon {
    display: inline-flex;
    color: rgba(var(--gold-rgb), 0.85);
}
.hof-champ-stat-label {
    flex: 1 1 auto;
    min-width: 0;
    font-family: var(--font-display);
    font-size: 0.9375rem;
    font-weight: 900;
    text-transform: uppercase;
    letter-spacing: 0.18em;
    color: rgba(230, 210, 160, 0.96);
}
.hof-champ-stat-value {
    font-family: var(--font-display);
    font-size: 1.4rem;
    font-weight: 700;
    letter-spacing: 0.01em;
    font-variant-numeric: tabular-nums;
    color: #F7E6A8;
    white-space: nowrap;
}

.hof-champ-link {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    /* was a 23px target; the margin absorbs the added padding so the link
       sits where it did. */
    padding-block: 0.4375rem;
    margin-top: 0.9625rem;
    font-family: var(--font-display);
    font-size: 0.9375rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.2em;
    color: rgba(226, 190, 106, 0.95);
    text-decoration: none;
    transition: color 0.18s ease, gap 0.18s ease;
}
.hof-champ-link:hover { color: #FFD700; gap: 0.65rem; }

/* ─── Boards column ──────────────────────────────────────────────────────── */
.hof-boards-label {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 0.8rem;
    margin: 0;
    font-family: var(--font-display);
    font-size: 0.9375rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.24em;
    line-height: 1.2;
    color: rgba(230, 201, 133, 0.95);
}
.hof-boards-label-line {
    flex: 0 1 5.5rem;
    height: 1px;
    background: linear-gradient(90deg, rgba(var(--gold-rgb), 0), rgba(var(--gold-rgb), 0.6));
}

.hof-boards .hofw-cats {
    display: flex;
    flex-direction: column;
    gap: 1.3rem;
}

/* The board is a heading plus three bars — no frame, no accent colour of its
   own. It stays a link to the full table. */
.hofw-cat {
    display: block;
    text-decoration: none;
}
.hofw-cat-head {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.55rem;
}
.hofw-cat-icon {
    display: inline-flex;
    color: rgba(var(--gold-rgb), 0.8);
}
.hofw-cat-label {
    font-family: var(--font-display);
    font-size: 0.9375rem;
    font-weight: 900;
    text-transform: uppercase;
    letter-spacing: 0.2em;
    color: rgba(216, 189, 126, 0.92);
}

.hofw-cat-rows {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}
/*
 * Rank is the bar's leading edge and the numeral, not a filled medal chip.
 * The fill stays gold on every row so the three boards read as one block; only
 * the 3px edge changes, which is enough to place first from third at a glance.
 */
.hofw-cat-row {
    --rank-rgb: 232, 193, 84;
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.6rem 0.95rem;
    border-radius: 0.45rem;
    overflow: hidden;
    background: linear-gradient(90deg,
        rgba(var(--gold-rgb), 0.15) 0%,
        rgba(var(--gold-rgb), 0.07) 45%,
        rgba(var(--gold-rgb), 0.015) 78%,
        rgba(var(--gold-rgb), 0) 100%);
    transition: background 0.2s ease;
}
.hofw-cat-row.r2 { --rank-rgb: 196, 199, 205; }
.hofw-cat-row.r3 { --rank-rgb: 205, 138, 76; }
.hofw-cat-row::before {
    content: '';
    position: absolute;
    inset-block: 0;
    inset-inline-start: 0;
    width: 3px;
    background: rgb(var(--rank-rgb));
    box-shadow: 0 0 10px rgba(var(--rank-rgb), 0.45);
}
.hofw-cat:hover .hofw-cat-row {
    background: linear-gradient(90deg,
        rgba(var(--gold-rgb), 0.22) 0%,
        rgba(var(--gold-rgb), 0.1) 45%,
        rgba(var(--gold-rgb), 0.02) 78%,
        rgba(var(--gold-rgb), 0) 100%);
}
.hofw-cat-medal {
    min-width: 0.9rem;
    font-family: var(--font-display);
    font-size: 0.875rem;
    font-weight: 900;
    font-variant-numeric: tabular-nums;
    color: rgb(var(--rank-rgb));
    flex-shrink: 0;
}
/*
 * Alliance tag. p_alliances.name is varchar(10) in this codebase — it IS the
 * short tag, so this never needs truncating. flex-shrink stays 0 so a long
 * player name gives up its characters before the tag does.
 */
.hofw-cat-tag {
    flex-shrink: 0;
    padding: 0.05rem 0.4rem;
    border-radius: 0.25rem;
    font-family: var(--font-display);
    font-size: 0.8125rem;
    font-weight: 900;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    background: rgba(var(--gold-rgb), 0.16);
    border: 1px solid rgba(var(--gold-rgb), 0.28);
    color: rgba(226, 199, 133, 0.95);
}
.hofw-cat-name {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 1rem;
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: rgba(229, 212, 172, 0.95);
}
.hofw-cat-stat {
    font-family: var(--font-display);
    font-size: 1rem;
    font-weight: 700;
    letter-spacing: 0.01em;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    color: #F3E1A4;
}

/* ─── Entrance ───────────────────────────────────────────────────────────── */
/* Outer columns come in from their own sides, the centre rises — so the trophy
   reads as the anchor the two wings arrive around. */
.has-reveal .hof-head,
.has-reveal .hof-champion,
.has-reveal .hof-centre,
.has-reveal .hof-boards {
    opacity: 0;
    transition: opacity 0.9s cubic-bezier(0.22, 0.61, 0.36, 1),
                transform 1.5s cubic-bezier(0.16, 0.84, 0.28, 1);
    will-change: transform, opacity;
}
.has-reveal .hof-champion { transform: translate3d(-5rem, 0, 0); }
.has-reveal .hof-boards   { transform: translate3d(5rem, 0, 0); }
.has-reveal .hof-centre   { transform: translate3d(0, 2.5rem, 0); transition-delay: 0.12s; }

.has-reveal .hof-head { transform: translate3d(0, 1.5rem, 0); }
.has-reveal .hof-head.is-revealed,
.has-reveal .hof-champion.is-revealed,
.has-reveal .hof-centre.is-revealed,
.has-reveal .hof-boards.is-revealed { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
    .hof-head, .hof-champion, .hof-centre, .hof-boards { opacity: 1; transform: none; transition: none; }
}

/* Stacked: title and trophy lead, then the champion, then the boards. */
@media (max-width: 1099px) {
    .hof-centre { order: -1; }
    .hof-boards-label { justify-content: center; }
}

/* ============================================================================
   IN-GAME FEATURES — rail + stage  (v0 prototype port)
   ----------------------------------------------------------------------------
   Was a centred divider, one big frame, and a horizontal thumbnail strip. Now a
   full-width heading over two columns: a named rail carrying the counter and all
   nine features, and the frame on the right above a nine-segment progress bar.
   ========================================================================== */

.feat-backdrop { position: relative; isolation: isolate; }
/* replaced by the shared .section-band plate */
.feat-backdrop--legacy-plate-removed {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background:
        radial-gradient(100% 70% at 38% 46%,
            rgba(24, 18, 8, 0.50) 0%,
            rgba(12, 9, 4, 0.68) 46%,
            rgba(6, 4, 2, 0.78) 72%,
            rgba(6, 4, 2, 0) 100%),
        linear-gradient(to bottom,
            rgba(4, 3, 1, 0) 0%,
            rgba(4, 3, 1, 0.52) 12%,
            rgba(4, 3, 1, 0.66) 50%,
            rgba(4, 3, 1, 0.52) 88%,
            rgba(4, 3, 1, 0) 100%);
}

.feat-band {
    max-width: 82rem;
    margin: 0 auto;
    padding: 3.5rem 1.5rem 4.5rem;
}
@media (min-width: 1000px) { .feat-band { padding: 4.5rem 2.5rem 5.5rem; } }

/* ─── Heading ────────────────────────────────────────────────────────────── */
.feat-head { margin-bottom: 2.25rem; text-align: center; }
@media (min-width: 1000px) { .feat-head { text-align: right; } }

.feat-title {
    font-family: var(--font-display);
    font-size: 1.5rem;
    font-weight: 900;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    margin: 0 0 0.375rem;
    background: linear-gradient(180deg, #FFFFFF 0%, #FFF8DC 20%, #FFD700 45%, var(--gold-400) 70%, #9A7515 100%);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
}
@media (min-width: 768px)  { .feat-title { font-size: 2.25rem; } }
@media (min-width: 1024px) { .feat-title { font-size: 3rem; } }

.feat-subtitle {
    margin: 0;
    font-size: 0.9375rem;
    line-height: 1.6;
    color: rgba(210, 190, 145, 0.85);
}

/* ─── Row ────────────────────────────────────────────────────────────────── */
.feat-row { display: flex; flex-direction: column; gap: 1.75rem; }
@media (min-width: 1000px) {
    .feat-row { flex-direction: row; align-items: stretch; gap: 2rem; }
    .feat-rail  { flex: 0 0 18rem; width: 18rem; }
    .feat-stage { flex: 1 1 auto; min-width: 0; }
}

/* ─── Rail ───────────────────────────────────────────────────────────────── */
.feat-rail { display: flex; flex-direction: column; justify-content: center; }

.feat-counter {
    display: flex;
    align-items: baseline;
    gap: 0.4rem;
    margin: 0 0 1.1rem;
    font-family: var(--font-display);
    font-variant-numeric: tabular-nums;   /* so the number does not jog as it counts */
}
.feat-counter-now   { font-size: 2rem; font-weight: 900; color: #F4E287; line-height: 1; }
.feat-counter-sep,
.feat-counter-total { font-size: 0.9375rem; font-weight: 700; color: rgba(190, 165, 115, 0.7); }

.feat-list { display: flex; flex-direction: column; }

.feat-list-item {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.75rem;
    width: 100%;
    padding: 0.6rem 0;
    background: none;
    border: 0;
    border-bottom: 1px solid rgba(var(--gold-rgb), 0.08);
    text-align: right;
    cursor: pointer;
}
.feat-list-item:last-child { border-bottom: 0; }

/* The accent bar grows for the active item — this is the main "you are here"
   signal, so the label itself does not have to shout. */
.feat-list-bar {
    flex: 0 0 auto;
    width: 3px;
    height: 0.9rem;
    border-radius: 999px;
    background: rgba(var(--gold-rgb), 0.22);
    transition: height 0.3s var(--ease-out, cubic-bezier(0.22, 1, 0.36, 1)),
                background-color 0.3s ease;
}
.feat-list-name {
    min-width: 0;
    font-size: 0.9375rem;          /* the page's small-body size — kept readable */
    font-weight: 600;
    line-height: 1.25;
    color: rgba(196, 176, 132, 0.78);
    transition: color 0.25s ease, letter-spacing 0.25s ease;
}
.feat-list-item:hover .feat-list-name { color: rgba(232, 217, 176, 0.95); }
.feat-list-item:hover .feat-list-bar  { background: rgba(var(--gold-rgb), 0.45); }

.feat-list-item.is-active .feat-list-bar {
    height: 1.75rem;
    background: linear-gradient(180deg, #FFD700, var(--gold-400));
    box-shadow: 0 0 10px rgba(var(--gold-rgb), 0.5);
}
.feat-list-item.is-active .feat-list-name {
    color: #F4E287;
    letter-spacing: 0.02em;
}

/* ─── Stage ──────────────────────────────────────────────────────────────── */
.feat-stage { display: flex; flex-direction: column; gap: 0.85rem; justify-content: center; }
/* the frame was centred in a 64rem box of its own; in the row it simply fills */
.feat-stage .gallery-feature { margin: 0; width: 100%; }

.feat-progress {
    display: flex;
    align-items: center;
    gap: 0.25rem;
}
.feat-progress-seg {
    flex: 1 1 0;
    height: 3px;
    padding: 0;
    border: 0;
    border-radius: 999px;
    background: rgba(var(--gold-rgb), 0.16);
    cursor: pointer;
    transition: background-color 0.3s ease, box-shadow 0.3s ease;
}
.feat-progress-seg:hover { background: rgba(var(--gold-rgb), 0.36); }
.feat-progress-seg.is-active {
    background: linear-gradient(90deg, #FFD700, var(--gold-400));
    box-shadow: 0 0 10px rgba(var(--gold-rgb), 0.45);
}
/* The segments are 3px tall — far under any sane touch target — so they get an
   invisible padded hit area rather than being made visually chunky. */
.feat-progress-seg::after {
    content: '';
    position: absolute;
    /* -10px gave a 23px target. -14px gives 31px on a mouse, and the coarse
       block below takes it to 43px for a finger. The bar itself stays 3px. */
    inset: -14px 0;
}
@media (hover: none) and (pointer: coarse) {
    .feat-progress-seg::after { inset: -20px 0; }
}
.feat-progress-seg { position: relative; }

/* ─── Entrance ───────────────────────────────────────────────────────────── */
/* Heading first, then the rail from the left and the stage from the right. */
.has-reveal .feat-head,
.has-reveal .feat-rail,
.has-reveal .feat-stage {
    opacity: 0;
    transition: opacity 0.9s cubic-bezier(0.22, 0.61, 0.36, 1),
                transform 1.5s cubic-bezier(0.16, 0.84, 0.28, 1);
    will-change: transform, opacity;
}
.has-reveal .feat-head  { transform: translate3d(0, 1.75rem, 0); }
.has-reveal .feat-rail  { transform: translate3d(-4rem, 0, 0); transition-delay: 0.1s; }
.has-reveal .feat-stage { transform: translate3d(4rem, 0, 0); transition-delay: 0.16s; }

.has-reveal .feat-head.is-revealed,
.has-reveal .feat-rail.is-revealed,
.has-reveal .feat-stage.is-revealed { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
    .feat-head, .feat-rail, .feat-stage { opacity: 1; transform: none; transition: none; }
    .feat-list-bar, .feat-list-name, .feat-progress-seg { transition: none; }
}

/* ============================================================================
   EXPLORE MORE — heading band + numbered cards  (v0 prototype port)
   ----------------------------------------------------------------------------
   One accent per card, declared once. The original rules repeated each colour
   four times over (border, bar, icon, title) as separate [data-c] selectors; the
   new parts need it too, which would have meant three more triplets. A single
   custom property per card covers all of them and is the only thing that has to
   change if a fourth card is ever added.
   ========================================================================== */

.explore-card[data-c="discord"] { --ex: 114, 137, 218; }
.explore-card[data-c="manual"]  { --ex:  52, 211, 153; }
.explore-card[data-c="sd"]      { --ex:  96, 165, 250; }

.explore-backdrop { position: relative; isolation: isolate; }
/* replaced by the shared .section-band plate */
.explore-backdrop--legacy-plate-removed {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background: linear-gradient(to bottom,
        rgba(4, 3, 1, 0) 0%,
        rgba(4, 3, 1, 0.48) 16%,
        rgba(4, 3, 1, 0.60) 50%,
        rgba(4, 3, 1, 0.48) 84%,
        rgba(4, 3, 1, 0) 100%);
}

.explore-band {
    max-width: 78rem;
    margin: 0 auto;
    padding: 3.5rem 1.5rem;
}
@media (min-width: 1000px) { .explore-band { padding: 4.5rem 2.5rem; } }

.explore-head { margin-bottom: 1.75rem; text-align: center; }
@media (min-width: 1000px) { .explore-head { text-align: right; } }

.explore-title {
    font-family: var(--font-display);
    font-size: 1.5rem;
    font-weight: 900;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    margin: 0 0 0.375rem;
    background: linear-gradient(180deg, #FFFFFF 0%, #FFF8DC 20%, #FFD700 45%, var(--gold-400) 70%, #9A7515 100%);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
}
@media (min-width: 768px)  { .explore-title { font-size: 2.25rem; } }
@media (min-width: 1024px) { .explore-title { font-size: 3rem; } }

.explore-subtitle {
    margin: 0;
    font-size: 0.9375rem;
    line-height: 1.6;
    color: rgba(210, 190, 145, 0.85);
}

/* ─── Card ───────────────────────────────────────────────────────────────── */
.explore-card { padding: 1.5rem 1.5rem 1.25rem; gap: 1rem; }

/* Tinted wash so each card carries its colour beyond the 3px bar, as the
   prototype does — kept very low so the description stays the brightest thing
   on the card. */
.explore-card::after {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: radial-gradient(120% 90% at 12% 0%,
        rgba(var(--ex), 0.14) 0%,
        rgba(var(--ex), 0.04) 42%,
        transparent 72%);
}
.explore-card > * { position: relative; z-index: 1; }

/* The oversized index. Sits behind the content, clipped by the card's own
   overflow, and is aria-hidden — decoration, not information. */
.explore-card-num {
    position: absolute;
    top: 0.35rem;
    left: 0.9rem;
    z-index: 0;
    font-family: var(--font-display);
    font-size: 4.5rem;
    font-weight: 900;
    line-height: 1;
    color: rgba(var(--ex), 0.16);
    letter-spacing: -0.02em;
    user-select: none;
    transition: color var(--dur-base) var(--ease-out);
}
.explore-card:hover .explore-card-num { color: rgba(var(--ex), 0.26); }

.explore-card-body { display: flex; flex-direction: column; gap: 0.4rem; }

.explore-card-eyebrow {
    margin: 0;
    font-family: var(--font-display);
    font-size: 0.8125rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.22em;
    color: rgba(var(--ex), 0.95);
}

/* Bigger than the old 0.875rem: the title is now the card's headline rather
   than one item in a row with the icon and arrow. */
.explore-card-title { font-size: 1.125rem; margin: 0; }

.explore-card-arrow {
    display: inline-flex;
    align-items: center;
    margin-top: auto;
    color: rgba(var(--ex), 0.75);
    transition: transform var(--dur-base) var(--ease-out), color var(--dur-base) var(--ease-out);
}
.explore-card:hover .explore-card-arrow { transform: translateX(-4px); color: rgba(var(--ex), 1); }

/* ─── Entrance ───────────────────────────────────────────────────────────── */
/* The heading rises, then the three cards follow one after another. --i is set
   per card in the markup so the stagger survives any reordering. */
.has-reveal .explore-head,
.has-reveal .explore-grid .explore-card {
    opacity: 0;
    transition: opacity 0.8s cubic-bezier(0.22, 0.61, 0.36, 1),
                transform 1.2s cubic-bezier(0.16, 0.84, 0.28, 1);
    will-change: transform, opacity;
}
.has-reveal .explore-head { transform: translate3d(0, 1.75rem, 0); }
.has-reveal .explore-grid .explore-card {
    transform: translate3d(0, 2.5rem, 0);
    transition-delay: calc(0.12s + var(--i, 0) * 0.11s);
}
.has-reveal .explore-head.is-revealed,
.has-reveal .explore-grid.is-revealed .explore-card { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
    .explore-head, .explore-grid .explore-card { opacity: 1; transform: none; transition: none; }
}

/* ============================================================================
   SECTION BANDS — one shared plate, connectors, and the hero join
   ----------------------------------------------------------------------------
   Each of the five bands used to carry its own hand-tuned pair of gradients.
   They were near-identical, drifted from one another, and had a real bug:

   ⚠ A radial gradient does NOT fade at its element's top edge. The old plates
   layered `radial(... at 50% 46%)` over a linear fade, assuming the linear one
   would soften the join — but at the band's top edge the radial was already
   ~0.75 opaque on its own, so the linear underneath it changed nothing. Against
   another dark band that passed unnoticed; against the bright hero it drew the
   hard horizontal line across the page that prompted this.

   The fix is structural rather than another set of hand-tuned stops: ONE plate,
   with the vertical fade applied as a MASK over the whole layer. Everything the
   plate paints is faded at both ends, so no future gradient added here can
   reintroduce an edge. `--band-focus` moves the warm centre under whatever the
   section's artwork is, which is the only thing that ever actually varied.
   ========================================================================== */

/*
 * ⚠⚠ overflow-x: clip is load-bearing, do not remove it.
 *
 * The four section entrances slide their two columns in from opposite sides:
 *   .legacy-copy  translate3d( 6rem,0,0)      .legacy-art   -6rem
 *   .worlds-art   translate3d( 6rem,0,0)      .worlds-main  -6rem
 *   .hof-boards   translate3d( 5rem,0,0)      .hof-champion -5rem
 *   .feat-stage   translate3d( 4rem,0,0)      .feat-rail    -4rem
 *
 * Until a section is revealed its RIGHT-hand column sits up to 6rem (86px)
 * past where it belongs, and .is-revealed is TOGGLED, not latched - scrolling
 * away puts the offset back. On a phone there is always at least one
 * un-revealed section, so the document is permanently wider than the screen
 * and its width CHANGES as you scroll. That was the sideways scroll on the
 * landing page: the layout viewport grew to match, every position:fixed layer
 * stretched with it, and the navbar carried its hamburger off-screen.
 * Reported as "the header starts normal and then expands to the right".
 *
 * `clip`, NOT `hidden`: hidden would make every band a scroll container and
 * force overflow-y to auto, which breaks position:sticky descendants. clip
 * contains the transform and changes nothing else. .section-band is full page
 * width, so nothing that was already on-screen can be clipped by this.
 */
.section-band {
    position: relative;
    isolation: isolate;
    overflow-x: clip;
}

.section-band::before {
    content: '';
    position: absolute;
    /* Bleeds slightly past the band so neighbouring plates overlap rather than
       meet exactly — two masked edges butted together read as a faint seam. */
    inset: -6% 0;
    z-index: -1;
    pointer-events: none;
    background:
        radial-gradient(95% 68% at var(--band-focus, 50%) 44%,
            rgba(30, 22, 10, var(--band-a1, 0.52)) 0%,
            rgba(13, 10, 5, var(--band-a2, 0.70)) 46%,
            rgba(6, 4, 2, var(--band-a3, 0.80)) 100%);
    -webkit-mask-image: linear-gradient(to bottom,
        transparent 0%, #000 var(--band-in, 14%), #000 var(--band-out, 86%), transparent 100%);
            mask-image: linear-gradient(to bottom,
        transparent 0%, #000 var(--band-in, 14%), #000 var(--band-out, 86%), transparent 100%);
}

/* ─── Connector ──────────────────────────────────────────────────────────── */
/*
 * Sits on the seam between two bands: a hairline that fades out both ways with a
 * small rotated square at its centre. Quiet by design — it marks the join, it is
 * not meant to be read as a rule across the page. The last band has no section
 * after it, so it does not get one.
 */
.section-band::after {
    content: '';
    position: absolute;
    right: 50%;
    bottom: -0.5px;
    transform: translateX(50%);
    width: min(38rem, 62%);
    height: 1px;
    pointer-events: none;
    background: linear-gradient(90deg,
        transparent 0%,
        rgba(var(--gold-rgb), 0.16) 26%,
        rgba(var(--gold-rgb), 0.30) 50%,
        rgba(var(--gold-rgb), 0.16) 74%,
        transparent 100%);
}
.section-band.is-last::after { content: none; }

.section-band > .band-node {
    position: absolute;
    right: 50%;
    bottom: 0;
    width: 6px;
    height: 6px;
    transform: translate(50%, 50%) rotate(45deg);
    background: linear-gradient(135deg, #FFD700, var(--gold-400));
    box-shadow: 0 0 10px rgba(var(--gold-rgb), 0.45);
    pointer-events: none;
    z-index: 1;
}
.section-band.is-last > .band-node { display: none; }

/* ─── Hero join ──────────────────────────────────────────────────────────── */
/*
 * ⚠ There is deliberately NO extra fade on the hero.
 *
 * A `.landing-hero::after` foot gradient was tried here and made things worse,
 * not better. Two darkenings then met at the hero's bottom edge — the hero's own
 * fade arriving at ~0.78 alpha, and the band's plate starting from 0 and ramping
 * up — so the strip immediately below the boundary was LIGHTER than the strip
 * immediately above it. That reversal is exactly what reads as a drawn line, and
 * adding a second overlay to soften a seam is what created one.
 *
 * The band's own masked plate is the only thing at this boundary now, so the
 * darkening simply begins where the section begins and holds one value the whole
 * way down. The entry ramp below is long enough to be imperceptible without
 * introducing a second value to cross.
 */
.section-band.legacy-backdrop { --band-in: 16%; }

/* ============================================================================
   HERO PASS — presence, entrance, rhythm, mobile
   ----------------------------------------------------------------------------
   Measured before touching anything (1440x900):
     • CTA 278x65 with 16.2px text, while the stats pill above it was 620px wide
       — the most important control on the site was outranked by a row of numbers
     • 168px of dead space between the scroll hint and the bottom of the hero
     • mobile: the stats pill wrapped to 124px over three rows, pushing the logo
       to 334px down — you scrolled past numbers to reach the brand
     • nothing moved on load, while every section below it now animates in
   ========================================================================== */

/* ─── 1. The call to action ──────────────────────────────────────────────── */
.start-journey {
    padding: 1.15rem 3.25rem;
    border-radius: 0.85rem;
    font-size: 1.0625rem;
    letter-spacing: 0.08em;
    gap: 0.7rem;
    /* transform is animated on hover AND carries the entrance, so both are
       declared here; opacity is listed for the entrance only. */
    transition: transform 320ms var(--ease-out), box-shadow 320ms var(--ease-out), opacity 0.6s ease;
}
@media (min-width: 640px) { .start-journey { padding: 1.3rem 4rem;   font-size: 1.1875rem; } }
@media (min-width: 768px) { .start-journey { padding: 1.45rem 4.75rem; font-size: 1.3125rem; } }

.start-journey:hover  { transform: translateY(-3px) scale(1.03); }
.start-journey:active { transform: translateY(-1px) scale(0.99); transition-duration: 120ms; }

/* A second, periodic sweep lived here and was removed: `.start-journey::after`
   already carries a shimmer, and two over one button read as flicker.
   ⚠ Deleting it by byte offsets left an ORPHAN `}` right here. CSS has no syntax
   error to report — the parser simply discarded everything up to the next rule it
   could resynchronise on, which silently ate the glow override below. Rules far
   enough down still applied, so the sheet looked half-working. */

/*
 * ⚠ NO ::before or ::after here.
 *
 * A "breathing ring" was added on `.start-journey::before` and silently DESTROYED
 * the button's existing glow — that pseudo-element was already taken (a blurred
 * gold halo on a `cta-pulse` loop, and `::after` carries the shimmer). Same
 * element, same specificity, later in the file, so the original simply stopped
 * existing. Nothing errors when you overwrite a pseudo-element; the effect just
 * disappears, which is why it took a cascade audit to notice.
 *
 * ⚠ `html.perf-lite .start-journey::before` in perf-lite.css also targets that
 * glow to stop its animation on low-end machines. Redefining it here would have
 * quietly broken that opt-out too.
 *
 * Both slots stay with their originals; the extra presence the button needed is
 * applied by AMPLIFYING them below rather than by adding a third layer.
 */
.start-journey::before {
    inset: -7px;
    opacity: 0.95;
    filter: blur(11px);
}
.start-journey::after { opacity: 0.55; }

/* ─── 3. Vertical rhythm ─────────────────────────────────────────────────── */
/* The hero is a fixed-height block, so the reclaimed 168px is handed to the
   space AROUND the button rather than left pooling under the scroll hint. */
.landing-hero > .start-journey { margin-top: 0.5rem; }

/* ─── Launch clock ───────────────────────────────────────────────────────── */
/*
 * This was a bordered rectangle holding two rows of small text, with the launch
 * time set at the same weight as the Discord member count. Plain border, static
 * text, table-like rows: every marker of a dated countdown at once.
 *
 * Now the time IS the object. Each segment carries its own unit, the numerals
 * are display-sized, and there is no container — the space between the segments
 * does the framing. The faces use the same device as the champion's stat bars
 * downstairs: a gradient strongest at the top and gone by the bottom, a lit rim,
 * and no border anywhere.
 */
.hero-countdown {
    position: relative;
    z-index: 10;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.8rem;
    margin: 0.25rem 0 1.75rem;
}

/* The flanking hairlines. They were declared beside the slogan wrapper and
   went blank with it when that was removed — the countdown label still uses
   them, so they live here now, next to their only caller. */
.hero-eyebrow-line {
    width: 2.5rem;
    height: 1px;
    background: linear-gradient(90deg, transparent, rgba(var(--gold-rgb), 0.75));
}
.hero-eyebrow-line.is-flipped {
    background: linear-gradient(90deg, rgba(var(--gold-rgb), 0.75), transparent);
}
@media (min-width: 768px) { .hero-eyebrow-line { width: 4rem; } }

.hero-countdown-eyebrow {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: 0.7rem;
    margin: 0;
}
.hero-countdown-round {
    font-family: var(--font-display);
    font-size: 0.875rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.24em;
    color: rgba(226, 199, 133, 0.92);
}
@media (min-width: 768px) { .hero-countdown-round { font-size: 0.9375rem; } }

/*
 * Grid, not flex. The four unit labels are different lengths in every language
 * ("Days" against "Hours", "Мин" against "Часов"), so content-sized segments
 * came out 82 / 74 / 81 / 81 px and only line up by luck. Equal columns make the
 * symmetry structural instead.
 */
.hero-clock {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    align-items: start;
    justify-content: center;
    gap: 0.6rem;
    width: 100%;
    max-width: 23rem;
}
@media (min-width: 640px) { .hero-clock { gap: 0.85rem; max-width: 27rem; } }
.hero-countdown.is-large .hero-clock { max-width: 30rem; }

.cd-seg {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.3rem;
    padding: 0.7rem 0.55rem 0.6rem;
    border-radius: 0.6rem;
    overflow: hidden;
    /* Measured at 2.77:1 with a gold-tinted face: tinting the ground the
       same hue as the text is what killed it. A near-black face takes the
       same numerals to 8.8:1, and it still dissolves at the foot rather
       than closing into a box. */
    background: linear-gradient(180deg,
        rgba(10, 7, 3, 0.88) 0%,
        rgba(9, 6, 3, 0.80) 52%,
        rgba(8, 5, 2, 0.58) 82%,
        rgba(8, 5, 2, 0.28) 100%);
}
@media (min-width: 640px) { .cd-seg { padding: 0.85rem 0.75rem 0.7rem; } }
/* A lit top rim rather than a border: the face reads as struck metal catching
   the light, and nothing boxes the numeral in. */
.cd-seg::before {
    content: '';
    position: absolute;
    top: 0;
    inset-inline: 12%;
    height: 2px;
    border-radius: 2px;
    background: linear-gradient(90deg,
        rgba(var(--gold-rgb), 0) 0%,
        rgba(255, 227, 140, 0.95) 50%,
        rgba(var(--gold-rgb), 0) 100%);
}

.cd-num {
    display: block;
    font-family: var(--font-display);
    font-size: 2.1rem;
    font-weight: 900;
    line-height: 1;
    letter-spacing: 0.01em;
    /* Without tabular figures the segments jitter sideways every second. */
    font-variant-numeric: tabular-nums;
    background: linear-gradient(180deg, #FFFDF4 0%, #FCEDBE 38%, #F0CB63 74%, #D9A62E 100%);
    -webkit-background-clip: text;
            background-clip: text;
    -webkit-text-fill-color: transparent;
    filter: drop-shadow(0 3px 10px rgba(0, 0, 0, 0.6));
}
@media (min-width: 640px)  { .cd-num { font-size: 2.6rem; } }
@media (min-width: 1024px) { .cd-num { font-size: 3.1rem; } }

.cd-unit {
    font-family: var(--font-display);
    font-size: 0.6875rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.2em;
    color: rgba(214, 190, 138, 0.92);
}
@media (min-width: 640px) { .cd-unit { font-size: 0.75rem; } }

/* A short lift as a value rolls over. The seconds fire every second, so it has
   to be brief and small enough to read as a tick rather than a bounce. */
.cd-num.is-tick { animation: cd-tick 340ms cubic-bezier(0.16, 0.84, 0.28, 1); }
@keyframes cd-tick {
    0%   { transform: translateY(-0.16em); opacity: 0.35; }
    100% { transform: none; opacity: 1; }
}

/* Launch moment: the segments give way to the opening message. */
.hero-clock.is-opening > .cd-seg { display: none; }
.hero-clock.is-opening::after {
    content: attr(data-opening);
    font-family: var(--font-display);
    font-size: 1.25rem;
    font-weight: 900;
    text-transform: uppercase;
    letter-spacing: 0.16em;
    color: #F7E6A8;
}

/* Second and later rounds: one quiet line, not another four segments. */
.hero-countdown-more {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 1.1rem;
    margin: 0;
    font-size: 0.875rem;
    color: rgba(176, 154, 108, 0.85);
}
.hero-countdown-more-item { display: inline-flex; align-items: center; gap: 0.45rem; }
.hero-countdown-more-item .v {
    font-family: var(--font-display);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: rgba(226, 199, 133, 0.95);
}

/* With no live world to report, the clock is the only thing up here and can
   afford to be larger. */
@media (min-width: 640px)  { .hero-countdown.is-large .cd-num { font-size: 3.2rem; } }
@media (min-width: 1024px) { .hero-countdown.is-large .cd-num { font-size: 3.9rem; } }

/* ─── Live stats, under the button ───────────────────────────────────────── */
/*
 * These sat above the logo sharing the countdown's frame, which gave the Discord
 * member count the same weight as the launch date. They are proof the world is
 * alive, so they belong under the call to action and out of any container.
 */
.landing-hero > .hero-stats-pill {
    margin: 0 0 1.4rem;
    padding: 0 0.4rem;
    border: 0;
    border-radius: 0;
    background: none;
    box-shadow: none;
    opacity: 1;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    /* The base rule still clips, from when this was a capsule with a
       9999px radius. With the frame gone there is nothing to clip TO, and
       it was cutting the shadow behind the last number at the boundary. */
    overflow: visible;
    gap: 1.75rem;
    /* Read against bright artwork rather than only against the plate: at
       this size a shadow is worth more than another overlay, and it costs
       the background none of its brightness. */
    text-shadow: 0 2px 10px rgba(0, 0, 0, 0.9), 0 1px 3px rgba(0, 0, 0, 0.75);
}
.landing-hero > .hero-stats-pill .hero-stats-sep { background: rgba(var(--gold-rgb), 0.3); height: 1.05rem; }
.landing-hero > .hero-stats-pill .hero-stat-item { font-size: 1rem; color: rgba(226, 205, 155, 0.95); }
.landing-hero > .hero-stats-pill .hero-stat-item .v { font-size: 1.0625rem; color: #FFF0C4; font-weight: 900; }
.landing-hero > .hero-stats-pill .hero-stat-item svg { color: rgba(var(--gold-rgb), 0.85); }
/* The live dot keeps its green: that is a state, not decoration. */
.landing-hero > .hero-stats-pill .hero-stats-active {
    padding: 0.24rem 0.75rem;
    background: rgba(52, 211, 153, 0.16);
    border-color: rgba(52, 211, 153, 0.42);
    font-size: 0.875rem;
    letter-spacing: 0.12em;
}

/*
 * Reading plate for the hero content.
 *
 * The content sat straight on the artwork, which is bright warm olive right
 * where the text is. This is the same device as .section-band::before, which
 * every band below uses: a soft radial darkening focused behind the content
 * and eased to nothing long before it reaches an edge, so it never shows a
 * boundary and the art keeps full brightness at the sides where the rider and
 * the village are.
 *
 * z-index -1, not 0. The hero is a stacking context (position: relative plus
 * z-index: 10), and a positioned child at z-index 0 would paint ABOVE static
 * block content, covering the tagline and the button.
 */
.hero-plate {
    position: absolute;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background:
        radial-gradient(24% 15% at 50% 50%,
            rgba(104, 214, 232, 0.11) 0%,
            rgba(104, 214, 232, 0.05) 46%,
            rgba(104, 214, 232, 0) 100%),
        /* Was 52% x 46%, which put only 0.20 of plate under the clock at the
           top of the hero and 0.14 under the stats at the foot. Taller, so
           the whole column is covered, still eased to nothing at the edges. */
        radial-gradient(58% 62% at 50% 45%,
            rgba(6, 4, 2, 0.44) 0%,
            rgba(6, 4, 2, 0.38) 44%,
            rgba(6, 4, 2, 0.19) 72%,
            rgba(6, 4, 2, 0) 100%);
    /* Deepens as the hero leaves, so the content recedes rather than simply
       scrolling away. --hero-scroll is written by scroll-activate.js. */
    opacity: calc(1 + var(--hero-scroll, 0) * 0.35);
}

/* The seam mark, matching .section-band > .band-node. Positioned fully inside
   the hero because .landing-hero clips its overflow, so the usual
   translate(-50%, 50%) would have shown only the top half of the diamond. */
.hero-node {
    position: absolute;
    right: 50%;
    bottom: 3px;
    width: 6px;
    height: 6px;
    transform: translateX(50%) rotate(45deg);
    background: linear-gradient(135deg, #FFD700, var(--gold-400));
    box-shadow: 0 0 10px rgba(var(--gold-rgb), 0.45);
    pointer-events: none;
    z-index: 11;
    /* It marks the join to the next band, so it has no business being
       visible before anyone has moved. Fades in over the first tenth of
       the hero; opacity clamps at 1 on its own. */
    opacity: calc(var(--hero-scroll, 0) * 10);
}

/*
 * Scroll-linked recede.
 *
 * `translate`, not `transform`. The entrance animation above animates transform
 * with `forwards`, and a filled animation beats a declared property for the
 * rest of the page's life — the recede would never move. `translate` is a
 * separate property, so the two compose instead of fighting.
 */
.landing-hero > .hero-countdown,
.landing-hero > .hero-stats-pill,
.landing-hero > .hero-emblem,
.landing-hero > .hero-tagline,
.landing-hero > .start-journey {
    translate: 0 calc(var(--hero-scroll, 0) * -2.75rem);
}
.landing-hero > .scroll-down {
    translate: 0 calc(var(--hero-scroll, 0) * 1.5rem);
    opacity: calc(1 - var(--hero-scroll, 0) * 1.6);
}

@media (prefers-reduced-motion: reduce) {
    .landing-hero > .hero-countdown,
    .landing-hero > .hero-stats-pill,
    .landing-hero > .hero-emblem,
    .landing-hero > .hero-tagline,
    .landing-hero > .start-journey,
    .landing-hero > .scroll-down { translate: none; }
    .landing-hero > .scroll-down { opacity: 1; }
    .hero-node { opacity: 1; }
    .hero-plate { opacity: 1; }
}

.scroll-down { margin-top: auto; padding-bottom: 2.25rem; }
@media (min-width: 768px) {
    .hero-tagline    { margin-bottom: 2.25rem; }
    .scroll-down     { padding-bottom: 3rem; }
}

/* ─── 5. Depth behind the emblem ─────────────────────────────────────────── */
/* The logo sat directly on busy painted artwork. This lifts it off the plate
   without darkening the art around it. */
.hero-emblem { position: relative; }
.hero-emblem::before {
    content: '';
    position: absolute;
    right: 50%;
    top: 46%;
    width: 128%;
    height: 190%;
    transform: translate(50%, -50%);
    z-index: -1;
    pointer-events: none;
    /* 0.55/0.34 put a visible dark disc behind the mark. Lowered to a third
       so it still separates the metal from the painted artwork without
       reading as a shadow of its own. */
    background: radial-gradient(closest-side ellipse,
        rgba(0, 0, 0, 0.34) 0%,
        rgba(0, 0, 0, 0.20) 46%,
        rgba(0, 0, 0, 0) 78%);
}

/* Very slow drift on the fixed backdrop. Long enough (48s) to register as depth
   rather than as movement; scale keeps the edges covered while it travels. */
@media (min-width: 1024px) {
    .landing-atmos-bg { animation: hero-drift 48s ease-in-out infinite alternate; }
}
@keyframes hero-drift {
    from { transform: scale(1.06) translate3d(-0.8%, -0.4%, 0); }
    to   { transform: scale(1.06) translate3d(0.8%, 0.4%, 0); }
}

/* ─── 2. Entrance ────────────────────────────────────────────────────────── */
/*
 * Load-time, not scroll-time: the hero is already on screen, so it uses its own
 * stagger rather than the [data-reveal] observer the sections below use.
 *
 * ⚠ Gated behind .has-hero-rise, NOT .has-reveal. The hidden start state has
 * to be in place before the first paint or the hero shows at rest and then
 * snaps to hidden — .has-reveal arrives with a deferred script, far too late.
 * The gate is set by a blocking inline script in <head>; see page-shell.phtml.
 * This entrance is pure CSS with `forwards`, so nothing else is needed from JS.
 */
.has-hero-rise .hero-emblem,
.has-hero-rise .hero-tagline,
.has-hero-rise .hero-stats-pill,
.has-hero-rise .hero-countdown,
.has-hero-rise .start-journey,
.has-hero-rise .scroll-down {
    opacity: 0;
    transform: translate3d(0, 1.5rem, 0);
    animation: hero-rise 0.85s cubic-bezier(0.16, 0.84, 0.28, 1) forwards;
}
/* Delays follow the order they are read in, which changed when the clock
   moved below the brand — the countdown used to lead at 0.12s. */
.has-hero-rise .hero-emblem      { animation-delay: 0.14s; transform: translate3d(0, 2.25rem, 0); }
.has-hero-rise .hero-tagline     { animation-delay: 0.36s; }
.has-hero-rise .hero-stats-pill  { animation-delay: 0.50s; }
.has-hero-rise .hero-countdown   { animation-delay: 0.62s; }
.has-hero-rise .start-journey    { animation-delay: 0.78s; transform: translate3d(0, 1.75rem, 0) scale(0.96); }
.has-hero-rise .scroll-down      { animation-delay: 0.96s; }

@keyframes hero-rise {
    to { opacity: 1; transform: none; }
}

/* The sheen and ring would otherwise start mid-entrance, drawing attention to a
   button that has not arrived yet. */
.has-hero-rise .start-journey::after  { animation-delay: 1.6s; }
.has-hero-rise .start-journey::before  { animation-delay: 1.6s; }

@media (prefers-reduced-motion: reduce) {
    .has-hero-rise .hero-emblem,
    .has-hero-rise .hero-tagline,
    .has-hero-rise .hero-stats-pill,
    .has-hero-rise .hero-countdown,
    .has-hero-rise .start-journey,
    .has-hero-rise .scroll-down { animation: none; opacity: 1; transform: none; }
    .start-journey::after,
    .start-journey::before,
    .landing-atmos-bg { animation: none; }
    .start-journey::before { box-shadow: none; }
}

/* ─── 4. Mobile stats row ────────────────────────────────────────────────── */
/*
 * This used to be one horizontally-scrollable row. That existed for a reason
 * that no longer holds: the stats sat ABOVE the logo, wrapping put them on
 * three lines, and the brand did not appear until 334px down the screen.
 *
 * The row is below the call to action now, so height costs nothing there and
 * wrapping is simply better — all four numbers are visible at once instead of
 * two, with no hidden scroll and no faded edge that reads as a clipping bug.
 * The larger type this row carries had made the scrolled version worse: only
 * "Active realms" and "Total players" fitted before the fade.
 */
@media (max-width: 640px) {
    /* Beats the .landing-hero > .hero-stats-pill rule that sets the desktop
       gap, which is one specificity class higher than a bare class selector. */
    .landing-hero > .hero-stats-pill {
        flex-wrap: wrap;
        justify-content: center;
        gap: 0.45rem 1.15rem;
        padding: 0;
        max-width: 100%;
        overflow-x: visible;
        -webkit-mask-image: none;
                mask-image: none;
    }
    .hero-stats-pill > * { flex: 0 0 auto; }
    /* A separator at the end of a wrapped line dangles; the row reads fine
       without them once it is centred on two lines. */
    .landing-hero > .hero-stats-pill .hero-stats-sep { display: none; }

    /* Reclaim the space the pill was taking from the composition. */
    .hero-emblem { margin-top: 1.25rem; }
    .scroll-down { padding-bottom: 1.5rem; }
}

/* The drift is desktop-only (see the min-width: 1024px rule above), so mobile
   never pays for an animated full-screen background. */

/* ─── 3b. Pin the scroll hint, centre the stack ──────────────────────────── */
/*
 * `.landing-hero` reserves `padding-bottom: 9rem` so the hero reaches the fold
 * while its content stays optically centred. With `margin-top: auto` on the
 * scroll hint that backfired: an auto margin absorbs ALL free space, which
 * cancels `justify-content: center` and top-aligns the whole stack.
 *
 * The hint is taken out of flow and pinned near the fold instead. The stack then
 * centres properly in the space that remains, and the reserved padding can come
 * down from 9rem to 4.5rem because nothing needs to be parked in it any more.
 */
/* The scroll hint is pinned to the foot and out of flow, so the column above
   it needs that room reserved or the two collide on a short screen — measured
   as a 7px overlap at 375x667. Costs nothing on a tall viewport, where this
   only sets the box's minimum.

   Raised 6.75rem -> 8rem on 2026-08-22: once the stack centres, a short window
   has almost no slack to absorb, so the CTA drifted down onto the hint again -
   measured a 14px overlap at 1280x700. 8rem clears the hint (63px) plus its
   2.25rem offset plus a real gap. */
.landing-hero { padding-bottom: 8rem; }

/* ─── Short-and-wide viewports ───────────────────────────────────────────────
 * A 1366x768 laptop gives about 660px of viewport, and 1280x800 gives ~700px
 * once browser chrome is out. At that height the full-size composition
 * (454px of stack + 57px navbar + the pinned hint) leaves a 2px gap between
 * the CTA and the hint - they touch.
 *
 * Padding alone cannot fix that; there is nothing left to pad with. The
 * composition scales instead: a smaller mark and tighter rhythm, which buys
 * back ~63px and lets the stack centre with real air around it.
 *
 * Keyed on height AND a desktop width, so phones (which top-anchor and have
 * their own scale) are untouched.
 */
@media (min-width: 641px) and (max-height: 780px) {
    .landing-hero  { padding-top: 5rem; padding-bottom: 6.5rem; }
    /* .hero-logo-wrap width for this height moved to the foot of the file:
       the base widths are declared there, and a media query adds no specificity,
       so an override has to come after the rule it overrides. */
    .hero-tagline  { margin-top: 1.25rem; margin-bottom: 1.5rem; }
}
@media (min-width: 641px) and (max-height: 640px) {
    .landing-hero  { padding-top: 4.75rem; padding-bottom: 5.75rem; }
    /* see the note above - moved to the foot of the file. */
    .hero-tagline  { margin-top: 1rem; margin-bottom: 1.125rem; }
}

.scroll-down {
    position: absolute;
    right: 50%;
    bottom: 1.5rem;
    transform: translateX(50%);
    margin-top: 0;
    padding-bottom: 0;
}
@media (min-width: 768px) { .scroll-down { bottom: 2.25rem; } }
@media (max-width: 640px) { .scroll-down { bottom: 1rem; } }

/* The pin uses transform for centring, so the entrance must not overwrite it —
   it animates opacity only, and translates via its own inner offset. */
.has-hero-rise .scroll-down {
    transform: translateX(50%);
    animation-name: hero-rise-pinned;
}
@keyframes hero-rise-pinned {
    from { opacity: 0; transform: translateX(50%) translateY(1.5rem); }
    to   { opacity: 1; transform: translateX(50%); }
}

/* ─── 3c. Phone: anchor the stack near the top ───────────────────────────── */
/*
 * Pinning the scroll hint took 54px out of the flow, so the centred stack
 * re-centred DOWNWARD and the logo fell from 334px to 390px — the opposite of
 * what shrinking the stats pill was meant to achieve.
 *
 * On a phone the hero is tall relative to its content, so centring is the wrong
 * model: it strands the composition in the middle with a large empty cap. The
 * stack is anchored to the top instead, offset clear of the nav.
 */
@media (max-width: 640px) {
    .landing-hero {
        justify-content: flex-start;
        padding-top: calc(4.25rem + 2.25rem);   /* nav offset + breathing room */
    }
}

/* ============================================================================
   UPCOMING ROUND — present, not shouting
   ----------------------------------------------------------------------------
   A new round opening is the strongest reason a visitor has to act, and it was
   the quietest element on the page: 15%-alpha fill, a 30%-alpha border and
   80%-alpha text, sitting UNDER a bright white-and-green stats pill. Against the
   painted background it read as disabled.

   The first correction overshot — saturated orange (180,83,9) with a 34px glow
   and a 30%-alpha sweep read as fluorescent against a muted, painted backdrop.
   ⚠ The problem was HUE as much as intensity: pure orange is foreign to this
   page, whose whole palette is gold and bronze, so it looked like an alert
   pasted on rather than part of the design. Pulling the hue back toward amber
   lets it stay bright without shouting, and then the glow and sweep only need to
   be halved rather than removed.

   It still outranks the stats pill — first in reading order, warmer, and the only
   thing here that moves — but at roughly half the previous intensity.
   ========================================================================== */

.hero-countdown-pill {
    gap: 0.75rem;
    margin-top: 0.85rem;
    padding: 0.58rem 1.25rem;
    /* Amber/bronze, in the page's own family, instead of the orange alert. */
    background: linear-gradient(100deg,
        rgba(69, 43, 13, 0.88) 0%,
        rgba(92, 60, 19, 0.84) 45%,
        rgba(78, 50, 16, 0.88) 100%);
    border: 1px solid rgba(var(--gold-rgb), 0.38);
    box-shadow: 0 0 16px rgba(var(--gold-rgb), 0.14),
                0 8px 24px rgba(0, 0, 0, 0.42),
                inset 0 1px 0 rgba(255, 237, 213, 0.14);
}

/* Sweep kept, at well under half its previous strength and slower — enough to
   catch the eye in peripheral vision, not enough to read as flashing. */
.hero-countdown-pill::after {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: linear-gradient(105deg, transparent 40%, rgba(255, 240, 200, 0.11) 50%, transparent 60%);
    background-size: 220% 100%;
    animation: shimmer-x 5.5s ease-in-out infinite;
}

.hero-countdown-badge {
    padding: 0.22rem 0.6rem;
    font-size: 0.8125rem;
    letter-spacing: 0.14em;
    color: #F4E287;
    background: rgba(var(--gold-rgb), 0.14);
    border: 1px solid rgba(var(--gold-rgb), 0.3);
}
/* Live dot — smaller, gold rather than orange, with a gentler ring. */
.hero-countdown-badge::before {
    content: '';
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--gold-400, #D4AF37);
    box-shadow: 0 0 0 0 rgba(var(--gold-rgb), 0.55);
    animation: countdown-live 2.6s ease-out infinite;
}
@keyframes countdown-live {
    0%   { box-shadow: 0 0 0 0 rgba(var(--gold-rgb), 0.5); }
    70%  { box-shadow: 0 0 0 7px rgba(var(--gold-rgb), 0); }
    100% { box-shadow: 0 0 0 0 rgba(var(--gold-rgb), 0); }
}

.hero-countdown-text   { font-size: 0.875rem; color: rgba(240, 226, 190, 0.92); position: relative; z-index: 1; }
/* The timer is still the brightest thing in the pill — it is the actual message —
   but warm off-white rather than pure white, and the halo is a hint of gold
   instead of an orange bloom. */
.hero-countdown-text .v {
    font-size: 1rem;
    font-weight: 800;
    color: #FBF3D8;
    text-shadow: 0 0 9px rgba(var(--gold-rgb), 0.3);
}
@media (min-width: 768px) {
    .hero-countdown-pill    { padding: 0.66rem 1.55rem; }
    .hero-countdown-text    { font-size: 0.9375rem; }
    .hero-countdown-text .v { font-size: 1.1875rem; }
    .hero-countdown-badge   { font-size: 0.875rem; }
}

/* Badge and text sit above the sweep. */
.hero-countdown-badge { position: relative; z-index: 1; }

/* The stats pill steps back so it supports the countdown instead of outshouting
   it — same content, less weight. */
.hero-stats-pill { background: rgba(0, 0, 0, 0.45); opacity: 0.92; }

@media (prefers-reduced-motion: reduce) {
    .hero-countdown-pill::after,
    .hero-countdown-badge::before { animation: none; }
    .hero-countdown-badge::before { box-shadow: none; }
}

/* The countdown is the invitation and the stats are the reassurance, so the
   invitation goes first. Source order keeps the stats pill first (it is the
   fallback when no round is upcoming, and it must not depend on the countdown
   existing), so the swap is done with flex order rather than by moving markup. */
/* ⚠ NEGATIVE orders. Every other hero child sits at the default `order: 0`, so
   positive values would have pushed both pills BELOW the logo, tagline and
   button — which is exactly what happened on the first attempt. */

/* ─── Legacy pills: a real 2x2 ───────────────────────────────────────────── */
/*
 * These were a wrapping flex row, so each pill was as wide as its own label and
 * the four broke 3 + 1 — three across, one stranded underneath. Content-sized
 * items in a wrap container can only ever land symmetrically by coincidence.
 *
 * A 2x2 grid makes the symmetry structural: equal columns, equal rows, and it
 * stays 2x2 whatever the labels say in any of the eight languages. `align-items:
 * stretch` is what squares the heights — "Active Community" wraps to two lines
 * while "Fair Play" does not, and without it the two would differ in height.
 */
.legacy-pills {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    /* ⚠ `align-items: stretch` only equalises WITHIN a row. On a phone the first
       two labels wrap to two lines and the second two do not, so the rows came
       out 75px and 57px — even widths, uneven block. `grid-auto-rows: 1fr` sizes
       every row to the tallest, which is what makes all four boxes identical. */
    grid-auto-rows: 1fr;
    align-items: stretch;
    gap: 0.6875rem;
    width: 100%;
    max-width: 34rem;
}
.legacy-pill {
    justify-content: center;   /* vertical centring inside the now-taller cell */
    min-height: 100%;
}

/* Stacked layout keeps the grid centred under the copy. */
.legacy-band.is-artless .legacy-copy .legacy-pills { margin-inline: auto; }

/* One column on the narrowest screens: at 2x2 a phone gives each pill ~160px,
   which breaks "Active Community" onto three lines. */
@media (max-width: 380px) {
    .legacy-pills { grid-template-columns: minmax(0, 1fr); }
}

/* ============================================================================
   REALM ROWS — prominent numbers, shorter cards
   ----------------------------------------------------------------------------
   Measured against the prototype: our row stood 99px tall and its figures were
   13.5px in a muted tan, so the three numbers — the only reason to compare one
   realm with another — were the least visible thing on the card.

   Two causes, both structural rather than cosmetic:
     • the head stacked eyebrow / name / status pill vertically, 71px for three
       short strings
     • every figure shared one low-contrast colour, so nothing separated players
       from speed from online at a glance
   ========================================================================== */

@media (min-width: 640px) {
    /* Status pill moves up beside the name instead of sitting under it — the
       single biggest saving, and it reads better as a label on the realm. */
    .swidget-grid.is-rows .swcard-head {
        display: flex;
        align-items: center;
        gap: 0.75rem;
    }
    .swidget-grid.is-rows .swcard-head > div { min-width: 0; }
    .swidget-grid.is-rows .swcard-status { margin-top: 0; flex-shrink: 0; }

    .swidget-grid.is-rows .swcard-body { padding: 0.7rem 1rem; }

    /* The figures carry the card now. */
    .swidget-grid.is-rows .swcard-stat-value {
        font-size: 1.375rem;
        font-weight: 900;
        line-height: 1.1;
        font-variant-numeric: tabular-nums;
    }
    .swidget-grid.is-rows .swcard-stat-label {
        font-size: 0.75rem;
        letter-spacing: 0.12em;
        text-transform: uppercase;
    }
    /* The icon competed with the number for the same slot; the label already
       says what the figure is. */
    .swidget-grid.is-rows .swcard-stat-icon { display: none; }
    .swidget-grid.is-rows .swcard-stats { gap: 1.6rem; }
    .swidget-grid.is-rows .swcard-stat { min-width: 4.25rem; }

    /*
     * Colour per statistic, so the eye can track one column down the stack of
     * realms instead of re-reading three identical tan numbers on every row.
     * ⚠ Addressed by position: the three stats are emitted in a fixed order by
     * render_server_card (players, speed, online) and carry no modifier class of
     * their own. If a fourth is ever added, these need revisiting.
     */
    .swidget-grid.is-rows .swcard-stat:nth-child(1) .swcard-stat-value { color: #F4E287; }
    .swidget-grid.is-rows .swcard-stat:nth-child(2) .swcard-stat-value { color: #FB923C; }
    .swidget-grid.is-rows .swcard-stat:nth-child(3) .swcard-stat-value { color: #4ADE80; }

    /* A realm that is not yet playable shows placeholders, and colouring those
       as if they were live figures oversells it. */
    .swidget-grid.is-rows .swcard.soon .swcard-stat-value { color: rgba(190, 170, 130, 0.5); }
}

/* ⚠ The head must be given a floor. Enlarging the figures widened the stats
   block, which squeezed the name column to 98px on the widest card — so
   "Nexian Official" wrapped over three lines and that row grew to 111px while
   the other two shrank to 69px. The fix is a minimum width plus a single-line
   name, not a smaller font: the realm's name is the one thing on the row that
   must stay readable. */
@media (min-width: 640px) {
    .swidget-grid.is-rows .swcard-head { flex: 1 1 auto; min-width: 13rem; }
    .swidget-grid.is-rows .swcard-name {
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }
    .swidget-grid.is-rows .swcard-subtitle { white-space: nowrap; }
    .swidget-grid.is-rows .swcard-stat { min-width: 3.9rem; }
    .swidget-grid.is-rows .swcard-stats { gap: 1.35rem; }
}

/* The trailing action becomes a chevron only, as in the prototype.
   Its label ("Register", "Server Details") is a different length per realm, and
   the widest one squeezed the name column until "Nexian Official" truncated —
   the row's least important element pushing out its most important one. The card
   is a single button, the status pill already says whether the realm is live, and
   `font-size: 0` hides the words visually while leaving them in the accessibility
   tree, so nothing is lost to a screen reader. */
@media (min-width: 640px) {
    .swidget-grid.is-rows .swcard-cta {
        font-size: 0;
        gap: 0;
    }
    .swidget-grid.is-rows .swcard-cta svg {
        width: 1.1rem;
        height: 1.1rem;
    }
    .swidget-grid.is-rows .swcard-foot { gap: 0; }
}

/* ============================================================================
   REALM ROWS — align the columns, lighten the numerals
   ----------------------------------------------------------------------------
   The row was a flex line with a content-sized name block, so every card placed
   its stats wherever its own name and status happened to end: measured starts of
   494 / 542 / 558px for the figures and 385 / 472 / 438px for the tags. Three
   rows, three different rhythms, and the eye cannot compare a column that moves.

   Flex can only align these by accident. The row becomes a GRID with declared
   track widths, so the tags share one column and each statistic shares its own,
   whatever the realm is called.
   ========================================================================== */

@media (min-width: 640px) {
    .swidget-grid.is-rows .swcard-body {
        display: grid;
        /* name | status | stats | chevron */
        grid-template-columns: minmax(0, 1fr) 7.5rem auto 1.25rem;
        align-items: center;
        column-gap: 1.1rem;
    }
    /* ⚠ `display: contents`, not `block`. The status pill is a CHILD of the head,
       so `grid-column` on it does nothing while the head is a box — it just sat
       under the name again and the row grew back to 93px. Dissolving the head
       promotes its two children into the body grid, where the name takes column 1
       and the status column 2. Safe here only because the head carries no
       background, border or padding of its own; `display: contents` throws all of
       that away. */
    .swidget-grid.is-rows .swcard-head { grid-column: 1; min-width: 0; }
    .swidget-grid.is-rows .swcard-status {
        grid-column: 2;
        justify-self: start;
        margin-top: 0;
    }
    .swidget-grid.is-rows .swcard-stats {
        grid-column: 3;
        display: grid;
        grid-template-columns: repeat(3, 5.25rem);
        justify-items: center;
        gap: 0;
    }
    .swidget-grid.is-rows .swcard-foot { grid-column: 4; justify-self: end; }
    .swidget-grid.is-rows .swcard-divider { display: none; }

    /*
     * Lighter numerals. Inter at 900 was doing the shouting — at 19.8px that
     * weight closes the counters up and reads as a slab rather than a figure.
     * 650 keeps the emphasis while letting the digits breathe, and the negative
     * tracking recovers the width that the lower weight gives back.
     */
    .swidget-grid.is-rows .swcard-stat-value {
        font-family: var(--font-sans);
        font-weight: 650;
        letter-spacing: -0.015em;
        font-variant-numeric: tabular-nums;
        font-feature-settings: 'tnum' 1, 'lnum' 1;
    }
    .swidget-grid.is-rows .swcard-stat { min-width: 0; }
}

/* ⚠ Higher specificity on purpose.
   `.swidget-grid.is-rows .swcard-status { grid-column: 2 }` above did not win —
   setting the same property inline moved the pill from 181px to 399px, so the
   placement itself is sound and the declaration was simply losing the cascade.
   Rather than leave that as a mystery in a file this long, the placement rules
   are restated through the card so they cannot be outranked by anything already
   styling these elements. */
@media (min-width: 640px) {
    .swidget-grid.is-rows .swcard .swcard-head { grid-column: 1; }
    .swidget-grid.is-rows .swcard .swcard-status     { grid-column: 2; justify-self: start; }
    .swidget-grid.is-rows .swcard .swcard-stats      { grid-column: 3; }
    .swidget-grid.is-rows .swcard .swcard-foot       { grid-column: 4; justify-self: end; }
}

/* The card is a <button>, which centres its text by default. That was masked
   while the name sat inside its own flex wrapper; now that the head holds the
   two lines directly, it has to be stated. */
@media (min-width: 640px) {
    .swidget-grid.is-rows .swcard-head { text-align: right; }
}

/* ⚠ The head must be a COLUMN. An earlier rule in this file makes it a flex row
   (it used to hold the name block and the status pill side by side). With the
   status moved out, that row put the eyebrow and the name next to each other
   instead of stacked — which is why the eyebrows lined up at 181px while the
   names landed at 306 / 323 / 302, each pushed along by the eyebrow beside it. */
@media (min-width: 640px) {
    .swidget-grid.is-rows .swcard-head {
        display: flex;
        flex-direction: column;
        align-items: flex-start;
        justify-content: center;
        gap: 0.1rem;
    }
    .swidget-grid.is-rows .swcard-head > * { max-width: 100%; }
}


/* ============================================================================
   Band focus - "the part you are on is lit, the rest recedes"
   ----------------------------------------------------------------------------
   The same idea /rules uses on its document cards (see scroll-section.css),
   applied to the five landing bands. Which band is lit is decided in
   assets/js/scroll-activate.js by a focus line at 45% of the viewport, NOT by
   the fully-visible test /rules uses - the bands are too tall for that and
   every seam would dim the whole page for a moment.

   .has-band-dim is added by that script. If the script never runs, this
   selector never matches and nothing is dimmed - the same defensive gate
   .has-reveal uses, for the same reason: a page must never be left dark by a
   feature that failed to load.

   Desktop only. `filter` on a full-width band is a full-band raster on every
   frame of the transition, and mobile-lite already strips this class of effect
   for exactly that reason.
   ============================================================================ */
@media (min-width: 768px) and (hover: hover) {
    .has-band-dim .section-band {
        transition: filter 520ms var(--ease-out), opacity 520ms var(--ease-out);
        filter: saturate(0.74) brightness(0.62);
        opacity: 0.76;
    }
    .has-band-dim .section-band.is-focus {
        filter: none;
        opacity: 1;
    }
}
@media (prefers-reduced-motion: reduce) {
    .has-band-dim .section-band,
    .has-band-dim .section-band.is-focus {
        transition: none;
        filter: none;
        opacity: 1;
    }
}


/* ============================================================================
   Touch hit areas - landing-specific controls
   ----------------------------------------------------------------------------
   Companion to the block at the foot of components.css. Same rule: coarse
   pointer only, tap area only. Nothing here moves a label, changes a size or
   touches the mouse layout. Measured 2026-08-22 at 375x812; every value is the
   padding that takes that element to 44px, not a round number picked by eye.
   ============================================================================ */
@media (hover: none) and (pointer: coarse) {
    .worlds-updates-all { padding-block: 0.75rem; }    /* 32 -> 44 */
    .hof-champ-link     { padding-block: 0.6875rem; }  /* 37 -> 45 */
    .feat-list-item     { min-height: 44px; }          /* 39 -> 44 */
    .gallery-arrow      { min-width: 44px; min-height: 44px; } /* 40 -> 44 */
}


/* ============================================================================
   2026-08-22 - "THE LEGACY EVOLVES": lift + sheen
   ----------------------------------------------------------------------------
   Measured on assets/img/nexian-wordmark.webp (656x266):

       NEXIAN              mean luminance 0.268   brightest pixel 1.000
       THE LEGACY EVOLVES  mean luminance 0.173   brightest pixel 0.562

   The tagline is a third dimmer on average and has no highlight at all - the
   artist gave the wordmark a specular pass and never gave the tagline one. That
   is the whole reason it disappears against a lit background, and it is baked
   into the file, so it cannot be fixed with colour on text.

   Two layers of light, both painted THROUGH the artwork as a mask so they land
   on the glyphs and not on the box around them:

     LIFT   a constant, even wash - the brightness the tagline never got.
     SHEEN  a slow highlight that crosses it and then rests - the specular pass
            the wordmark has and the tagline does not.

   Ink geometry, measured rather than eyeballed:
       helmet    x   1-171
       gap       x 171-197
       tagline   x 197-644,  y 194-264
   so the clip is inset(72% 1.5% 0 29%) - the tagline's own rectangle, with the
   helmet and NEXIAN outside it and untouched.
   ============================================================================ */

.hero-logo-wrap {
    position: relative;
    display: block;
    /* The responsive widths moved here from .hero-logo so the wrapper is exactly
       the image box - the lift is positioned against it and has to agree with it
       to the pixel. */
    width: min(78vw, 20rem);
    /* Keeps the screen blend below talking to the logo only, instead of to
       whatever the hero happens to be painted over. */
    isolation: isolate;
}
@media (min-width: 640px)  { .hero-logo-wrap { width: min(70vw, 26rem); } }
@media (min-width: 1024px) { .hero-logo-wrap { width: 30rem; } }
@media (min-width: 1440px) { .hero-logo-wrap { width: 33rem; } }

.hero-logo {
    width: 100%;
    display: block;
}

.hero-legacy-lift {
    /*
     * The tagline's own pixels, drawn again on top of themselves and brightened.
     *
     * Multiplicative, not additive. A flat wash blended with `screen` lifts the
     * dark pixels of a letter far more than its highlights, which compresses the
     * range and flattens engraved metal - the reason A, L and V looked washed in
     * the first attempt. brightness() scales every channel by the same factor, so
     * the shading inside each letter survives.
     *
     * The factor is solved, not chosen: the tagline measures 0.176 mean luminance
     * against NEXIAN's 0.266, and brightness(1.20) lands it on 0.262. It gets the
     * same light as the wordmark above it and no more.
     *
     * ⚠ The asset holds the TAGLINE GLYPHS ONLY, and that is the whole trick.
     *
     * Two attempts failed by trying to isolate the tagline with a rectangle, and
     * a rectangle cannot do it: NEXIAN's `NE` and `AN` descend to y=208, and they
     * sit horizontally INSIDE the tagline's span (x 242-600), so any box that
     * covers the tagline also covers them. That is why the bottoms of the Ns kept
     * lighting up however the crop was nudged.
     *
     * The crop is built by connected-component analysis instead (see the notes in
     * this session): every separate shape in the artwork is labelled, and only the
     * 16 whose bounding box starts at or below y=199 are kept. NEXIAN's letters
     * and the helmet are literally not in the file, so the mask cannot leak onto
     * them no matter what the geometry does.
     *
     * Placement is that file's own bbox: x 240-603, y 197-226 of 656x266.
     */
    position: absolute;
    right: 36.585%;
    top: 74.060%;
    width: 55.335%;
    height: 10.902%;
    z-index: 2;
    pointer-events: none;

    background-image:
        /* the sheen, above */
        linear-gradient(102deg,
            transparent 45%,
            rgba(255, 252, 238, 0.58) 50%,
            transparent 55%),
        /* the letters, below */
        var(--legacy-art, url('/assets/img/nexian-legacy-art.webp'));
    background-size: 200% 100%, 100% 100%;
    background-position: -50% 0, 0 0;
    background-repeat: no-repeat, no-repeat;

    /* Same file as the mask, so the sheen is confined to the letterforms instead
       of sweeping the rectangle around them. */
    -webkit-mask: var(--legacy-art, url('/assets/img/nexian-legacy-art.webp')) center / 100% 100% no-repeat;
            mask: var(--legacy-art, url('/assets/img/nexian-legacy-art.webp')) center / 100% 100% no-repeat;

    filter: brightness(1.20);
}

/*
 * Narrower band and a shorter cycle than the first pass: the highlight is 10% of
 * a 200% backdrop (about 66px at desktop) instead of a fifth of the width, and
 * it comes round every 6s instead of 9. It still rests far longer than it moves
 * - the sweep is the first 14% of the cycle - because a highlight that runs
 * continuously stops reading as a highlight.
 */
@media (min-width: 1024px) and (hover: hover) {
    .hero-legacy-lift { animation: hero-legacy-sheen 6s ease-in-out infinite; }
}
@keyframes hero-legacy-sheen {
    0%   { background-position: -50% 0, 0 0; }
    14%  { background-position: 150% 0, 0 0; }
    100% { background-position: 150% 0, 0 0; }
}
@media (prefers-reduced-motion: reduce) {
    /* The brightness stays - that is the readability half. Only the sweep stops. */
    .hero-legacy-lift { animation: none; }
}

/* ============================================================================
   Hero with a launch clock
   ----------------------------------------------------------------------------
   The clock is ~142px (or 155px enlarged) plus its margins, and it lands in a
   composition that already filled the fold. Measured at 1280x800:

       with live worlds + clock   hero 854px in an 800px viewport
       pre-launch (large clock)   hero 813px

   In both the scroll hint fell below the fold, which makes it useless - it
   exists to say there is more underneath.

   So the composition gives the clock its room rather than overflowing: the same
   two levers the short-viewport block uses, for the same reason. Nothing here
   touches the clock itself; the clock is the reason the page is being looked at
   when it is showing.

   Placed BEFORE the short-viewport block below so that a short screen showing a
   clock still gets the tighter of the two.
   ============================================================================ */
@media (min-width: 641px) {
    .landing-hero.has-countdown .hero-logo-wrap { width: min(60vw, 24rem); }
    .landing-hero.has-countdown .hero-tagline   { margin-top: 1.25rem; margin-bottom: 1.5rem; }
    /* The two gaps bracketing the clock were 26px and 42px, the largest in the
       column. Trimming them buys the last 20px, which is what puts real air
       between the CTA and the pinned scroll hint (measured 2px before this). */
    .landing-hero.has-countdown .hero-stats-pill { margin-bottom: 0.875rem; }
    .landing-hero.has-countdown .hero-countdown  { margin-bottom: 1rem; }
    /*
     * ⚠ Trimming the content alone did NOT open the gap, and the reason is
     * worth keeping: the stack is CENTRED, so removing 20px of content just
     * re-centres what is left and the distance to a bottom-pinned element does
     * not change. The gap to the scroll hint is set by the reserved padding,
     * not by how tall the content is. 9rem is what fits: 88 top + 565 content
     * + 144 bottom = 797 in an 800px viewport.
     */
    .landing-hero.has-countdown { padding-bottom: 9rem; }
}

/*
 * Short-viewport widths, restated AFTER the base widths above.
 *
 * These used to sit with the rest of the short-viewport block further up the
 * file. Moving the sizing onto .hero-logo-wrap put the base declarations at the
 * foot of the file, and a media query carries no extra specificity - so the
 * later base rule silently beat the earlier override and a 700px-tall laptop
 * went back to the full-size mark. Measured: 480px where 384px was intended.
 */
@media (min-width: 641px) and (max-height: 780px) {
    .hero-logo-wrap { width: min(60vw, 24rem); }
}
@media (min-width: 641px) and (max-height: 640px) {
    .hero-logo-wrap { width: min(52vw, 20rem); }
}

/* Roster not announced yet (registry flag `tribes_tba`): the same badge with the
   colour drained out and a dashed edge — "pending", not "5 tribes in grey". The
   hue has to leave with the fact: a violet "?" reads as a value. */
.sd-pill-tribes.is-tba,
.sd-modal-tribes-count.is-tba,
.jmcard-pill-tribes.is-tba,
.swcard-tribes-pill.is-tba {
    background: rgba(232, 217, 176, 0.05);
    border: 1px dashed rgba(212, 175, 55, 0.38);
    color: rgba(232, 217, 176, 0.72);
    cursor: help;
}

/* ============================================================================
   REALM ROWS - status + tribes beside the name, never over the figures
   (2026-09-24, owner screenshot: "5 TRIBES" covered PLAYERS)
   ----------------------------------------------------------------------------
   The status column was a fixed 7.5rem track sized for ONE pill. The tribes
   badge joined it on 09-15, so "OPENS SOON" broke onto two lines and the tribes
   pill spilled over the first figure. A fixed track cannot hold words whose
   length changes with the language.

   render_server_card() now wraps the name block and the status in .swcard-main.
   That group owns the flexible first column and is a WRAPPING flex row: the
   pills sit right after the name, status above tribes (a two-line label beside
   the two-line name, so the row keeps its height and needs the width of ONE
   pill), and on a row too narrow even for that they move under the name
   instead of overlapping. The figures keep their own column and the first
   column never shrinks below its widest item, so nothing can cross into the
   figures and the pills can never sit on the name.
   ============================================================================ */
/* the live dot and the status word travel together (render_server_card) */
.swcard-status-line {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
}
@media (min-width: 640px) {
    .swidget-grid.is-rows .swcard .swcard-body {
        grid-template-columns: minmax(min-content, 1fr) auto 1.25rem;
        column-gap: 0.75rem;
    }
    /* Each figure's column is at least 4.75rem and exactly as wide as its own label
       beyond that, and never narrower, so a long one ("VELOCIDADE", "JOGADORES")
       can never run into its neighbour. */
    .swidget-grid.is-rows .swcard .swcard-stats {
        grid-template-columns: repeat(3, max-content);
    }
    .swidget-grid.is-rows .swcard .swcard-stat {
        min-width: 4.75rem;
        padding-inline: 0.25rem;
    }
    .swidget-grid.is-rows .swcard .swcard-main  { grid-column: 1; }
    .swidget-grid.is-rows .swcard .swcard-stats { grid-column: 2; }
    .swidget-grid.is-rows .swcard .swcard-foot  { grid-column: 3; justify-self: end; }
    .swidget-grid.is-rows .swcard .swcard-main {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        column-gap: 1rem;
        row-gap: 0.4rem;
        min-width: 0;
    }
    /* Every name block gets the width of the widest one (--swcard-head-w, set by the
       small script after the list in pages/landing.php), so the pills start at the
       same x on each row in every language. Without the script the 9.5rem floor
       still keeps everything apart; it only aligns less well. */
    .swidget-grid.is-rows .swcard .swcard-main > .swcard-head {
        flex: 0 0 auto;
        min-width: var(--swcard-head-w, 9.5rem);
        max-width: 100%;
    }
    .swidget-grid.is-rows .swcard .swcard-main > .swcard-status {
        flex: 0 1 auto;
        flex-direction: column;
        align-items: flex-start;
        gap: 0.3rem;
        min-width: 0;
        margin-top: 0;
    }
    .swidget-grid.is-rows .swcard .swcard-status-pill,
    .swidget-grid.is-rows .swcard .swcard-tribes-pill { white-space: nowrap; }

    /* NARROW CARDS. The trigger is the card's own width, not the screen's: at a
       1024px screen this band gives each card only ~518px, less than at 820px.
       Below 36rem a long name and the figures cannot share one line, so the
       figures move to a second line under the name group (the chevron spans
       both). Browsers without container queries keep the one-line row. */
    .swidget-grid.is-rows { container-type: inline-size; container-name: realms; }
    @container realms (max-width: 36rem) {
        .swidget-grid.is-rows .swcard .swcard-body {
            grid-template-columns: minmax(0, 1fr) 1.25rem;
            grid-template-rows: auto auto;
            row-gap: 0.6rem;
        }
        .swidget-grid.is-rows .swcard .swcard-main  { grid-column: 1; grid-row: 1; }
        .swidget-grid.is-rows .swcard .swcard-stats { grid-column: 1; grid-row: 2; justify-self: start; }
        .swidget-grid.is-rows .swcard .swcard-foot  { grid-column: 2; grid-row: 1 / span 2; }
    }
}

/* ============================================================================
   LEGACY BAND - title, then the badge, then the divider, all centred; the badge
   toned down (owner, 2026-09-24)
   ----------------------------------------------------------------------------
   Order (pages/landing.php): title, "The Legacy Evolves" badge, divider. In the
   two-column layout (>= 900px) those three are centred in the copy column; the
   quote and the pills stay ranged as before. Below 900px the column was already
   centred. The badge is quieter everywhere: smaller, lighter, softer gold, a
   fainter frame and no glow, so the title leads.
   ============================================================================ */
.legacy-copy .legacy-title { margin: 0 0 1rem; }
.legacy-copy .era-badge {
    gap: 0.55rem;
    padding: 0.3rem 1rem;
    margin-bottom: 1.25rem;
    background: rgba(var(--gold-rgb), 0.05);
    border-color: rgba(var(--gold-rgb), 0.22);
    box-shadow: none;
}
.legacy-copy .era-badge-dot {
    width: 0.3rem;
    height: 0.3rem;
    opacity: 0.6;
    box-shadow: none;
}
.legacy-copy .era-badge-text {
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.24em;
    color: rgba(232, 217, 176, 0.72);
    text-shadow: none;
}
@media (min-width: 900px) {
    .legacy-band .legacy-copy .legacy-title   { align-self: stretch; text-align: center; }
    .legacy-band .legacy-copy .era-badge      { align-self: center; }
    .legacy-band .legacy-copy .legacy-divider { align-self: center; justify-content: center; }
}
