/* Dispatch — layered on the classic stylesheet, which supplies the board,
   tiles, colour ramp, themes and fonts. Only what Dispatch adds lives here. */

/* Heading, orders panel and game switch, plus the leaderboard when
   there is one, at its tallest: both rows carrying a "best" line. Measured in
   the browser at 412px wide; the one-line heading (2026-10-12) took 69px off
   both. The :has() rule has to restate classic's, which it would otherwise
   lose to on specificity.
   These budget for the orders row wrapped onto two lines, as it is on a page
   under 384px wide. Once the screen is tall enough that the board, and so the
   page, is at least 384px wide, the row is one line and 26px shorter. */
@media (min-height: 561px) {
  :root {
    --chrome: 229px;
  }
  :root:has(.leaderboard) {
    --chrome: 367px;
  }
}

@media (min-height: 589px) {
  :root {
    --chrome: 203px;
  }
}

@media (min-height: 725px) {
  :root:has(.leaderboard) {
    --chrome: 341px;
  }
}

/* "Dispatch" runs about 4.4em wide in Clear Sans Bold, against 2.35em for
   "2048", so the fill-the-box sizing divides by more. */
.dispatch h1.title {
  font-size: clamp(22px, calc(100cqi / 4.6), 90px);
}

.game-message .message-spare {
  display: block;
  margin-top: 6px;
  font-size: calc(var(--board) * 0.05);
}

/* ---- orders ----
   One row above the board: the active order with the moves left beside it,
   the shipped count, then, stacked at the right, the next three incoming
   tiles over the two orders after this one. Moves left and shipped use the
   score boxes' look. On a page too narrow for all of it, the stack drops to
   a line of its own. */

.dispatch-panel {
  display: flex;
  flex-direction: column;
  gap: 8px;
  container-type: inline-size;
}

.dispatch-row {
  display: flex;
  align-items: stretch;
  gap: 6px;
  min-height: 60px;
}

.dispatch-active,
.dispatch-shipped {
  border-radius: 8px;
  background: var(--board-bg);
  color: var(--ink-light);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  transition-property: background-color, color;
  transition-duration: 240ms;
  transition-timing-function: ease;
}

.dispatch-active {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 14px 6px 8px;
}

/* The last few moves: the pill takes the title colour, in both themes. */
.dispatch-active.is-low {
  background: var(--ink);
  color: var(--ground);
}

.dispatch-active-chip {
  display: flex;
}

.dispatch-active-chip:empty {
  display: none;
}

.dispatch-moves,
.dispatch-shipped {
  display: flex;
  flex-direction: column-reverse;
  justify-content: center;
  font-size: 22px;
  line-height: 1.1;
}

.dispatch-shipped {
  align-items: center;
  min-width: 62px;
  padding: 6px 14px;
}

/* Captions above the numbers, as on the score boxes. */
.dispatch-moves::after,
.dispatch-shipped::after {
  color: var(--score-label);
  font-size: 11px;
  letter-spacing: 0.06em;
  line-height: 1.4;
  text-transform: uppercase;
  white-space: nowrap;
}

.dispatch-moves::after {
  content: "Moves left";
}

.dispatch-shipped::after {
  content: "Shipped";
}

.dispatch-active.is-low .dispatch-moves::after {
  color: inherit;
  opacity: 0.8;
}

/* The next tiles over the queued orders, right-aligned. */
.dispatch-previews {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  justify-content: center;
  gap: 6px;
  margin-left: auto;
}

/* Too narrow for one row (it needs about 383px): the stack becomes a line
   under the pill. */
@container (max-width: 383px) {
  .dispatch-row {
    flex-wrap: wrap;
  }

  .dispatch-previews {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    margin-left: 0;
  }
}

/* A page squeezed by a short screen: shorter caption, tighter pill. */
@container (max-width: 300px) {
  .dispatch-moves::after {
    content: "Moves";
  }

  .dispatch-active {
    gap: 8px;
    padding-right: 10px;
  }

  .dispatch-shipped {
    min-width: 0;
    padding: 6px 10px;
  }
}

