/* Inventor Link Lines — a broadsheet layout block crossed with a station sign board.
   Flat black sign blocks, hairline rules, square corners, everything on one grid. */

:root {
  --safe-t: env(safe-area-inset-top, 0px);
  --safe-r: env(safe-area-inset-right, 0px);
  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-l: env(safe-area-inset-left, 0px);
  --gap: 8px;
  --rule: 2px;
  --frame: 4px;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  min-height: 100%;
}

body {
  min-height: 100vh;
  min-height: 100dvh;
  background-color: var(--ak-bg);
  background-image: var(--ak-backdrop-layer, var(--ak-bg-art));
  background-size: cover;
  background-position: center top;
  background-attachment: fixed;
  color: var(--ak-ink);
  font-family: var(--ak-font-body);
  -webkit-tap-highlight-color: transparent;
}

[hidden] { display: none !important; }

/* ---------- stage: portrait, board above controls ---------- */

.stage {
  display: grid;
  grid-template-columns: var(--board);
  grid-template-areas:
    "top"
    "sign"
    "rules"
    "board"
    "note"
    "actions"
    "dir";
  row-gap: var(--gap);
  justify-content: center;
  align-content: start;
  --chrome-portrait: 432px;
  --board: min(
    calc(100vw - 24px - var(--safe-l) - var(--safe-r)),
    calc(100vh - var(--chrome-portrait) - var(--safe-t) - var(--safe-b)),
    600px
  );
  --board: min(
    calc(100dvw - 24px - var(--safe-l) - var(--safe-r)),
    calc(100dvh - var(--chrome-portrait) - var(--safe-t) - var(--safe-b)),
    600px
  );
  --n: 5;
  --cell: calc((var(--board) - 2 * var(--frame)) / var(--n));
  min-height: 100vh;
  min-height: 100dvh;
  padding:
    calc(8px + var(--safe-t))
    calc(12px + var(--safe-r))
    calc(8px + var(--safe-b))
    calc(12px + var(--safe-l));
  touch-action: manipulation;
  user-select: none;
  -webkit-user-select: none;
}

.top {
  grid-area: top;
  display: grid;
  grid-template-columns: 48px 1fr 48px;
  align-items: center;
  height: 52px;
  border-bottom: var(--rule) solid var(--ak-ink);
  box-shadow: 0 3px 0 -1px var(--ak-accent);
  padding-bottom: 4px;
}

.logo {
  justify-self: center;
  height: 40px;
  width: auto;
  max-width: 100%;
  object-fit: contain;
}

.mute {
  width: 48px;
  height: 48px;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: var(--ak-accent-2);
  color: var(--ak-btn-ink);
  display: grid;
  place-items: center;
  cursor: pointer;
}
.mute svg {
  width: 24px;
  height: 24px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: square;
  stroke-linejoin: miter;
}
.mute .spk { fill: currentColor; }
.mute .cross { display: none; }
.mute[aria-pressed="true"] .wave { display: none; }
.mute[aria-pressed="true"] .cross { display: inline; }
.mute:focus-visible,
.sign-btn:focus-visible {
  outline: 3px solid var(--ak-focus);
  outline-offset: 2px;
}

/* ---------- departure sign ---------- */

.sign {
  grid-area: sign;
  justify-self: center;
  display: flex;
  gap: 3px;
  padding: 5px;
  background: var(--ak-accent-2);
  border-bottom: 4px solid var(--ak-accent);
}

.flap {
  position: relative;
  width: clamp(28px, calc(var(--board) / 10), 44px);
  height: clamp(36px, calc(var(--board) / 8), 52px);
  display: grid;
  place-items: center;
  background: #262320;
  color: var(--ak-btn-ink);
  font-family: var(--ak-font-body);
  font-weight: 700;
  font-size: clamp(20px, calc(var(--board) / 15), 32px);
  line-height: 1;
  overflow: hidden;
}
.flap::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 1px;
  background: var(--ak-ink);
}
.flap.is-blank { color: transparent; }

/* ---------- board ---------- */

.board-wrap {
  grid-area: board;
  position: relative;
  width: var(--board);
  height: var(--board);
  justify-self: center;
}

