/* css/battle-v2.css - tabletop battle layout, mats, battle effects, fishing v1.63, Character stage, glass pill, borders (v1.58 - v1.70).
   The CSS files are one stylesheet cut into pieces in cascade order (index.html links them in this order): a later rule
   overrides an earlier one. Append new rules to latest.css unless you know nothing later overrides them. */
/* ===== Tabletop battle layout (v1.58.0) =====
   The two boards sit on a tilted glass table (perspective on .field, rotateX on .table), Spirit is a ring around
   each portrait, and the hand fans out. Cards are dragged from the hand onto the table (see btStartDrag in
   js/battle-ui.js). These rules override the older flat-layout battle rules above; the element ids are unchanged. */
#battleView .side { background: none; border: 0; box-shadow: none; padding: 2px 8px; gap: 12px; border-left: 0; border-radius: 0; }
#battleView #btYouBar { border-left: 0; margin-bottom: 4px; }
#battleView .nmv { display: flex; flex-direction: column; min-width: 0; flex: 1; text-align: left; }
#battleView .nmv .who { font-family: var(--f-display); font-size: 1.1rem; font-weight: 500; flex: none; }
#battleView .spirit { position: relative; flex: none; width: 62px; height: 62px; border-radius: 50%; overflow: visible;
  background: conic-gradient(var(--ring, var(--water)) var(--p, 100%), color-mix(in srgb, var(--hl) 14%, transparent) 0); box-shadow: 0 0 14px color-mix(in srgb, var(--water) 30%, transparent); display: grid; place-items: center; }
#battleView .spirit .fill { display: none; }
#battleView .spirit .bt-portrait { width: calc(100% - 8px); height: calc(100% - 8px); font-size: 1.7rem; box-shadow: none; }
#battleView .spirit .num { inset: auto; right: -10px; bottom: -6px; width: auto; min-width: 38px; display: block; padding: 1px 6px; text-align: center; font-size: .66rem; background: var(--bg-bottom); border: 1px solid var(--water); border-radius: 999px; color: var(--ink); text-shadow: none; font-variant-numeric: tabular-nums; }
#battleView .side.turn .spirit { box-shadow: 0 0 0 2px var(--water), 0 0 18px color-mix(in srgb, var(--water) 55%, transparent); }
#battleView .side.target-glow { box-shadow: none; animation: none; }
#battleView .side.target-glow .spirit { box-shadow: 0 0 0 3px var(--boss-glow), 0 0 22px rgba(201,111,111,.7); animation: bt_tglow 1s ease-in-out infinite; }
#battleView .divider { position: relative; z-index: 3; justify-content: flex-start; padding: 0 10px; min-height: 26px; }
#battleView .divider .msg { background: color-mix(in srgb, var(--stone) 85%, transparent); }
#battleView .field { perspective: 900px; align-items: center; justify-content: center; padding: 2px 4px; flex-direction: row; }
#battleView .table { width: 100%; transform: rotateX(24deg); transform-origin: 50% 55%; padding: 6px; border-radius: 18px;
  background: linear-gradient(180deg, color-mix(in srgb, var(--water) 7%, transparent), color-mix(in srgb, var(--water) 18%, transparent));
  border: 1px solid color-mix(in srgb, var(--water) 35%, transparent); box-shadow: 0 30px 36px rgba(0,0,0,.4), inset 0 0 36px color-mix(in srgb, var(--water) 12%, transparent); }
#battleView .table .board { background: none; border: 0; padding: 6px 4px; }
#battleView .table #btYouBoard { border: 0; }
#battleView .seam { height: 2px; margin: 4px 12px; background: linear-gradient(90deg, transparent, var(--water), transparent); box-shadow: 0 0 12px var(--water); }
#battleView .coach { position: relative; z-index: 3; min-height: 18px; }
#battleView .hand { height: 120px; gap: 0; padding: 14px 6px 0; overflow: visible; }
#battleView .hand .hcard { margin: 0 -4px; height: 100px; transform: translateY(var(--dy, 0px)) rotate(var(--rot, 0deg)); transform-origin: 50% 150%; transition: transform .2s ease; }
#battleView .hand .card { touch-action: none; -webkit-user-select: none; user-select: none; }
/* dragging a card from the hand onto the table */
#battleView .card.drag-ghost { position: fixed; left: 0; top: 0; z-index: 60; margin: 0; pointer-events: none; transition: none; will-change: transform; animation: none; box-shadow: 0 16px 30px rgba(0,0,0,.5), 0 0 0 2px var(--water); }
#battleView .card.drag-origin { opacity: .25; filter: saturate(.4); }
#battleView .slot.drop-zone { border-color: rgba(141,188,203,.7); background: rgba(141,188,203,.1); }
#battleView .slot.drop-next { animation: bt_dropNext 1.2s ease-in-out infinite; }
@keyframes bt_dropNext { 50% { box-shadow: 0 0 14px 2px rgba(141,188,203,.6); } }
#battleView .slot.drop-hover { border-style: solid; border-color: var(--water); background: rgba(141,188,203,.3); box-shadow: 0 0 16px var(--water); animation: none; }
#battleView .table.cast-zone { box-shadow: 0 30px 36px rgba(0,0,0,.4), 0 0 0 2px var(--accent), 0 0 26px color-mix(in srgb, var(--accent) 45%, transparent); }
#battleView .card.drop-hover { box-shadow: 0 0 0 3px var(--c-grey-100), 0 0 20px rgba(255,240,180,.9); }

