/* Shop-floor TV view - a big, read-only, always-on display meant to be
   viewed from across a bay, not held in a hand. Reuses styles.css's
   color variables and fonts but fixes the dark palette permanently
   (rather than following prefers-color-scheme) since a wall-mounted
   kiosk should look the same regardless of the display's own OS theme,
   and dark is easier on the eyes in a shop and better for an
   always-on screen. Everything here is deliberately large and simple -
   no buttons, no drag targets, nothing meant to be touched.
*/

.tv-body {
  --bg: #0b0d10;
  --surface: #171b20;
  --surface-2: #1d2229;
  --ink: #f2f4f5;
  --ink-soft: #9aa5ac;
  --line: #2c343b;
  --good: #63bd85;
  --good-bg: #163524;
  --warn: #e2af51;
  --warn-bg: #3a2c0f;
  --bad: #e0776a;
  --bad-bg: #3a1a16;
  background: var(--bg);
  color: var(--ink);
  overflow: hidden; /* a kiosk screen never scrolls the page itself - columns scroll internally */
}

.tv-body #tv-view {
  height: 100vh;
  display: flex;
  flex-direction: column;
}

.tv-header {
  display: flex;
  align-items: center;
  gap: 20px;
  padding: 18px 32px;
  background: var(--steel, #05070a);
  border-bottom: 3px solid var(--accent);
  flex: 0 0 auto;
}

.tv-header-logo {
  height: 62px;
  width: auto;
}

.tv-header-brand {
  /* The Broccolo mark itself is black line art on a transparent
     background - fine on the light login screen, but invisible against
     this header's near-black bar. Inverting flips the black artwork to
     white while leaving the transparent background untouched, so it
     reads clean on dark without needing a separate white-logo asset. */
  filter: invert(1);
}

.tv-header-badge {
  height: 52px; /* the Subaru Certified badge is a wider/shorter mark than the Broccolo logo - matched by eye rather than to the same height */
}

.tv-header-basf {
  height: 40px;
  width: auto;
  border-radius: 6px;
  padding: 3px 6px;
  background: #fff; /* the BASF mark itself is white-on-blue - a thin white
    frame around its own blue box keeps it from looking like a stray
    rectangle floating on the dark header, and echoes how the mark
    already presents on a light background elsewhere */
}

.tv-header-certs {
  display: flex;
  align-items: center;
  gap: 8px;
}

.tv-header-cert {
  /* Unlike the BASF mark, these came in on a plain white background that
     was keyed out to transparent (offline, not in CSS) - so the badge's
     own gray/gold/blue artwork sits directly on the dark header instead
     of inside a white card, reading as embedded rather than pasted on. */
  height: 44px;
  width: auto;
}

.tv-header-title {
  /* A dedicated serif, not var(--font-display) - that variable is shared
     with the column headers/card text elsewhere on this screen, and this
     is meant to look like the shop's own name/wordmark rather than match
     those. Title case + tighter spacing reads classier in a serif than
     the bold uppercase condensed look used for everything else. */
  font-family: 'Times New Roman', Times, Georgia, serif;
  font-size: 30px;
  font-weight: 600;
  letter-spacing: 0.01em;
  text-transform: none;
  margin: 0;
  color: #fff;
}

.tv-header-spacer { flex: 1; }

.tv-header-goal {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding-right: 24px;
  margin-right: 24px;
  border-right: 1px solid var(--line);
}

.tv-goal-pct {
  font-family: var(--font-mono);
  font-size: 26px;
  font-weight: 700;
  color: #fff;
}

.tv-goal-pct.is-good { color: var(--good); }

.tv-goal-label {
  font-size: 13px;
  color: var(--ink-soft);
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.tv-header-weather {
  display: flex;
  align-items: center;
  gap: 8px;
  padding-right: 24px;
  margin-right: 24px;
  border-right: 1px solid var(--line);
}

.tv-weather-icon { font-size: 30px; line-height: 1; }

.tv-weather-temp {
  font-family: var(--font-mono);
  font-size: 22px;
  color: #fff;
}

.tv-header-datetime { text-align: right; }

.tv-header-date {
  font-family: var(--font-mono);
  color: var(--ink-soft);
  font-size: 15px;
  letter-spacing: 0.03em;
}

.tv-header-clock {
  font-family: var(--font-mono);
  color: #fff;
  font-size: 26px;
  min-width: 130px;
}

.tv-quote-bar {
  flex: 0 0 auto;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  padding: 8px 32px;
  text-align: center;
}

.tv-quote-text {
  font-family: var(--font-display);
  font-style: italic;
  font-size: 16px;
  color: var(--ink-soft);
  letter-spacing: 0.01em;
  transition: opacity 1s ease;
}

.tv-quote-text.is-fading { opacity: 0; }

.tv-offline-banner {
  flex: 0 0 auto;
  background: var(--bad-bg);
  color: var(--bad);
  text-align: center;
  padding: 8px;
  font-size: 16px;
  font-weight: 600;
}

.tv-footer {
  flex: 0 0 auto;
  padding: 6px 32px;
  text-align: right;
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--ink-soft);
  border-top: 1px solid var(--line);
}

.tv-columns {
  flex: 1 1 auto;
  display: flex;
  gap: 16px;
  padding: 16px;
  overflow-x: auto;
  overflow-y: hidden;
  min-height: 0;
  scrollbar-width: none; /* the strip auto-scrolls on its own (tv.js) - no scrollbar to grab */
}
.tv-columns::-webkit-scrollbar { display: none; }

.tv-column {
  flex: 1 0 320px;
  max-width: 420px;
  min-width: 280px;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border-radius: 12px;
  border-top: 6px solid var(--stage-color, var(--accent));
  min-height: 0;
  overflow: hidden;
}

.tv-column-head {
  padding: 14px 16px 10px;
  flex: 0 0 auto;
  display: flex;
  align-items: baseline;
  gap: 10px;
  border-bottom: 1px solid var(--line);
}

.tv-column-title {
  font-family: var(--font-display);
  font-size: 20px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: #fff;
  margin: 0;
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tv-column-codes {
  font-family: var(--font-mono);
  font-size: 14px;
  font-weight: 400;
  text-transform: none;
  color: var(--ink-soft);
  letter-spacing: normal;
}

.tv-column-count {
  font-family: var(--font-mono);
  font-size: 16px;
  color: var(--ink-soft);
  background: var(--surface-2);
  border-radius: 999px;
  padding: 2px 10px;
}

.tv-column-body {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 10px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  scrollbar-width: none; /* auto-scrolls on its own (tv.js) - no scrollbar to grab */
}
.tv-column-body::-webkit-scrollbar { display: none; }

.tv-column-empty {
  color: var(--ink-soft);
  font-size: 14px;
  padding: 12px;
  text-align: center;
}

.tv-card {
  background: var(--surface-2);
  border-radius: 10px;
  padding: 12px 14px;
  border-left: 5px solid var(--stage-color, var(--accent));
}

.tv-card.is-sample {
  border-left-style: dashed;
  opacity: 0.8;
}

.tv-card-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px;
}

.tv-card-customer {
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: 600;
  color: #fff;
  line-height: 1.15;
}

.tv-card-ro {
  /* Deliberately much larger/brighter than the rest of the card's small
     print (plate, phase code) - the RO # is the one thing a tech needs
     to match at a glance from across the bay, everything else is
     secondary context read up close. */
  font-family: var(--font-mono);
  font-size: 22px;
  font-weight: 700;
  color: #fff;
  white-space: nowrap;
}

.tv-card-vehicle {
  font-size: 15px;
  color: var(--ink-soft);
  margin-top: 2px;
}

.tv-card-codes {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: 12.5px;
  color: var(--ink-soft);
  letter-spacing: 0.02em;
  margin-top: 3px;
}

.tv-card-phase {
  font-size: 13px;
  color: var(--ink-soft);
  margin-top: 6px;
  font-style: italic;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tv-card-meta-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 8px;
}

.tv-badge {
  font-size: 13px;
  font-weight: 600;
  padding: 3px 9px;
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink-soft);
  white-space: nowrap;
}

