/* Treasure Hunters.
 *
 * The field is deep water and card-table felt at once; the hardware is brass, because the
 * physical game moves yellow chips up four printed tracks. Everything numeric is set in a
 * monospace face with tabular figures: this is a game where the number on the card IS the
 * rule, and the columns should line up like a ship's log.
 *
 * No web fonts, no external requests of any kind - the game must play with the internet
 * unplugged (docs/07-delivery.md).
 */

:root {
  --abyss: #071a24;
  --fathom: #0e2e3b;
  --brine: #1b4a5a;
  --brass: #c9922e;
  --brass-dim: #6b4f1c;
  --bone: #e8e2d3;
  --blood: #a8322d;
  --verdigris: #4fa88b;

  --ink-1: var(--bone);
  --ink-2: #9db2bb;
  --ink-3: #5d7883;

  --font-display: Georgia, "Iowan Old Style", "Palatino Linotype", "Book Antiqua", serif;
  --font-ui: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
  --font-data: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;

  --gap: clamp(0.75rem, 1.4vw, 1.25rem);
  --radius: 3px;
  --rule: 1px solid var(--brine);

  /* The card in play and the empty slot it leaves behind have to agree, or the
     table jumps every time a card is drawn. Sized so the illustration band has
     room to read as a picture rather than a stripe. */
  --card-w: clamp(14rem, 60vw, 20rem);
}

* {
  box-sizing: border-box;
}

/* A class with a display rule outranks the UA [hidden] rule, which silently resurrects
   anything toggled with .hidden = true. Settle it once, here. */
[hidden] {
  display: none !important;
}

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