/* ===== Table mats and card decks (v1.59.0) ===== */
/* A mat is just a background + inset edge. The same .mat-* class dresses the player's row of the battle table
   (#btYouRow) and the little preview swatches in Customize and the Shop. */
.mat-glass   { background: linear-gradient(180deg, rgba(141,188,203,.05), rgba(141,188,203,.14)); box-shadow: inset 0 0 0 1px rgba(141,188,203,.28); }
.mat-moss    { background: repeating-linear-gradient(45deg, rgba(255,255,255,.04) 0 2px, transparent 2px 4px), radial-gradient(circle at 30% 20%, var(--c-green-35), var(--c-green-22-2) 78%); box-shadow: inset 0 0 0 2px var(--c-green-15), inset 0 0 22px rgba(0,0,0,.35); }
.mat-velvet  { background: linear-gradient(115deg, transparent 38%, rgba(255,255,255,.08) 50%, transparent 62%), linear-gradient(180deg, var(--c-indigo-31), var(--c-indigo-19)); box-shadow: inset 0 0 0 2px var(--c-indigo-12), inset 0 0 22px rgba(0,0,0,.4); }
.mat-linen   { background: repeating-linear-gradient(0deg, rgba(120,100,60,.13) 0 1px, transparent 1px 4px), repeating-linear-gradient(90deg, rgba(120,100,60,.13) 0 1px, transparent 1px 4px), var(--c-amber-77-3); box-shadow: inset 0 0 0 2px var(--c-amber-62), inset 0 0 18px rgba(120,100,60,.25); }
.mat-lacquer { background: linear-gradient(135deg, rgba(255,255,255,.16) 0, transparent 32%), linear-gradient(180deg, var(--c-red-33), var(--c-red-18)); box-shadow: inset 0 0 0 2px var(--c-amber-60), inset 0 0 0 4px var(--c-red-18), inset 0 0 18px rgba(0,0,0,.4); }
.mat-stars   { background: radial-gradient(1.5px 1.5px at 14% 26%, var(--c-grey-100), transparent), radial-gradient(1px 1px at 38% 70%, var(--c-blue-94), transparent), radial-gradient(1.5px 1.5px at 62% 30%, var(--c-grey-100), transparent), radial-gradient(1px 1px at 84% 62%, var(--c-grey-100), transparent), radial-gradient(1px 1px at 50% 12%, var(--c-blue-91), transparent), radial-gradient(1.5px 1.5px at 92% 20%, var(--c-grey-100), transparent), linear-gradient(180deg, var(--c-blue-14), var(--c-blue-21)); box-shadow: inset 0 0 0 2px var(--c-amber-72), inset 0 0 18px rgba(0,0,0,.4); }
.mat-aurora  { background: linear-gradient(120deg, rgba(60,200,150,.92), rgba(60,120,210,.92) 50%, rgba(150,80,200,.92)); box-shadow: inset 0 0 0 2px rgba(255,255,255,.35), inset 0 0 22px rgba(0,0,0,.3); }
.mat-swatch { position: relative; width: 100%; height: 46px; border-radius: 12px; border: 2px solid transparent; cursor: pointer; display: flex; align-items: flex-end; justify-content: center; padding: 0 4px 3px; overflow: visible; }
.mat-swatch > span:first-child { font-size: .58rem; font-weight: 700; color: var(--c-grey-100); text-shadow: 0 1px 2px rgba(0,0,0,.8); line-height: 1.05; text-align: center; }
.mat-swatch.mat-linen > span:first-child { color: var(--c-amber-16-2); text-shadow: none; }
.mat-swatch.mat-glass { background: linear-gradient(180deg, var(--c-cyan-36), var(--c-cyan-26)); }
.mat-swatch.active { border-color: var(--water); box-shadow: 0 0 0 2px var(--water); }
.mat-swatch.locked { opacity: .55; }
.mat-swatch:active { transform: scale(.96); }
.mat-row { grid-template-columns: repeat(auto-fill, minmax(92px, 1fr)); }
.shop-mat-row { grid-template-columns: repeat(3, 1fr); }
.shop-mat-row .mat-swatch { height: 56px; }
.customize-label small { font-weight: 400; opacity: .7; }

