/* Tako Tomago — two elements on a dark ground.
   The page commits to dark: the flare render is volumetric light, and it only
   reads as light against near-black. There is no light theme. */

:root {
  --ground: #050507;
  --ink: #f2f2f5;
  --muted: rgba(242, 242, 245, 0.55);
  color-scheme: dark;

  /* The built-in CSS easings are too weak to read as intentional. These are the
     stronger variants: ease-out for anything entering or responding to the
     pointer, ease-in-out for things moving across the screen. Nothing in this
     file uses ease-in — it delays the first few frames, which is exactly when
     the eye is watching, and makes the whole page feel sluggish. */
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);

  /* One press feedback duration, shared, so every pressable agrees. */
  --press: 160ms;
}

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

html { background: var(--ground); }

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font: 400 16px/1.5 "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  -webkit-font-smoothing: antialiased;
}

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ---------- Element 1 · flare hero ---------- */

.hero {
  position: relative;
  display: grid;
  place-items: center;
  /* svh, so mobile browser chrome collapsing does not crop the mark. */
  height: 100svh;
  min-height: 480px;
  overflow: hidden;
  background: var(--ground);
}

/* The renderer owns its own ResizeObserver and DPR handling, so the canvas
   only has to fill the stage and never be given intrinsic sizing. */
.hero canvas {
  display: block;
  width: 100%;
  height: 100%;
  touch-action: none;
}

/* No WebGPU, or reduced motion — the plain mark, sized to sit where the
   rendered one does. */
.hero-fallback {
  width: min(38vmin, 320px);
  height: auto;
}

/* Nothing is painted until the renderer's first frame lands, so the mark does
   not flash in at full brightness before the flare wraps it. */
.hero[data-flare-state="loading"] canvas { opacity: 0; }
/* A first-paint reveal, seen once a session — it can afford to be slower than
   the 300ms ceiling the interactive animations hold to. */
.hero[data-flare-state="live"] canvas {
  opacity: 1;
  transition: opacity 600ms var(--ease-out);
}

/* Four corner labels over the hero. The nav is inert to the pointer — the
   flare tracks the cursor across the whole stage, and only the four words
   themselves take hits. */
.hero-nav {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
}

.hero-nav-link {
  --nav-pad: clamp(18px, 3.4vw, 52px);
  position: absolute;
  pointer-events: auto;
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: clamp(15px, 1.7vw, 24px);
  /* Helvetica Bold, set tight — the weight carries the label, not tracking. */
  font-weight: 700;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  color: var(--ink);
  /* Named properties, never `all`: `all` would sweep up the layout properties
     the corner offsets rely on. */
  transition: color 200ms ease, transform var(--press) var(--ease-out);
}

/* Rest is white; the corner's own colour only arrives on hover, where the
   flare picks up the same value (see flare-mount.js). */