.dispatch-orders {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.order {
  display: flex;
  align-items: center;
  gap: 2px;
}

.order-chip,
.next-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 5px;
  background: var(--c);
  color: var(--tile-ink);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.order-chip {
  min-width: 26px;
  height: 24px;
  padding: 0 4px;
  font-size: 13px;
}

.dispatch-active .order-chip {
  min-width: 50px;
  height: 42px;
  padding: 0 6px;
  font-size: 22px;
}

/* Upstream's palette sets 8 and up in light type. */
:root[data-palette="original"] .order-chip:not([data-v="2"]):not([data-v="4"]),
:root[data-palette="original"] .next-chip:not([data-v="2"]):not([data-v="4"]) {
  color: var(--ink-light);
}

.order-edge {
  display: inline-flex;
  color: var(--ink);
}

.order-edge svg {
  width: 18px;
  height: 18px;
}

.order-edge[data-edge="right"] svg  { transform: rotate(90deg); }
.order-edge[data-edge="bottom"] svg { transform: rotate(180deg); }
.order-edge[data-edge="left"] svg   { transform: rotate(270deg); }

.dispatch-next {
  display: flex;
  align-items: center;
  gap: 4px;
  color: var(--ink-muted);
}

.next-chip {
  min-width: 22px;
  height: 22px;
  padding: 0 4px;
  font-size: 12px;
}

/* ---- bays ----
   The two middle cells of the ordered edge light up in the order's colour, and
   a bar in the board's margin marks the edge they ship through. */

.grid-cell.is-bay {
  background: color-mix(in srgb, var(--c) 22%, var(--cell-empty));
  box-shadow: inset 0 0 0 3px var(--c);
}

.bay-bar {
  position: absolute;
  z-index: 1;
  display: none;
  border-radius: 999px;
  background: var(--c);
  pointer-events: none;
}

.bay-bar[data-edge] {
  display: block;
}

/* Cells sit at 3% / 27.25% / 51.5% / 75.75% and are 21.25% wide, so the middle
   pair spans 27.25% to 72.75%; the bar sits in the 3% margin outside them. */
.bay-bar[data-edge="top"],
.bay-bar[data-edge="bottom"] {
  left: 27.25%;
  width: 45.5%;
  height: 1.4%;
}

.bay-bar[data-edge="top"]    { top: 0.8%; }
.bay-bar[data-edge="bottom"] { bottom: 0.8%; }

.bay-bar[data-edge="left"],
.bay-bar[data-edge="right"] {
  top: 27.25%;
  height: 45.5%;
  width: 1.4%;
}

.bay-bar[data-edge="left"]  { left: 0.8%; }
.bay-bar[data-edge="right"] { right: 0.8%; }

/* ---- shipping ----
   The shipped tile slides into its bay like any other, then leaves through the
   edge. The delay lets the slide land first. */

/* Keyed off the inner element: the actuator rewrites the wrapper's classes a
   frame after adding it, so a class put on the wrapper does not last. */
.tile:has(> .tile-inner.is-shipping) {
  z-index: 20;
}

.tile .tile-inner.is-shipping {
  animation: 300ms cubic-bezier(0.5, 0, 0.9, 0.5) var(--slide) forwards;
}

.tile-inner.is-shipping[data-edge="top"]    { animation-name: ship-top; }
.tile-inner.is-shipping[data-edge="bottom"] { animation-name: ship-bottom; }
.tile-inner.is-shipping[data-edge="left"]   { animation-name: ship-left; }
.tile-inner.is-shipping[data-edge="right"]  { animation-name: ship-right; }

@keyframes ship-top    { to { transform: translateY(-120%) scale(0.8); opacity: 0; } }
@keyframes ship-bottom { to { transform: translateY(120%) scale(0.8);  opacity: 0; } }
@keyframes ship-left   { to { transform: translateX(-120%) scale(0.8); opacity: 0; } }
@keyframes ship-right  { to { transform: translateX(120%) scale(0.8);  opacity: 0; } }

/* ---- leaderboard: today's run ---- */

.dispatch .lb-title {
  display: flex;
  justify-content: space-between;
}

.lb-run {
  justify-self: end;
  padding: 2px 7px;
  border-radius: 4px;
  background: rgba(0, 0, 0, 0.14);
  font-size: 12px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* A full run: the green from the ramp's 64, fixed so it reads as "done" in
   both palettes. */
.lb-run.is-full {
  background: #00db97;
  color: #241f1a;
}

.lb-none {
  justify-self: end;
  font-size: 12px;
  opacity: 0.6;
  white-space: nowrap;
}

/* A practice run that beat the counted one, under that run's turns left. */
.lb-daybest {
  display: block;
  font-size: 11px;
  font-weight: 700;
  opacity: 0.7;
}

@media (prefers-reduced-motion: reduce) {
  .tile .tile-inner.is-shipping {
    animation-duration: 1ms;
    animation-delay: 0ms;
  }
}
