/* KayRaoke: shared tokens, site pages (generated by tools/build_site.py) and the player. */
@font-face {
  font-family: "Heebo";
  src: url("../fonts/Heebo.woff2") format("woff2");
  font-weight: 400 800;
  font-display: swap;
}

:root {
  --ink: #0d0e24;
  --navy: #14163a;
  --surface: #1b1e48;
  --surface-hi: #252961;
  --line: rgba(251, 246, 236, 0.12);        /* decorative card borders */
  --line-strong: rgba(251, 246, 236, 0.42); /* boundaries of controls: 3:1 or more on the night sky */
  --cream: #fbf6ec;
  --muted: #bdb9d6;
  --muted-2: #a9a5c8;                        /* small print; 4.5:1 or more on every part of the sky */
  --card: rgba(27, 30, 72, 0.6);
  --card-hi-border: rgba(242, 177, 56, 0.45);
  --gold: #f2b138;
  --gold-hi: #ffe26e;
  --gold-lo: #ff9a1e;
  --outline: #120e28;

  --font: "Heebo", "Arial Hebrew", system-ui, sans-serif;
  --radius: 14px;
  --radius-sm: 8px;
  --h1: clamp(32px, 6vw, 48px);
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-6: 24px;
  --space-8: 32px;
  --space-12: 48px;
  --container: 1200px;
  --ease: cubic-bezier(0.2, 0.7, 0.2, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in-out: cubic-bezier(0.45, 0, 0.55, 1);
  --ease-intro: cubic-bezier(0.22, 1, 0.36, 1); /* the opening: a long, soft deceleration */
  --control-bg: rgba(27, 30, 72, 0.7);
  --radius-md: 10px;
  --h1-hero: clamp(36px, 6.5vw, 60px);
  --h2: clamp(26px, 4vw, 34px);
  --space-16: 72px;
  /* the word "karaoke" and the hero's ball: warm colours of similar brightness (no single bright band), symmetric so
     the slow back-and-forth drift has no seam */
  --grad-karaoke: #ff9a1e, #f07a5a, #e0559a, #a970f5, #e0559a, #f07a5a, #ff9a1e;
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; color-scheme: dark; }
/* The hidden attribute always wins over component display rules (buttons, links shown as flex or grid).
   Overlays are the exception: they keep their own fade-out rule further down. */
[hidden]:not(.overlay) { display: none !important; }
body {
  margin: 0;
  font-family: var(--font);
  color: var(--cream);
  background: var(--ink);
  line-height: 1.5;
}
img { display: block; max-width: 100%; }
a { color: inherit; }
button { font: inherit; color: inherit; }
:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; border-radius: 4px; }
::selection { background: rgba(242, 177, 56, 0.35); }

.skip-link {
  position: absolute;
  inset-inline-start: var(--space-4);
  top: -60px;
  padding: var(--space-2) var(--space-4);
  background: var(--gold);
  color: var(--navy);
  font-weight: 700;
  border-radius: var(--radius-sm);
  z-index: 100;
  text-decoration: none;
}
.skip-link:focus { top: var(--space-4); }

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden; clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* Night-sky ground shared by both pages: deep navy falling to a warm horizon. */
.sky { background: #08081c; }
.sky::after {
  content: ""; position: fixed; inset: 0; z-index: -2; pointer-events: none; /* below the home dunes (-1) */
  background:
    radial-gradient(120% 70% at 50% 115%, rgba(120, 52, 58, 0.55), transparent 60%),
    linear-gradient(180deg, #08081c 0%, #15123a 55%, #2a1838 100%);
}
/* Stars (owner's request: "movement that is barely noticeable, but movement"): two layers drift slowly sideways at
   slightly different speeds (about 2 px a second, a hint of depth) and the nearer one gently brightens and dims.
   Transform and opacity only, so the browser moves ready-made layers instead of redrawing. Each layer is one tile
   wider than the screen and moves by exactly one tile, so the loop has no seam. */
.stars { position: fixed; inset: 0; pointer-events: none; overflow: hidden; }
.stars i { position: absolute; top: 0; bottom: 0; left: 0; }
.stars i:first-child {
  width: calc(100% + 640px); opacity: 0.8;
  background-image:
    radial-gradient(1.2px 1.2px at 12% 18%, rgba(255, 245, 220, 0.7), transparent),
    radial-gradient(1px 1px at 27% 62%, rgba(255, 245, 220, 0.45), transparent),
    radial-gradient(1.4px 1.4px at 44% 8%, rgba(255, 245, 220, 0.6), transparent),
    radial-gradient(1px 1px at 58% 35%, rgba(255, 245, 220, 0.4), transparent),
    radial-gradient(1.6px 1.6px at 71% 14%, rgba(255, 245, 220, 0.7), transparent),
    radial-gradient(1px 1px at 83% 48%, rgba(255, 245, 220, 0.45), transparent),
    radial-gradient(1.2px 1.2px at 92% 26%, rgba(255, 245, 220, 0.55), transparent),
    radial-gradient(1px 1px at 6% 44%, rgba(255, 245, 220, 0.4), transparent),
    radial-gradient(1.3px 1.3px at 36% 30%, rgba(255, 245, 220, 0.5), transparent),
    radial-gradient(1px 1px at 66% 70%, rgba(255, 245, 220, 0.3), transparent);
  background-size: 640px 520px;
  animation: stars-drift-far 360s linear infinite;
}
.stars i:last-child {
  width: calc(100% + 560px);
  background-image:
    radial-gradient(1.8px 1.8px at 8% 30%, rgba(255, 245, 220, 0.85), transparent),
    radial-gradient(1.4px 1.4px at 31% 12%, rgba(255, 236, 190, 0.75), transparent),
    radial-gradient(1.6px 1.6px at 52% 54%, rgba(255, 245, 220, 0.7), transparent),
    radial-gradient(1.2px 1.2px at 77% 38%, rgba(255, 245, 220, 0.8), transparent),
    radial-gradient(2px 2px at 90% 8%, rgba(255, 236, 190, 0.8), transparent),
    radial-gradient(1.3px 1.3px at 64% 84%, rgba(255, 245, 220, 0.6), transparent);
  background-size: 560px 460px;
  animation: stars-drift-near 240s linear infinite, stars-twinkle 7s var(--ease-in-out) infinite alternate;
}
@keyframes stars-drift-far { to { transform: translateX(-640px); } }
@keyframes stars-drift-near { to { transform: translateX(-560px); } }
@keyframes stars-twinkle { 0% { opacity: 0.2; } 45% { opacity: 0.85; } 100% { opacity: 0.4; } }

/* ---------- Site pages (generated by tools/build_site.py) ---------- */
.page { max-width: var(--container); margin: 0 auto; padding: var(--space-6) var(--space-4) var(--space-12); position: relative; }
/* The header stays at the top while the page scrolls (owner's request) and gets a little smaller once the page has
   scrolled: it slides up by its top margin (sticky top goes negative, so the page below never moves), the logo scales
   down and a dark bar fades in behind it. Full width, with the content column's edges kept by the inline padding. */
.site-header {
  --shrink: 12px;
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-3) var(--space-6);
  padding: calc(var(--space-2) + var(--shrink)) max(var(--space-4), calc((100% - var(--container)) / 2 + var(--space-4))) var(--space-2);
  position: sticky; top: 0;
  transition: top 0.25s var(--ease);
}
.site-header::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: rgba(8, 8, 28, 0.86); border-block-end: 1px solid var(--line);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  opacity: 0; transition: opacity 0.25s var(--ease);
}
.site-header .brand img { transform-origin: 0 50%; transition: transform 0.25s var(--ease); }
[dir="rtl"] .site-header .brand img { transform-origin: 100% 50%; }
html.scrolled .site-header { top: calc(-1 * var(--shrink)); }
html.scrolled .site-header::before { opacity: 1; }
html.scrolled .site-header .brand img { transform: scale(0.84); }
/* in-page links and the skip link land below the header, not under it */
html { scroll-padding-top: 76px; }
.site-nav { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2); }
.nav-links { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2); list-style: none; margin: 0; padding: 0; }
.site-nav a {
  display: inline-flex; align-items: center; justify-content: center; min-height: 44px; min-width: 44px; padding: 0 var(--space-3);
  border-radius: 999px; text-decoration: none; font-weight: 500; color: var(--muted);
  transition: color 0.2s var(--ease), background 0.2s var(--ease);
}
.site-nav a:hover, .site-nav a[aria-current="page"] { color: var(--cream); background: rgba(251, 246, 236, 0.08); }
.site-nav a[aria-current="page"] { box-shadow: inset 0 -2px 0 var(--gold); }
.site-nav .lang-switch { border: 1px solid var(--line-strong); color: var(--cream); margin-inline-start: var(--space-2); }
.site-nav .lang-switch:hover { border-color: var(--gold); }

