/*
 * FIFA World Cup 26 Stadiums — playground map styles
 * Page-local layout only. Fonts, colour, spacing, motion and base element styles come
 * from the shared design system (design-system.css, linked first in index.html): Zalando
 * Sans (--font-primary) on body, kaneda-gothic (--font-display) on headings. Every value
 * that has a design-system token uses it; only bespoke geometry (the 50/50 split, viewport
 * heights, brand-mark/spinner pixel sizes) stays literal. The page-local cream lives in the
 * --fifa-pane-bg variable so it flips to the system dark background in dark mode; every other
 * colour (text, border, background) is a semantic token that flips on its own.
 */

/* ------ ACCESSIBILITY HELPERS ------ */
/* Not provided by the design system; their tokenisable values use system tokens. */

.visually-hidden {
    position: absolute !important;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.skip-link {
    position: absolute;
    z-index: 300; /* above the nav header (200) so it stays reachable on focus */
    top: var(--space-m);
    left: var(--space-m);
    padding: var(--space-m) var(--space-l);
    background: var(--text-primary);
    border-radius: var(--radius-s);
    color: var(--background-primary);
    text-decoration: none;
    transform: translateY(-150%);
}

.skip-link:focus {
    transform: translateY(0);
}

/* ------ MAP LAYOUT ------ */
/* Bespoke side-by-side geometry the design-system grid can't express. The split, 100vh
   scroller and fixed map column are layout geometry, not design tokens. The content pane is
   capped so the map takes the extra width on large screens: 50/50 until ~1280px, then the
   pane holds at 40rem (640px, the system reading width) and the map grows to fill the rest. */

:root {
    --content-pane: min(50%, 40rem);
    --header-h: 64px; /* nav bar height; the fixed map + content pane are offset by it */
    --fifa-pane-bg: #fafafa; /* page-local cream; flips dark under [data-theme="dark"] */
}

/* Dark mode: the cream panels go to the system dark background. The header and text use
   semantic tokens already, so they flip on their own; the Mapbox map follows via its
   Standard lightPreset (night), set in script.js. */
[data-theme="dark"] {
    --fifa-pane-bg: var(--background-primary);
}

/* Nav header — reuses the shared .experiment-header chrome (experiment-controls.css).
   Pinned to --header-h so the map + content-pane offsets below stay exact, and given the
   highest stacking context (bar the skip-link) so it always sits above the fixed map, its
   Mapbox controls and the loading mask. */
.experiment-header {
    position: sticky;
    top: 0;
    z-index: 200;
    height: var(--header-h);
}

.map-wrapper {
    position: fixed;
    top: var(--header-h);
    bottom: 0;
    left: 0;
    width: calc(100% - var(--content-pane));
}

#map {
    width: 100%;
    height: 100%;
}

#mapContent,
.map-content {
    width: var(--content-pane);
    height: calc(100vh - var(--header-h));
    margin-left: calc(100% - var(--content-pane));
    overflow-y: scroll;
    background-color: var(--fifa-pane-bg); /* cream in light, system dark bg in dark */
}

/* -- Section -- */
/* Horizontal padding comes from the inner .padding-global wrapper (design system, 24px);
   .map-section keeps only the vertical padding plus the min-height the ScrollTrigger
   top-center/bottom-center handoff depends on (script.js). */
.map-section {
    box-sizing: border-box;
    min-height: 100vh;
    padding-bottom: var(--space-xl);
    border-bottom: var(--border-s) solid var(--border-faded);
}

.map-section:last-child {
    border-bottom: none;
}

/* Blocks own spacing via gap; neutralise the base heading/paragraph margins inside them
   so .gap-s is the single source of rhythm (design system: no margins inside blocks). */
.map-section .block > * {
    margin: 0;
}

/* -- Host-city figure (full-bleed, 16:9) -- */
/* Full width: sits outside .padding-global (a direct child of .map-section), so the image
   bleeds edge-to-edge; its bottom margin owns the gap down to the padded content. */
.map-section-figure {
    margin: 0 0 var(--space-xl);
}

.map-section-image {
    display: block;
    width: 100%;
    height: auto;
}

/* Credit is inset to line up with the padded content below the full-bleed image. */
.map-section-credit {
    margin-top: var(--space-s);
    padding-inline: var(--space-xl);
    color: var(--text-secondary); /* semantic token; AA-safe on the #fafafa panel */
    font-size: var(--font-2xs);
    line-height: var(--line-height-l);
    display: none;
}

/* -- Display heading -- */
/* Mirrors the studio `.headline-display` treatment (studio.css isn't loaded on this
   standalone page); family, size and leading all come from system tokens. */
.headline-display {
    font-family: var(--font-display);
    font-size: var(--font-10xl);
    font-weight: 700;
    line-height: 0.85;
    letter-spacing: 0;
    text-transform: uppercase;
}

/* -- Stadium index list (top-of-article jump nav, grouped by country) -- */
.stadium-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-l);
    padding-top: var(--space-xl);
}

.stadium-list > * {
    margin: 0;
}

/* List heading — the display treatment of .headline-display at a smaller size, so it reads
   as a (smaller) headline over the grouped links rather than a tiny eyebrow. */
.stadium-list-title {
    font-family: var(--font-display);
    font-size: var(--font-6xl);
    font-weight: 700;
    line-height: 0.85;
    letter-spacing: 0;
    text-transform: uppercase;
}

