/* Desert Island Decks
   Base layer only: the background, a container, a type scale and a few layout
   helpers. No visual styling — colours, fonts and design decisions go below. */

/* ---------- tokens ---------- */

:root {
  /* Cream and red come straight from the sketch, so page and canvas agree. */
  --cream: rgb(255, 250, 240);
  --red:   rgb(150, 10, 10);
  --ink:   #2b241c;              /* readable body text — a warm near-black */

  /* Fluid type. Each step interpolates between a phone size and a desktop size,
     so there's no need for font-size media queries. Use with var(--step-2) etc. */
  --step--1: clamp(0.83rem, 0.79rem + 0.20vw, 0.94rem);
  --step-0:  clamp(1.00rem, 0.93rem + 0.33vw, 1.19rem);
  --step-1:  clamp(1.20rem, 1.09rem + 0.55vw, 1.50rem);
  --step-2:  clamp(1.44rem, 1.26rem + 0.89vw, 1.89rem);
  --step-3:  clamp(1.73rem, 1.45rem + 1.39vw, 2.38rem);
  --step-4:  clamp(2.07rem, 1.66rem + 2.09vw, 3.00rem);
  --step-5:  clamp(2.49rem, 1.88rem + 3.05vw, 3.78rem);

  --font: "Fraunces", Georgia, "Times New Roman", serif;
  --font-name: "Piazzolla", Georgia, "Times New Roman", serif;  /* the DJ name only */

  /* Header placement, shared with the booking button so the two line up:
     the button sits the same distance in from the right and the bottom as the
     header text sits from the right and the top. */
  --header-inset: clamp(0px, 4vw, 64px);   /* extra hold-off from the right edge */
  --header-edge: calc(var(--gutter) + var(--header-inset));
  --header-top: clamp(28px, 5vh, 56px);

  /* The header's own top offset. On a portrait screen it drops so the lockup
     meets the sun; the booking button keeps --header-top either way, so it
     stays exactly where it is. */
  --header-top-text: var(--header-top);

  --control-h: 44px;  /* height of a tappable control — booking, the play button */

  --fade-in: 5s;      /* how long the header and button take to appear */
  --glow: 1;          /* strength of the cream halo behind the header text */

  --measure: 1040px;  /* how wide content is allowed to get */
  --gutter: 24px;     /* space between content and the screen edge */
  --gap: 20px;        /* default space between grid items */
}

@media (max-width: 480px) {
  :root { --gutter: 18px; }
}

/* Portrait — phones, and any window taller than it is wide. The sketch uses the
   same test, so the sun and the text move together. */
@media (orientation: portrait) {
  :root { --header-top-text: 66px; }
}

/* ---------- reset ---------- */

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

html, body {
  margin: 0;
  padding: 0;
  min-height: 100svh;          /* svh, not vh — vh overflows on iOS */
  background: var(--cream);    /* shows before p5 loads */
}

body {
  color: var(--ink);
  font-family: var(--font);
  font-size: var(--step-0);
  line-height: 1.6;
  font-optical-sizing: auto;   /* Fraunces adjusts its drawing to the size it's set at */

  /* Fraunces' two character axes, both currently off.
     SOFT (0-100) rounds the terminals; 0 is crisp, 100 is fully softened.
     WONK (0 or 1) swaps in the odd, canted letterforms; 1 turns them on.
     Change them here to affect everything, or per element:
       h1 { font-variation-settings: "SOFT" 40, "WONK" 1; }   */
  font-variation-settings: "SOFT" 0, "WONK" 0;
}

/* Form controls don't inherit the page font on their own. */
input, button, select, textarea { font-family: inherit; }

img, svg, video, canvas { max-width: 100%; height: auto; }

/* ---------- the p5 background ---------- */

#bg-layer {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;   /* clicks pass through to the page */
  overflow: hidden;
}

/* will-change gives the canvas its own compositing layer. Without it Safari
   rasterises it as part of the page's tiles, and on a page that never scrolls
   a tile that came out at low resolution has nothing to trigger it being drawn
   again — which shows up as one band of the screen looking coarser than the
   rest. Its own layer is rasterised once, at device resolution, as a unit. */
#bg-canvas {
  display: block;
  will-change: transform;
  backface-visibility: hidden;
}

/* ---------- one screen, locked ---------- */