/* Phones: the page links fold into a menu under the header; the language switch stays visible next to the button.
   Only with JavaScript (html.js, set in <head>), so without it the links simply stay in the header. */
.site-header { z-index: 30; }
.menu-toggle { display: none; }
.menu-toggle svg { width: 22px; height: 22px; }
.menu-toggle .i-close, .menu-toggle[aria-expanded="true"] .i-menu { display: none; }
.menu-toggle[aria-expanded="true"] .i-close { display: block; }
@keyframes menu-in { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
@media (max-width: 767px) {
  .site-header { column-gap: var(--space-3); }
  .js .menu-toggle {
    display: inline-grid; place-items: center; width: 44px; height: 44px; order: 2; cursor: pointer;
    border-radius: 999px; border: 1px solid var(--line-strong); background: transparent; color: var(--cream);
    transition: border-color 0.2s var(--ease);
  }
  .js .menu-toggle:hover, .js .menu-toggle[aria-expanded="true"] { border-color: var(--gold); }
  .js .site-nav .lang-switch { order: 1; margin-inline-start: 0; }
  .js .nav-links {
    display: none; position: absolute; top: 100%; inset-inline: var(--space-4); margin-top: var(--space-2);
    flex-direction: column; align-items: stretch; gap: var(--space-1); padding: var(--space-2);
    background: var(--surface); border: 1px solid var(--line-strong); border-radius: var(--radius);
    box-shadow: 0 16px 40px rgba(0, 0, 0, 0.5);
  }
  .js .nav-links.open { display: flex; animation: menu-in 0.15s var(--ease-out); }
  .js .nav-links a { display: flex; justify-content: flex-start; min-height: 48px; padding: 0 var(--space-4); border-radius: var(--radius-sm); font-size: 18px; }
}
/* The narrowest phones (320-380 px): a slightly smaller logo keeps logo, language switch and menu button on one row. */
@media (max-width: 380px) { .site-header .brand img { height: 40px; } }

@keyframes rise { from { transform: translateY(8px); } to { transform: none; } }
.page-head, .prose { animation: rise 0.3s var(--ease-out) both; }
/* The opening screen is a full-width band (it sits outside the content column, in <main> itself): the dunes run
   edge to edge and dissolve into the page below. On desktop it fills the first screen under the header. */
.hero-wrap { position: relative; }
.hero-viz {
  position: absolute; inset: 0; width: 100%; height: 100%; z-index: -1; pointer-events: none;
  -webkit-mask-image: linear-gradient(to bottom, #000 70%, transparent 100%); mask-image: linear-gradient(to bottom, #000 70%, transparent 100%);
}
.hero-split {
  max-width: var(--container); margin-inline: auto; padding: var(--space-12) var(--space-4);
  display: grid; gap: var(--space-8); align-items: center;
}
@media (min-width: 900px) {
  .hero-split {
    grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); gap: var(--space-12); padding-block: var(--space-16);
    min-height: calc(100vh - 72px); min-height: min(calc(100svh - 72px), 920px);
  }
}
.kicker { margin: 0 0 var(--space-3); color: var(--gold); font-weight: 500; letter-spacing: 0.08em; font-size: 14px; text-transform: uppercase; text-wrap: balance; }
/* The English tagline on Hebrew pages keeps its own direction but lines up with the Hebrew heading. */
[dir="rtl"] .kicker[dir="ltr"], [dir="rtl"] .lede[dir="ltr"] { text-align: right; }
.hero-actions { display: flex; flex-wrap: wrap; gap: var(--space-3); margin: 0; }
.hero-actions .btn { text-wrap: balance; }
.hero-stage { position: relative; display: grid; justify-items: center; gap: var(--space-3); padding-top: 28px; }
.demo-screen {
  position: relative; width: min(100%, 560px); aspect-ratio: 16 / 10; border-radius: 18px; overflow: hidden;
  background: radial-gradient(90% 70% at 50% 110%, rgba(120, 52, 58, 0.5), transparent 60%), linear-gradient(180deg, #0a0a22, #1a1442);
  box-shadow: 0 0 0 1px rgba(251, 246, 236, 0.14), 0 24px 60px rgba(0, 0, 0, 0.45);
  display: grid; place-items: center; padding: 8% 6% 10%;
}
.demo-logo { position: absolute; top: 14px; inset-inline-start: 16px; height: 22px; width: auto; opacity: 0.9; }
.demo-lyrics { display: grid; gap: 0.5em; text-align: center; font-size: clamp(18px, 3.4vw, 32px); font-weight: 800; line-height: 1.25; transition: opacity 0.3s var(--ease); }
.demo-line { text-wrap: balance; }
.demo-line .w-base { color: var(--cream); text-shadow: 0 0 1px var(--outline), 1px 1px 0 var(--outline), -1px -1px 0 var(--outline), 0 4px 12px rgba(0,0,0,0.5); }
.demo-line .w-fill { position: absolute; inset: 0; color: transparent; background: linear-gradient(180deg, var(--gold-hi) 15%, var(--gold-lo) 90%); -webkit-background-clip: text; background-clip: text; visibility: hidden; }
.demo-bar { position: absolute; inset-inline: 6%; bottom: 14px; height: 4px; border-radius: 2px; background: rgba(251, 246, 236, 0.16); overflow: hidden; }
.demo-bar i { display: block; height: 100%; width: 100%; background: var(--gold); transform: scaleX(0); transform-origin: left; }
[dir="rtl"] .demo-bar i { transform-origin: right; }
.demo-lyrics.fading { opacity: 0; }
/* Under the demo screen: which song is playing, and a link that opens it in the player. */
.demo-caption { display: grid; justify-items: center; row-gap: var(--space-2); width: min(100%, 560px); }
.demo-from { margin: 0; font-size: 15px; color: var(--muted); text-align: center; text-wrap: balance; min-height: 3em; align-content: center; }
.demo-from strong { color: var(--cream); font-weight: 700; }
.demo-open {
  display: inline-flex; align-items: center; gap: var(--space-2); min-height: 44px; padding: 0 var(--space-4);
  border-radius: 999px; border: 1px solid var(--line-strong); color: var(--cream); text-decoration: none; font-weight: 700; font-size: 15px;
  transition: border-color 0.2s var(--ease), background 0.2s var(--ease);
}
.demo-open:hover { border-color: var(--gold); background: rgba(242, 177, 56, 0.1); }
.demo-open svg { width: 16px; height: 16px; color: var(--gold); }
.mic { position: absolute; width: clamp(64px, 12%, 96px); height: auto; top: 0; inset-inline-end: 2%; transform-origin: 50% 90%;
  animation: mic-drop 1s var(--ease-intro) 0.7s both, float 5s var(--ease-in-out) 1.7s infinite; }
/* The sound waves come out of the microphone only while a word of the demo is being sung (home.js sets .singing). */
.mic .wave { transform-origin: 69px 0px; animation: wave 2.4s var(--ease-out) infinite; animation-play-state: paused; }
.hero-stage.singing .mic .wave { animation-play-state: running; }
.mic .wave-2 { animation-delay: 0.5s; }
.mic .waves { opacity: 0; transition: opacity 0.3s var(--ease); }
.hero-stage.singing .mic .waves { opacity: 1; }
@keyframes float { 0%, 100% { transform: translateY(0) rotate(-6deg); } 50% { transform: translateY(-10px) rotate(-2deg); } }
@keyframes wave { 0% { opacity: 0; transform: scale(0.6); } 30% { opacity: 1; } 100% { opacity: 0; transform: scale(1.35); } }
/* Phones: the hero column stacks, so the title's microphone is the only one (two in one column look repeated). */
@media (max-width: 899px) { .hero-stage .mic { display: none; } }



.credit { color: inherit; text-decoration: underline; text-decoration-color: var(--line-strong); text-underline-offset: 3px; }
.credit:hover { color: var(--cream); text-decoration-color: currentColor; }
.footer-links a, .credit { display: inline-block; padding-block: 12px; }

/* minmax(0, 1fr): a row is never widened by the longest unbreakable name in another row */
.song-list, .song-grid { grid-template-columns: minmax(0, 1fr); }
@media (min-width: 900px) { .song-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* Songs page filters. Desktop: search, language chips, then artist and sort side by side.
   Phones: search, then a Filter button (opens language + artist) and the sort picker; see the media query below. */
.filters { grid-template-columns: auto auto 1fr; grid-template-areas: "search search search" "chips chips chips" "artist sort ."; column-gap: var(--space-6); }
.filter-bar, .filter-panel { display: contents; }
.filters .search-field { grid-area: search; }
.filters .chips { grid-area: chips; }
.filters .artist-select { grid-area: artist; }
.filters .sort-select { grid-area: sort; }
.filters .filter-toggle, .filters .filter-done, .filters .sort-select svg { display: none; } /* phones only (below) */
/* Computers (owner's request): language, artist and sort on one row under the search; sort at the row's end. */
@media (min-width: 768px) {
  .page .filters { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3) var(--space-6); }
  .page .filters .search-field { flex: 1 0 100%; max-width: none; }
  .page .filters .search-field input { max-width: 420px; }
  .page .filters .chips { order: 1; }
  .page .filters .artist-select { order: 2; }
  .page .filters .sort-select { order: 3; margin-inline-start: auto; }
}
.filter-count {
  min-width: 22px; height: 22px; padding: 0 6px; border-radius: 999px; display: inline-grid; place-items: center;
  background: var(--gold); color: var(--navy); font-size: 13px; font-weight: 800;
}
@media (max-width: 767px) {
  .js .filters { grid-template-columns: minmax(0, 1fr); grid-template-areas: none; }
  .js .filters .search-field, .js .filters .chips, .js .filters .artist-select, .js .filters .sort-select { grid-area: auto; }
  .js .filter-bar { display: flex; flex-wrap: wrap; gap: var(--space-2); }
  .js .filters .filter-toggle {
    display: inline-flex; align-items: center; gap: var(--space-2); min-height: 44px; padding: 0 var(--space-4); cursor: pointer;
    border-radius: 999px; border: 1px solid var(--line-strong); background: var(--control-bg); color: var(--cream); font-weight: 500;
  }
  .js .filter-toggle[aria-expanded="true"] { border-color: var(--gold); }
  .js .filter-toggle svg { width: 20px; height: 20px; }
  .js .filter-toggle [hidden] { display: none; }
  /* sort: the native picker in a pill with an icon; its label stays for screen readers */
  .js .sort-select { position: relative; }
  .js .sort-select > span { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .js .filters .sort-select svg { display: block; position: absolute; inset-inline-start: 14px; width: 20px; height: 20px; pointer-events: none; color: var(--cream); }
  .js .sort-select select { border-radius: 999px; padding-inline-start: 42px; font-weight: 500; }
  .js .filter-panel {
    display: none; gap: var(--space-4); padding: var(--space-4);
    background: var(--card); border: 1px solid var(--line-strong); border-radius: var(--radius);
  }
  .js .filter-panel.open { display: grid; animation: menu-in 0.15s var(--ease-out); }
  .js .filter-panel .artist-select { display: grid; gap: var(--space-2); }
  .js .filter-panel .artist-select select { width: 100%; }
  .js .filters .filter-done { display: inline-flex; width: 100%; }
}

.artists-strip .marquee { overflow: hidden; margin-top: var(--space-4); padding-block: var(--space-2); mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent); -webkit-mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent); }
.artists-strip .marquee:focus-within { mask-image: none; -webkit-mask-image: none; }
.marquee-track { display: flex; gap: var(--space-3); width: max-content; animation: marquee 60s linear infinite; }
.marquee-copy { display: contents; }
[dir="rtl"] .marquee-track { animation-name: marquee-rtl; }
/* The carousel stops under the mouse, while a card has keyboard focus, and while a finger rests on it. */
.marquee:hover .marquee-track, .marquee:focus-within .marquee-track, .marquee:active .marquee-track { animation-play-state: paused; }
@keyframes marquee { to { transform: translateX(calc(-50% - var(--space-3) / 2)); } }
@keyframes marquee-rtl { to { transform: translateX(calc(50% + var(--space-3) / 2)); } }
.mcard {
  display: grid; justify-items: center; gap: var(--space-1); width: 172px; padding: var(--space-4) 10px; text-decoration: none; text-align: center;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  transition: background 0.2s var(--ease), border-color 0.2s var(--ease), transform 0.2s var(--ease);
}
.mcard:hover, .mcard:focus-visible { background: var(--surface-hi); border-color: var(--card-hi-border); transform: translateY(-3px); }
.mcard .avatar { width: 64px; height: 64px; font-size: 22px; }
.mcard-name { font-weight: 700; font-size: 15px; line-height: 1.2; text-wrap: balance; }
.mcard-count { font-size: 13px; color: var(--gold); }
@media (prefers-reduced-motion: reduce) {
  .marquee-track { animation: none; flex-wrap: wrap; width: auto; }
  .marquee-copy { display: none; }
  .artists-strip .marquee { mask-image: none; -webkit-mask-image: none; }
  .mic, .mic .wave { animation: none; }
}
.hero h1 { margin: 0; font-size: var(--h1-hero); line-height: 1.1; font-weight: 800; letter-spacing: -0.01em; text-wrap: balance; }
.hero-lead { margin: var(--space-4) 0 var(--space-2); font-size: 19px; color: var(--muted); max-width: 46ch; text-wrap: pretty; }
.hero-motto { margin: 0 0 var(--space-6); font-size: 19px; font-weight: 700; color: var(--cream); }
/* The colours drift slowly through the word (one full cycle about 10 s); the gradient repeats its first colour at the
   end and the image is two words wide, so moving it by one tile loops without a seam. */
.hero h1 .grad {
  background: linear-gradient(90deg, var(--grad-karaoke)) 0% 50% / 300% 100%;
  -webkit-background-clip: text; background-clip: text; color: transparent;
  -webkit-box-decoration-break: clone; box-decoration-break: clone; padding-bottom: 0.06em;
}

/* Opening of the home page (owner's requests: "open with a nice animation", then "smoother and nicer"). The heading's
   words come into focus one after another like a karaoke line, then the text, the button, the karaoke screen and the
   microphones glide in; the ball joins at the end (home.js). About 1.8 s, once, with one soft deceleration and no
   bounce. It waits for the font (site.js adds html.intro-go when the font is ready, 0.8 s at most), so no word jumps
   while it moves; without JavaScript it plays straight away. Reduced motion: everything appears at once. */
@keyframes word-in { from { opacity: 0; transform: translateY(0.28em); filter: blur(8px); } to { opacity: 1; transform: none; filter: none; } }
@keyframes fade-up { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
@keyframes screen-in { from { opacity: 0; transform: translateY(22px) scale(0.98); } to { opacity: 1; transform: none; } }
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes mic-drop { from { opacity: 0; transform: translateY(-26px) rotate(-18deg); } to { opacity: 1; transform: translateY(0) rotate(-6deg); } }
@keyframes mic-pop { from { opacity: 0; transform: translateY(8px) scale(0.7) rotate(-28deg); } to { opacity: 1; transform: rotate(-12deg) translateY(0); } }
.hero .h1w { display: inline-block; --d: 0.1s; animation: word-in 0.9s var(--ease-intro) var(--d) both; }
.hero .h1w:nth-child(2) { --d: 0.19s; }
.hero .h1w:nth-child(3) { --d: 0.28s; }
.hero .h1w:nth-child(4) { --d: 0.37s; }
.hero .h1w:nth-child(5) { --d: 0.46s; }
.hero .h1w:nth-child(6) { --d: 0.55s; }
.hero h1 .h1w.grad { animation: word-in 0.9s var(--ease-intro) var(--d) both, grad-drift 14s var(--ease-in-out) infinite alternate; }
.hero .kicker { animation: fade-up 0.9s var(--ease-intro) 0s both; }
.hero-lead { animation: fade-up 0.9s var(--ease-intro) 0.55s both; }
.hero-motto { animation: fade-up 0.9s var(--ease-intro) 0.68s both; }
.hero-actions { animation: fade-up 0.9s var(--ease-intro) 0.8s both; }
.hero-stage .demo-screen { animation: screen-in 1.1s var(--ease-intro) 0.2s both; }
.hero-stage .demo-caption { animation: fade-in 0.9s var(--ease) 0.9s both; }
.hero-viz { animation: fade-in 1.6s var(--ease) both; }
/* held at the first frame until the font is ready (JavaScript only) */
.js:not(.intro-go) .hero .h1w, .js:not(.intro-go) .hero .kicker, .js:not(.intro-go) .hero-lead,
.js:not(.intro-go) .hero-motto, .js:not(.intro-go) .hero-actions, .js:not(.intro-go) .hero-stage .demo-screen,
.js:not(.intro-go) .hero-stage .demo-caption, .js:not(.intro-go) .hero-viz, .js:not(.intro-go) .hero-mic,
.js:not(.intro-go) .hero-stage .mic { animation-play-state: paused; }
/* The colours blend and drift slowly back and forth through the word (a third of the gradient shows at a time). */
@keyframes grad-drift { to { background-position: 100% 50%; } }
@media (forced-colors: active) { .hero h1 .grad { color: CanvasText; background: none; } }
/* Hero decoration (owner's request): a small microphone that sways and "sings" beside the title, and a small
   ball that hops around the title and subtitle, spinning as it rolls (home.js drives the ball). */
.hero-wrap { overflow-x: clip; }
.hero-text { position: relative; }
.hero-mic {
  position: absolute; top: -10px; inset-inline-end: 0; width: 40px; pointer-events: none;
  transform-origin: 50% 85%; animation: mic-pop 1s var(--ease-intro) 0.45s both, mic-sing 2.8s var(--ease-in-out) 1.45s infinite;
}
.hero-mic svg { display: block; width: 100%; height: auto; }
.hero-mic .wave { transform-origin: 69px 0px; animation: wave 2.4s var(--ease-out) infinite; }
.hero-mic .wave-2 { animation-delay: 0.6s; }
@keyframes mic-sing {
  0%, 100% { transform: rotate(-12deg) translateY(0); }
  25% { transform: rotate(5deg) translateY(-4px); }
  50% { transform: rotate(-6deg) translateY(0); }
  75% { transform: rotate(9deg) translateY(-3px); }
}
@media (min-width: 900px) { .hero-mic { width: 54px; top: -22px; } }
.hero-ball {
  position: absolute; top: 0; left: 0; width: 16px; height: 16px; z-index: 2; pointer-events: none;
  opacity: 0; transition: opacity 0.8s var(--ease); will-change: transform;
}
.hero-ball.on { opacity: 1; }
.hero-ball i {
  position: absolute; inset: 0; border-radius: 50%;
  background: conic-gradient(#ff9a1e, #f07a5a, #e0559a, #a970f5, #ff9a1e);
  box-shadow: 0 0 12px rgba(255, 154, 30, 0.55);
}
.hero-ball::after { /* a fixed highlight, so the ball looks round while its colours turn */
  content: ""; position: absolute; inset: 0; border-radius: 50%;
  background: radial-gradient(circle at 32% 28%, rgba(255, 255, 255, 0.85) 0 2px, rgba(255, 255, 255, 0) 5px);
}
@media (prefers-reduced-motion: reduce) { .hero-ball { display: none; } }

/* Hero scene (owner's request): an illustrated laptop with a wired microphone, a speaker and two kids singing,
   drawn in tools/hero-scene.svg and inlined by build_site.py. The laptop's lid and screen are HTML laid over the
   drawing's empty lid area (x 210-590, y 120-372 of 800 x 560), so the live karaoke demo plays on the laptop.
   Opening (owner: "make it look like a real laptop opening", "after the rest of the opening"): the laptop arrives
   closed; once the text has come in, the lid's cover folds up to a line at the hinge and the dark screen side rises
   from it, then the screen wakes up (glow, logo, lyrics) and the demo starts (home.js). The kids sway and bob, their
   mouths sing and the speaker pulses while a word is being sung (home.js sets .singing), the raised arm waves, eyes
   blink, notes float. Reduced motion: the laptop is open and on at once, all still. */
.scene { position: relative; width: min(100%, 680px); aspect-ratio: 800 / 560; }
.scene-art { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.laptop-lid {
  position: absolute; left: 26.25%; top: 21.43%; width: 47.5%; height: 45%; container-type: inline-size;
  padding: 1.5% 1.5% 1.7%; border-radius: 4% 4% 1.4% 1.4% / 6% 6% 2% 2%;
  /* the bezel around black glass with a faint reflection: what shows while the screen is off */
  background: linear-gradient(115deg, transparent 22%, rgba(251, 246, 236, 0.05) 40%, transparent 58%) content-box,
    linear-gradient(#04040c, #04040c) content-box, linear-gradient(180deg, #2a2e66, #15173d);
  box-shadow: inset 0 0 0 1px rgba(251, 246, 236, 0.14), 0 18px 40px rgba(0, 0, 0, 0.45);
  transform-origin: 50% 100%;
}
.laptop-lid::before { /* camera */
  content: ""; position: absolute; top: 1.6%; left: 49.4%; width: 1.2%; aspect-ratio: 1; border-radius: 50%;
  background: #0d0e24; box-shadow: inset 0 0 0 1px rgba(251, 246, 236, 0.18);
}
.scene .demo-screen {
  width: 100%; height: 100%; aspect-ratio: auto; border-radius: 1.6cqw; padding: 7cqw 5cqw 8cqw;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.5), inset 0 0 40px rgba(242, 177, 56, 0.08);
}
/* The closed lid lying on the keyboard deck (hinge y 372, x 210-590 like the open lid, so the width holds through the
   flip; front y 402, x 175-625, above the base's front lip): ::before is its outer cover, ::after the soft shadow the
   open lid casts on the deck at the hinge. */
.laptop-cover { position: absolute; left: 21.875%; top: 66.43%; width: 56.25%; height: 5.36%; pointer-events: none; }
.laptop-cover::before, .laptop-cover::after {
  content: ""; position: absolute; inset: 0; clip-path: polygon(7.8% 0, 92.2% 0, 100% 100%, 0 100%); transform-origin: 50% 0;
}
.laptop-cover::before {
  background: radial-gradient(2.4% 18% at 50% 50%, var(--gold) 0 40%, rgba(242, 177, 56, 0) 100%),
    linear-gradient(100deg, transparent 18%, rgba(251, 246, 236, 0.13) 42%, transparent 62%),
    linear-gradient(0deg, rgba(251, 246, 236, 0.3) 0 1px, transparent 1px),
    linear-gradient(180deg, #23275c, #333879);
}
.laptop-cover::after { inset-block-end: 55%; background: linear-gradient(180deg, rgba(5, 5, 18, 0.55), rgba(5, 5, 18, 0)); opacity: 0; }
.scene .demo-logo { top: 3.2cqw; inset-inline-start: 3.6cqw; height: 5.2cqw; }
.scene .demo-lyrics { font-size: 6.2cqw; }
@media (max-width: 600px) { .scene .demo-lyrics { font-size: 7.6cqw; gap: 0.35em; } } /* the laptop is small on phones */
.scene .demo-bar { bottom: 3.4cqw; inset-inline: 5cqw; height: max(3px, 0.9cqw); }

/* The lid swings from 0 to 100 degrees on one ease-in-out, seen from about 7 degrees above the deck: the cover's
   height follows sin(7deg - angle) down to a line at the hinge, then the screen side's height follows
   sin(angle - 7deg) (keyframe stops sampled from those curves); the lid brightens as it turns upright. */
@keyframes cover-fold {
  4% { transform: scaleY(0.961); clip-path: polygon(7.8% 0, 92.2% 0, 99.7% 100%, 0.3% 100%); }
  8% { transform: scaleY(0.838); clip-path: polygon(7.8% 0, 92.2% 0, 98.74% 100%, 1.26% 100%); }
  11% { transform: scaleY(0.688); clip-path: polygon(7.8% 0, 92.2% 0, 97.57% 100%, 2.43% 100%); }
  14% { transform: scaleY(0.484); clip-path: polygon(7.8% 0, 92.2% 0, 95.98% 100%, 4.02% 100%); }
  16.5% { transform: scaleY(0.271); clip-path: polygon(7.8% 0, 92.2% 0, 94.31% 100%, 5.69% 100%); }
  /* edge-on, the lid's thickness stays as a line at the hinge until the screen side has risen past it */
  19.2%, 21.5% { transform: scaleY(0.08); clip-path: polygon(7.8% 0, 92.2% 0, 92.82% 100%, 7.18% 100%); opacity: 1; }
  22.5%, to { transform: scaleY(0.08); clip-path: polygon(7.8% 0, 92.2% 0, 92.82% 100%, 7.18% 100%); opacity: 0; }
}
@keyframes lid-rise {
  0%, 19.2% { transform: scaleY(0); filter: brightness(0.5); box-shadow: inset 0 0 0 1px rgba(251, 246, 236, 0.14), 0 0 0 rgba(0, 0, 0, 0); } /* edge-on: the cover's line shows the lid */
  22% { transform: scaleY(0.041); filter: brightness(0.5); }
  27% { transform: scaleY(0.128); filter: brightness(0.52); }
  32% { transform: scaleY(0.233); filter: brightness(0.54); }
  37% { transform: scaleY(0.355); filter: brightness(0.57); }
  42% { transform: scaleY(0.484); filter: brightness(0.61); box-shadow: inset 0 0 0 1px rgba(251, 246, 236, 0.14), 0 0 0 rgba(0, 0, 0, 0); } /* the drop shadow grows with the lid, no haze around a thin bar */
  47% { transform: scaleY(0.613); filter: brightness(0.65); }
  52% { transform: scaleY(0.73); filter: brightness(0.7); }
  57% { transform: scaleY(0.827); filter: brightness(0.76); }
  62% { transform: scaleY(0.9); filter: brightness(0.81); }
  67% { transform: scaleY(0.95); filter: brightness(0.85); }
  72% { transform: scaleY(0.979); filter: brightness(0.9); }
  78% { transform: scaleY(0.996); filter: brightness(0.94); }
  to { transform: none; filter: none; }
}
/* the backlight comes on a little bright, then settles */
@keyframes screen-wake { from { opacity: 0; filter: brightness(1.9) saturate(0.5); } 35% { opacity: 1; } to { opacity: 1; filter: none; } }
@keyframes wake-in { from { opacity: 0; } } /* to the element's own opacity */
@keyframes glow-up { from { opacity: 0.1; } to { opacity: 1; } } /* the room stays dim until the screen lights it */
@keyframes kid-in-a { from { opacity: 0; transform: translateX(-22px); } to { opacity: 1; transform: none; } }
@keyframes kid-in-b { from { opacity: 0; transform: translateX(22px); } to { opacity: 1; transform: none; } }
/* small sway: the mic cable joins the boy's hand through a short stub that tolerates about 4 px of movement */
@keyframes kid-sway { from { transform: rotate(-0.8deg); } to { transform: rotate(0.8deg) translateY(-2px); } }
@keyframes tz-sway { from { transform: rotate(-4deg); } to { transform: rotate(4deg); } }
@keyframes kid-bounce { from { transform: translateY(0); } to { transform: translateY(-5px); } }
@keyframes head-nod { from { transform: rotate(-3deg); } to { transform: rotate(3deg); } }
@keyframes arm-wave { from { transform: rotate(-7deg); } to { transform: rotate(9deg); } }
@keyframes eyes-blink { 0%, 95%, 100% { transform: scaleY(1); } 97% { transform: scaleY(0.04); } } /* shut, not a pale slit */
@keyframes mouth-sing { from { transform: scaleY(0.55); } to { transform: scaleY(1.1); } }
@keyframes cone-thump { 0%, 100% { transform: scale(1); } 40% { transform: scale(1.07); } }
@keyframes note-float { 0% { opacity: 0; transform: translateY(8px); } 25% { opacity: 1; } 100% { opacity: 0; transform: translateY(-18px); } }
.has-scene .scene-art { animation: fade-in 1s var(--ease) 0.1s both; }
/* The laptop opens once the text's opening has finished (1.85 s), the screen wakes when the lid is open (3.3 s), the
   demo starts after the lyrics are in (home.js, 4.3 s). The swing's easing is in the keyframes, hence linear. */
.has-scene .laptop-cover { animation: fade-in 1s var(--ease) 0.1s both; }
.has-scene .laptop-cover::before { animation: cover-fold 1.4s linear 1.85s both; }
.has-scene .laptop-cover::after { animation: fade-in 0.9s var(--ease-in-out) 2.1s both; }
.has-scene .laptop-lid { animation: lid-rise 1.4s linear 1.85s both; }
.has-scene .scene .demo-screen { animation: screen-wake 0.7s var(--ease) 3.3s both; }
.has-scene .scene .demo-logo { animation: wake-in 0.5s var(--ease) 3.55s backwards; }
.has-scene .scene .demo-lyrics, .has-scene .scene .demo-bar { animation: wake-in 0.5s var(--ease) 3.75s backwards; }
.has-scene .demo-caption { animation: fade-in 0.6s var(--ease) 3.75s both; } /* names the song once it can be seen */
/* the screen's light: on the deck, and the room's glow (the drawing leaves a hole for the lid; closed, there is none) */
.has-scene .scene-art [fill="url(#sf-deckGlow)"] { animation: fade-in 0.8s var(--ease) 3.3s both; }
.has-scene .scene-art #glow { clip-path: none; animation: glow-up 0.9s var(--ease) 3.3s both; }
.scene-art #kid-a { animation: kid-in-a 1.1s var(--ease-intro) 0.55s both; }
.scene-art #kid-b { animation: kid-in-b 1.1s var(--ease-intro) 0.7s both; }
.scene-art .body, .scene-art .head, .scene-art .arm-raised, .scene-art .eyes, .scene-art .mouth, .scene-art #speaker-cone,
.scene-art #notes > * { transform-box: fill-box; }
.scene-art .body { transform-origin: 50% 100%; }
.scene-art .head { transform-origin: 50% 90%; }
.scene-art .mouth, .scene-art .eyes, .scene-art #speaker-cone { transform-origin: 50% 50%; }
.scene-art #kid-a .body { animation: kid-sway 2.4s var(--ease-in-out) 1.6s infinite alternate; }
.scene-art #kid-b .body { animation: kid-bounce 0.6s var(--ease-in-out) 1.6s infinite alternate; }
.scene-art #kid-a .head { animation: head-nod 1.2s var(--ease-in-out) infinite alternate; }
.scene-art #kid-b .head { animation: head-nod 1.2s var(--ease-in-out) 0.3s infinite alternate-reverse; }
.scene-art .arm-raised { transform-origin: 20% 90%; animation: arm-wave 0.6s var(--ease-in-out) infinite alternate; }
.scene-art .eyes { animation: eyes-blink 4.6s linear infinite; }
.scene-art #kid-b .eyes { animation-delay: 1.9s; }
.scene-art .mouth { transform: scaleY(0.6); transition: transform 0.15s var(--ease); }
.hero-stage.singing .scene-art .mouth { animation: mouth-sing 0.28s var(--ease-in-out) infinite alternate; }
.hero-stage.singing .scene-art #kid-b .mouth { animation-delay: 0.1s; }
.hero-stage.singing .scene-art #speaker-cone { animation: cone-thump 0.46s var(--ease-in-out) infinite; }
.scene-art #notes > * { animation: note-float 3.2s var(--ease-out) infinite; }
.scene-art .tzitzit { animation: tz-sway 1.3s var(--ease-in-out) infinite alternate; }
.scene-art #kid-b .tzitzit { animation-duration: 0.6s; } /* he bounces faster */
.scene-art #notes > :nth-child(2) { animation-delay: 1.1s; }
.scene-art #notes > :nth-child(3) { animation-delay: 2.2s; }
@media (prefers-reduced-motion: reduce) {
  .has-scene .scene-art, .scene-art #kid-a, .scene-art #kid-b, .has-scene .laptop-cover,
  .has-scene .laptop-cover::before, .has-scene .laptop-cover::after, .has-scene .laptop-lid, .has-scene .scene .demo-screen,
  .has-scene .scene .demo-logo, .has-scene .scene .demo-lyrics, .has-scene .scene .demo-bar,
  .has-scene .demo-caption, .has-scene .scene-art [fill="url(#sf-deckGlow)"], .has-scene .scene-art #glow {
    animation-delay: 0s; /* open and on at once */
  }
}
.js:not(.intro-go) .has-scene .scene-art, .js:not(.intro-go) .has-scene .laptop-lid, .js:not(.intro-go) .scene-art #kid-a,
.js:not(.intro-go) .scene-art #kid-b, .js:not(.intro-go) .has-scene .scene .demo-screen,
.js:not(.intro-go) .has-scene .laptop-cover, .js:not(.intro-go) .has-scene .laptop-cover::before,
.js:not(.intro-go) .has-scene .laptop-cover::after, .js:not(.intro-go) .has-scene .scene .demo-logo,
.js:not(.intro-go) .has-scene .scene .demo-lyrics, .js:not(.intro-go) .has-scene .scene .demo-bar,
.js:not(.intro-go) .has-scene .demo-caption, .js:not(.intro-go) .has-scene .scene-art [fill="url(#sf-deckGlow)"], .js:not(.intro-go) .has-scene .scene-art #glow { animation-play-state: paused; }

/* the hero's button: slimmer and lighter than the other large buttons (owner's request) */
.hero-actions .btn-lg { min-height: 50px; padding: 0 var(--space-6); font-size: 18px; font-weight: 500; }

.section { padding: var(--space-8) 0 0; }
.section h2 { margin: 0; font-size: var(--h2); font-weight: 800; line-height: 1.15; text-wrap: balance; }
.page-head h1 { margin: 0; font-size: var(--h1); font-weight: 800; line-height: 1.1; text-wrap: balance; }
.section-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-4); margin-bottom: var(--space-4); }
.section-head a { display: inline-flex; align-items: center; min-height: 44px; color: var(--gold); text-decoration: none; font-weight: 500; }
.section-head a:hover { text-decoration: underline; }
.section .song-list { margin-top: 0; }
.song-list { list-style: none; margin: var(--space-6) 0 0; padding: 0; display: grid; gap: var(--space-3); }
.section h2 + .song-list { margin-top: var(--space-4); }

.steps { list-style: none; counter-reset: step; margin: var(--space-6) 0 0; padding: 0; display: grid; gap: var(--space-4); grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
.steps li { counter-increment: step; padding: var(--space-4); border: 1px solid var(--line); border-radius: var(--radius); background: rgba(27, 30, 72, 0.5); display: grid; gap: var(--space-1); }
.steps li::before { content: counter(step); width: 32px; height: 32px; display: grid; place-items: center; border-radius: 50%; background: var(--gold); color: var(--navy); font-weight: 800; margin-bottom: var(--space-2); }
.steps strong { font-size: 18px; text-wrap: balance; }
.steps span { color: var(--muted); text-wrap: pretty; }
/* "How it works" on the home page: plain numbered columns (after the generic .steps rules so they win). */
.steps-plain { counter-reset: step; }
.steps-plain li { border: 0; background: none; padding: 0; border-top: 2px solid var(--gold); padding-top: var(--space-4); border-radius: 0; }
.steps-plain li::before { content: counter(step, decimal-leading-zero); width: auto; height: auto; display: block; background: none; color: var(--gold); font-size: 15px; font-weight: 700; letter-spacing: 0.08em; margin: 0; border-radius: 0; place-items: start; }

.page-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: var(--space-2) var(--space-4); padding-top: var(--space-6); }
.filters { display: grid; gap: var(--space-3); margin-top: var(--space-6); }
.chips { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.chips-label, .select > span { color: var(--muted); font-size: 15px; margin-inline-end: var(--space-1); }
.chip {
  min-height: 44px; padding: 0 var(--space-4); border-radius: 999px; cursor: pointer;
  background: var(--control-bg); border: 1px solid var(--line-strong); color: var(--cream);
  transition: border-color 0.2s var(--ease), background 0.2s var(--ease), transform 0.1s var(--ease);
}
.chip:hover { border-color: var(--cream); }
.chip:active { transform: scale(0.96); }
/* filtering the list cross-fades (View Transitions API, progressive) */
::view-transition-old(root), ::view-transition-new(root) { animation-duration: 0.18s; }
.chip[aria-pressed="true"] { background: var(--gold); border-color: var(--gold); color: var(--navy); font-weight: 700; }
.select { display: inline-flex; align-items: center; gap: var(--space-2); }
.select select {
  min-height: 44px; padding: 0 var(--space-3); font: inherit; color: var(--cream);
  background: var(--control-bg); border: 1px solid var(--line-strong); border-radius: var(--radius-sm); max-width: 100%;
}
.select select:focus { border-color: var(--gold); }
.select select option { background: var(--surface); color: var(--cream); }
.empty div { margin-top: var(--space-4); }

.coming-list { list-style: none; margin: var(--space-4) 0 0; padding: 0; display: grid; gap: var(--space-2); }
.coming-item {
  display: grid; grid-template-columns: 56px 1fr auto; align-items: center; gap: var(--space-4);
  padding: var(--space-3); padding-inline-end: var(--space-4);
  border: 1px dashed var(--line); border-radius: var(--radius); background: rgba(27, 30, 72, 0.35); opacity: 0.85;
}
.coming-item img, .coming-tile { width: 56px; height: 56px; border-radius: var(--radius-md); }
.coming-tile { display: grid; place-items: center; background: rgba(251, 246, 236, 0.08); color: var(--muted); }
.coming-tile svg { width: 26px; height: 26px; }
.coming-text { display: grid; min-width: 0; }
.coming-item .song-title { font-size: 18px; }
/* On phones the badge would squeeze the title to a few letters wide; the section heading already says "Coming soon". */
@media (max-width: 480px) {
  .coming-item { grid-template-columns: 56px minmax(0, 1fr); }
  .coming-item .badge { display: none; }
}
.badge { font-size: 13px; font-weight: 700; letter-spacing: 0.04em; color: var(--gold); border: 1px solid rgba(242, 177, 56, 0.5); border-radius: 999px; padding: 4px 10px; white-space: nowrap; }
.muted { color: var(--muted); margin: var(--space-2) 0 0; text-wrap: pretty; }
.coming .section-head { margin-bottom: 0; }

/* Cards wide enough that every name ("Mordechai Ben David") and every role line stays on one line. */
.artist-grid { list-style: none; margin: var(--space-6) 0 0; padding: 0; display: grid; gap: var(--space-3); grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr)); }
.artist-card {
  display: grid; grid-template-columns: 64px 1fr; align-items: center; gap: var(--space-4); padding: var(--space-4); min-height: 44px; text-decoration: none;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  transition: background 0.2s var(--ease), border-color 0.2s var(--ease), transform 0.2s var(--ease);
}
.artist-card:hover, .artist-card:focus-visible { background: var(--surface-hi); border-color: var(--card-hi-border); transform: translateY(-2px); }
.artist-card:active { transform: scale(0.99); transition-duration: 0.08s; }
.artist-text { display: grid; gap: var(--space-1); min-width: 0; }
.avatar { width: 72px; height: 72px; border-radius: 50%; object-fit: cover; flex: none; background: rgba(251, 246, 236, 0.06); }
/* Fallback for an artist without any picture: initials on the brand colours (visibly not a photo). */
.avatar-mono {
  display: grid; place-items: center; font-weight: 800; font-size: 26px; letter-spacing: 0.02em; color: var(--cream);
  background: linear-gradient(145deg, hsl(var(--h) 45% 38%), hsl(calc(var(--h) + 40) 50% 22%));
  box-shadow: inset 0 0 0 2px rgba(251, 246, 236, 0.12);
}
.profile { display: grid; grid-template-columns: auto 1fr; align-items: center; gap: var(--space-4) var(--space-6); }
.profile .avatar { width: 160px; height: 160px; font-size: 56px; }
.profile-text { display: grid; gap: var(--space-2); min-width: 0; }
@media (max-width: 480px) { .profile { grid-template-columns: 1fr; } .profile .avatar { width: 120px; height: 120px; font-size: 42px; } }
.artist-card .avatar { width: 64px; height: 64px; font-size: 23px; }
.artist-name { font-size: 19px; font-weight: 700; text-wrap: balance; }
.artist-roles { color: var(--muted); font-size: 15px; text-wrap: balance; }
@media (max-width: 360px) {
  .artist-card { grid-template-columns: 56px 1fr; gap: var(--space-3); padding: var(--space-3); }
  .artist-card .avatar { width: 56px; height: 56px; font-size: 20px; }
  .artist-name { font-size: 18px; }
  .artist-roles { font-size: 14px; }
}
.artist-count { color: var(--gold); font-size: 14px; }
.profile-alt, .profile-roles { margin: 0; color: var(--muted); text-wrap: balance; }
.photo-credit { margin: var(--space-1) 0 0; font-size: 14px; color: var(--muted-2); }
.photo-credit a { display: inline-block; padding-block: 12px; color: inherit; text-underline-offset: 3px; }
.photo-credit a { margin-block: -12px; } /* 44 px tap target without taller lines */

.prose { max-width: 62ch; padding-top: var(--space-6); }
.prose h1 { margin: 0 0 var(--space-4); font-size: var(--h1); font-weight: 800; line-height: 1.1; text-wrap: balance; }
.prose .lede { color: var(--gold); font-weight: 500; letter-spacing: 0.04em; font-size: 15px; text-transform: uppercase; }
.prose p { font-size: 18px; line-height: 1.6; text-wrap: pretty; }
.prose .actions { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-top: var(--space-6); }
.footer-links a { color: inherit; text-decoration: none; min-width: 44px; text-align: center; }
.footer-links a:hover { color: var(--cream); }

.brand { display: inline-flex; align-items: center; min-height: 44px; } /* a full-size tap target at any logo size */
.brand img { height: 48px; width: auto; }

/* ---------- Songs page: search, filters, song rows ---------- */
.search-field { position: relative; flex: 1 1 280px; max-width: 420px; }
.search-field svg {
  position: absolute;
  inset-inline-start: 14px;
  top: 50%;
  transform: translateY(-50%);
  width: 20px; height: 20px;
  color: var(--muted);
  pointer-events: none;
}
.search-field input {
  width: 100%;
  height: 48px;
  padding-inline: 44px 14px;
  font: inherit;
  font-size: 16px;
  color: var(--cream);
  background: var(--control-bg);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  transition: border-color 0.2s var(--ease), background 0.2s var(--ease);
}
.search-field input::placeholder { color: var(--muted-2); }
.search-field input:hover { border-color: var(--cream); }
.search-field input:focus { border-color: var(--gold); background: var(--surface); }
.result-count { margin: 0; color: var(--muted); font-size: 15px; }

/* A song row: cover, title and artist, the length (small, beside the play button), play. Two lines of text only
   (owner's request: no separate line for length and language), so the rows stay low and clean. */
.song {
  display: grid;
  grid-template-columns: 64px minmax(0, 1fr) auto auto;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-2);
  padding-inline-end: var(--space-4);
  text-decoration: none;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  transition: background 0.2s var(--ease), border-color 0.2s var(--ease), transform 0.2s var(--ease);
}
.song:hover, .song:focus-visible { background: var(--surface-hi); border-color: var(--card-hi-border); transform: translateY(-2px); }
.song:active { transform: scale(0.99); transition-duration: 0.08s; }
.song img { width: 64px; height: 64px; border-radius: var(--radius-md); object-fit: cover; background: rgba(251, 246, 236, 0.06); }
.song > span { min-width: 0; overflow-wrap: anywhere; } /* last resort on the narrowest screens: never wider than the row */
.song-title { display: block; font-size: 20px; font-weight: 700; line-height: 1.25; text-wrap: balance; }
.song-artist { display: block; color: var(--muted); font-size: 16px; text-wrap: balance; }
.song-dur { color: var(--muted-2); font-size: 14px; font-variant-numeric: tabular-nums; }
.song-play {
  width: 48px; height: 48px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--gold);
  color: var(--navy);
  transition: background 0.2s var(--ease);
}
.song:hover .song-play { background: var(--gold-hi); }
.song-play svg { width: 22px; height: 22px; }

