:root {
  --navy-1: #0d2a55;
  --navy-2: #1d3a66;
  --navy-3: #3f5c8c;
  --blue-4: #7f9cc9;
  --blue-5: #9fb6d8;
  --blue-6: #cfdcf0;
  --blue-7: #b8c7e0;
  --red: #e63946;
  --gold: #ffd97a;
  --white: #ffffff;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  background: linear-gradient(135deg, var(--navy-1), var(--navy-2) 60%, var(--navy-3));
  font-family: "Arial", "Helvetica Neue", sans-serif;
  color: var(--white);
}

.frame {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
}

/* ---------- top bar ---------- */
.topbar {
  display: flex;
  align-items: center;
  padding: 2.2vh 3vw 1.6vh;
  border-bottom: 0.3vh solid rgba(255,255,255,0.12);
}

.wordmark-wrap {
  border-left: 0.7vh solid var(--red);
  padding-left: 1.2vh;
}

/* Restyled <select> so it reads as plain bold text with a small dropdown
   arrow, not a default form control - it's a city switcher, one selection
   at a time, populated live from /api/cities. */
.wordmark {
  appearance: none;
  -webkit-appearance: none;
  background: transparent
    url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='%23ffffff'%3E%3Cpath d='M5.5 7.5l4.5 5 4.5-5z'/%3E%3C/svg%3E")
    no-repeat right 0.2vh center / 2vh 2vh;
  border: none;
  color: var(--white);
  font-family: inherit;
  font-weight: 700;
  font-size: 3.2vh;
  letter-spacing: 0.02em;
  padding-right: 2.6vh;
  cursor: pointer;
}
.wordmark option {
  background: var(--navy-2);
  color: var(--white);
  font-size: 2vh;
}

.topbar-right { flex: 1; text-align: center; }
.section-label {
  font-weight: 700;
  font-size: 3vh;
  letter-spacing: 0.1em;
  color: var(--white);
}

/* Fixed-width slot matching the weather column's own width (18vw), so the
   clock sits centered directly above the weather sidebar instead of flush
   against the page's far edge. */
.clock {
  flex: 0 0 18vw;
  font-size: 2.4vh;
  font-weight: 700;
  color: var(--blue-6);
  font-variant-numeric: tabular-nums;
  text-align: center;
}

/* ---------- content row (stage + weather sidebar) ---------- */
.content-row {
  flex: 1;
  display: flex;
  min-height: 0;
}

/* ---------- main stage ---------- */
.stage {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  /* bottom padding removed on purpose: the dots-row right below is meant to
     be the ONLY gap between the card's yellow progress bar and the ticker,
     so it can center the dots within it. A bottom pad here on top of that
     would make the dots sit lower than actual-center within the visible
     yellow-to-red gap, which is what was happening before. */
  padding: 2vh 1.5vw 0 3vw;
  min-width: 0;
  overflow: hidden;
}

.card {
  position: relative;
  display: flex;
  width: 100%;
  height: 100%;
  background: rgba(255,255,255,0.04);
  border: 1px solid rgba(255,255,255,0.08);
  border-radius: 1.6vh;
  overflow: hidden;
  opacity: 0;
  transform: translateY(1.5vh);
  transition: opacity 0.6s ease, transform 0.6s ease;
}
.card.visible { opacity: 1; transform: translateY(0); }

.card-media {
  position: relative;
  flex: 0 0 46%;
  overflow: hidden;
  background: var(--navy-2);
}
/* Two-layer image: a blurred cover copy fills the panel with no visible
   edges, and the real (sharp) image sits on top at object-fit: contain so
   it is never cropped and never upscaled past its own resolution (which is
   what was pixelating small source photos before). */
.media-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: blur(3vh) brightness(0.5);
  transform: scale(1.15);
}
.media-fg {
  position: absolute;
  inset: 0;
  margin: auto;
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  z-index: 1;
}
.card-media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to right, transparent 60%, rgba(13,42,85,0.55));
}

