/* ===========================================================================
   Exosphere

   The button palette below is not authored here — app.js writes --cta-* from
   events.json, which the build pipeline fills in from the current poster. The
   values in :root are the fallback used before data lands (and if it never
   does). Everything that paints the CTA reads those variables, so the primary
   button and the sticky bar can never drift apart.
   =========================================================================== */

:root {
    --bg: #000;
    --fg: #e6e6e6;
    --fg-dim: rgba(255, 255, 255, 0.62);

    /* Poster-derived, overwritten at runtime. */
    --cta-fill: #00f361;
    --cta-fill-hover: #00f361;
    --cta-label: #0a0a0a;
    --cta-accent: #00e2d2;
    --cta-ring: #02e2d2;
    --cta-ring-width: 0px; /* set to 2px only when the solver asks for a ring */

    --rhythm: clamp(1.5rem, 3vw, 2.75rem);
}

*, *::before, *::after { box-sizing: border-box; }

html {
    height: 100%;
    background: var(--bg);
    scroll-behavior: smooth;
}

body {
    margin: 0;
    padding: 0;
    overflow-x: hidden;
    background: var(--bg);
    color: var(--fg);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

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

#page1 {
    background: url('background1.png') center center / cover no-repeat;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    position: relative;
    width: 100%;
    min-height: 100svh;
}

.logo {
    font-family: 'Libre Barcode 128 Text', monospace;
    font-size: clamp(3rem, 7vw, 9rem);
    text-align: center;
    user-select: none;
    display: flex;
    align-items: center;
    justify-content: center;
    white-space: nowrap;
    width: 100%;
    padding: 0 20px;
    min-height: 1.2em;
    line-height: 1;
    transform: translateY(0.1em);
    color: #fff;
    /* Kerning off so the barcode glyphs keep uniform bar widths — the font
       draws bars per character and letting pairs kern makes the code ragged. */
    letter-spacing: 0;
    font-kerning: none;
    font-feature-settings: "kern" 0;
}

/* Deliberately quiet. It sits directly under a logo that can reach 9rem, so it
   reads as a caption to the mark rather than a second headline. Same type
   vocabulary as .scroll-cue and .spotlight__eyebrow — the page already has one
   voice for small uppercase text and this joins it. */
.tagline {
    margin: 0.9em 0 0;
    padding: 0 1.5rem;
    max-width: 46rem;
    font-family: 'Inconsolata', monospace;
    font-weight: 300;
    font-size: clamp(0.6rem, 1.1vw, 0.82rem);
    text-transform: uppercase;
    letter-spacing: 0.28em;
    line-height: 2;
    text-align: center;
    color: var(--fg-dim);
    user-select: none;
    /* Wrap between phrases on narrow screens rather than forcing one long line
       or breaking a phrase across two. */
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0 0.75em;
}

.tagline__word {
    white-space: nowrap;
}

/* A step dimmer than the words so the phrases read first and the dashes just
   separate them. */
.tagline__sep {
    color: rgba(255, 255, 255, 0.3);
}

.date {
    font-family: 'Inconsolata', monospace;
    font-weight: 400;
    font-size: clamp(0.9rem, 2vw, 1.6rem);
    color: var(--fg);
    letter-spacing: 0.15em;
    text-align: center;
    user-select: none;
    position: absolute;
    bottom: 15vh;
    left: 50%;
    transform: translateX(-50%);
}

/* The hero used to give no hint that a second screen existed. */
.scroll-cue {
    position: absolute;
    bottom: 3vh;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.6em;
    text-decoration: none;
    color: var(--fg-dim);
    font-family: 'Inconsolata', monospace;
    font-size: 0.7rem;
    letter-spacing: 0.35em;
    text-transform: uppercase;
    transition: color 140ms ease;
}
.scroll-cue:hover { color: var(--fg); }
.scroll-cue:focus-visible {
    outline: 2px solid var(--cta-ring);
    outline-offset: 6px;
    border-radius: 4px;
}
.scroll-cue__arrow {
    width: 1px;
    height: 2.5rem;
    background: linear-gradient(to bottom, transparent, currentColor);
    animation: cueDrift 2.4s ease-in-out infinite;
}
@keyframes cueDrift {
    0%, 100% { transform: translateY(0);     opacity: 0.5; }
    50%      { transform: translateY(0.4rem); opacity: 1; }
}