.empty {
  margin-top: var(--space-6);
  padding: var(--space-8) var(--space-6);
  text-align: center;
  text-wrap: balance;
  color: var(--muted);
  border: 1px dashed var(--line);
  border-radius: var(--radius);
}
.empty strong { display: block; color: var(--cream); font-size: 18px; margin-bottom: var(--space-1); }

.site-footer {
  max-width: var(--container);
  margin: 0 auto;
  padding: var(--space-8) var(--space-4) var(--space-12);
  color: var(--muted);
  font-size: 14px;
  border-top: 1px solid var(--line);
  position: relative;
  display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: var(--space-2) var(--space-4);
}
/* SimplySite credit (skill section 15): the studio's own logo, small, on a light chip because the footer is dark. */
.site-footer .credit {
  display: inline-flex; align-items: center; gap: var(--space-2); min-height: 44px; color: var(--muted); text-decoration: none;
}
.site-footer .credit img {
  display: block; width: auto; height: 28px; padding: 5px 9px; box-sizing: content-box;
  background: #fbf6ec; border-radius: 8px; transition: transform 0.2s var(--ease);
}
.site-footer .credit:hover img, .site-footer .credit:focus-visible img { transform: translateY(-1px); }
/* Phones: the credit sits alone, centred, at the very bottom of the page (owner's request). */
@media (max-width: 767px) { .site-footer .credit { flex-basis: 100%; justify-content: center; margin-top: var(--space-4); } }