/* the battle table is now two rows (board + deck pile) on either side of the seam */
#battleView .trow { display: flex; align-items: center; gap: 6px; padding: 3px 6px 3px 2px; border-radius: 14px; }
#battleView .trow .board { flex: 1; min-width: 0; padding: 4px 0 4px 4px; }
#battleView .pile { position: relative; flex: 0 0 48px; width: 48px; aspect-ratio: 3 / 4; margin-right: 6px; }
#battleView .pile.empty { border: 1.5px dashed var(--stone-edge); border-radius: 9px; }
#battleView .pile.empty::after { content: 'Empty'; position: absolute; inset: 0; display: grid; place-items: center; font-size: .56rem; color: var(--ink-soft); }
#battleView .pile-n { position: absolute; right: -6px; bottom: -9px; z-index: 20; min-width: 24px; text-align: center; padding: 0 6px; font-size: .62rem; font-weight: 700; background: var(--bg-bottom); border: 1px solid var(--water); border-radius: 999px; color: var(--ink); font-variant-numeric: tabular-nums; }
/* a card back: the default design, or the player's sleeve on their own deck and hand */
.cback { position: absolute; inset: 0; border-radius: 9px; overflow: hidden; background: linear-gradient(135deg, var(--c-cyan-41), var(--c-cyan-26-2)); border: 2px solid rgba(255,255,255,.4); box-shadow: 0 2px 5px rgba(0,0,0,.45), inset 0 0 0 3px rgba(0,0,0,.18); }
.cback::before { content: ''; position: absolute; inset: 5px; border: 1px solid rgba(255,255,255,.38); border-radius: 6px; z-index: 1; }
.cback::after { content: '✦'; position: absolute; inset: 0; display: grid; place-items: center; color: rgba(255,255,255,.75); font-size: 1.15rem; z-index: 1; }
.cback.sleeved::after { content: none; }
.cback .sleeve-fx { position: absolute; inset: 0; opacity: .6; z-index: 0; }
.cback .sleeve-mark { position: absolute; inset: 0; display: grid; place-items: center; font-size: 1.2rem; z-index: 2; filter: drop-shadow(0 1px 1px rgba(0,0,0,.5)); }
.cback.sleeved { border-color: var(--sleeve-edge, rgba(255,255,255,.5)); }
#battleView .ohand { display: flex; align-items: center; margin-left: auto; padding-right: 8px; min-height: 40px; }
#battleView .ohand .cback { position: relative; inset: auto; flex: none; width: 26px; height: 36px; margin-left: -14px; border-radius: 6px; transform: translateY(var(--y, 0px)) rotate(var(--r, 0deg)); transform-origin: 50% 120%; }
#battleView .ohand .cback::before { inset: 3px; border-radius: 4px; } #battleView .ohand .cback::after { font-size: .7rem; }
#battleView .ohand .cback:first-child { margin-left: 0; }
.cback.flying { position: fixed; inset: auto; left: 0; top: 0; margin: 0; z-index: 70; pointer-events: none; transform-origin: 0 0; will-change: transform; }
#battleView .card.deal-hide, #battleView .ohand .cback.deal-hide { visibility: hidden; }

/* ===== Battle fixes and effects (v1.61.0) ===== */
/* 1fr alone means minmax(auto, 1fr): a long card name or a wide card could stretch its column, so one row ended up
   with bigger cards than the other and pushed the deck pile over the last slot. minmax(0, 1fr) pins every column. */
#battleView .board { grid-template-columns: repeat(4, minmax(0, 1fr)); }
#battleView .slot, #battleView .card { min-width: 0; }
#battleView .field { perspective: 1500px; }
#battleView .table { transform: rotateX(17deg); }
#battleView .trow .board { overflow: visible; }
#battleView .pile { flex: 0 0 46px; width: 46px; margin-right: 8px; }
/* the life bar: a plain, wide, numbered bar under each name, like the original flat layout */
#battleView .sbar { position: relative; height: 20px; margin: 2px 0 1px; border-radius: 999px; background: rgba(0,0,0,.4); border: 1px solid color-mix(in srgb, var(--hl) 18%, transparent); overflow: hidden; max-width: 210px; }
#battleView .sbar .fill { position: absolute; inset: 0 auto 0 0; width: 100%; border-radius: 999px; background: linear-gradient(90deg, var(--rc-a), var(--rc-b)); transition: width .5s cubic-bezier(.34,1.2,.5,1), background .3s ease; }
#battleView .sbar.low .fill { background: linear-gradient(90deg, var(--c-orange-77), var(--lose-glow)); }
#battleView .sbar .sn { position: absolute; inset: 0; display: grid; place-items: center; font-size: .72rem; font-weight: 800; color: var(--c-grey-100); text-shadow: 0 1px 2px rgba(0,0,0,.6); font-variant-numeric: tabular-nums; }
#battleView .sbar.hit { animation: bt_shake .35s ease; } #battleView .sbar.heal { animation: bt_pulseHeal .5s ease; }
#battleView .spirit .num { display: none; }
#battleView .side.target-glow .sbar, #battleView .side.drop-hover .sbar { box-shadow: 0 0 0 2px var(--boss-glow), 0 0 14px rgba(201,111,111,.8); }
#battleView .side.drop-hover .spirit { box-shadow: 0 0 0 3px var(--c-grey-100), 0 0 26px rgba(255,200,120,.9); }
/* the direct-attack button: shown whenever the selected card may hit the Spirit */
#battleView .atk-face { margin-left: auto; min-height: 44px; padding: 0 18px; border: 0; border-radius: 999px; font: 800 .86rem var(--f-ui); color: var(--c-grey-100); background: linear-gradient(180deg, var(--c-red-60), var(--c-red-46)); box-shadow: 0 0 0 2px rgba(255,255,255,.35), 0 4px 14px rgba(177,66,59,.6); animation: bt_pulseAtk 1.1s ease-in-out infinite; cursor: pointer; }
#battleView .atk-face.hidden { display: none; }
@keyframes bt_pulseAtk { 50% { box-shadow: 0 0 0 2px rgba(255,255,255,.35), 0 0 0 9px rgba(216,104,92,.35), 0 4px 14px rgba(177,66,59,.6); } }
#battleView #btYouBoard .card.can-act { touch-action: none; cursor: grab; }
#battleView .card.targetable { cursor: pointer; }