.tv-badge.is-warn { background: var(--warn-bg); color: var(--warn); }
.tv-badge.is-bad { background: var(--bad-bg); color: var(--bad); }
.tv-badge.is-good { background: var(--good-bg); color: var(--good); }
.tv-badge.is-sample { color: var(--ink-soft); background: var(--surface); border: 1px dashed var(--line); }

.tv-card-insurance {
  font-size: 13px;
  color: var(--ink-soft);
  margin-top: 6px;
}

.tv-pct-row {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 6px;
  font-size: 12px;
  color: var(--ink-soft);
}

.tv-pct-tag {
  flex: 0 0 auto;
  width: 40px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.tv-pct-bar {
  flex: 1;
  height: 6px;
  border-radius: 999px;
  background: var(--line);
  overflow: hidden;
}

.tv-pct-fill {
  height: 100%;
  background: var(--accent);
  border-radius: 999px;
}

.tv-pct-label {
  flex: 0 0 auto;
  font-family: var(--font-mono);
  width: 38px;
  text-align: right;
}

.tv-tech-chips {
  display: flex;
  margin-top: 8px;
}

.tv-tech-chip {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--accent-ink);
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 2px solid var(--surface-2);
  margin-left: -8px;
}

.tv-tech-chip:first-child { margin-left: 0; }