@media (max-width: 480px) {
  .song { grid-template-columns: 56px minmax(0, 1fr) auto; gap: var(--space-3); }
  .song img { width: 56px; height: 56px; }
  /* phones: the length gives its room to the names; screen readers still read it */
  .song-dur { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .song-title { font-size: 18px; }
  .song-play { width: 44px; height: 44px; }
}
/* The narrowest phones (320-360 px): a smaller cover and tighter spacing keep full artist names on their lines. */
@media (max-width: 360px) {
  .song { grid-template-columns: 48px minmax(0, 1fr) auto; gap: var(--space-2); padding-inline-end: var(--space-3); }
  .song img { width: 48px; height: 48px; }
  .song-artist { font-size: 15px; }
}
/* The narrowest phones (320 px): the whole row is the link, so the play circle gives its width to the title and a
   three-word title stays on one line. */
@media (max-width: 340px) {
  .song { grid-template-columns: 48px minmax(0, 1fr); }
  .song .song-play { display: none; }
}

/* ---------- Player ---------- */
.player {
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  display: grid;
  grid-template-rows: auto 1fr auto;
  /* one column the width of the screen: without it the column grows to the header's unbroken title and artist line
     (ellipsised inside), which pushed the lyrics off-centre on phones for songs with several artists */
  grid-template-columns: minmax(0, 1fr);
}
/* Background animation canvas (assets/js/viz.js) sits behind everything on the player page. */
.viz { position: fixed; inset: 0; width: 100%; height: 100%; z-index: 0; pointer-events: none; }
.player.viz-on .stars { display: none; } /* the canvas draws its own stars */
.player > :not(.viz):not(audio):not(.skip-link):not(.stars) { position: relative; z-index: 1; }

.player-bar {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-4) clamp(16px, 3vw, 40px);
  position: relative;
  z-index: 5;
  transition: opacity 0.3s var(--ease);
}
.back-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 44px;
  padding-inline: var(--space-3) var(--space-4);
  border-radius: 999px;
  text-decoration: none;
  font-weight: 500;
  color: var(--muted);
  border: 1px solid var(--line-strong);
  transition: color 0.2s var(--ease), border-color 0.2s var(--ease);
}
.back-link:hover { color: var(--cream); border-color: var(--cream); }
.back-link svg { width: 18px; height: 18px; }
.now-playing { flex: 1; min-width: 0; text-align: center; }
.now-playing h1 { display: block; margin: 0; font-size: 17px; font-weight: 700; line-height: 1.4; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.now-playing span { display: block; font-size: 14px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.player-bar .brand img { height: 40px; }

.stage {
  position: relative;
  display: grid;
  place-items: center;
  padding: 0 clamp(16px, 5vw, 80px);
  min-height: 0;
}
.lyrics {
  width: 100%;
  display: grid;
  gap: clamp(18px, 4vh, 44px);
  font-size: clamp(32px, min(8.6vw, 8.5vh), 92px);
  font-weight: 800;
  line-height: 1.22;
  text-align: center;
}
.slot { display: grid; }
.slot > .line { grid-area: 1 / 1; }
.slot-0 > .line { align-self: end; }
.slot-1 > .line { align-self: start; }
.line {
  opacity: 0;
  visibility: hidden;
  transform: translateY(10px);
  transition: opacity 0.25s var(--ease), transform 0.35s var(--ease-out), visibility 0s linear 0.25s;
  text-wrap: balance;
}
.line.on { opacity: 1; visibility: visible; transform: none; transition: opacity 0.25s var(--ease), transform 0.35s var(--ease-out), visibility 0s; }
.run[dir="ltr"] { font-weight: 700; }
.w { position: relative; display: inline-block; white-space: nowrap; }
.w-base {
  color: var(--cream);
  text-shadow:
    0 0 1px var(--outline),
    2px 0 0 var(--outline), -2px 0 0 var(--outline), 0 2px 0 var(--outline), 0 -2px 0 var(--outline),
    2px 2px 0 var(--outline), -2px -2px 0 var(--outline), 2px -2px 0 var(--outline), -2px 2px 0 var(--outline),
    0 6px 18px rgba(0, 0, 0, 0.55);
}
.w-fill {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, var(--gold-hi) 15%, var(--gold-lo) 90%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  filter: drop-shadow(0 0 10px rgba(255, 170, 40, 0.45));
  visibility: hidden; /* shown and masked frame by frame by the player (soft-edged wipe) */
  pointer-events: none;
}

.countdown {
  position: absolute;
  inset-inline: 0;
  display: flex;
  justify-content: center;
  gap: 18px;
  opacity: 0;
  transition: opacity 0.2s var(--ease);
  pointer-events: none;
}
.countdown.on { opacity: 1; }
.countdown i {
  width: 18px; height: 18px;
  border-radius: 50%;
  background: var(--gold-lo);
  box-shadow: 0 0 0 3px var(--outline);
  transition: transform 0.2s var(--ease), opacity 0.2s var(--ease);
}
.countdown i.off { transform: scale(0.3); opacity: 0; }

/* Instrumental intro: song title on stage. Long breaks: a bar counting down to the next line. */
.stage-title {
  position: absolute;
  inset-inline: 0;
  top: 50%;
  transform: translateY(-60%);
  display: grid;
  justify-items: center;
  gap: var(--space-2);
  padding: 0 var(--space-6);
  text-align: center;
  opacity: 0;
  transition: opacity 0.3s var(--ease);
  pointer-events: none;
}
.stage-title.on { opacity: 1; }
.stage-title strong {
  font-size: clamp(36px, min(8vw, 9vh), 96px);
  line-height: 1.1;
  font-weight: 800;
  color: var(--gold-hi);
  text-wrap: balance;
  text-shadow: 0 0 1px var(--outline), 0 6px 24px rgba(0, 0, 0, 0.6);
}
.stage-title span { font-size: clamp(18px, 2.6vw, 30px); color: var(--muted); text-wrap: balance; }
.break {
  position: absolute;
  inset-inline: 0;
  bottom: clamp(24px, 9vh, 90px);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  color: var(--gold);
  opacity: 0;
  transition: opacity 0.3s var(--ease);
  pointer-events: none;
}
.break.on { opacity: 1; }
.break svg { width: 22px; height: 22px; }
.break-bar { width: min(240px, 50vw); height: 4px; border-radius: 2px; background: rgba(251, 246, 236, 0.16); overflow: hidden; }
.break-bar i { display: block; height: 100%; width: 100%; background: var(--gold); transform-origin: left; transform: scaleX(0); }
[dir="rtl"] .break-bar i { transform-origin: right; }

/* Overlays: intro, end, error */
/* Overlays scroll when the card is taller than the stage (200% zoom, landscape phones): the card centres
   itself with auto margins, which never push it past the top edge. */
.overlay {
  position: absolute;
  inset: 0;
  display: grid;
  justify-items: center;
  overflow-y: auto;
  padding: var(--space-6);
  text-align: center;
  z-index: 4;
  background: radial-gradient(60% 60% at 50% 50%, rgba(13, 14, 36, 0.55), rgba(13, 14, 36, 0.85));
  transition: opacity 0.35s var(--ease), visibility 0s; /* shown: visible at once (focusable), then fades in */
}
.overlay[hidden] { display: grid; opacity: 0; visibility: hidden; pointer-events: none; transition: opacity 0.35s var(--ease), visibility 0s linear 0.35s; }
.overlay-card { max-width: 560px; margin-block: auto; display: grid; justify-items: center; gap: var(--space-4); transition: transform 0.35s var(--ease-out); }
.overlay[hidden] .overlay-card { transform: scale(0.96); }
.overlay-card .cover { opacity: 0; transition: opacity 0.3s var(--ease); }
.overlay-card .cover.ready { opacity: 1; }
@keyframes breathe { 0%, 100% { box-shadow: 0 0 0 0 rgba(242, 177, 56, 0.45); } 50% { box-shadow: 0 0 0 12px rgba(242, 177, 56, 0); } }
#start:not(:disabled) { animation: breathe 2.2s var(--ease-in-out) 2; } /* two pulses, under 5 s (WCAG 2.2.2) */
.kbd-hint { display: none; color: var(--muted); font-size: 14px; margin-top: var(--space-2); }
.kbd-hint kbd { font: inherit; padding: 1px 6px; border: 1px solid var(--line-strong); border-radius: 5px; color: var(--cream); }
@media (hover: hover) and (pointer: fine) { .kbd-hint { display: block; } }
.flash {
  position: absolute; inset-inline: 0; top: 50%; transform: translateY(-50%) scale(0.6);
  display: grid; place-items: center; opacity: 0; pointer-events: none; z-index: 3;
}
.flash i { width: 84px; height: 84px; border-radius: 50%; background: rgba(13, 14, 36, 0.7); display: grid; place-items: center; color: var(--cream); }
.flash svg { width: 40px; height: 40px; }
.flash.on { animation: flash 0.6s var(--ease-out) both; }
@keyframes flash { 0% { opacity: 0; transform: translateY(-50%) scale(0.6); } 20% { opacity: 1; transform: translateY(-50%) scale(1); } 100% { opacity: 0; transform: translateY(-50%) scale(1.15); } }
.next-song { display: flex; align-items: center; gap: var(--space-3); margin-top: var(--space-2); text-decoration: none; color: var(--muted); }
.next-song img { width: 48px; height: 48px; border-radius: 8px; }
.next-song b { display: block; color: var(--cream); }
.next-song:hover b { color: var(--gold-hi); }
.overlay-card img.cover { width: clamp(120px, 22vh, 200px); height: auto; aspect-ratio: 1; border-radius: var(--radius); box-shadow: 0 18px 50px rgba(0, 0, 0, 0.55); }
.overlay-card h1, .overlay-card h2 { margin: 0; font-size: clamp(30px, 5.5vw, 60px); line-height: 1.1; font-weight: 800; color: var(--gold-hi); text-wrap: balance; }
.overlay-card p { margin: 0; color: var(--muted); font-size: clamp(17px, 2.2vw, 22px); text-wrap: balance; }
.overlay-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--space-3); margin-top: var(--space-2); }
/* Song pages: the artist names link to their pages (top bar and intro card); under them the language, the length and
   the credits from meta.json, one small line each. */