body {
  background: var(--abyss);
  background-image: radial-gradient(ellipse at 50% -10%, #10394a 0%, var(--abyss) 62%);
  color: var(--ink-1);
  font-family: var(--font-ui);
  font-size: clamp(14px, 0.5vw + 12px, 16px);
  line-height: 1.5;
  -webkit-text-size-adjust: 100%;
}

h1,
h2 {
  margin: 0;
  font-weight: 400;
}

/* ---------------------------------------------------------------- masthead */

.app {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}

.masthead {
  display: flex;
  align-items: baseline;
  gap: var(--gap);
  padding: 0.7rem clamp(0.75rem, 2vw, 1.5rem);
  border-bottom: var(--rule);
  background: linear-gradient(180deg, rgba(14, 46, 59, 0.9), transparent);
}

.wordmark {
  font-family: var(--font-display);
  font-size: clamp(1.05rem, 1.6vw, 1.4rem);
  letter-spacing: 0.02em;
  color: var(--bone);
  white-space: nowrap;
}

.wordmark--large {
  font-size: clamp(2rem, 6vw, 3.25rem);
  line-height: 1.05;
  margin-bottom: 0.4rem;
}

.tally {
  display: flex;
  gap: 1.25rem;
  font-family: var(--font-data);
  font-size: 0.72rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.tally b {
  font-weight: 400;
  color: var(--ink-2);
}

.pips {
  letter-spacing: 0.18em;
  margin-left: 0.4rem;
}

.pips--won {
  color: var(--brass);
}

.pips--lost {
  color: var(--blood);
}

.masthead-meta {
  margin-left: auto;
  font-family: var(--font-data);
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
  text-align: right;
}

/* ------------------------------------------------------------------ layout */

.layout {
  flex: 1;
  display: grid;
  grid-template-columns: minmax(15rem, 17rem) minmax(0, 1fr) minmax(15rem, 19rem);
  gap: var(--gap);
  padding: var(--gap);
  align-items: stretch;
}

.rail {
  display: flex;
  flex-direction: column;
  align-content: flex-start;
  gap: var(--gap);
  min-width: 0;
}

.rail > .panel {
  flex: 0 0 auto;
}

.panel {
  background: linear-gradient(180deg, rgba(27, 74, 90, 0.22), rgba(7, 26, 36, 0.4));
  border: var(--rule);
  border-radius: var(--radius);
  padding: 0.85rem 0.9rem 1rem;
  min-width: 0;
}

.panel-title {
  font-family: var(--font-data);
  font-size: 0.66rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 0.7rem;
}

.hint {
  margin: -0.35rem 0 0.7rem;
  font-size: 0.76rem;
  color: var(--ink-3);
  min-height: 1.1em;
}

/* --------------------------------------------------- health: 21 real ticks */

/* The printed tracker runs 21 down to 0, so the meter is 21 discrete marks that go
   out one at a time - not a percentage bar. */
.meter {
  display: flex;
  gap: 2px;
  height: 2.1rem;
  align-items: stretch;
}

.tick {
  flex: 1;
  border-radius: 1px;
  background: #0b2330;
  box-shadow: inset 0 0 0 1px rgba(27, 74, 90, 0.55);
  transition: background 220ms ease, box-shadow 220ms ease;
}

.tick.lit {
  background: linear-gradient(180deg, var(--verdigris), #2f7a63);
  box-shadow: none;
}

.meter.low .tick.lit {
  background: linear-gradient(180deg, #d05149, var(--blood));
}

.meter.critical .tick.lit {
  animation: pulse 1.4s ease-in-out infinite;
}

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

.meter-read {
  margin: 0.5rem 0 0;
  font-family: var(--font-data);
  font-size: 1.6rem;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

.meter-of {
  font-size: 0.8rem;
  color: var(--ink-3);
  margin-left: 0.15rem;
}

/* ------------------------------------------- the signature: upgrade tracks */

.board {
  display: grid;
  /* minmax(0,...) rather than 1fr: a grid track will not shrink below its min-content
     width by default, so the longest upgrade note pushed the Guile column out through
     the side of the panel. */
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0.45rem;
}

.track {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.3rem;
  padding: 0.4rem 0.25rem 0.3rem;
  border: 1px solid transparent;
  border-radius: var(--radius);
  background: rgba(7, 26, 36, 0.5);
}

.track.pickable {
  cursor: pointer;
  border-color: var(--brass);
  background: rgba(201, 146, 46, 0.1);
}

.track.pickable:hover,
.track.pickable:focus-visible {
  background: rgba(201, 146, 46, 0.2);
}

.track.chosen {
  border-color: var(--verdigris);
  background: rgba(79, 168, 139, 0.14);
}

.rungs {
  display: flex;
  flex-direction: column-reverse;
  gap: 3px;
}

.rung {
  height: 1.35rem;
  border-radius: 1px;
  background: #0b2330;
  box-shadow: inset 0 0 0 1px rgba(27, 74, 90, 0.5);
  display: grid;
  place-items: center;
  font-family: var(--font-data);
  font-size: 0.58rem;
  color: var(--ink-3);
  transition: transform 260ms cubic-bezier(0.34, 1.4, 0.64, 1), background 200ms ease;
}

.rung.held {
  /* the brass chip */
  background: linear-gradient(180deg, #e8b455, var(--brass) 55%, #8f6318);
  color: #2a1c05;
  font-weight: 700;
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.35);
}

.rung.below {
  background: var(--brass-dim);
  box-shadow: none;
}

.rung.base {
  height: 0.5rem;
  background: #0a1f2a;
  box-shadow: inset 0 0 0 1px rgba(27, 74, 90, 0.35);
  font-size: 0;
}

.rung.base.held {
  height: 1.35rem;
  font-size: 0.58rem;
}

.track-name {
  font-family: var(--font-data);
  font-size: 0.58rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-align: center;
  color: var(--ink-2);
}

.track-note {
  font-size: 0.6rem;
  text-align: center;
  color: var(--ink-3);
  min-height: 2.2em;
  line-height: 1.25;
}

.abilities {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  margin-top: 0.6rem;
}

.ability {
  font-family: var(--font-data);
  font-size: 0.58rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 0.12rem 0.34rem;
  border: 1px solid var(--brine);
  border-radius: 2px;
  color: var(--ink-3);
}

.ability.on {
  border-color: var(--brass);
  color: var(--brass);
}

.ability.spent {
  border-color: var(--blood);
  color: var(--blood);
  text-decoration: line-through;
}

/* ------------------------------------------------------------- the table */

.table {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--gap);
  min-width: 0;
  padding: 0.25rem 0 1rem;
}

.piles {
  display: flex;
  gap: clamp(1rem, 4vw, 2.5rem);
}

.pile {
  appearance: none;
  font: inherit;
  color: inherit;
  width: clamp(4.5rem, 9vw, 6rem);
  padding: 0;
  border: none;
  background: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
  cursor: default;
}

.pile-back {
  position: relative;
  width: 100%;
  aspect-ratio: 4 / 5;
  border-radius: var(--radius);
  border: 1px solid var(--brine);
  background:
    repeating-linear-gradient(135deg, rgba(27, 74, 90, 0.55) 0 6px, transparent 6px 12px),
    linear-gradient(180deg, #123443, #0a222d);
  display: grid;
  place-items: center;
  font-family: var(--font-data);
  font-size: 1.1rem;
  color: var(--ink-2);
  transition: transform 160ms ease, border-color 160ms ease, box-shadow 160ms ease;
}

/* With the art installed the painted back IS the pile, so the placeholder weave and
   its border get out of the way. */
.has-art .pile-back {
  border-color: transparent;
  background: none;
}

.pile-face {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  border-radius: var(--radius);
}

/* The count reads over the medallion, so it carries its own plate. */
.pile-count {
  position: relative;
  z-index: 1;
}

.has-art .pile-count {
  padding: 0.05em 0.45em;
  border-radius: 999px;
  background: rgba(7, 26, 36, 0.72);
  box-shadow: inset 0 0 0 1px rgba(201, 146, 46, 0.5);
  color: var(--bone);
}

.pile[data-live="1"] {
  cursor: pointer;
}

.pile[data-live="1"] .pile-back {
  border-color: var(--brass);
  box-shadow: 0 0 0 1px rgba(201, 146, 46, 0.35), 0 8px 22px -12px rgba(201, 146, 46, 0.7);
}

.pile[data-live="1"]:hover .pile-back,
.pile[data-live="1"]:focus-visible .pile-back {
  transform: translateY(-5px);
}

.pile-empty .pile-back {
  opacity: 0.35;
  border-style: dashed;
}

.pile-name {
  font-family: var(--font-data);
  font-size: 0.6rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* -------------------------------------------------------------- the card */

.stage {
  display: flex;
  align-items: center;
  gap: var(--gap);
  min-height: calc(var(--card-w) * 5 / 4);
}

.card {
  width: var(--card-w);
  aspect-ratio: 4 / 5;
  border-radius: 5px;
  border: 1px solid #cfc6b0;
  background: linear-gradient(175deg, #f5f1e6, #ddd5c2);
  color: #1d2a30;
  display: flex;
  flex-direction: column;
  padding: 0.55rem 0.6rem;
  box-shadow: 0 18px 34px -18px rgba(0, 0, 0, 0.85);
  animation: deal 300ms cubic-bezier(0.2, 0.9, 0.3, 1.2);
}

/* ------------------------------------------------------- the dressed card face
 *
 * Three layers: illustration, frame, live text. The frames were painted at 1600x2000
 * with the sockets in fixed places, so every position below is a percentage measured
 * off those masters - the card can be any size and the rank still lands in its socket.
 *
 * Text is sized in cqw (percent of the card's own width) rather than rem, for the same
 * reason: one set of numbers that holds from a phone to a projector.
 */

.card--dressed {
  position: relative;
  container-type: inline-size;
  width: var(--card-w);
  /* The illustrations, the frames and the back are all 4:5. */
  aspect-ratio: 4 / 5;
  display: block;
  padding: 0;
  border: none;
  border-radius: 3.5%;
  background: none;
  color: #f7ead0;
  filter: drop-shadow(0 20px 26px rgba(0, 0, 0, 0.55));
}

.card--dressed .card-illustration,
.card--dressed .card-frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.card--dressed .card-illustration {
  /* Both are 4:5, so this crops nothing - the illustration is seen whole, which is
     what it was composed for. */
  object-fit: cover;
  border-radius: 3.5%;
}

/* `fill` rather than `contain`: the frame must land exactly on the card's edges, and a
   rounding difference of one pixel would float the sockets off their marks. */
.card--dressed .card-frame {
  object-fit: fill;
}

.card-rank {
  position: absolute;
  display: grid;
  place-items: center;
  font-family: var(--font-data);
  font-weight: 700;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  /* The sockets are cut out of the frame, so the rank sits on whatever the artwork is
     doing underneath. Cream with a hard shadow reads over sky and over hull alike. */
  color: #ffeec2;
  text-shadow: 0 0.4cqw 0.8cqw rgba(0, 0, 0, 0.9), 0 0 0.3cqw rgba(0, 0, 0, 0.8);
  background: radial-gradient(
    closest-side,
    rgba(9, 28, 38, 0.88),
    rgba(9, 28, 38, 0.72) 62%,
    rgba(9, 28, 38, 0) 100%
  );
}

.card--enemy .card-rank {
  left: 5.6%;
  top: 5.5%;
  width: 20%;
  height: 16.5%;
  font-size: 9.5cqw;
}

.card--boon .card-rank {
  left: 6.2%;
  top: 6.5%;
  width: 23.8%;
  height: 16%;
  font-size: 8.5cqw;
}

.card--treasure .card-rank {
  left: 6.9%;
  top: 6%;
  width: 26.9%;
  height: 22.5%;
  font-size: 11cqw;
}

/* Three circular sockets down the enemy frame's left rail. */
.card-sockets img {
  position: absolute;
  left: 9.2%;
  width: 12.9%;
  aspect-ratio: 1;
  object-fit: contain;
  filter: drop-shadow(0 0.2cqw 0.4cqw rgba(0, 0, 0, 0.55));
}

.card-sockets img:nth-child(1) {
  top: 30.6%;
}

.card-sockets img:nth-child(2) {
  top: 50.6%;
}

.card-sockets img:nth-child(3) {
  top: 72.1%;
}

/* The torn parchment panel, which is part of the frame painting. */
.card-rules {
  position: absolute;
  margin: 0;
  display: grid;
  place-items: center;
  text-align: center;
  text-wrap: balance;
  line-height: 1.2;
  color: #3d2b12;
  text-shadow: none;
}

.card--enemy .card-rules {
  left: 31%;
  top: 75.5%;
  width: 62%;
  height: 18.5%;
  font-size: 4.4cqw;
}

.card--boon .card-rules {
  left: 10%;
  top: 75.5%;
  width: 79%;
  height: 16%;
  font-size: 4.6cqw;
}

@keyframes deal {
  from {
    transform: translateY(-26px) rotate(-3deg);
    opacity: 0;
  }
}

.card-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  font-family: var(--font-data);
  font-size: 1.5rem;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.card-suit {
  font-size: 1.15rem;
}

.card.red {
  color: var(--blood);
}

.card-art {
  flex: 1;
  /* A flex child floors at its content's size, so without a min-height the illustration
     pushes past the slot it was given and the card crops it by accident. Floored at a
     band rather than 0, so the wordiest card cannot squeeze the picture out entirely. */
  min-height: 3.5rem;
  margin: 0.4rem 0;
  border-radius: 2px;
  background: rgba(29, 42, 48, 0.06);
  /* The slot is sized by the card, never by the picture inside it: pinning the image
     to these edges is what makes that true, since a percentage height would otherwise
     resolve against the illustration's own dimensions and spill. */
  position: relative;
  overflow: hidden;
}

.card-art img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  /* The illustrations are portrait (4:5) and the slot is a wide band, so something
     has to give. Contained, they shrink to a stamp between two empty margins; so
     they fill the band instead, framed a third of the way down - the line that keeps
     every captain's face, both ships and the open chest inside the crop. */
  object-fit: cover;
  object-position: 50% 18%;
}

/* No illustration yet: let the name and rules text take the whole face. */
.card--textonly {
  justify-content: center;
  gap: 0.5rem;
}

.card--textonly .card-name {
  font-size: 0.95rem;
}

.card--textonly .card-text {
  font-size: 0.7rem;
}

.card-name {
  font-family: var(--font-display);
  font-size: 0.78rem;
  text-align: center;
  color: #445159;
  padding: 0 0.2rem;
}

.card-text {
  font-size: 0.63rem;
  line-height: 1.28;
  text-align: center;
  color: #364349;
}

.card-icons {
  display: flex;
  gap: 0.22rem;
  justify-content: center;
  margin-top: 0.35rem;
}

/* Icon glyphs are illustration and belong to the deck's art set. Until those land the
   strip is a data-driven word mark, derived from cards.json exactly like the engine's
   rules are - so a card can never disagree with what beats it (R-13). */
.icon-chip {
  font-family: var(--font-data);
  font-size: 0.5rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  border: 1px solid #a9a08a;
  border-radius: 2px;
  padding: 0.05rem 0.24rem;
  color: #55503f;
}

.stage-empty {
  width: var(--card-w);
  aspect-ratio: 4 / 5;
  border: 1px dashed var(--brine);
  border-radius: 5px;
  display: grid;
  place-items: center;
  text-align: center;
  padding: 1rem;
  color: var(--ink-3);
  font-size: 0.78rem;
}

.stage-roll {
  font-family: var(--font-data);
  text-align: center;
  min-width: 8rem;
}

.roll-die {
  font-size: clamp(2.5rem, 7vw, 3.75rem);
  line-height: 1;
  font-variant-numeric: tabular-nums;
  animation: settle 380ms cubic-bezier(0.2, 1.5, 0.4, 1);
}

@keyframes settle {
  from {
    transform: scale(1.5) rotate(-8deg);
    opacity: 0.2;
  }
}

.roll-sum {
  font-size: 0.72rem;
  color: var(--ink-2);
  margin-top: 0.3rem;
}

.roll-verdict {
  font-size: 0.66rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  margin-top: 0.35rem;
}

.roll-verdict.hit {
  color: var(--verdigris);
}

.roll-verdict.miss {
  color: var(--blood);
}

/* ------------------------------------------------------------- decisions */

.prompt {
  font-family: var(--font-display);
  font-size: clamp(1rem, 2vw, 1.3rem);
  text-align: center;
  min-height: 1.6em;
  color: var(--bone);
}

.prompt em {
  font-style: normal;
  color: var(--brass);
}

.actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.55rem;
  justify-content: center;
  max-width: 44rem;
}

.action {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.22rem;
  max-width: 13rem;
}

.btn {
  appearance: none;
  font-family: var(--font-ui);
  font-size: 0.86rem;
  padding: 0.5rem 0.95rem;
  border-radius: var(--radius);
  border: 1px solid var(--brine);
  background: rgba(27, 74, 90, 0.35);
  color: var(--ink-1);
  cursor: pointer;
  transition: background 140ms ease, border-color 140ms ease, transform 90ms ease;
}

.btn:hover:not(:disabled) {
  background: rgba(27, 74, 90, 0.65);
  border-color: var(--brass);
}

.btn:active:not(:disabled) {
  transform: translateY(1px);
}

.btn:disabled {
  cursor: not-allowed;
  opacity: 0.4;
}

.btn--primary {
  background: linear-gradient(180deg, #e0a63c, var(--brass));
  border-color: #8f6318;
  color: #2a1c05;
  font-weight: 600;
}

.btn--primary:hover:not(:disabled) {
  background: linear-gradient(180deg, #f0b950, var(--brass));
}

.btn--danger {
  border-color: #7a2723;
  color: #eba7a3;
}

.action-reason {
  font-size: 0.64rem;
  line-height: 1.3;
  text-align: center;
  color: var(--ink-3);
}

.tray {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  justify-content: center;
  padding: 0.6rem 0.7rem;
  border: 1px dashed var(--brass);
  border-radius: var(--radius);
  background: rgba(201, 146, 46, 0.07);
}

/* -------------------------------------------------------- card chips/strips */

.chip {
  appearance: none;
  font-family: var(--font-data);
  font-size: 0.82rem;
  font-variant-numeric: tabular-nums;
  padding: 0.28rem 0.5rem;
  min-width: 2.6rem;
  border-radius: 2px;
  border: 1px solid #cfc6b0;
  background: linear-gradient(175deg, #f5f1e6, #ddd5c2);
  color: #1d2a30;
  cursor: default;
}

.chip.red {
  color: var(--blood);
}

button.chip {
  cursor: pointer;
}

button.chip:hover,
button.chip:focus-visible {
  border-color: var(--brass);
  box-shadow: 0 0 0 2px rgba(201, 146, 46, 0.4);
}

.cardstrip {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  max-height: 8.5rem;
  overflow-y: auto;
}

.cardstrip--dim .chip {
  opacity: 0.62;
}

.empty-note {
  font-size: 0.72rem;
  color: var(--ink-3);
  font-style: italic;
}

.haul-read {
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
  font-family: var(--font-data);
}

.haul-total {
  font-size: 2rem;
  line-height: 1;
  color: var(--brass);
  font-variant-numeric: tabular-nums;
}

.haul-goal {
  font-size: 0.7rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.haul-bar {
  height: 4px;
  margin: 0.5rem 0 0.7rem;
  background: #0b2330;
  border-radius: 2px;
  overflow: hidden;
}

.haul-bar span {
  display: block;
  height: 100%;
  background: linear-gradient(90deg, var(--brass-dim), var(--brass));
  transition: width 400ms cubic-bezier(0.2, 0.9, 0.3, 1);
}

/* ----------------------------------------------------------------- the log */

.log {
  list-style: none;
  margin: 0;
  padding: 0;
  max-height: 15rem;
  overflow-y: auto;
  display: flex;
  flex-direction: column-reverse;
  gap: 0.3rem;
  font-size: 0.72rem;
  line-height: 1.35;
}

.log li {
  color: var(--ink-2);
  border-left: 2px solid var(--brine);
  padding-left: 0.5rem;
}

.log li.k-DAMAGE,
.log li.k-STOLEN,
.log li.k-LOSE_ROUND,
.log li.k-MATCH_LOST {
  border-left-color: var(--blood);
}

.log li.k-TREASURE,
.log li.k-CREW_COLLECT,
.log li.k-RECLAIM,
.log li.k-WIN_ROUND,
.log li.k-MATCH_WON,
.log li.k-EVADED,
.log li.k-DEFEATED {
  border-left-color: var(--verdigris);
}

.log li.k-SECOND_CHANCE {
  border-left-color: var(--brass);
  color: var(--brass);
}

.log li.k-ROUND_START {
  border-left-color: var(--brass);
  color: var(--ink-3);
  letter-spacing: 0.04em;
}

/* ------------------------------------------------------------------ seats */

.seats {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: center;
  padding: 0.6rem clamp(0.75rem, 2vw, 1.5rem);
  border-top: var(--rule);
  background: rgba(7, 26, 36, 0.75);
}

.seat {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.25rem 0.6rem;
  border: 1px solid var(--brine);
  border-radius: 999px;
  font-size: 0.78rem;
}

.seat.active {
  border-color: var(--brass);
  color: var(--brass);
}

.seat.you .seat-name {
  text-decoration: underline;
  text-underline-offset: 2px;
}

.seat-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--verdigris);
}

.seat.away .seat-dot {
  background: var(--ink-3);
}

.seat-role {
  font-family: var(--font-data);
  font-size: 0.58rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.takeover-note {
  margin-left: auto;
  font-size: 0.72rem;
  color: var(--brass);
}

/* ------------------------------------------------------------------ veils */

.veil {
  position: fixed;
  inset: 0;
  display: flex;
  justify-content: center;
  padding: var(--gap);
  background: rgba(4, 15, 21, 0.9);
  backdrop-filter: blur(6px);
  z-index: 20;
  overflow-y: auto;
}

.veil > * {
  /* Centres while it fits; keeps both ends reachable once it does not. */
  margin: auto;
  flex: 0 0 auto;
}

.veil[hidden] {
  display: none;
}

.sheet {
  width: min(34rem, 100%);
  background: linear-gradient(180deg, rgba(27, 74, 90, 0.3), rgba(7, 26, 36, 0.7));
  border: var(--rule);
  border-radius: var(--radius);
  padding: clamp(1.25rem, 4vw, 2.25rem);
}

.tagline {
  color: var(--ink-2);
  margin: 0 0 1.5rem;
  font-size: 0.92rem;
  max-width: 30rem;
}

.joinform {
  display: flex;
  gap: 0.5rem;
  align-items: flex-end;
  flex-wrap: wrap;
}

.field {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  flex: 1;
  min-width: 11rem;
}

.field-label {
  font-family: var(--font-data);
  font-size: 0.62rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-3);
}

input[type="text"],
.field input {
  font: inherit;
  padding: 0.5rem 0.6rem;
  border-radius: var(--radius);
  border: 1px solid var(--brine);
  background: rgba(7, 26, 36, 0.8);
  color: var(--ink-1);
}

.field input:focus-visible {
  outline: 2px solid var(--brass);
  outline-offset: 1px;
}

.roster {
  margin-top: 1.4rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

.choose {
  border: none;
  margin: 1.4rem 0 1rem;
  padding: 0;
  display: grid;
  gap: 0.4rem;
}

.pick {
  display: flex;
  gap: 0.6rem;
  align-items: flex-start;
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--brine);
  border-radius: var(--radius);
  cursor: pointer;
}

.pick:has(input:checked) {
  border-color: var(--brass);
  background: rgba(201, 146, 46, 0.09);
}

.pick span {
  display: flex;
  flex-direction: column;
}

.pick em {
  font-style: normal;
  font-size: 0.74rem;
  color: var(--ink-3);
}

.waiting,
.share {
  font-size: 0.78rem;
  color: var(--ink-3);
  margin: 1rem 0 0;
}

.share code {
  font-family: var(--font-data);
  color: var(--brass);
}

.veil--curtain .sheet--curtain {
  text-align: center;
}

/* The map and the coins are the nice-to-have; the button out is not. It stays on screen
   however tall the rest becomes. */
.curtain-actions {
  position: sticky;
  bottom: 0;
  background: linear-gradient(180deg, transparent, rgba(7, 26, 36, 0.92) 35%);
  padding-bottom: 0.4rem;
}

.curtain-eyebrow {
  font-family: var(--font-data);
  font-size: 0.66rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin: 0 0 0.5rem;
}

.curtain-title {
  font-family: var(--font-display);
  font-size: clamp(1.8rem, 6vw, 2.8rem);
  line-height: 1.1;
}

.curtain-title.won {
  color: var(--brass);
}

.curtain-title.lost {
  color: var(--blood);
}

.curtain-body {
  color: var(--ink-2);
  margin: 0.7rem 0 1.4rem;
}

.curtain-actions {
  display: flex;
  gap: 0.5rem;
  justify-content: center;
  flex-wrap: wrap;
}

/* ------------------------------------------------ second chance: the beat */

.flash {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 40;
  opacity: 0;
  background: radial-gradient(circle at 50% 50%, rgba(201, 146, 46, 0.55), transparent 62%);
}

.flash.fire {
  animation: flare 1100ms ease-out;
}

@keyframes flare {
  12% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}

/* ------------------------------------------------------------------ errors */

.err {
  color: #eba7a3;
  font-size: 0.8rem;
}

.err--float {
  position: fixed;
  left: 50%;
  bottom: 1.25rem;
  transform: translateX(-50%);
  z-index: 50;
  margin: 0;
  padding: 0.55rem 0.9rem;
  border: 1px solid #7a2723;
  border-radius: var(--radius);
  background: rgba(38, 12, 11, 0.96);
  max-width: min(30rem, 92vw);
  text-align: center;
}

.err[hidden] {
  display: none;
}

:focus-visible {
  outline: 2px solid var(--brass);
  outline-offset: 2px;
}

/* =========================================================== the art set ===
 *
 * Everything below is reached only when the host has the illustrations installed and
 * the client has set `.has-art` on <body>. Without it the game keeps the typographic
 * table it was built with - which is a real supported state, not a fallback nobody
 * looks at, so nothing here may be load-bearing for legibility or layout.
 */

body.has-art {
  background-image:
    linear-gradient(180deg, rgba(7, 26, 36, 0.82), rgba(7, 26, 36, 0.94)),
    image-set(url('/art/bg-gameplay.webp') 1x);
  background-size: cover;
  background-position: center;
  background-attachment: fixed;
}

/* Portrait phones get the separately composed portrait plate, never a crop of the
   landscape one - the art bible is explicit about it and the compositions differ. */
@media (orientation: portrait) {
  body.has-art {
    background-image:
      linear-gradient(180deg, rgba(7, 26, 36, 0.82), rgba(7, 26, 36, 0.94)),
      image-set(url('/art/bg-gameplay-portrait.webp') 1x);
  }
}

/* -- wordmark becomes the painted logo ----------------------------------- */

.wordmark--art {
  font-size: 0;
  line-height: 0;
}

.wordmark .logo {
  display: block;
  width: auto;
  height: clamp(1.5rem, 2.6vw, 2.1rem);
}

.wordmark--large .logo {
  height: clamp(7rem, 20vw, 13rem);
  margin-inline: auto;
}

/* -- panels become dark wood, cornered in gold --------------------------- */

.has-art .masthead {
  align-items: center;
  border-bottom: none;
  /* The rope divider runs the width of the masthead, seamless in the middle. */
  border-image: url('/art/ui-divider-rope.webp') 0 0 40 0 / 0 0 0.7rem 0 / 0 stretch round;
}

.has-art .panel {
  border: none;
  background: rgba(7, 26, 36, 0.55);
  /* The 9-slice: corners painted, edges tiled, middle filled with the grain. */
  border-image: url('/art/ui-panel-wood.webp') 68 fill / 1rem / 0 round;
  padding: 1rem 1.05rem 1.15rem;
}

/* The upgrade board is the signature panel, so it gets the painted banner. The banner
   is 4:1 and this strip is far wider, so it is cropped to fit rather than stretched -
   squashing the wave ends into ovals is worse than losing them. */
.has-art .panel--board .panel-title {
  position: relative;
  margin: -0.4rem -0.45rem 0.85rem;
  padding: 0.55rem 0.8rem;
  color: #4a3517;
  text-shadow: none;
  border-radius: 2px;
  background: url('/art/ui-header-upgrades.webp') center / cover no-repeat;
}

.has-art .panel--board .title-icon {
  opacity: 1;
  filter: drop-shadow(0 1px 1px rgba(255, 255, 255, 0.5));
}

/* The health strip sits behind the 21 ticks rather than replacing them: the ticks are
   the reading, the plate is the furniture. */
.has-art .panel--health .meter {
  padding: 0.28rem 0.4rem;
  background: url('/art/ui-tracker-health.webp') center / 100% 100% no-repeat;
  height: 2.5rem;
}

/* The ship's-wheel marker, beside the number it marks. */
.health-token {
  width: 1.5rem;
  height: 1.5rem;
  object-fit: contain;
  vertical-align: -0.3rem;
  margin-right: 0.35rem;
}

/* The tray is where the game hands you a choice, so it is parchment, not ship's wood. */
.has-art .tray {
  border: none;
  border-image: url('/art/ui-panel-parchment.webp') 60 fill / 0.85rem / 0 round;
  color: #3d2b12;
  padding: 0.7rem 0.8rem;
}

.has-art .tray .seat-role {
  color: #6a4d1c;
}

/* -- icons beside the panel titles --------------------------------------- */

.panel-title {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

.title-icon {
  width: 1.15rem;
  height: 1.15rem;
  object-fit: contain;
  opacity: 0.85;
}

/* -- the upgrade board: painted chips on painted tracks ------------------ */

.rung {
  position: relative;
}

.rung-token {
  position: absolute;
  inset: 0;
  margin: auto;
  width: auto;
  height: 132%;
  object-fit: contain;
  pointer-events: none;
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.6));
}

/* One painted coin, tinted per track - the way the printed game uses one bag of
   chips for four columns. */
.track[data-track='sails'] .rung-token {
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.6)) hue-rotate(150deg) saturate(0.85);
}

.track[data-track='cannons'] .rung-token {
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.6)) hue-rotate(-35deg) saturate(1.15);
}

.track[data-track='guile'] .rung-token {
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.6)) hue-rotate(255deg) saturate(0.8);
}

