/* kenoku, the play table.
 *
 * Themes are variable sets on <body>. The state classes on a square (.shadow,
 * .sealed, .blot, .koma, .hit...) and the digit colours are shared by every
 * theme, which is how "a theme changes the look, never the information"
 * (CLAUDE.md pillar 2) holds by construction rather than by review. */

:root {
  --ink: #1d1a16;
  --cream: #fbf3e2;
  --hanko: #c8312a;
  --hanko-deep: #66251e;
  --sakura: #f2a3bb;

  /* One colour per digit, traditional dye names. A warded digit lights up
     across the board in its colour, so these are information, not decoration. */
  --d1: #d7263d; /* beni */
  --d2: #e8740f; /* daidai */
  --d3: #d9a400; /* yamabuki */
  --d4: #3a9a3e; /* wakatake */
  --d5: #0f9e95; /* seiji */
  --d6: #2459b8; /* ruri */
  --d7: #7a3aa6; /* edo murasaki */
  --d8: #df4f86; /* sakura, deepened to read on wood */
  --d9: #3a3632; /* sumi */

  --display: 'Potta One', 'Hiragino Maru Gothic ProN', sans-serif;
  --numeral: 'Kaisei Tokumin', 'Hiragino Mincho ProN', serif;
  --body: 'Shippori Mincho B1', 'Hiragino Mincho ProN', serif;

  --bounce: cubic-bezier(.2, 1.7, .4, 1);
}

