/* ==========================================================================
   style.css  -  the look of the website
   --------------------------------------------------------------------------
   How CSS works, in one sentence:
     You pick something on the page (a "selector", like .button) and then
     describe how it should look inside { curly brackets }.

   "Mobile first" means: the rules at the top are made for a PHONE.
   At the bottom, a "@media (min-width: ...)" block adds changes that
   only apply when the screen is wider (tablet / computer).

   Sections in this file:
     1. Colors and settings (easy to change in one place)
     2. Basic page setup
     3. Header (logo)
     4. Buttons
     5. Upcoming event
     6. stay.connect.ed
     7. Footer, 7b. Sound on/off button
     9. Visual effects (grain, glow, flash, scroll reveal)
     8. Wider screens (700px+), 8b. Two-column event layout (900px+)
   ========================================================================== */


/* --------------------------------------------------------------------------
   1. COLORS AND SETTINGS
   Variables are named boxes for values. Write them once here, use them
   everywhere with var(--name). To change the palette, edit only this block.
   -------------------------------------------------------------------------- */
:root {
  /* Backgrounds */
  --color-background: #000000;       /* pure black */
  --color-background-raised: #171717;/* very slightly lighter, used for the button */

  /* Text (all pass the readability test on the black background) */
  --color-text: #f5f5f5;             /* off-white for all main text */
  --color-text-muted: #b8b8b8;       /* slightly quieter text (still very readable) */

  /* Thin lines and borders */
  --color-line: #2e2e2e;             /* faint divider lines between sections */
  --color-border: #6e6e6e;           /* button border (subtle grey) */

  /* Fonts. The browser tries the first font; if the visitor does not
     have it, it moves on to the next one in the list. */
  --font-headings: "Helvetica Neue", Helvetica, Arial, sans-serif;
  --font-body: "Courier New", "Lucida Sans Typewriter", monospace;
  --font-buttons: "Raleway", sans-serif;

  /* Maximum width of the text column, so lines never get too long */
  --content-width: 38rem;

  /* Maximum width shared by the logo and the flyer, so both line up.
     Change this one number to resize both together. */
  --flyer-max-width: 520px;

  /* Length of one heartbeat. The glow AND the flyer both use this same
     number, which is what keeps them pulsing in sync. Change it here to
     speed up or slow down both together (0.9s is about 67 beats per minute). */
  --heartbeat-duration: 0.9s;
}


/* --------------------------------------------------------------------------
   2. BASIC PAGE SETUP
   -------------------------------------------------------------------------- */

/* Make width calculations predictable: padding and borders count inside
   an element's width instead of being added on top of it. */
*,
*::before,
*::after {
  box-sizing: border-box;
}

/* The HTML "hidden" attribute must always win over other display rules.
   (Our script uses it to show or hide the upcoming event.) */
[hidden] {
  display: none !important;
}

/* The page background is set on BOTH "html" (the whole browser window,
   including areas beyond the content) and "body", as solid pure black
   (#000000), written out directly with no transparency. */
html {
  background: #000000;
}

body {
  margin: 0;                        /* remove the browser's default outer gap */
  background: #000000;
  color: var(--color-text);
  font-family: var(--font-body);    /* typewriter style for normal text */
  font-size: 1rem;                  /* 1rem = the visitor's default size (usually 16px) */
  line-height: 1.7;                 /* space between lines, for easy reading */

  /* Make the page at least as tall as the screen, so the footer
     stays at the bottom even if the content is short. */
  min-height: 100vh;
  display: flex;
  flex-direction: column;

  /* No text selection anywhere by default: dragging the mouse or
     long-pressing on a phone does not highlight text. Everything inside
     the body inherits this. The "-webkit-" line is the same rule for
     Safari, which needs its own version. The one exception (the address)
     is set in section 5. */
  -webkit-user-select: none;
  user-select: none;

  /* Ordinary arrow cursor over text (no I-beam) */
  cursor: default;
}

/* Links and buttons keep the pointing-hand cursor, so it is clear they
   can be clicked. (This only changes the cursor, not selection.) */
a,
button {
  cursor: pointer;
}

/* The main content grows to fill the free space (pushes footer down) */
main {
  flex: 1;
}

/* All headings (h1 to h4) use Helvetica */
h1, h2, h3, h4 {
  font-family: var(--font-headings);
  font-weight: 700;
  line-height: 1.15;
  margin: 0 0 1rem;
}

p {
  margin: 0 0 1rem;
}

/* Links: same color as the text, with an underline, so they are obvious */
a {
  color: inherit;
  text-underline-offset: 0.2em;
}

/* Keyboard users see a clear outline on whatever is selected */
a:focus-visible {
  outline: 2px solid var(--color-text);
  outline-offset: 4px;
}

/* A reusable "container": centers content and adds side space on phones */
.container {
  width: 100%;
  max-width: var(--content-width);
  margin: 0 auto;
  padding: 0 1.5rem;
  text-align: center;               /* everything on this page is centered */
}


/* --------------------------------------------------------------------------
   3. HEADER
   Just the logo, centered. White logo on black: always visible.
   -------------------------------------------------------------------------- */
.site-header {
  padding: 2rem 1.5rem 1.5rem;
  text-align: center;

  /* Keeps the logo drawn ABOVE the red glow that spreads out from behind
     the flyer (see section 5). */
  position: relative;
  z-index: 1;
}

/* The logo link: a box as wide as the flyer's box (never wider than the
   screen), centered with "auto" side margins. */
.site-logo {
  display: block;
  max-width: var(--flyer-max-width);
  margin: 0 auto;
}

/* The logo image fills its box. The height follows automatically, so the
   wordmark keeps its proportions (wide and thin) at every screen size. */
.site-logo img {
  display: block;
  width: 100%;
  height: auto;
}


/* --------------------------------------------------------------------------
   3b. ENTRY SCREEN
   A full-screen black cover shown when the page opens. The logo starts in
   the middle of it, with the ENTER button below. Pressing ENTER glides the
   logo up into the header, fades the cover away, and script.js then removes
   the cover from the page.

   Classes that script.js and the inline script in the HTML put on the
   whole page ("html"):
     js-enabled  = JavaScript is running
     is-entry    = the entry screen is active (page hidden, no scrolling)
     is-entering = the logo is on its way to the header
   -------------------------------------------------------------------------- */