.rung-level {
  position: relative;
  z-index: 1;
}

.has-art .rung.held {
  background: #0b2330;
  box-shadow: inset 0 0 0 1px rgba(27, 74, 90, 0.5);
  color: #2a1c05;
}

.track-name {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.25rem;
}

.track-icon {
  width: 1.05rem;
  height: 1.05rem;
  object-fit: contain;
}

.ability {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
}

.ability-icon {
  width: 0.95rem;
  height: 0.95rem;
  object-fit: contain;
  opacity: 0.5;
}

.ability.on .ability-icon {
  opacity: 1;
}

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

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.45rem;
}

.btn-icon {
  width: 1.15rem;
  height: 1.15rem;
  object-fit: contain;
  flex: none;
}

.btn:disabled .btn-icon {
  opacity: 0.45;
  filter: grayscale(0.7);
}

/* -- the round tally, as coins ------------------------------------------ */

.pips--coins {
  display: inline-flex;
  gap: 0.2rem;
  align-items: center;
  letter-spacing: 0;
}

.pips--coins .pip {
  width: 1.05rem;
  height: 1.05rem;
  object-fit: contain;
  opacity: 0.28;
  filter: grayscale(0.85);
  transition: opacity 200ms ease, filter 200ms ease, transform 200ms ease;
}

