/* ============================================================
   Infinite Tides — fan-made pirate card-battler roguelite
   Palette: deep storm-sea navy + brass, elemental accent set
   ============================================================ */

:root{
  --ink:        #0B1A24;
  --ink-2:      #122A3C;
  --ink-3:      #1B3A50;
  --parchment:  #EEE3C8;
  --parchment-dim: #C8BC9F;
  --brass:      #C9A24B;
  --brass-bright: #EFCB72;
  --danger:     #C0442E;

  --fire:       #E1592C;
  --earth:      #8A9A4E;
  --lightning:  #B98BE0;
  --air:        #8FD0DA;
  --water:      #4C86BE;
  --neutral:    #9AA5AD;
  --mythic:     #4DE8D0;

  --radius: 10px;
  --shadow-deep: 0 12px 30px rgba(0,0,0,0.45);
  font-size: 16px;
}

*{ box-sizing: border-box; }

/* Real user report, tested on an installed iOS PWA: long-pressing any
   card/building/portrait image brought up Safari's native "Save Image
   to Photos / Copy / Look Up" menu — an OS-level image-save affordance
   that makes no sense for game art the player is meant to tap through,
   not extract. -webkit-touch-callout is the specific, standard iOS
   Safari/WKWebView property for this exact menu; -webkit-user-drag and
   user-select close the adjacent "drag the image out" / "select and
   copy" paths on other browsers. Scoped to img specifically (not body/*)
   so genuinely selectable text elsewhere — the save-code export/import
   box in Settings, most notably — is completely unaffected. */
img{
  -webkit-touch-callout: none;
  -webkit-user-drag: none;
  user-select: none; -webkit-user-select: none;
}