/* Without JavaScript: the entry screen is just an ordinary block at the top
   of the page holding the logo, and the ENTER button is hidden. */
.entry-screen {
  padding: 2rem 1.5rem 1.5rem;
  text-align: center;
}

.entry-button-wrap {
  display: none;
}

/* With JavaScript: a black cover over the whole screen. Its z-index (40) is
   above the page, and below the film grain (50), so the grain also covers it. */
.js-enabled .entry-screen {
  position: fixed;
  inset: 0;                         /* shorthand for top, right, bottom, left = 0 */
  z-index: 40;
  display: flex;
  align-items: center;              /* centered up-down ... */
  justify-content: center;          /* ... and left-right */
  padding: 0;
  background: #000000;
  transition: opacity 0.5s ease;    /* the fade-out at the end (keep in sync with PAGE_REVEAL_MS in script.js) */
}

/* The logo's holder has the same side spacing as the header (1.5rem), so the
   logo is exactly the same width here as in the header. */
.js-enabled .entry-logo-slot {
  position: relative;
  width: 100%;
  padding: 0 1.5rem;
}

/* The two ENTER buttons hang BELOW the logo without taking up room in the
   layout ("position: absolute"). That way the logo stays exactly centered,
   and it does not shift when the buttons disappear.

   - "display: flex" (with the default direction, a row) puts the two buttons
     SIDE BY SIDE at every screen width, phones included. There is no stacked
     layout any more.
   - "justify-content: center" centers the pair under the logo.
   - "gap: 1px" leaves exactly 1 pixel between the left button's right edge
     and the right button's left edge. (Each button's red shape fills its
     whole box, so the visible gap is 1px too.)
   - "align-items: flex-start" keeps both buttons level at the top.
   - The side padding is small (0.5rem = 8px) because on a 320px phone every
     pixel counts. It grows back to 1.5rem on wide screens (see the media
     query further down). */
.js-enabled .entry-button-wrap {
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  justify-content: center;
  gap: 1px;
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  margin-top: 2.5rem;
  padding: 0 0.5rem;
}

/* "position: relative" makes each button the anchor for its splatter layer. */
.entry-button-wrap .entry-button {
  position: relative;
}

/* SIZE OF THE BUTTONS. Both labels stay on ONE line, side by side, on every
   phone from about 320px wide upward. To make that possible the text, the
   letter spacing and the padding all shrink together on narrow screens:

   - font-size: "clamp(smallest, preferred, largest)". The preferred size is
     3.5vw (3.5% of the screen width), so the text grows and shrinks with the
     screen. It never goes below 0.7rem (11.2px, still readable in bold
     capitals), and never above 1.2rem (19.2px, the size on big screens).
     Examples: 320px wide -> 11.2px, 360px -> 12.6px, 390px -> 13.7px, and
     from about 550px upward -> 19.2px.
   - letter-spacing: 0.06em (a little tighter than on big screens).
   - padding: written in "em", which means "times the button's own text
     size", so the padding shrinks in proportion to the text. Left and right
     0.6em; top 0.9em; bottom 0.9em plus the 18px room for the splatter
     (see the next note).
   - white-space: nowrap = never break the label onto a second line.

   The measurements behind these numbers: the two labels together are about
   23em wide, plus 2.4em of side padding, plus 8px of invisible borders: at
   320px wide that is 283px of the 303px available (320 minus the 16px of
   side padding and the 1px gap). At 360px it is 319px of 343px.

   NOTE: these rules are written with THREE classes, on purpose. The general
   ".button.button-ticket" rule (two classes) is further down in this file,
   and would win a tie. Three classes always win. (An earlier version of this
   font-size lost that tie, so it never applied.) */
.button.button-ticket.entry-button {
  font-size: clamp(0.7rem, 3.5vw, 1.2rem);
  letter-spacing: 0.06em;
  white-space: nowrap;
  padding: 0.9em 0.6em calc(0.9em + 18px);
}
/* BLOOD SPLATTER BUTTONS. The button's red shape is not a rectangle: its top
   and sides are straight and clean (so the text stays easy to read), but its
   bottom edge is an uneven splatter, with rounded blobs and sharper drips.

   How it is built:
   - The button itself is see-through (no background, invisible border). It
     keeps its normal rectangle, so the keyboard focus outline (drawn around
     the whole box) is not cut off, and clicking works everywhere on it.
   - The red shape is a separate layer BEHIND the text: the "::before"
     (a box that CSS creates inside the button, filling all of it, drawn
     under the text thanks to "z-index: -1"). That layer is what gets cut
     into the splatter shape with "clip-path".
   - Extra room at the bottom: "padding-bottom" adds 18px under the text.
     The splatter's body ends 18px above the box's bottom, and only the
     drips and blobs reach into those last 18px. So the text has the same
     space above and below it as before.
   - The outline: "clip-path: polygon(...)" is a list of points; everything
     outside the outline is cut away. Each point is "how far across (as a
     percentage of the width)" and "how far down". The down values are
     written as "calc(100% - 9px)" = "9 pixels above the bottom", so the
     drips reach the same number of pixels on any button width. There are
     two outlines, one for each button (they follow this note). Each is
     uneven on purpose on its OUTER side and calm on its INNER side.   - Depth: the fill is brick red (#9e2b24) with two soft shadings laid over
     it. One darkens the edges, the other darkens toward the bottom, so the
     drips and tips look deeper and thicker.
   - On hover / keyboard focus the fill sinks to the darker red (#6e1e19),
     with the same slow 0.5 second change as GET YOUR TICKET.
   - The two rules with ":hover" and ":focus-visible" are needed to stop the
     general button styles from painting a plain rectangle on hover.
   - The falling drops (script.js) start from the tips of the outlines: the
     places listed in SPLATTER_TIPS_SIDE_BY_SIDE (in script.js) match the
     deepest points of the outlines. If you change an outline, change that
     list. */
.button.button-ticket.entry-button,
.button.button-ticket.entry-button:hover,
.button.button-ticket.entry-button:focus-visible {
  background: transparent;
  border-color: transparent;
}