.pips--coins .pip--taken {
  opacity: 1;
  filter: none;
  transform: scale(1.06);
}

/* -- the die ------------------------------------------------------------- */

.roll-die {
  position: relative;
  display: grid;
  place-items: center;
}

.roll-d12 {
  position: absolute;
  width: 1.55em;
  height: 1.55em;
  object-fit: contain;
  opacity: 0.5;
}

.roll-number {
  position: relative;
  z-index: 1;
  text-shadow: 0 2px 8px rgba(7, 26, 36, 0.9);
}

/* -- the mats the piles and discards sit on ------------------------------ */

/* The mat is the rope outline the pile sits inside, so the back is inset within it
   rather than covering it. Both are card-shaped, so neither distorts. */
.has-art .pile-back {
  background: url('/art/mat-draw.webp') center / 100% 100% no-repeat;
}

.has-art .pile-face {
  inset: 8%;
}

/* An empty discard pile shows its mat - a card-shaped slot, kept card-shaped. */
.mat-slot {
  width: clamp(4rem, 26%, 5.5rem);
  aspect-ratio: 4 / 5;
  object-fit: contain;
  opacity: 0.75;
  margin-bottom: 0.35rem;
}

/* -- the lobby ----------------------------------------------------------- */

/* The title harbour before you have a seat; the prepared deck once you do. */
.has-art .veil {
  background-image:
    linear-gradient(180deg, rgba(7, 26, 36, 0.5), rgba(7, 26, 36, 0.86)),
    image-set(url('/art/bg-title.webp') 1x);
  background-size: cover;
  background-position: center;
}