/* vmin, not vh - a vh-only size looks fine on a 16:9 TV but blows up (wider
   than the panel) on anything narrower/taller, which is what was clipping
   the caption text off the side of the box. */
.qr-box {
  position: absolute;
  right: 2vmin;
  /* Sits directly on the gold progress bar: that bar is .progress-bar-track,
     absolute at bottom:0 of .card with height 0.7vh, and .card-media stretches
     to the cards full height, so matching its height puts the box edge exactly
     on top of it with no gap and no overlap. */
  bottom: 0.7vh;
  width: auto;              /* sized by its contents now the caption is beside it */
  background: var(--white);
  border-radius: 1vmin;
  padding: 1vmin;
  display: flex;
  flex-direction: row-reverse;   /* DOM is code-then-caption, so this puts the
                                    caption on the LEFT without reordering the
                                    markup */
  align-items: center;
  gap: 1vmin;
  box-shadow: 0 0.6vmin 1.4vmin rgba(0,0,0,0.35);
  z-index: 2;
  box-sizing: border-box;
}
/* The code itself is now sized explicitly rather than inheriting the box
   width, which no longer means anything once the caption shares the row.
   18vmin is double the old effective size (11vmin box less 1vmin padding
   a side). */
.qr-box #qrcode {
  flex: 0 0 auto;
  width: 18vmin;
}
.qr-box #qrcode img, .qr-box #qrcode canvas {
  display: block;
  width: 100%;
  height: auto;
}
.qr-caption {
  color: var(--navy-1);
  font-size: 1.3vmin;
  font-weight: 700;
  margin-top: 0;            /* no longer stacked underneath */
  letter-spacing: 0.02em;
  text-align: right;        /* reads toward the code it belongs to */
  white-space: normal;
  width: 7vmin;             /* fixed, so the caption wraps instead of
                               stretching the box out over the artwork */
}

.card-body {
  flex: 1;
  padding: 4vh 3.5vw;
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-width: 0;
}

.date-badge {
  display: inline-block;
  align-self: flex-start;
  background: var(--gold);
  color: var(--navy-1);
  font-weight: 700;
  font-size: 3.0vh;
  letter-spacing: 0.06em;
  padding: 0.7vh 1.6vh;
  border-radius: 100px;
  margin-bottom: 2.5vh;
}