.button.button-ticket.entry-button::before {
  content: "";
  position: absolute;
  inset: -2px;                       /* also covers the 2px invisible border, so the shape fills the whole box */
  z-index: -1;                       /* behind the button's text */
  pointer-events: none;
  background-color: #9e2b24;
  background-image:
    radial-gradient(ellipse at 50% 30%, transparent 55%, rgba(0, 0, 0, 0.28) 100%),
    linear-gradient(to bottom, transparent 62%, rgba(0, 0, 0, 0.4) 100%);
  transition: background-color 0.5s ease;
}

.button.button-ticket.entry-button:hover::before,
.button.button-ticket.entry-button:focus-visible::before {
  background-color: #6e1e19;
}

/* THE TWO OUTLINES. The buttons sit side by side at every screen width, and
   each has its own shape. They are different, but related:
   - OUTER sides (the left button's left, the right button's right): organic
     splatter, with rounded blobs and sharp drips. The two buttons use
     different arrangements of them, so the pair does not look like a
     mirror-image copy.
   - INNER sides (facing each other, 1px apart): calm. The organic bottom edge
     fades out over the inner ~40% of the button into an even, gently curved
     edge, and the two inner corners are cleanly rounded (10px at the top,
     9px at the bottom). So the pair reads as two related pieces, not two
     random ones.
   - Each outline is a list of points, as explained above (77 points for the
     left button, 74 for the right). The lists were calculated, not drawn by
     hand. "-webkit-clip-path" is the same rule for older Safari browsers.
   - The buttons are told apart by their data-enter-mode label in the HTML:
     "music" is the left button, "heartbeat" the right one. */
.button.button-ticket.entry-button[data-enter-mode="music"]::before {
  -webkit-clip-path: polygon(0% 0%, calc(100% - 10px) 0%, calc(100% - 7.4px) 0.3px, calc(100% - 5px) 1.3px, calc(100% - 2.9px) 2.9px, calc(100% - 1.3px) 5px, calc(100% - 0.3px) 7.4px, 100% 10px, 100% calc(100% - 25px), calc(100% - 0.3px) calc(100% - 22.7px), calc(100% - 1.2px) calc(100% - 20.5px), calc(100% - 2.6px) calc(100% - 18.6px), calc(100% - 4.5px) calc(100% - 17.2px), calc(100% - 6.7px) calc(100% - 16.3px), calc(100% - 9px) calc(100% - 16px), 92% calc(100% - 16px), 90% calc(100% - 16px), 88% calc(100% - 16px), 86% calc(100% - 16px), 84% calc(100% - 16px), 82% calc(100% - 16px), 80% calc(100% - 16.1px), 78% calc(100% - 16.2px), 76% calc(100% - 16.4px), 74% calc(100% - 16.5px), 72% calc(100% - 16.4px), 70% calc(100% - 16.2px), 68% calc(100% - 16px), 66% calc(100% - 16.2px), 64% calc(100% - 16.6px), 62% calc(100% - 17.2px), 61% calc(100% - 17.4px), 60% calc(100% - 14.8px), 58% calc(100% - 12.9px), 56% calc(100% - 12.1px), 55% calc(100% - 12px), 54% calc(100% - 12.1px), 52% calc(100% - 12.8px), 50% calc(100% - 14.7px), 49% calc(100% - 18px), 48% calc(100% - 18px), 46% calc(100% - 17.7px), 44% calc(100% - 16.9px), 43.8% calc(100% - 16.8px), 42% calc(100% - 9.7px), 41% calc(100% - 3px), 40% calc(100% - 9.7px), 38.2% calc(100% - 16.5px), 38% calc(100% - 16.5px), 36% calc(100% - 16.9px), 34% calc(100% - 17.1px), 33% calc(100% - 17.1px), 32% calc(100% - 12.7px), 30% calc(100% - 9.4px), 28% calc(100% - 7.8px), 26% calc(100% - 7.1px), 25% calc(100% - 7px), 24% calc(100% - 7.1px), 22% calc(100% - 1px), 20% calc(100% - 9.4px), 18% calc(100% - 12.7px), 17% calc(100% - 17.3px), 16% calc(100% - 17px), 14% calc(100% - 16.6px), 13.2% calc(100% - 16.5px), 12% calc(100% - 10.5px), 11% calc(100% - 1px), 10% calc(100% - 10.5px), 9% calc(100% - 17px), 8.8% calc(100% - 16.1px), 8% calc(100% - 14px), 6% calc(100% - 12.2px), 5% calc(100% - 12px), 4% calc(100% - 12.2px), 2% calc(100% - 14px), 1% calc(100% - 16.6px), 0% calc(100% - 16.8px));
  clip-path: polygon(0% 0%, calc(100% - 10px) 0%, calc(100% - 7.4px) 0.3px, calc(100% - 5px) 1.3px, calc(100% - 2.9px) 2.9px, calc(100% - 1.3px) 5px, calc(100% - 0.3px) 7.4px, 100% 10px, 100% calc(100% - 25px), calc(100% - 0.3px) calc(100% - 22.7px), calc(100% - 1.2px) calc(100% - 20.5px), calc(100% - 2.6px) calc(100% - 18.6px), calc(100% - 4.5px) calc(100% - 17.2px), calc(100% - 6.7px) calc(100% - 16.3px), calc(100% - 9px) calc(100% - 16px), 92% calc(100% - 16px), 90% calc(100% - 16px), 88% calc(100% - 16px), 86% calc(100% - 16px), 84% calc(100% - 16px), 82% calc(100% - 16px), 80% calc(100% - 16.1px), 78% calc(100% - 16.2px), 76% calc(100% - 16.4px), 74% calc(100% - 16.5px), 72% calc(100% - 16.4px), 70% calc(100% - 16.2px), 68% calc(100% - 16px), 66% calc(100% - 16.2px), 64% calc(100% - 16.6px), 62% calc(100% - 17.2px), 61% calc(100% - 17.4px), 60% calc(100% - 14.8px), 58% calc(100% - 12.9px), 56% calc(100% - 12.1px), 55% calc(100% - 12px), 54% calc(100% - 12.1px), 52% calc(100% - 12.8px), 50% calc(100% - 14.7px), 49% calc(100% - 18px), 48% calc(100% - 18px), 46% calc(100% - 17.7px), 44% calc(100% - 16.9px), 43.8% calc(100% - 16.8px), 42% calc(100% - 9.7px), 41% calc(100% - 3px), 40% calc(100% - 9.7px), 38.2% calc(100% - 16.5px), 38% calc(100% - 16.5px), 36% calc(100% - 16.9px), 34% calc(100% - 17.1px), 33% calc(100% - 17.1px), 32% calc(100% - 12.7px), 30% calc(100% - 9.4px), 28% calc(100% - 7.8px), 26% calc(100% - 7.1px), 25% calc(100% - 7px), 24% calc(100% - 7.1px), 22% calc(100% - 1px), 20% calc(100% - 9.4px), 18% calc(100% - 12.7px), 17% calc(100% - 17.3px), 16% calc(100% - 17px), 14% calc(100% - 16.6px), 13.2% calc(100% - 16.5px), 12% calc(100% - 10.5px), 11% calc(100% - 1px), 10% calc(100% - 10.5px), 9% calc(100% - 17px), 8.8% calc(100% - 16.1px), 8% calc(100% - 14px), 6% calc(100% - 12.2px), 5% calc(100% - 12px), 4% calc(100% - 12.2px), 2% calc(100% - 14px), 1% calc(100% - 16.6px), 0% calc(100% - 16.8px));
}

