/* 暗棋 (Banqi) — M2.5 realistic art: a real wooden board and real wooden pieces.
 *
 * The look follows the approved mockup (.supervise/art/mock.html) and pushes the
 * details further: two procedurally generated wood textures (web/wood-textures.js,
 * generated ONCE at boot, handed in as data URLs on :root) plus gradients and
 * box-shadows for everything else — no image files, no fonts, no build step.
 *
 * Performance rules (SPEC §6) this file obeys:
 *   * textures are static background-images; nothing paints per frame
 *   * only `transform` and `opacity` are animated (flip / slide / capture / shake)
 *   * box-shadow is styled per state, never transitioned frame by frame
 *   * one element per cell, plus a fixed 4-element piece (lift > disc > face+back)
 *
 * Layout is a fixed, full-viewport column: top HUD (電腦), board, bottom HUD
 * (你).  The board itself is sized in JS (web/app.js -> layout()) so that the
 * cells stay disc-like and every tap target is >= 44px; the page therefore never
 * scrolls (especially not horizontally at 375px wide).
 */

:root {
  /* --- table ---------------------------------------------------------- */
  --table: #2b1d14;
  --table-mid: #4a3222;
  --table-deep: #180f09;

  /* --- wood (textures are injected by app.js) ------------------------- */
  --board-tex: none;
  --face-tex: none;
  --back-tex: none;
  --wood-fallback: #dcab6e;
  --wood-face-fallback: #e2b97e;
  --wood-back-fallback: #d6ac72;

  /* --- ink & brass ---------------------------------------------------- */
  --ink: rgba(58, 30, 12, 0.82);
  --ink-soft: rgba(58, 30, 12, 0.55);
  --brass: #d8b271;
  --brass-dark: #8a5a26;
  --brass-deep: #6b421a;
  --gold: #f0c469;
  --gold-soft: rgba(255, 220, 120, 0.85);

  --ink-red: #b01e14;
  --ink-black: #1b1712;
  --text: #f6ead6;
  --text-dim: #c9b193;

  --font-cn: "BiauKai", "Kaiti TC", "STKaiti", "DFKai-SB", "KaiTi", "Songti TC",
    "Times New Roman", serif;

  --pad-board: 13px; /* room for the grid + the frame ring outside it */
  --grid-border: 2px; /* the ink frame around the grid (see .grid) */
  --ring: 1.2px; /* the carved ring on a piece: scaled for small discs below */
  --cell: 64px;
  --cell-w: 64px;
  --cell-h: 64px;
  --radius-board: 12px;

  --dur-flip: 340ms;
  --dur-move: 230ms;
  --dur-fast: 130ms;
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
  height: 100%;
  overflow: hidden; /* no page scrolling at any width */
  background: var(--table-deep);
}

body {
  font-family: var(--font-cn);
  color: var(--text);
  -webkit-text-size-adjust: 100%;
  text-rendering: optimizeLegibility;
}

/* ------------------------------------------------------------------ shell -- */

#app {
  position: fixed;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  overflow: hidden;
  /* the dark table the board lies on */
  background:
    radial-gradient(ellipse 120% 80% at 50% 26%, var(--table-mid) 0%, var(--table) 52%, var(--table-deep) 100%),
    var(--table-deep);
  padding-top: env(safe-area-inset-top, 0px);
  padding-bottom: env(safe-area-inset-bottom, 0px);
  padding-left: env(safe-area-inset-left, 0px);
  padding-right: env(safe-area-inset-right, 0px);
  touch-action: manipulation;
}

/* -------------------------------------------------------------------- HUD -- */

.hud {
  flex: 0 0 auto;
  padding: 6px 12px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  user-select: none;
  -webkit-user-select: none;
}

.player-row {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 30px;
}