/* faint blue column guides along the top edge, as on a layout sheet */
.board-wrap::before {
  content: "";
  position: absolute;
  left: var(--frame);
  right: var(--frame);
  top: -7px;
  height: 6px;
  background-image: repeating-linear-gradient(
    90deg,
    transparent 0,
    transparent calc(var(--cell) - 2px),
    color-mix(in srgb, var(--ak-accent) 55%, transparent) calc(var(--cell) - 2px),
    color-mix(in srgb, var(--ak-accent) 55%, transparent) var(--cell)
  );
}

.board {
  position: absolute;
  inset: 0;
  border: var(--frame) solid var(--ak-ink);
  background: var(--ak-bg);
  touch-action: none;
  outline: none;
  cursor: crosshair;
}
.board:focus-visible { box-shadow: 0 0 0 3px var(--ak-bg), 0 0 0 6px var(--ak-focus); }

.cells,
.pieces {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-columns: repeat(var(--n), 1fr);
  grid-template-rows: repeat(var(--n), 1fr);
}

.cell {
  position: relative;
  border-right: 1px solid color-mix(in srgb, var(--ak-ink) 55%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--ak-ink) 55%, transparent);
  /* one cell of the painted layout sheet, as newsprint for every square */
  background-image: url("art/layout-grid.png");
  background-size: calc(384 / 60 * 100%) calc(384 / 58 * 100%);
  background-position: calc(94 / 324 * 100%) calc(109 / 326 * 100%);
}
.cell.is-last-col { border-right: 0; }
.cell.is-last-row { border-bottom: 0; }

/* the pencil X: copy marked for the spike */
.cell::after {
  content: "";
  position: absolute;
  inset: 26%;
  background:
    linear-gradient(45deg, transparent calc(50% - 0.75px), var(--x-ink) calc(50% - 0.75px), var(--x-ink) calc(50% + 0.75px), transparent calc(50% + 0.75px)),
    linear-gradient(-45deg, transparent calc(50% - 0.75px), var(--x-ink) calc(50% - 0.75px), var(--x-ink) calc(50% + 0.75px), transparent calc(50% + 0.75px));
  --x-ink: color-mix(in srgb, var(--ak-ink-muted) 22%, transparent);
}
.cell.is-filled::after,
.cell.is-end::after { display: none; }

/* a failed check marks every empty square plainly */
.cell.is-gap { box-shadow: inset 0 0 0 3px var(--ak-accent); }
.cell.is-gap::after {
  inset: 22%;
  --x-ink: var(--ak-accent);
  background:
    linear-gradient(45deg, transparent calc(50% - 2px), var(--x-ink) calc(50% - 2px), var(--x-ink) calc(50% + 2px), transparent calc(50% + 2px)),
    linear-gradient(-45deg, transparent calc(50% - 2px), var(--x-ink) calc(50% - 2px), var(--x-ink) calc(50% + 2px), transparent calc(50% + 2px));
}

/* every pair joined but squares left over: show where they are */
.cell.is-hole { box-shadow: inset 0 0 0 3px var(--ak-accent); }
.cell.is-hole::after { --x-ink: var(--ak-accent); }

/* a press on an empty square: marked plainly until the next move */
.cell.is-reject { box-shadow: inset 0 0 0 3px var(--ak-ink); }
.cell.is-reject::after {
  inset: 18%;
  --x-ink: var(--ak-ink);
  background:
    linear-gradient(45deg, transparent calc(50% - 2px), var(--x-ink) calc(50% - 2px), var(--x-ink) calc(50% + 2px), transparent calc(50% + 2px)),
    linear-gradient(-45deg, transparent calc(50% - 2px), var(--x-ink) calc(50% - 2px), var(--x-ink) calc(50% + 2px), transparent calc(50% + 2px));
}

.cell.is-cursor { box-shadow: inset 0 0 0 3px var(--ak-ink); }
.board:not(:focus-visible) .cell.is-cursor { box-shadow: none; }
.cell.is-gap.is-cursor { box-shadow: inset 0 0 0 3px var(--ak-accent), inset 0 0 0 6px var(--ak-ink); }

.lines,
.guide {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}

.pieces { pointer-events: none; }