.button.button-ticket.entry-button[data-enter-mode="heartbeat"]::before {
  -webkit-clip-path: polygon(100% 0%, 10px 0%, 7.4px 0.3px, 5px 1.3px, 2.9px 2.9px, 1.3px 5px, 0.3px 7.4px, 0% 10px, 0% calc(100% - 25px), 0.3px calc(100% - 22.7px), 1.2px calc(100% - 20.5px), 2.6px calc(100% - 18.6px), 4.5px calc(100% - 17.2px), 6.7px calc(100% - 16.3px), 9px calc(100% - 16px), 8% calc(100% - 16px), 10% calc(100% - 16px), 12% calc(100% - 16px), 14% calc(100% - 16px), 16% calc(100% - 16px), 18% calc(100% - 16px), 20% calc(100% - 16.1px), 22% calc(100% - 16.1px), 24% calc(100% - 16.2px), 26% calc(100% - 16.5px), 28% calc(100% - 16.8px), 30% calc(100% - 17px), 32% calc(100% - 17.2px), 34% calc(100% - 17px), 36% calc(100% - 16.6px), 38% calc(100% - 16.4px), 38.5% calc(100% - 16.5px), 40% calc(100% - 14.7px), 42% calc(100% - 13.4px), 44% calc(100% - 13px), 46% calc(100% - 13.3px), 48% calc(100% - 14.6px), 49.5% calc(100% - 16.5px), 50% calc(100% - 16.5px), 52% calc(100% - 17px), 54% calc(100% - 10.5px), 55% calc(100% - 5px), 56% calc(100% - 10.5px), 58% calc(100% - 18px), 60% calc(100% - 17.9px), 62% calc(100% - 17.4px), 64% calc(100% - 17px), 66% calc(100% - 17px), 66.4% calc(100% - 17px), 68% calc(100% - 8.7px), 69% 100%, 70% calc(100% - 8.7px), 71.5% calc(100% - 17px), 71.6% calc(100% - 16.2px), 72% calc(100% - 13.9px), 74% calc(100% - 9.5px), 76% calc(100% - 7.4px), 78% calc(100% - 6.3px), 80% calc(100% - 6px), 82% calc(100% - 6.3px), 84% calc(100% - 7.4px), 86% calc(100% - 9.5px), 88% calc(100% - 13.9px), 88.5% calc(100% - 17.6px), 89.6% calc(100% - 17.4px), 90% calc(100% - 16.6px), 90.5% calc(100% - 13.7px), 92% calc(100% - 2px), 94% calc(100% - 13px), 94.4% calc(100% - 13px), 96% calc(100% - 13.9px), 97.5% calc(100% - 17.5px), 98% calc(100% - 17.4px), 100% calc(100% - 16.8px));
  clip-path: polygon(100% 0%, 10px 0%, 7.4px 0.3px, 5px 1.3px, 2.9px 2.9px, 1.3px 5px, 0.3px 7.4px, 0% 10px, 0% calc(100% - 25px), 0.3px calc(100% - 22.7px), 1.2px calc(100% - 20.5px), 2.6px calc(100% - 18.6px), 4.5px calc(100% - 17.2px), 6.7px calc(100% - 16.3px), 9px calc(100% - 16px), 8% calc(100% - 16px), 10% calc(100% - 16px), 12% calc(100% - 16px), 14% calc(100% - 16px), 16% calc(100% - 16px), 18% calc(100% - 16px), 20% calc(100% - 16.1px), 22% calc(100% - 16.1px), 24% calc(100% - 16.2px), 26% calc(100% - 16.5px), 28% calc(100% - 16.8px), 30% calc(100% - 17px), 32% calc(100% - 17.2px), 34% calc(100% - 17px), 36% calc(100% - 16.6px), 38% calc(100% - 16.4px), 38.5% calc(100% - 16.5px), 40% calc(100% - 14.7px), 42% calc(100% - 13.4px), 44% calc(100% - 13px), 46% calc(100% - 13.3px), 48% calc(100% - 14.6px), 49.5% calc(100% - 16.5px), 50% calc(100% - 16.5px), 52% calc(100% - 17px), 54% calc(100% - 10.5px), 55% calc(100% - 5px), 56% calc(100% - 10.5px), 58% calc(100% - 18px), 60% calc(100% - 17.9px), 62% calc(100% - 17.4px), 64% calc(100% - 17px), 66% calc(100% - 17px), 66.4% calc(100% - 17px), 68% calc(100% - 8.7px), 69% 100%, 70% calc(100% - 8.7px), 71.5% calc(100% - 17px), 71.6% calc(100% - 16.2px), 72% calc(100% - 13.9px), 74% calc(100% - 9.5px), 76% calc(100% - 7.4px), 78% calc(100% - 6.3px), 80% calc(100% - 6px), 82% calc(100% - 6.3px), 84% calc(100% - 7.4px), 86% calc(100% - 9.5px), 88% calc(100% - 13.9px), 88.5% calc(100% - 17.6px), 89.6% calc(100% - 17.4px), 90% calc(100% - 16.6px), 90.5% calc(100% - 13.7px), 92% calc(100% - 2px), 94% calc(100% - 13px), 94.4% calc(100% - 13px), 96% calc(100% - 13.9px), 97.5% calc(100% - 17.5px), 98% calc(100% - 17.4px), 100% calc(100% - 16.8px));
}