#np-artist a, #intro-artist a { color: inherit; text-decoration: underline; text-decoration-color: rgba(251, 246, 236, 0.35); text-decoration-thickness: 1px; text-underline-offset: 0.2em; }
#np-artist a:hover, #intro-artist a:hover { color: var(--cream); text-decoration-color: currentColor; }
.overlay-card .song-facts, .overlay-card .song-credits { font-size: 15px; color: var(--muted-2); margin-top: calc(-1 * var(--space-2)); }
.overlay-card .song-facts time { font-variant-numeric: tabular-nums; }
.song-credits > span { display: block; text-wrap: balance; }

.overlay-end { background: radial-gradient(60% 60% at 50% 50%, rgba(13, 14, 36, 0.72), rgba(13, 14, 36, 0.92)); }
.end-logo { width: min(340px, 72vw); height: auto; margin-bottom: var(--space-2); }

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: 52px;
  padding: 0 var(--space-6);
  border-radius: 999px;
  border: 1px solid transparent;
  font-size: 18px;
  font-weight: 700;
  text-decoration: none;
  cursor: pointer;
  transition: background 0.2s var(--ease), border-color 0.2s var(--ease), transform 0.15s var(--ease);
}
.btn:active:not(:disabled) { transform: scale(0.97); }
/* Disabled (the song is still loading): visibly inactive, not clickable-looking. */
.btn:disabled, .icon-btn:disabled, .range:disabled { opacity: 0.45; cursor: default; pointer-events: none; }
.btn svg { width: 22px; height: 22px; }
.btn-primary { background: var(--gold); color: var(--navy); }
.btn-primary:hover { background: var(--gold-hi); }
.btn-secondary { background: transparent; border-color: var(--line-strong); color: var(--cream); }
.btn-secondary:hover { border-color: var(--cream); }
.btn-lg { min-height: 60px; font-size: 20px; padding: 0 var(--space-8); }