.tv-empty-state {
  margin: auto;
  color: var(--ink-soft);
  font-size: 20px;
  text-align: center;
}

/* Small unobtrusive control to switch between the default side-by-side
   board and the "Cycle" mode below - low-opacity until touched/hovered
   so it doesn't distract from a screen meant to be looked at, not used,
   most of the time. */
.tv-mode-toggle {
  position: fixed;
  right: 14px;
  bottom: 14px;
  z-index: 10;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--ink-soft);
  font-size: 18px;
  cursor: pointer;
  opacity: 0.35;
  transition: opacity 0.15s;
}
.tv-mode-toggle:hover, .tv-mode-toggle:focus-visible { opacity: 1; }

/* ---------- Cycle mode: one board column ("phase") at a time, paged
   into a grid of larger notecards, auto-advancing on a timer (tv.js) -
   an alternative to the default side-by-side strip above, for a screen
   easier to read at a glance/from further away. ---------- */
.tv-body #tv-cycle {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  min-height: 0;
  padding: 20px 32px;
}

.tv-cycle-header {
  display: flex;
  align-items: baseline;
  gap: 14px;
  flex: 0 0 auto;
  margin-bottom: 18px;
  border-bottom: 3px solid var(--stage-color, var(--accent));
  padding-bottom: 12px;
}

.tv-cycle-phase-title {
  font-family: var(--font-display);
  font-size: 34px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: #fff;
  margin: 0;
}

.tv-cycle-phase-codes {
  font-family: var(--font-mono);
  font-size: 18px;
  color: var(--ink-soft);
}

.tv-cycle-page-indicator {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 16px;
  color: var(--ink-soft);
}

/* Clips the grid below so a page-change slide moves fully off/on screen
   within this box, instead of spilling into the header/footer above and
   below it - the grid itself is absolutely positioned to fill this. */
.tv-cycle-viewport {
  flex: 1 1 auto;
  min-height: 0;
  position: relative;
  overflow: hidden;
}

.tv-cycle-grid {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  grid-auto-rows: min-content;
  align-content: start;
  gap: 10px;
  overflow-y: auto;
  /* Base state for the slide transition tv.js drives via inline styles
     on page change - see renderCyclePage(). Plain content refreshes
     (a live job move, the fallback poll) pass no direction and skip the
     transition entirely, so this never animates on data alone. */
  transform: translate(0, 0);
}
.tv-cycle-grid.is-full-detail { grid-template-columns: repeat(4, 1fr); }

.tv-cycle-card {
  /* --stage-color here is actually set per-card by tv.js to a
     green/yellow/red "how long has this been in the shop" color rather
     than the board stage's own color - every card on one cycle page
     already shares the same stage (a page IS one stage), so the stage
     color would be identical card to card and tell a tech nothing a
     glance at the page header doesn't already say. Aging is the thing
     that actually varies card to card and is worth flagging at a glance. */
  background: var(--surface);
  border-radius: 9px;
  border-left: 4px solid var(--stage-color, var(--accent));
  padding: 10px 12px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  overflow: hidden;
}