/* BIG SCREENS (800px wide and up): plenty of room, so the buttons go back to
   the full size: 1.2rem text, wide letter spacing, and generous padding
   (1.75rem at the sides), and the side margins grow back to 1.5rem. Below
   800px the smaller, screen-relative values further up apply. */
@media (min-width: 800px) {
  .js-enabled .entry-button-wrap {
    padding: 0 1.5rem;
  }

  .button.button-ticket.entry-button {
    font-size: 1.2rem;
    letter-spacing: 0.1em;
    padding: 1rem 1.75rem calc(1rem + 18px);
  }
}
/* FALLING DROPS. script.js creates one of these <div>s at one of the tips of
   a button's splatter edge, makes it fall, and removes it again when it has
   faded out. Only the LOOKS are here; the movement, the stretching and the
   fading are done by script.js.

   - A teardrop shape: the rounded corners are smaller at the top and much
     rounder at the bottom ("border-radius: horizontal / vertical").
   - Same reds as the buttons: brick red at the top, the deeper red at the
     bottom.
   - "position: absolute" inside the entry cover, which fills the screen, so
     the numbers script.js gives (left and top) are screen positions.
   - "transform-origin: 50% 0" = stretch downward from the top of the drop.
   - "pointer-events: none": drops can never be clicked or block a click.
   - Layering: a drop has z-index 0 and the buttons have z-index 1 (next
     rule). So a drop from the upper button falls BEHIND the lower button
     instead of streaking across its text, and comes out again below it. */