/* effects */
#battleView .fx { position: fixed; pointer-events: none; z-index: 65; }
#battleView .fx-orb { left: 0; top: 0; width: 28px; height: 28px; margin: -14px 0 0 -14px; border-radius: 50%; background: radial-gradient(circle, var(--c-grey-100) 0, var(--c) 52%, transparent 72%); box-shadow: 0 0 18px 6px var(--c); }
#battleView .fx-burst { width: 96px; height: 96px; margin: -48px 0 0 -48px; border-radius: 50%; border: 3px solid var(--c); box-shadow: 0 0 26px var(--c), inset 0 0 18px var(--c); animation: fxBurst .5s ease-out forwards; }
@keyframes fxBurst { from { transform: scale(.2); opacity: 1; } to { transform: scale(1.5); opacity: 0; } }
#battleView .fx-wash { position: absolute; inset: 0; z-index: 38; background: radial-gradient(circle at var(--x, 50%) var(--y, 50%), color-mix(in srgb, var(--c) 55%, transparent), transparent 62%); opacity: 0; animation: fxWash .65s ease-out forwards; }
@keyframes fxWash { 25% { opacity: .9; } to { opacity: 0; } }
#battleView .fx-sweep { height: 74px; margin-top: -37px; background: linear-gradient(90deg, transparent, var(--c) 30%, var(--c-grey-100) 50%, var(--c) 70%, transparent); transform-origin: 0 50%; animation: fxSweep .6s ease-out forwards; }
@keyframes fxSweep { 0% { transform: scaleX(0); opacity: .95; } 70% { transform: scaleX(1); opacity: .8; } to { transform: scaleX(1); opacity: 0; } }
#battleView .fx-bolt { width: 6px; margin-left: -3px; background: linear-gradient(180deg, transparent, var(--c-grey-100) 30%, var(--c)); box-shadow: 0 0 14px 3px var(--c); animation: fxBolt .36s ease-out forwards; }
@keyframes fxBolt { 0% { opacity: 0; transform: scaleY(.2); transform-origin: 50% 0; } 30% { opacity: 1; transform: scaleY(1); transform-origin: 50% 0; } to { opacity: 0; transform: scaleY(1); transform-origin: 50% 0; } }
#battleView .fx-rise { font-size: 1.05rem; color: var(--c); text-shadow: 0 0 8px var(--c); opacity: 0; animation: fxRise .85s ease-out var(--d, 0ms) forwards; }
@keyframes fxRise { 0% { opacity: 0; transform: translateY(0) scale(.6); } 25% { opacity: 1; } to { opacity: 0; transform: translateY(-46px) scale(1.2); } }
#battleView .fx-whoosh { width: 90px; height: 90px; margin: -45px 0 0 -45px; border-radius: 50%; border: 4px dotted var(--c); animation: fxWhoosh .55s ease-out forwards; }
@keyframes fxWhoosh { from { transform: rotate(0) scale(.3); opacity: 1; } to { transform: rotate(240deg) scale(1.5); opacity: 0; } }
/* attacked: a slash across the card; defended: a shield bubble pops around it */
#battleView .card .fx-slash { position: absolute; inset: -6%; pointer-events: none; z-index: 8; }
#battleView .card .fx-slash::before, #battleView .card .fx-slash::after { content: ''; position: absolute; left: -8%; right: -8%; height: 4px; border-radius: 3px; background: linear-gradient(90deg, transparent, var(--c-grey-100), transparent); box-shadow: 0 0 10px var(--c-orange-77-2); transform: rotate(-38deg) scaleX(0); opacity: 0; animation: fxSlash .34s ease-out forwards; }
#battleView .card .fx-slash::before { top: 38%; } #battleView .card .fx-slash::after { top: 58%; animation-delay: .07s; }
#battleView .card .fx-slash.gold::before, #battleView .card .fx-slash.gold::after { background: linear-gradient(90deg, transparent, var(--c-amber-86-2), transparent); box-shadow: 0 0 12px var(--c-amber-68-2); }
@keyframes fxSlash { 0% { transform: rotate(-38deg) scaleX(0); opacity: 1; } 55% { transform: rotate(-38deg) scaleX(1); opacity: 1; } to { transform: rotate(-38deg) scaleX(1); opacity: 0; } }
#battleView .card .fx-shield { position: absolute; inset: -16%; border-radius: 50%; pointer-events: none; z-index: 9; display: grid; place-items: center; font-size: 1.7rem; border: 3px solid rgba(190,235,255,.95); background: radial-gradient(circle, rgba(190,235,255,.4), rgba(190,235,255,.08) 65%, transparent 72%); box-shadow: 0 0 18px rgba(150,220,255,.8); animation: fxShield .62s ease-out forwards; }
#battleView .card .fx-shield::after { content: '🛡️'; filter: drop-shadow(0 1px 2px rgba(0,0,0,.5)); }
@keyframes fxShield { 0% { transform: scale(.45); opacity: 0; } 28% { transform: scale(1); opacity: 1; } to { transform: scale(1.35); opacity: 0; } }
#battleView .fx-vig { position: absolute; inset: 0; z-index: 40; opacity: 0; animation: fxVig .6s ease-out forwards; }
#battleView .fx-vig.red { background: radial-gradient(ellipse at 50% 55%, transparent 52%, rgba(214,72,60,.6)); }
#battleView .fx-vig.gold { background: radial-gradient(ellipse at 50% 20%, rgba(255,214,120,.5), transparent 55%); }
@keyframes fxVig { 20% { opacity: 1; } to { opacity: 0; } }
#battleView.shake .field { animation: bt_tableShake .3s ease; } #battleView.shake-hard .field { animation: bt_tableShakeHard .34s ease; }
@keyframes bt_tableShake { 25% { transform: translate(-2px, 1px); } 50% { transform: translate(2px, -1px); } 75% { transform: translate(-1px, 0); } }
@keyframes bt_tableShakeHard { 20% { transform: translate(-5px, 2px); } 40% { transform: translate(5px, -2px); } 60% { transform: translate(-3px, 1px); } 80% { transform: translate(2px, 0); } }