.has-art .veil--seated {
  background-image:
    linear-gradient(180deg, rgba(7, 26, 36, 0.5), rgba(7, 26, 36, 0.86)),
    image-set(url('/art/bg-lobby.webp') 1x);
}

@media (orientation: portrait) {
  .has-art .veil {
    background-image:
      linear-gradient(180deg, rgba(7, 26, 36, 0.78), rgba(7, 26, 36, 0.93)),
      image-set(url('/art/bg-title-portrait.webp') 1x);
  }

  .has-art .veil--seated {
    background-image:
      linear-gradient(180deg, rgba(7, 26, 36, 0.78), rgba(7, 26, 36, 0.93)),
      image-set(url('/art/bg-lobby-portrait.webp') 1x);
  }
}

.has-art .sheet:not(.sheet--title) {
  position: relative;
  border: none;
  border-image: url('/art/ui-panel-wood.webp') 68 fill / 1.25rem / 0 round;
}

/* The corner ornament is one painting rotated into all four corners. */
.has-art .sheet:not(.sheet--title)::before,
.has-art .sheet:not(.sheet--title)::after {
  content: '';
  position: absolute;
  width: 3.2rem;
  height: 3.2rem;
  background: url('/art/ui-corner-flourish.webp') center / contain no-repeat;
  pointer-events: none;
  opacity: 0.9;
}

