/* ═══════════════════════════════════════════════════════════
   Joozic — assets/css/base.css

   Shared shell: tokens, reset, grain, idle brand block, LIVE
   badge, toast. The expanding-panel layout itself lives in
   panels.css.

   JS writes --accent / --accent-ink onto :root for the active
   station.
   ═══════════════════════════════════════════════════════════ */

:root {
  /* Brand palette — supplied by the designer. --teal is the station palette's
     teal (joozic hits): the splash, and the accent before any station is
     chosen. */
  --grey:   #222222;
  --teal:   #3ec8c5;
  --yellow: #f1b434;

  /* Live accent — overwritten per station by JS, teal until then */
  --accent:     var(--teal);
  --accent-ink: #05070f;

  --ink:    #ffffff;
  --ink-70: rgba(255, 255, 255, 0.72);

  /* White-based, so only for things drawn on the grey page rather than on a
     station colour — the toast and the config-error note. Anything inside a
     panel mixes from --c-ink instead. */
  --glass:      rgba(255, 255, 255, 0.05);
  --hairline:   rgba(255, 255, 255, 0.11);
  --hairline-2: rgba(255, 255, 255, 0.2);
  --blur: saturate(1.4) blur(22px);

  --display: 'Poppins', system-ui, sans-serif;
  --body: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;

  --r-md: 14px;
  --r-lg: 20px;

  /* The ticker reads against #222 now rather than the navy, where 0.55 sank
     into the background. Ambient still, but legible. */
  --ticker-opacity: 0.72;

  --pad: clamp(16px, 3.5vw, 44px);
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
}

/* ─────────────── Reset ─────────────── */

*,
*::before,
*::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  -webkit-tap-highlight-color: transparent;
}

html {
  /* A definite height here gives percentages something dependable to resolve
     against. iOS home-screen web apps report 100dvh smaller than the actual
     screen, which left a dead band below the last row; 100% of the viewport
     does not have that problem. */
  height: 100%;
  background: var(--grey);
  color-scheme: dark;
  -webkit-text-size-adjust: 100%;
  /* Blocks the browser's pull-to-refresh gesture and the overscroll bounce, so
     the page feels fixed like an app rather than a document. Normal scrolling
     (an open panel taller than the screen) is unaffected. */
  overscroll-behavior: none;
}

body {
  font-family: var(--body);
  color: var(--ink);
  /* --app-height is measured from window.innerHeight by app.js; the percentage
     is only the pre-script fallback. See the note on <html> above. */
  min-height: var(--app-height, 100%);
  overflow-x: hidden;
  overscroll-behavior: none;
  -webkit-font-smoothing: antialiased;

  background: var(--grey);
}

/* ─────────────── Splash ─────────────── */

/* The first screen: a teal field with the wordmark, the prompt and an arrow
   down to the stations. A section rather than a state — it stays where it is
   and you scroll past it. */
.splash {
  position: relative;
  display: grid;
  place-items: center;
  padding: 24px;
  background: var(--teal);
  overflow: hidden;
}

/* The j behind everything, held at 5% so it is a mark in the colour rather than
   a picture on it. Masked over a flat ink fill like every other mark on the
   site, so it needs no artwork of its own beyond the one file.

   Sized against the viewport height rather than the width: the shape is tall
   and narrow, so on a phone a width-based size would be a sliver and on a wide
   desktop it would run off the top and bottom. */
.splash::before {
  content: '';
  position: absolute;
  inset: 0;
  /* Deliberately not z-index: -1. A negative child only stays inside its parent
     when that parent makes a stacking context, and `position: relative` alone
     does not — so it fell through to the root layer and painted behind the
     splash's own teal, which is to say invisibly. The content above it is
     lifted instead, which needs nothing of the parent. */
  z-index: 0;
  background-color: var(--grey);
  opacity: 0.05;
  -webkit-mask: url("../../images/joozic-j.svg") center / auto 62% no-repeat;
          mask: url("../../images/joozic-j.svg") center / auto 62% no-repeat;
  pointer-events: none;
}


/* The nine station colours as one continuous band across the very bottom edge —
   a glimpse of the wall before you reach it. Built from the same data the wall
   is, so it can never drift from the palette.

   No gaps and no inset: it is a single band edge to edge, not a row of
   separated blocks. The teal one disappears into the teal ground, which is
   correct rather than a hole — on the wall it is a station like any other, and
   here it is the page. */
.splash__strip {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1;
  display: flex;
  height: 22px;
  pointer-events: none;
}

.splash__strip span {
  flex: 1 1 0;
  background: var(--c);
}



.splash__prompt {
  margin-top: clamp(18px, 3vh, 34px);
  font-family: var(--display);
  font-weight: 900;
  font-style: italic;
  font-size: clamp(0.72rem, 1.1vw, 0.9rem);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--grey);
  /* letter-spacing trails the last glyph too; pull it back into optical centre */
  padding-left: 0.2em;
}

.splash__down {
  margin-top: clamp(10px, 1.8vh, 20px);
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  color: var(--grey);
  animation: nudge 2.4s ease-in-out infinite;
}