html, body{
  margin:0; padding:0; height:100%;
  background:
    radial-gradient(ellipse at 20% -10%, #1c3f56 0%, transparent 55%),
    radial-gradient(ellipse at 90% 110%, #0f2636 0%, transparent 50%),
    linear-gradient(180deg, var(--ink) 0%, #081420 100%);
  color: var(--parchment);
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
  overflow-x: hidden;
}
/* Real user bug report (desktop): centered content — most visibly the
   Loadout screen's tab bar/hero — visibly shifted left/right when
   switching between a tab tall enough to need a scrollbar and one that
   isn't. `body` is this page's real scroll container (confirmed: it's
   the element whose overflow-y actually toggles a scrollbar; see the
   scrollRestoration fix above for how that got established), so its
   own scrollbar reserving/releasing ~4px of width was the direct
   cause — confirmed live by measuring a horizontally-centered
   element's position across all 5 loadout tabs before applying this.
   scrollbar-gutter:stable reserves that space unconditionally, whether
   or not a given tab's content actually needs to scroll, so centered
   content never moves based on which tab happens to be active. */
body{ scrollbar-gutter: stable; }

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

.screen{ display:none; flex:1; flex-direction:column; }
.screen.active{ display:flex; }

/* ---------------- Title screen ---------------- */
/* .title-wrap base stays generic/unscoped — #screen-mode-select reuses
   it too (.mode-select-wrap). Everything #screen-title-scoped below is
   a layered override on top, not a replacement. */
.title-wrap{
  margin:auto; text-align:center; max-width:520px; padding: 32px 20px;
}
#screen-title{ position:relative; overflow:hidden; }
.title-bg{ position:absolute; inset:0; z-index:0; }
.title-bg-art{
  position:absolute; inset:-4%;
  background: url("assets/backgrounds/vortex-cover.png") center 38% / cover no-repeat;
  animation: titleDrift 46s ease-in-out infinite alternate;
}
.title-bg-shade{
  position:absolute; inset:0;
  background:
    linear-gradient(90deg, rgba(7,16,25,0.92) 0%, rgba(7,16,25,0.72) 34%, rgba(7,16,25,0.25) 62%, rgba(7,16,25,0.05) 100%),
    linear-gradient(0deg, rgba(7,16,25,0.9) 0%, transparent 32%),
    linear-gradient(180deg, rgba(7,16,25,0.55) 0%, transparent 26%);
}
@keyframes titleDrift{
  from{ transform: scale(1) translate(0, 0); }
  to{ transform: scale(1.07) translate(-1.2%, 1%); }
}

.title-cards{ position:absolute; inset:0; z-index:1; pointer-events:none; }
.float-card-wrap{
  position:absolute;
  --fc-w: 116px;
  width: var(--fc-w);
  animation: cardFloat 9s ease-in-out infinite;
  filter: drop-shadow(0 14px 20px rgba(0,0,0,0.55));
}
/* Mini replica of the in-game card: full-bleed diamond art on top,
   dark navy body with name + rules text, gold cost circle. Colours
   follow the title screen palette (deep navy, brass, parchment ink). */
.float-card{
  position:relative;
  width:100%;
  padding: calc(var(--fc-w) * 0.045);
  padding-top: calc(var(--fc-w) * 0.05);
  border-radius: calc(var(--fc-w) * 0.09);
  background: linear-gradient(180deg, #1A2A3E 0%, #0E1B2A 60%, #0A1420 100%);
  border: 2px solid #8C97A6;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.14),
    inset 0 -2px 0 rgba(0,0,0,0.35);
  overflow:hidden;
}
.float-card-art{
  position:relative;
  width: calc(100% + var(--fc-w) * 0.09);
  margin: calc(var(--fc-w) * -0.05) calc(var(--fc-w) * -0.045) 0;
  aspect-ratio: 1 / 0.82;
  display:flex; align-items:center; justify-content:center;
  overflow:hidden;
  background: radial-gradient(circle at 50% 40%, #22344C 0%, #101E30 80%);
}
.float-card-art img{
  width:104%; height:104%;
  object-fit:contain;
  display:block;
  filter: drop-shadow(0 2px 3px rgba(0,0,0,0.45));
}
.float-card-cost{
  position:absolute; z-index:3;
  top: calc(var(--fc-w) * 0.10); left: calc(var(--fc-w) * 0.06);
  width: calc(var(--fc-w) * 0.21); height: calc(var(--fc-w) * 0.21);
  border-radius:50%;
  background: radial-gradient(circle at 35% 30%, #F6E3B4 0%, #E4C87E 55%, #C9A24B 100%);
  border: 1px solid rgba(58,36,8,0.55);
  box-shadow: 0 1px 3px rgba(0,0,0,0.5), inset 0 -1px 2px rgba(58,36,8,0.35);
  color:#3A2408;
  font-family:'IBM Plex Mono', monospace; font-weight:700;
  font-size: calc(var(--fc-w) * 0.13);
  display:flex; align-items:center; justify-content:center;
}
.float-card-name{
  margin-top: calc(var(--fc-w) * 0.02);
  padding: 0 calc(var(--fc-w) * 0.02);
  color:#F2E8D0;
  font-weight:700; text-align:center; line-height:1.15;
  font-size: calc(var(--fc-w) * 0.115);
  letter-spacing:0.01em;
  text-shadow: 0 1px 2px rgba(0,0,0,0.6);
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden;
}
.float-card-text{
  margin-top: calc(var(--fc-w) * 0.03);
  padding: 0 calc(var(--fc-w) * 0.02) calc(var(--fc-w) * 0.02);
  color:#C8D3E0;
  text-align:center; line-height:1.25;
  font-size: calc(var(--fc-w) * 0.10);
}
.fc-1{ top:8%;  right:8%;  transform:rotate(8deg);   animation-delay:0s;    --fc-w:132px; }
.fc-2{ top:52%; right:19%; transform:rotate(-10deg); animation-delay:-2.5s; --fc-w:104px; }
.fc-3{ top:22%; right:32%; transform:rotate(5deg);   animation-delay:-5s;   --fc-w:88px;  }
.fc-4{ top:66%; right:4%;  transform:rotate(-6deg);  animation-delay:-7s;   --fc-w:112px; }
.fc-5{ top:3%;  right:44%; transform:rotate(-13deg); animation-delay:-4s;   --fc-w:80px; opacity:0.8; }
@keyframes cardFloat{
  0%, 100%{ margin-top:0; }
  50%{ margin-top:-16px; }
}

#screen-title .title-wrap{
  position:relative; z-index:2;
  text-align:left;
  max-width:600px;
  padding: 48px 24px 40px;
  margin-left: clamp(0px, 6vw, 96px);
  margin-right: auto;
}
#screen-title .title-wrap > *{ margin-left:0; }
.title-kicker{
  font-family:'IBM Plex Mono', monospace;
  font-size:0.72rem; letter-spacing:0.32em; text-transform:uppercase;
  color: var(--brass-bright);
  margin:0 0 14px;
  opacity:0.9;
}
.title-kicker::before{
  content:""; display:inline-block; width:34px; height:1px;
  background: var(--brass); vertical-align:middle; margin-right:12px;
  transform: translateY(-2px);
}
.game-title{
  font-family:'Pirata One', serif;
  font-size: clamp(3.4rem, 10vw, 7rem);
  line-height:0.95;
  letter-spacing: 2px;
  margin: 0 0 18px;
  background: linear-gradient(180deg, #F6DD9A 20%, var(--brass-bright) 55%, var(--brass) 100%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
  filter: drop-shadow(0 4px 0 rgba(0,0,0,0.55)) drop-shadow(0 0 34px rgba(233,196,104,0.28));
}
.game-subtitle{
  color: var(--parchment);
  font-size: 1.02rem;
  line-height:1.6;
  margin: 0 0 30px;
  letter-spacing: 0.3px;
  max-width: 46ch;
  text-shadow: 0 1px 8px rgba(0,0,0,0.6);
}
.title-actions{
  display:flex; flex-wrap:wrap; gap:12px; align-items:center;
}
#screen-title #btn-start{
  padding: 17px 52px; font-size:1.15rem;
  box-shadow: 0 6px 0 #8B6C2E, 0 14px 34px rgba(0,0,0,0.5), 0 0 30px rgba(239,203,114,0.25);
}
.title-note{
  margin-top:26px; font-size:0.82rem; color: var(--parchment-dim); line-height:1.6;
  max-width: 44ch;
  text-shadow: 0 1px 6px rgba(0,0,0,0.6);
}
.install-hint{
  display:none; margin-top:16px;
}
.install-hint.active{
  display:flex; justify-content:flex-start;
  font-size:0.8rem; color: var(--brass-bright);
}

@media (max-width: 720px){
  .title-bg-art{ background-position: center 30%; }
  .title-bg-shade{
    background:
      linear-gradient(0deg, rgba(7,16,25,0.94) 0%, rgba(7,16,25,0.55) 45%, rgba(7,16,25,0.35) 100%);
  }
  #screen-title .title-wrap{ margin-left:auto; text-align:center; padding: 40px 22px 32px; }
  .title-kicker::before{ display:none; }
  #screen-title .game-subtitle, #screen-title .title-note{ margin-left:auto; margin-right:auto; }
  .game-subtitle{ margin-bottom:26px; }
  .title-actions{ justify-content:center; }
  .install-hint.active{ justify-content:center; }
  /* The desktop layout keeps the floating cards clear of the text by
     keeping text left / cards right — that strategy breaks down once
     title-wrap centers on mobile (confirmed visually: cards badly
     overlapped the title/button/note). No repositioning fully avoids
     overlap once the text column is centered and full-width, so all 5
     hide here — the background art alone reads fine at this width. */
  .title-cards{ display:none; }
}

/* ---------------- Mode select ---------------- */
#screen-mode-select{ position:relative; overflow:hidden; }
.mode-select-wrap{
  max-width:640px; width:100%; margin:auto; text-align:center;
  padding: 38px 22px 64px; position:relative; z-index:1;
}
.mode-select-hero{ margin-bottom: 30px; }
.mode-cards{ display:flex; flex-direction:column; gap:14px; margin-bottom:20px; }
.mode-card{
  display:block; width:100%; text-align:left;
  background: linear-gradient(180deg, rgba(28,62,86,0.88) 0%, rgba(16,38,52,0.94) 100%);
  border: 1px solid rgba(233,196,104,0.30); border-radius:16px;
  padding:18px 22px; cursor:pointer;
  transition: border-color 0.18s, transform 0.18s, box-shadow 0.18s;
  font-family:'IBM Plex Sans', sans-serif;
  box-shadow: 0 12px 30px rgba(0,0,0,0.32), inset 0 1px 0 rgba(255,255,255,0.08);
  animation: loadoutPanelIn 0.5s ease both;
}
.mode-card:nth-child(1){ animation-delay:0.05s; }
.mode-card:nth-child(2){ animation-delay:0.10s; }
.mode-card:nth-child(3){ animation-delay:0.15s; }
.mode-card:nth-child(4){ animation-delay:0.20s; }
button.mode-card:hover{
  border-color: var(--brass-bright); transform: translateY(-2px);
  box-shadow: 0 16px 38px rgba(0,0,0,0.40), 0 0 22px rgba(233,196,104,0.14), inset 0 1px 0 rgba(255,255,255,0.10);
}
button.mode-card:focus-visible{
  outline: 2px solid var(--brass-bright); outline-offset: 3px;
}
.mode-card.locked{ opacity:0.5; cursor:default; }
.mode-card-title{
  font-family:'Pirata One', serif; font-size:1.45rem; margin-bottom:4px;
  background: linear-gradient(180deg, #F6DD9A 15%, var(--brass-bright) 60%, var(--brass) 100%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
  filter: drop-shadow(0 2px 0 rgba(0,0,0,0.5));
  display:flex; align-items:center; gap:12px;
}
.mode-card-title::after{
  content:""; flex:1; height:1px;
  background: linear-gradient(90deg, rgba(233,196,104,0.35), transparent);
}
.mode-card-desc{ font-size:0.85rem; color: var(--parchment-dim); line-height:1.55; }
.endless-slots{ display:flex; flex-direction:column; gap:10px; margin-bottom:16px; }
.endless-slot{
  display:flex; align-items:center; gap:10px;
  background: var(--ink-2); border: 1px solid rgba(233,196,104,0.25); border-radius:10px;
  padding:12px 16px;
  transition: border-color 0.15s;
}
.endless-slot:has(.endless-slot-main:hover){ border-color: var(--brass-bright); }
.endless-slot-main{
  flex:1; min-width:0; text-align:left; cursor:pointer;
  background:none; border:none; padding:0; font-family:'IBM Plex Sans', sans-serif;
}
.endless-slot-label{ font-size:0.85rem; color: var(--parchment); }
.endless-slot-sub{ font-size:0.72rem; color: var(--parchment-dim); margin-top:2px; }
.endless-slot-delete{
  flex-shrink:0; width:28px; height:28px; border-radius:50%;
  background: var(--ink-3); border: 1px solid rgba(192,68,46,0.4);
  color: var(--danger); font-size:0.8rem; cursor:pointer;
}

.btn{
  font-family:'IBM Plex Sans', sans-serif;
  font-weight:600;
  border-radius: 999px;
  border: none;
  cursor: pointer;
  padding: 12px 28px;
  font-size: 0.95rem;
  transition: transform 0.12s ease, box-shadow 0.12s ease, filter 0.12s ease;
  /* Real user bug report (mobile, screen recording): rapidly tapping
     between the loadout tab bar's buttons could land as a native
     double-tap-to-zoom gesture instead of two separate taps — since
     this is a single-page app that never reloads, the resulting zoom
     then persisted across every later tab switch, visibly (a whole-
     page scale/position jump that self-"fixed" only by switching to a
     tab tall enough to force a manual scroll, never actually zooming
     back out). touch-action:manipulation tells the browser this
     element is for immediate tapping, not gesture detection — it
     disables double-tap-zoom (and the old ~300ms tap delay) on it
     specifically, while leaving deliberate two-finger pinch-zoom on
     the rest of the page untouched. */
  touch-action: manipulation;
}
.btn:active{ transform: translateY(1px) scale(0.98); }
.btn-primary{
  background: linear-gradient(180deg, var(--brass-bright), var(--brass));
  color: #22160A;
  box-shadow: 0 6px 0 #8B6C2E, 0 10px 20px rgba(0,0,0,0.35);
}
.btn-primary:hover{ filter: brightness(1.06); }
.btn-secondary{
  background: var(--ink-3);
  color: var(--parchment);
  border: 1px solid rgba(233,196,104,0.35);
}
.btn-secondary:hover{ filter: brightness(1.25); }
.btn-large{ padding: 15px 40px; font-size: 1.1rem; }
.btn:disabled{ opacity:0.4; cursor:not-allowed; filter:none; transform:none; }
.btn-danger{ border-color: rgba(192,68,46,0.5); color: var(--danger); margin: 4px 0 0; }
.btn-danger:hover{ background: rgba(192,68,46,0.15); filter:none; }

/* ---------------- HUD ---------------- */
.hud{
  display:flex; align-items:center; gap: 22px;
  /* Right padding reserves room for the fixed menu icon (.menu-fab-wrap,
     top:14px/right:14px, 40px) so hud-save-block's "Save & Quit" button
     never renders underneath it — real user feedback, it used to
     overlap on the battle screen (the only screen with top-right HUD
     content of its own) back when this was two separate icons. */
  padding: 12px 70px 12px 20px;
  background: linear-gradient(180deg, rgba(18,42,60,0.95), rgba(18,42,60,0.7));
  border-bottom: 1px solid rgba(233,196,104,0.25);
  flex-wrap: wrap;
}
.hud-block{ display:flex; flex-direction:column; gap:4px; min-width:80px; }
.hud-save-block{ margin-left:auto; min-width:0; }
.hud-save-block .btn{ margin-top:0; }
.hud-label{
  font-size: 0.62rem; text-transform: uppercase; letter-spacing: 1.4px;
  color: var(--brass); font-weight: 600;
}
.hud-value{ font-family:'IBM Plex Mono', monospace; font-size:1.05rem; font-weight:600;}

.bar{
  width:100%; height:14px; border-radius:8px; overflow:hidden;
  background: rgba(0,0,0,0.4); border: 1px solid rgba(255,255,255,0.08);
}
.bar-fill{
  height:100%; width:100%;
  background: linear-gradient(90deg, #4C86BE, #6FB0DE);
  transition: width 0.35s ease;
}
.bar-enemy-hp .bar-fill{ background: linear-gradient(90deg, #C0442E, #E1592C); }
.bar-text{ font-family:'IBM Plex Mono', monospace; font-size:0.72rem; color: var(--parchment-dim); }

/* Real user feedback: "a decision-timer under critical HP" — resolved
   as visual pressure only (owner's call, no forced auto-end turn). See
   CRITICAL_HP_PCT/render() in game.js — toggled on #player-combatant-hp
   at 25% HP or below, matching this game's own existing definition of
   "critical HP" (last_ditch's freeBelowHpPct). The player's HP bar is
   normally blue, unlike the enemy's already-red one, so switching it to
   the same danger red here reads as a clear state change rather than
   colliding with an existing convention. */
.combatant-hp.critical-hp .bar-fill{ background: linear-gradient(90deg, #C0442E, #E1592C); }
.combatant-hp.critical-hp .bar-text{ color: #FF9B82; font-weight:700; }
.combatant-hp.critical-hp .bar{ box-shadow: 0 0 0 1px rgba(192,68,46,0.6); }
.combatant-hp.critical-hp{ animation: criticalHpPulse 1.1s ease-in-out infinite; }
@keyframes criticalHpPulse{
  0%, 100%{ filter: drop-shadow(0 0 0 rgba(192,68,46,0)); }
  50%{ filter: drop-shadow(0 0 7px rgba(192,68,46,0.85)); }
}

/* Affinity indicator — real user feedback: the full 5-node wheel read as
   confusing and took up too much main-screen space for what a player
   actually needs turn to turn, which is just "what's the current
   target's element." Trimmed to a single node showing that one element
   — the other 4 elements' cycle relationships are still explained via
   this node's own tooltip (elementTooltip()) and the Help modal, just
   no longer rendered as 5 permanent on-screen dots. */
.wheel-block{ margin-left:auto; align-items:center; }
.element-wheel{
  width: 28px; height:28px; display:flex; align-items:center; justify-content:center;
}
.wheel-node{
  width:24px; height:24px; border-radius:50%;
  display:flex; align-items:center; justify-content:center;
  font-size:13px; border:2px solid rgba(255,255,255,0.15);
  box-shadow: 0 0 0 2px rgba(255,255,255,0.4);
  transition: box-shadow .2s ease, transform .2s ease;
}
.wheel-node.active-target{
  box-shadow: 0 0 0 3px rgba(255,255,255,0.9), 0 0 14px currentColor;
}

/* ---------------- Battlefield: open ocean scene ---------------- */
.ocean-battlefield{
  position: relative;
  flex: 1;
  min-height: 320px;
  margin: 4px 20px 14px;
  border-radius: var(--radius);
  overflow: hidden;
  border: 1px solid rgba(233,196,104,0.18);
  background:
    radial-gradient(ellipse at 25% 15%, rgba(255,255,255,0.07), transparent 45%),
    repeating-linear-gradient(115deg, rgba(255,255,255,0.025) 0 2px, transparent 2px 26px),
    linear-gradient(180deg, #1c5273 0%, #123f5c 45%, #0a2638 100%);
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  padding: 22px 26px;
}

.player-combatant, .enemy-combatant{
  display:flex; flex-direction:column; align-items:center; gap:8px;
  flex: none; max-width: 46%;
  position: relative; /* anchors .hit-fx — see showHitFx()/showPlayerEvadeFx() */
}
.enemy-combatant{ align-items:center; }

/* Real user feedback: visual effects for combat hits and evades — a
   real toming.app CC0 VFX render (boom02 for a landed hit,
   vfx_boss_splash_flat for a dodge) popping over whoever was just
   hit/evaded. These ship with an opaque cream backdrop baked in like
   the rest of this project's toming.app art, but unlike ships/
   equipment (see chroma_key.py's own header comment — its color-key
   left a residual halo on those after real tuning, so they got
   hand-matted art instead), it ran clean on both of these on the
   first pass — checked directly by compositing the keyed output onto
   the battlefield's own dark navy before committing to it. Local,
   one-time `assets/effects/*.webp` are the already-keyed, real-alpha
   output; nothing runs chroma_key.py at request time. See showHitFx()
   (enemy-side, dynamically created and torn down each render since
   #enemies-row is fully rebuilt) and showPlayerEvadeFx() (player-side,
   appended straight to .player-combatant, which render() never
   rebuilds wholesale). */
.hit-fx{
  position:absolute; top:50%; left:50%; z-index:6;
  width:84px; height:84px;
  transform: translate(-50%,-50%) scale(0.5);
  filter: drop-shadow(0 4px 10px rgba(0,0,0,0.55));
  opacity:0; pointer-events:none;
  animation: hitFxPop 700ms ease-out forwards;
}
.hit-fx img{ width:100%; height:100%; object-fit:contain; }
@keyframes hitFxPop{
  0%{ opacity:0; transform:translate(-50%,-50%) scale(0.4); }
  22%{ opacity:1; transform:translate(-50%,-50%) scale(1.1); }
  38%{ transform:translate(-50%,-50%) scale(1); }
  78%{ opacity:1; transform:translate(-50%,-50%) scale(1); }
  100%{ opacity:0; transform:translate(-50%,-50%) scale(1.15); }
}

.enemies-row{
  display:flex; flex-wrap:wrap; gap:14px;
  justify-content:center; align-items:flex-end;
  flex: none; max-width: 52%;
}
.enemies-row .enemy-combatant{
  max-width:none; flex: 0 1 150px;
  padding: 6px; border-radius: 14px;
  transition: box-shadow 0.15s ease;
  cursor: pointer;
}
.enemies-row .enemy-combatant .enemy-portrait{
  width: clamp(72px, 12vw, 130px);
  height: clamp(60px, 10vw, 110px);
}
.enemies-row .enemy-combatant.targeted{
  box-shadow: 0 0 0 2px var(--brass-bright), 0 6px 14px rgba(0,0,0,0.4);
  background: rgba(239,203,114,0.08);
}
.enemies-row .enemy-combatant.miniboss{
  border: 1px solid var(--lightning);
}
.enemies-row .enemy-combatant.miniboss .enemy-name{
  color: var(--lightning);
}
.enemies-row .enemy-combatant.miniboss.targeted{
  box-shadow: 0 0 0 2px var(--brass-bright), 0 0 14px var(--lightning);
}

.ship-portrait-lg{
  width: 190px; height:150px; border-radius:10px;
  filter: drop-shadow(0 10px 14px rgba(0,0,0,0.45));
  background: transparent;
}
.ship-portrait-lg .art-fallback{ background:none; font-size:3.4rem; }
.ship-portrait-lg .art-fallback,
.enemy-portrait .art-fallback{ background: none; }
.art-slot.ship-portrait-lg img, .art-slot.enemy-portrait img{ object-fit: contain; }
/* Enemy source art shipped as a flat RGB render — a baked-in off-white
   studio backdrop, no alpha channel at all. First attempt used
   mix-blend-mode:multiply as a no-asset-editing shortcut, but that
   darkens the whole image by its own overall brightness, not just the
   background — anything pale (Foam Monster, Mist Monster) crushed to a
   near-invisible shadow instead of just losing its backdrop. Replaced
   with a real one-time color-key pass (see "Ship/enemy background
   removal" in README.md) that punches the specific backdrop color out
   to true alpha, so every file's own colors stay exactly as bright/
   dark as the source art intended. Ship portraits initially stayed
   static/flat-background after the Skiff kept showing a residual pale
   glow even post-fix — later swapped for real hand/AI-matted
   transparent renders the owner provided directly (clean edges even on
   thin masts/flags, no color-key needed at all), so ships now get the
   same treatment as enemies. A gentle idle bob (iconBob) on top, same
   family as the title screen's cardFloat but smaller amplitude/faster
   cycle — meant to read as "alive," not as a distraction during real
   decisions. */
.art-slot.ship-portrait-lg img, .art-slot.enemy-portrait img{
  animation: iconBob 3.2s ease-in-out infinite;
}
@keyframes iconBob{
  0%, 100%{ transform: translateY(0); }
  50%{ transform: translateY(-6px); }
}
.enemies-row .enemy-combatant:nth-child(2) .enemy-portrait img{ animation-delay:-1.6s; }
.enemies-row .enemy-combatant:nth-child(3) .enemy-portrait img{ animation-delay:-0.8s; }
@media (prefers-reduced-motion: reduce){
  .art-slot.ship-portrait-lg img, .art-slot.enemy-portrait img{ animation: none; }
}

.enemy-portrait{
  width: 130px; height:110px; border-radius:10px;
  filter: drop-shadow(0 8px 12px rgba(0,0,0,0.4));
  background: transparent; border: none;
}

.combatant-hp{ width: 190px; display:flex; flex-direction:column; align-items:center; gap:3px; }
.enemy-combatant .combatant-hp{ width: 150px; }
.combatant-hp .bar-text{ text-shadow: 0 1px 3px rgba(0,0,0,0.8); }

.enemy-name-row{ display:flex; align-items:center; gap:8px; justify-content:center; }
.enemy-name{
  font-family:'Pirata One', serif; font-size:1.3rem; color: var(--parchment);
  text-shadow: 0 2px 6px rgba(0,0,0,0.7);
}

.tag{
  font-size:0.65rem; text-transform:uppercase; letter-spacing:1px; font-weight:700;
  padding: 3px 9px; border-radius:999px; border:1px solid currentColor;
  background: rgba(0,0,0,0.35);
}
/* min-height reserves room for 2 full lines of chips (~20px each + 6px
   gap), not just 1 — .ocean-battlefield/.enemies-row both bottom-anchor
   their columns (align-items:flex-end), so when this row's real content
   grows past 1 line it used to grow the whole column, and since the
   anchor holds the *bottom* edge fixed, the ship/enemy portrait above it
   visibly shifted position turn to turn as buffs/debuffs stacked up or
   wore off — real user feedback: "getting certain buffs moves the ship."
   Reserving 2 lines up front covers the common case (most fights never
   need a 3rd); a genuinely packed status row can still shift things
   slightly beyond that, but that's a rare edge case, not the everyday
   bounce this was. */
.status-row{ display:flex; gap:6px; flex-wrap:wrap; min-height:46px; align-content:flex-start; justify-content:center; }
.element-source-row{ display:flex; gap:6px; flex-wrap:wrap; justify-content:center; margin-top:2px; }
.element-source-chip{ font-weight:700; }
.status-chip{
  font-size:0.68rem; padding:2px 8px; border-radius:999px;
  background: rgba(0,0,0,0.5); border:1px solid rgba(255,255,255,0.15);
  font-weight:600;
}
.status-chip.chip-shield{ border-color: var(--water); color: var(--air); }
.status-chip.chip-regen{ border-color: var(--earth); color: #b9d47a; }
.status-chip.chip-buff{ border-color: var(--brass-bright); color: var(--brass-bright); }
.status-chip.chip-debuff{ border-color: var(--danger); color: #e58a78; }
.intent-box{ min-height: 22px; }
.intent{
  font-family:'IBM Plex Mono', monospace; font-size:0.85rem; font-weight:600;
  display:flex; align-items:center; gap:6px; justify-content:center;
  text-shadow: 0 1px 4px rgba(0,0,0,0.8);
}
.intent-preview{
  font-family:'IBM Plex Mono', monospace; font-size:0.7rem; font-weight:500;
  color: var(--parchment-dim); text-align:center; margin-top:2px;
  text-shadow: 0 1px 4px rgba(0,0,0,0.8);
}

.turn-banner{
  position: absolute; left: 50%; bottom: 14px; transform: translate(-50%, 8px);
  max-width: calc(100% - 28px);
  background: rgba(4,10,15,0.85);
  border: 1px solid var(--brass);
  border-radius: 10px;
  padding: 8px 16px;
  font-family:'IBM Plex Mono', monospace; font-size:0.78rem; font-weight:600;
  color: var(--parchment);
  text-align: center;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.2s ease, transform 0.2s ease;
  z-index: 5;
}
.turn-banner.visible{ opacity: 1; transform: translate(-50%, 0); }

.log-panel-mini{
  position: absolute; top: 10px; left: 10px; width: 220px; max-height: 130px;
  overflow: hidden;
  background: rgba(4,10,15,0.55);
  border: 1px solid rgba(255,255,255,0.1);
  border-radius: 10px;
  padding: 8px 12px;
  backdrop-filter: blur(2px);
}
.battle-log{
  max-height: 114px; overflow-y:auto; display:flex; flex-direction:column-reverse;
  font-size:0.72rem; line-height:1.5; color: var(--parchment-dim);
}
.battle-log .log-new{ color: var(--parchment); }

/* ---------------- Piles + hand ---------------- */
.pile-row{
  display:flex; align-items:center; gap:16px; padding: 4px 20px;
}
.pile{
  display:flex; align-items:center; gap:6px;
  font-family:'IBM Plex Mono', monospace; font-size:0.85rem; color: var(--parchment-dim);
}
.pile-icon{ height:1.6rem; width:auto; filter: drop-shadow(0 1px 2px rgba(0,0,0,0.5)); }
.pile-row .btn{ margin-left:auto; }

.ap-diamond{
  width:44px; height:44px; flex:none;
  background: linear-gradient(180deg, var(--brass-bright), var(--brass));
  transform: rotate(45deg);
  border-radius: 8px;
  box-shadow: 0 4px 0 #8B6C2E, 0 8px 14px rgba(0,0,0,0.35);
  display:flex; align-items:center; justify-content:center;
}
.ap-diamond span{
  transform: rotate(-45deg);
  font-family:'IBM Plex Mono', monospace; font-weight:700; font-size:0.72rem;
  color:#22160A;
}

.hand{
  display:flex; gap:12px; padding: 14px 20px 26px;
  overflow-x:auto; justify-content: flex-start;
  min-height: 210px;
}

.card{
  flex: none;
  width: 128px; height: 178px;
  border-radius: 12px;
  position:relative;
  background: linear-gradient(180deg, #1B3A50, #0F2434);
  border: 2px solid var(--neutral);
  cursor:pointer;
  display:flex; flex-direction:column;
  overflow:hidden;
  transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
  box-shadow: 0 6px 14px rgba(0,0,0,0.4);
}
.card:hover{ transform: translateY(-10px); box-shadow: 0 14px 26px rgba(0,0,0,0.55); }
.card.unaffordable{ opacity:0.45; cursor:not-allowed; }
.card.unaffordable:hover{ transform:none; }
.card.pickable{ border-color: var(--brass-bright); box-shadow: 0 0 0 2px rgba(233,196,104,0.4), 0 6px 14px rgba(0,0,0,0.4); }
/* Wave 1's scripted sequence — a card that isn't the current required
   step, distinct from .unaffordable ("you can't afford this yet") since
   the message here is "this isn't the one to play right now" instead.
   Heavier dimming, no pointer cursor, and — unlike .unaffordable — never
   gets a click handler bound at all (see renderCardEl()), so this class
   is purely visual confirmation of a state the DOM already enforces. */
.card.tutorial-locked{ opacity:0.3; cursor:default; filter:grayscale(0.6); }
.card.tutorial-locked:hover{ transform:none; }
/* The one card a scripted tutorial step actually wants played — sorted
   to the front of the hand (see render()) and highlighted here too, so
   it isn't mistaken for one of the surrounding locked cards, especially
   since a locked card can still carry the same discount badge (a
   captain discount can apply to whichever card is played next,
   independent of which one the sequence itself requires). */
.card.tutorial-required{ animation: pulseHint 1.6s ease-in-out infinite; border-color: var(--brass-bright) !important; box-shadow: 0 0 0 0 rgba(233,196,104,0.55), 0 6px 14px rgba(0,0,0,0.4); }

/* End Turn, once a scripted tutorial turn has nothing left to play —
   see tutorialNothingLeftThisTurn(). A fully dimmed hand with AP still
   unspent otherwise reads as stuck rather than "you're done here." */
@keyframes pulseHint{
  0%, 100%{ box-shadow: 0 0 0 0 rgba(233,196,104,0.55); }
  50%{ box-shadow: 0 0 0 8px rgba(233,196,104,0); }
}
.pulse-hint{ animation: pulseHint 1.6s ease-in-out infinite; border-color: var(--brass-bright) !important; }

/* End Turn confirmation — real user feedback: highlight it red and
   require a real confirmation (hold, or tap-arm-then-tap-confirm) when
   AP is still unspent on something playable in hand. See
   handHasAffordablePlay() and its wiring in game.js. */
#btn-end-turn.end-turn-warn{
  background: var(--danger);
  color: #fff;
  border-color: rgba(255,255,255,0.3);
  box-shadow: 0 0 0 2px rgba(192,68,46,0.35);
}
#btn-end-turn.end-turn-warn:hover{ filter: brightness(1.15); }
#btn-end-turn.end-turn-warn.confirm-armed{
  animation: endTurnArmedPulse 0.9s ease-in-out infinite;
}
@keyframes endTurnArmedPulse{
  0%, 100%{ box-shadow: 0 0 0 2px rgba(192,68,46,0.35); }
  50%{ box-shadow: 0 0 0 7px rgba(192,68,46,0.55); }
}
#btn-end-turn.holding{ position: relative; overflow: hidden; }
#btn-end-turn.holding::after{
  content:""; position:absolute; inset:0;
  background: rgba(255,255,255,0.3);
  transform-origin: left; transform: scaleX(0);
  animation: endTurnHoldFill 0.55s linear forwards;
}
@keyframes endTurnHoldFill{ to{ transform: scaleX(1); } }

.card[data-element="fire"]{ border-color: var(--fire); }
.card[data-element="earth"]{ border-color: var(--earth); }
.card[data-element="lightning"]{ border-color: var(--lightning); }
.card[data-element="air"]{ border-color: var(--air); }
.card[data-element="water"]{ border-color: var(--water); }

.card-cost{
  position:absolute; top:6px; left:6px; z-index:2;
  width:24px; height:24px; border-radius:50%;
  background: var(--brass-bright); color:#22160A;
  font-family:'IBM Plex Mono', monospace; font-weight:700; font-size:0.8rem;
  display:flex; align-items:center; justify-content:center;
  box-shadow: 0 2px 4px rgba(0,0,0,0.4);
}
/* A captain/card discount actively making this card cheaper right now
   (Cross's every-5th-card, Squall's first-card, Stormcaller's
   wave-opener, Disco's lucky roll, Refill Cannon, Hasty Plan,
   critical-HP-free) — .card-cost above already shows the real
   discounted number, not the sticker cost; this is the reason why,
   reusing the exact same text playCard()'s own log line shows for the
   same event. Truncates with an ellipsis rather than wrapping/
   overflowing a 128px-wide card — the full text is still in the
   title attribute for hover/long-press. */
.card-discount-badge{
  position:absolute; top:4px; left:32px; right:4px; z-index:2;
  background: rgba(233,196,104,0.94); color:#22160A;
  font-family:'IBM Plex Mono', monospace; font-weight:700; font-size:0.5rem;
  line-height:1.2; padding:2px 5px; border-radius:6px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.4);
  text-align:center; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}

/* Equipment rarity badge — shape-coded instead of text, since rarity
   words ("Legendary") overflowed the round AP-cost-style badge. Used
   in place of .card-cost on equipment tiles (reward picks, Loadout
   equip grid, the catalog) — same corner position, no text, the full
   rarity name is still available on hover via title. */
.rarity-badge{
  position:absolute; top:6px; left:6px; z-index:2;
  width:22px; height:22px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.4);
}
.rarity-badge[data-rarity="common"]{ background: var(--neutral); border-radius:50%; }
.rarity-badge[data-rarity="rare"]{ background: var(--water); clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%); }
.rarity-badge[data-rarity="legendary"]{ background: var(--brass-bright); clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%); }
.rarity-badge[data-rarity="mythic"]{ background: var(--mythic); clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%); }

.card-art{ flex: 1 1 auto; position:relative; }
.card-art .art-fallback{ font-size: 2.4rem; }
.card-body{
  padding: 6px 8px 8px; background: rgba(8,20,30,0.9);
}
.card-name{ font-size:0.72rem; font-weight:700; line-height:1.15; margin-bottom:3px; }
.card-desc{ font-size:0.62rem; color: var(--parchment-dim); line-height:1.3; }

/* Generic art-slot component: real PNG on top, CSS fallback beneath */
.art-slot{ position:relative; overflow:hidden; background: #0E202D; }
.art-slot img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; z-index:1; }
.art-fallback{
  position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
  font-size:2.8rem;
}
.art-slot[data-kind="fire"] .art-fallback{ background: radial-gradient(circle, #6b2a13, #2a0f06); }
.art-slot[data-kind="earth"] .art-fallback{ background: radial-gradient(circle, #454f27, #1c2110); }
.art-slot[data-kind="lightning"] .art-fallback{ background: radial-gradient(circle, #4d3566, #1d1428); }
.art-slot[data-kind="air"] .art-fallback{ background: radial-gradient(circle, #2c5a61, #102428); }
.art-slot[data-kind="water"] .art-fallback{ background: radial-gradient(circle, #1f4160, #0c1c2b); }
.art-slot[data-kind="neutral"] .art-fallback{ background: radial-gradient(circle, #33404a, #14191d); }

/* ---------------- Loadout / prep screen ---------------- */
#screen-loadout{ position:relative; overflow:hidden; }
/* Real user bug report, three separate rounds before this was actually
   found: content on a short tab (Crew, then Equipment on a different
   report) rendered vertically centered — "further down", "not aligned
   the same", "centers to the middle" were all the same underlying bug
   seen at different tab/device-height combinations. Root cause: plain
   `margin: auto` here was meant only to horizontally center this
   max-width:960px box, but .loadout-wrap is a flex item inside
   .screen (display:flex; flex-direction:column) — flexbox's `margin:
   auto` absorbs free space on BOTH axes for a flex item, not just the
   one it looks like it targets, so on any tab short enough to fit the
   viewport (confirmed live: a 430×932 iPhone-15-Pro-Max-sized viewport
   with Crew's collapsed, both-slots-filled content measured 84px of
   empty space above and 83px below — genuine centering, not a rounding
   artifact) the whole page centered vertically instead of staying
   pinned to the top like every taller tab already did. `margin: 0
   auto` keeps the horizontal centering (0 vertical margin — nothing
   left for flexbox to auto-distribute there) without the side effect. */
#screen-loadout .loadout-wrap{
  margin: 0 auto; text-align:center; max-width:960px; width:100%; padding: 38px 22px 64px;
  position:relative; z-index:1;
}

/* Header block — same brass-gradient Pirata One treatment as the title screen */
.loadout-hero{ margin-bottom: 32px; text-align:center; }
.loadout-kicker{
  font-family:'IBM Plex Mono', monospace;
  font-size:0.72rem; letter-spacing:0.28em; text-transform:uppercase;
  color: var(--brass-bright); margin:0 0 12px; opacity:0.9;
}
.loadout-title{
  font-family:'Pirata One', serif;
  font-size: clamp(2.2rem, 6vw, 3.8rem);
  line-height:0.98; margin: 0 0 14px;
  background: linear-gradient(180deg, #F6DD9A 20%, var(--brass-bright) 55%, var(--brass) 100%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
  filter: drop-shadow(0 3px 0 rgba(0,0,0,0.55)) drop-shadow(0 0 26px rgba(233,196,104,0.22));
}
.loadout-subtitle{
  color: var(--parchment-dim); font-size:0.95rem; line-height:1.55;
  max-width: 60ch; margin: 0 auto 16px;
}

.coin-balance{
  display:inline-flex; align-items:center; gap:8px;
  font-family:'IBM Plex Mono', monospace; font-size:1.02rem; color: var(--brass-bright);
  background: rgba(11,26,36,0.65); border: 1px solid rgba(233,196,104,0.25);
  border-radius: 999px; padding: 8px 16px; backdrop-filter: blur(4px);
  box-shadow: 0 4px 14px rgba(0,0,0,0.25);
}
.coin-icon{ height:1.3rem; width:auto; filter: drop-shadow(0 1px 2px rgba(0,0,0,0.5)); }

/* Subtle floating card silhouettes behind the panels */
.loadout-deco{
  position:absolute; inset:0; z-index:0; pointer-events:none; overflow:hidden;
}
.loadout-deco-card{
  position:absolute; width:120px; height:160px; border-radius:12px;
  background:
    linear-gradient(180deg, rgba(245,234,208,0.08) 0%, rgba(245,234,208,0.02) 100%);
  border: 2px solid rgba(233,196,104,0.12);
  opacity:0.18;
  box-shadow: 0 14px 30px rgba(0,0,0,0.35);
  animation: cardFloat 12s ease-in-out infinite;
}
.ldc-1{ top: 10%; left: -2%; transform: rotate(-16deg); animation-delay:0s; }
.ldc-2{ top: 44%; right: -3%; transform: rotate(12deg); animation-delay:-4s; width:100px; height:132px; opacity:0.12; }
.ldc-3{ bottom: 8%; left: 6%; transform: rotate(-8deg); animation-delay:-7.5s; width:80px; height:108px; opacity:0.10; }

/* Reuses .collection-nav/.collection-nav-btn's pill styling (see below)
   for visual consistency with the Achievements/Help modals' own nav —
   just a touch of extra top spacing since this sits on a full page
   between the hero and the sections, not inside a modal right below a
   header. No position:sticky (see .collection-nav's own comment on why
   this codebase avoids it) — deliberately plain and non-scrolling. */
#loadout-tabs{ margin-top:8px; }

.loadout-heading{
  font-family:'Pirata One', serif; font-size:1.35rem; color: var(--brass-bright);
  margin: 0; text-align:left;
  display:flex; align-items:center; gap:12px;
}
.loadout-heading::after{
  content:""; flex:1; height:1px;
  background: linear-gradient(90deg, rgba(233,196,104,0.45), transparent);
  margin-left: 4px;
}
/* Each loadout section (Captain/Ship/Equipment/Crew/Deck) collapses its
   own big pick-from-N grid behind a toggle — real user feedback that the
   whole "Prepare Your Voyage" page turned into a long scroll once most
   of the roster (and especially the ever-growing card collection) was
   unlocked. The compact "current pick" pieces (detail panel, slot
   cards) stay visible above the fold regardless. Each section is also a
   framed panel, matching Choose Your Voyage's mode cards.
   Real user feedback, second round: on top of that, only ONE section is
   ever shown at a time now — real tabs (#loadout-tabs), not all 5
   stacked — see switchLoadoutTab() in game.js. display:none is the
   default here; .tab-active overrides it for whichever section is
   currently selected. Toggling display:none -> block already restarts
   `animation: loadoutPanelIn` for free each time a tab becomes active,
   which is also why the old per-section staggered nth-of-type
   animation-delay rules are gone — they only made sense when all 5
   sections rendered together on page load. */
.loadout-section{
  display:none;
  margin: 20px 0; padding: 22px;
  text-align:left;
  background: linear-gradient(180deg, rgba(28,62,86,0.88) 0%, rgba(16,38,52,0.94) 100%);
  border: 1px solid rgba(233,196,104,0.30);
  border-radius: 16px;
  box-shadow: 0 14px 36px rgba(0,0,0,0.35), inset 0 1px 0 rgba(255,255,255,0.08);
  animation: loadoutPanelIn 0.5s ease both;
}
.loadout-section.tab-active{ display:block; }
@keyframes loadoutPanelIn{
  from{ opacity:0; transform: translateY(18px); }
  to{ opacity:1; transform: translateY(0); }
}
.loadout-section-head{
  display:flex; align-items:center; justify-content:space-between; gap:12px;
  margin-bottom:14px;
}
.loadout-toggle-btn{ flex:none; }
.loadout-browse{ margin-top:14px; }
/* Real user feedback: the toggle/Done button used to live in the
   section header, so confirming a pick after browsing a long grid
   (especially the ever-growing card collection) meant scrolling all
   the way back up. Now a direct child of .loadout-section, placed
   after that section's browse grid in the HTML — see index.html —
   so it always lands wherever the section's content actually ends,
   collapsed or expanded. */
.loadout-section > .loadout-toggle-btn{ display:block; margin-top:14px; }
#btn-depart.loadout-depart{
  width: 100%;
  max-width: 340px;
  margin: 34px auto 0;
  box-shadow: 0 6px 0 #8B6C2E, 0 10px 22px rgba(0,0,0,0.45), 0 0 36px rgba(233,196,104,0.18);
}
#screen-loadout #btn-resume{
  display: block;
  width: 100%;
  max-width: 340px;
  margin: 14px auto 0;
}
#crew-heading-note:not(:empty), #captain-heading-note:not(:empty){
  background: rgba(201,162,75,0.14);
  border: 1px solid var(--brass);
  border-radius: 8px;
  padding: 10px 14px;
  color: var(--parchment);
  font-weight: 600;
  text-align: left;
}

.ship-tile, .crew-tile, .captain-tile{ height:auto; min-height:178px; padding-bottom:10px; }
.ship-tile .card-art, .crew-tile .card-art, .captain-tile .card-art{ min-height:90px; }

.card.locked{ opacity:0.5; }
.card.locked:hover{ transform:none; }
.card.selected{ border-color: var(--brass-bright); box-shadow: 0 0 0 2px var(--brass-bright), 0 6px 14px rgba(0,0,0,0.4); }

.lock-badge{ margin-top:6px; font-size:0.62rem; color: var(--brass-bright); }
.free-badge{ color: var(--earth); }
.card.free-pick{ opacity:1; border-color: var(--earth); box-shadow: 0 0 0 2px var(--earth), 0 6px 14px rgba(0,0,0,0.4); }
.card.picked-for-detail{ outline: 2px solid var(--parchment); outline-offset: 2px; }

/* Mythic equipment with 2 variants (Cannon, Full Sail) — inline switcher
   inside the reward-tile card, buttons stopPropagation so clicking one
   doesn't also toggle the whole item equipped/unequipped. */
.mythic-variant-switcher{ display:flex; gap:6px; justify-content:center; flex-wrap:wrap; margin-top:8px; }
.mythic-variant-switcher .btn:disabled{ opacity:1; border-color: var(--brass-bright); cursor:default; }

/* Equipped crew slots (click to view in the detail panel) */
.crew-slots{ display:flex; gap:14px; justify-content:center; margin-bottom:16px; flex-wrap:wrap; }
.crew-slot-card{
  width:150px; min-height:110px; border-radius:12px;
  border:2px solid rgba(233,196,104,0.25);
  background: rgba(11,26,36,0.55);
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:5px; padding:12px; cursor:pointer; text-align:center;
  transition: border-color .15s ease, transform .15s ease;
}
.crew-slot-card:hover{ transform: translateY(-3px); }
.crew-slot-card.filled{ border-color: var(--brass-bright); }
.crew-slot-card.filled.selected{ box-shadow: 0 0 0 2px var(--parchment); }
.crew-slot-card.empty{ color: var(--parchment-dim); border-style:dashed; }
.crew-slot-icon{ font-size:1.8rem; }
.crew-slot-portrait{
  width:56px; height:56px; border-radius:50%; flex:none;
  border:2px solid var(--brass); background: rgba(0,0,0,0.3);
}
.crew-slot-portrait .art-fallback{ font-size:1.6rem; border-radius:50%; }
.crew-slot-name{ font-size:0.78rem; font-weight:700; }
.crew-slot-level{ font-size:0.65rem; color: var(--parchment-dim); }

/* Detail panel for the currently selected crew member */
.crew-detail{
  display:none; gap:20px; align-items:center;
  background: rgba(0,0,0,0.28); border:1px solid rgba(255,255,255,0.08);
  border-radius: var(--radius); padding:18px; margin-bottom:22px; text-align:left;
}
.crew-detail.active{ display:flex; }
.crew-detail-portrait{
  width:96px; height:96px; flex:none; border-radius:12px; border:2px solid var(--neutral);
  display:flex; align-items:center; justify-content:center; font-size:3rem;
  background: rgba(0,0,0,0.3);
}
.crew-detail-portrait[data-rarity="common"]{ border-color: var(--neutral); }
.crew-detail-portrait[data-rarity="rare"]{ border-color: var(--water); }
.crew-detail-portrait[data-rarity="legendary"]{ border-color: var(--brass-bright); }
.crew-detail-body{ flex:1; min-width:0; }
.crew-detail-name{ font-family:'Pirata One', serif; font-size:1.4rem; color: var(--parchment); margin-bottom:6px; }
.crew-detail-tags{ display:flex; gap:6px; margin-bottom:8px; flex-wrap:wrap; }
.crew-detail-desc{ color: var(--parchment-dim); font-size:0.85rem; margin-bottom:12px; }
.crew-detail-actions{ display:flex; gap:10px; flex-wrap:wrap; }
.ship-flavor{ color: var(--parchment-dim); font-size:0.8rem; font-style:italic; line-height:1.5; margin: 4px 0 12px; }

.ship-skill-row{ display:flex; gap:8px; flex-wrap:wrap; margin-bottom:12px; }
.skill-chip{
  font-size:0.7rem; padding:4px 10px; border-radius:999px;
  background: rgba(0,0,0,0.35); border:1px solid rgba(255,255,255,0.15);
  color: var(--parchment-dim);
}
.skill-chip.unlocked{ border-color: var(--brass-bright); color: var(--brass-bright); }
.skill-chip-lv{ font-weight:700; margin-right:4px; }

.crew-roster{ margin-bottom:10px; }

/* Deck builder */
.deck-default-row{ opacity:0.85; margin-bottom:18px; }
.deck-default-card{ cursor:default; }
.deck-default-card:hover{ transform:none; }
.deck-collection-grid{ margin-bottom:10px; }
.deck-collection-tile{ display:flex; flex-direction:column; align-items:center; gap:6px; }
.deck-stepper{ display:flex; align-items:center; gap:8px; }
.deck-stepper .btn-small{ padding:3px 10px; font-size:0.75rem; }
.deck-stepper-count{ font-family:'IBM Plex Mono', monospace; font-size:0.72rem; color: var(--parchment-dim); min-width:38px; text-align:center; }

/* Quick-remove badge on the always-visible "built into this run's
   deck" extras row — the card tile itself reuses .deck-default-card
   (display only), this button is the one interactive part. */
.deck-extra-remove{
  position:absolute; top:4px; right:4px; z-index:2;
  width:20px; height:20px; border-radius:50%;
  background: rgba(11,26,36,0.85); border:1px solid rgba(233,196,104,0.4);
  color: var(--parchment); font-size:0.85rem; line-height:1; cursor:pointer;
  display:flex; align-items:center; justify-content:center;
}
.deck-extra-remove:hover{ border-color: var(--danger); color: var(--danger); }

/* Deck presets — save/load up to 3 named 10-card selections. Same
   dark-card-with-gold-border language as .crew-slot-card, not a new
   visual pattern. */
.deck-presets{ display:flex; flex-wrap:wrap; gap:10px; align-items:flex-start; margin-bottom:16px; }
.deck-preset-tile{
  width:150px; min-height:90px; border-radius:12px;
  border:2px solid rgba(233,196,104,0.25);
  background: rgba(11,26,36,0.55);
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:6px; padding:12px; text-align:center;
}
.deck-preset-tile.filled{ border-color: var(--brass-bright); }
.deck-preset-name{ font-size:0.8rem; font-weight:700; color: var(--parchment); word-break:break-word; }
.deck-preset-name.deck-preset-empty{ color: var(--parchment-dim); font-weight:400; font-style:italic; }
.deck-preset-count{ font-size:0.68rem; color: var(--parchment-dim); }
.deck-preset-actions{ display:flex; gap:6px; align-items:center; }
.deck-preset-actions .btn-small{ padding:3px 8px; font-size:0.68rem; }
.deck-preset-delete{
  width:20px; height:20px; border-radius:50%; flex:none;
  background: rgba(11,26,36,0.85); border:1px solid rgba(233,196,104,0.4);
  color: var(--parchment); font-size:0.8rem; line-height:1; cursor:pointer;
  display:flex; align-items:center; justify-content:center;
}
.deck-preset-delete:hover{ border-color: var(--danger); color: var(--danger); }
.deck-preset-clear{ align-self:center; }

.deck-toolbar{ display:flex; flex-wrap:wrap; gap:8px; margin-bottom:14px; }
.deck-search-input, .deck-filter-select{
  background: var(--ink-3);
  border: 1px solid var(--brass);
  color: var(--parchment);
  font-family:'IBM Plex Sans', sans-serif;
  font-size:0.8rem;
  border-radius:6px;
  padding:6px 10px;
}
.deck-search-input{ flex:1 1 160px; min-width:120px; }
.deck-search-input::placeholder{ color: var(--parchment-dim); }
.deck-filter-select{ flex:0 0 auto; }
.deck-search-input:focus, .deck-filter-select:focus{ outline:2px solid var(--brass-bright); outline-offset:1px; }

.card[data-rarity="common"]{ border-color: var(--neutral); }
.card[data-rarity="rare"]{ border-color: var(--water); }
.card[data-rarity="legendary"]{ border-color: var(--brass-bright); }

.btn-small{ padding:5px 12px; font-size:0.68rem; margin-top:6px; }

.crew-bar{ display:flex; gap:10px; padding: 0 20px 10px; flex-wrap:wrap; }
.crew-active-btn{ font-size:0.8rem; }
.crew-active-btn.armed{ border-color: var(--brass-bright); color: var(--brass-bright); }

/* ---------------- Modals ---------------- */
.modal-overlay{
  display:none; position:fixed; inset:0; background: rgba(4,10,15,0.78);
  align-items:center; justify-content:center; z-index: 50; padding:20px;
}
.modal-overlay.active{ display:flex; }
.modal-overlay.input-lock{ pointer-events: none; }
.modal-overlay.input-lock .modal{ opacity: 0.72; }
.modal{
  background: linear-gradient(180deg, #16324675, #0e222f);
  background-color: #14293A;
  border: 1px solid rgba(233,196,104,0.35);
  border-radius: 16px;
  padding: 30px; max-width: 620px; width:100%;
  text-align:center;
  box-shadow: var(--shadow-deep);
}
.modal-title{ font-family:'Pirata One', serif; font-size:2.1rem; color: var(--brass-bright); margin:0 0 6px; }
.modal-sub{ color: var(--parchment-dim); margin: 0 0 20px; font-size:0.9rem; }
.modal-btn-row{ display:flex; gap:12px; justify-content:center; flex-wrap:wrap; }
.reward-cards{ display:flex; gap:14px; justify-content:center; margin-bottom:20px; flex-wrap:wrap; }

/* ---------------- Menu / Settings / Help ---------------- */
/* One overflow menu instead of one fixed icon per destination — real
   user feedback that 2 already crowded the top-right corner (see .hud's
   reserved right-padding below), and a 3rd (Help, split out from
   Settings) would only get worse, especially on narrow/mobile
   viewports. Scales to any number of menu items with zero extra HUD
   footprint. */
.menu-fab-wrap{ position:fixed; top:14px; right:14px; z-index:40; }
.menu-fab{
  width:40px; height:40px; border-radius:50%;
  background: var(--ink-3); border: 1px solid rgba(233,196,104,0.35);
  color: var(--parchment); font-size:1.1rem; cursor:pointer;
  display:flex; align-items:center; justify-content:center;
  transition: filter 0.12s ease, transform 0.12s ease;
}
.menu-fab:hover{ filter: brightness(1.25); }
.menu-fab:active{ transform: scale(0.94); }
.menu-dropdown{
  display:none; flex-direction:column;
  position:absolute; top:48px; right:0; min-width:230px;
  background: var(--ink-3); border: 1px solid rgba(233,196,104,0.35);
  border-radius: 10px; overflow:hidden;
  box-shadow: var(--shadow-deep);
}
.menu-dropdown.open{ display:flex; }
.menu-item{
  display:flex; align-items:center; gap:10px;
  padding: 12px 16px; background:transparent; border:none;
  color: var(--parchment); font-size:0.92rem; text-align:left;
  cursor:pointer; font-family: inherit;
}
.menu-item:hover{ background: rgba(255,255,255,0.07); }
.menu-item + .menu-item{ border-top: 1px solid rgba(233,196,104,0.15); }
/* Real user feedback: the ✕ used to scroll away with the content
   since it was just absolutely-positioned inside the one scrolling
   element. A position:sticky header (tried first) fixed that on
   desktop but showed a visible content sliver above it during
   momentum scroll on mobile — a known iOS quirk with sticky elements
   nested inside a scrolling box. Restructured instead so the header
   is a plain, non-scrolling flex sibling that never shares a scroll
   region with .help-content at all — only .help-content scrolls. */
.modal-help{
  max-width: 640px; max-height: 82vh;
  display:flex; flex-direction:column;
  text-align:left; position:relative;
}
.modal-help-header{
  position:relative; flex-shrink:0;
  padding-bottom:12px; margin-bottom:12px;
  border-bottom: 1px solid rgba(233,196,104,0.2);
}
.modal-help .modal-title{ text-align:center; margin:0; padding-right:40px; }
.help-close{
  position:absolute; top:0; right:0;
  width:32px; height:32px; border-radius:50%;
  background: var(--ink-3); border: 1px solid rgba(233,196,104,0.35);
  color: var(--parchment); font-size:0.95rem; cursor:pointer;
}
.help-close:hover{ filter: brightness(1.25); }
/* Catch-up toast for an achievement unlocked mid-battle and missed —
   see checkForNewAchievements(). Sits in normal document flow (not
   showTurnBanner()'s absolutely-positioned, auto-hiding battle-screen
   banner, which lives in a completely different part of the DOM this
   modal can't reach), stays until the modal is closed and reopened
   with nothing new to report. */
.achievements-new-toast{
  background: rgba(233,196,104,0.14);
  border: 1px solid var(--brass-bright);
  border-radius: 10px;
  padding: 10px 14px;
  margin: 0 0 14px;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--parchment);
  line-height: 1.5;
}
/* Jump nav for #modal-achievements only (4 sections is enough to make
   4600px+ of blind scrolling a real problem) — a plain, non-scrolling
   flex sibling above .help-content, same reasoning as the header
   above: sticky-inside-a-scroll-box has that iOS momentum-scroll
   sliver bug, so this stays out of the scroll region entirely instead. */
.collection-nav{
  display:flex; gap:6px; flex-wrap:wrap; flex-shrink:0;
  margin-bottom:14px; padding-bottom:12px;
  border-bottom: 1px solid rgba(233,196,104,0.2);
}
.collection-nav-btn{
  flex:1 1 auto; padding:7px 10px; border-radius:999px;
  background: rgba(0,0,0,0.25); border:1px solid rgba(233,196,104,0.25);
  color: var(--parchment-dim); font-size:0.76rem; font-weight:600;
  cursor:pointer; text-align:center; white-space:nowrap;
  transition: border-color .15s ease, color .15s ease, background .15s ease;
  /* See .btn's own touch-action comment — same double-tap-zoom fix,
     needed here too since these buttons don't carry the .btn class. */
  touch-action: manipulation;
}
.collection-nav-btn:hover{ border-color: rgba(233,196,104,0.5); color: var(--parchment); }
.collection-nav-btn.active{
  background: rgba(233,196,104,0.14); border-color: var(--brass-bright); color: var(--brass-bright);
}
.help-content{ flex:1; min-height:0; overflow-y:auto; }
.help-section{ margin-bottom:22px; }
.help-section h3{
  font-family:'Pirata One', serif; font-size:1.25rem; color: var(--brass-bright);
  margin: 0 0 8px; border-bottom: 1px solid rgba(233,196,104,0.2); padding-bottom:4px;
}
.help-section p{ color: var(--parchment); font-size:0.85rem; line-height:1.55; margin:0 0 8px; }
.help-section p a{ color: var(--brass-bright); text-decoration: underline; }
.help-section p a:hover{ filter: brightness(1.15); }
.help-section ul{ margin:0 0 8px; padding-left:20px; }
.help-section li{ color: var(--parchment); font-size:0.85rem; line-height:1.55; margin-bottom:6px; }
.achievements-tracks{ display:flex; flex-direction:column; gap:8px; }
.achv-track-row{
  display:flex; align-items:center; gap:12px;
  padding:8px 10px; border-radius:10px;
  background: rgba(0,0,0,0.2); border: 1px solid rgba(233,196,104,0.12);
  filter:grayscale(0.5);
}
.achv-track-row.unlocked{ filter:none; border-color: rgba(233,196,104,0.3); }
.achv-track-icon{
  width:40px; height:40px; border-radius:8px; object-fit:contain; flex-shrink:0;
  background: rgba(0,0,0,0.3);
}
.achv-track-info{ flex:1; min-width:0; }
.achv-track-name{ font-size:0.85rem; color: var(--parchment); }
.achv-track-row.unlocked .achv-track-name{ color: var(--brass-bright); }
.achv-track-progress{ font-size:0.72rem; color: var(--parchment-dim); margin-top:2px; }
.mastery-grid{
  display:grid; grid-template-columns: repeat(auto-fill, minmax(72px, 1fr));
  gap:10px;
}
.mastery-tile{
  display:flex; flex-direction:column; align-items:center; gap:3px;
  padding:6px; border-radius:8px; opacity:0.5; filter:grayscale(0.5);
}
.mastery-tile.unlocked{ opacity:1; filter:none; }
.mastery-tile.maxed{ background: rgba(233,196,104,0.08); }
.mastery-tile img{ width:100%; aspect-ratio:1; object-fit:cover; border-radius:50%; border: 1px solid rgba(233,196,104,0.25); }
.mastery-tile-name{ font-size:0.6rem; color: var(--parchment-dim); text-align:center; line-height:1.2; }
.mastery-tile-rank{ font-size:0.58rem; color: var(--parchment-dim); text-align:center; }
.mastery-tile.unlocked .mastery-tile-rank{ color: var(--brass-bright); font-weight:600; }
.mastery-tile.maxed .mastery-tile-rank{ color: var(--good, #7FA96B); }
.ship-skins-filter-row{ display:flex; gap:12px; align-items:center; margin:10px 0 14px; flex-wrap:wrap; }
.skin-search-input{
  flex:1; min-width:160px;
  background: var(--ink-3); border: 1px solid rgba(233,196,104,0.3); border-radius:8px;
  padding:8px 10px; color: var(--parchment); font-size:0.85rem;
}
.skin-search-input:focus{ outline:none; border-color: var(--brass-bright); }
.skin-search-input::placeholder{ color: var(--parchment-dim); }
.skin-search-toggle{ font-size:0.8rem; white-space:nowrap; }
/* A tile hidden by the search/unlocked-only filters — kept in the DOM
   (not removed) so the unlocked-first sort order and click handlers
   stay simple, just visually collapsed to nothing. */
.skin-tile.filtered-out{ display:none; }
.ship-skins-by-hull, .skin-hull-section-list{ display:flex; flex-direction:column; gap:16px; }
.skin-hull-section h4{
  font-family:'Pirata One', serif; font-size:1rem; color: var(--brass-bright);
  margin:0 0 8px;
}
.skin-tile-row{
  display:flex; gap:10px; overflow-x:auto; padding-bottom:4px;
}
.skin-tile{
  flex-shrink:0; width:96px; text-align:center;
  padding:6px; border-radius:8px;
  border: 2px solid transparent;
  position:relative;
}
.skin-tile.locked{ opacity:0.45; filter:grayscale(0.6); }
.skin-tile.selectable{ cursor:pointer; }
.skin-tile.selectable:hover{ background: rgba(233,196,104,0.08); }
.skin-tile.selected{ border-color: var(--brass-bright); background: rgba(233,196,104,0.1); }
.skin-tile img{
  width:100%; aspect-ratio:1; object-fit:contain; border-radius:6px;
  background: rgba(0,0,0,0.3);
}
/* Equipment tiles swap the plain square img above for the same circular
   gold-ring badge equipment already uses elsewhere (Loadout equipped
   slots, salvage reward cards) — .crew-slot-portrait is a fixed 56px
   circle, so it needs centering inside this 96px tile itself. */
.skin-tile .crew-slot-portrait{ margin: 0 auto; }
.skin-tile-name{
  font-size:0.62rem; color: var(--parchment-dim); margin-top:4px;
  line-height:1.2; min-height: calc(1.2em * 2);
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical;
  overflow:hidden; text-overflow:ellipsis;
}
.skin-tile.selected .skin-tile-name{ color: var(--brass-bright); font-weight:600; }
.skin-tile-lock{
  position:absolute; top:4px; right:4px; font-size:0.7rem;
  filter: drop-shadow(0 1px 2px rgba(0,0,0,0.8));
}
/* Your Island — a spatial scene (buildings placed on one island, not a
   card list) with a master/detail pair below it, the same convention
   .crew-detail-* already uses for the Loadout screen's Ship section —
   clicking a marker on the scene shows its info/action in
   #island-detail-panel rather than a floating tooltip anchored to
   click coordinates (no precedent for that anywhere in this codebase,
   and it's worse on mobile touch). */
.modal-island{ max-width: 960px; }
/* .modal-help is a flex column with a fixed max-height (82vh) — every
   other modal using it scrolls via .help-content's overflow-y:auto;
   this one has no .help-content wrapper, so it needs the same
   treatment directly or a tall scene+panel combo just gets clipped by
   the modal's own max-height with nothing to scroll it into view. */
#island-scene-wrap{
  margin-top:14px; flex:1; min-height:0; overflow-y:auto;
}
#island-scene{
  /* width:100% and max-height don't resolve together cleanly against a
     fixed aspect-ratio (max-height wins but width doesn't shrink to
     compensate, stretching the box) — sizing width as the min of "full
     container width" and "whatever a 46vh-tall 16:10 box would be
     wide" keeps the real ratio intact either way, whichever constraint
     is tighter. */
  position:relative; width:min(100%, calc(46vh * 1.6)); aspect-ratio: 16 / 10;
  border-radius:16px; overflow:hidden; margin:0 auto;
  background: radial-gradient(ellipse at center, #1c4a5e 0%, #0E202D 75%, #0B1A24 100%);
  border: 1px solid rgba(233,196,104,0.2);
}
/* Organic island silhouette — no background art asset exists for this
   (the toming.app catalog this project's whole art pipeline draws from
   has individual building/decoration sprites only, no terrain), so
   this is a plain CSS blob: two layered, slightly offset shapes using
   the asymmetric-border-radius trick for an organic (not rectangular)
   outline, fully responsive since it's not an image. */
.island-landmass-sand, .island-landmass-grass{
  position:absolute; border-radius: 63% 37% 54% 46% / 43% 65% 35% 57%;
}
.island-landmass-sand{
  top:10%; left:8%; width:84%; height:80%;
  background: #d9c08a;
}
.island-landmass-grass{
  top:16%; left:16%; width:68%; height:64%;
  background: #5b8c4a;
  border-radius: 58% 42% 48% 52% / 38% 58% 42% 62%;
}
.island-building-marker{
  position:absolute; transform: translate(-50%, -50%);
  display:flex; flex-direction:column; align-items:center; gap:2px;
  width:14%; min-width:44px; max-width:80px;
  background:none; border:none; padding:0; cursor:pointer;
  transition: transform 0.15s ease;
}
/* min-width alone doesn't shrink with the scene on narrow viewports —
   at mobile widths the scene itself gets much narrower (width:100% of
   a small modal) while 14% of that is smaller than any reasonable tap
   target, so min-width was winning and making markers proportionally
   *larger* relative to the shrunk scene, overlapping each other. Real
   bug, caught by measuring actual rendered rects at mobile width, not
   assumed. Dropping the name label below 640px removes the tallest
   part of each marker's footprint — the more effective fix, since
   vertical (label) height was overlapping sooner than horizontal width
   did in practice. */
@media (max-width: 640px){
  .island-building-marker{ min-width:32px; }
  .island-building-marker-name{ display:none; }
}
.island-building-marker:hover{ transform: translate(-50%, -50%) scale(1.08); }
.island-building-marker.selected .island-building-portrait{
  box-shadow: 0 0 0 3px var(--brass-bright), 0 4px 10px rgba(0,0,0,0.5);
}
.island-building-marker.locked{ opacity:0.55; filter:grayscale(0.6); }
.island-building-marker-name{
  font-family:'Pirata One', serif; font-size:0.68rem; color: var(--brass-bright);
  text-align:center; text-shadow: 0 1px 3px rgba(0,0,0,0.9);
  line-height:1.1;
}
.island-building-portrait{
  width:100%; aspect-ratio:1; border-radius:8px;
}
.island-building-portrait img{
  width:100%; height:100%; object-fit:contain; border-radius:6px;
  filter: drop-shadow(0 3px 6px rgba(0,0,0,0.6));
}
#island-detail-panel{
  display:flex; gap:14px; margin-top:16px; min-height:96px;
  padding:12px; border-radius:10px;
  background: rgba(0,0,0,0.2); border: 1px solid rgba(233,196,104,0.15);
}
#island-detail-panel .island-building-portrait{ width:72px; height:72px; flex-shrink:0; }
#island-detail-panel .island-building-level{
  font-family:'IBM Plex Mono', monospace; font-size:0.75rem;
  color: var(--parchment-dim);
}
.settings-toggle{
  display:flex; align-items:flex-start; gap:10px; cursor:pointer;
  font-size:0.85rem; color: var(--parchment); line-height:1.5;
}
.settings-toggle input{ margin-top:3px; width:16px; height:16px; accent-color: var(--brass-bright); cursor:pointer; flex-shrink:0; }
.settings-select-row{
  display:flex; align-items:center; justify-content:space-between; gap:10px;
  font-size:0.85rem; color: var(--parchment); margin-top:14px;
}
.settings-select-row[hidden]{ display:none; }
.settings-select{
  background: var(--ink-3); border: 1px solid rgba(233,196,104,0.3); border-radius:8px;
  padding:6px 10px; color: var(--parchment); font-size:0.85rem; cursor:pointer;
}
.settings-note{ font-size:0.72rem; color: var(--parchment-dim); margin-top:6px; line-height:1.5; }
.settings-slider{ width:140px; accent-color: var(--brass-bright); cursor:pointer; }
.redeem-row{ display:flex; gap:8px; }
.redeem-input{
  flex:1; min-width:0;
  background: var(--ink-3); border: 1px solid rgba(233,196,104,0.3); border-radius:8px;
  padding:8px 10px; color: var(--parchment); font-size:0.85rem;
  text-transform:uppercase; letter-spacing:0.04em;
}
.redeem-input:focus{ outline:none; border-color: var(--brass-bright); }
.redeem-msg{ font-size:0.78rem; margin:8px 0 0; min-height:1.1em; }
.redeem-msg.success{ color: var(--good, #7FA96B); }
.redeem-msg.error{ color: var(--danger); }
.save-transfer-block{ display:flex; flex-direction:column; gap:6px; margin-top:12px; }
.save-code-box{
  width:100%; box-sizing:border-box; resize:vertical;
  background: var(--ink-3); border: 1px solid rgba(233,196,104,0.3); border-radius:8px;
  padding:8px 10px; color: var(--parchment); font-size:0.72rem; font-family: monospace;
  line-height:1.4; word-break:break-all;
}
.save-code-box:focus{ outline:none; border-color: var(--brass-bright); }
.help-danger-zone{
  margin-top: 12px; padding-top:16px; border-top: 1px solid rgba(192,68,46,0.3);
  text-align:center;
}
.help-danger-label{
  font-size:0.7rem; text-transform:uppercase; letter-spacing:1.4px;
  color: var(--danger); margin: 0 0 8px; font-weight:600;
}

/* ---------------- Simple font (Settings toggle) ----------------
   Swaps every decorative 'Pirata One' heading for the plainer body
   face — real user feedback flagged the blackletter as hard to read,
   especially mixed with numbers/punctuation (deck counts, etc.). */
body.simple-font .game-title,
body.simple-font .enemy-name,
body.simple-font .loadout-heading,
body.simple-font .crew-detail-name,
body.simple-font .modal-title,
body.simple-font .help-section h3{
  font-family:'IBM Plex Sans', system-ui, sans-serif;
}

/* ---------------- Scrollbar ---------------- */
::-webkit-scrollbar{ height:8px; width:8px; }
::-webkit-scrollbar-thumb{ background: rgba(233,196,104,0.35); border-radius:8px; }

/* ---------------- Responsive ---------------- */
@media (max-width: 640px){
  .hud{ gap:12px; }
  .wheel-block{ margin-left:0; }
  .card{ width: 104px; height: 152px; }

  .ocean-battlefield{
    flex-direction: column-reverse; align-items:center; gap:10px;
    padding: 14px 14px 10px; min-height: 0;
  }
  .player-combatant, .enemy-combatant{ max-width: 100%; }
  .enemies-row{ max-width:100%; }
  .ship-portrait-lg{ width:130px; height:104px; }
  .enemy-portrait{ width:96px; height:80px; }
  .enemies-row .enemy-combatant .enemy-portrait{ width:96px; height:80px; }
  .combatant-hp, .enemy-combatant .combatant-hp{ width:130px; }
  .log-panel-mini{
    position: static; width:100%; max-height:80px;
  }
}

/* ==========================================================================
   Help / Settings / Achievements modals — storybook alignment
   Brings the three .modal-help popups in line with the redesigned title,
   Choose Your Voyage, and Prepare Your Voyage screens: navy-gradient
   panels, brass borders, brass-gradient Pirata One titles, kicker lines.
   Scoped to .modal-help so #modal-end / #modal-tutorial stay untouched.
   ========================================================================== */

/* Slightly softened, blurred backdrop behind these modals */
#modal-help.modal-overlay,
#modal-settings.modal-overlay,
#modal-achievements.modal-overlay{
  background: rgba(4,10,15,0.72);
  backdrop-filter: blur(5px);
}

.modal-help{
  background: linear-gradient(180deg, rgba(28,62,86,0.96) 0%, rgba(16,38,52,0.99) 100%);
  border: 1px solid rgba(233,196,104,0.45);
  border-radius: 20px;
  padding: 26px 26px 22px;
  box-shadow:
    0 24px 60px rgba(0,0,0,0.55),
    inset 0 1px 0 rgba(255,255,255,0.08),
    0 0 0 1px rgba(0,0,0,0.35);
}

/* Entrance — same family as the loadout/mode-select panels */
#modal-help.modal-overlay.active .modal,
#modal-settings.modal-overlay.active .modal,
#modal-achievements.modal-overlay.active .modal{
  animation: loadoutPanelIn 0.35s ease both;
}

/* Kicker above the title, same mono/letterspaced treatment as the heroes */
.modal-kicker{
  font-family:'IBM Plex Mono', monospace;
  font-size:0.68rem; letter-spacing:0.28em; text-transform:uppercase;
  color: var(--brass-bright); margin:0 0 8px; opacity:0.9;
  text-align:center;
}

/* Brass-gradient display title, matching .loadout-title */
.modal-help .modal-title{
  font-size: clamp(1.7rem, 4vw, 2.3rem);
  line-height:1;
  background: linear-gradient(180deg, #F6DD9A 20%, var(--brass-bright) 55%, var(--brass) 100%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
  filter: drop-shadow(0 2px 0 rgba(0,0,0,0.55)) drop-shadow(0 0 20px rgba(233,196,104,0.20));
}

/* Header rule — slightly richer brass line */
.modal-help .modal-help-header{
  padding-bottom:14px; margin-bottom:16px;
  border-bottom: 1px solid rgba(233,196,104,0.35);
  box-shadow: 0 1px 0 rgba(0,0,0,0.35);
}

/* Close button — brass chip like the title-screen pills */
.modal-help .help-close{
  background: rgba(11,26,36,0.65);
  border: 1px solid rgba(233,196,104,0.4);
  color: var(--brass-bright);
  transition: filter 0.12s ease, transform 0.12s ease;
}
.modal-help .help-close:hover{ filter: brightness(1.3); }
.modal-help .help-close:active{ transform: scale(0.92); }

/* Each section becomes a subtle panel-in-panel */
.modal-help .help-section{
  margin-bottom:16px;
  padding: 14px 16px;
  background: rgba(11,26,36,0.5);
  border: 1px solid rgba(233,196,104,0.16);
  border-radius: 12px;
}
.modal-help .help-section h3{
  border-bottom-color: rgba(233,196,104,0.28);
}
.modal-help .help-section > :last-child{ margin-bottom:0; }

/* Danger zone keeps its warning character but matches the panel language */
.modal-help .help-danger-zone{
  margin-top: 4px; padding: 14px 16px 12px;
  border: 1px solid rgba(192,68,46,0.35);
  border-top: 1px solid rgba(192,68,46,0.35);
  border-radius: 12px;
  background: rgba(60,16,10,0.25);
}

@media (max-width: 640px){
  .modal-help{ padding: 20px 16px 16px; }
  .modal-help .help-section{ padding: 12px; }
}

/* ================================================================
   BATTLE SCREEN BRUSH-UP — scoped to #screen-battle
   Same storybook navy/brass language as title, loadout and modals.
   ================================================================ */

#screen-battle.active{ animation: battleScreenIn 0.5s cubic-bezier(0.22, 1, 0.36, 1) both; }
@keyframes battleScreenIn{
  from{ opacity: 0; transform: translateY(14px); }
  to{ opacity: 1; transform: none; }
}

/* --- HUD: deeper navy with brass underline glow --- */
#screen-battle .hud{
  background: linear-gradient(180deg, rgba(27,58,80,0.98), rgba(11,26,36,0.9));
  border-bottom: 1px solid rgba(233,196,104,0.4);
  box-shadow: 0 1px 0 rgba(233,196,104,0.15), 0 8px 22px rgba(0,0,0,0.35);
  backdrop-filter: blur(3px);
}
#screen-battle .hud-value{ color: var(--brass-bright); text-shadow: 0 1px 4px rgba(0,0,0,0.6); }

/* --- Battlefield: night sea with moonlit swell --- */
#screen-battle .ocean-battlefield{
  border: 1px solid rgba(233,196,104,0.32);
  box-shadow: inset 0 0 60px rgba(0,0,0,0.45), var(--shadow-deep);
  background:
    radial-gradient(ellipse at 78% -8%, rgba(239,203,114,0.16), transparent 42%),
    radial-gradient(ellipse at 20% 108%, rgba(76,134,190,0.22), transparent 55%),
    repeating-linear-gradient(115deg, rgba(255,255,255,0.028) 0 2px, transparent 2px 26px),
    linear-gradient(180deg, #14384f 0%, #0e2a3d 48%, #081a26 100%);
}
/* drifting wave shimmer */
#screen-battle .ocean-battlefield::before{
  content:""; position:absolute; inset:0; pointer-events:none;
  background:
    repeating-linear-gradient(178deg, rgba(143,208,218,0.05) 0 3px, transparent 3px 34px),
    repeating-linear-gradient(184deg, rgba(143,208,218,0.04) 0 2px, transparent 2px 46px);
  animation: battleSeaDrift 14s linear infinite alternate;
}
@keyframes battleSeaDrift{
  from{ background-position: 0 0, 0 0; }
  to{ background-position: 40px 26px, -34px 20px; }
}

/* --- Enemy frames: panel-in-panel like loadout --- */
#screen-battle .enemies-row .enemy-combatant{
  background: rgba(11,26,36,0.45);
  border: 1px solid rgba(233,196,104,0.14);
  box-shadow: 0 8px 18px rgba(0,0,0,0.35);
}
#screen-battle .enemies-row .enemy-combatant.targeted{
  border-color: rgba(239,203,114,0.7);
  background: rgba(239,203,114,0.10);
  box-shadow: 0 0 0 2px var(--brass-bright), 0 10px 22px rgba(0,0,0,0.45);
}
#screen-battle .enemy-name{
  background: linear-gradient(180deg, var(--brass-bright), var(--brass));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
#screen-battle .enemies-row .enemy-combatant.miniboss .enemy-name{
  background: linear-gradient(180deg, #d9b8f2, var(--lightning));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}

/* --- HP bars: brass-rimmed --- */
#screen-battle .bar{ border: 1px solid rgba(233,196,104,0.28); box-shadow: inset 0 1px 3px rgba(0,0,0,0.6); }

/* --- Log panel: framed like the other panels --- */
#screen-battle .log-panel-mini{
  background: linear-gradient(180deg, rgba(18,42,60,0.85), rgba(11,26,36,0.9));
  border: 1px solid rgba(233,196,104,0.25);
  box-shadow: 0 6px 16px rgba(0,0,0,0.4);
  backdrop-filter: blur(4px);
}

/* --- Turn banner: kicker style --- */
#screen-battle .turn-banner{
  background: linear-gradient(180deg, rgba(18,42,60,0.95), rgba(11,26,36,0.95));
  border: 1px solid rgba(233,196,104,0.5);
  box-shadow: 0 8px 22px rgba(0,0,0,0.5);
  letter-spacing: 1.2px; text-transform: uppercase;
  color: var(--brass-bright);
}

/* --- Pile row + AP diamond --- */
#screen-battle .pile{
  background: rgba(11,26,36,0.55);
  border: 1px solid rgba(233,196,104,0.22);
  border-radius: 10px; padding: 5px 12px;
}
#screen-battle .pile-row{ padding-top: 8px; padding-bottom: 8px; }
#screen-battle .ap-diamond{
  box-shadow: 0 4px 0 #8B6C2E, 0 8px 16px rgba(0,0,0,0.4), 0 0 16px rgba(239,203,114,0.35);
}

/* --- Crew/equipment bars + hand: gentle staggered entrance --- */
#screen-battle.active .pile-row,
#screen-battle.active .crew-bar,
#screen-battle.active .hand{
  animation: battleRailIn 0.55s cubic-bezier(0.22, 1, 0.36, 1) both;
}
#screen-battle.active .crew-bar{ animation-delay: 0.08s; }
#screen-battle.active .hand{ animation-delay: 0.16s; }
@keyframes battleRailIn{
  from{ opacity: 0; transform: translateY(12px); }
  to{ opacity: 1; transform: none; }
}

/* ==========================================================================
   Reward / End / Tutorial modals — storybook alignment
   Same navy-gradient panel, brass border, brass-gradient Pirata One title,
   and kicker line as the .modal-help popups. Scoped to these three IDs so
   no other modal behavior changes; JS-toggled classes untouched.
   ========================================================================== */

#modal-reward.modal-overlay,
#modal-end.modal-overlay,
#modal-tutorial.modal-overlay{
  background: rgba(4,10,15,0.72);
  backdrop-filter: blur(5px);
}

#modal-reward .modal,
#modal-end .modal,
#modal-tutorial .modal{
  background: linear-gradient(180deg, rgba(28,62,86,0.96) 0%, rgba(16,38,52,0.99) 100%);
  border: 1px solid rgba(233,196,104,0.45);
  border-radius: 20px;
  padding: 30px 30px 26px;
  box-shadow:
    0 24px 60px rgba(0,0,0,0.55),
    inset 0 1px 0 rgba(255,255,255,0.08),
    0 0 0 1px rgba(0,0,0,0.35);
}

/* Entrance — same family as the loadout/mode-select panels */
#modal-reward.modal-overlay.active .modal,
#modal-end.modal-overlay.active .modal,
#modal-tutorial.modal-overlay.active .modal{
  animation: loadoutPanelIn 0.35s ease both;
}

/* Brass-gradient display titles, matching the .modal-help treatment */
#modal-reward .modal-title,
#modal-end .modal-title,
#modal-tutorial .modal-title{
  font-size: clamp(1.7rem, 4vw, 2.3rem);
  line-height: 1;
  margin: 0 0 10px;
  background: linear-gradient(180deg, #F6DD9A 20%, var(--brass-bright) 55%, var(--brass) 100%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
  filter: drop-shadow(0 2px 0 rgba(0,0,0,0.55)) drop-shadow(0 0 20px rgba(233,196,104,0.20));
}

#modal-reward .modal-sub,
#modal-end .modal-sub,
#modal-tutorial .modal-sub{
  font-size: 0.95rem;
  line-height: 1.55;
}

/* Reward picks row — a subtle panel-in-panel behind the offered cards */
#modal-reward .reward-cards{
  padding: 16px 14px;
  margin-bottom: 22px;
  background: rgba(11,26,36,0.5);
  border: 1px solid rgba(233,196,104,0.16);
  border-radius: 12px;
}

/* Primary CTAs inside these modals get the brass-gradient Set Sail look */
#modal-reward .btn-primary,
#modal-end .btn-primary,
#modal-tutorial .btn-primary{
  background: linear-gradient(180deg, #F6DD9A 0%, var(--brass-bright) 45%, var(--brass) 100%);
  color: #1A1206;
  border: 1px solid rgba(233,196,104,0.7);
  text-shadow: none;
  box-shadow: 0 6px 18px rgba(233,196,104,0.28), 0 2px 6px rgba(0,0,0,0.4);
}
#modal-reward .btn-primary:hover,
#modal-end .btn-primary:hover,
#modal-tutorial .btn-primary:hover{ filter: brightness(1.1); }
#modal-reward .btn-primary:active,
#modal-end .btn-primary:active,
#modal-tutorial .btn-primary:active{ transform: scale(0.97); }

@media (max-width: 640px){
  #modal-reward .modal,
  #modal-end .modal,
  #modal-tutorial .modal{ padding: 22px 16px 18px; }
  #modal-reward .reward-cards{ padding: 12px 10px; }
}

/* ---------------- Reduced motion ---------------- */
@media (prefers-reduced-motion: reduce){
  *{ transition: none !important; }
  #modal-help.modal-overlay.active .modal,
  #modal-settings.modal-overlay.active .modal,
  #modal-achievements.modal-overlay.active .modal{ animation: none !important; }
  #screen-battle.active,
  #screen-battle.active .pile-row,
  #screen-battle.active .crew-bar,
  #screen-battle.active .hand{ animation: none !important; }
  #screen-battle .ocean-battlefield::before{ animation: none !important; }
  #modal-reward.modal-overlay.active .modal,
  #modal-end.modal-overlay.active .modal,
  #modal-tutorial.modal-overlay.active .modal{ animation: none !important; }
  .hit-fx{ animation: none !important; opacity:1 !important; transform: translate(-50%,-50%) !important; }
  .loadout-section{ animation: none !important; }
  .combatant-hp.critical-hp{ animation: none !important; filter: drop-shadow(0 0 7px rgba(192,68,46,0.85)) !important; }
}