/* ----------------------------------------------------------- spotlight --- */

.spotlight {
    background: var(--bg);
    width: 100%;
    padding: clamp(3rem, 10vh, 8rem) clamp(1rem, 5vw, 4rem);
}

/* Two columns on wide screens: the poster no longer pushes the CTA off-screen.
   This is the single biggest funnel change — previously the button sat below a
   full-width poster inside a 100vh section, i.e. a second scroll past the fold. */
.spotlight__inner {
    max-width: 1180px;
    margin: 0 auto;
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: clamp(2rem, 5vw, 4.5rem);
    align-items: center;
}

.event-poster {
    width: 100%;
    height: auto;
    display: block;
    border: 1px solid rgba(255, 255, 255, 0.08);
}

.spotlight__body { min-width: 0; }

.spotlight__eyebrow {
    margin: 0 0 1.2em;
    font-family: 'Inconsolata', monospace;
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.45em;
    text-transform: uppercase;
    color: var(--cta-accent);
}

.event-title {
    font-family: 'Barlow', sans-serif;
    font-weight: 100;
    font-style: italic;
    font-size: clamp(1.9rem, 4vw, 3.4rem);
    margin: 0 0 0.25em;
    line-height: 1.05;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: #fff;
}

.subtitle {
    font-family: 'Inconsolata', monospace;
    font-weight: 300;
    font-size: clamp(0.85rem, 1.6vw, 1.15rem);
    margin: 0 0 var(--rhythm);
    color: var(--fg-dim);
    letter-spacing: 0.42em;
    text-transform: uppercase;
}

.spotlight__meta {
    display: flex;
    flex-wrap: wrap;
    gap: clamp(1.25rem, 3vw, 2.5rem);
    margin: 0 0 var(--rhythm);
    font-family: 'Inconsolata', monospace;
}
.spotlight__meta div { min-width: 0; }
.spotlight__meta dt {
    font-size: 0.62rem;
    letter-spacing: 0.3em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.4);
    margin-bottom: 0.5em;
}
.spotlight__meta dd {
    margin: 0;
    font-size: clamp(0.95rem, 1.5vw, 1.15rem);
    letter-spacing: 0.1em;
    color: #fff;
}

.ticket-note {
    margin: 1em 0 0;
    font-family: 'Inconsolata', monospace;
    font-size: 0.72rem;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: var(--fg-dim);
}
.ticket-note:empty { display: none; }

/* ================================================================ CTA ===
   Deliberately plain. The old button carried a cyan-to-green gradient (so
   contrast varied across the label), a white text-stroke plus a four-way white
   text-shadow on black text (which lightened the glyph edges and *reduced*
   contrast while imitating font weight), a skew that dragged the text with it,
   and a ::before overlay on z-index:-1 that rendered behind the section and was
   therefore never visible. All of that is gone. Flat fill, real weight, one
   colour, measured contrast.
   ======================================================================= */

.ticket-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.75em;

    padding: 1.05em 2.6em;
    border: none;
    border-radius: 2px;
    cursor: pointer;
    text-decoration: none;

    font-family: 'Inconsolata', 'Courier New', monospace;
    font-size: clamp(1rem, 1.3vw, 1.25rem);
    font-weight: 700;
    letter-spacing: 0.26em;
    text-transform: uppercase;

    background-color: var(--cta-fill);
    color: var(--cta-label);

    /* Only raised when the solver could not win object contrast on hue alone. */
    box-shadow: 0 0 0 var(--cta-ring-width) var(--cta-ring);

    transition: background-color 120ms ease, transform 120ms ease;
}

.ticket-button:hover {
    background-color: var(--cta-fill-hover);
    transform: translateY(-1px);
}

.ticket-button:active { transform: translateY(0); }

/* Previously absent entirely — keyboard users got no indication at all. */
.ticket-button:focus-visible {
    outline: 3px solid var(--cta-ring);
    outline-offset: 3px;
}

.ticket-button--compact {
    padding: 0.8em 1.7em;
    font-size: clamp(0.8rem, 1vw, 0.95rem);
    letter-spacing: 0.2em;
}

.ticket-button[aria-disabled="true"] {
    opacity: 0.5;
    pointer-events: none;
}

/* --------------------------------------------------------- sticky CTA --- */