.splash__down svg { width: 30px; height: 30px; }
.splash__down:hover { animation-play-state: paused; }

/* Travels the same way the reader is being asked to. Opacity and transform
   only — nothing that needs a shadow to read. */
/* The arrow is inside a centred column now, so this is a plain vertical move —
   it no longer has to carry the -50% that used to centre it. */
@keyframes nudge {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(7px); }
}

img { max-width: 100%; display: block; }
svg { width: 20px; height: 20px; fill: currentColor; flex: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
a { color: inherit; }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 6px; }
::selection { background: var(--accent); color: var(--accent-ink); }

/* ─────────────── Film grain ─────────────── */

/* Sits over everything, blended so it reads as texture on both the near-black
   base and the colour blooms. Cheap: one tiny tiled SVG, no repaint. */
.grain {
  position: fixed;
  inset: 0;
  z-index: 100;
  pointer-events: none;
  opacity: 0.05;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ─────────────── Idle brand moment ─────────────── */

/* The splash's content: wordmark, instruction, arrow, stacked and centred as
   one group. Lifted above the j behind it — without this it is unpositioned
   content and the absolutely positioned watermark would paint over it. */
.brand {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

/* SVG is 557 × 200.

   Masked over a flat fill rather than shown as an image, which is what lets it
   take a colour at all. The main logo file is two-tone — the wordmark white,
   the two dots Joozic teal — so on the teal ground the dots would vanish and
   the letters could not be recoloured. The footer file is the same wordmark
   drawn as plain unfilled paths, so it picks up whatever fill sits behind the
   mask, dots included. */
.brand__logo {
  width: clamp(190px, 27vw, 360px);
  aspect-ratio: 557.56 / 200.54;
  margin: 0 auto;
  background-color: var(--grey);
  -webkit-mask: url("../../images/joozic-logo.svg") center / contain no-repeat;
          mask: url("../../images/joozic-logo.svg") center / contain no-repeat;
}



/* ─────────────── Wordmark (Poppins 900 italic) ─────────────── */

.wordmark {
  font-family: var(--display);
  font-weight: 900;
  font-style: italic;
  letter-spacing: -0.035em;
  font-size: 1.4rem;
  line-height: 1;
  display: inline-block;
}

/* ─────────────── Tags / LIVE badge ─────────────── */

/* Green LIVE badge with a pulsing dot */
.live-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  white-space: nowrap;
  /* Sits on the station colour, so it is drawn in that panel's ink rather than
     in the status green — green on gold or on teal is barely a distinction, and
     an outline reads more cleanly on a flat colour than a filled chip. Pip
     included: the comp has it monochrome, and the pulse carries the liveness on
     its own. */
  color: var(--c-ink, var(--ink));
  background: transparent;
  border: 1.5px solid var(--c-ink, #222);
}

.live-badge__pip {
  width: 6px;
  height: 6px;
  flex: none;
  border-radius: 50%;
  background: currentColor;
  animation: pip 2s ease-out infinite;
}

/* Flat pulse — opacity and scale, not an expanding glow ring */
@keyframes pip {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: 0.4; transform: scale(0.78); }
}

/* Also inside a coloured panel, so ink-based like the rest of it. */
.is-offline .live-badge {
  color: color-mix(in srgb, var(--c-ink, #222) 45%, transparent);
  background: color-mix(in srgb, var(--c-ink, #222) 6%, transparent);
  border-color: color-mix(in srgb, var(--c-ink, #222) 18%, transparent);
}

.is-offline .live-badge__pip { animation: none; }

/* ─────────────── Toast ─────────────── */

.toast {
  position: fixed;
  left: 50%;
  bottom: calc(24px + env(safe-area-inset-bottom, 0px));
  z-index: 200;
  transform: translate(-50%, 14px);
  padding: 10px 18px;
  border-radius: 999px;
  font-size: 0.83rem;
  font-weight: 500;
  background: rgba(34, 34, 34, 0.95);
  border: 1px solid var(--hairline-2);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.26s var(--ease), transform 0.26s var(--ease);
  max-width: calc(100vw - 28px);
  text-align: center;
}

.toast.is-up { opacity: 1; transform: translate(-50%, 0); }

/* ─────────────── Config-error note ─────────────── */

.boot-note {
  margin: 24px var(--pad);
  padding: 16px 18px;
  border-radius: var(--r-md);
  border: 1px solid var(--hairline);
  background: var(--glass);
  color: var(--ink-70);
  font-size: 0.9rem;
  line-height: 1.6;
}

.boot-note code { font-family: ui-monospace, monospace; color: var(--yellow); }

/* ─────────────── Preferences ─────────────── */

@media (prefers-reduced-motion: reduce) {
  /* 0s, not 0.001s — a sub-frame duration can leave Chromium reporting the
     transition as still running, pinning properties at their start value. */
  *,
  *::before,
  *::after {
    animation-duration: 0s !important;
    animation-delay: 0s !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0s !important;
    transition-delay: 0s !important;
  }
}

@media (prefers-contrast: more) {
  :root {
    --glass: rgba(255, 255, 255, 0.11);
    --hairline: rgba(255, 255, 255, 0.3);
  }
}