.has-art .sheet:not(.sheet--title)::before {
  top: 0.2rem;
  left: 0.2rem;
}

.has-art .sheet:not(.sheet--title)::after {
  bottom: 0.2rem;
  right: 0.2rem;
  transform: rotate(180deg);
}

.lobby-captain:empty {
  display: none;
}

.captain-full {
  display: block;
  width: auto;
  height: clamp(12rem, 52vh, 26rem);
  margin: 0 auto;
  object-fit: contain;
  filter: drop-shadow(0 12px 18px rgba(0, 0, 0, 0.55));
}

.pick .badge {
  width: 4.4rem;
  height: auto;
  object-fit: contain;
  flex: none;
  margin-right: 0.15rem;
}

/* -- the title screen ----------------------------------------------------- */

/* The lobby is a title card standing on the painting, not a form inside a box. */
.sheet--title {
  width: min(54rem, 100%);
  background: none;
  border: none;
  padding: clamp(0.75rem, 3vw, 2rem);
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

/* Everything on the title screen sits on artwork, so it carries its own contrast. */
.sheet--title .tagline,
.sheet--title .waiting,
.sheet--title .share,
.sheet--title .field-label {
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.8);
}

.sheet--title .tagline {
  margin: 0 0 1.2rem;
  max-width: 32rem;
}

.sheet--title .joinform,
.sheet--title .choose,
.sheet--title .roster {
  width: 100%;
  justify-content: center;
}

.sheet--title .choose {
  text-align: left;
}

.sheet--title .roster {
  margin-top: 1rem;
}

/* The captain gets the room's empty width instead of its scarce height: standing to
   one side on a landscape screen, above the controls on a phone. */
.title-body {
  display: grid;
  grid-template-columns: auto minmax(20rem, 30rem);
  align-items: center;
  justify-content: center;
  gap: clamp(0.75rem, 3vw, 3rem);
  width: 100%;
}

.title-controls {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-width: 0;
}

@media (max-width: 66rem), (orientation: portrait) {
  .title-body {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.5rem;
  }

  .captain-full {
    height: clamp(8rem, 24vh, 14rem);
  }

  .sheet--title .tagline {
    margin-bottom: 0.6rem;
  }
}

/* -- choosing a captain --------------------------------------------------- */

.crewpick {
  width: 100%;
  margin: 0.2rem 0 1rem;
}

.crewpick .field-label {
  display: block;
  margin-bottom: 0.55rem;
}

.crewpick-row {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0.5rem;
}

.crewtile {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.2rem;
  padding: 0.45rem 0.3rem 0.55rem;
  border: 1px solid var(--brine);
  border-radius: var(--radius);
  background: rgba(7, 26, 36, 0.66);
  color: var(--ink-1);
  font-family: var(--font-ui);
  cursor: pointer;
  transition: background 140ms ease, border-color 140ms ease, transform 90ms ease;
}

.crewtile:hover:not(:disabled) {
  transform: translateY(-2px);
  border-color: var(--brass);
  background: rgba(27, 74, 90, 0.6);
}

.crewtile--mine {
  border-color: var(--brass);
  background: rgba(201, 146, 46, 0.15);
}

/* A captain somebody else is already sailing with: shown, named, and not takeable. */
.crewtile--taken {
  opacity: 0.4;
  cursor: not-allowed;
  filter: grayscale(0.85);
}

.crewtile-face {
  width: 100%;
  max-width: 5.5rem;
  aspect-ratio: 1;
  object-fit: cover;
  object-position: 50% 16%;
  border-radius: 50%;
  background: rgba(4, 15, 21, 0.55);
  box-shadow: 0 0 0 1px rgba(201, 146, 46, 0.35);
}

.crewtile-name {
  font-family: var(--font-display);
  font-size: 0.92rem;
  line-height: 1.2;
}

.crewtile--mine .crewtile-name {
  color: var(--brass);
}

.crewtile-note {
  font-size: 0.66rem;
  color: var(--ink-3);
  line-height: 1.25;
}

/* -- the host's grip on the room ------------------------------------------ */

.crewadmin {
  display: flex;
  justify-content: center;
  gap: 0.5rem;
  margin-top: 0.9rem;
}

.btn--quiet {
  font-size: 0.78rem;
  padding: 0.35rem 0.75rem;
  background: rgba(7, 26, 36, 0.7);
  color: var(--ink-2);
}