/* The page is a single screen, so there is nothing to scroll. Without this a
   phone still lets you drag it: iOS scrolls the document up by the height of
   the address bar in order to collapse it, which carries the header up with
   it. Fixing the body takes the page out of the scrolling model altogether —
   the drag does nothing and the text stays put. overscroll-behavior kills the
   rubber-band at the same time.

   When the page grows past one screen, take the one-screen class off the
   <html> element in index.html and it scrolls normally again. Anything below
   the fold is invisible while it's on. */
html.one-screen,
html.one-screen body {
  height: 100%;
  overflow: hidden;
  overscroll-behavior: none;
}

html.one-screen body {
  position: fixed;
  inset: 0;
  width: 100%;

  /* Kills the double-tap zoom. A zoomed canvas doesn't redraw at the new
     scale the way text does — it just gets magnified, which looks like the
     lines have gone coarse. Pinch zoom still works, deliberately. */
  touch-action: manipulation;
}

/* ---------- layout ---------- */

/* Everything you add lives in here. It centres, caps its width, and keeps a
   margin from the screen edge at every size. */
.page {
  position: relative;
  z-index: 1;             /* above the canvas */
  max-width: var(--measure);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* A full-height block — a hero, say. */
.full { min-height: 100svh; }

/* Vertical rhythm between sections, scaled to the viewport. */
section { padding-block: clamp(48px, 9vh, 96px); }

/* Rows that fit as many columns as there's room for, then stack. No media
   query needed. Override the column width per use: style="--min: 220px". */
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(var(--min, 280px), 100%), 1fr));
  gap: var(--gap);
}

/* A row that wraps instead of overflowing — nav links, tags, buttons. */
.row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--gap);
  align-items: center;
}

/* Cap line length for readable paragraphs. */
.prose { max-width: 62ch; }

/* Anything wider than the screen (a table, a wide diagram) goes in one of
   these so the page itself never scrolls sideways. */
.scroll-x { overflow-x: auto; }

/* ---------- touch and motion ---------- */

/* Comfortable tap targets on phones. */
a, button, .btn, input, select, textarea { min-height: var(--control-h, 44px); }
a, button, .btn { display: inline-flex; align-items: center; }

/* Inputs below 16px make iOS zoom in on focus. */
input, select, textarea { font-size: max(16px, var(--step-0)); }

