/* universallynull.com — link page and admin. Uses only tier-2 tokens from
   tokens.css (shared with production.universallynull.com). House rules carry
   over: no text over photos, IBM Plex Mono only for numbers and dates. */

/* This page's accents. Blue and red tint the hero photo (so the promoter
   site reads apart from production's blue/pink/green); red also lights the
   alerts button. */
:root {
  --ul-blue: #2B3BFF;
  --ul-red: #FF1E3C;
}

*, *::before, *::after { box-sizing: border-box; }
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: .01ms !important; }
}

body {
  margin: 0;
  background: var(--surface);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}
img { max-width: 100%; height: auto; display: block; }
a { color: var(--text); text-underline-offset: 3px; }
:where(a, button, input, textarea, select, summary):focus-visible {
  outline: 2px solid var(--focus); outline-offset: 2px; border-radius: var(--radius);
}
ul { list-style: none; margin: 0; padding: 0; }

/* ---------- Header ----------
   Sticky, like production's masthead: logo on the left, the production /
   rental link on the right. 64px tall. */
.masthead {
  position: sticky; top: 0; z-index: 50;
  background: var(--surface); border-bottom: 1px solid var(--border);
}
.masthead-in {
  max-width: 1200px; margin-inline: auto; padding-inline: 16px;   /* production's shell: 1200px including its gutters */
  height: 64px; display: flex; align-items: center; justify-content: space-between; gap: 1rem;
}
@media (min-width: 960px) { .masthead-in { padding-inline: var(--gutter); } }
.wordmark { display: block; line-height: 0; flex: none; }
.wordmark img { height: 44px; width: auto; }   /* production: 44 / 30 (≤560px) / 26 (≤360px) */
.nav-cta {
  display: inline-flex; align-items: center; white-space: nowrap;
  padding: .55rem .9rem; border: 1px solid var(--border-strong); border-radius: var(--radius);
  font-size: .9rem; font-weight: 600; text-decoration: none;
  transition: border-color .15s ease, background-color .15s ease;
}
.nav-cta:hover { border-color: var(--text); background: var(--surface-raised); }
@media (max-width: 560px) { .wordmark img { height: 30px; } }
@media (max-width: 400px) { .nav-cta { padding: .5rem .7rem; font-size: .82rem; } }
@media (max-width: 360px) { .wordmark img { height: 26px; } }

/* Phones: the photo fills most of the first screen with logo, bio and socials
   on its darkened bottom edge; alerts + events follow below it (a panel over
   the photo would hide most of it at this width). Desktop moves the shows
   onto the photo as a panel on the right. */
.hero {
  position: relative; isolation: isolate;
  display: grid; grid-template-areas: "top" "shows";
}
.hero-photo, .hero::before, .intro { grid-area: top; }
.hero-photo { z-index: -2; margin: 0; position: relative; }
.hero-photo img {
  width: 100%; height: 100%; object-fit: cover; object-position: 40% 50%;
  filter: grayscale(1) contrast(1.12) brightness(.9);
}
/* Colour grade, built like production's: the greyscale photo is multiplied
   by a blue-to-red sweep. */
.hero-photo::after {
  content: ""; position: absolute; inset: 0; mix-blend-mode: multiply;
  background: linear-gradient(115deg, var(--ul-blue) 25%, var(--ul-red) 75%);
}
.hero::before {
  content: ""; z-index: -1;
  background: linear-gradient(to top, var(--surface) 0%, rgb(14 14 15 / .6) 25%, rgb(14 14 15 / .5) 55%, rgb(14 14 15 / .2) 100%);
}
/* Phones: the first screen ends with the Sign up / Mixes / Merch row just
   above the browser's bottom bar (svh = the screen with its bars showing):
   the hero is the screen minus the 64px header and ~3.75rem for that row.
   The lockup starts at production's height (13rem down) where there's room,
   higher on shorter phones so the row still fits. */
.intro {
  min-height: calc(100svh - 64px - 3.75rem); grid-template-rows: auto auto auto 1fr auto;
  padding: min(13rem, 22svh) 16px 1.75rem;
}
.follow-row { grid-row: 5; }
.tagline, .blurb { text-wrap: balance; }
.blurb { margin: .5rem 0 0; color: var(--text-muted); }
/* Title and description under the logo, styled like production's hero lede
   pair ("When your event needs serious sound." then its paragraph): same size,
   the first semibold in full white, the second regular in muted grey. */