.who {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 11px 4px;
  font-size: 16px;
  font-weight: 700;
  letter-spacing: 1.5px;
  flex: 0 0 auto;
  border-radius: 4px;
  color: #2a1608;
  background-color: var(--brass);
  background-image:
    linear-gradient(180deg, rgba(255, 248, 228, 0.55) 0%, rgba(255, 236, 200, 0) 46%),
    linear-gradient(180deg, var(--brass) 0%, #b98a45 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 252, 240, 0.7),
    inset 0 -1px 0 rgba(90, 54, 12, 0.45),
    0 1px 0 #6b421a,
    0 3px 7px rgba(0, 0, 0, 0.45);
}
.hud-top .who-name { color: #f6e2c4; }
.hud-bottom .who-name { color: #33200c; }
.hud-top .who { color: #ffeccb; }
.hud-bottom .who { color: #33200c; }

.color-tag {
  font-size: 11px;
  font-weight: 700;
  padding: 0 6px;
  border-radius: 999px;
  border: 1px solid currentColor;
  letter-spacing: 0;
  line-height: 1.5;
}
.color-tag[data-color="red"] { color: #a3130b; background: rgba(255, 240, 235, 0.5); }
.color-tag[data-color="black"] { color: #1b1712; background: rgba(255, 250, 240, 0.42); }

/* captured pieces trays — a fixed two-row strip so the board never resizes
   while pieces are being captured */
.tray {
  flex: 1 1 auto;
  display: flex;
  flex-wrap: wrap;
  gap: 1px;
  align-content: flex-start;
  height: 40px;
  padding: 2px 4px;
  border-radius: 5px;
  overflow: hidden;
  /* a shallow brass rail rather than a black slab: an empty tray should read as
     "nothing here yet", not as a hole in the table */
  background:
    linear-gradient(180deg, rgba(0, 0, 0, 0.22) 0%, rgba(0, 0, 0, 0.1) 100%);
  box-shadow:
    inset 0 0 0 1px rgba(216, 178, 113, 0.22),
    inset 0 1px 2px rgba(0, 0, 0, 0.4),
    0 1px 0 rgba(255, 236, 200, 0.05);
}
.tray:empty::after {
  content: "";
  height: 3px;
  margin: 6px 2px;
  flex: 1 1 auto;
  border-radius: 2px;
  background: linear-gradient(90deg, transparent, rgba(216, 178, 113, 0.16) 20%, rgba(216, 178, 113, 0.16) 80%, transparent);
}
/* a captured piece: the same boxwood disc, miniature */
.tray .cap {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-size: 11px;
  line-height: 1;
  font-weight: 700;
  background-color: var(--wood-face-fallback);
  background-image:
    /* a gentler varnish highlight than the board pieces: at 18px the strong one
       reads as a smear across the character */
    radial-gradient(circle at 34% 28%, rgba(255, 252, 240, 0.34) 0%, rgba(255, 252, 240, 0) 46%),
    var(--face-tex);
  background-size: cover, cover;
  box-shadow:
    inset 0 0 0 1px rgba(120, 70, 25, 0.45),
    inset 0 -1px 2px rgba(120, 80, 40, 0.45),
    0 1px 0 #a87838,
    0 2px 3px rgba(0, 0, 0, 0.5);
  text-shadow: 0 1px 0 rgba(255, 245, 225, 0.5);
}
.tray .cap.red { color: var(--ink-red); }
.tray .cap.black { color: var(--ink-black); }

.status-row {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 26px;
}

.banner {
  font-size: 16px;
  font-weight: 700;
  letter-spacing: 2px;
  color: var(--gold);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.75), 0 0 12px rgba(240, 196, 105, 0.25);
  transition: color var(--dur-fast) ease;
}
#app[data-phase="computer"] .banner {
  color: #ffd9a1;
}
#app[data-phase="computer"] .banner::after {
  content: "";
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-left: 8px;
  border-radius: 50%;
  background: var(--gold);
  box-shadow: 0 0 8px rgba(240, 196, 105, 0.9);
  vertical-align: middle;
  animation: pulse 1.1s ease-in-out infinite;
}
#app[data-phase="over"] .banner {
  color: #ffe9b8;
}

@keyframes pulse {
  0%, 100% { opacity: 0.25; transform: scale(0.8); }
  50% { opacity: 1; transform: scale(1.15); }
}

.progress {
  margin-left: auto;
  font-size: 12px;
  color: var(--text-dim);
  letter-spacing: 1px;
  white-space: nowrap;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
}

/* controls */
.controls {
  position: relative;
  display: flex;
  gap: 8px;
  justify-content: space-between;
  padding-top: 4px;
}
/* a thin brass rule above the controls, like a real board's edge trim */
.controls::before {
  content: "";
  position: absolute;
  left: 2px;
  right: 2px;
  top: -2px;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(216, 178, 113, 0.35) 18%, rgba(216, 178, 113, 0.35) 82%, transparent);
}

.btn {
  flex: 1 1 0;
  min-height: 44px; /* tap target */
  padding: 9px 10px;
  font-family: inherit;
  font-size: 16px;
  font-weight: 700;
  letter-spacing: 2px;
  color: #2b1409;
  border: 1px solid #8a5a26;
  border-radius: 9px;
  background-color: #e0b478;
  background-image:
    linear-gradient(180deg, rgba(255, 250, 232, 0.75) 0%, rgba(255, 244, 214, 0.1) 42%, rgba(150, 92, 30, 0.16) 100%),
    linear-gradient(180deg, #f0d59b 0%, #dcb377 55%, #c79a58 100%);
  box-shadow:
    0 2px 0 #7c4d1d,
    0 4px 9px rgba(0, 0, 0, 0.45),
    inset 0 1px 0 rgba(255, 255, 255, 0.7),
    inset 0 -1px 0 rgba(120, 74, 22, 0.35);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  text-shadow: 0 1px 0 rgba(255, 250, 235, 0.5);
}
.btn:active {
  transform: translateY(2px);
  box-shadow:
    0 0 0 #7c4d1d,
    0 1px 3px rgba(0, 0, 0, 0.5),
    inset 0 1px 0 rgba(255, 255, 255, 0.4);
}
.btn[aria-pressed="false"] {
  filter: saturate(0.32) brightness(0.82);
}
.btn:disabled {
  filter: grayscale(0.65) brightness(0.68);
  cursor: default;
  box-shadow: 0 1px 0 #6b421a, inset 0 1px 0 rgba(255, 255, 255, 0.3);
}
.btn.ghost {
  color: var(--text);
  background-color: rgba(255, 255, 255, 0.06);
  background-image: none;
  border-color: rgba(216, 178, 113, 0.35);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
}
.btn.primary {
  color: #2b1409;
}

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

.board-area {
  flex: 1 1 auto;
  min-height: 0;
  display: grid;
  place-items: center;
  padding: 6px 12px 8px;
}

/* the slab: wood texture, a double frame, a soft inner vignette and a visible
   stacked thickness (the box-shadow "steps") dropping onto the dark table.
   The slab itself is a plain block — .grid, inside it, owns the track layout. */
.board {
  position: relative;
  padding: var(--pad-board);
  border-radius: var(--radius-board);
  background-color: var(--wood-fallback);
  /* SPEC §6: portrait shows vertical grain, landscape horizontal.  The texture
     is rasterised ONCE with the grain along x, so landscape paints it straight
     from the slab and portrait paints it on a turned quarter-turn child layer
     (--board-tex is handed to whichever one needs it).  No second canvas. */
  background-image: var(--board-tex);
  box-shadow:
    /* the mockup's frame sheen and inner vignette (this is what gives the slab its
       depth — a flat wash reads as cardboard), plus a slightly brighter front edge
       so the light still comes from above the table in both orientations */
    inset 0 0 0 2px rgba(255, 230, 190, 0.33),
    inset 0 0 40px rgba(90, 45, 10, 0.42),
    inset 0 22px 26px -20px rgba(255, 250, 234, 0.26),
    /* thickness, stacked */
    0 1px 0 #b1803f,
    0 2px 0 #a06f34,
    0 3px 0 #8d5f2b,
    0 4px 0 #7a5023,
    0 5px 0 #68431c,
    0 6px 0 #573716,
    0 7px 1px #472c11,
    /* contact shadow */
    0 12px 22px rgba(0, 0, 0, 0.55),
    0 26px 48px rgba(0, 0, 0, 0.45);
  touch-action: manipulation;
  user-select: none;
  -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
}

/* The same canvas again, with the grain running the other way.  The layer is
   `inset: 0`, so it can never be smaller than the slab, and app.js stretches the
   image to exactly that box (--grain-size) — the grain is a directional pattern,
   so scaling it swaps which way it runs.  In landscape the slab paints the
   texture itself and this layer is not needed. */
/* The slab paints the grain sheet directly in portrait (grain vertical).  In
   landscape the same sheet is turned a quarter turn by this layer: `.grain` is a
   window that is exactly the slab and can never move, and the `i` inside it is
   the slab's box with width and height swapped, centred and rotated about its own
   centre — so after the turn it lands exactly on the slab, and `cover` keeps the
   sheet's aspect ratio.  Rotating a child rather than the window is what makes
   the coverage provable. */
.board .grain {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  overflow: hidden;
  pointer-events: none;
  display: none;
}
.board[data-grain="landscape"] .grain {
  display: block;
}
.board .grain i {
  position: absolute;
  left: 50%;
  top: 50%;
  display: block;
  background-image: var(--board-tex);
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  transform: translate(-50%, -50%) rotate(90deg);
}

/* landscape / wide boards: the thickness is still at the bottom, which is
   exactly where a board lying on a table shows it */
.board::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  /* a barely-there corner darkening, cheaper than a second gradient layer */
  background: radial-gradient(120% 90% at 50% 0%, rgba(255, 245, 220, 0.07) 0%, rgba(0, 0, 0, 0) 55%);
}

/* ink grid: a double frame (thick outer line + thin ring 5px outside it) and
   1.5px ink lines between the cells — no gaps, like a printed board */
.grid {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: repeat(var(--cols, 4), var(--cell-w, var(--cell, 64px)));
  grid-template-rows: repeat(var(--rows, 8), var(--cell-h, var(--cell, 64px)));
  border: var(--grid-border) solid var(--ink);
  outline: 2px solid var(--ink);
  outline-offset: 5px;
  box-shadow:
    inset 0 1px 0 rgba(255, 246, 228, 0.2),
    inset 0 0 20px rgba(70, 34, 8, 0.22);
}

/* every cell is the tap target (>= 44px is guaranteed by the JS sizing) */
.cell {
  position: relative;
  width: var(--cell-w, var(--cell, 64px));
  height: var(--cell-h, var(--cell, 64px));
  padding: 0;
  margin: 0;
  border: 0;
  border-right: 2px solid var(--ink);
  border-bottom: 2px solid var(--ink);
  border-radius: 0;
  background: transparent;
  cursor: pointer;
  font: inherit;
  overflow: hidden;
}
.cell.last-col { border-right: 0; }
.cell.last-row { border-bottom: 0; }
/* the frame reads thicker than the inner lines, as on a printed board */
.cell.first-col { border-left: var(--grid-border) solid var(--ink); }
.cell.first-row { border-top: var(--grid-border) solid var(--ink); }

/* last move: a faint warm tint on the from/to cells */
.cell.last-from {
  background: rgba(255, 206, 116, 0.16);
}
.cell.last-to {
  background: rgba(255, 214, 130, 0.3);
  box-shadow: inset 0 0 12px rgba(255, 198, 90, 0.35);
}

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

/* .piece carries the 2D motion (lift, shake) and is also the element the fx
   ghosts animate, so the slide keyframes never have to fight the flip.
   `color` is the piece's ink, which the carved ring and the character use. */
.piece {
  color: var(--ink-black);
  --base: translate(-50%, -50%);
  /* the mockup's 2px lift: it is what exposes the disc's stacked edge below */
  margin-top: -2px;
  position: absolute;
  left: 50%;
  top: 50%;
  width: calc(min(var(--cell-w, 64px), var(--cell-h, 64px)) * 0.9);
  height: calc(min(var(--cell-w, 64px), var(--cell-h, 64px)) * 0.9);
  transform: var(--base);
  transition: transform 150ms cubic-bezier(0.34, 1.3, 0.5, 1);
  will-change: transform;
}

/* .disc is the physical piece: a thick boxwood cylinder.  Only the flip acts
   on it, so rotateY() and translateY() never fight over one transform. */
.disc {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background-color: var(--wood-face-fallback);
  background-image: var(--face-tex);
  /* the mockup's zoom: each disc samples a small patch of the boxwood sheet, so
     the grain inside a piece is at a believable scale and neighbouring pieces
     rarely show the same patch (app.js varies the position per square) */
  background-size: 220%;
  background-position: 34% 42%;
  /* the visible thickness of the disc: five hard steps, then its shadow */
  box-shadow:
    0 1px 0 #c9995a,
    0 2px 0 #b98848,
    0 3px 0 #a87838,
    0 4px 0 #976a2e,
    0 5px 1px #845c26,
    0 8px 10px rgba(0, 0, 0, 0.45);
  transform: rotateY(0deg);
  transform-style: flat;
  /* the turn of a flip (app.js -> turnDisc).  A transition, not an animation:
     the final value is owned by the class, so nothing can get stuck mid-flip. */
  transition: transform var(--dur-flip) cubic-bezier(0.4, 0.05, 0.25, 1);
  will-change: transform;
}

/* face and back are the two sides of the same disc; both are always in the DOM
   and the browser hides whichever one is turned away.  At the 90° midpoint the
   disc's own boxwood shows through, which is exactly what the 2px side wall of
   a flipped piece looks like. */
.piece .face,
.piece .back {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background-size: cover;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}

/* face-up: carved, paint-filled character + a carved inner ring */
.piece .face {
  display: grid;
  place-items: center;
  background-color: var(--wood-face-fallback);
  background-image: var(--face-tex);
}
.piece .face::before {
  content: "";
  position: absolute;
  inset: 13%;
  border-radius: 50%;
  /* a carved line takes the piece's ink colour, exactly as in the mockup */
  border: var(--ring) solid currentColor;
  opacity: 0.62;
  box-shadow:
    inset 0 1px 1px rgba(96, 56, 16, 0.4),
    0 1px 0 rgba(255, 250, 234, 0.5);
}
.piece .face .ch {
  position: relative;
  z-index: 1;
  font-size: calc(min(var(--cell-w, 64px), var(--cell-h, 64px)) * 0.46);
  font-weight: 700;
  line-height: 1;
  text-shadow:
    0 1px 0 rgba(255, 248, 228, 0.7),
    0 -1px 0 rgba(60, 26, 4, 0.45),
    0 2px 3px rgba(80, 40, 10, 0.3);
}
.piece.red .face { color: var(--ink-red); }
.piece.black .face { color: var(--ink-black); }
.piece.red .face .ch { color: var(--ink-red); }
.piece.black .face .ch { color: var(--ink-black); }

/* face-down: the blank back of the same wooden piece — different tone, a faint
   ring, never a character */
.piece .back {
  transform: rotateY(180deg);
  background-color: var(--wood-back-fallback);
  background-image: var(--back-tex);
}
.piece .back::before {
  content: "";
  position: absolute;
  inset: 13%;
  border-radius: 50%;
  /* the back has no character: a faint ring, nothing else */
  border: var(--ring) solid rgba(128, 78, 28, 0.55);
  box-shadow:
    inset 0 1px 1px rgba(96, 56, 16, 0.35),
    0 1px 0 rgba(255, 248, 230, 0.42);
}

/* varnish highlight (top-left) + convex rim; sits above the character */
/* Varnish highlight (top-left) + convex rim, exactly as in the mockup: this is
   what makes the disc read as a domed piece of boxwood rather than a flat disc. */
.disc::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  pointer-events: none;
  background:
    radial-gradient(circle at 32% 26%, rgba(255, 250, 235, 0.55) 0%, rgba(255, 250, 235, 0) 38%),
    radial-gradient(circle at 50% 50%, rgba(0, 0, 0, 0) 58%, rgba(70, 35, 5, 0.28) 100%);
}

/* the flip: rotating the disc past 90° swaps which side faces the viewer.
   `.is-down` is the same state while the flip is driven by the Web Animations
   API (app.js -> flipDisc), which is how a piece that was hidden a moment ago
   gets a real turn instead of a pop. */
.piece.down .disc,
.disc.is-down {
  transform: rotateY(180deg);
}
.piece.no-anim .disc,
.disc.no-turn {
  transition: none !important;
}
/* a disc that is mid-turn must not also be shaken sideways */
.cell.shake .disc.is-down {
  animation: none;
}

/* selection: the piece lifts off the board, the shadow grows, a gold ring */
.cell.selected .piece {
  transform: var(--base) translateY(-8%) scale(1.05);
}
.cell.selected .disc {
  box-shadow:
    inset 0 2px 2px rgba(255, 246, 224, 0.42),
    inset 0 -3px 5px rgba(112, 66, 22, 0.5),
    0 2px 0 #c0904f,
    0 4px 0 #a87838,
    0 6px 0 #8a6130,
    0 9px 2px #6f4a20,
    0 14px 18px rgba(0, 0, 0, 0.55),
    0 0 0 3px rgba(255, 218, 122, 0.9),
    0 0 16px 2px rgba(255, 206, 100, 0.5);
}
.cell.selected .face .ch {
  color: var(--ink-red);
}
.cell.selected .piece.black .face .ch {
  color: var(--ink-black);
}

/* legal destination: a small green dot (empty cell) ... */
.cell.hint .piece,
.cell.hint::after,
.cell.hint-capture::after {
  pointer-events: none;
}
.cell.hint::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 24%;
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: radial-gradient(circle at 42% 36%, rgba(150, 224, 120, 0.95) 0%, rgba(52, 118, 42, 0.88) 70%, rgba(30, 76, 24, 0.85) 100%);
  box-shadow:
    0 0 0 3px rgba(255, 255, 255, 0.35),
    0 2px 5px rgba(0, 0, 0, 0.45);
}
/* ... and a red ring around a capture target's piece */
.cell.hint-capture::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 88%;
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  border: 2.5px solid rgba(255, 84, 52, 0.92);
  box-shadow:
    0 0 10px rgba(255, 80, 40, 0.55),
    inset 0 0 8px rgba(255, 110, 70, 0.45);
}

