/* Graphic lyric layout — full-bleed justified caps over a duotone background. */

/* Fonts are linked from the document head — see index.html. */

:root {
  --dark: #28331d;
  --light: #e6ddc6;
  --ground: var(--dark);
  --ink: var(--light);
}

/* Sections alternate which colour is the ground and which is the type. */
body.is-inverted {
  --ground: var(--light);
  --ink: var(--dark);
}

body {
  background: var(--ground);
  transition: background 900ms ease;
}

/* --- duotone background --------------------------------------------------- */

#bg {
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  background: var(--ground);
}

#bg video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

#bg.is-duotone video {
  filter: url(#duotone);
  /* The video is texture, not the subject — keep it under the type. */
  opacity: 0.55;
}

/* --- type ----------------------------------------------------------------- */

#g-lyrics {
  position: fixed;
  inset: 0;
  z-index: 10;

  display: flex;
  flex-direction: column;
  justify-content: center;

  /* Top reserve is the icon strip's height — the vertical fit measures the
     content box, so the type simply has less room and shrinks to suit. */
  padding: var(--chrome-top, 60px) 2.2vw 9vh;
  box-sizing: border-box;

  font-family: Anton, Impact, "Haettenschweiler", sans-serif;
  color: var(--ink);
  text-transform: uppercase;
  line-height: 0.94;

  pointer-events: none;   /* never blocks the mute toggle */
  opacity: 0;
  transition: opacity 700ms ease;
}

#g-lyrics.is-on { opacity: 1; }

/* --- ink bleed -------------------------------------------------------------
   The filter spreads and roughens the edges; the blend mode is what makes the
   ink sit *in* the footage rather than on top of it. The two blend modes are
   not interchangeable — dark ink soaks in by darkening, light ink by
   lightening, and the palette inverts between sections. */

#g-lyrics.is-inked {
  filter: url(#ink);
}

#g-lyrics[data-blend="multiply"] { mix-blend-mode: multiply; }
#g-lyrics[data-blend="screen"]   { mix-blend-mode: screen; }

/* The filter is applied to the whole layer, so it repaints whenever a word
   reveals. Promote it to its own layer so that repaint stays off the main
   thread's critical path. */
#g-lyrics.is-inked { will-change: filter; }

/* Flush to both edges: the leftover width becomes the gaps between words,
   which is what gives the block its irregular rhythm. */
.g-line {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  width: 100%;
  white-space: nowrap;
}

/* --- composition modes ---------------------------------------------------
   Justified is the signature. The ragged modes exist to break it up, and they
   need real word spaces because there is no leftover width to distribute. */

#g-lyrics[data-align="left"] .g-line   { justify-content: flex-start; gap: var(--min-gap, 0.34em); }
#g-lyrics[data-align="center"] .g-line { justify-content: center;     gap: var(--min-gap, 0.34em); }
#g-lyrics[data-align="right"] .g-line  { justify-content: flex-end;   gap: var(--min-gap, 0.34em); }

/* Where the block sits in the frame. */
#g-lyrics[data-anchor="top"]    { justify-content: flex-start; }
#g-lyrics[data-anchor="center"] { justify-content: center; }
#g-lyrics[data-anchor="bottom"] { justify-content: flex-end; }

/* A lone word spreads letter by letter across the frame. */
.g-line.is-solo .g-word {
  display: flex;
  justify-content: space-between;
  width: 100%;
}

.g-word {
  opacity: 0;
  transition: opacity 260ms ease;
}

.g-word.is-on { opacity: 1; }

/* --- footer --------------------------------------------------------------- */

/* Visit count. Lives in the footer's left cell, which the artist name would
   otherwise occupy, and reads at the same weight as the clock opposite it —
   present if you look for it, not announcing itself. */
.g-views {
  opacity: 0.55;
  font-variant-numeric: tabular-nums;
}


#g-footer {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 20;
  padding: 0 2.2vw 10px;
  pointer-events: none;
  color: var(--ink);
  font-family: "DM Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