/* The host's way out of a live match, sat at the far end of the masthead. */
.masthead .btn--quiet {
  align-self: center;
  flex: none;
}

/* Hand the room over, or show somebody the gangplank. Host only, lobby only. */
.seat-crown,
.seat-kick {
  appearance: none;
  border: none;
  background: none;
  color: var(--ink-3);
  font-size: 0.78rem;
  line-height: 1;
  padding: 0.2rem 0.3rem;
  margin-left: -0.15rem;
  border-radius: var(--radius);
  cursor: pointer;
  flex: none;
}

.seat-crown:hover {
  color: var(--brass);
  background: rgba(201, 146, 46, 0.18);
}

.seat-kick:hover {
  color: #ef8f80;
  background: rgba(168, 50, 45, 0.28);
}

@media (max-width: 36rem) {
  .crewpick-row {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* -- the tables on this host ---------------------------------------------- */

.tablelist {
  width: 100%;
  margin-bottom: 1rem;
}

.tablelist[hidden] {
  display: none;
}

.tablelist .field-label {
  display: block;
  margin-bottom: 0.45rem;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.8);
}

.tablelist-rows {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.tablerow {
  appearance: none;
  display: grid;
  grid-template-columns: 1fr auto auto;
  align-items: center;
  gap: 0.7rem;
  text-align: left;
  padding: 0.55rem 0.75rem;
  border: 1px solid var(--brine);
  border-radius: var(--radius);
  background: rgba(7, 26, 36, 0.72);
  color: var(--ink-1);
  font-family: var(--font-ui);
  font-size: 0.86rem;
  cursor: pointer;
  transition: background 140ms ease, border-color 140ms ease;
}

.tablerow:hover:not(:disabled) {
  border-color: var(--brass);
  background: rgba(27, 74, 90, 0.6);
}

.tablerow--full {
  opacity: 0.45;
  cursor: not-allowed;
}

.tablerow-name {
  font-family: var(--font-display);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tablerow-seats {
  font-family: var(--font-data);
  font-size: 0.78rem;
  color: var(--brass);
}

.tablerow-state {
  font-family: var(--font-data);
  font-size: 0.66rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.tablelist .empty-note {
  margin: 0;
  font-size: 0.8rem;
  color: var(--ink-3);
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.8);
}

/* -- the parrot as tutor --------------------------------------------------- */

/* Anchored to the table rather than floating over it: a tip is something to read
   alongside the decision, not a dialog that has to be cleared before you can act. */
.tutor {
  position: fixed;
  left: clamp(0.5rem, 1.5vw, 1rem);
  bottom: 4.5rem;
  z-index: 15;
  display: flex;
  align-items: flex-end;
  gap: 0.5rem;
  width: min(24rem, calc(100vw - 1.5rem));
  padding: 0.7rem 0.8rem;
  border: 1px solid var(--brass);
  border-radius: var(--radius);
  background: rgba(7, 26, 36, 0.94);
  box-shadow: 0 10px 26px rgba(0, 0, 0, 0.55);
}

.tutor[hidden] {
  display: none;
}

.tutor-parrot {
  width: clamp(2.6rem, 6vw, 3.4rem);
  height: auto;
  object-fit: contain;
  flex: none;
}

.tutor-body {
  min-width: 0;
}

.tutor-text {
  margin: 0 0 0.5rem;
  font-size: 0.84rem;
  line-height: 1.4;
  color: var(--ink-1);
}

.tutor-actions {
  display: flex;
  gap: 0.4rem;
  flex-wrap: wrap;
}

/* What each track buys, while the tips are on. A definition list across the full panel
   width - the same copy inside the four columns became four columns of broken prose. */
.board-guide {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.15rem 0.5rem;
  margin: 0.7rem 0 0;
  font-size: 0.66rem;
  line-height: 1.3;
}

.board-guide dt {
  font-family: var(--font-data);
  font-size: 0.6rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--brass);
}

.board-guide dd {
  margin: 0;
  color: var(--ink-3);
}

/* -- new player or old salt ------------------------------------------------ */

.tutorpick {
  width: 100%;
  margin-top: 0.9rem;
}

.tutorpick[hidden] {
  display: none;
}

.tutorpick .field-label {
  display: block;
  margin-bottom: 0.4rem;
}

.tutorpick-row {
  display: flex;
  gap: 0.4rem;
  justify-content: center;
}

.tutorbtn {
  appearance: none;
  flex: 1 1 0;
  max-width: 11rem;
  font-family: var(--font-ui);
  font-size: 0.82rem;
  padding: 0.45rem 0.7rem;
  border: 1px solid var(--brine);
  border-radius: var(--radius);
  background: rgba(7, 26, 36, 0.66);
  color: var(--ink-2);
  cursor: pointer;
  transition: background 140ms ease, border-color 140ms ease, color 140ms ease;
}

.tutorbtn:hover {
  border-color: var(--brass);
  color: var(--ink-1);
}

.tutorbtn--on {
  border-color: var(--brass);
  background: rgba(201, 146, 46, 0.16);
  color: var(--brass);
}

.tutorpick-note {
  margin: 0.4rem 0 0;
  font-size: 0.72rem;
  color: var(--ink-3);
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.8);
}

/* The tip would sit on top of the action buttons on a narrow screen. */
@media (max-width: 60rem) {
  .tutor {
    position: static;
    width: 100%;
    margin: 0.6rem 0 0;
  }
}

/* -- the curtain --------------------------------------------------------- */

.has-art .curtain--won {
  background-image:
    linear-gradient(180deg, rgba(7, 26, 36, 0.72), rgba(7, 26, 36, 0.92)),
    image-set(url('/art/bg-victory.webp') 1x);
}

.has-art .curtain--lost {
  background-image:
    linear-gradient(180deg, rgba(7, 26, 36, 0.74), rgba(7, 26, 36, 0.93)),
    image-set(url('/art/bg-defeat.webp') 1x);
}

@media (orientation: portrait) {
  .has-art .curtain--won {
    background-image:
      linear-gradient(180deg, rgba(7, 26, 36, 0.72), rgba(7, 26, 36, 0.92)),
      image-set(url('/art/bg-victory-portrait.webp') 1x);
  }

  .has-art .curtain--lost {
    background-image:
      linear-gradient(180deg, rgba(7, 26, 36, 0.74), rgba(7, 26, 36, 0.93)),
      image-set(url('/art/bg-defeat-portrait.webp') 1x);
  }
}

/* The wave divider closes the curtain's reading before its buttons. */
.has-art .curtain-actions {
  padding-top: 1rem;
  border-image: url('/art/ui-divider-wave.webp') 40 0 0 0 / 0.75rem 0 0 0 / 0 stretch stretch;
}

.curtain-mascot:empty {
  display: none;
}

.curtain-mascot .mascot {
  width: clamp(4.5rem, 12vh, 7rem);
  height: auto;
  object-fit: contain;
  margin-bottom: 0.3rem;
  filter: drop-shadow(0 10px 14px rgba(0, 0, 0, 0.5));
}

/* The voyage map, with a coin on each stop the crew has actually reached. */
.curtain-voyage {
  margin: 0.9rem auto 1.3rem;
  width: min(100%, 24rem);
}

.curtain-voyage:empty {
  display: none;
}

.voyage-map {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 3px;
}

/* The coins sit under the map rather than on it: the map has its own painted route,
   and six markers dropped on top of it would be claiming to be those stops. */
.voyage-stops {
  display: flex;
  justify-content: center;
  gap: 0.4rem;
  margin-top: 0.55rem;
}

.voyage-stop {
  width: 1.9rem;
  aspect-ratio: 1;
  object-fit: contain;
  opacity: 0.25;
  filter: grayscale(0.9);
}

/* A gap between the three won and the three lost, so the two runs read apart. */
.voyage-stop:nth-child(3) {
  margin-right: 0.9rem;
}

.voyage-stop.reached {
  opacity: 1;
  filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.6));
}

