/* ==========================================================================
   Epochs — the round, and the components only the round has.

   This is `app.css`'s layer 5 in a file of its own: the timeline row and its
   n + 1 slots, the artwork card and its reveal, the countdown ring, the table
   screen, the player list, the chat sheet's log. It is loaded AFTER `app.css`,
   so a rule here beats the component it varies without needing a stronger
   selector to do it. Every colour, size and duration below is one of the
   reader's tokens (`app.css` §1); nothing here invents a value.

   Two accents and only two: `--accent` and `--danger` carry interaction, and
   `--ok` / `--warn` never colour a button — only text, a chip or a ring.

   Three things animate, and all three stop under `prefers-reduced-motion`:
   the ring's sweep, the strip's scroll, and the reveal's cross-fade.
   ========================================================================== */

/* --- 1 · the timeline row ------------------------------------------------
   n cards, n + 1 slots, in that alternation. The strip owns the horizontal
   axis; the PAGE never scrolls sideways (STYLE.md §3).                      */

.timeline {
  display: flex;
  align-items: stretch;
  gap: 0;
  overflow-x: auto;
  overflow-y: hidden;
  padding: var(--space-2) 0;
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
}

.timeline::-webkit-scrollbar { height: 6px; }
.timeline::-webkit-scrollbar-thumb { background: var(--line); border-radius: var(--radius-pill); }

/* The touch target is wider than the mark drawn inside it: "it looks like a
   6 px gap" and "you can hit it with a thumb" both have to be true. */
.tl-slot {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: var(--tap);
  min-height: var(--tap);
  padding: 0;
  border: none;
  border-radius: var(--radius-md);
  background: transparent;
  color: inherit;
  cursor: pointer;
}

.tl-slot[aria-disabled='true'] { cursor: default; pointer-events: none; }

.tl-mark {
  display: block;
  width: 4px;
  height: 60%;
  min-height: var(--space-6);
  border-radius: var(--radius-pill);
  background: var(--line);
}

/* Pressable only where the stage says so — the strip carries the state and the
   slot inherits it, so one attribute turns a whole row on. */
.timeline[data-placeable='true'] .tl-slot:not([aria-disabled='true']) .tl-mark,
.timeline[data-challengeable='true'] .tl-slot:not([aria-disabled='true']) .tl-mark {
  width: 6px;
  background: var(--accent);
}

.timeline[data-placeable='true'] .tl-slot:hover,
.timeline[data-challengeable='true'] .tl-slot:hover {
  background: color-mix(in srgb, var(--accent) 12%, transparent);
}

.tl-slot[aria-pressed='true'] { background: color-mix(in srgb, var(--accent) 20%, transparent); }

/* The active player's pick, ringed once the challenge stage begins. */
.tl-slot[data-placed='true'] { box-shadow: inset 0 0 0 2px var(--accent); }

/* Right and wrong are STATUS, in text and in a ring — never a green button. */
.tl-slot[data-correct='true'] .tl-mark { background: var(--ok); }
.tl-slot[data-correct='true'] { box-shadow: inset 0 0 0 2px var(--ok); }
.tl-slot[data-correct='false'] .tl-mark { background: var(--danger); }

.tl-card {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  width: 120px;
  margin: 0;
  padding: var(--space-1);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--card);
  scroll-snap-align: center;
}

.tl-card img,
.tl-thumb {
  display: block;
  width: 100%;
  height: 160px;
  border-radius: var(--radius-sm);
  object-fit: cover;
  background: var(--bg);
}

.tl-thumb.placeholder { border: 1px dashed var(--line); }

.tl-card[data-won='true'] { border-color: var(--accent); }