/* Two columns: Canada + Mexico stack in the left column, the United States fills the right.
   Collapses to a single column on mobile (see RESPONSIVE). */
.stadium-list-columns {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-l) var(--space-2xl);
    align-items: start;
}

.stadium-list-column {
    display: flex;
    flex-direction: column;
    gap: var(--space-l);
}

.stadium-list-group {
    display: flex;
    flex-direction: column;
    gap: var(--space-2xs);
    padding-bottom: var(--space-m);
}

.stadium-list-group > * {
    margin: 0;
}

/* Country label — a small category divider above each group's big display links. */
.stadium-list-country {
    color: var(--text-secondary);
    font-family: var(--font-primary);
    font-size: var(--font-xs);
    font-weight: var(--font-weight-medium);
    line-height: var(--line-height-m);
    letter-spacing: var(--letter-spacing-l);
    text-transform: uppercase;
}

.stadium-list-items {
    display: grid;
    grid-template-columns: 1fr;
    margin: 0;
    padding: 0;
    list-style: none;
}

.stadium-list-items li {
    margin: 0;
}

.stadium-list-link {
    display: block;
    padding: var(--space-2xs) 0;
    border-bottom: var(--border-s) solid var(--border-faded);
    color: var(--text-primary);
    font-family: var(--font-display);
    font-size: var(--font-4xl);
    font-weight: 700;
    text-transform: uppercase;
    text-decoration: none;
    transition: color var(--motion-page-fade-duration) var(--motion-page-fade-easing);
}

.stadium-list-link:hover,
.stadium-list-link:focus-visible {
    color: var(--text-accent);
}

/* -- Stadium facts (label/value spec table per stadium) -- */
/* A two-column definition list: the label column auto-sizes to the widest label, values
   fill the rest, and every row carries a hairline rule. No column-gap — the value's left
   padding provides the separation while keeping the row border continuous across both cells. */
.stadium-facts {
    display: grid;
    grid-template-columns: max-content 1fr;
    margin: 0;
    margin-bottom: var(--space-m);
}

.stadium-facts dt,
.stadium-facts dd {
    margin: 0;
    padding: var(--space-s) 0;
    border-bottom: var(--border-s) solid var(--border-faded);
    line-height: var(--line-height-m);
}

/* Muted label with a trailing colon added in CSS (kept out of the markup). */
.stadium-facts dt {
    color: var(--text-secondary);
}

.stadium-facts dt::after {
    content: ":" / ""; /* decorative colon; the empty alt keeps it out of the a11y tree */
}

.stadium-facts dd {
    padding-left: var(--space-xl);
}

/* ------ LOADING OVERLAY ------ */
/* Branded mask over the map during its heavy first paint. Scoped inside .map-wrapper
   (position: fixed), so it covers exactly the map region and leaves the stadium guide
   usable. Removed by teardownMapLoading() in script.js. */

.map-loading {
    position: absolute;
    z-index: 5; /* above the map canvas, below the nav header + skip-link */
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: var(--fifa-pane-bg); /* matches the scroller it masks; flips in dark */
    transition: opacity var(--motion-page-fade-duration) var(--motion-page-fade-easing);
}

.map-loading--hidden {
    opacity: 0;
}

.map-loading__inner {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-xl);
}

.map-loading__mark {
    display: block;
    width: 56px; /* brand-mark geometry */
    height: 56px;
}

.map-loading__spinner {
    width: 28px; /* spinner geometry */
    height: 28px;
    border: 3px solid var(--border-faded);
    border-top-color: var(--text-primary);
    border-radius: 50%;
}

.map-loading__text {
    margin: 0;
    color: var(--text-secondary);
    font-size: var(--text-size-xs);
}

/* No-map notice at the top of the stadium guide — hidden unless script.js reveals it. */
.map-fallback-note {
    color: var(--text-secondary);
}

/* Spin only when motion is welcome. Opting *into* the animation (rather than turning it
   off) keeps both the reduced-motion and unknown-preference cases static — the mask can
   sit on screen for up to 8s, so a spinner must respect the preference. */
@media (prefers-reduced-motion: no-preference) {
    .map-loading__spinner {
        animation: map-loading-spin 0.8s linear infinite; /* continuous loader speed, not a UI transition */
    }
}

@keyframes map-loading-spin {
    to {
        transform: rotate(360deg);
    }
}

/* ------ RESPONSIVE ------ */

/* -- Mobile / tablet: map on top, content below -- */
@media (max-width: 768px) {
    .map-wrapper {
        position: fixed;
        top: var(--header-h);
        left: 0;
        bottom: auto;
        width: 100%;
        height: 40vh;
    }

    #map {
        width: 100%;
        height: 100%;
    }

    #mapContent,
    .map-content {
        width: 100%;
        height: calc(100vh - 40vh - var(--header-h));
        margin-top: 40vh;
        margin-left: 0;
    }

    .map-section {
        min-height: 60vh;
        padding-bottom: var(--space-l);
    }

    .headline-display {
        font-size: var(--font-6xl);
        line-height: 0.85;
    }

    .stadium-list-title {
        font-size: var(--font-5xl);
    }

    /* Stack the country columns: Canada → Mexico → United States, single column. */
    .stadium-list-columns {
        grid-template-columns: 1fr;
    }
}