/* ===== Fishing, v1.63.0: swimming fish, floating bait, aiming, and cast/catch/escape animations ===== */
.fs-swim { left: 0; right: 0; top: 0; bottom: 0; z-index: 2; pointer-events: none; }
.fs-sw { position: absolute; transform: translate(-50%, -50%); transition: left var(--mv, 0s) ease-in-out, top var(--mv, 0s) ease-in-out, opacity .5s; }
.fs-sw .in { display: block; line-height: 1; animation: fsSwim var(--dur, 16s) linear var(--dl, 0s) infinite; filter: saturate(.8) brightness(.85); }
.fs-sw.small .in { font-size: 1.9rem; } .fs-sw.medium .in { font-size: 2.7rem; } .fs-sw.large .in { font-size: 3.8rem; filter: saturate(.8) brightness(.72); }
.fs-sw.legend .in { filter: drop-shadow(0 0 10px var(--c-amber-83)) drop-shadow(0 0 4px var(--c-amber-86-2)); }
.fs-sw.near::after { content: ''; position: absolute; left: 50%; top: 50%; width: 130%; height: 130%; transform: translate(-50%, -50%); border-radius: 50%; border: 2px solid rgba(232,203,136,.9); box-shadow: 0 0 16px rgba(232,203,136,.6); animation: fsNear 1.1s ease-in-out infinite; }
@keyframes fsNear { 50% { transform: translate(-50%, -50%) scale(1.15); opacity: .55; } }
.fs-sw.fadein { opacity: 0; }
@keyframes fsSwim { 0% { transform: translateX(0) scaleX(-1); } 49% { transform: translateX(var(--sw, 60px)) scaleX(-1); } 50% { transform: translateX(var(--sw, 60px)) scaleX(1); } 99% { transform: translateX(0) scaleX(1); } 100% { transform: translateX(0) scaleX(-1); } }
.fs-fl { position: absolute; transform: translate(-50%, -50%); font-size: 1.15rem; line-height: 1; opacity: .9; animation: fsFloat var(--dur, 6s) ease-in-out var(--dl, 0s) infinite; filter: drop-shadow(0 2px 3px rgba(0,0,0,.4)); }
@keyframes fsFloat { 0%, 100% { transform: translate(-50%, -50%) translate(0, 0) rotate(-6deg); } 50% { transform: translate(-50%, -50%) translate(var(--fx, 14px), -7px) rotate(8deg); } }
.fs-aim { z-index: 4; width: 46px; height: 46px; margin: -23px 0 0 -23px; border-radius: 50%; border: 2px dashed rgba(255,255,255,.85); box-shadow: 0 0 14px rgba(255,255,255,.35); pointer-events: none; animation: fsAim 1.4s ease-in-out infinite; }
.fs-aim::after { content: '✕'; position: absolute; inset: 0; display: grid; place-items: center; font-size: .8rem; color: var(--c-grey-100); }
.fs-aim.hidden, .fs-hook.hidden { display: none; }
@keyframes fsAim { 50% { transform: scale(1.18); opacity: .6; } }
.fs-hook { z-index: 3; font-size: 1.2rem; line-height: 1; transform: translate(-50%, -50%); transition: top .7s ease-in, left .7s ease-in; filter: drop-shadow(0 0 6px rgba(255,255,255,.5)); }
.fs-bucket { left: 12px; top: calc(11% + env(safe-area-inset-top, 0px)); z-index: 4; font-size: 2.1rem; line-height: 1; }
.fs-bucket b { position: absolute; right: -8px; bottom: -6px; font-size: .62rem; background: var(--bg-bottom); border: 1px solid var(--accent); border-radius: 999px; padding: 0 5px; color: var(--ink); }
.fs-bucket.bump { animation: fsBump .5s ease; }
@keyframes fsBump { 30% { transform: scale(1.3) rotate(-10deg); } 60% { transform: scale(.95) rotate(6deg); } }
.fs-drop { position: absolute; z-index: 8; width: 7px; height: 7px; margin: -3px; border-radius: 50%; background: radial-gradient(circle at 35% 30%, var(--c-grey-100), var(--c-cyan-85) 60%, rgba(150,210,235,.5)); pointer-events: none; animation: fsDrop .7s cubic-bezier(.2,.8,.4,1) forwards; }
.fs-drop.gold { background: radial-gradient(circle at 35% 30%, var(--c-grey-100), var(--c-amber-83) 60%, var(--c-amber-72)); }
@keyframes fsDrop { 0% { transform: translate(0, 0); opacity: 1; } 60% { opacity: 1; } 100% { transform: translate(var(--dx), var(--dy)); opacity: 0; } }
.fs-puff { position: absolute; z-index: 8; font-size: 1.4rem; pointer-events: none; animation: fsPuff .8s ease-out forwards; }
@keyframes fsPuff { from { transform: translate(-50%, -50%) scale(.5); opacity: 1; } to { transform: translate(-50%, -140%) scale(1.5); opacity: 0; } }
.fs-flash { position: absolute; inset: 0; z-index: 9; pointer-events: none; background: radial-gradient(circle at var(--x, 50%) var(--y, 30%), rgba(255,246,214,.75), transparent 55%); animation: fsFlash .55s ease-out forwards; }
.fs-flash.gold { background: radial-gradient(circle at var(--x, 50%) var(--y, 30%), rgba(255,226,140,.9), rgba(255,226,140,.2) 45%, transparent 65%); }
@keyframes fsFlash { 0% { opacity: 0; } 25% { opacity: 1; } 100% { opacity: 0; } }
.fish-scene.shake { animation: fsShake .3s ease; }
@keyframes fsShake { 25% { transform: translate(-3px, 2px); } 50% { transform: translate(3px, -2px); } 75% { transform: translate(-2px, 0); } }
/* phases added in v1.63.0: cast (line in flight), landing / away (catch or escape animation), result (Cast again) */
.fish-scene[data-phase="cast"] .fs-bobber, .fish-scene[data-phase="landing"] .fs-bobber, .fish-scene[data-phase="away"] .fs-bobber { animation: none; }
.fish-scene[data-phase="result"] .fs-bobber, .fish-scene[data-phase="landing"] .fs-bobber { opacity: 0; }
.fish-scene[data-phase="cast"] .fs-ring, .fish-scene[data-phase="result"] .fs-ring, .fish-scene[data-phase="idle"] .fs-ring { animation: none; }
.fs-panel .btn:disabled { opacity: .6; }
@media (prefers-reduced-motion: reduce) { .fs-sw .in, .fs-fl, .fs-aim, .fs-sw.near::after { animation: none; } }