/* transit-map strokes, drawn in cell units */
.lines path {
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.lines .route.is-faded { opacity: 0.25; }
.lines .l-ink { stroke: var(--ak-ink); }
.lines .l-bg { stroke: var(--ak-bg); }
.lines .l-fill-ink { fill: var(--ak-ink); }
.lines .spark {
  stroke: var(--ak-bg);
  stroke-linecap: butt;
  opacity: 0;
}
.lines .end-cap .cap-ring {
  fill: var(--ak-bg);
  stroke: var(--ak-ink);
}
.lines .end-cap .cap-dot { stroke: var(--ak-ink); }
.lines .end-cap.is-live .cap-ring { stroke: var(--ak-accent); stroke-width: 0.11; }

.guide path { fill: none; stroke-linecap: butt; stroke-linejoin: round; }
.guide .arrow-back { stroke: var(--ak-bg); }
.guide .ghost-back { stroke: var(--ak-ink); stroke-linecap: round; stroke-dasharray: 0.07 0.18; }
.guide .ghost { stroke-linecap: round; }
.guide .arrow { stroke: var(--ak-accent); }
.guide .g-head { fill: var(--ak-accent); stroke: none; }

/* ---------- pieces ---------- */

.piece {
  position: relative;
  place-self: center;
  width: 94%;
  height: 94%;
}

.piece .art {
  position: absolute;
  background-repeat: no-repeat;
}

/* inventor: round badge straight from the painted sheet */
.piece.badge .art {
  inset: 0;
  background-image: url("art/inventor-badge.png");
  background-size: calc(384 / 125 * 100%) calc(384 / 124 * 100%);
  border-radius: 50%;
}

/* invention: square plate, thick black border, object from the painted sheet */
.piece.plate {
  background: var(--ak-bg);
  border: max(2px, calc(var(--cell) * 0.06)) solid var(--ak-ink);
}
.piece.plate .art {
  inset: 10%;
  background-image: url("art/invention-plate.png");
}

.piece .num {
  position: absolute;
  display: grid;
  place-items: center;
  min-width: max(20px, calc(var(--cell) * 0.44));
  height: max(20px, calc(var(--cell) * 0.44));
  padding: 0 2px;
  background: var(--ak-accent-2);
  color: var(--ak-btn-ink);
  font-family: var(--ak-font-body);
  font-weight: 700;
  font-size: max(16px, calc(var(--cell) * 0.34));
  line-height: 1;
  border-bottom: 3px solid var(--route);
}
.piece.badge .num {
  left: 50%;
  bottom: -4%;
  transform: translateX(-50%);
}
.piece.plate .num {
  left: -2px;
  top: -2px;
}

/* a pointed-at piece: the ring sits around it, never on its face */
.piece.is-flag::before {
  content: "";
  position: absolute;
  inset: -6%;
  border: 3px dashed var(--ak-accent);
}
.piece.badge.is-flag::before { border-radius: 50%; }

/* the line in hand: where it began, and the piece it is heading for */
.piece.is-source::after,
.piece.is-target::after {
  content: "";
  position: absolute;
  inset: -7%;
  pointer-events: none;
}
.piece.is-source::after { border: 3px solid var(--ak-ink); }
.piece.is-target::after {
  border: 4px solid var(--ak-accent);
  box-shadow: 0 0 0 2px var(--ak-bg);
}
.piece.badge.is-source::after,
.piece.badge.is-target::after { border-radius: 50%; }

.guide .finger {
  fill: var(--ak-accent);
  stroke: var(--ak-bg);
}

/* ---------- note (guide caption, wrong-move message, check result) ---------- */

.note {
  grid-area: note;
  margin: 0;
  min-height: 52px;
  padding: 8px 12px;
  display: flex;
  align-items: center;
  background: var(--ak-surface);
  border-left: 6px solid var(--ak-accent);
  color: var(--ak-ink);
  font-size: 18px;
  font-weight: 600;
  line-height: 1.3;
}
.note.is-warn { border-left-color: var(--ak-ink); }
.note.is-warn::before {
  content: "!";
  flex: none;
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  margin-right: 10px;
  background: var(--ak-ink);
  color: var(--ak-bg);
  font-weight: 700;
}
.note .note-body { display: flex; flex-direction: column; gap: 4px; }
/* the personal next step after a near miss: this board, this inventor */
.note .note-next {
  padding-top: 4px;
  border-top: 2px solid var(--ak-ink);
  font-weight: 700;
}
/* while it shows, the route list steps aside to give it room */
.stage.is-checked .directory { display: none; }

.note.is-quiet {
  font-weight: 400;
  color: var(--ak-ink-muted);
  font-size: 16px;
}

/* ---------- sign buttons ---------- */

.actions {
  grid-area: actions;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  container-type: inline-size;
}
.actions .sign-btn { flex: 1 1 56px; }
/* in a narrow column the check button wraps onto its own full-width row */
.actions .sign-btn.is-go { flex: 1 1 140px; }
.actions .sign-btn:not(.is-go) { padding: 0 6px; }
.actions .sign-btn:not(.is-go) svg { display: none; }
@container (min-width: 420px) {
  .actions .sign-btn:not(.is-go) svg { display: block; }
}

.sign-btn {
  min-height: 48px;
  padding: 0 10px;
  border: 0;
  border-radius: 0;
  background: var(--ak-accent-2);
  color: var(--ak-btn-ink);
  font-family: var(--ak-font-body);
  font-size: 16px;
  font-weight: 700;
  letter-spacing: 0.01em;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  cursor: pointer;
  touch-action: manipulation;
  white-space: nowrap;
}
.sign-btn svg {
  flex: none;
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.4;
  stroke-linecap: square;
  stroke-linejoin: miter;
}
.sign-btn.is-go {
  white-space: normal;
  text-align: left;
  line-height: 1.1;
  background: var(--ak-btn-fill);
  justify-content: space-between;
  padding: 0 12px;
  border-top: 4px solid var(--ak-accent-2);
}
.sign-btn:active { background: var(--ak-btn-active); }
.sign-btn:disabled {
  /* an unlit sign: still plainly readable, clearly not the one to press */
  background: var(--ak-surface);
  color: var(--ak-ink-muted);
  box-shadow: inset 0 0 0 2px var(--ak-ink-muted);
  cursor: default;
}
@media (hover: hover) {
  .sign-btn:not(:disabled):hover { background: var(--ak-btn-hover); }
}
.sign-btn.is-flag { outline: 3px dashed var(--ak-accent); outline-offset: 3px; }

/* ---------- result: a sign plate that flips down ---------- */

.result {
  grid-row: note-start / actions-end;
  grid-column: note;
  background: var(--ak-bg);
  border: var(--frame) solid var(--ak-ink);
  transform-origin: top center;
}
.result-head {
  margin: 0;
  padding: 6px 12px;
  background: var(--ak-accent-2);
  color: var(--ak-btn-ink);
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  border-bottom: 4px solid var(--ak-accent);
}
.result-says {
  margin: 0;
  padding: 10px 12px 2px;
  font-family: var(--ak-font-display);
  font-weight: 700;
  font-size: 20px;
  line-height: 1.25;
  color: var(--ak-ink);
}
.result-clip {
  margin: 0;
  padding: 6px 12px 2px;
  font-size: 15px;
  line-height: 1.3;
  color: var(--ak-ink);
}
.clip-head {
  display: block;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ak-accent);
}
.result-sub {
  margin: 0;
  padding: 2px 12px 10px;
  font-size: 15px;
  color: var(--ak-ink-muted);
}
.result-actions {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4px;
  padding: 0 8px 8px;
}

