/* ==========================================================================
   HEARTS, specific styles.

   This file comes AFTER ../styles.css, which carries everything the games have
   in common: sidebar, menus, board, felt, cards, modal dialogs, scrollbars,
   language toggle. Only the table, the four seats, the trick in the middle and
   the passing panel are found here.
   ========================================================================== */

/* ---------- SHAPE OF THE TABLE ----------
   The same rectangle as the poker, and for the same reasons: four players face
   each other two by two, and a table that stretched with the window would end
   up crushing what it holds. Thirteen cards per hand ask for width, three rows
   of cards for height: the 3/2 ratio gives both. */
#board {
  width: auto;
  /* The cap counts what sits around the table: the padding of the playing area
     and the footer, some hundred pixels that must stay on screen, the table
     never making the page scroll. */
  height: min(calc(100vh - 105px), 50vw);
  aspect-ratio: 3 / 2;
  min-height: 0;
  max-width: 100%;
  border-radius: 18px;
}

#board-felt {
  display: flex;
  flex-direction: column;
  min-height: 0;
  border-radius: 12px;
  /* The felt does not clip what overflows it: a long name plate goes over the
     wood of the frame, as on a real table. The shared stylesheet puts a safety
     overflow-x on it, which would clip the height too. */
  overflow: visible;
}

#board-inner {
  /* The cards follow the real width of the felt, in container query units:
     that is the rule of the site, and it keeps a hand of thirteen cards from
     overflowing on a narrow window. */
  --card-w: clamp(40px, 8cqw, 100px);
  --card-h: calc(var(--card-w) * 244 / 168);
  /* Step of a face-up fan: a little more than half a card, which leaves the
     index corner of every card in sight. Thirteen cards then measure seven card
     widths. */
  --fan-step: calc(var(--card-w) * 0.52);
  /* A face-down hand shows nothing worth reading: a sliver is enough, and the
     three other players take up that much less room. */
  --back-step: calc(var(--card-w) * 0.22);
  /* How far a card stands out of the hand, hovered or chosen for the exchange:
     the same height for both, a chosen card being told apart by its gold edge,
     not by standing higher. The button is placed above that, not above the hand
     at rest. */
  --card-lift: 14px;
  flex: 1;
  width: 100%;
  min-height: 0;
  position: relative;
}

/* ---------- SEATS ----------
   Four players around the rectangle: the human to the south, the machines to
   the west, the north and the east. Each is placed as a percentage of the felt,
   never at a fixed distance, so as to follow the size of the screen.

   The flanks are the exception: their distance from the edge is measured on the
   card, half a hand lying down being 0.73 of a card width, since a card is as
   wide lying down as it is tall standing up. A percentage moved them inwards as
   the window narrowed, exactly when the middle needed the room. */
.seat {
  position: absolute;
  transform: translate(-50%, -50%);
}

.seat.south { left: 50%; top: 87%; }
.seat.north { left: 50%; top: 13%; }
.seat.west  { left: calc(var(--card-w) * 0.73 + 10px); top: 50%; }
.seat.east  { left: calc(100% - var(--card-w) * 0.73 - 10px); top: 50%; }

/* The name plate is out of the flow, under the cards: counted in the height, it
   would shift the centre of the seat and the flanks would no longer fall level
   with the middle of the table. */
.seat-hand {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* The hand itself: cards laid one over the other, each carrying its own offset
   in line. The width follows the number of cards, so the fan closes up as it
   is played and stays centred on its seat. */
.hand-cards {
  position: relative;
  height: var(--card-h);
}

.hand-cards .card {
  position: absolute;
  top: 0;
  width: var(--card-w);
  height: var(--card-h);
  transition: transform 0.12s ease;
}

/* On the flanks the cards lie sideways. Rotation does not change an element's
   footprint: the fan is therefore placed absolutely in the middle of a box
   whose width and height are swapped. That box keeps the size of a full hand,
   so the plate stays put while the hand empties. */
.seat.west .seat-hand,
.seat.east .seat-hand {
  width: var(--card-h);
  height: calc(var(--card-w) + 12 * var(--back-step));
}

.seat.west .hand-cards,
.seat.east .hand-cards {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%) rotate(90deg);
}