.sticky-cta {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 50;
    background: rgba(8, 8, 8, 0.92);
    backdrop-filter: blur(10px);
    border-top: 1px solid rgba(255, 255, 255, 0.1);
    transform: translateY(110%);
    transition: transform 220ms cubic-bezier(0.4, 0, 0.2, 1);
}
.sticky-cta.is-visible { transform: translateY(0); }

.sticky-cta__inner {
    max-width: 1180px;
    margin: 0 auto;
    padding: 0.8rem clamp(1rem, 5vw, 4rem);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
}

.sticky-cta__text {
    font-family: 'Inconsolata', monospace;
    font-size: 0.8rem;
    letter-spacing: 0.24em;
    text-transform: uppercase;
    color: var(--fg-dim);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ------------------------------------------------------------ archive --- */

.archive {
    padding: clamp(3rem, 9vh, 7rem) 0 clamp(5rem, 12vh, 9rem);
    border-top: 1px solid rgba(255, 255, 255, 0.08);
}
.archive[hidden] { display: none; }

.archive__header {
    max-width: 1180px;
    margin: 0 auto clamp(1.5rem, 4vw, 2.5rem);
    padding: 0 clamp(1rem, 5vw, 4rem);
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
}

.archive__title {
    margin: 0;
    font-family: 'Inconsolata', monospace;
    font-size: clamp(0.8rem, 1.4vw, 1rem);
    font-weight: 400;
    letter-spacing: 0.42em;
    text-transform: uppercase;
    color: var(--fg-dim);
}

.archive__controls { display: flex; gap: 0.5rem; }

.rail-btn {
    width: 2.4rem;
    height: 2.4rem;
    border: 1px solid rgba(255, 255, 255, 0.18);
    background: transparent;
    color: var(--fg);
    font-size: 0.9rem;
    cursor: pointer;
    border-radius: 2px;
    transition: border-color 120ms ease, color 120ms ease;
}
.rail-btn:hover { border-color: var(--cta-accent); color: var(--cta-accent); }
.rail-btn:focus-visible { outline: 2px solid var(--cta-ring); outline-offset: 2px; }
.rail-btn[disabled] { opacity: 0.3; cursor: default; }

.rail {
    list-style: none;
    margin: 0;
    padding: 0 clamp(1rem, 5vw, 4rem);
    display: flex;
    gap: clamp(1rem, 2vw, 1.75rem);
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    /* Without this the snapport ignores the padding above, so the rail scrolls
       itself by exactly padding-left on load and clips the first poster. */
    scroll-padding-inline: clamp(1rem, 5vw, 4rem);
    scrollbar-width: thin;
    scrollbar-color: rgba(255, 255, 255, 0.2) transparent;
}
.rail:focus-visible { outline: 2px solid var(--cta-ring); outline-offset: 4px; }
.rail::-webkit-scrollbar { height: 6px; }
.rail::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.2); }

.rail__item {
    flex: 0 0 auto;
    width: clamp(210px, 24vw, 300px);
    scroll-snap-align: start;
}

/* Real anchors, so these are crawlable and middle-clickable. */
.rail__link {
    display: block;
    text-decoration: none;
    color: var(--fg);
    transition: transform 140ms ease;
}
.rail__link:hover { transform: translateY(-3px); }
.rail__link:focus-visible { outline: 2px solid var(--cta-ring); outline-offset: 4px; }

.rail__img {
    width: 100%;
    aspect-ratio: 1 / 1;
    object-fit: cover;
    display: block;
    border: 1px solid rgba(255, 255, 255, 0.1);
    filter: grayscale(0.55);
    transition: filter 200ms ease;
}
.rail__link:hover .rail__img { filter: grayscale(0); }