.blood-drop {
  position: absolute;
  z-index: 0;
  background: linear-gradient(to bottom, #9e2b24, #6e1e19);
  border-radius: 50% 50% 50% 50% / 30% 30% 70% 70%;
  transform-origin: 50% 0;
  pointer-events: none;
  will-change: transform, opacity;   /* tells the browser this will move, so it prepares to animate smoothly */
}

.entry-button-wrap .entry-button {
  z-index: 1;
}

.entry-screen.is-leaving {
  opacity: 0;
  pointer-events: none;
}

/* While the logo is inside the cover it is just a picture: clicking it does
   nothing. (This stops applying once the logo moves to the header.) */
.entry-screen .site-logo {
  pointer-events: none;
}

/* The ENTER buttons: a quick fade-out (0.25 seconds) when one is pressed.
   (Their red splatter shape and its color change are described above, in the
   "BLOOD SPLATTER BUTTONS" note.) */
.button.button-ticket.entry-button {
  transition: opacity 0.25s ease;
}

.entry-button.is-leaving {
  opacity: 0;
  pointer-events: none;
}

.entry-button:focus-visible {
  outline: 2px solid var(--color-text);
  outline-offset: 4px;
}

/* While the entry screen is active, the rest of the page exists but is
   invisible ("visibility: hidden" also hides it from keyboards and screen
   readers), and the page cannot be scrolled. When "is-entry" is removed,
   the content fades in (the opacity transition below). */
main,
.site-footer {
  transition: opacity 0.5s ease;    /* keep in sync with PAGE_REVEAL_MS in script.js */
}

.is-entry main,
.is-entry .site-footer {
  opacity: 0;
  visibility: hidden;
}

.is-entry,
.is-entry body {
  overflow: hidden;
}

/* The sound button stays out of sight until the visitor has entered */
.is-entry .sound-toggle {
  opacity: 0;
  visibility: hidden;
}

/* While the logo glides to the header, the header must be drawn ABOVE the
   black cover (40), otherwise the logo would be hidden behind it. It stays
   below the film grain (50). The header itself is see-through, so the cover
   still shows around the logo. */
.is-entering .site-header {
  z-index: 45;
}


/* --------------------------------------------------------------------------
   4. BUTTONS
   Used for "GET YOUR TICKET" and "Follow on Instagram". Raleway font.
   Restrained look: dark grey fill, thin grey border. No bright colors.
   -------------------------------------------------------------------------- */
.button {
  display: inline-block;
  font-family: var(--font-buttons);
  font-weight: 600;
  font-size: 0.95rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  text-decoration: none;
  padding: 0.95rem 2.25rem;
  background: var(--color-background-raised);
  color: var(--color-text);
  border: 1px solid var(--color-border);
  transition: background 0.2s, border-color 0.2s;
}

/* On hover / keyboard focus: the border turns white and the fill lightens */
.button:hover,
.button:focus-visible {
  background: #262626;
  border-color: var(--color-text);
}


/* The ticket button: a muted brick red, and the ONE strong color on the page.
   It is written as ".button.button-ticket" (both classes together) so that
   these rules win over the plain ".button" rules above. */
.button.button-ticket {
  background: #9e2b24;              /* muted brick red */
  border: 2px solid #9e2b24;        /* same color, so there is no visible outline */
  color: #ffffff;
  font-weight: 700;                 /* bold */
  font-size: 1.2rem;                /* larger and bold: keeps white-on-red easy to read */
  letter-spacing: 0.1em;
  padding: 1rem 1.75rem;
  max-width: 100%;                  /* never wider than the screen */
  transition: background 0.5s ease, border-color 0.5s ease;   /* slow, "sinking" change */
}

/* Hover / keyboard focus: the brick red sinks into a darker, deeper red */
.button.button-ticket:hover,
.button.button-ticket:focus-visible {
  background: #6e1e19;
  border-color: #6e1e19;
  color: #ffffff;
}


/* --------------------------------------------------------------------------
   5. UPCOMING EVENT
   The flyer, the description, the address, and the ticket button.
   The top padding also gives some breathing room under the logo.
   -------------------------------------------------------------------------- */
/* The top padding (2rem = 32px) leaves room for the flyer's red glow, which
   reaches at most about 28px above the flyer. Nothing here is clipped, so
   the glow simply fades out on its own. */
.upcoming-event {
  padding: 2rem 0 4rem;
}

/* This section's container is wider than the others, to leave room for
   two columns on big screens. */
.upcoming-event .container {
  max-width: 68rem;
}

/* The box holding flyer + text. On phones it is a single narrow column,
   the same width as before. (The two-column version is in section 8.) */
.event-layout {
  max-width: var(--content-width);
  margin: 0 auto;
}

/* The flyer: never wider than --flyer-max-width (520px, set at the top),
   centered, and it shrinks proportionally on small screens so it can
   never overflow. */
.event-flyer {
  max-width: var(--flyer-max-width);
  margin: 0 auto 2rem;              /* "auto" on the sides = centered */

  /* Needed for the glow below: "relative" lets us place the glow relative
     to the flyer; "isolate" keeps the glow tucked BEHIND the image. */
  position: relative;
  isolation: isolate;
}

.event-flyer img {
  display: block;
  width: 100%;                      /* fill the box (capped by --flyer-max-width) */
  height: auto;                     /* keep the flyer's proportions */

  /* The flyer breathes in time with the glow: same duration, same
     easing, same "lub-dub" steps (see flyer-heartbeat in section 9). */
  animation: flyer-heartbeat var(--heartbeat-duration) ease-in-out infinite;
}

/* AMBIENT RED GLOW behind the flyer.
   This is its own element (the <div class="flyer-glow"> in the HTML). The
   flyer image itself has NO glow styling: no shadow, no border, nothing.

   The glow follows the flyer's straight edges: a soft red light that is
   brightest right at the edge and fades away over a short distance, evenly
   along the top, bottom and sides, and rounded off slightly at the corners.

   How it is made:
     The .flyer-glow box sits behind the flyer, a little SMALLER than it
     (inset: 6px pulls every side 6px inward, so the box is completely
     hidden behind the image). Around that box, "box-shadow" draws the red
     light. A shadow with a blur fades smoothly to fully transparent, so it
     has no hard edge of its own. The syntax is:
       box-shadow: sideways up-down blur spread color
     - blur: how far the fade reaches (the light is gone about that far out)
     - spread: pushes the whole shadow outward before it fades

   Why the box is tucked in behind the flyer:
     The pulse makes the box swell by about 1%. A shadow is only drawn
     OUTSIDE its box, so if the box ever stuck out past the flyer, a thin
     dark strip (the empty inside of the box) would show between the flyer
     and the light. Because the box is 6px inside the flyer's edge and
     grows by only about 3px, it can never stick out. That thin dark strip
     is what appeared in an earlier version.

   Size of the light: about 20 to 28px past the flyer's edge. --glow-blur
   shrinks on narrow screens ("clamp(smallest, preferred, largest)" with
   5vw, 5% of the screen width), so on a phone the light stays inside the
   space around the flyer and never reaches the screen edge or the text.

   To make the glow tighter or wider, change --glow-blur (and the 8px
   spread) below. */
.event-flyer {
  --glow-blur: clamp(16px, 5vw, 26px);
}

.flyer-glow {
  position: absolute;
  inset: 6px;                                   /* 6px inside the flyer's edges: hidden behind it */
  z-index: -1;                                  /* behind the flyer image */
  box-shadow: 0 0 var(--glow-blur) 8px rgba(158, 43, 36, 0.9);   /* the button's brick red */
  pointer-events: none;
  animation: glow-heartbeat var(--heartbeat-duration) ease-in-out infinite;
}

/* NO PULSE: when the visitor entered WITH MUSIC there is no heartbeat, so
   nothing should beat. script.js puts the class "no-heartbeat-pulse" on the
   whole page in that case. The flyer and the glow then stay perfectly
   still. The glow gets a fixed middle strength (0.78, about the average of
   its pulse, which moved between 0.72 and 0.92) so it looks the same as
   the pulsing version does at rest, not brighter. If the visitor chose
   WITHOUT MUSIC this class is never added, and everything pulses with the
   heartbeat as before. */
.no-heartbeat-pulse .event-flyer img,
.no-heartbeat-pulse .flyer-glow {
  animation: none;
}

.no-heartbeat-pulse .flyer-glow {
  opacity: 0.78;
  transform: none;
}

/* The text column. "relative" + z-index keeps the text drawn above the glow. */
.event-text {
  position: relative;
  z-index: 1;
}

/* The box around the ticket button. Centering is set here, so the button
   sits in the middle of the text column even on desktop, where the
   paragraphs around it are left-aligned. On phones everything is already
   centered, so nothing changes there. */
.event-cta {
  text-align: center;
}

/* The dinner / bottles paragraph, just below the ticket button */
.event-description {
  margin: 2rem 0 0;                 /* space above (after the button), none below */
}

/* The event description block, just above the ticket button */
.event-about {
  margin-bottom: 2rem;              /* space between the text and the button */
}

.event-about p {
  margin: 0 0 1rem;                 /* space between its paragraphs */

  /* "pre-line" makes the browser show a \n written in content.js as a real
     line break inside the paragraph. (Normally browsers ignore line breaks.) */
  white-space: pre-line;
}

/* No extra gap under the last paragraph (the box adds its own gap) */
.event-about p:last-child {
  margin-bottom: 0;
}

/* The FIRST paragraph ("Some nights ask for a costume...") works like a
   subtitle: bigger and bolder than the paragraphs below it.
   (It applies to whatever is the first line in aboutParagraphs in content.js.)
   clamp(smallest, preferred, largest) makes it grow with the screen but
   stay small enough that it does not wrap awkwardly on a phone. */
.event-about p:first-child {
  font-size: clamp(1.1rem, 4.6vw, 1.5rem);
  font-weight: 700;
  line-height: 1.3;
  margin-bottom: 1.5rem;            /* a bit more air between subtitle and body */
  text-wrap: balance;               /* evens out line lengths where supported */
}

/* The small "Location:" label: smaller, uppercase, spaced-out letters and
   a quieter grey, so it reads as a label and not as content. */
.event-location-label {
  font-size: 0.75rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--color-text-muted);
  margin: 2.5rem 0 0.25rem;         /* big gap above (after the button), small gap below */
}