a.hero-nav-link:focus-visible { color: var(--corner, #fff); }

/* Touch devices fire :hover on tap and then keep it, so every hover state in
   this file is gated. Without it the corner would stay lit after a tap. */
@media (hover: hover) and (pointer: fine) {
  a.hero-nav-link:hover { color: var(--corner, #fff); }
}

/* The press has to be felt, not seen — the interface confirming it heard you. */
a.hero-nav-link:active { transform: scale(0.97); }

.hero-nav-link:focus-visible {
  outline: 1px solid var(--muted);
  outline-offset: 6px;
}

/* No destination yet — present for the composition, not yet a link. */
span.hero-nav-link { cursor: default; }

.corner-tl { --corner: #48b0c9; top: var(--nav-pad); left: var(--nav-pad); }
.corner-tr { --corner: #3e72be; top: var(--nav-pad); right: var(--nav-pad); margin-right: -0.01em; }
.corner-bl { --corner: #7d50c8; bottom: var(--nav-pad); left: var(--nav-pad); }
.corner-br { --corner: #dd62df; bottom: var(--nav-pad); right: var(--nav-pad); margin-right: -0.01em; }

/* ---------- Element 2 · release collage ---------- */

.releases {
  /* The wall runs edge to edge — the artwork is the layout. */
  padding: 0;
}

.release-grid,
.gallery-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(220px, 50vw), 1fr));
  gap: 0;
}

.release,
.shot {
  position: relative;
  display: block;
  aspect-ratio: 1;
  overflow: hidden;
  background: #0b0b0f;
  /* Covers vary in exposure; a hairline keeps two dark ones from fusing. */
  outline: 1px solid rgba(255, 255, 255, 0.04);
  outline-offset: -1px;
}

.release img,
.shot img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Resting slightly down lets hover bring a cover forward without the tile
     ever showing its own background. */
  transform: scale(1.001);
  /* Was 400ms. A hover fires dozens of times on a wall this size, so it holds
     to the interactive budget — 240ms with a strong curve reads as more
     responsive than 400ms with a weak one, at less than two-thirds the time. */
  transition: transform 240ms var(--ease-out), filter 240ms ease;
  filter: saturate(0.92) brightness(0.88);
}

.release:focus-visible img,
.shot:focus-visible img {
  transform: scale(1.06);
  filter: saturate(1) brightness(1);
}

@media (hover: hover) and (pointer: fine) {
  .release:hover img,
  .shot:hover img {
    transform: scale(1.06);
    filter: saturate(1) brightness(1);
  }
}

/* Pressing settles back toward the resting size rather than growing further —
   the tile gives under the finger instead of pushing against it. */
.release:active img,
.shot:active img {
  transform: scale(1.02);
  transition-duration: var(--press);
}

.release:focus-visible,
.shot:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: -2px;
  z-index: 1;
}

/* ---------- Element 3 · gallery ---------- */

.gallery { padding: 0; }

/* Nothing baked yet — a real destination instead of a blank band. */
.gallery-empty,
.tour-empty {
  margin: 0;
  padding: clamp(48px, 9vw, 104px) clamp(20px, 5vw, 64px);
  text-align: center;
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: clamp(15px, 1.7vw, 24px);
  font-weight: 700;
  letter-spacing: 0.01em;
  text-transform: uppercase;
}

.gallery-empty a,
.tour-empty a {
  color: var(--ink);
  text-decoration: none;
  border-bottom: 2px solid var(--muted);
  padding-bottom: 2px;
  /* inline-block so the press transform has a box to scale. */
  display: inline-block;
  transition: color 200ms ease, border-color 200ms ease,
              transform var(--press) var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
  .gallery-empty a:hover,
  .tour-empty a:hover { color: #fff; border-bottom-color: #fff; }
}

.gallery-empty a:active,
.tour-empty a:active { transform: scale(0.97); }

/* ---------- Element 4 · tour ---------- */

.tour { padding: clamp(40px, 7vw, 96px) clamp(20px, 5vw, 64px); }

.tour-list {
  list-style: none;
  margin: 0 auto;
  padding: 0;
  max-width: 900px;
}

.show {
  display: grid;
  grid-template-columns: minmax(96px, auto) 1fr auto;
  gap: clamp(12px, 2.5vw, 32px);
  align-items: baseline;
  padding: clamp(14px, 2vw, 22px) 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}

.show-date { font-variant-numeric: tabular-nums; color: var(--muted); }
.show-where { color: var(--ink); }
.show-venue { display: block; color: var(--muted); font-size: 0.85em; }

.show-tickets {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-weight: 700;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  font-size: 0.8em;
  color: var(--ink);
  text-decoration: none;
  white-space: nowrap;
  transition: color 200ms ease, transform var(--press) var(--ease-out);
}

.show {
  transition: border-color 200ms ease;
}

@media (hover: hover) and (pointer: fine) {
  .show:hover { border-bottom-color: rgba(255, 255, 255, 0.22); }
  .show-tickets:hover { color: #fff; }
}

.show-tickets:active { transform: scale(0.97); }

/* Songkick sits under the list either way. */
.tour-all {
  display: block;
  margin: clamp(24px, 4vw, 40px) auto 0;
  max-width: 900px;
  text-align: center;
  color: var(--muted);
  text-decoration: none;
  font-size: 0.9em;
  transition: color 240ms ease;
}

@media (hover: hover) and (pointer: fine) {
  .tour-all:hover { color: var(--ink); }
}

@media (max-width: 620px) {
  .show { grid-template-columns: 1fr auto; }
  .show-date { grid-column: 1 / -1; }
}

/* ---------- Listen and follow ---------- */

/* This block did not exist. The six icons were rendering at their default
   300x150 intrinsic size, scaled to 1400px each and filled solid black, which
   is what made the footer 8000+ pixels tall. */
.links {
  padding: clamp(48px, 8vw, 96px) clamp(20px, 5vw, 64px) clamp(56px, 9vw, 112px);
}

.link-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: clamp(12px, 3vw, 32px);
  margin: 0;
  padding: 0;
  list-style: none;
}

.link-row a {
  display: grid;
  place-items: center;
  /* 44px keeps the tap target honest even though the glyph is 26px. */
  width: 44px;
  height: 44px;
  color: var(--muted);
  transition: color 200ms ease, transform var(--press) var(--ease-out);
}

/* Only the <svg> is targeted, so the one child carrying its own fill
   presentation attribute (Instagram's dot) keeps it — a presentation attribute
   on an element beats a value inherited from its parent. */
.link-row svg {
  width: 26px;
  height: 26px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.4;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.link-row a:focus-visible {
  color: var(--ink);
  outline: 1px solid var(--muted);
  outline-offset: 4px;
  border-radius: 4px;
}

@media (hover: hover) and (pointer: fine) {
  .link-row a:hover {
    color: var(--ink);
    transform: translateY(-2px);
  }
}

.link-row a:active { transform: scale(0.94); }

/* Reduced motion means fewer and gentler, not none: the colour and opacity
   changes that explain what is happening stay, everything positional goes. */
@media (prefers-reduced-motion: reduce) {
  .release img,
  .shot img { transition: filter 200ms ease; }
  .release:hover img,
  .release:focus-visible img,
  .shot:hover img,
  .shot:focus-visible img,
  .release:active img,
  .shot:active img { transform: none; }

  a.hero-nav-link:active,
  .link-row a:active,
  .link-row a:hover,
  .show-tickets:active,
  .gallery-empty a:active,
  .tour-empty a:active { transform: none; }

  .hero[data-flare-state="live"] canvas { transition: none; }
}