/* ---------- THE PLAYER'S OWN HAND ----------
   A card he may play answers the mouse; the others are dimmed, so that the rule
   of the suit is read on the table rather than in the rules. Dimming, never
   fading: cards overlap, and one made transparent would show its neighbour
   through it.

   **A raised card does not come to the front.** The cards of a fan overlap, and
   only the visible sliver of each answers the mouse, its neighbour on the right
   covering the rest. Bringing the hovered card above that neighbour widened its
   catchment to the whole card: the cursor could travel a full card width and
   the same one stayed up, instead of the fan following the cursor from one card
   to the next. The lift alone is enough to see it, its top edge standing clear
   of the hand. */
.hand-cards .card.playable { cursor: pointer; }

/* **A finger does not hover.** On a touch screen the browser keeps `:hover` on
   the last thing tapped until something else is tapped: a card put back down
   stayed standing, and no gesture could bring it back into the hand. The lift
   on hover is therefore only for the pointers that can leave a card, and the
   script marks nothing on a touch either.

   `.hovered` is posted by the script on the card under a motionless mouse,
   which a freshly rebuilt element never gets from `:hover` alone. */
@media (hover: hover) {
  .hand-cards .card.playable:hover {
    transform: translateY(calc(-1 * var(--card-lift)));
  }
}

.hand-cards .card.hovered {
  transform: translateY(calc(-1 * var(--card-lift)));
}

.hand-cards .card.idle { filter: brightness(0.5); }

/* A card chosen for the exchange stands up out of the hand, and comes back down
   at a second click. It stays in its rank for the same reason: in front, it
   swallowed the clicks meant for its neighbour. */
.hand-cards .card.chosen {
  transform: translateY(calc(-1 * var(--card-lift)));
  outline: 3px solid #ffe94a;
  outline-offset: 2px;
  box-shadow: 0 0 0 6px rgba(255, 233, 74, 0.24), 0 0 16px 4px rgba(255, 233, 74, 0.5);
}

/* The three cards just received from a neighbour, marked long enough to be
   found in the hand they have just joined. */
.hand-cards .card.received {
  z-index: 4;
  outline: 3px solid #6fd3a0;
  outline-offset: 2px;
  box-shadow: 0 0 0 6px rgba(111, 211, 160, 0.22);
}

/* ---------- NAME PLATE ----------
   Name, running score, and what the hand in progress has cost. The felt is too
   busy for plain text to hold its own on it.

   The plate never comes between a hand and the middle of the table: to the
   south it falls under the cards, to the north it therefore goes above. */
.seat-label {
  position: absolute;
  top: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%);
  padding: 4px 12px 5px;
  border-radius: 4px;
  background: rgba(0, 0, 0, 0.62);
  border: 1px solid rgba(255, 255, 255, 0.28);
  text-align: center;
  line-height: 1.25;
  white-space: nowrap;
}

.seat.north .seat-label {
  top: auto;
  bottom: calc(100% + 8px);
}

.seat-name {
  font-size: clamp(11px, 1.15cqw, 15px);
  color: #fff;
}

.seat-count {
  font-size: clamp(10px, 1.05cqw, 14px);
  color: #cfcfc4;
  font-variant-numeric: tabular-nums;
}

/* What the hand in progress has cost this player, beside his total. Red: these
   are points one does not want. */
.seat-delta {
  margin-left: 6px;
  color: #f87171;
}

/* The seat to play stands out: without it, nothing says whose turn it is. */
.seat.active .seat-label {
  border-color: #f3ea69;
  box-shadow: 0 0 0 1px rgba(243, 234, 105, 0.5), 0 4px 12px rgba(0, 0, 0, 0.5);
}

/* ---------- THE TRICK ----------
   Four cards thrown to the middle, each on the side of the player who played
   it. The slots stay painted on the felt: they do not disappear when a card
   lands, it is on them that it comes to rest. */
#trick {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: calc(var(--card-w) * 3.4);
  height: calc(var(--card-h) * 2.15);
}

.trick-slot {
  position: absolute;
  width: var(--card-w);
  aspect-ratio: 168 / 244;
  border-radius: 5px;
  outline: 1px solid rgba(255, 255, 255, 0.22);
  outline-offset: -1px;
}

.trick-slot.north { left: 50%; top: 0; transform: translateX(-50%); }
.trick-slot.south { left: 50%; bottom: 0; transform: translateX(-50%); }
.trick-slot.west  { left: 0; top: 50%; transform: translateY(-50%); }
.trick-slot.east  { right: 0; top: 50%; transform: translateY(-50%); }