/* The address itself: normal off-white text, so it stands out more than the label */
.event-address {
  font-size: 0.95rem;
  margin: 0;
  white-space: pre-line;            /* shows each \n from content.js as a line break */

  /* The ONE exception to "no selection": visitors can select and copy the
     address (to paste into Maps or a note). The text cursor over it hints
     that it can be selected. */
  -webkit-user-select: text;
  user-select: text;
  cursor: text;
}

/* Shown when no event is planned */
.event-empty h2 {
  font-size: clamp(1.9rem, 7vw, 3rem);
}


/* --------------------------------------------------------------------------
   6. STAY.CONNECT.ED
   No divider line: the spacing alone separates it from the event above.
   The bottom padding is small on purpose, so the footer follows closely.

   IF SECTIONS EVER FEEL LIKE THEY BLUR TOGETHER, here is a ready-made
   alternative: a very faint line that fades out at both ends. To use it,
   copy these two lines into the ".stay-connected" rule below and again
   into the ".site-footer" rule (one copy in each):

   border-top: 1px solid transparent;
   border-image: linear-gradient(to right, transparent, rgba(255, 255, 255, 0.18), transparent) 1;
   -------------------------------------------------------------------------- */
.stay-connected {
  padding: 3.5rem 0 2rem;
}

.stay-connected h2 {
  font-size: clamp(1.7rem, 6vw, 2.4rem);
}


/* --------------------------------------------------------------------------
   7. FOOTER
   -------------------------------------------------------------------------- */
.site-footer {
  text-align: center;
  padding: 1.5rem 1.5rem 2rem;      /* small top padding: it follows the button closely */
}

/* "join.the.community" */
.footer-title {
  font-family: var(--font-headings);
  font-size: 1.25rem;
  font-weight: 700;
  margin: 0 0 1rem;
}

.footer-links {
  list-style: none;
  margin: 0 0 1.5rem;
  padding: 0;
  display: flex;
  justify-content: center;
  gap: 1.75rem;
}

.footer-links a {
  font-size: 0.9rem;
  letter-spacing: 0.08em;
}

/* The email, written as plain text */
.footer-email {
  font-size: 0.85rem;
  color: var(--color-text-muted);
  margin-bottom: 2rem;
  overflow-wrap: anywhere;          /* if the screen is very narrow, allow it to wrap */
}

.footer-copyright {
  font-size: 0.75rem;
  color: var(--color-text-muted);
  margin: 0;
}


/* --------------------------------------------------------------------------
   7b. SOUND ON/OFF BUTTON
   Small, quiet, fixed in the bottom-right corner. z-index 70 keeps it above
   the grain (50) and the flash (60) layers so it can always be clicked.
   -------------------------------------------------------------------------- */
.sound-toggle {
  position: fixed;
  right: max(1rem, env(safe-area-inset-right));    /* stay clear of phone notches */
  bottom: max(1rem, env(safe-area-inset-bottom));
  z-index: 70;

  width: 2.75rem;                   /* 44px: comfortable to tap with a thumb */
  height: 2.75rem;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;

  background: rgba(0, 0, 0, 0.6);
  color: var(--color-text);
  border: 1px solid var(--color-line);
  cursor: pointer;
  opacity: 0.6;                     /* understated until you point at it */
  transition: opacity 0.2s, border-color 0.2s;
}

.sound-toggle:hover,
.sound-toggle:focus-visible {
  opacity: 1;
  border-color: var(--color-border);
}

.sound-toggle:focus-visible {
  outline: 2px solid var(--color-text);
  outline-offset: 3px;
}

/* Icon: waves when sound is on; a cross when it is off */
.sound-toggle .icon-cross {
  display: none;
}

.sound-toggle.is-muted .icon-waves {
  display: none;
}

.sound-toggle.is-muted .icon-cross {
  display: inline;
}


/* --------------------------------------------------------------------------
   9. VISUAL EFFECTS
   All effects use only CSS animation ("keyframes") and are kept light:
   they only change "transform" and "opacity", which the browser can
   animate smoothly without redoing the page layout.

   An animation is defined in two steps:
     a) @keyframes name { ... }   describes WHAT changes over time
     b) animation: name 5s ...    applies it to an element
   -------------------------------------------------------------------------- */

/* ---- Film grain --------------------------------------------------------
   A fixed layer covering the whole screen, filled with fine noise.
   The noise picture is generated by the browser from a tiny SVG recipe
   (the long "data:image/svg+xml..." line), so there is no image file to
   download. The layer is twice the screen size and is nudged around in
   small jumps, which makes the grain look alive.
   pointer-events: none = clicks pass straight through it. */
.film-grain {
  position: fixed;
  top: -50%;
  left: -50%;
  width: 200%;
  height: 200%;
  z-index: 50;
  pointer-events: none;
  opacity: 0.08;                    /* very faint: texture, not static */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n' x='0' y='0'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 200px 200px;     /* the noise tile repeats like wallpaper */
  animation: grain-shift 3s steps(1) infinite;
}

/* "steps(1)" makes the layer JUMP between positions instead of sliding.
   Each jump is tiny (about 1% of the layer) and they happen a few times a
   second, like real film grain. */
@keyframes grain-shift {
  0%   { transform: translate(0, 0); }
  12%  { transform: translate(-1.2%, 0.8%); }
  25%  { transform: translate(0.9%, -1.1%); }
  37%  { transform: translate(-0.6%, -0.9%); }
  50%  { transform: translate(1.1%, 0.7%); }
  62%  { transform: translate(-1%, 1.2%); }
  75%  { transform: translate(0.7%, -0.6%); }
  87%  { transform: translate(-0.9%, 0.4%); }
  100% { transform: translate(0, 0); }
}