.tagline, .blurb { font-size: clamp(1.05rem, 1.6vw, 1.22rem); line-height: 1.6; max-width: 44ch; }
.tagline { margin: 1rem 0 0; font-weight: 600; color: var(--text); }
.scroll-cue { display: none; }
.shows {
  grid-area: shows; width: 100%; max-width: 720px; margin-inline: auto;
  padding: .75rem 16px 0;
}
.page {
  max-width: 720px; margin-inline: auto; padding-inline: 16px;
  display: grid; gap: clamp(2rem, 5vw, 2.75rem);
  padding-block: clamp(2rem, 5vw, 2.75rem) 2rem;
}
.shows, .more { display: grid; gap: clamp(2rem, 5vw, 2.75rem); align-content: start; min-width: 0; }

/* ---------- Intro ---------- */
.intro { display: grid; justify-items: center; text-align: center; gap: .9rem; }
/* Hero lockup, as on production's home page: the braces mark beside a
   stacked "It's Null / or nothing". Sized like production's (clamp(3.2rem,
   9vw, 7.5rem)) but capped by the column width so it never runs out of it. */
.intro { container-type: inline-size; }
.hero-title {
  display: flex; align-items: center; gap: .3em; justify-self: stretch;
  font-size: min(clamp(3.2rem, 9vw, 7.5rem), 14.5cqi);
}
.hero-title h1 {
  margin: 0; flex: none; font-size: 1em; font-weight: 600; line-height: .9; letter-spacing: -.035em;
  text-transform: uppercase; text-align: left;
}
.hero-title h1 > span { display: block; }
/* "or" set light and small, its cap height on the line's (as production). */
.hero-title h1 .lt { font-weight: 400; font-size: .6em; letter-spacing: 0; vertical-align: .465em; }
.hero-mark { flex: none; height: calc(2 * .9em); width: auto; aspect-ratio: 251 / 397; fill: var(--text); }
/* Phones: exactly production's mobile size (3.2rem), only easing off on
   screens too narrow for it (the lockup is ~6.8em wide, plus the gutters). */
@media (max-width: 959.98px) {
  .hero-title { font-size: min(3.2rem, calc((100vw - 24px) / 6.8)); }
}
/* "Follow us" + icons. Same mono label as the section headings. */
.follow { display: grid; justify-items: center; gap: .35rem; }
.follow-h { margin: 0; font-family: var(--font-num); font-weight: 500; font-size: .8rem; color: var(--text); }
.socials { display: flex; gap: .35rem; }
.socials a {
  display: grid; place-items: center; width: 2.75rem; height: 2.75rem;
  border-radius: var(--radius); color: var(--text);
}
.socials a:hover { background: rgb(255 255 255 / .1); }
.socials svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.6; }
.socials .fill, .socials .dot { fill: currentColor; stroke: none; }

/* ---------- Section label (mono index line, as on production) ---------- */
.eyebrow {
  font-family: var(--font-num); font-weight: 500; font-size: .8rem; color: var(--text-muted);
  margin: 0 0 .9rem; display: flex; align-items: center; gap: .75rem;
}
.eyebrow::before { content: ""; width: 1.5rem; height: 1px; background: var(--border-strong); }

/* ---------- Link rows ---------- */
.links { display: grid; gap: .6rem; }
.link {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  min-height: 3.6rem; padding: .85rem 1.15rem;
  border: 1px solid var(--border-strong); border-radius: var(--radius);
  font-weight: 600; text-decoration: none;
  transition: background-color .15s ease, border-color .15s ease;
}
.link::after { content: "\2192"; font-weight: 400; color: var(--text-muted); flex: none; }
.link:hover { background: var(--surface-raised); border-color: var(--text); }

/* High priority links: compact buttons side by side (two or three to a row,
   wrapping), right under the events. */
.links.priority { display: flex; flex-wrap: wrap; gap: .6rem; }
.links.priority li { flex: 1 1 9.5rem; display: flex; }   /* a leftover button stretches to fill its row */
.links.priority li .link { flex: 1; }
/* Phones: the high priority buttons go above the events (under the alerts
   button); desktop keeps them under the events in the hero panel. */