/* tap-a-piece-that-cannot-move: a knock, not a slide (transform only) */
@keyframes shake {
  0%, 100% { transform: rotateY(var(--ry, 0deg)) translateX(0); }
  22% { transform: rotateY(var(--ry, 0deg)) translateX(-4px); }
  45% { transform: rotateY(var(--ry, 0deg)) translateX(4px); }
  68% { transform: rotateY(var(--ry, 0deg)) translateX(-2.5px); }
  86% { transform: rotateY(var(--ry, 0deg)) translateX(2px); }
}
.cell.shake .disc {
  animation: shake 280ms ease-in-out;
}
.piece.down {
  --ry: 180deg;
}

/* -------------------------------------------------------------------- fx --- */

/* ghosts used for slide / capture animations live above the cells.
   The negative inset cancels the grid's 2px ink frame so that a ghost's
   offsetLeft/offsetTop (measured from the grid's border box) lands exactly on
   the cell it copies. */
.fx-layer {
  position: absolute;
  inset: calc(var(--grid-border, 2px) * -1);
  pointer-events: none;
  z-index: 5;
}
/* one ghost per animated cell: absolutely positioned over that cell, so the
   .piece inside it keeps exactly the size of a real piece */
.fx-layer .fx-cell {
  position: absolute;
  pointer-events: none;
}