.controls {
  display: grid;
  grid-template-columns: auto auto 1fr auto auto;
  align-items: center;
  gap: var(--space-3) var(--space-4);
  padding: var(--space-4) clamp(16px, 3vw, 40px) max(var(--space-4), env(safe-area-inset-bottom));
  background: linear-gradient(0deg, rgba(8, 8, 28, 0.85), rgba(8, 8, 28, 0));
  position: relative;
  z-index: 5;
  transition: opacity 0.3s var(--ease);
}
.icon-btn {
  width: 44px; height: 44px;
  display: grid; place-items: center;
  border: 0;
  border-radius: 50%;
  background: transparent;
  cursor: pointer;
  color: var(--cream);
  transition: background 0.2s var(--ease);
}
.icon-btn:hover { background: rgba(251, 246, 236, 0.1); }
.icon-btn svg { width: 24px; height: 24px; }
.icon-btn.play { width: 52px; height: 52px; background: var(--gold); color: var(--navy); }
.icon-btn.play:hover { background: var(--gold-hi); }
.icon-btn.play svg { width: 26px; height: 26px; }
.time { font-variant-numeric: tabular-nums; font-size: 14px; color: var(--muted); white-space: nowrap; }
.seek-wrap { display: flex; align-items: center; gap: var(--space-3); min-width: 0; }
.range {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 44px;
  background: transparent;
  cursor: pointer;
  --pct: 0%;
}
.range::-webkit-slider-runnable-track {
  height: 6px;
  border-radius: 3px;
  background: linear-gradient(to left, var(--gold) var(--pct), rgba(251, 246, 236, 0.42) var(--pct));
}
.range::-moz-range-track { height: 6px; border-radius: 3px; background: rgba(251, 246, 236, 0.42); }
.range::-moz-range-progress { height: 6px; border-radius: 3px; background: var(--gold); }
.range::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 20px; height: 20px;
  margin-top: -7px;
  border-radius: 50%;
  background: var(--cream);
  border: 0;
}
.range::-moz-range-thumb { width: 20px; height: 20px; border-radius: 50%; background: var(--cream); border: 0; }
.range[dir="ltr"]::-webkit-slider-runnable-track {
  background: linear-gradient(to right, var(--gold) var(--pct), rgba(251, 246, 236, 0.42) var(--pct));
}
.volume { display: flex; align-items: center; gap: var(--space-1); }
.volume .range { width: 96px; }

.player.idle { cursor: none; }
/* Hidden controls do not catch taps: the first tap only brings them back. */
.player.idle .controls, .player.idle .player-bar { opacity: 0; pointer-events: none; }

@media (max-width: 640px) {
  .player-bar .brand { display: none; }
  .now-playing { text-align: start; }
  .controls { grid-template-columns: auto auto 1fr auto; }
  .volume { display: none; }
  .seek-wrap { grid-column: 1 / -1; order: -1; }
  .controls #fs { grid-column: 4; }
}
@media (max-height: 480px) {
  .overlay-card .cover { width: 72px; }
  .end-logo { width: min(200px, 50vw); }
  .kbd-hint { display: none; }
}

/* !important is intended here: the reduced-motion preference overrides every component's own motion. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; animation-delay: 0s !important; }
  .hero-viz { display: none; }
}