/* ---------- rules strip: what a solve needs, counted live ---------- */

.rules {
  grid-area: rules;
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 4px;
}
.rule {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 32px;
  padding: 2px 6px;
  background: var(--ak-bg);
  border: 2px solid var(--ak-ink);
  color: var(--ak-ink);
  font-size: 15px;
  font-weight: 700;
  line-height: 1.1;
  text-align: center;
}
.rule svg {
  flex: none;
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
}
.rule.is-done {
  background: var(--ak-accent-2);
  color: var(--ak-btn-ink);
}
#ruleCross.is-done {
  background: var(--ak-bg);
  color: var(--ak-ink);
}
.stage.is-result .rules { display: none; }

/* ---------- route directory ---------- */

.directory {
  grid-area: dir;
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: 8px;
  border-top: var(--rule) solid var(--ak-ink);
  container-type: inline-size;
}
@container (max-width: 320px) {
  .directory .route-row { grid-template-columns: 24px minmax(0, 1fr) 16px; }
  .directory .route-row .swatch { display: none; }
}
.route-row {
  display: grid;
  grid-template-columns: 24px 34px minmax(0, 1fr) 16px;
  align-items: center;
  gap: 6px;
  height: 34px;
  border-bottom: 1px solid color-mix(in srgb, var(--ak-ink) 35%, transparent);
  background: color-mix(in srgb, var(--ak-bg) 92%, transparent);
  padding-right: 4px;
}
.route-row .tag {
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  background: var(--ak-accent-2);
  color: var(--ak-btn-ink);
  font-weight: 700;
  font-size: 14px;
}
.route-row .swatch {
  width: 34px;
  height: 11px;
  background-image: url("art/route-line.png");
  background-repeat: no-repeat;
}
.route-row .names {
  min-width: 0;
  display: flex;
  flex-direction: column;
  line-height: 1.1;
}
.route-row .who {
  font-size: 14px;
  font-weight: 700;
  color: var(--ak-ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.route-row .what {
  font-size: 13px;
  color: var(--ak-ink-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.route-row .state {
  width: 16px;
  height: 16px;
  fill: none;
  stroke: var(--ak-ink);
  stroke-width: 2.6;
  stroke-linecap: square;
  visibility: hidden;
}
.route-row.is-joined .state { visibility: visible; }
.route-row.is-short { box-shadow: inset 4px 0 0 var(--ak-accent); }
.route-row.is-short .who { color: var(--ak-accent); }

/* ---------- small screens ---------- */

.stage[data-routes="7"] { --chrome-portrait: 452px; }
/* a shorter phone held upright: tighter rows, names only in the route list */
@media (orientation: portrait) and (max-height: 800px) {
  .stage, .stage[data-routes="7"] { --chrome-portrait: 394px; row-gap: 6px; }
  .directory { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .directory .route-row { height: 28px; grid-template-columns: 24px minmax(0, 1fr) 16px; }
  .route-row .swatch,
  .route-row .what { display: none; }
  .result-says { font-size: 18px; padding-top: 6px; }
  .result-clip { font-size: 14px; padding-top: 4px; }
  .result-sub { font-size: 14px; padding-bottom: 6px; }
}
.stage.is-result .directory { display: none; }

@media (orientation: portrait) and (max-height: 700px) {
  .stage, .stage[data-routes="7"] { --chrome-portrait: 312px; }
  .result-says { font-size: 17px; }
  .directory { display: none; }
}

/* ---------- landscape: board to one side, sign and controls to the other ---------- */

@media (orientation: landscape) {
  .stage {
    --board: min(
      calc(100vh - 8px - var(--safe-t) - var(--safe-b)),
      calc(100vw - 324px - var(--safe-l) - var(--safe-r)),
      720px
    );
    --board: min(
      calc(100dvh - 8px - var(--safe-t) - var(--safe-b)),
      calc(100dvw - 324px - var(--safe-l) - var(--safe-r)),
      720px
    );
    --panel: clamp(232px, calc(100dvw - var(--board) - 86px - var(--safe-l) - var(--safe-r)), 420px);
  }

  .stage {
    grid-template-columns: var(--panel) var(--board);
    grid-template-rows: minmax(0, 1fr) auto auto auto auto auto auto minmax(0, 1fr);
    grid-template-areas:
      ". board"
      "top board"
      "sign board"
      "rules board"
      "note board"
      "actions board"
      "dir board"
      ". board";
    column-gap: 10px;
    align-content: center;
    height: 100vh;
    height: 100dvh;
    padding-top: calc(4px + var(--safe-t));
    padding-bottom: calc(4px + var(--safe-b));
    padding-right: calc(68px + var(--safe-r));
    padding-left: calc(8px + var(--safe-l));
  }

  .board-wrap {
    grid-row: 1 / -1;
    align-self: center;
  }

  .top {
    grid-template-columns: 48px 1fr;
    column-gap: 12px;
    height: 48px;
  }
  .logo { justify-self: start; height: 36px; }
  .sign { justify-self: start; }
  .flap {
    width: clamp(28px, calc(var(--panel) / 9), 44px);
    height: clamp(34px, calc(var(--panel) / 7.5), 52px);
    font-size: clamp(20px, calc(var(--panel) / 14), 30px);
  }
  .note { min-height: 48px; }
  .directory { align-self: start; }
}

@media (orientation: landscape) and (max-height: 420px) {
  .stage { row-gap: 6px; }
  .top { height: 44px; }
  .logo { height: 32px; }
  .flap { height: 34px; font-size: 22px; }
  .note { font-size: 18px; padding: 6px 10px; }
  .directory { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .directory .route-row { height: 28px; grid-template-columns: 24px minmax(0, 1fr) 16px; }
  .directory .route-row .swatch { display: none; }
  .route-row .who { font-size: 15px; }
  .rule { min-height: 30px; font-size: 14px; padding: 0 6px; }
  .result-clip { font-size: 14px; padding-top: 4px; }
  .route-row .what { display: none; }
  .result-says { font-size: 18px; padding-top: 6px; }
  .result-sub { padding-bottom: 6px; }
}

/* a narrow phone on its side: the board gets the room, the name list steps aside */
@media (orientation: landscape) and (max-height: 420px) and (max-width: 760px) {
  .directory { display: none; }
  /* a narrow column after a near miss: the caption already says what the strip counts */
  .stage.is-checked .rules { display: none; }
  .stage.is-checked .note { font-size: 16px; line-height: 1.25; padding: 6px 8px; }
  .result-head { padding: 4px 10px; font-size: 12px; }
  .result-says { font-size: 16px; padding: 4px 10px 0; }
  .result-clip { font-size: 13px; padding: 4px 10px 0; }
  .result-sub { font-size: 13px; padding: 2px 10px 6px; }
  .result-actions .sign-btn { white-space: normal; line-height: 1.1; text-align: left; }
}

/* ---------- motion ---------- */

@media (prefers-reduced-motion: no-preference) {
  .flap.is-flipping { animation: flap 90ms linear; }

  .piece.is-thunk { animation: thunk 260ms cubic-bezier(0.3, 1.4, 0.5, 1); }
  .piece.is-settle { animation: settle 340ms cubic-bezier(0.3, 1.4, 0.5, 1) both; }
  .piece.is-flag::before { animation: ring-pulse 1100ms ease-in-out infinite; }
  .piece.is-target::after { animation: ring-scale 900ms ease-in-out infinite; }
  .sign-btn.is-flag { animation: btn-pulse 1100ms ease-in-out infinite; }
  .guide .ghost,
  .guide .ghost-back { animation: dash-run 900ms linear infinite; }

  .route { transition: opacity 140ms linear; }
  .lines.is-dim .route { opacity: 0.35; }
  .lines.is-dim .route.is-lit { opacity: 1; }
  .route.is-lit .spark { animation: spark 700ms ease-out both; }

  .seg-new { animation: snap 120ms ease-out; }

  .result.is-flip { animation: plate-flip 320ms cubic-bezier(0.2, 0.9, 0.3, 1.2) both; }
  .note.is-new { animation: slide-in 180ms ease-out; }
  .end-cap.is-live .cap-ring { animation: ring-scale 900ms ease-in-out infinite; transform-box: fill-box; transform-origin: center; }
  .guide .ring { animation: ring-scale 1100ms ease-in-out infinite; transform-box: fill-box; transform-origin: center; }
  .guide .arrow { animation: dash-run 900ms linear infinite; }
}

@keyframes flap {
  0% { transform: scaleY(1); }
  50% { transform: scaleY(0.05); }
  100% { transform: scaleY(1); }
}
@keyframes thunk {
  0% { transform: scale(1.14); }
  60% { transform: scale(0.95); }
  100% { transform: scale(1); }
}
@keyframes settle {
  0% { transform: translateY(-8%); }
  70% { transform: translateY(2%); }
  100% { transform: translateY(0); }
}
@keyframes ring-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.45; }
}
@keyframes btn-pulse {
  0%, 100% { outline-offset: 3px; }
  50% { outline-offset: 6px; }
}
@keyframes spark {
  from { stroke-dashoffset: 0.2; opacity: 1; }
  to { stroke-dashoffset: -1; opacity: 1; }
}
@keyframes snap {
  from { opacity: 0.4; }
  to { opacity: 1; }
}
@keyframes plate-flip {
  from { transform: scaleY(0); }
  to { transform: scaleY(1); }
}
@keyframes slide-in {
  from { transform: translateX(-10px); }
  to { transform: translateX(0); }
}
@keyframes head-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}
@keyframes ring-scale {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.08); }
}
@keyframes dash-run {
  to { stroke-dashoffset: -0.5; }
}

/* ---------- sideways with room to spare: a station board, not a squeezed stack ----------
   The sign runs across the top of the control side; under it the three rules read down
   like a departures list, beside a block of four sign buttons; the caption and route list
   sit underneath. The board keeps the whole height on its own side. */
@media (orientation: landscape) and (min-width: 761px) {
  .stage {
    --panel: clamp(232px, calc(100dvw - var(--board) - 94px - var(--safe-l) - var(--safe-r)), 420px);
    grid-template-columns:
      calc((var(--panel) - 8px) * 0.46)
      calc((var(--panel) - 8px) * 0.54)
      var(--board);
    grid-template-rows: minmax(0, 1fr) auto auto auto auto auto minmax(0, 1fr);
    grid-template-areas:
      ". . board"
      "top top board"
      "sign sign board"
      "rules actions board"
      "note note board"
      "dir dir board"
      ". . board";
    column-gap: 8px;
  }
  .board-wrap { margin-left: 2px; }
  .rules {
    grid-template-columns: 1fr;
    grid-auto-rows: 1fr;
    align-content: stretch;
    gap: 4px;
  }
  .rules .rule {
    justify-content: flex-start;
    text-align: left;
    padding: 2px 10px;
    border-width: 0 0 0 6px;
    background: var(--ak-surface);
  }
  .rules .rule.is-done {
    background: var(--ak-accent-2);
    border-left-color: var(--ak-accent);
  }
  .rules #ruleCross.is-done {
    background: var(--ak-surface);
    border-left-color: var(--ak-ink);
  }
  .actions {
    display: grid;
    grid-template-columns: 1fr 1fr;
    grid-auto-rows: minmax(48px, 1fr);
    gap: 4px;
  }
  .actions .sign-btn { min-height: 48px; }
  .actions .sign-btn.is-go {
    grid-column: auto;
    padding: 0 8px;
    font-size: 15px;
  }
  .result {
    grid-row: rules-start / note-end;
    grid-column: rules-start / actions-end;
  }
}