.tl-year {
  font-size: var(--text-sm);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.tl-title {
  font-size: var(--text-xs);
  color: var(--muted);
  line-height: 1.3;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

/* A chip on a slot: the avatar's mechanism, at slot size. Not a .badge (it is
   inside the layout, not over it) and not a .pill (the topbar's alone). */
.tl-chip {
  display: grid;
  place-items: center;
  width: var(--space-6);
  height: var(--space-6);
  border-radius: var(--radius-pill);
  border: 1px solid var(--line);
  font-size: var(--text-xs);
  font-weight: 700;
  background: var(--card);
}

.tl-chip.lit {
  background: oklch(from var(--card) calc(l + var(--lit-pull)) var(--cover-chroma) var(--cover-hue));
  border-color: oklch(from var(--card) calc(l + 0.2) var(--lit-line) var(--cover-hue));
}

.tl-chip[data-self='true'] { box-shadow: 0 0 0 2px var(--accent); }

/* --- 2 · the artwork card ------------------------------------------------ */

.artwork {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.artwork img,
.artwork-placeholder {
  display: block;
  width: 100%;
  max-height: 42dvh;
  aspect-ratio: 3 / 4;
  border-radius: var(--radius-lg);
  object-fit: contain;
  background: var(--card);
  transition: opacity var(--dur) ease;
}

.artwork-placeholder { border: 1px dashed var(--line); }

.artwork[data-img='failed'] img { display: none; }

.artwork figcaption {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.artwork-year {
  font-size: var(--text-xl);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.artwork-title { font-size: var(--text-base); font-weight: 600; }
.artwork-artist { font-size: var(--text-sm); color: var(--muted); }

/* The reason this app may show these pictures at all. */
.artwork-credit { font-size: var(--text-xs); color: var(--muted); line-height: 1.45; }
.artwork-credit a { color: inherit; text-decoration: underline; }

/* A third flex item beside the picture and the ring, so it needs the same two
   rules the other free-text surfaces have (`.request .claim`, `.chat-text`): a
   24-character name is one unbreakable word, and without these it sets the
   row's floor and scrolls the page sideways. */
.artwork-result {
  min-width: 0;
  margin: var(--space-2) 0 0;
  font-size: var(--text-md);
  overflow-wrap: anywhere;
}

/* The reveal cross-fades; under reduced motion it simply swaps (§5). */
.artwork[data-state='revealed'] img { animation: artwork-reveal var(--dur) ease-out; }

@keyframes artwork-reveal {
  from { opacity: 0.4; }
  to { opacity: 1; }
}

/* --- 3 · the countdown ring ----------------------------------------------
   One custom property, `--countdown-frac` (1 → 0), and the geometry is here.
   r = 16 in a 36-box, so the circumference is 2πr ≈ 100.53.                 */

.countdown {
  position: relative;
  display: inline-grid;
  place-items: center;
  width: var(--space-12);
  height: var(--space-12);
  --countdown-colour: var(--accent);
}

.countdown[data-urgency='warn'] { --countdown-colour: var(--warn); }
.countdown[data-urgency='danger'] { --countdown-colour: var(--danger); }

.countdown-ring {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  transform: rotate(-90deg);
}

.countdown-track,
.countdown-sweep {
  fill: none;
  stroke-width: 3;
}

.countdown-track { stroke: var(--line); }

.countdown-sweep {
  stroke: var(--countdown-colour);
  stroke-linecap: round;
  stroke-dasharray: 100.53;
  stroke-dashoffset: calc(100.53 * (1 - var(--countdown-frac, 0)));
  transition: stroke-dashoffset var(--dur) linear;
}

.countdown-text {
  font-size: var(--text-sm);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--countdown-colour);
}

/* --- 4 · the table screen ------------------------------------------------ */

.table {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-4);
}

.turn-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
}

.turn-head h2 { margin: 0; font-size: var(--text-lg); }

.table-card {
  display: flex;
  align-items: flex-start;
  gap: var(--space-4);
}

.table-card .artwork { flex: 1 1 auto; min-width: 0; }
.table-card .countdown { flex: 0 0 auto; }

.table-controls {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.table-controls .actions { margin-top: 0; }
.table-controls .actions:empty { display: none; }
.table-controls .hint { flex-basis: 100%; margin: 0; }

.ask-chip label { display: block; font-size: var(--text-sm); color: var(--muted); }
.ask-chip .field-row { display: flex; gap: var(--space-2); align-items: center; }
.ask-chip .field-row input { flex: 1 1 auto; min-width: 0; min-height: var(--tap); }

.request .claim {
  margin: var(--space-2) 0;
  font-style: italic;
  overflow-wrap: anywhere;
}

.ended { display: flex; flex-direction: column; gap: var(--space-4); padding: var(--space-4); }

/* --- 5 · the player list -------------------------------------------------
   `app/STYLE.md` §6, and the ONE definition of the row: the lobby's list and
   the stats sheet's are the same markup from the same renderer
   (`views/people.js`), so they are the same component here too.

   One row per PLAYER, in turn order: avatar, name (with the master's star and
   the friend mark), the two counts, a presence chip, and — for the master
   alone — the row of buttons about that person. The status marker is a `.chip`
   and never a `.pill`; the star is the only badge of office and it carries a
   real accessible name. The counts are `tabular-nums` so a column of them
   lines up.                                                                 */

.player-list { list-style: none; margin: 0 0 var(--space-6); padding: 0; }

.player-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-3);
  min-height: var(--tap);
  padding: var(--space-3) 0;
}

.player-row + .player-row { border-top: 1px solid var(--line); }

.player-name {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 600;
}

.player-cards,
.player-chips {
  flex: 0 0 auto;
  min-width: 3ch;
  text-align: right;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}

/* The star is the only badge of office, and it is the one place a hue that is
   not an accent may touch a glyph: it says WHOSE device is the truth. */
.player-row .master-mark { flex: none; color: var(--warn); display: inline-flex; }

/* The friend mark is the reader's, in the reader's hue: the ring round the
   avatar and the glyph beside the name, both `--hue-chat`. */
.player-row .friend-mark { flex: none; color: var(--hue-chat); display: inline-flex; }
.player-row[data-friend='true'] .avatar { box-shadow: 0 0 0 2px var(--hue-chat); }

.player-row[data-active='true'] { font-weight: 650; }

/* Somebody who left is still a row — their cards are out of the deck and their
   seat is still theirs (`docs/RULES.md` §9) — but they are not in the room. */
.player-row[data-left='true'] { color: var(--muted); }
.player-row[data-left='true'] .player-name,
.player-row[data-online='false'] .player-name { color: var(--muted); }

/* The master's controls take the whole second line rather than squeezing four
   44px buttons in beside a name. On a phone that is the only way they fit; on
   a laptop it keeps the row readable, which is the same reason. */
.player-row .actions { flex: 1 1 100%; margin-top: var(--space-1); }
.player-row .actions:empty { display: none; }

.winner-list { margin: var(--space-1) 0 0; padding-left: var(--space-5); }

/* --- 6 · the chat sheet's log -------------------------------------------- */

.chat-log { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }

.chat-line {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: var(--space-1) var(--space-2);
  padding: var(--space-2) 0;
  align-items: baseline;
}

.chat-line .avatar { grid-row: span 2; align-self: start; }
.chat-who { font-weight: 650; font-size: var(--text-sm); }
.chat-at { color: var(--muted); font-size: var(--text-xs); font-variant-numeric: tabular-nums; }

.chat-text {
  grid-column: 2 / -1;
  overflow-wrap: anywhere;
  line-height: 1.45;
}

.chat-line[data-self='true'] .chat-who { color: var(--accent); }
.chat-line[data-friend='true'] .chat-who { color: var(--hue-chat); }

.chat-compose {
  position: sticky;
  bottom: 0;
  display: flex;
  gap: var(--space-2);
  padding-top: var(--space-3);
  background: var(--card);
}

.chat-compose input {
  flex: 1 1 auto;
  min-width: 0;
  min-height: var(--tap);
}

/* --- 7 · reduced motion --------------------------------------------------
   The ring stops sweeping (the number is the whole component), the strip
   scrolls instantly, and the reveal swaps rather than fades.                */

@media (prefers-reduced-motion: reduce) {
  .timeline { scroll-behavior: auto; }
  .countdown-sweep { transition: none; }
  .artwork[data-state='revealed'] img { animation: none; }
  .artwork img { transition: none; }
}