.card-body h1 {
  font-size: 3.0vh;
  font-weight: 700;
  line-height: 1.15;
  margin: 0 0 2.2vh;
  color: var(--white);
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.meta-list {
  display: flex;
  flex-direction: column;
  gap: 1.1vh;
  margin-bottom: 2.2vh;
}
.meta-list .meta-item {
  display: flex;
  align-items: flex-start;
  gap: 1vh;
  font-size: 3.0vh;
  color: var(--blue-6);
  line-height: 1.35;
}
.meta-list .meta-icon { flex: 0 0 auto; font-size: 3.0vh; }
.meta-list .meta-text { flex: 1; min-width: 0; }

.blurb {
  font-size: 3.0vh;
  line-height: 1.35;
  color: var(--blue-7);
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  max-width: 70ch;
}

/* ---------- weather sidebar (same 3-view rotation as the MCL NEWS videos:
   NEXT 12 HOURS / 7-DAY FORECAST / LONG RANGE) ---------- */
.weather-bar {
  flex: 0 0 18vw;
  margin: 2vh 3vw 2vh 0;
  background: #050e1f;
  border: 2px solid #2c4a80;
  border-radius: 1.6vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  min-width: 0;
}

.wx-header {
  flex: 0 0 auto;
  background: var(--red);
  color: white;
  font-weight: 700;
  font-size: 2vh;
  text-align: center;
  padding: 1.4vh 0;
  letter-spacing: 0.04em;
}
.wx-subheader {
  flex: 0 0 auto;
  color: var(--blue-4);
  font-weight: 700;
  font-size: 1.7vh;
  text-align: center;
  letter-spacing: 0.08em;
  padding: 1.4vh 0 0.6vh;
  transition: opacity 0.4s ease;
}

.wx-rows {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: space-evenly;
  padding: 0.6vh 1.4vw 1.4vh;
  transition: opacity 0.4s ease;
}
.wx-row {
  display: flex;
  align-items: center;
  font-size: 1.7vh;
}
.wx-row .wx-label {
  flex: 1;
  color: #dce6f5;
  font-weight: 700;
}
.wx-row .wx-emoji { flex: 0 0 auto; font-size: 2.4vh; margin: 0 0.8vw; }
.wx-row .wx-temp { flex: 0 0 auto; color: white; font-weight: 700; text-align: right; min-width: 5.5ch; }
.wx-row .wx-pop { flex: 0 0 auto; color: #6fa8ff; font-size: 1.4vh; margin-left: 0.8vw; min-width: 3ch; text-align: right; }

/* ---------- progress dots (per event, alongside the yellow bar) ----------
   Sits between the card's progress-bar and the ticker. A city with 50+
   events wraps to a couple of rows instead of running past the edges. */
.dots-row {
  flex: 0 0 auto;
  width: 100%;
  height: 3.6vh;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  align-content: center;
  gap: 0.8vmin;
  padding: 0 3vw;
  overflow: hidden;
}
.dots-row .dot-el {
  flex: 0 0 auto;
  width: 0.8vmin;
  height: 0.8vmin;
  border-radius: 50%;
  background: rgba(255,255,255,0.3);
  transition: background 0.3s ease;
}
.dots-row .dot-el.active { background: var(--gold); }

/* ---------- ticker ---------- */
.ticker-wrap {
  display: flex;
  align-items: center;
  background: var(--red);
  height: 10.8vh;
  overflow: hidden;
}
.ticker-label {
  flex: 0 0 auto;
  font-weight: 700;
  font-size: 3.8vh;
  letter-spacing: 0.1em;
  padding: 0 2.2vw;
  height: 100%;
  display: flex;
  align-items: center;
  background: rgba(0,0,0,0.18);
}
.ticker-track {
  flex: 1;
  overflow: hidden;
  white-space: nowrap;
  position: relative;
}
.ticker-content {
  display: inline-block;
  padding-left: 100%;
  font-size: 3.8vh;
  font-weight: 600;
  animation-name: ticker;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
  /* duration is set inline by app.js, scaled to content length so speed
     (not time) stays constant no matter how many events are in the ticker */
  animation-duration: 60s;
}
@keyframes ticker {
  from { transform: translateX(0); }
  to   { transform: translateX(-100%); }
}

/* ---------- progress bar ----------
   A per-event dot row doesn't scale - a city with 50+ upcoming events turns
   into an unreadable solid line. A single fill bar tracking time-until-next
   works the same regardless of list length. */
.progress-bar-track {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 0.7vh;
  background: rgba(255,255,255,0.12);
  z-index: 3;
}
.progress-bar-fill {
  height: 100%;
  width: 0%;
  background: var(--gold);
}
.progress-bar-fill.animate {
  transition: width linear;
}

.frame { position: relative; }

/* ---- Pi (offline) display additions -------------------------------------
   The city is fixed by the sign's own config, so the wordmark is plain text,
   not the laptop display's city <select>. */
div.wordmark { background: none; padding-right: 0; cursor: default; }
.qr-box.hidden { display: none; }
/* Venue's own posts ("ads") use the gold accent instead of the event date badge. */
.card.is-ad .date-badge { background: var(--gold, #f2b705); color: var(--navy, #0b1f3a); }
.offline-note { position: absolute; right: 1.2vh; bottom: 0.6vh; font-size: 1.3vh; opacity: 0.55; }

/* headless screenshots of virtual signs: no transitions to catch half-way */
html.still *, html.still *::before, html.still *::after { transition: none !important; }