/* The rule is the transport: played portion solid, remainder faint. It keeps
   its hairline weight until you reach for it, so it stays a rule and only
   becomes a control on approach. */
.g-scrub {
  position: relative;
  height: 1px;
  margin-bottom: 7px;
  cursor: pointer;
  pointer-events: auto;      /* the footer itself ignores the mouse */
  touch-action: none;        /* let us handle the drag, not the browser */
  transition: height 140ms ease, margin-bottom 140ms ease;
}

/* Invisible padding so a 1px line is still an easy target. */
.g-scrub::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: -11px;
  bottom: -11px;
}

/* the unplayed remainder */
.g-scrub::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--ink);
  opacity: 0.3;
}

.g-scrub-fill {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: var(--ink);
  transform: scaleX(0);
  transform-origin: left center;
}

/* Playhead — only shown while hovering or scrubbing. */
.g-scrub-head {
  position: absolute;
  top: 50%;
  width: 2px;
  height: 11px;
  margin-left: -1px;
  z-index: 2;
  background: var(--ink);
  transform: translateY(-50%) scaleY(0);
  transition: transform 140ms ease;
}

.g-scrub:hover,
.g-scrub:focus-visible,
.g-scrub.is-scrubbing {
  height: 3px;
  margin-bottom: 5px;
  outline: none;
}

.g-scrub:hover .g-scrub-head,
.g-scrub:focus-visible .g-scrub-head,
.g-scrub.is-scrubbing .g-scrub-head {
  transform: translateY(-50%) scaleY(1);
}

/* Keyboard focus in the palette rather than the browser's blue. */
.g-scrub:focus-visible::after { opacity: 0.6; }

/* Three equal-weight columns rather than space-between: the title then sits
   on the centre of the screen no matter what the artist and track fields
   contain — with space-between it drifted toward whichever side was longer. */
.g-meta {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: baseline;
  opacity: 0.92;
}

.g-artist { justify-self: start; }
.g-title  { justify-self: center; }

/* A drawn title is masked like the icons, so it takes the ink colour and
   inverts with the palette instead of being fixed black artwork.
   The mask URL is built absolute in lyrics.js: a relative path in a custom
   property resolves against this stylesheet, not the document, so it would
   look for the image under /css/ and silently mask the element to nothing. */
.g-title.is-drawn {
  display: block;
  height: var(--title-h, 16px);
  width: calc(var(--title-h, 16px) * var(--title-ratio, 6.93));
  background-color: var(--ink);
  -webkit-mask-image: var(--title-src);
  mask-image: var(--title-src);
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
}

.g-time { display: flex; gap: 2.5vw; justify-self: end; }

/* The mute control belongs to this palette now — the earlier white pill was
   built for a white page and reads as a foreign object here. It sits on the
   footer line, in the same monospace, and inverts with everything else. */
#audio-toggle {
  left: 2.2vw;
  bottom: 34px;
  padding: 4px 0;
  border-radius: 0;
  background: transparent;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  color: var(--ink);
  font-family: "DM Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px;
  letter-spacing: 0.16em;
  opacity: 0.75;
  z-index: 30;
}

#audio-toggle:hover,
#audio-toggle:focus-visible {
  opacity: 1;
  text-decoration: underline;
}

/* The default focus ring is bright blue, which is jarring against this
   palette — keep focus visible, but in the page's own colours. */
#audio-toggle:focus-visible {
  outline: 1px solid var(--ink);
  outline-offset: 3px;
}

@media (max-width: 640px) {
  /* Keep --chrome-top: this is the only other rule that sets this padding,
     and overriding the top value collapsed the band the icon strip sits in,
     putting the type straight over the icons. */
  #g-lyrics { padding: var(--chrome-top, 60px) 4vw 10vh; }
  #g-footer { font-size: 9px; letter-spacing: 0.1em; }
}

@media (prefers-reduced-motion: reduce) {
  #g-lyrics, .g-word, body { transition: none; }
}