/* the destination piece is hidden while its ghost slides in */
.piece.ghosted {
  visibility: hidden;
}

/* ---------------------------------------------------------------- overlay -- */

.overlay {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: grid;
  place-items: center;
  padding: 24px;
  background: rgba(12, 5, 2, 0.66);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
}
.overlay[hidden] {
  display: none;
}

.dialog {
  width: min(340px, 100%);
  padding: 18px 18px 16px;
  border-radius: 14px;
  position: relative;
  border: 1px solid var(--brass-dark);
  background-color: #3b2712;
  background-image: var(--board-tex);
  background-size: 260%;
  background-position: 30% 40%;
  box-shadow:
    inset 0 0 0 1px rgba(255, 240, 214, 0.22),
    inset 0 0 44px rgba(40, 18, 4, 0.7),
    0 2px 0 #6b421a,
    0 4px 0 #54330f,
    0 20px 44px rgba(0, 0, 0, 0.65);
  text-align: center;
  animation: dialog-in 200ms ease-out;
}
@keyframes dialog-in {
  from { opacity: 0; transform: translateY(8px) scale(0.97); }
  to { opacity: 1; transform: none; }
}

.dialog-title {
  margin: 0 0 6px;
  font-size: 24px;
  letter-spacing: 3px;
  color: #ffe6a8;
  text-shadow: 0 2px 4px rgba(0, 0, 0, 0.75), 0 0 14px rgba(240, 196, 105, 0.3);
}