@media (max-width: 959.98px) {
  .shows > .links.priority { order: 1; }
  .shows > section { order: 2; }
}
.links.priority .link {
  min-height: 0; justify-content: center; text-align: center; gap: .5rem;
  padding: .75rem 1rem; font-size: .95rem; line-height: 1.25;
}
.links.priority .link::after { font-size: .9em; }

/* ---------- Events ---------- */
.events { display: grid; border-top: 1px solid var(--border); }
/* More than three events: the list scrolls (height set by a small script to
   end at the third event; this max-height is the no-script fallback). */
.events.is-capped {
  max-height: 20rem; overflow-y: auto; overscroll-behavior: contain;
  scrollbar-width: thin; scrollbar-color: var(--border-strong) transparent;
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 40px), transparent);
          mask-image: linear-gradient(to bottom, #000 calc(100% - 40px), transparent);
}
.events.is-capped.at-end { -webkit-mask-image: none; mask-image: none; }
.events.is-capped::-webkit-scrollbar { width: 6px; }
.events.is-capped::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 3px; }
.events.is-capped:focus-visible { outline: 2px solid var(--focus); outline-offset: 4px; }
.event {
  display: grid; grid-template-columns: 3.4rem 1fr auto; align-items: center; gap: 1rem;
  padding: 1rem .25rem; border-bottom: 1px solid var(--border); text-decoration: none;
}
.events li { border-bottom: 1px solid var(--border); }
.events li .event { border-bottom: 0; }
a.event:hover { background: var(--surface-raised); }
.when { display: grid; justify-items: center; font-family: var(--font-num); line-height: 1.1; }
.when .mon, .when .dow { font-size: .72rem; color: var(--text-muted); text-transform: uppercase; }
.when .day { font-size: 1.55rem; font-weight: 500; }
.what { display: grid; gap: .2rem; min-width: 0; }
.what .title { font-weight: 600; overflow-wrap: anywhere; }
.what .meta { font-size: .9rem; color: var(--text-muted); }
.go { font-size: .9rem; color: var(--text-muted); white-space: nowrap; }
a.event .go::after { content: " \2192"; }
.tag {
  font-size: .78rem; padding: .2rem .5rem; border: 1px solid var(--border-strong);
  border-radius: var(--radius); color: var(--text-muted); white-space: nowrap;
}

.foot { text-align: center; color: var(--text-muted); font-size: .85rem; }
.foot p { margin: 0; }

/* ---------- Desktop: hero ----------
   The photo fills the top of the screen. Logo and bio sit bottom-left on a
   dark gradient; the alerts link and shows sit on the right in a solid-ish
   panel, so no text lands straight on the busy photo. */
@media (min-width: 960px) {
  .hero {
    grid-template-areas: none;
    /* Same frame as production's hero: a 1200px column with its gutter, the
       hero filling the screen, content centred top to bottom. */
    min-height: min(calc(100svh - 65px), 62rem);   /* fills the screen under the header (64px + 1px border) */
    padding: 5rem max(var(--gutter), calc((100vw - 1200px) / 2 + var(--gutter)));
    grid-template-columns: minmax(0, 1fr) minmax(380px, 460px);
    align-items: center; column-gap: 4rem;
  }
  .hero-photo, .hero::before, .intro, .shows { grid-area: auto; }
  .hero-photo { position: absolute; inset: 0; }
  .hero::before {
    position: absolute; inset: 0;
    background:
      linear-gradient(to top, var(--surface) 0%, rgb(14 14 15 / 0) 38%),
      linear-gradient(to right, rgb(14 14 15 / .88) 0%, rgb(14 14 15 / .45) 45%, rgb(14 14 15 / .2) 100%);
  }
  .intro { justify-items: start; text-align: left; align-self: center; min-height: 0; padding: 0; grid-template-rows: none; gap: 0; }
  .follow-row { grid-row: auto; }
  .follow { justify-items: start; }
  .follow-h { margin-left: 0; }
  .tagline { margin: 1.75rem 0 0; }   /* production: 1.75rem under the title */
  .blurb { margin-top: 1rem; }        /* production: 1rem between the two */
  .follow-row { margin-top: 2rem; }
  /* Down arrow at the foot of the hero, as on production. */
  .scroll-cue {
    display: block; position: absolute; left: 50%; bottom: 1.5rem; width: 1.6rem; height: 1.6rem; margin-left: -.8rem;
    fill: none; stroke: var(--text-muted); stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round;
    animation: scroll-cue 2.2s ease-in-out infinite;
  }
  .socials { margin-left: -.7rem; }

  .shows {
    align-self: center; gap: 1.75rem; padding: 1.75rem; max-width: none; margin: 0;
    background: rgb(14 14 15 / .86);
    -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
    border: 1px solid var(--border); border-radius: var(--radius);
  }
  .shows .link { min-height: 3.75rem; }

  .page { max-width: calc(1200px + 2 * var(--gutter)); padding: 3.5rem var(--gutter) 2.5rem; gap: 3.5rem; }
  .more { grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); column-gap: 2.5rem; }
}