.tv-cycle-card-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
}

.tv-cycle-card-customer {
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 600;
  color: #fff;
  line-height: 1.15;
}

.tv-cycle-card-ro {
  font-family: var(--font-mono);
  font-size: 24px;
  font-weight: 700;
  color: #fff;
  white-space: nowrap;
}

.tv-cycle-card-vehicle { font-size: 13px; color: var(--ink-soft); }
.tv-cycle-card-vin { font-family: var(--font-mono); font-size: 12px; color: var(--ink-soft); }
.tv-cycle-card-phase { font-size: 13px; color: var(--ink-soft); font-style: italic; }
.tv-cycle-card-notes {
  font-size: 14px;
  color: var(--ink-soft);
  background: var(--surface-2);
  border-radius: 8px;
  padding: 8px 10px;
  margin-top: 4px;
  overflow-y: auto;
}
.tv-cycle-card-insurance { font-size: 15px; color: var(--ink-soft); margin-top: auto; }
.tv-cycle-card-meta-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 4px; }
.tv-cycle-empty { margin: auto; color: var(--ink-soft); font-size: 22px; text-align: center; }

/* ---------- Rally car easter egg ---------- */
/* Drives left-to-right across the whole screen every so often (see
   runRallyCar() in tv.js) - fixed position and pointer-events:none so it
   never blocks a click and never nudges the board layout underneath it. */
.tv-rally-car {
  position: fixed;
  bottom: 90px;
  left: -240px;
  width: 200px;
  z-index: 50;
  pointer-events: none;
}
.tv-rally-car.is-driving { animation: tv-rally-drive-x 7s linear forwards; }
.tv-rally-car.is-driving .tv-rally-car-svg { animation: tv-rally-bounce 0.28s ease-in-out infinite; }
.tv-rally-car-svg { display: block; width: 100%; height: auto; filter: drop-shadow(0 6px 6px rgba(0,0,0,0.35)); }
.tv-rally-number { font: 700 22px 'Oswald', sans-serif; fill: #1450c4; }
.tv-rally-wheel { animation: tv-rally-spin 0.4s linear infinite; }
.tv-rally-wheel-l { transform-origin: 56px 76px; }
.tv-rally-wheel-r { transform-origin: 168px 76px; }
.tv-rally-dust {
  position: absolute;
  bottom: 6px;
  left: -10px;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(210,195,160,0.55), rgba(210,195,160,0));
  opacity: 0;
}
.tv-rally-car.is-driving .tv-rally-dust-1 { animation: tv-rally-puff 0.6s ease-out infinite; }
.tv-rally-car.is-driving .tv-rally-dust-2 { animation: tv-rally-puff 0.6s ease-out 0.2s infinite; }
.tv-rally-car.is-driving .tv-rally-dust-3 { animation: tv-rally-puff 0.6s ease-out 0.4s infinite; }

@keyframes tv-rally-drive-x {
  0% { left: -240px; }
  100% { left: 100vw; }
}
@keyframes tv-rally-bounce {
  0%, 100% { transform: translateY(0) rotate(0deg); }
  50% { transform: translateY(-2px) rotate(-0.6deg); }
}
@keyframes tv-rally-spin {
  to { transform: rotate(360deg); }
}
@keyframes tv-rally-puff {
  0% { opacity: 0.6; transform: scale(0.4) translateX(0); }
  100% { opacity: 0; transform: scale(1.6) translateX(-30px); }
}

/* A TV is almost always landscape and wide, but keep this from breaking
   outright if someone opens it on a narrower screen to check it. */
@media (max-width: 900px) {
  .tv-header-title { font-size: 20px; }
  .tv-header-clock { font-size: 20px; }
  .tv-column { flex: 1 0 240px; min-width: 220px; }
  .tv-cycle-grid { grid-template-columns: repeat(2, 1fr) !important; }
}