.dialog-text {
  margin: 0 0 14px;
  font-size: 14px;
  line-height: 1.7;
  color: #f0e0c6;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.7);
  white-space: pre-line;
}

.dialog-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.dialog-buttons .btn {
  flex: 1 1 120px;
}

/* ------------------------------------------------------- wide orientations - */

/* Landscape / desktop: a little more air around the board, HUD stays compact and
   lines up with the slab (--hud-w is measured from the board in app.js). */
@media (orientation: landscape) and (min-width: 700px) {
  .hud {
    width: 100%;
    max-width: max(var(--hud-w, 100%), 360px);
    margin: 0 auto;
    padding: 6px 0;
  }
  .board-area {
    padding: 2px 0 8px;
  }
  .who { font-size: 16px; }
  .tray { height: 30px; }
  .tray .cap { width: 15px; height: 15px; font-size: 10px; }
  .controls { padding-top: 2px; }
  .btn { min-height: 40px; padding: 6px 10px; }
  .dialog { width: min(420px, 100%); }
}

/* the carved ring is a physical detail: it gets thinner as the disc gets
   smaller, so a 390px-wide phone does not get a chunky ring */
@media (max-width: 430px) {
  :root { --ring: 1.1px; }
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-flip: 1ms;
    --dur-move: 1ms;
    --dur-fast: 1ms;
  }
  .piece,
  .disc,
  .cell,
  .btn,
  .dialog {
    animation: none !important;
    transition: none !important;
  }
}