/* ---------- theme: woodblock (free) ---------- */
.theme-woodblock {
  --page: #ece0c8;
  --page-ink: var(--ink);
  --panel: #f6ecd8;
  --panel-edge: rgba(29, 26, 22, 0.16);
  --board: linear-gradient(135deg, #d8b47c, #c99a5c);
  --frame: 12px solid #7b5631;
  --frame-shadow: inset 0 0 0 2px #5a3c1f, 0 14px 30px rgba(0, 0, 0, 0.28);
  --board-radius: 4px;
  --box: var(--ink);
  --box-radius: 0;
  --box-edge: none;
  --cell: repeating-linear-gradient(92deg, #dcb983 0 6px, #d4ae76 6px 9px);
  --cell-out: #b79c78;
  --cell-shadow: repeating-linear-gradient(92deg, #a98a62 0 6px, #a3845c 6px 9px);
  --cell-radius: 0;
  --cell-lift: none;
  --face-ink: rgba(29, 26, 22, 0.7);
  /* A hairline of ink so the lighter dyes (yamabuki above all) hold on wood. */
  --digit-stroke: 0.025em;
  --digit-glow: none;
}

/* ---------- theme: matsuri day (pack) ---------- */
.theme-day {
  --page: linear-gradient(180deg, #fff4df, #ffe1c4);
  --page-ink: var(--ink);
  --panel: #fffaf0;
  --panel-edge: rgba(29, 26, 22, 0.22);
  --board: #ffcf6e;
  --frame: 6px solid var(--ink);
  --frame-shadow: 0 8px 0 var(--ink), 0 20px 34px rgba(0, 0, 0, 0.25);
  --board-radius: 18px;
  --box: #fff;
  --box-radius: 10px;
  --box-edge: 3px solid var(--ink);
  --cell: #fffaf0;
  --cell-out: rgba(255, 255, 255, 0.35);
  --cell-shadow: #e7dccb;
  --cell-radius: 8px;
  --cell-lift: inset 0 -3px 0 rgba(0, 0, 0, 0.12), 0 2px 0 rgba(0, 0, 0, 0.25);
  --face-ink: rgba(29, 26, 22, 0.6);
  --digit-stroke: 0.04em;
  --digit-glow: none;
}
/* Nine wagara, one per box. Box membership is the whole sudoku, so making
   each box visibly its own is legibility, not ornament. */
.theme-day .box:nth-child(1) { background: conic-gradient(#ffb3c6 25%, #ffd6e0 0 50%, #ffb3c6 0 75%, #ffd6e0 0) 0 0 / 16px 16px; }
.theme-day .box:nth-child(2) { background: radial-gradient(circle at 50% 100%, #8ec5ff 0 30%, #d6ebff 31% 45%, #8ec5ff 46% 60%, #d6ebff 61%) 0 0 / 20px 12px; }
.theme-day .box:nth-child(3) { background: repeating-linear-gradient(60deg, #ffe08a 0 2px, transparent 2px 12px), repeating-linear-gradient(-60deg, #ffe08a 0 2px, transparent 2px 12px), repeating-linear-gradient(0deg, #ffe08a 0 2px, #fff3c4 2px 12px); }
.theme-day .box:nth-child(4) { background: radial-gradient(circle, transparent 55%, #9fe0a3 56% 62%, transparent 63%) 0 0 / 16px 16px, radial-gradient(circle, transparent 55%, #9fe0a3 56% 62%, transparent 63%) 8px 8px / 16px 16px, #dcf5dd; }
.theme-day .box:nth-child(5) { background: linear-gradient(135deg, #c5a3ff 25%, transparent 25%) -8px 0 / 16px 16px, linear-gradient(225deg, #c5a3ff 25%, transparent 25%) -8px 0 / 16px 16px, #ece0ff; }
.theme-day .box:nth-child(6) { background: repeating-linear-gradient(90deg, #ffb27a 0 7px, #ffd8b8 7px 14px); }
.theme-day .box:nth-child(7) { background: radial-gradient(circle, #ff8fab 0 18%, transparent 20%) 0 0 / 14px 14px, radial-gradient(circle, #ffc2d1 0 14%, transparent 16%) 7px 7px / 14px 14px, #ffe6ec; }
.theme-day .box:nth-child(8) { background: repeating-linear-gradient(45deg, #7fd8cf 0 4px, #d4f3ef 4px 10px); }
.theme-day .box:nth-child(9) { background: radial-gradient(circle at 50% 50%, transparent 40%, #ffd166 41% 47%, transparent 48%) 0 0 / 18px 18px, #fff1c2; }

/* ---------- theme: matsuri night (pack) ---------- */
.theme-night {
  --page: radial-gradient(ellipse at 50% 0, #2b2f63, #12132b 70%);
  --page-ink: #f6e9d2;
  --panel: rgba(255, 255, 255, 0.06);
  --panel-edge: rgba(201, 162, 74, 0.45);
  --board: linear-gradient(160deg, #1e1b2e, #0e0d18);
  --frame: 3px solid #c9a24a;
  --frame-shadow: 0 0 0 6px #1a1626, 0 0 0 8px #c9a24a, 0 0 60px rgba(255, 140, 60, 0.25);
  --board-radius: 14px;
  --box: rgba(201, 162, 74, 0.18);
  --box-radius: 8px;
  --box-edge: 1px solid rgba(201, 162, 74, 0.6);
  --cell: linear-gradient(180deg, #2a2540, #1f1b30);
  --cell-out: rgba(255, 255, 255, 0.03);
  --cell-shadow: #15121f;
  --cell-radius: 6px;
  --cell-lift: inset 0 1px 0 rgba(255, 255, 255, 0.08);
  --face-ink: rgba(246, 233, 210, 0.6);
  --digit-stroke: 0;
  --digit-glow: 0 0 8px currentColor, 0 0 16px currentColor;
  /* Sumi is the one digit colour that vanishes on lacquer; lifted so 九 is as
     legible here as in the free theme. */
  --d9: #d9d2c4;
}

/* ---------- page ---------- */
* { box-sizing: border-box; }
html { background: #2a2824; }
body {
  margin: 0;
  min-height: 100vh;
  background: var(--page);
  color: var(--page-ink);
  font: 500 16px/1.5 var(--body);
  transition: background 300ms ease;
}
button { font: inherit; color: inherit; }

.topbar {
  display: flex; align-items: center; gap: 18px; flex-wrap: wrap;
  max-width: 1320px; margin: 0 auto; padding: 16px 16px 6px;
}
.brand { display: flex; align-items: baseline; gap: 10px; text-decoration: none; color: inherit; }
.brand-mark, .brand-word {
  font-family: var(--display);
  color: var(--cream);
  -webkit-text-stroke: 0.07em var(--ink);
  paint-order: stroke fill;
  text-shadow: 0.05em 0.07em 0 var(--hanko-deep);
}
.brand-mark { font-size: 34px; }
.brand-word { font-size: 20px; letter-spacing: 0.06em; }
.spacer { flex: 1; }
.themes { display: flex; gap: 4px; }
.themes button, .seed-field button {
  border: 1px solid var(--panel-edge); background: var(--panel); border-radius: 999px;
  padding: 4px 12px; font-size: 13px; cursor: pointer;
}
.themes button small { opacity: 0.6; font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; }
.themes button[aria-pressed='true'] { background: var(--hanko); color: var(--cream); border-color: var(--hanko-deep); }
.sound-toggle {
  border: 1px solid var(--panel-edge); background: var(--panel); border-radius: 999px;
  padding: 3px 12px; cursor: pointer; font: 400 15px var(--display); color: inherit;
}
.sound-toggle[aria-pressed='true'] { background: var(--hanko); color: var(--cream); border-color: var(--hanko-deep); }
.seed-field { display: flex; align-items: center; gap: 6px; font-size: 13px; }
.seed-field input {
  width: 120px; padding: 4px 8px; border: 1px solid var(--panel-edge); border-radius: 6px;
  background: var(--panel); color: inherit; font: 600 14px var(--body);
}

/* ---------- table layout ---------- */
.table {
  display: grid;
  grid-template-columns: 220px minmax(0, 640px) minmax(260px, 320px);
  gap: 22px;
  justify-content: center;
  align-items: start;
  max-width: 1320px; margin: 0 auto; padding: 10px 16px 48px;
}
@media (max-width: 1180px) {
  .table { grid-template-columns: minmax(0, 640px) minmax(260px, 320px); }
  .hand { grid-column: 1 / -1; display: flex; flex-wrap: wrap; gap: 14px; align-items: center; }
}
@media (max-width: 820px) {
  .table { grid-template-columns: minmax(0, 1fr); }
  .topbar .themes { order: 3; width: 100%; overflow-x: auto; }
}

.hand, .side { display: flex; flex-direction: column; gap: 14px; }

.ledger {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; margin: 0;
  padding: 12px; background: var(--panel); border: 1px solid var(--panel-edge); border-radius: 10px;
}
.ledger div { min-width: 0; }
.ledger dt { font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase; opacity: 0.7; }
.ledger dd { margin: 0; font: 400 26px/1.1 var(--display); }
.ledger .ante dd { color: var(--hanko); }
.ledger .ante dd small { font: 700 12px var(--body); color: var(--page-ink); opacity: 0.8; margin-left: 4px; }
.ledger dd.bump { animation: bump 420ms var(--bounce); }
@keyframes bump { 0% { transform: scale(1); } 40% { transform: scale(1.35); } 100% { transform: scale(1); } }

.tools { display: flex; flex-direction: column; gap: 8px; }
@media (max-width: 1180px) { .tools { flex-direction: row; flex-wrap: wrap; } }
.tool {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 12px; border-radius: 12px; cursor: pointer;
  background: var(--panel); border: 2px solid var(--panel-edge);
  box-shadow: 0 3px 0 var(--panel-edge);
  transition: transform 120ms ease, box-shadow 120ms ease;
}
.tool:hover { transform: translateY(-1px); }
.tool:active { transform: translateY(2px) scale(0.98); box-shadow: 0 1px 0 var(--panel-edge); }
.tool[aria-pressed='true'] { border-color: var(--hanko); box-shadow: 0 3px 0 var(--hanko-deep); }
.tool:disabled { opacity: 0.45; cursor: not-allowed; transform: none; }
.tool-icon {
  width: 34px; height: 34px; display: grid; place-items: center; flex: none;
  font: 800 18px/1 var(--numeral);
}
.koma-icon { clip-path: polygon(50% 0, 88% 18%, 100% 100%, 0 100%, 12% 18%); background: linear-gradient(160deg, #f6dfa6, #d9ae62 55%, #b98a45); color: var(--ink); padding-top: 6px; }
.hanko-icon { background: var(--hanko); color: var(--cream); border-radius: 4px; transform: rotate(-6deg); font-family: var(--display); font-weight: 400; }
.marks-icon { border: 2px dashed currentColor; border-radius: 6px; font-family: var(--display); font-weight: 400; }
.tool-label { font-size: 15px; font-weight: 700; }
.tool-label b { font: 400 18px var(--display); color: var(--hanko); margin-left: 4px; }
.how { margin: 0; font-size: 13px; opacity: 0.8; }

/* ---------- the board ---------- */
.board-wrap, .board-stage { position: relative; }

/* ---------- the arena: rival, board, you (the bible, s6) ----------
   A ranked match seats the two players either side of the board, as the duel
   art does. The strip dissolves into the grid so each seat is its own column. */
[data-mode='ranked'] .table { grid-template-columns: 200px minmax(0, 860px) minmax(260px, 300px); }
.board-wrap.arena {
  display: grid; grid-template-columns: 124px minmax(0, 1fr) 124px; grid-template-areas: 'rival stage me';
  gap: 12px; align-items: start;
}
.board-wrap.arena .match-strip { display: contents; }
.board-wrap.arena .board-stage { grid-area: stage; }
.board-wrap.arena .seat {
  flex-direction: column; justify-content: flex-start; text-align: center; gap: 6px; padding: 12px 8px;
  border: 3px solid var(--ink); border-radius: 12px; background: var(--cream); color: var(--ink);
  box-shadow: 0 4px 0 var(--ink); position: sticky; top: 12px;
}
.board-wrap.arena .seat.rival { grid-area: rival; border-color: #23395d; box-shadow: 0 4px 0 #23395d; }
.board-wrap.arena .seat.me { grid-area: me; border-color: var(--hanko); box-shadow: 0 4px 0 var(--hanko-deep); }
.board-wrap.arena .seat-face { width: 76px; height: 76px; font-size: 34px; }
.board-wrap.arena .seat-text { justify-items: center; max-width: 100%; }
.board-wrap.arena .seat-text b { max-width: 108px; }
.board-wrap.arena .seat-sub, .board-wrap.arena .seat.rival .seat-sub { justify-content: center; }
.board-wrap.arena .vs { display: none; }
.seat-cap { display: none; }
.board-wrap.arena .seat-cap { display: block; font: 800 10px var(--body); letter-spacing: 0.2em; text-transform: uppercase; opacity: 0.6; }
.seat-note { display: none; }
.board-wrap.arena .seat-note { display: block; font-size: 12px; line-height: 1.35; opacity: 0.8; }
@media (max-width: 1180px) {
  [data-mode='ranked'] .table { grid-template-columns: minmax(0, 780px) minmax(260px, 300px); }
}
@media (max-width: 820px) {
  [data-mode='ranked'] .table { grid-template-columns: minmax(0, 1fr); }
  /* A phone keeps the rival on the left and you on the right, side by side
     over the board, so the scene reads the same way round. */
  .board-wrap.arena { grid-template-columns: 1fr auto 1fr; grid-template-areas: 'rival vs me' 'stage stage stage'; gap: 8px; }
  .board-wrap.arena .vs { display: block; grid-area: vs; align-self: center; }
  .board-wrap.arena .seat { flex-direction: row; text-align: left; padding: 6px 8px; position: static; }
  .board-wrap.arena .seat.rival { flex-direction: row-reverse; text-align: right; }
  .board-wrap.arena .seat-face { width: 40px; height: 40px; font-size: 20px; }
  .board-wrap.arena .seat-text { justify-items: start; }
  .board-wrap.arena .seat.rival .seat-text { justify-items: end; }
  .board-wrap.arena .seat-text b { max-width: 26vw; font-size: 15px; }
  .board-wrap.arena .seat-cap, .board-wrap.arena .seat-note { display: none; }
}
.board {
  position: relative;
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 7px;
  padding: 12px; aspect-ratio: 1;
  background: var(--board); border: var(--frame); border-radius: var(--board-radius);
  box-shadow: var(--frame-shadow);
}
.board.shake { animation: shake 360ms ease-in-out; }
@keyframes shake {
  20% { transform: translate(-4px, 2px) rotate(-0.4deg); }
  40% { transform: translate(4px, -2px) rotate(0.4deg); }
  60% { transform: translate(-3px, 1px); }
  80% { transform: translate(2px, -1px); }
}
.box {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 3px; padding: 3px;
  background: var(--box); border-radius: var(--box-radius); border: var(--box-edge);
}

.sq {
  position: relative; display: grid; place-items: center;
  aspect-ratio: 1; min-width: 0; padding: 0; overflow: visible;
  border: 0; border-radius: var(--cell-radius);
  background: var(--cell); box-shadow: var(--cell-lift);
  cursor: pointer;
  transition: transform 140ms ease, filter 140ms ease;
}
.sq:not(:disabled):hover { transform: translateY(-2px) scale(1.04); z-index: 2; }
.sq:disabled { cursor: default; }
.sq:focus-visible { outline: 3px solid var(--hanko); outline-offset: 1px; z-index: 3; }
/* Out of the bag beats in shadow: a square with no petals cannot be played,
   and that is the first thing the eye needs. Never filter a whole square to
   show this, because a filter greys the digit too and a theme may not make a
   digit harder to read. */
.sq.shadow { background: var(--cell-shadow); }
.sq.out, .sq.out.shadow { background: var(--cell-out); box-shadow: none; }
.sq.out .face { opacity: 0.35; }

.sq .face { position: absolute; top: 3px; left: 5px; font: 700 10px/1 var(--body); color: var(--face-ink); }
.sq .digit {
  font: 800 clamp(17px, 3.1vw, 30px)/1 var(--numeral);
  -webkit-text-stroke: var(--digit-stroke) var(--ink); paint-order: stroke fill;
  text-shadow: var(--digit-glow);
  pointer-events: none;
}
.sq .digit.fresh { animation: brushin 520ms var(--bounce) both; }
@keyframes brushin {
  0% { opacity: 0; transform: scale(1.9) rotate(-12deg); filter: blur(3px); }
  60% { opacity: 1; transform: scale(0.9) rotate(3deg); filter: blur(0); }
  100% { transform: scale(1) rotate(0); }
}
.sq .pips { position: absolute; bottom: 3px; right: 3px; display: flex; gap: 1px; align-items: center; font: 700 9px var(--body); }
.sq .pips i {
  width: 7px; height: 7px; border-radius: 60% 0 60% 0; transform: rotate(-20deg);
  background: var(--sakura); border: 1px solid rgba(0, 0, 0, 0.25);
}
.sq.tided .pips i:last-child { animation: pop 520ms var(--bounce) both; }
@keyframes pop { 0% { transform: scale(0) rotate(-20deg); } 70% { transform: scale(1.6) rotate(-20deg); } 100% { transform: scale(1) rotate(-20deg); } }

.sq .marks {
  /* Starts below the square number, which sits in the top left corner. */
  position: absolute; inset: 13px 3px 2px; display: grid; grid-template-columns: repeat(3, 1fr);
  font: 700 8px/1 var(--body); place-items: center; color: var(--face-ink); pointer-events: none;
}

/* koma: a shogi piece, this round's spot */
.sq .koma {
  position: absolute; inset: 9% 13% 5%; z-index: 2;
  clip-path: polygon(50% 0, 88% 18%, 100% 100%, 0 100%, 12% 18%);
  background: linear-gradient(160deg, #f6dfa6, #d9ae62 55%, #b98a45);
  filter: drop-shadow(0 2px 0 rgba(0, 0, 0, 0.35));
  display: grid; place-items: center; padding-top: 16%;
  font: 800 clamp(12px, 1.9vw, 19px)/1 var(--numeral); color: var(--ink);
  animation: placekoma 380ms var(--bounce) both;
  pointer-events: none;
}
@keyframes placekoma { 0% { transform: translateY(-40%) scale(1.3, 0.7); opacity: 0; } 60% { transform: translateY(4%) scale(0.92, 1.1); opacity: 1; } 100% { transform: none; } }
.theme-night .sq .koma { filter: drop-shadow(0 0 6px rgba(255, 190, 90, 0.8)); }

/* hanko: a seal. Pending (this round, unresolved) is a ghost; sealed is solid. */
.sq .hanko {
  position: absolute; inset: 12%; z-index: 1; border-radius: 4px;
  display: grid; place-items: center; transform: rotate(-7deg);
  background: var(--hanko); color: #fff4ea;
  box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.55), inset 0 0 6px rgba(0, 0, 0, 0.35);
  font: 400 clamp(15px, 2.4vw, 24px)/1 var(--display);
  pointer-events: none;
}
.theme-night .sq .hanko { box-shadow: 0 0 14px rgba(255, 80, 60, 0.8), inset 0 0 0 2px rgba(255, 255, 255, 0.55); }
.sq .hanko.pending {
  background: transparent; color: var(--hanko);
  box-shadow: inset 0 0 0 2px var(--hanko);
  animation: hover-seal 1.4s ease-in-out infinite alternate;
}
@keyframes hover-seal { from { transform: rotate(-7deg) translateY(-2px); } to { transform: rotate(-4deg) translateY(1px); } }
.sq .hanko.slam { animation: slam 520ms cubic-bezier(.3, 1.6, .5, 1) both; }
@keyframes slam {
  0% { transform: rotate(-20deg) scale(2.4); opacity: 0; }
  55% { transform: rotate(-5deg) scale(0.86); opacity: 1; }
  75% { transform: rotate(-8deg) scale(1.06); }
  100% { transform: rotate(-7deg) scale(1); }
}

/* blot: a wrong seal. The true digit shows through, greyed. */
.sq .blot {
  position: absolute; inset: -8%; z-index: 1; pointer-events: none;
  background:
    radial-gradient(circle at 28% 72%, #111 0 7%, transparent 8%),
    radial-gradient(circle at 80% 20%, #111 0 5%, transparent 6%),
    radial-gradient(circle at 50% 50%, #151311 0 34%, transparent 36%),
    radial-gradient(ellipse at 40% 42%, #151311 0 30%, transparent 31%),
    radial-gradient(ellipse at 62% 58%, #151311 0 29%, transparent 30%);
}
.sq .blot.spread { animation: spread 700ms cubic-bezier(.2, .9, .3, 1) both; }
@keyframes spread { 0% { transform: scale(0.1) rotate(-30deg); opacity: 0.4; } 100% { transform: scale(1) rotate(0); opacity: 1; } }
.sq.blotted .digit { position: relative; z-index: 2; color: #8d8a84 !important; text-shadow: none; -webkit-text-stroke: 0; }

/* targeting and selection */
.sq.targetable { outline: 2px dashed var(--hanko); outline-offset: -3px; }
.sq.targeted { outline: 3px solid var(--hanko); outline-offset: -3px; }
.sq.picking { outline: 3px solid var(--hanko); outline-offset: -3px; z-index: 3; }

/* the hit: squash, a blade cut and a petal burst */
.sq.hit { animation: squash 420ms var(--bounce); z-index: 3; }
@keyframes squash { 0% { transform: scale(1); } 30% { transform: scale(1.22, 0.82); } 60% { transform: scale(0.9, 1.1); } 100% { transform: scale(1); } }
.sq.hit::before {
  content: ''; position: absolute; left: -35%; right: -35%; top: 48%; height: 4px; z-index: 5;
  background: linear-gradient(90deg, transparent, #fff 25%, #fff 75%, transparent);
  box-shadow: 0 0 10px 2px rgba(255, 255, 255, 0.95);
  transform: rotate(-28deg) scaleX(0); animation: slash 520ms ease-out both;
}
@keyframes slash { 0% { transform: rotate(-28deg) scaleX(0); opacity: 1; } 35% { transform: rotate(-28deg) scaleX(1); opacity: 1; } 100% { transform: rotate(-28deg) scaleX(1); opacity: 0; } }
.sq.hit::after {
  content: ''; position: absolute; inset: -45%; z-index: 4; pointer-events: none;
  background:
    radial-gradient(ellipse 6% 9% at 20% 30%, #f7a6c1 90%, transparent),
    radial-gradient(ellipse 7% 5% at 80% 25%, #f7a6c1 90%, transparent),
    radial-gradient(ellipse 5% 8% at 75% 80%, #f9c2d4 90%, transparent),
    radial-gradient(ellipse 8% 5% at 25% 78%, #f9c2d4 90%, transparent),
    radial-gradient(ellipse 5% 7% at 50% 8%, #f7a6c1 90%, transparent),
    radial-gradient(ellipse 6% 5% at 92% 55%, #f7a6c1 90%, transparent);
  animation: burst 700ms ease-out both;
}
@keyframes burst { 0% { opacity: 0; transform: scale(0.4) rotate(0); } 25% { opacity: 1; } 100% { opacity: 0; transform: scale(1.3) rotate(40deg); } }
.sq.scored { background: #fff1a8; }
.theme-night .sq.scored { background: radial-gradient(circle, #ffb35c, #b8442a); }
.sq.missed { filter: brightness(0.92); }

/* the ward chain: every shown square of a warded digit pulses in its colour */
.sq.ward { animation: ward 760ms ease-out both; animation-delay: var(--chain, 0s); z-index: 2; }
@keyframes ward {
  0% { box-shadow: 0 0 0 0 transparent; }
  35% { box-shadow: 0 0 0 3px var(--wc), 0 0 18px 5px var(--wc); transform: scale(1.08); }
  100% { box-shadow: 0 0 0 0 transparent; transform: scale(1); }
}

/* ---------- fx layer: petals in flight, popups, the verdict stamp ---------- */
.fx { position: absolute; inset: 0; pointer-events: none; z-index: 10; }
.petal {
  position: absolute; left: 0; top: 0; width: 26px; height: 21px; margin: -10px 0 0 -13px;
  border-radius: 70% 0 70% 0; border: 1px solid rgba(0, 0, 0, 0.18);
  background: radial-gradient(circle at 30% 30%, #ffe4ec, #f4a3bb 65%, #e07a98);
  display: grid; place-items: center; font: 700 9px/1 var(--body); color: #6b1d3a;
}
.pop {
  position: absolute; transform: translate(-50%, -50%);
  font: 400 22px/1 var(--display); color: var(--cream);
  -webkit-text-stroke: 0.08em var(--ink); paint-order: stroke fill;
  text-shadow: 0.05em 0.07em 0 var(--hanko-deep);
  animation: floatup 900ms ease-out both; white-space: nowrap;
}
.pop.big { font-size: 34px; }
.pop.bad { color: #ffd2cc; text-shadow: 0.05em 0.07em 0 #000; }
@keyframes floatup {
  0% { opacity: 0; transform: translate(-50%, -20%) scale(0.4); }
  25% { opacity: 1; transform: translate(-50%, -60%) scale(1.15); }
  100% { opacity: 0; transform: translate(-50%, -160%) scale(1); }
}
.verdict-stamp {
  position: absolute; left: 50%; top: 50%; width: 46%; aspect-ratio: 1;
  display: grid; place-items: center; border-radius: 12px;
  font: 400 clamp(90px, 18vw, 190px)/1 var(--display); color: #fff4ea;
  background: var(--hanko); box-shadow: inset 0 0 0 8px rgba(255, 255, 255, 0.6), 0 20px 40px rgba(0, 0, 0, 0.35);
  transform: translate(-50%, -50%) rotate(-8deg);
  animation: verdict 1500ms cubic-bezier(.3, 1.6, .5, 1) both;
}
.verdict-stamp.lost { background: var(--ink); color: #e9dcc4; }
@keyframes verdict {
  0% { opacity: 0; transform: translate(-50%, -50%) rotate(-25deg) scale(2.6); }
  30% { opacity: 1; transform: translate(-50%, -50%) rotate(-6deg) scale(0.9); }
  42% { transform: translate(-50%, -50%) rotate(-9deg) scale(1.04); }
  80% { opacity: 1; transform: translate(-50%, -50%) rotate(-8deg) scale(1); }
  100% { opacity: 0; transform: translate(-50%, -50%) rotate(-8deg) scale(1); }
}

/* ---------- digit picker ---------- */
.picker {
  position: absolute; z-index: 20; width: 168px; padding: 8px;
  background: var(--cream); border: 3px solid var(--ink); border-radius: 12px;
  box-shadow: 0 6px 0 var(--ink), 0 16px 30px rgba(0, 0, 0, 0.3);
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 5px;
  animation: pickerin 260ms var(--bounce) both; color: var(--ink);
}
.picker[hidden] { display: none; }
@keyframes pickerin { from { opacity: 0; transform: scale(0.6); } }
.picker .title { grid-column: 1 / -1; font: 700 12px var(--body); text-align: center; }
.picker button {
  aspect-ratio: 1; border-radius: 8px; border: 2px solid var(--ink); background: #fff;
  font: 800 22px/1 var(--numeral); cursor: pointer; display: grid; place-items: center;
  box-shadow: 0 2px 0 var(--ink);
}
.picker button:hover { transform: translateY(-1px) scale(1.06); }
.picker button.unlikely { opacity: 0.35; }
.picker .cancel { grid-column: 1 / -1; aspect-ratio: auto; font: 700 12px var(--body); padding: 4px; }

/* ---------- modes, account, the daily ---------- */
.modes { display: flex; gap: 4px; margin-left: 8px; }
.modes a {
  text-decoration: none; color: inherit; font: 700 13px var(--body); letter-spacing: 0.08em; text-transform: uppercase;
  padding: 4px 10px; border-radius: 999px; border: 1px solid transparent;
}
body:not(.mode-remote) #mode-practice, [data-mode='daily'] #mode-daily, [data-mode='ranked'] #mode-ranked { border-color: var(--hanko); color: var(--hanko); }
.mode-remote .seed-field { display: none; }
.match-strip {
  display: flex; align-items: center; gap: 8px; margin-bottom: 10px; padding: 8px 14px;
  border-radius: 10px; border: 2px solid var(--ink); background: var(--cream); color: var(--ink); font-size: 15px;
  box-shadow: 0 3px 0 var(--ink);
}
.match-strip[hidden] { display: none; }
.match-strip { justify-content: space-between; gap: 10px; }
.match-strip .vs { font: 400 26px var(--display); color: var(--hanko); flex: none; }
.seat { display: flex; align-items: center; gap: 8px; min-width: 0; flex: 1; }
.seat.rival { flex-direction: row-reverse; text-align: right; }
.seat-face {
  display: grid; place-items: center; width: 48px; height: 48px; flex: none; border: 3px solid var(--ink);
  border-radius: 10px; background: #fff; font: 400 22px var(--display); overflow: hidden;
}
.seat.me .seat-face { border-color: var(--hanko); }
.seat-face img.face { width: 100%; height: 100%; border: 0; border-radius: 0; image-rendering: pixelated; }
.seat-text { display: grid; min-width: 0; }
.seat-text b { font: 400 18px var(--display); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.seat-sub { display: flex; gap: 6px; align-items: center; font-weight: 700; opacity: 0.8; font-size: 14px; }
.seat.rival .seat-sub { justify-content: flex-end; }
img.flag { width: 20px; height: auto; border-radius: 2px; box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25); }

/* ---------- CLASH: scan -> lock -> VS (web/js/clash.js) ---------- */
.clash {
  position: fixed; inset: 0; z-index: 50; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 14px; padding: 16px; color: #f6e9d2; background: radial-gradient(ellipse at 50% 30%, #2b2f63, #12132b 70%);
}
.clash[hidden] { display: none; }
.clash-globe { position: relative; width: min(520px, 92vw); aspect-ratio: 1; max-height: 46vh; }
.clash-globe canvas { width: 100%; height: 100%; display: block; }
.clash-ticker { position: absolute; left: 0; right: 0; top: 8px; text-align: center; font: 400 18px var(--display); color: var(--sakura); letter-spacing: 0.2em; }
.clash-seats { display: flex; align-items: center; gap: 14px; }
.clash-seat { display: grid; justify-items: center; gap: 4px; width: min(170px, 38vw); text-align: center; }
.clash-seat .seat-face { width: min(120px, 28vw); height: min(120px, 28vw); border: 4px solid #f6e9d2; border-radius: 16px; color: var(--ink); font-size: 48px; box-shadow: 0 6px 0 rgba(0, 0, 0, 0.5); }
.clash-seat.mine .seat-face { border-color: var(--hanko); }
.clash-seat .seat-name { font: 400 20px var(--display); max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.clash-seat .seat-meta { display: flex; gap: 6px; align-items: center; font-weight: 700; }
.clash-seat .seat-badge { font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase; opacity: 0.7; }
.clash-vs { font: 400 56px var(--display); color: var(--hanko); text-shadow: 0 3px 0 #000; }
.clash[data-beat='scan'] .clash-seat.rival .seat-face { animation: clash-wait 900ms ease-in-out infinite alternate; }
@keyframes clash-wait { from { opacity: 0.35; } to { opacity: 1; } }
.clash[data-beat='vs'] .clash-seat { animation: clash-in 420ms var(--bounce) both; }
.clash[data-beat='vs'] .clash-seat.rival { animation-delay: 120ms; }
@keyframes clash-in { from { transform: scale(0.6); opacity: 0; } }
.clash-status { margin: 0; max-width: 520px; text-align: center; font-size: 16px; }
.clash-go { visibility: hidden; font-size: 22px; }
.clash[data-beat='vs'] .clash-go { visibility: visible; }
@media (prefers-reduced-motion: reduce) {
  .clash .clash-seat, .clash .seat-face { animation: none !important; }
}
.verdict .delta { margin: 4px 0; font: 400 54px/1 var(--display); }
.verdict .delta.up { color: #2f8a3a; }
.verdict .delta.down { color: var(--hanko); }
.duel { margin: 8px auto 10px; border-collapse: collapse; font-size: 15px; }
.duel th, .duel td { padding: 3px 12px; text-align: center; }
.duel th { font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase; opacity: 0.7; }
.duel tr.mine td { font-weight: 700; color: var(--hanko); }
.verdict code { font-size: 11px; word-break: break-all; }
.verdict .small { font-size: 12px; opacity: 0.75; }
.face-link {
  display: inline-grid; place-items: center; width: 34px; height: 34px; flex: none;
  border: 2px solid var(--ink); border-radius: 10px; background: var(--cream); color: var(--ink);
  font: 400 16px var(--display); text-decoration: none; box-shadow: 0 2px 0 var(--ink); overflow: hidden;
}
.face-link img.face { width: 100%; height: 100%; image-rendering: pixelated; background: #fff; }
.face-slot { display: inline-flex; vertical-align: middle; margin-right: 6px; }
.face-slot:empty { display: none; }
.face-slot img.face { width: 26px; height: 26px; border-radius: 6px; border: 2px solid var(--ink); background: #fff; image-rendering: pixelated; }
.duel .face-slot img.face { width: 28px; height: 28px; }
.account-button {
  border: 2px solid var(--ink); background: var(--cream); color: var(--ink); border-radius: 999px;
  padding: 3px 14px; font: 400 14px var(--display); cursor: pointer; box-shadow: 0 2px 0 var(--ink); text-decoration: none;
}
dialog.account {
  border: 3px solid var(--ink); border-radius: 14px; padding: 20px; width: min(380px, 92vw);
  background: var(--cream); color: var(--ink); box-shadow: 0 6px 0 var(--ink);
}
dialog.account::backdrop { background: rgba(29, 26, 22, 0.55); }
dialog.account h2 { margin: 0 0 4px; font: 400 26px var(--display); }
dialog.account .small { margin: 0 0 12px; font-size: 13px; opacity: 0.8; }
dialog.account label { display: grid; gap: 3px; margin-bottom: 10px; font-weight: 700; font-size: 14px; }
dialog.account input { padding: 8px 10px; border: 2px solid var(--ink); border-radius: 8px; font: 500 16px var(--body); background: #fff; }
dialog.account:not([data-mode='signup']) .when-signup,
dialog.account:not([data-mode='link']) .when-link,
dialog.account[data-mode='link'] .when-password { display: none; }
dialog.account .sent { margin: 0 0 10px; font-weight: 700; color: var(--d4); }
dialog.account .account-links { display: flex; gap: 12px; flex-wrap: wrap; justify-content: space-between; margin: 10px 0 0; }
dialog.account .error { color: var(--hanko); min-height: 1.2em; margin: 0 0 8px; font-weight: 700; }
dialog.account .row { align-items: center; }
.link { border: 0; background: none; text-decoration: underline; cursor: pointer; font-size: 14px; }
.verdict h3 { margin: 14px 0 6px; font: 400 18px var(--display); }
.verdict .nudge { color: var(--hanko); font-weight: 700; }
.daily-board { list-style: none; margin: 0 0 12px; padding: 0; display: grid; gap: 3px; text-align: left; font-size: 14px; }
.daily-board li { display: grid; grid-template-columns: 28px 1fr auto 34px; gap: 8px; padding: 4px 8px; border-radius: 6px; background: rgba(255, 255, 255, 0.5); }
.daily-board li.mine { background: var(--hanko); color: var(--cream); font-weight: 700; }
.daily-board li.empty { display: block; opacity: 0.7; }
@media (max-width: 820px) { .modes { margin-left: 0; } }

/* ---------- the first run's coach ---------- */
.coach {
  position: relative; padding: 16px 16px 14px; border-radius: 12px;
  background: var(--cream); color: var(--ink);
  border: 3px solid var(--ink); box-shadow: 0 5px 0 var(--ink);
  animation: pickerin 320ms var(--bounce) both;
}
.coach[hidden] { display: none; }
.coach h2 { margin: 0 0 6px; font: 400 22px/1.15 var(--display); }
.coach p { margin: 0 0 12px; font-size: 15px; }
.coach .coach-count { position: absolute; top: 10px; right: 12px; font: 700 12px var(--body); opacity: 0.6; }
.coach .row { align-items: center; }
.coach-skip { border: 0; background: none; text-decoration: underline; font-size: 13px; cursor: pointer; opacity: 0.7; }
/* What the lesson wants touched glows; it is the only thing that is enabled. */
.coach-target { position: relative; z-index: 4; animation: beckon 1.3s ease-in-out infinite; }
@keyframes beckon {
  0%, 100% { box-shadow: 0 0 0 2px var(--hanko), 0 0 0 0 rgba(200, 49, 42, 0.5); }
  50% { box-shadow: 0 0 0 3px var(--hanko), 0 0 0 9px rgba(200, 49, 42, 0); }
}
.board.coach-target { animation: none; box-shadow: var(--frame-shadow), 0 0 0 4px var(--hanko); }

/* ---------- tray, offers, verdict ---------- */
.tray { display: flex; flex-direction: column; gap: 12px; }
.prompt { font-weight: 700; }
.btn {
  text-decoration: none; display: inline-block;
  font: 400 20px/1 var(--display); padding: 0.55em 1.2em 0.62em;
  border: 0.12em solid var(--ink); border-radius: 0.45em; cursor: pointer;
  color: var(--cream); background: linear-gradient(180deg, #e2483f, var(--hanko) 60%, #a5241e);
  box-shadow: 0 0.2em 0 var(--ink), inset 0 0.12em 0 rgba(255, 255, 255, 0.35);
  transition: transform 120ms ease, box-shadow 120ms ease;
}
.btn.alt { color: var(--ink); background: linear-gradient(180deg, #fff6e4, #f1dfbd 70%); }
.btn:hover:not(:disabled) { transform: translateY(-1px) scale(1.03); }
.btn:active:not(:disabled) { transform: translateY(0.14em) scale(0.97, 0.94); box-shadow: 0 0.06em 0 var(--ink); }
.btn:disabled { filter: grayscale(0.7); opacity: 0.55; cursor: not-allowed; }
/* Glow, not scale: a button that never stops moving is a button an automated
   click (and a hurried thumb) can never land on cleanly. */
.btn.ready { animation: ready 1.6s ease-in-out infinite; }
@keyframes ready { 50% { box-shadow: 0 0.2em 0 var(--ink), 0 0 0 0.25em rgba(200, 49, 42, 0.35), 0 0 1.2em rgba(255, 120, 90, 0.7); } }
.row { display: flex; gap: 8px; flex-wrap: wrap; }

.ofuda-row { display: grid; gap: 10px; }
.ofuda {
  position: relative; text-align: left; cursor: pointer;
  padding: 14px 14px 12px 16px; border-radius: 6px;
  background: linear-gradient(180deg, #fffaf0, #f6ead2); color: var(--ink);
  border: 2px solid var(--ink); border-top: 10px solid var(--hanko);
  box-shadow: 0 4px 0 var(--ink);
  animation: dealt 480ms var(--bounce) both;
  transition: transform 140ms ease;
}
.ofuda:nth-child(2) { animation-delay: 90ms; }
.ofuda:nth-child(3) { animation-delay: 180ms; }
@keyframes dealt { from { opacity: 0; transform: translateY(30px) rotate(6deg) scale(0.8); } }
.ofuda:hover:not(:disabled) { transform: translateY(-3px) rotate(-1deg); }
.ofuda:disabled { cursor: default; }
.ofuda.chosen { outline: 4px solid var(--hanko); }
.ofuda h3 { margin: 0 0 2px; font: 400 20px/1.1 var(--display); }
.ofuda .flavor { margin: 0 0 6px; font-size: 13px; font-style: italic; opacity: 0.75; }
.ofuda .effect { margin: 0; font-size: 15px; font-weight: 700; }
.ofuda .need { display: inline-block; margin-top: 6px; font-size: 12px; color: var(--hanko); font-weight: 700; }

.verdict { padding: 18px; border-radius: 12px; background: var(--panel); border: 2px solid var(--panel-edge); text-align: center; }
.verdict h2 { margin: 0; font: 400 26px/1.1 var(--display); }
.verdict .depth { margin: 6px 0; font: 400 64px/1 var(--display); color: var(--hanko); }
.verdict p { margin: 4px 0; }

.note { margin: 0; min-height: 1.5em; font-weight: 700; }

.record h2 { margin: 0 0 6px; font: 400 18px var(--display); }
.record ol { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; font-size: 14px; }
.record li { display: grid; grid-template-columns: 34px 70px 1fr; gap: 6px; padding: 4px 8px; border-radius: 6px; background: var(--panel); }
.record li.failed { color: var(--hanko); font-weight: 700; }
.record .seal-mark { font-family: var(--display); }

/* ---------- phone ---------- */
.ledger .short { display: none; }
@media (max-width: 820px) {
  .topbar { gap: 8px 10px; padding: 10px 10px 4px; }
  .brand-mark { font-size: 26px; }
  .brand-word { font-size: 14px; }
  .seed-field input { width: 92px; }
  .themes { gap: 4px; }
  .themes button { font-size: 12px; padding: 3px 9px; white-space: nowrap; }

  /* Board first: everything above it is squeezed to one line each, so the
     board starts in the top third of the screen instead of halfway down. */
  .table { gap: 10px; padding: 4px 8px 110px; }
  .hand { gap: 8px; }
  .ledger { grid-template-columns: repeat(5, 1fr); gap: 2px; padding: 6px 8px; width: 100%; }
  .ledger dt { font-size: 9px; letter-spacing: 0.06em; }
  .ledger dd { font-size: 20px; }
  .ledger .long { display: none; }
  .ledger .short { display: inline; }
  .ledger .ante dd small { display: block; margin: 0; font-size: 10px; }
  .tools { flex-direction: row; width: 100%; gap: 6px; }
  .tool { flex: 1; padding: 5px 6px; gap: 6px; justify-content: center; }
  .tool-icon { width: 28px; height: 28px; font-size: 15px; }
  .tool-label { font-size: 13px; }
  .marks-icon + .tool-label { font-size: 0; }
  .marks-icon + .tool-label::after { content: 'Marks'; font-size: 13px; }
  .how { display: none; }

  .board { padding: 6px; gap: 4px; }
  .theme-woodblock .board { border-width: 7px; }
  .box { gap: 2px; padding: 2px; }
  .sq .face { top: 1px; left: 2px; font-size: 7.5px; }
  .sq .digit { font-size: 19px; }
  .sq .hanko { font-size: 15px; }
  .sq .koma { font-size: 12px; }
  .sq .pips { bottom: 1px; right: 1px; }
  .sq .pips i { width: 5px; height: 5px; }
  .sq .marks { inset: 9px 1px 1px; font-size: 7px; }

  /* The fall button docks to the bottom edge, where a thumb already is. */
  #fall {
    position: fixed; left: 10px; right: 10px; z-index: 30; font-size: 18px;
    bottom: calc(10px + env(safe-area-inset-bottom));
  }
  /* Docked over the board, so it must stay opaque while it waits; the count
     it shows replaces the prompt line it would otherwise cover. */
  #fall:disabled { opacity: 1; filter: none; background: linear-gradient(180deg, #8d857a, #6f675d); }
  .tray .prompt { display: none; }
  /* The digit picker becomes a sheet on whichever half of the screen the
     named square is not on, so it never covers the square it names. */
  .picker.sheet {
    position: fixed; left: 8px !important; right: 8px; width: auto; top: auto !important; z-index: 40;
    bottom: calc(8px + env(safe-area-inset-bottom)); grid-template-columns: repeat(9, 1fr); gap: 4px;
  }
  .picker.sheet.up { top: calc(8px + env(safe-area-inset-top)) !important; bottom: auto; }
  .picker.sheet button { font-size: 19px; }
  /* The lesson's coach docks above the fall button and the page gets room to
     scroll every highlighted square clear of it. */
  .coach {
    position: fixed; left: 8px; right: 8px; z-index: 29; max-height: 42vh; overflow: auto;
    bottom: calc(76px + env(safe-area-inset-bottom)); padding: 12px 12px 10px;
  }
  .coach h2 { font-size: 18px; }
  .coach p { font-size: 14px; margin-bottom: 8px; }
  body.coaching .table { padding-bottom: 46vh; }
  /* While a digit is being named the sheet is the only thing at the bottom. */
  body.picking .coach, body.picking #fall { visibility: hidden; }
}

/* ---------- the painted set (web/js/art.js) ----------
   Every rule here is keyed on a has-art-* class, which art.js adds only once
   that image has loaded. Without it, the CSS-drawn look above stands. */

/* Woodblock wears the wood and the paper. The two packs keep their own looks. */
.has-art-washi-512 .theme-woodblock { background: var(--art-washi-512) 0 0 / 512px, #ece0c8; }
.has-art-kaya-512 .theme-woodblock .sq {
  background: var(--art-kaya-512) var(--grain-x) var(--grain-y) / 512px, #d8b47c;
}
/* Shadowed and out-of-play squares darken or grey the same wood with a wash,
   rather than a filter on the square: a filter would dim the digit as well. */
.has-art-kaya-512 .theme-woodblock .sq.shadow {
  background: linear-gradient(rgba(70, 45, 20, 0.38), rgba(70, 45, 20, 0.38)), var(--art-kaya-512) var(--grain-x) var(--grain-y) / 512px, #a98a62;
}
.has-art-kaya-512 .theme-woodblock .sq.out,
.has-art-kaya-512 .theme-woodblock .sq.out.shadow {
  background: linear-gradient(rgba(150, 140, 125, 0.62), rgba(150, 140, 125, 0.62)), var(--art-kaya-512) var(--grain-x) var(--grain-y) / 512px, #b79c78;
}
.has-art-kaya-512 .theme-woodblock .sq.scored {
  background: linear-gradient(rgba(255, 236, 160, 0.55), rgba(255, 236, 160, 0.55)), var(--art-kaya-512) var(--grain-x) var(--grain-y) / 512px, #f3d39c;
}

/* Wood is busier than the flat colour it replaces, so digits on it get a soft
   paper halo. Without it the lighter dyes (yamabuki 三, daidai 二) fade into
   the brighter grain, and a theme may not make a digit harder to read. */
.has-art-kaya-512 .theme-woodblock .sq .digit {
  -webkit-text-stroke: 0.04em var(--ink);
  text-shadow: 0 0 2px rgba(255, 249, 235, 0.95), 0 0 6px rgba(255, 249, 235, 0.85);
}

/* The hanko and the blot are game objects, so every theme gets the painted
   ones. The digit stays a font, over the stamp, exactly as before. */
.has-art-hanko .sq .hanko:not(.pending) {
  background: var(--art-hanko) center / 100% 100% no-repeat;
  box-shadow: none;
  border-radius: 0;
}
.has-art-blot .sq .blot { background: var(--art-blot) center / contain no-repeat; }

/* A falling petal becomes a painted one; the square number rides on it. */
.petal.painted {
  border: 0; border-radius: 0; width: 30px; height: 30px; margin: -15px 0 0 -15px;
  background: var(--petal) center / contain no-repeat;
  color: #5a1630; text-shadow: 0 0 3px #fff, 0 0 2px #fff;
}

/* Offer cards on the painted talisman. Stretched only sideways, which keeps
   its two bands level; the padding clears them. */
.has-art-ofuda .ofuda {
  background: var(--art-ofuda) center / 100% 100% no-repeat;
  border: 0;
  box-shadow: 0 5px 0 rgba(29, 26, 22, 0.55), 0 10px 18px rgba(0, 0, 0, 0.2);
  padding: 26px 22px 26px;
}
.has-art-ofuda .ofuda.chosen { outline-offset: 2px; }

/* Verdict pictures: the duel, a cleared run, a fallen one, the daily banner. */
.verdict-art {
  margin: -18px -18px 12px; border-radius: 10px 10px 0 0;
  background: center / cover no-repeat; aspect-ratio: 16 / 9;
  animation: dealt 520ms var(--bounce) both;
}
.verdict-art.banner { margin: 6px 0 10px; border-radius: 8px; aspect-ratio: 21 / 9; animation: none; }

/* The mon beside the wordmark. */
.has-art-mon .brand::before {
  content: ''; width: 38px; height: 38px; align-self: center; flex: none;
  background: var(--art-mon) center / contain no-repeat;
}
.brand { align-items: center; }

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

/* ---------- the sensei (web/js/sensei.js, the bible s8) ----------
   The old sword master at full size: the 1024 portrait shown big beside one
   line of rules. He sits in a corner and never covers the middle of the board. */
.rules-button {
  display: inline-grid; place-items: center; width: 34px; height: 34px; flex: none; cursor: pointer;
  border: 2px solid var(--ink); border-radius: 50%; background: var(--hanko); color: var(--cream);
  font: 400 17px var(--display); box-shadow: 0 2px 0 var(--ink);
}
.sensei {
  position: fixed; right: 16px; bottom: calc(16px + env(safe-area-inset-bottom)); z-index: 45;
  display: grid; grid-template-columns: minmax(0, 300px) 190px; grid-template-areas: 'say face'; align-items: end; gap: 0;
  pointer-events: none;
}
.sensei[hidden] { display: none; }
.sensei > * { pointer-events: auto; }
.sensei-portrait {
  grid-area: face; width: 190px; height: 190px; border: 4px solid var(--ink); border-radius: 50%; overflow: hidden;
  background: #efe3c9; box-shadow: 0 6px 0 var(--ink), 0 18px 40px rgba(0, 0, 0, 0.35);
  display: grid; place-items: center; position: relative; z-index: 1;
}
.sensei-portrait img { width: 100%; height: 100%; object-fit: cover; }
.sensei-glyph { font: 400 90px var(--display); color: var(--hanko); }
.sensei-bubble {
  grid-area: say; position: relative; margin: 0 -18px 40px 0; padding: 14px 34px 12px 18px;
  background: var(--cream); color: var(--ink); border: 3px solid var(--ink); border-radius: 14px;
  box-shadow: 0 5px 0 var(--ink), 0 14px 30px rgba(0, 0, 0, 0.25);
}
.sensei-tag { display: block; font: 800 12px var(--body); letter-spacing: 0.18em; text-transform: uppercase; color: var(--hanko); }
.sensei-bubble p { margin: 4px 0 10px; font: 600 16px/1.45 var(--body); }
.sensei-row { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.sensei.in .sensei-portrait { animation: sensei-in 520ms var(--bounce) both; }
.sensei.in .sensei-bubble { animation: sensei-say 420ms 160ms var(--bounce) both; }
@keyframes sensei-in { from { opacity: 0; transform: translateY(40px) scale(0.7); } }
@keyframes sensei-say { from { opacity: 0; transform: translateX(16px) scale(0.85); } }
@keyframes sensei-say-down { from { opacity: 0; transform: translateY(-12px) scale(0.85); } }
@media (prefers-reduced-motion: reduce) { .sensei.in .sensei-portrait, .sensei.in .sensei-bubble { animation: none; } }
@media (max-width: 820px) {
  /* On a phone he comes in from the top, clear of the docked fall button. */
  .sensei {
    left: 8px; right: 8px; bottom: auto; top: calc(8px + env(safe-area-inset-top));
    grid-template-columns: 112px minmax(0, 1fr); grid-template-areas: 'face say'; align-items: start;
  }
  .sensei-portrait { width: 112px; height: 112px; }
  .sensei-glyph { font-size: 50px; }
  .sensei-bubble { margin: 20px 0 0 -14px; padding: 10px 12px 10px 24px; }
  .sensei.in .sensei-bubble { animation-name: sensei-say-down; }
  .sensei-bubble p { font-size: 14px; }
}
dialog.account.rules-scroll { width: min(560px, 92vw); }
.rules { margin: 0 0 14px; padding-left: 1.3em; display: grid; gap: 7px; font-size: 15px; line-height: 1.45; }
.rules b { color: var(--hanko); }

/* The rivalry line on a ranked verdict: the record, the streak, the rank. */
.standing { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px; margin: 6px 0; }
.standing > span { padding: 3px 10px; border: 2px solid var(--ink); border-radius: 999px; background: var(--cream); font-weight: 700; font-size: 14px; }
.standing .streak { background: var(--hanko); color: var(--cream); }
.standing b { font-family: var(--numeral); }
.hook { margin: 2px 0 8px; font-weight: 800; color: var(--hanko); text-align: center; }

/* CLASH leads the nav: the one mode painted as a seal rather than a word. */
.modes a.clash-link { background: var(--hanko); color: var(--cream); border-color: var(--ink); box-shadow: 0 2px 0 var(--ink); }
[data-mode='ranked'] .modes a#mode-ranked.clash-link { color: var(--cream); border-color: var(--ink); }

/* ---------- the rest of the painted set ----------
   duel behind CLASH, the tree behind the tree's count, the blossoms behind a
   won stamp, and the daimyo in a seat no rival has taken yet. Each switches on
   only once its image has loaded. */
.has-art-duel .clash {
  background: linear-gradient(180deg, rgba(18, 19, 43, 0.55), rgba(18, 19, 43, 0.9) 60%), var(--art-duel) center top / cover no-repeat, #12132b;
}
.has-art-tree .ledger {
  background: linear-gradient(rgba(246, 236, 216, 0.84), rgba(246, 236, 216, 0.84)), var(--art-tree) center 30% / cover no-repeat, var(--panel);
}
.has-art-samurai-daimyo .seat-face.empty {
  background: var(--art-samurai-daimyo) center / cover no-repeat; color: #fff;
  text-shadow: 0 2px 0 var(--ink), 0 0 10px var(--ink); filter: grayscale(1) contrast(0.9);
}
.bloom {
  position: absolute; left: 50%; top: 50%; width: 90%; aspect-ratio: 1; pointer-events: none;
  background: var(--art-blossoms) center / contain no-repeat;
  transform: translate(-50%, -50%) scale(0.3); opacity: 0;
  animation: bloom 1600ms var(--bounce) both;
}
@keyframes bloom {
  35% { opacity: 1; transform: translate(-50%, -50%) scale(1.05) rotate(8deg); }
  100% { opacity: 0; transform: translate(-50%, -50%) scale(1.3) rotate(18deg); }
}