/* ===== Character tab, v1.64.0: the stage (you + companion on a backdrop) and the drawer of views below it ===== */
#characterPanel { margin: 0 -12px; padding-bottom: 8px; }
.ch-stage { position: relative; height: 236px; overflow: hidden; color: var(--c-grey-100); border-radius: 0 0 26px 26px; background: linear-gradient(180deg, var(--sk-a, var(--c-cyan-67-2)), var(--sk-b, var(--c-grey-89))); transition: height .35s ease; }
.ch-stage:not(.dark) { color: var(--c-cyan-16); }
.ch-stage.compact { height: 124px; }
.ch-deco { position: absolute; inset: 0; pointer-events: none; }
.ch-d { position: absolute; line-height: 1; opacity: .85; animation: chDrift 9s ease-in-out infinite; }
@keyframes chDrift { 50% { transform: translate(10px, -5px); } }
.ch-ground { position: absolute; left: -12%; right: -12%; bottom: -42px; height: 96px; border-radius: 50%; background: var(--gr, var(--c-green-59)); box-shadow: inset 0 10px 16px rgba(255,255,255,.14); transition: transform .35s ease; }
.ch-stage.compact .ch-ground { transform: translateY(26px); }
.ch-top { position: absolute; left: 14px; right: 14px; top: 12px; display: flex; justify-content: space-between; align-items: center; gap: 8px; z-index: 3; transition: opacity .25s ease; }
.ch-stage.compact .ch-top { opacity: 0; pointer-events: none; }
.ch-id { display: flex; align-items: center; flex-wrap: wrap; gap: 4px 8px; min-width: 0; }
.ch-name { font-family: var(--f-display); font-weight: 500; font-size: 1.2rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ch-chip, .ch-peb { font-size: .7rem; font-weight: 700; padding: 3px 10px; border-radius: 999px; background: rgba(15,24,30,.5); color: var(--c-grey-100); white-space: nowrap; }
.ch-actors { position: absolute; left: 0; right: 0; bottom: 30px; display: flex; justify-content: center; align-items: flex-end; gap: 26px; z-index: 2; transition: transform .35s ease, bottom .35s ease; }
.ch-stage.compact .ch-actors { bottom: 14px; transform: scale(.62); transform-origin: 50% 100%; }
.ch-actor { border: 0; background: none; padding: 0; font: inherit; color: inherit; display: grid; justify-items: center; gap: 5px; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.ch-av.avatar-preview { margin: 0; width: 88px; height: 88px; font-size: 2.9rem; }
.ch-pal-f { font-size: 3.6rem; line-height: 1; filter: drop-shadow(0 6px 4px rgba(0,0,0,.25)); animation: chBob 3s ease-in-out infinite; }
.ch-pal.empty .ch-pal-f { opacity: .5; filter: grayscale(1); animation: none; }
@keyframes chBob { 50% { transform: translateY(-5px); } }
.ch-actor.hop > span:first-child { animation: chHop .45s ease; }
@keyframes chHop { 35% { transform: translateY(-16px) scale(1.06); } 70% { transform: translateY(0) scale(.96, 1.04); } }
.ch-plate { display: grid; gap: 3px; justify-items: center; font-size: .68rem; font-weight: 800; padding: 2px 10px; border-radius: 999px; background: color-mix(in srgb, var(--stone) 92%, transparent); color: var(--ink); border: 1px solid var(--stone-edge); min-width: 56px; }
.ch-xp { display: block; width: 100%; height: 3px; border-radius: 3px; background: var(--track); overflow: hidden; margin: 0 0 2px; }
.ch-xp b { display: block; height: 100%; background: var(--accent); }
.ch-paint { position: absolute; right: 12px; bottom: 12px; z-index: 4; width: 38px; height: 38px; border-radius: 50%; border: 1px solid var(--stone-edge); background: color-mix(in srgb, var(--stone) 92%, transparent); font-size: 1.1rem; cursor: pointer; }
.ch-stage.compact .ch-paint { bottom: 8px; width: 32px; height: 32px; font-size: 1rem; }
.ch-drawer { padding: 14px 12px 8px; }
.ch-body { display: flex; flex-direction: column; gap: 4px; }
.ch-level { margin-bottom: 10px; }
.ch-filter { display: flex; gap: 6px; flex-wrap: wrap; margin: 4px 0 8px; }
.ch-shop { width: 100%; display: flex; flex-direction: column; align-items: center; gap: 2px; min-height: 52px; } .ch-shop small { font-weight: 600; font-size: .72rem; opacity: .8; }
.ach.wearable { font-family: inherit; color: inherit; cursor: pointer; }
.ach.wearable:active { transform: scale(.96); }
.ach.worn { border-color: var(--accent); box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 30%, transparent); }
.ch-empty { text-align: center; display: grid; gap: 6px; justify-items: center; padding: 18px 12px; background: var(--stone); border: 1px dashed var(--stone-edge); border-radius: 16px; }
.ch-empty-f { font-size: 2.6rem; opacity: .5; filter: grayscale(1); }
.ch-pal-card { display: flex; gap: 14px; align-items: center; background: var(--stone); border: 1px solid var(--stone-edge); border-radius: 16px; padding: 12px; margin-bottom: 8px; }
.ch-pal-big { font-size: 3rem; line-height: 1; }
.ch-pal-info { display: grid; gap: 3px; min-width: 0; }
.ch-perk { font-size: .8rem; color: var(--water-ink); }
.stage-swatch { align-items: flex-start; padding-top: 5px; }
.stage-swatch > span { color: var(--c-grey-100); text-shadow: 0 1px 3px rgba(0,0,0,.7); font-size: .62rem; text-align: center; line-height: 1.1; }
@media (prefers-reduced-motion: reduce) { .ch-d, .ch-pal-f { animation: none; } .ch-stage, .ch-actors, .ch-ground, .ch-top { transition: none; } }

/* ===== Floating glass top pill, full-bleed town map, floating dock (v1.65.0) ===== */
:root { --hud-h: 72px; --dock-h: 74px; }
.board-wrap { padding: 0; }
.screen { position: relative; padding: var(--hud-h) 12px calc(var(--dock-h) + 14px + env(safe-area-inset-bottom)); }
body.in-battle .screen { padding: 0 0 calc(6px + env(safe-area-inset-bottom)); }
body.in-battle .board-wrap { padding: 8px 10px 0; }
/* the top pill: avatar, district and sky in the middle, Pebbles on the right */
.hud { position: absolute; left: 10px; right: 10px; top: 10px; margin: 0; z-index: 10; padding: 6px 10px 6px 8px; gap: 8px; border-radius: 999px;
  background: var(--glass); border: 1px solid color-mix(in srgb, var(--stone-edge) 80%, transparent); box-shadow: 0 6px 18px var(--shadow); }
.hud-identity { order: 0; } .hud-ambient { order: 1; } .hud-resources { order: 2; }
.hud-id-text, .hud-spacer, .hud-clock, #pillCards, #pillWins { display: none; }
.hud-ambient { flex: 1; max-width: none; min-width: 0; justify-content: center; padding: 0 4px; background: none; border: 0; box-shadow: none; }
.hud-ambient-text { align-items: center; gap: 0; min-width: 0; }
.hud-district { font-family: var(--f-display); font-weight: 500; font-size: 1.02rem; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; line-height: 1.15; }
.hud-ambient-sub { display: flex; align-items: center; gap: 4px; min-width: 0; font-size: 0.66rem; color: var(--ink-soft); }
.hud-ambient-sub .hud-ambient-icon { font-size: 0.8rem; }
.hud-ambient-sub .amb-time, .hud-ambient-sub .amb-weather { max-width: 70px; font-size: 0.66rem; font-weight: 600; color: var(--ink-soft); }
.hud-ambient-sub .amb-weather:not(:empty)::before { content: '· '; }
#pillPebbles .hs-icon { width: 28px; height: 28px; font-size: 0.9rem; box-shadow: none; }
#pillPebbles .hs-bar { height: 24px; margin-left: -12px; padding-left: 16px; }
/* the town map fills the screen behind the pill and the dock */
#townPanel { position: absolute; inset: 0; margin: 0; }
#districtLabel { display: none !important; }
.town-map-wrap { position: absolute; inset: 0; isolation: isolate; }
.town-view { margin: 0; border-radius: 0; box-shadow: none; }
.map-radar-btn { top: calc(var(--hud-h) + 10px); bottom: auto; right: 12px; }
.town-info { position: absolute; left: 12px; right: 12px; bottom: calc(var(--dock-h) + 22px + env(safe-area-inset-bottom)); margin: 0; z-index: 8; display: flex; flex-direction: column; align-items: center; gap: 6px; pointer-events: none; }
.ambient-line, .town-info .log { width: max-content; max-width: 100%; padding: 5px 12px; border-radius: 999px; background: var(--glass); border: 1px solid color-mix(in srgb, var(--stone-edge) 80%, transparent); font-size: 0.72rem; box-shadow: 0 4px 12px var(--shadow); }
.town-info .log { color: var(--ink); min-height: 0; margin: 0; }
.town-info .log:empty { display: none; }
#decorationHint, #hideseekHint { position: absolute; top: calc(var(--hud-h) + 8px); left: 12px; right: 64px; z-index: 12; }
#decorationHint.hidden, #hideseekHint.hidden { display: none; }
/* the menu (a round button, an info bar and a window) is in the FAN MENU block at the end of latest.css (build 290) */
#townPanel.tab-away { opacity: 0; pointer-events: none; }   /* not visibility: that is inherited, so flipping it restyles every tile */
/* a panel arriving: fade and a short slide in the direction of travel, never touching layout */
.tab-in, .tab-in-l, .tab-in-r { animation: tabIn 0.3s cubic-bezier(0.22, 0.8, 0.3, 1) 0.04s both; will-change: opacity, transform; }
.tab-in-r { --tx: 16px; } .tab-in-l { --tx: -16px; }
@keyframes tabIn { from { opacity: 0; transform: translate3d(var(--tx, 0px), 6px, 0); } to { opacity: 1; transform: none; } }
.toast { bottom: calc(env(safe-area-inset-bottom) + var(--dock-h) + 60px); }
#sceneView { padding-top: calc(var(--hud-h) + 2px); }
@media (prefers-reduced-motion: reduce) { .tab-in, .tab-in-l, .tab-in-r { animation: none; } }

/* ===== Level ring (v1.67.0): XP as a ring around the avatar, the level hanging below it, nothing covering the face ===== */
@property --p { syntax: '<number>'; inherits: false; initial-value: 0; }
.hud-ring { position: relative; width: 50px; height: 50px; flex: none; border-radius: 50%; display: grid; place-items: center;
  background: conic-gradient(var(--accent) calc(var(--p, 0) * 1%), var(--track) 0); transition: --p 0.6s ease; }
.hud-ring .hud-portrait { width: 42px; height: 42px; }   /* keeps the thick avatar border (--av-border-w), so the ring is a touch bigger than before */
.hud-ring .hud-portrait .a-emoji { font-size: 1.1rem; }
.hud-ring .lvl-badge { left: 50%; right: auto; bottom: -9px; transform: translateX(-50%); min-width: 0; height: 15px; padding: 0 6px; font-size: 0.58rem; white-space: nowrap; border: 2px solid var(--stone); box-shadow: 0 0 0 1px var(--stone-edge); }
.hud-ring .lvl-badge::before { content: 'Lv\00a0'; }
.hud-xp-bar { display: none; }

/* ===== v1.69.0: the avatar opens Settings and Social; everything about the character lives in the Character tab ===== */
.hud-gear { position: absolute; top: -5px; right: -7px; z-index: 2; width: 17px; height: 17px; border-radius: 50%; display: grid; place-items: center; font-size: 0.55rem; line-height: 1;
  background: var(--stone); border: 1px solid var(--stone-edge); box-shadow: 0 1px 3px var(--shadow); pointer-events: none; }
.name-input { width: 100%; }

/* Smooth neighbour chat (v1.70.0): the talk card and card inspector are sheets over a live, animating town.
   A full-screen backdrop-filter blur there forced the browser to re-blur the whole map every frame while the
   overlay faded in, which showed as a brief flash/glitch on phones (HANDOFF §9: avoid blur over animated
   content). Sheets use a plain dim instead, with a quicker fade, and the card itself slides up in one motion. */
.overlay.sheet, .overlay.inspect-overlay { backdrop-filter: none; -webkit-backdrop-filter: none; transition: opacity .2s ease; }
.overlay.sheet .overlay-card, .overlay.inspect-overlay .overlay-card { will-change: transform; }

/* Dragging a ready card from the table to attack (v1.70.0). While it is held: a dashed aim line runs from the
   attacker to the ghost (solid and bright once it is over something it may hit), the ghost glows red, enemy cards
   that can't be hit dim, the one under the ghost gets a crosshair, and the Spirit says what a drop there does.
   transform/opacity only, and no blur, per HANDOFF §9. */
#battleView.attack-drag .aim-line { position: absolute; height: 0; border-top: 3px dashed rgba(255,170,150,.85); transform-origin: 0 50%; pointer-events: none; z-index: 59; filter: drop-shadow(0 0 4px rgba(201,111,111,.9)); }
#battleView.attack-drag .aim-line::after { content: ''; position: absolute; right: -4px; top: -9px; border-left: 14px solid rgba(255,170,150,.95); border-top: 7.5px solid transparent; border-bottom: 7.5px solid transparent; }
#battleView.attack-drag .aim-line.locked { border-top-style: solid; border-top-color: var(--c-grey-100); }
#battleView.attack-drag .aim-line.locked::after { border-left-color: var(--c-grey-100); }
#battleView .card.attack-ghost { box-shadow: 0 16px 30px rgba(0,0,0,.5), 0 0 0 3px var(--boss-glow), 0 0 22px rgba(201,111,111,.8); }
#battleView.attack-drag #btOppBoard .card:not(.targetable) { opacity: .45; filter: saturate(.5); }
#battleView.attack-drag #btOppBoard .card.drop-hover { transform: scale(1.08); box-shadow: 0 0 0 4px var(--c-grey-100), 0 0 26px rgba(255,120,100,.95); animation: none; opacity: 1; filter: none; }
#battleView.attack-drag #btOppBoard .card.drop-hover::after { content: '⚔️'; position: absolute; left: 50%; top: 50%; transform: translate(-50%,-50%); font-size: 2rem; text-shadow: 0 2px 8px rgba(0,0,0,.7); pointer-events: none; z-index: 6; }
#battleView.attack-drag #btOppBoard .card.atk-blocked { opacity: 1; filter: saturate(.3); box-shadow: 0 0 0 3px var(--c-grey-53); }
#battleView.attack-drag #btOppBoard .card.atk-blocked::after { content: '🛡️ Guard first'; position: absolute; left: 50%; top: 50%; transform: translate(-50%,-50%); white-space: nowrap; font-size: .62rem; font-weight: 700; background: var(--stone); color: var(--ink); border-radius: 999px; padding: 3px 7px; pointer-events: none; z-index: 6; }
#battleView.attack-drag #btOppBar.target-glow::after { content: '⚔️ Drop here to hit their Spirit'; position: absolute; left: 50%; bottom: -10px; transform: translateX(-50%); white-space: nowrap; font-size: .62rem; font-weight: 700; background: var(--stone); color: var(--ink); border-radius: 999px; padding: 3px 8px; box-shadow: 0 1px 4px var(--shadow); pointer-events: none; z-index: 6; }
#battleView.attack-drag #btOppBar.drop-hover::after { content: '⚔️ Release to attack!'; background: var(--boss-glow); color: var(--c-grey-100); }