/* ---------- the opening screen (built by start.js; styled here, never replaced) ---------- */

/* the first move comes straight after the title, so the floating Play button can never cover it */
@media (orientation: portrait) {
  #activity-start#activity-start.is-instructions .ak-sheet {
    display: flex;
    flex-direction: column;
  }
  #activity-start#activity-start.is-instructions .ak-head { order: 0; }
  #activity-start#activity-start.is-instructions .ak-first {
    order: 1;
    margin-top: var(--ak-space-5);
  }
  #activity-start#activity-start.is-instructions .ak-howto {
    order: 2;
    gap: var(--ak-space-5);
    margin-top: var(--ak-space-5);
  }
  #activity-start#activity-start.is-instructions .ak-go {
    order: 3;
    align-self: center;
  }
  #activity-start#activity-start.is-instructions .ak-body { line-height: 1.45; }
  #activity-start#activity-start.is-instructions .ak-section:not(:last-child)::after {
    bottom: calc(-1 * var(--ak-space-5));
  }
}

/* stronger ink on the small print */
#activity-start#activity-start .ak-tagline {
  color: var(--ak-ink);
  font-weight: 600;
}
#activity-start#activity-start .ak-label,
#activity-start#activity-start .ak-first-label {
  color: var(--ak-ink);
}
#activity-start#activity-start .ak-section:not(:last-child)::after {
  background: var(--ak-accent);
}
