/* Wall display. Everything scales off viewport units so one build works on a
   43" 1080p panel and a 65" 4K without per-screen tuning. */

.board {
  height: 100vh;
  display: grid;
  grid-template-rows: auto auto 1fr auto;
  /* minmax(0, …) everywhere: by default a grid/flex track grows to fit its
     longest unbreakable content, and on a wall display that means a long
     vehicle name or a busy queue pushes half the board off the screen. */
  grid-template-columns: minmax(0, 1fr);
  gap: 0.6vh;
  padding: 1.2vh 1.2vw;
  overflow: hidden;
}

.topbar {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
}

.brand {
  display: flex;
  align-items: center;
  gap: 1vw;
  min-width: 0;
}

/* Sized off viewport height so the header keeps its proportion from a 43"
   panel up to 4K, and capped so a wide wordmark cannot crowd out the clock. */
.logo {
  height: clamp(1.6rem, 5vh, 5rem);
  max-width: 34vw;
  width: auto;
  object-fit: contain;
}

.topbar h1 {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  margin: 0;
  font-size: clamp(1.1rem, 2.6vh, 2.6rem);
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--text-dim);
  text-transform: uppercase;
}

.topbar-right { display: flex; align-items: baseline; gap: 1.4vw; }

.clock {
  font-size: clamp(1.1rem, 2.8vh, 2.8rem);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* Stale data on a wall monitor is worse than no data — say so plainly. */
.stale {
  font-size: clamp(0.8rem, 1.9vh, 1.7rem);
  font-weight: 700;
  color: var(--bg);
  background: var(--overdue);
  padding: 0.2em 0.7em;
  border-radius: 999px;
}

.banners:empty { display: none; }

.banner {
  display: flex;
  align-items: center;
  gap: 0.8vw;
  background: var(--surface-2);
  border-left: 0.7vw solid var(--brand, var(--st-assigned));
  border-radius: var(--radius);
  padding: 0.9vh 1.2vw;
  font-size: clamp(1rem, 2.8vh, 2.6rem);
  font-weight: 600;
}

.banner.level-warn   { border-left-color: var(--due-soon); }
.banner.level-urgent { border-left-color: var(--overdue); }

.banner .banner-tag {
  font-size: 0.55em;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-dim);
  flex: none;
}

.bays {
  display: grid;
  gap: 1vh 1vw;
  grid-template-columns: repeat(var(--cols, 3), minmax(0, 1fr));
  grid-auto-rows: 1fr;
  min-height: 0;
}

.bay {
  position: relative;
  min-width: 0;
  display: grid;
  grid-template-rows: auto 1fr auto;
  gap: 0.4vh;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.1vh 1.1vw 1.1vh calc(1.1vw + 1vw);
  min-height: 0;
  overflow: hidden;
}

/* The status stripe: color, but always alongside the written status below. */
.bay::before {
  content: '';
  position: absolute;
  inset: 0 auto 0 0;
  width: 1vw;
  background: var(--status, var(--st-waiting));
}

.bay.is-empty { opacity: 0.45; }
.bay.is-overdue  { border-color: var(--overdue); }
.bay.is-due_soon { border-color: var(--due-soon); }

.bay-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.6vw;
}

.bay-name {
  font-size: clamp(1.1rem, 3.4vh, 3.4rem);
  font-weight: 800;
  letter-spacing: 0.01em;
  white-space: nowrap;
}

.bay-head-right { display: flex; align-items: baseline; gap: 0.6vw; }

.bay-stacked {
  font-size: clamp(0.7rem, 1.8vh, 1.6rem);
  font-weight: 800;
  color: var(--bg);
  background: var(--text-dim);
  border-radius: 999px;
  padding: 0.1em 0.6em;
  white-space: nowrap;
}

.bay-ro {
  font-family: var(--mono);
  font-size: clamp(0.75rem, 1.9vh, 1.7rem);
  color: var(--text-dim);
}

.bay-body {
  display: grid;
  align-content: center;
  min-height: 0;
  overflow: hidden;
}

/* The vehicle is what someone across the shop is actually looking for, so it
   gets the middle of the tile and the largest type after the bay name. */
.bay-vehicle {
  font-size: clamp(1.1rem, 4.4vh, 4.2rem);
  font-weight: 600;
  line-height: 1.05;
  text-wrap: balance;
  overflow-wrap: anywhere;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.bay-desc {
  margin-top: 0.5vh;
  font-size: clamp(0.75rem, 2.3vh, 2.2rem);
  color: var(--text-dim);
  line-height: 1.2;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.bay-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6vw;
}

.bay-status {
  font-size: clamp(0.8rem, 2.2vh, 2.1rem);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--status, var(--st-waiting));
  white-space: nowrap;
}

.bay-meta { display: flex; align-items: center; gap: 0.6vw; }

.tech-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2.2em;
  padding: 0.1em 0.45em;
  border-radius: 0.35em;
  font-size: clamp(0.8rem, 2.2vh, 2.1rem);
  font-weight: 800;
  color: #0b0f16;
  background: var(--tech, var(--st-assigned));
}