.rail__name {
    margin: 0.9em 0 0.25em;
    font-family: 'Inconsolata', monospace;
    font-size: 0.85rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.rail__date {
    margin: 0;
    font-family: 'Inconsolata', monospace;
    font-size: 0.72rem;
    letter-spacing: 0.2em;
    color: rgba(255, 255, 255, 0.42);
}

/* ----------------------------------------------------------- schedule ---

   Upcoming events read as a calendar, not a gallery. A poster rail makes you
   decode artwork to find a date; a dated row answers "when is the next one"
   without reading anything. Past events keep the rail because there the poster
   *is* the point. */

.schedule-section {
    padding: clamp(3rem, 9vh, 6rem) 0 clamp(3rem, 8vh, 5rem);
    border-top: 1px solid rgba(255, 255, 255, 0.08);
}
.schedule-section[hidden] { display: none; }

.schedule-header {
    max-width: 1180px;
    margin: 0 auto clamp(1.25rem, 3vw, 2rem);
    padding: 0 clamp(1rem, 5vw, 4rem);
}

.schedule-title {
    margin: 0;
    font-family: 'Inconsolata', monospace;
    font-size: clamp(0.8rem, 1.4vw, 1rem);
    font-weight: 400;
    letter-spacing: 0.42em;
    text-transform: uppercase;
    color: var(--cta-accent);
}

.schedule-note {
    margin: 0.6em 0 0;
    font-family: 'Inconsolata', monospace;
    font-size: 0.78rem;
    letter-spacing: 0.12em;
    color: var(--fg-dim);
}

.schedule {
    list-style: none;
    max-width: 1180px;
    margin: 0 auto;
    padding: 0 clamp(1rem, 5vw, 4rem);
}

.schedule__item + .schedule__item { margin-top: 0.6rem; }

/* The whole row is the anchor — a big target beats a small "details" link. */
.schedule__link {
    display: grid;
    grid-template-columns: auto auto minmax(0, 1fr) auto;
    align-items: center;
    gap: clamp(1rem, 2.5vw, 1.9rem);
    padding: clamp(1rem, 2vw, 1.4rem) clamp(1rem, 2.2vw, 1.6rem);
    text-decoration: none;
    color: var(--fg);
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 2px;
    background: rgba(255, 255, 255, 0.015);
    transition: border-color 140ms ease, background-color 140ms ease;
}
.schedule__link:hover {
    border-color: var(--cta-accent);
    background: rgba(255, 255, 255, 0.045);
}
.schedule__link:focus-visible {
    outline: 2px solid var(--cta-ring);
    outline-offset: 3px;
}

/* The date block is the anchor of the row — biggest thing in it, read first. */
.schedule__when {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-width: 3.9rem;
    font-family: 'Inconsolata', monospace;
    line-height: 1;
}
.schedule__month {
    font-size: 0.68rem;
    letter-spacing: 0.24em;
    text-transform: uppercase;
    color: var(--cta-accent);
}
.schedule__day {
    font-size: clamp(1.5rem, 2.6vw, 2rem);
    font-weight: 600;
    margin: 0.12em 0;
}
.schedule__weekday {
    font-size: 0.6rem;
    letter-spacing: 0.2em;
    color: rgba(255, 255, 255, 0.4);
}

/* Big enough to actually read the artwork. 3/4 matches the portrait crop
   Eventbrite posters come in, so the whole poster shows instead of a square
   punched out of the middle of it. */
.schedule__thumb {
    width: clamp(96px, 11vw, 150px);
    aspect-ratio: 3 / 4;
    object-fit: cover;
    display: block;
    border: 1px solid rgba(255, 255, 255, 0.14);
    background: rgba(255, 255, 255, 0.03);
}

.schedule__body { min-width: 0; }

.schedule__name {
    margin: 0;
    font-family: 'Inconsolata', monospace;
    font-size: clamp(0.85rem, 1.5vw, 1.05rem);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.schedule__meta {
    margin: 0.35em 0 0;
    font-family: 'Inconsolata', monospace;
    font-size: 0.72rem;
    letter-spacing: 0.14em;
    color: rgba(255, 255, 255, 0.45);
}

/* Deliberately an outline, not a filled button. The solid CTA belongs to the
   spotlight alone — two filled buttons on one screen split the decision. */
.schedule__action {
    font-family: 'Inconsolata', monospace;
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    white-space: nowrap;
    padding: 0.7em 1.3em;
    border: 1px solid var(--cta-accent);
    color: var(--cta-accent);
    border-radius: 2px;
    transition: background-color 140ms ease, color 140ms ease;
}
.schedule__link:hover .schedule__action {
    background: var(--cta-accent);
    color: #0a0a0a;
}
.schedule__action.is-sold-out {
    border-color: rgba(255, 255, 255, 0.22);
    color: rgba(255, 255, 255, 0.45);
}
.schedule__link:hover .schedule__action.is-sold-out {
    background: transparent;
    color: rgba(255, 255, 255, 0.45);
}

/* ------------------------------------------------------------ contact --- */

.contact {
    border-top: 1px solid rgba(255, 255, 255, 0.08);
    /* Clears the sticky bar so the last line is never trapped underneath it. */
    padding: clamp(3rem, 8vh, 5rem) 0 clamp(5rem, 12vh, 7rem);
}

.contact__inner {
    max-width: 1180px;
    margin: 0 auto;
    padding: 0 clamp(1rem, 5vw, 4rem);
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: clamp(1.25rem, 3vw, 1.9rem);
}

.contact__label {
    margin: 0;
    font-family: 'Inconsolata', monospace;
    font-size: clamp(0.8rem, 1.4vw, 1rem);
    letter-spacing: 0.42em;
    text-transform: uppercase;
    color: var(--fg-dim);
}

.contact__links {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: clamp(1rem, 3vw, 2.5rem);
}

.contact__link {
    display: inline-flex;
    align-items: center;
    gap: 0.7em;
    padding: 0.55em 0.2em;
    text-decoration: none;
    color: var(--fg);
    font-family: 'Inconsolata', monospace;
    font-size: clamp(0.78rem, 1.2vw, 0.95rem);
    letter-spacing: 0.16em;
    transition: color 140ms ease;
}
.contact__link:hover { color: var(--cta-accent); }
.contact__link:focus-visible {
    outline: 2px solid var(--cta-ring);
    outline-offset: 4px;
    border-radius: 2px;
}

/* Stroked icons so they sit at the same visual weight as the type beside them
   and pick up the poster accent on hover along with the label. */
.contact__icon {
    width: 1.15em;
    height: 1.15em;
    flex: 0 0 auto;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.6;
    stroke-linecap: round;
    stroke-linejoin: round;
}
.contact__icon .is-filled { fill: currentColor; stroke: none; }

.contact__note {
    margin: 0;
    font-family: 'Inconsolata', monospace;
    font-size: 0.7rem;
    letter-spacing: 0.24em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.3);
}

/* ---------------------------------------------------------- responsive --- */

@media (max-width: 860px) {
    .spotlight__inner {
        grid-template-columns: minmax(0, 1fr);
        gap: clamp(1.5rem, 6vw, 2.5rem);
    }
    /* Poster first, then the pitch, then the button — but the whole block is
       now short enough that the CTA is reachable in one scroll. */
    .spotlight__media { order: 1; }
    .spotlight__body  { order: 2; }
    .event-poster { max-width: 480px; margin: 0 auto; }
    .ticket-button { width: 100%; }
    .date { bottom: 18vh; }
}

@media (max-width: 700px) {
    /* Poster on the left, date and details stacked beside it, action full width
       underneath. Four columns on a phone squeezes the title to an ellipsis and
       shrinks the tap target — but the poster stays, it is half the point. */
    .schedule__link {
        grid-template-columns: auto minmax(0, 1fr);
        grid-template-areas:
            'poster when'
            'poster body'
            'action action';
        align-items: start;
        row-gap: 0.55rem;
        column-gap: 1rem;
    }
    .schedule__thumb { grid-area: poster; width: clamp(84px, 26vw, 120px); }
    /* The poster spans both text rows and is taller than they are, so the spare
       height is split between them. Pull each toward the shared edge or the
       date and the title drift to opposite ends of the card. */
    .schedule__when  { grid-area: when; align-self: end; }
    .schedule__body  { grid-area: body; align-self: start; }
    .schedule__action { grid-area: action; text-align: center; padding: 0.85em 1rem; }

    /* Horizontal on mobile so the date sits on one line above the title rather
       than pushing the whole row tall. */
    .schedule__when {
        flex-direction: row;
        align-items: baseline;
        justify-content: flex-start;
        gap: 0.5em;
        min-width: 0;
    }
    .schedule__day { font-size: 1.35rem; margin: 0; }

    .schedule__name { white-space: normal; }
}

@media (max-width: 480px) {
    .subtitle { letter-spacing: 0.3em; }
    .event-title { letter-spacing: 0.12em; }
    .sticky-cta__text { display: none; }
    .sticky-cta__inner { justify-content: stretch; }
    .ticket-button--compact { width: 100%; }
}

/* ------------------------------------------------------ reduced motion --- */

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
    .ticket-button:hover, .rail__link:hover { transform: none; }
}