/* ---- Heartbeat: the glow AND the flyer -------------------------------
   One cycle lasts --heartbeat-duration (0.9 seconds, set at the top of this
   file) and has TWO beats, like a real heart: a strong "lub" and a softer
   "dub", followed by a short rest.
   The percentages are moments inside the cycle (for example 14% is about
   0.13 seconds in). It cannot listen to the audio: it is a fixed rhythm
   that approximates it.

   The two animations below use the SAME percentages, the SAME duration and
   the SAME easing, and both elements start at the same moment, so the glow
   and the flyer beat together as one movement. Only the amounts differ:
   the glow changes a lot, the flyer only a tiny bit.
   Only opacity and scale change: the width and height never do. */

/* The glow: a faint brightening and swelling on each beat. The swing is
   small on purpose (opacity only moves between 0.72 and 0.92, and the size
   by about 2%), so the breathing is felt more than seen. */
@keyframes glow-heartbeat {
  0%   { opacity: 0.72; transform: scale(0.99); }     /* at rest */
  14%  { opacity: 0.92; transform: scale(1.012); }    /* "lub": the strong beat */
  28%  { opacity: 0.78; transform: scale(0.995); }    /* small dip between beats */
  42%  { opacity: 0.86; transform: scale(1.006); }    /* "dub": the softer beat */
  65%  { opacity: 0.72; transform: scale(0.99); }     /* back to rest ... */
  100% { opacity: 0.72; transform: scale(0.99); }     /* ... and a pause before the next one */
}

/* The flyer: an almost imperceptible breath. 1 = normal size, and the
   biggest it gets is 1.008 (0.8% bigger). */
@keyframes flyer-heartbeat {
  0%   { transform: scale(1); }                       /* at rest */
  14%  { transform: scale(1.008); }                   /* "lub" */
  28%  { transform: scale(1.002); }                   /* small dip between beats */
  42%  { transform: scale(1.005); }                   /* "dub" */
  65%  { transform: scale(1); }                       /* back to rest ... */
  100% { transform: scale(1); }                       /* ... and a pause */
}

/* ---- Screen flash ------------------------------------------------------
   A layer over the whole screen, normally invisible (opacity 0).
   Its light is a soft radial gradient: brightest at one point (where the
   lightning seems to come from) and fading to transparent away from it.
   The colour is a cool white with a hint of blue: #eaf0ff, which in the
   "rgba" notation below is rgba(234, 240, 255, ...).

   Two variables, --flash-x and --flash-y, hold the position of that bright
   point. script.js gives them NEW random values at every flash, so the
   light comes from a different place each time. (The values after the comma
   in var(...) are the defaults if the script has not set them yet.)
   The flicker itself (pulses, timing, strength) is also created by
   script.js at every flash. */
.screen-flash {
  position: fixed;
  inset: 0;                         /* shorthand for top, right, bottom, left = 0 */
  z-index: 60;
  pointer-events: none;
  background: radial-gradient(
    circle at var(--flash-x, 50%) var(--flash-y, 0%),
    rgba(234, 240, 255, 1) 0%,      /* full strength at the source ... */
    rgba(234, 240, 255, 0.55) 30%,  /* ... softer around it ... */
    rgba(234, 240, 255, 0) 80%      /* ... and gone before the far edges */
  );
  opacity: 0;
}

/* ---- Scroll reveal -----------------------------------------------------
   Blocks marked class="reveal" start invisible and 16px lower than their
   final place. When script.js adds "is-visible" (the moment they scroll
   into view), they fade in and slide up.
   The rule only applies when the script has confirmed it is running
   (the "js-enabled" class on the page), so that if the script ever fails,
   the text is never left invisible. */
.js-enabled .reveal {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.9s ease, transform 0.9s ease;
}

.js-enabled .reveal.is-visible {
  opacity: 1;
  transform: none;
}

/* ---- Respect visitors who prefer less motion ---------------------------
   Many phones and computers have a "reduce motion" setting (helpful for
   people with motion sensitivity or migraines). If it is on, we switch
   off the moving effects: no grain movement, no pulsing glow, no flash,
   and content simply appears without sliding. */
@media (prefers-reduced-motion: reduce) {
  .film-grain,
  .flyer-glow,
  .event-flyer img {
    animation: none;
  }

  /* The entry screen's fades become instant */
  main,
  .site-footer,
  .js-enabled .entry-screen,
  .button.button-ticket.entry-button,
  .button.button-ticket.entry-button::before {
    transition: none;
  }

  .screen-flash {
    display: none;
  }

  .js-enabled .reveal {
    opacity: 1;
    transform: none;
    transition: none;
  }
}


/* --------------------------------------------------------------------------
   8. WIDER SCREENS (tablet and computer: 700px and up)
   Only the things that need to change are listed here.
   -------------------------------------------------------------------------- */
@media (min-width: 700px) {

  .site-header {
    padding-top: 2.5rem;
  }

  .upcoming-event {
    padding: 2rem 0 5.5rem;
  }

  .stay-connected {
    padding: 5rem 0 2.5rem;
  }
}

/* --------------------------------------------------------------------------
   8b. DESKTOP TWO-COLUMN EVENT LAYOUT (900px and up)
   All the text on the left, flyer on the right, vertically centered
   next to the flyer. Below 900px nothing here applies, so phones and
   small tablets keep the single stacked column.
   -------------------------------------------------------------------------- */
@media (min-width: 900px) {

  /* "display: grid" lays children out in rows and columns. Here: two
     columns of equal width ("1fr 1fr"), with a gap between them.
     minmax(0, 1fr) stops a long word from stretching a column.
     align-items: center = vertically centers the text next to the flyer. */
  .event-layout {
    max-width: none;
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 4rem;
    align-items: center;
  }

  /* The flyer fills its column (still never wider than 520px) and no longer
     needs the space underneath or the auto-centering.
     "order: 2" = show this item second, so the flyer goes on the RIGHT. */
  .event-flyer {
    margin: 0;
    order: 2;
  }

  /* Text reads better left-aligned in a column next to an image.
     "order: 1" = show this item first, so the text goes on the LEFT.
     (In the HTML the flyer still comes first, so on phones, where this
     block does not apply, the flyer stays on top.) */
  .event-text {
    text-align: left;
    order: 1;
  }
}