:focus-visible { outline: 2px solid var(--red); outline-offset: 3px; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---------- your styles below ---------- */

/* ---------- fade in on load ---------- */

/* The header and the button ease up out of the cream over five seconds, while
   the flow field is still drawing itself in. `both` holds them at opacity 0
   before the animation starts, so there's no flash of text first.
   The reduced-motion block in the base layer collapses this to an instant. */
@keyframes fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.site-header,
.booking,
.player {
  animation: fade-in var(--fade-in, 5s) ease-out both;
}

/* ---------- header ---------- */

.site-header {
  position: relative;
  z-index: 1;                  /* above the canvas, like .page */

  display: grid;
  gap: 14px;
  justify-items: start;
  text-align: left;

  /* Full window width, so the block tracks the left edge however wide the
     screen gets. --header-inset (in :root) holds it off that edge; raise it to
     move the lockup further right. It stays left-aligned at every width. */
  padding-left: var(--header-edge);
  padding-right: var(--gutter);

  padding-block: var(--header-top-text) clamp(40px, 9vh, 90px);
}

.site-header .brand {
  margin: 0;
  font-size: clamp(11px, 2vw, 15px);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  font-weight: 500;

  /* line-height 1 removes the leading above the caps, so the visible text
     starts exactly at --header-top. Letter-spacing adds its gap after each
     letter, which only pushes the right edge in — with the text left-aligned
     there's nothing to compensate for. */
  line-height: 1;
}

.site-header .presents {
  margin: 0;
  font-size: clamp(10px, 1.7vw, 13px);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  font-weight: 500;
  color: var(--red);
  line-height: 1;

  /* Indented from the margin so the three lines aren't a flat stack. In em, so
     it stays proportional at every screen size. */
  margin-left: 1.4em;
}

/* Piazzolla for the name — Fraunces' J hooks below the baseline and reads badly
   at this size. Everything else on the page stays in Fraunces. */
.site-header .dj {
  margin: 0;
  font-family: var(--font-name);
  font-variation-settings: normal;   /* Fraunces' axes don't apply to this face */
  font-size: clamp(38px, 11vw, 128px);
  line-height: 0.92;
  font-weight: 500;
  letter-spacing: -0.015em;
  text-wrap: balance;

  /* Optical alignment: the D's serif reaches further left than the flat edge of
     the capitals above, so a measured-flush margin reads as the name sticking
     out. Pulling it back a hair makes the edge look straight. In em, so it
     scales with the type. */
  margin-left: -0.03em;
}

/* The flow field is denser in some places than others, and it redraws
   differently every load, so the text can land on a dense patch and get hard to
   read. Each line carries its own cream glow: three tight opaque layers kill the
   trail pixels touching the letters, three wide faint ones fade the halo out so
   it has no visible edge. Raise --glow to strengthen it. */
.site-header .brand,
.site-header .presents,
.site-header .dj {
  text-shadow:
    0 0 calc(2px  * var(--glow)) var(--cream),
    0 0 calc(4px  * var(--glow)) var(--cream),
    0 0 calc(8px  * var(--glow)) var(--cream),
    0 0 calc(16px * var(--glow)) rgba(255, 250, 240, 0.9),
    0 0 calc(28px * var(--glow)) rgba(255, 250, 240, 0.65),
    0 0 calc(44px * var(--glow)) rgba(255, 250, 240, 0.4);
}

/* ---------- booking button ---------- */

/* Fixed to the window, so it stays put as the page scrolls. */
.booking {
  position: fixed;
  /* Diagonally opposite the header: the same inset from its own edge, and the
     same distance up from the bottom as the header sits down from the top. */
  right: var(--header-edge);
  bottom: calc(var(--header-top) + env(safe-area-inset-bottom, 0px));
  z-index: 2;

  font-family: var(--font);
  font-size: clamp(11px, 1.2vw, 14px);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;

  color: var(--cream);
  background: var(--red);
  border: 1px solid var(--red);
  border-radius: 999px;
  padding-inline: clamp(18px, 2vw, 24px);
  transition: background-color 0.15s ease, transform 0.15s ease;
}

.booking:hover,
.booking:focus-visible {
  background: #7d0808;
  transform: translateY(-1px);
}

@media (prefers-reduced-motion: reduce) {
  .booking:hover, .booking:focus-visible { transform: none; }
}


/* ---------- mix player ---------- */

/* The mirror of the booking button: same inset from its own edge, same
   distance up from the bottom. A solid black triangle and a 3px red track
   that fills as the mix plays. The cream drop-shadows are the halo the header text
   uses, rebuilt for a shape instead of a glyph — without them the triangle
   disappears into a dense patch of field. */
.player {
  position: fixed;
  left: var(--header-edge);
  bottom: calc(var(--header-top) + env(safe-area-inset-bottom, 0px));
  z-index: 2;

  display: flex;
  align-items: center;
  gap: clamp(12px, 1.4vw, 20px);

  /* The same height as the booking button, sitting on the same bottom edge, so
     the triangle and the track share a midline with it across the window. The
     triangle is shorter than this box; centring it here is what lines it up. */
  height: var(--control-h);

  filter:
    drop-shadow(0 0 calc(2px  * var(--glow)) var(--cream))
    drop-shadow(0 0 calc(5px  * var(--glow)) var(--cream))
    drop-shadow(0 0 calc(12px * var(--glow)) rgba(255, 250, 240, 0.85))
    drop-shadow(0 0 calc(26px * var(--glow)) rgba(255, 250, 240, 0.55));
}

/* The padding gives a comfortable tap target; the matching negative margin
   pulls the box back so the triangle itself still starts exactly on the
   margin and the gap to the track is measured from the glyph, not the box. */
.play {
  appearance: none;
  border: 0;
  background: none;
  min-height: 0;
  padding: 11px 14px;
  margin: -11px -14px;
  cursor: pointer;
  color: var(--ink);   /* the same warm near-black as the header text */
  display: grid;
  place-items: center;
}

.play svg {
  display: block;
  height: clamp(24px, 2.6vw, 34px);
  width: auto;
  fill: currentColor;
}

.play .ic-pause { display: none; }
.player.playing .play .ic-play { display: none; }
.player.playing .play .ic-pause { display: block; }

.track {
  position: relative;
  height: 3px;
  width: clamp(120px, 15vw, 240px);
  background: rgba(150, 10, 10, 0.18);
}

.fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: calc(var(--p, 0) * 100%);
  background: var(--red);
}