.bay-elapsed {
  font-family: var(--mono);
  font-size: clamp(0.85rem, 2.4vh, 2.3rem);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.bay-promised {
  font-size: clamp(0.7rem, 1.8vh, 1.6rem);
  font-weight: 700;
  color: var(--text-dim);
  white-space: nowrap;
}

.bay.is-overdue  .bay-promised { color: var(--overdue); }
.bay.is-due_soon .bay-promised { color: var(--due-soon); }

.bay-empty-text {
  align-self: center;
  font-size: clamp(1rem, 3vh, 2.8rem);
  font-weight: 700;
  color: var(--text-dim);
}

.queue-strip {
  display: flex;
  align-items: center;
  gap: 1vw;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0.8vh 1vw;
  min-height: 0;
}

.queue-label {
  flex: none;
  font-size: clamp(0.75rem, 1.9vh, 1.7rem);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--text-dim);
}

.queue {
  flex: 1;
  min-width: 0;
  display: flex;
  gap: 0.8vw;
  margin: 0;
  padding: 0;
  list-style: none;
  overflow: hidden;
}

.queue li {
  display: flex;
  align-items: baseline;
  gap: 0.5vw;
  background: var(--surface-2);
  border-radius: 0.5em;
  padding: 0.35vh 0.8vw;
  font-size: clamp(0.8rem, 2.1vh, 2rem);
  font-weight: 600;
  white-space: nowrap;
}

.queue li.is-overdue { box-shadow: inset 0 0 0 2px var(--overdue); }
.queue .q-ro { font-family: var(--mono); font-size: 0.8em; color: var(--text-dim); }

/* ---- live clocks --------------------------------------------------------- */

.bay-elapsed { display: inline-flex; align-items: center; gap: 0.35em; }
.bay-elapsed.is-running { color: var(--st-in_progress); }
/* A paused job's time is frozen: dim it so "stopped" never reads as "stuck". */
.bay-elapsed.is-paused { color: var(--text-dim); }

.live-dot {
  width: 0.5em;
  height: 0.5em;
  border-radius: 50%;
  background: currentColor;
  animation: pulse 1s steps(2, jump-none) infinite;
}

.clock .colon { animation: pulse 1s steps(2, jump-none) infinite; }
.clock .ampm { font-size: 0.6em; color: var(--text-dim); }

@keyframes pulse { 50% { opacity: 0.15; } }

/* Respect the OS setting; the seconds still count, only the blink stops. */
@media (prefers-reduced-motion: reduce) {
  .live-dot, .clock .colon { animation: none; }
}

/* Align the clock with the title rather than the logo's baseline. */
.topbar { align-items: center; }

/* With seconds on the timers the footer can be wider than a narrow tile. Wrap
   the meta onto its own line rather than overflow or hide the due time. */
.bay-foot { flex-wrap: wrap; row-gap: 0.3vh; }
.bay-meta { margin-left: auto; }

/* ---- shop hours ------------------------------------------------------------ */

.hours-pill {
  font-size: clamp(0.8rem, 1.9vh, 1.7rem);
  font-weight: 800;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--line);
  padding: 0.2em 0.8em;
  border-radius: 999px;
}

/* In progress but not counting: the shop is closed. */
.bay-elapsed.is-after-hours { color: var(--text-dim); }
.bay-elapsed.is-after-hours .live-dot { display: none; }

/* ---- page banner ---------------------------------------------------------- */

.page-banner {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1.2vw;
  padding: 2.4vh 2vw;
  font-size: clamp(1.4rem, 5vh, 5rem);
  font-weight: 800;
  background: var(--due-soon);
  color: #1a1204;
  box-shadow: 0 -1vh 4vh rgba(0, 0, 0, 0.5);
}
.page-banner .small { font-size: 0.45em; font-weight: 700; }
.page-banner .ic-dot {
  width: 0.55em; height: 0.55em; border-radius: 50%;
  background: currentColor;
  animation: ic-pulse 0.9s ease-in-out infinite;
}
@keyframes ic-pulse { 50% { opacity: 0.25; transform: scale(0.8); } }
@media (prefers-reduced-motion: reduce) { .page-banner .ic-dot { animation: none; } }

/* Pin every region to its own row. With implicit placement, an empty (hidden)
   notices row made each later region slide up one slot — the bays landed in an
   auto-height row and the Next Up strip took the stretch row, squashing every
   tile to the top whenever no announcement was showing. */
.board > .topbar       { grid-row: 1; }
.board > .banners      { grid-row: 2; }
.board > .bays         { grid-row: 3; }
.board > .queue-strip  { grid-row: 4; }

/* Offline snapshot: the timer is not counting, so it must not look like it is. */
.bay-elapsed.is-frozen { color: var(--text-dim); }
.bay-elapsed.is-frozen .live-dot { display: none; }