.trick-slot .card {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* The card that takes the trick is lit for as long as the trick stays on the
   table: that is what says where the cards are about to go, and why. The light
   is meant to be seen across the table, and the card passes in front of its
   neighbours so that nothing eats the outline. */
.card.taking,
.fig-card.best {
  outline: 3px solid #ffe94a;
  outline-offset: 2px;
  box-shadow: 0 0 0 6px rgba(255, 233, 74, 0.28), 0 0 18px 4px rgba(255, 233, 74, 0.55);
  z-index: 5;
}

.fig-card.best { position: relative; }

/* ---------- THE PACK ----------
   In the middle of the table, face down, for the length of the deal only: after
   it there is not one card left, and the middle belongs to the trick. It shows
   its thickness, one edge per card, and thins out as it is dealt. The top and
   the edges are children: the background of a parent is painted before its
   children, so nothing can be slipped underneath. */
#deck {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: var(--card-w);
  aspect-ratio: 168 / 244;
}

#deck .top-card,
#deck .edge {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  border-radius: 6px;
  border: var(--card-border, 1px solid #999);
}

#deck .top-card {
  background: center / var(--card-bg-size, 104% 102.7%) no-repeat;
  box-shadow: 0 6px 14px rgba(0, 0, 0, 0.5);
}

/* The edge is the side of a card: paper, nothing else. */
#deck .edge { background: #f2efe6; }

/* A card in flight: a copy sliding from one point of the table to another, then
   vanishing, the render taking over. It carries its width inline, --card-w
   living on the board. */
.card.in-flight {
  position: absolute;
  z-index: 40;
  pointer-events: none;
  aspect-ratio: 168 / 244;
  border-radius: 6px;
  border: var(--card-border, 1px solid #999);
  background: center / var(--card-bg-size, 104% 102.7%) no-repeat;
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.55);
}

/* ---------- THE EXCHANGE ----------
   The button sits right on top of the cards standing out of the hand, the
   instruction above it: the three cards are chosen down there, and the hand
   goes from the cards to the button without crossing the table. The seat being
   centred at 87 % of the felt and standing one card high, its cards begin half
   a card above that; a card standing out of the hand rises --card-lift, and the
   block is anchored by its foot ten pixels above that. Measured on the hand at
   rest, the button would have been covered the moment a card was chosen. */
#pass-panel {
  position: absolute;
  left: 50%;
  top: calc(87% - var(--card-h) / 2 - var(--card-lift) - 10px);
  transform: translate(-50%, -100%);
  z-index: 6;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(10px, 1.4cqw, 20px);
}

#pass-note {
  max-width: 34cqw;
  padding: 8px 24px 10px;
  border-radius: 999px;
  background: rgba(8, 8, 8, 0.92);
  border: 1px solid rgba(255, 255, 255, 0.24);
  text-align: center;
  color: #f0f0e6;
  font-size: clamp(13px, 1.5cqw, 22px);
  line-height: 1.35;
}

#btn-pass {
  padding: 0 clamp(14px, 2cqw, 30px);
  height: clamp(28px, 3.4cqw, 46px);
  border-radius: 4px;
  border: 1px solid #4ade80;
  background: #1d6b3a;
  color: #fff;
  font-family: inherit;
  font-size: clamp(12px, 1.5cqw, 18px);
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease;
}

#btn-pass:hover:not(:disabled) { background: #248046; }

#btn-pass:disabled {
  background: rgba(9, 9, 9, 0.88);
  border-color: #666;
  color: #bbb;
  cursor: default;
}

/* ---------- ANNOUNCEMENT ----------
   Out of the flow, in the band left free between the trick and the player's
   hand: the middle of the table belongs to the four cards, and an announcement
   laid over them would hide the very thing one is looking at. That band is
   narrow, so the type is smaller than at the poker, where the middle is
   free.

   A passing announcement fades after a second; a hand's result holds until the
   next deal. */
#message {
  position: absolute;
  left: 50%;
  top: 73%;
  transform: translate(-50%, -50%);
  z-index: 50;
  max-width: 84%;
  width: fit-content;
  padding: 6px 28px 8px;
  border-radius: 999px;
  background: #0a0a0a;
  border: 1px solid rgba(255, 255, 255, 0.2);
  box-shadow: 0 4px 18px rgba(0, 0, 0, 0.6);
  text-align: center;
  font-size: clamp(15px, 1.9cqw, 28px);
  font-weight: 600;
  color: #fff;
}