/* -- feedback effects ---------------------------------------------------- */

/* One transparent layer over the whole table. It never takes a click, and every
   effect removes itself when its animation ends. */
.fx-layer {
  position: fixed;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
  z-index: 35;
}

.fx {
  position: absolute;
  object-fit: contain;
  opacity: 0;
}

/* Over the card in play: the burst, the cannon, the heal. */
.fx--burst {
  top: 50%;
  left: 50%;
  width: min(34rem, 62vw);
  height: auto;
  translate: -50% -50%;
  animation: fx-burst 900ms ease-out forwards;
}

@keyframes fx-burst {
  0% {
    opacity: 0;
    scale: 0.72;
  }
  22% {
    opacity: 1;
    scale: 1.04;
  }
  100% {
    opacity: 0;
    scale: 1.18;
  }
}

.fx--rise {
  top: 50%;
  left: 50%;
  width: min(26rem, 46vw);
  height: auto;
  translate: -50% -50%;
  animation: fx-rise 950ms ease-out forwards;
}

@keyframes fx-rise {
  0% {
    opacity: 0;
    translate: -50% -34%;
  }
  25% {
    opacity: 1;
  }
  100% {
    opacity: 0;
    translate: -50% -72%;
  }
}

.fx--sweep {
  top: 50%;
  left: 50%;
  width: min(30rem, 55vw);
  height: auto;
  animation: fx-sweep 780ms ease-out forwards;
}

@keyframes fx-sweep {
  0% {
    opacity: 0;
    translate: -86% -50%;
  }
  30% {
    opacity: 1;
  }
  100% {
    opacity: 0;
    translate: -14% -50%;
  }
}

/* The travelling shine that reads as a card turning over. */
.fx--shine {
  top: 50%;
  left: 50%;
  width: min(24rem, 42vw);
  height: auto;
  translate: -50% -50%;
  animation: fx-shine 620ms ease-out forwards;
}

@keyframes fx-shine {
  0% {
    opacity: 0;
    scale: 0.9;
  }
  30% {
    opacity: 0.85;
  }
  100% {
    opacity: 0;
    scale: 1.05;
  }
}

/* Damage, victory and defeat are edge treatments with a clear centre, so they cover
   the whole viewport and leave the table readable underneath. */
.fx--edge {
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  animation: fx-edge 1100ms ease-out forwards;
}

@keyframes fx-edge {
  0% {
    opacity: 0;
  }
  18% {
    opacity: 0.92;
  }
  100% {
    opacity: 0;
  }
}

/* -- adrift -------------------------------------------------------------- */

.adrift {
  position: fixed;
  inset: 0;
  display: grid;
  place-items: center;
  background: rgba(7, 26, 36, 0.82);
  z-index: 40;
}

/* The chart room: where you work out where you are. */
.has-art .adrift {
  background-image:
    linear-gradient(180deg, rgba(7, 26, 36, 0.88), rgba(7, 26, 36, 0.95)),
    image-set(url('/art/bg-tutorial.webp') 1x);
  background-size: cover;
  background-position: center;
}

@media (orientation: portrait) {
  .has-art .adrift {
    background-image:
      linear-gradient(180deg, rgba(7, 26, 36, 0.88), rgba(7, 26, 36, 0.95)),
      image-set(url('/art/bg-tutorial-portrait.webp') 1x);
  }
}

/* -- the parrot ---------------------------------------------------------- */

.mascot--thinking,
.mascot--pointing {
  width: 1.6rem;
  height: 1.6rem;
  object-fit: contain;
  vertical-align: -0.45rem;
  margin-right: 0.35rem;
}

.adrift-card {
  text-align: center;
  max-width: 22rem;
  padding: 1rem;
  color: var(--ink-2);
}

.adrift-parrot {
  width: 100%;
  max-width: 18rem;
  height: auto;
  border-radius: var(--radius);
  margin-bottom: 0.6rem;
}

/* -- seats --------------------------------------------------------------- */

.seat-portrait {
  width: 2.2rem;
  height: 2.2rem;
  border-radius: 50%;
  object-fit: cover;
  object-position: 50% 22%;
  box-shadow: 0 0 0 1px rgba(201, 146, 46, 0.55);
  flex: none;
}

.seat.away .seat-portrait {
  filter: grayscale(0.9);
  opacity: 0.5;
}

.seat-pennant {
  width: 1rem;
  height: 1rem;
  object-fit: contain;
  flex: none;
}

/* ------------------------------------------------------------- responsive */

@media (max-width: 68rem) {
  .layout {
    grid-template-columns: minmax(0, 1fr);
  }

  /* Scrolling is for the log and the discards. Whatever else is on the table, the card
     you are deciding about and the buttons that decide it stay on screen together. */
  .controls {
    position: sticky;
    bottom: 0;
    z-index: 12;
    margin: 0 calc(var(--gap) * -1);
    padding: 0.5rem var(--gap) calc(0.5rem + env(safe-area-inset-bottom, 0px));
    background: linear-gradient(180deg, transparent, rgba(7, 26, 36, 0.93) 22%);
  }

  /* The artwork gives way before the controls do. */
  .stage {
    min-height: 0;
  }

  .card {
    width: max(11rem, min(var(--card-w), (100dvh - 20rem) * 4 / 5));
  }

  .rail {
    flex-direction: row;
    flex-wrap: wrap;
  }

  .rail > .panel {
    flex: 1 1 15rem;
  }

  .table {
    order: -1;
  }
}

@media (max-width: 34rem) {
  .stage {
    flex-direction: column;
  }

  .masthead {
    flex-wrap: wrap;
  }

  .masthead-meta {
    margin-left: 0;
    text-align: left;
    width: 100%;
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}