/* ---------- Alerts button (first top link) ----------
   Glows red on page load, then fades out completely; wiggles once a minute
   (first at the one-minute mark). Both stop under reduced motion. */
.link-callout {
  animation:
    callout-glow 2.6s ease-out .4s both,
    callout-wiggle 60s linear 60s infinite;
}
@keyframes callout-glow {
  0%   { box-shadow: 0 0 0 0 transparent; border-color: var(--border-strong); }
  35%  { box-shadow: 0 0 34px 6px color-mix(in srgb, var(--ul-red) 70%, transparent); border-color: var(--ul-red); }
  100% { box-shadow: 0 0 0 0 transparent; border-color: var(--border-strong); }   /* fully gone once it's played */
}
/* 60s cycle: the wiggle is the first ~1.2s, then it rests. */
@keyframes callout-wiggle {
  0%    { transform: rotate(0); }
  0.4%  { transform: rotate(-2deg); }
  0.8%  { transform: rotate(2deg); }
  1.2%  { transform: rotate(-1.5deg); }
  1.6%  { transform: rotate(1deg); }
  2%, 100% { transform: rotate(0); }
}
@media (prefers-reduced-motion: reduce) { .link-callout { animation: none; } }

/* ---------- No link sections ----------
   With nothing below the hero, the page is one screen: the hero takes what's
   left under the header and the copyright line sits at the bottom of it (no
   scroll arrow, which the template drops). On phones the stacked content is
   usually taller than the screen, and the footer simply follows it. */
body.no-more main { min-height: calc(100svh - 65px);  /* 64px header + its 1px border */ display: flex; flex-direction: column; }
body.no-more .hero { flex: 1 0 auto; }
body.no-more .page { padding-block: 1.25rem; }
@media (min-width: 960px) {
  body.no-more .hero { min-height: 0; }
  body.no-more .page { padding-block: 1.25rem; }
}

.label-short { display: none; }

/* ---------- Phones: production-style hero text ----------
   Title and description left-aligned, like production's hero; Follow us
   and the icons centred.
   Under the photo, the alerts sign-up and the high priority buttons share one
   row (they're flattened into the panel's flex row), then the events.
   Desktop is unchanged. */
@media (max-width: 959.98px) {
  .tagline, .blurb { justify-self: stretch; text-align: left; text-wrap: pretty; }
  .follow-row { justify-self: center; }   /* Follow us + icons stay centred */
  /* Follow us sits halfway between the description and the buttons below:
     it spans the stretchy space at the bottom of the photo, centred, and
     the hero and the buttons give up their own padding where they meet. */
  .follow-row { grid-row: 4 / 6; align-self: center; margin-block: calc(2rem - .9rem) 2rem; }   /* at least 2rem each side (the grid gap supplies .9rem above) */
  .intro { padding-bottom: 0; }
  .shows { padding-top: 0; }

  .shows { display: flex; flex-wrap: wrap; gap: .6rem; }
  .shows > .links { display: contents; }
  .shows > .links > li { order: 0; flex: 1 1 0; min-width: 0; display: flex; }
  .shows > .links.priority > li { order: 1; }
  .shows > .links > li > .link {
    flex: 1; min-height: 0; justify-content: center; text-align: center; gap: .4rem;
    padding: .75rem .6rem; font-size: .9rem; line-height: 1.25;
  }
  .shows > section { order: 2; flex: 0 0 100%; margin-top: 1.4rem; }
  /* The alerts button reads just "Sign up" on phones (full text stays as its label for screen readers). */
  .link-callout .label-full { display: none; }
  .link-callout .label-short { display: inline; }
}