#message:empty {
  padding: 0;
  background: none;
  border-color: transparent;
  box-shadow: none;
}

#message.fading {
  animation: messageFade 1.7s ease forwards;
}

@keyframes messageFade {
  0%, 59% { opacity: 1; }
  100% { opacity: 0; visibility: hidden; }
}

#message.win { color: #4ade80; }

/* ---------- SIDEBAR ---------- */
#pass-line {
  font-size: 14px;
  color: #aaa;
  margin-bottom: 6px;
}

/* The record, above the scores as in the other games. It is the lowest total
   the player has ever finished a game with: here, few points is the good
   news. */
#record {
  color: #bbb;
  font-size: 17px;
  margin-bottom: 12px;
}

#record:empty { display: none; }

/* The four totals, one line each. The plates on the felt say the same thing,
   but a column is what one reads to know where the game stands. */
#scoreboard {
  width: 100%;
  border-collapse: collapse;
  font-size: 15px;
  color: #bbb;
  margin-bottom: 18px;
}

#scoreboard td {
  padding: 5px 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
}

#scoreboard tr:last-child td { border-bottom: none; }

#scoreboard td:last-child {
  text-align: right;
  font-weight: bold;
  color: #fff;
  font-variant-numeric: tabular-nums;
}

#scoreboard tr.me td { color: #fff; }

/* ---------- THE RULES ----------
   Five tabs are one more than the shared dialog was cut for: on a narrow
   window, where it comes down to its floor of 560px, they take a second line
   rather than run off the edge. On a wide one they stay in a row.

   The moon's figure holds fourteen cards, the thirteen hearts and the queen:
   seven to a row, each overlapping the one before, since fourteen cards cannot
   be shown whole side by side. The columns are narrower than a card, which is
   what makes them overlap; the last of each row sticks out beyond its column,
   and the padding gives that room back so the two rows stay centred. */
.rules-tabs { flex-wrap: wrap; }

#fig-moon {
  display: grid;
  grid-template-columns: repeat(7, calc(var(--fig-card-w, 46px) * 0.45));
  justify-content: center;
  /* The shared gap of the figures would push the cards apart again. */
  column-gap: 0;
  row-gap: 6px;
  padding-right: calc(var(--fig-card-w, 46px) * 0.55);
}

/* ---------- END OF THE GAME ----------
   The window is laid on the table, not on the page: the sidebar takes its share
   of the width on the left, and a window centred on the window would sit off to
   one side of the felt. Its place is measured by the script and posted here,
   the panel on the left being able to collapse. */
#over-dialog.open {
  position: fixed;
  left: var(--table-x, 50%);
  top: var(--table-y, 50%);
  transform: translate(-50%, -50%);
}

/* The final table, in the same shape as the sidebar one, at reading size. */
#over-line {
  font-size: 17px;
  color: #ccc;
  margin-bottom: 12px;
}

#over-scores {
  width: 100%;
  border-collapse: collapse;
  font-size: 16px;
  color: #ccc;
}

#over-scores td {
  padding: 6px 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
}

#over-scores tr:last-child td { border-bottom: none; }

#over-scores td:last-child {
  text-align: right;
  font-weight: bold;
  color: #fff;
  font-variant-numeric: tabular-nums;
}

#over-scores tr.winner td { color: #4ade80; }

/* ---------- NARROW SCREEN ----------
   Below 820px the table takes back the height of its content: the fixed ratio
   no longer makes sense when the width is not enough to house four seats.

   **The cards are cut on the width, and the table is then given the height they
   need.** A share of the screen (66vh) left them at eight hundredths of a felt
   already narrow, tiny in the middle of an empty table, and the height could not
   be spent because the seats sit at 13 % and 87 % of it. The panel takes the top
   of a tablet page anyway and the table is scrolled to: it may as well be as
   tall as its cards require.

   The count: a seat needs half a card height plus its name plate above the 13 %
   mark, which gives 5.6 cards plus two plates for the whole table. */
@media (max-width: 820px) {
  #board {
    width: 100%;
    height: auto;
    aspect-ratio: auto;
  }

  #board-inner {
    --card-w: clamp(40px, 11cqw, 100px);
    min-height: calc(62cqw + 370px);
  }

  #message { font-size: 17px; }
}
