
  :root {
    --ink: #143146;
    --accent: #3aa3d9;
    --accent-2: #ffd166;
    --good: #4ec96b;
    --bad: #ff6b6b;
    --gold: #ffb720;
  }
  * { box-sizing: border-box; }
  html, body {
    margin: 0;
    padding: 0;
    height: 100dvh;
    overflow: hidden;
    font-family: "Comic Sans MS", "Chalkboard SE", "Baloo", system-ui, sans-serif;
    color: var(--ink);
    user-select: none;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
  }
  html, body {
    min-height: 100vh;
    min-height: 100dvh;
  }
  body {
    background: linear-gradient(180deg, #cfeefe 0%, #e6f6ce 50%, #5cc4ee 70%, #2c80b3 100%);
    display: flex;
    flex-direction: column;
    margin: 0;
  }

  /* Top padding clears the absolutely-positioned 🏠 / 🛒 / 🎵 buttons
     so the title doesn't sit underneath them. */
  header { text-align: center; padding: 56px 12px 4px; flex: 0 0 auto; }
  /* Phone landscape: fixed chrome (header + HUD + controls) used to leave
     only a sliver of water — compact it so the stage keeps ~2/3 of the
     height. Portrait and iPad are untouched. */
  @media (max-height: 480px) {
    header { padding: 6px 88px 0; }
    h1 { font-size: 15px; }
    #hud { font-size: 11px; padding: 2px 10px; margin-top: 2px; }
    #controls button { padding: 6px 6px; }
    #controls { margin-top: 4px; }
  }
  h1 {
    margin: 0;
    font-size: clamp(17px, 4.4vw, 30px);
    color: #1f6f9a;
    text-shadow: 0 2px 0 #fff, 0 4px 0 rgba(0,0,0,0.15);
  }

  /* HUD */
  #hud {
    flex: 0 0 auto;
    display: flex;
    gap: 6px 12px;
    justify-content: center;
    align-items: center;
    flex-wrap: wrap;
    font-size: clamp(12px, 2.4vw, 16px);
    background: rgba(255,255,255,0.92);
    padding: 4px 12px;
    border-radius: 999px;
    width: fit-content;
    max-width: 96vw;
    margin: 4px auto 0;
    box-shadow: 0 2px 6px rgba(0,0,0,0.12);
  }
  #hud b { color: #1f6f9a; }
  #hud .gold b { color: var(--gold); }
  #hud .danger b { color: var(--bad); }
  /* Inline HUD/button icons — black silhouettes for the white-ish HUD,
     white silhouettes for the colored gradient buttons. */
  .hud-icon, .btn-icon {
    display: inline-block;
    width: 1.05em;
    height: 1.05em;
    vertical-align: -0.18em;
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;
    margin-right: 2px;
  }

  /* Stage — fills remaining vertical space on phones, capped on desktop */
  #stage {
    position: relative;
    flex: 1 1 auto;
    width: min(100vw, 720px);
    min-height: 0;
    margin: 6px auto 0;
    border-radius: 22px;
    border: 5px solid var(--accent);
    overflow: hidden;
    box-shadow: 0 6px 0 var(--accent), 0 12px 24px rgba(0,0,0,0.18);
    background: linear-gradient(180deg, #cfeefe 0%, #e6f6ce 28%, #c8e7a4 32%, #5cc4ee 38%, #2c80b3 100%);
    transition: background 400ms;
    /* Drag-to-steer owns every touch here — without this the browser can
       claim the pan and pointercancel silently kills the steer. */
    touch-action: none;
  }
  /* Phone: full-bleed stage, no rounded corners */
  @media (max-width: 700px) {
    #stage {
      width: 100vw;
      margin: 4px 0 0;
      border-radius: 0;
      border-left: none;
      border-right: none;
      box-shadow: 0 4px 0 var(--accent);
    }
  }
  .deco {
    position: absolute;
    pointer-events: none;
    line-height: 1;
    filter: drop-shadow(0 2px 2px rgba(0,0,0,0.18));
  }
  /* Kenney PNG decor (seaweed, rocks, bubbles). All PNG decor anchors
     by bottom-center via translate(-50%, -100%) so the d.y value in
     each spot's decor array is the seafloor attachment point. */
  .deco.deco-png {
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;
    image-rendering: pixelated;
    image-rendering: crisp-edges;
    filter: drop-shadow(0 2px 3px rgba(0,0,0,0.25));
    transform: translate(-50%, -100%);
  }
  /* Seaweed grows from the seafloor → anchored at its bottom so the
     decor's d.y value is the seafloor attachment point. Sways gently,
     each instance gets a randomized animation-delay inline. */
  .deco.deco-seaweed {
    transform-origin: 50% 100%;
    animation: seaweedSway 3.6s ease-in-out infinite alternate;
  }
  @keyframes seaweedSway {
    0%   { transform: translate(-50%, -100%) rotate(-5deg); }
    100% { transform: translate(-50%, -100%) rotate( 5deg); }
  }
  /* Sky decor (clouds, sun) — anchored at TOP-CENTER instead of
     bottom. d.y is the top of the sprite. */
  .deco.deco-sky {
    transform: translate(-50%, 0);
    filter: drop-shadow(0 1px 2px rgba(0,0,0,0.15));
  }
  .deco.deco-cloud {
    animation: cloudDrift 38s ease-in-out infinite alternate;
  }
  @keyframes cloudDrift {
    0%   { transform: translate(calc(-50% - 18px), 0); }
    100% { transform: translate(calc(-50% + 18px), 0); }
  }
  /* Bubbles drift up + fade out. d.y is the start position; keyframes
     carry the bubble upward in screen space. */
  .deco.deco-bubble {
    animation: bubbleFloat 5s ease-in-out infinite;
  }
  @keyframes bubbleFloat {
    0%   { transform: translate(-50%, -100%); opacity: 0.4; }
    40%  { transform: translate(-50%, -200%); opacity: 0.85; }
    100% { transform: translate(-50%, -310%); opacity: 0;    }
  }
  /* Boat-bobbing animation while idle on the water */
  @keyframes boatBob {
    0%,100% { transform: translateY(0) rotate(-1.5deg); }
    50%     { transform: translateY(-3px) rotate(1.5deg); }
  }
  /* Fisherman + boat sprite (Gemini-generated). Bottom-anchored at the
     waterline (~58% up from the bottom of the stage = same Y across
     every spot's background) so it visually sits ON the painted water
     surface. The rod is baked into the sprite. The actual character
     sprite is set from JS based on the selected fishingCharacter. */
  #fisher {
    position: absolute;
    left: 14%;
    bottom: 56%;
    width: clamp(72px, 11vw, 112px);
    aspect-ratio: 1 / 1;
    background-position: center bottom;
    background-size: contain;
    background-repeat: no-repeat;
    transform-origin: bottom center;
    animation: boatBob 2600ms ease-in-out infinite;
    pointer-events: none;
    z-index: 4;
    filter: drop-shadow(0 4px 4px rgba(0,0,0,0.22));
  }
  /* Princess sprites are 25% larger than the fisher boy — they take
     up more vertical space (long dresses + crowns + flowing hair) so
     they look small at the boy's display size. */
  #fisher.princess {
    width: clamp(90px, 13.75vw, 140px);
  }

  /* Companion sprites — small standalone animals that ride alongside
     any character. Two slots: AIR (parrot/butterfly/hummingbird flies
     in a loose loop above the boat) and WATER (duck/dolphin/otter
     swims back and forth in the water near the boat). Both hidden by
     default; JS sets background-image + display when one is owned. */
  #companion-air, #companion-water {
    position: absolute;
    pointer-events: none;
    z-index: 4;
    background-position: center;
    background-size: contain;
    background-repeat: no-repeat;
    display: none;
    filter: drop-shadow(0 2px 3px rgba(0,0,0,0.25));
  }
  #companion-air {
    width: clamp(36px, 6vw, 56px);
    aspect-ratio: 1 / 1;
    left: 8%;
    bottom: 70%;
    animation: companionFly 5800ms ease-in-out infinite;
  }
  #companion-water {
    width: clamp(46px, 7.5vw, 70px);
    aspect-ratio: 1 / 1;
    left: 32%;
    bottom: 46%;
    animation: companionSwim 7200ms ease-in-out infinite;
  }
  /* Splash the Dolphin is a bigger creature than the otter/duck — render
     it 50% larger so it reads as a "real" dolphin and not a guppy. */
  #companion-water.is-dolphin {
    width: clamp(69px, 11.25vw, 105px);
  }
  /* While the critter is actively diving for a fish, JS overrides the
     CSS animation with inline transform tweens. .fetching just turns
     off the looping swim so the JS tweens drive the position alone. */
  #companion-water.fetching {
    animation: none;
  }
  @keyframes companionFly {
    0%   { transform: translate(0, 0) scaleX(1); }
    25%  { transform: translate(80px, -14px) scaleX(1); }
    49%  { transform: translate(160px, 0) scaleX(1); }
    50%  { transform: translate(160px, 0) scaleX(-1); }
    75%  { transform: translate(80px, -10px) scaleX(-1); }
    99%  { transform: translate(0, 0) scaleX(-1); }
    100% { transform: translate(0, 0) scaleX(1); }
  }
  @keyframes companionSwim {
    0%   { transform: translate(0, 0) scaleX(1); }
    25%  { transform: translate(60px, 6px) scaleX(1); }
    49%  { transform: translate(120px, 0) scaleX(1); }
    50%  { transform: translate(120px, 0) scaleX(-1); }
    75%  { transform: translate(60px, 8px) scaleX(-1); }
    99%  { transform: translate(0, 0) scaleX(-1); }
    100% { transform: translate(0, 0) scaleX(1); }
  }
  /* Quackers dance — happy hop + wiggle while the duck's perk is
     active. Overrides companionSwim with a faster bouncy loop so the
     kid can see Quackers is "doing the magic" while fish drift in. */
  #companion-water.duck-dancing {
    animation: duckDance 700ms ease-in-out infinite;
    filter: drop-shadow(0 0 8px rgba(255,230,120,0.9))
            drop-shadow(0 2px 3px rgba(0,0,0,0.25));
  }
  @keyframes duckDance {
    0%   { transform: translate(0, 0)    rotate(-8deg) scale(1); }
    25%  { transform: translate(0, -18px) rotate(0deg)  scale(1.08); }
    50%  { transform: translate(0, 0)    rotate(8deg)  scale(1); }
    75%  { transform: translate(0, -10px) rotate(0deg)  scale(1.05); }
    100% { transform: translate(0, 0)    rotate(-8deg) scale(1); }
  }

  /* Water haze — light blue wash over the painted water region.
     Mutes the busy underwater plants painted into bg-pond etc. so
     small fish sprites stand out instead of camouflaging into the
     cattails / lily pads. Anchored to the waterline (~38% down)
     and gets deeper towards the bottom. */
  #water-haze {
    position: absolute;
    inset: 38% 0 0 0;
    background: linear-gradient(
      to bottom,
      rgba(150,200,230,0.18) 0%,
      rgba(40,110,170,0.30) 100%
    );
    pointer-events: none;
    z-index: 1;
  }

  /* Hook + line drawn via SVG-style absolute pos */
  #line {
    position: absolute;
    width: 2px;
    background: rgba(255,255,255,0.85);
    transform-origin: top center;
    pointer-events: none;
    z-index: 2;
  }
  #hook {
    position: absolute;
    width: 26px;
    height: 26px;
    transform: translate(-50%, -50%);
    pointer-events: none;
    z-index: 5;
    font-size: 22px;
    line-height: 26px;
    text-align: center;
    filter: drop-shadow(0 2px 2px rgba(0,0,0,0.4));
  }
  #hook .ring {
    position: absolute;
    inset: -4px;
    border-radius: 50%;
    border: 2px dashed rgba(255,255,255,0.7);
    opacity: 0;
  }
  /* Spin only while visible — it used to tick forever at opacity 0. */
  #hook.glow .ring { opacity: 1; animation: spin 2.4s linear infinite; }
  @keyframes spin { to { transform: rotate(360deg); } }

  /* Mid-trip consumable activation strip — vertical column on the
     right edge of the stage, one button per consumable the kid owns
     a charge of. Hidden when empty. */
  #consumable-strip {
    position: absolute;
    right: 8px;
    top: 50%;
    transform: translateY(-50%);
    display: flex;
    flex-direction: column;
    gap: 8px;
    z-index: 10;
    pointer-events: none;
  }
  #consumable-strip:empty { display: none; }
  #consumable-strip .ctile {
    pointer-events: auto;
    width: 56px;
    height: 56px;
    border-radius: 14px;
    border: 2px solid var(--gold);
    background: rgba(255,255,255,0.94);
    font-size: 26px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    box-shadow: 0 3px 10px rgba(0,0,0,0.18);
    position: relative;
    transition: transform 120ms ease;
  }
  #consumable-strip .ctile:active { transform: scale(0.92); }
  #consumable-strip .ctile .badge {
    position: absolute;
    bottom: -4px;
    right: -4px;
    background: var(--ink, #234);
    color: white;
    font-size: 12px;
    font-weight: bold;
    padding: 2px 6px;
    border-radius: 10px;
    border: 2px solid white;
    line-height: 1;
  }
  #consumable-strip .ctile.active {
    border-color: var(--good);
    background: #e9fff0;
    animation: cpulse 0.9s ease-in-out infinite;
  }
  @keyframes cpulse {
    0%, 100% { box-shadow: 0 3px 10px rgba(0,0,0,0.18); }
    50%      { box-shadow: 0 3px 16px rgba(80, 200, 120, 0.55); }
  }

  /* Supplies section in the shop reuses .upgrade-row styling but
     adds a subtle ribbon so the kid can tell it's consumables. */
  .consumable-row .pips { color: #5a7a90; font-size: 12px; }
  .consumable-row .count {
    background: var(--gold);
    color: white;
    border-radius: 10px;
    padding: 2px 8px;
    font-weight: bold;
    font-size: 13px;
    margin-left: 6px;
  }

  .swimmer {
    position: absolute;
    font-size: 28px;
    transform: translate(-50%, -50%) scaleX(var(--dir, 1));
    pointer-events: none;
    z-index: 3;
    /* Bright halo + dark drop-shadow so fish pop against the painted
       underwater plants (the Lily Pond bg is especially busy with
       cattails + lily pads that would otherwise camouflage them). */
    filter: drop-shadow(0 0 3px rgba(255,255,255,0.85))
            drop-shadow(0 2px 3px rgba(0,0,0,0.45));
    transition: opacity 200ms;
    /* Own compositor layer: left/top moves recomposite the cached texture
       instead of re-running both blur passes per sprite per frame. */
    will-change: transform;
  }
  /* Kenney fishpack sprite — replaces emoji rendering when the pool
     entry has a `sprites` array. Bumped from 44 → 52 px so sprites
     are easier to spot against busy painted backgrounds (Lily Pond). */
  .swimmer.has-sprite {
    width: 52px;
    height: 52px;
    font-size: 0;
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;
    filter: drop-shadow(0 0 3px rgba(255,255,255,0.9))
            drop-shadow(0 2px 3px rgba(0,0,0,0.45));
    image-rendering: pixelated;
    image-rendering: crisp-edges;
  }
  /* No `.img-loading` rule any more. The old "hide the swimmer until
     decode() resolves" trick had a fatal hole: decode() also resolves
     on FAILURE, which dropped the class while leaving an empty 52×52
     box behind (font-size:0 killed the emoji fallback) — the catchable
     invisible fish Katherine kept seeing. New architecture: spawnSwimmer
     always renders the emoji first as a guaranteed-visible fallback,
     then swaps to the sprite only if decode succeeds. There is no
     state where a swimmer renders nothing, so img-loading isn't needed.
   */

  /* Painted Gemini sprites (assets/sprites/) — render smooth, NOT
     pixelated. Override applies to any element whose inline style
     references the sprites/ folder. */
  .swimmer.has-sprite[style*="sprites/"],
  .deco.deco-png[style*="sprites/"] {
    image-rendering: auto;
    image-rendering: -webkit-optimize-contrast;
  }
  .swimmer.has-sprite.junk {
    width: 36px;
    height: 36px;
    opacity: 0.92;
  }
  .swimmer.has-sprite.boss {
    width: 72px;
    height: 72px;
  }
  .swimmer.caught { z-index: 6; }
  /* Junk: greyer, smaller, drifts slower than fish. Visually obvious
     that you should NOT grab it. Caught junk fills a bucket slot
     without giving any coins. */
  .swimmer.junk {
    font-size: 24px;
    filter: saturate(0.5) brightness(0.85) drop-shadow(0 2px 2px rgba(0,0,0,0.3));
    opacity: 0.92;
  }
  /* Boss: BIG ONE — pulsing gold glow, oversized, screen-grabbing. */
  .swimmer.boss {
    font-size: 48px;
    z-index: 5;
    animation: bossGlow 1.4s ease-in-out infinite;
  }
  @keyframes bossGlow {
    0%,100% { filter: drop-shadow(0 0 6px gold)  drop-shadow(0 2px 4px rgba(0,0,0,0.4)); }
    50%     { filter: drop-shadow(0 0 18px gold) drop-shadow(0 2px 4px rgba(0,0,0,0.4)); }
  }
  .treasure {
    font-size: 45px;
    animation: bobby 1400ms ease-in-out infinite;
  }
  @keyframes bobby {
    0%,100% { transform: translate(-50%,-50%) translateY(0); }
    50%     { transform: translate(-50%,-50%) translateY(-6px); }
  }
  /* Butterfly Lucky Mode sparkle — clovers + coin emoji burst out
     of the butterfly when the chests appear. CSS variables --dx and
     --rot are set inline per particle so each one drifts a slightly
     different way. */
  .lucky-particle {
    position: absolute;
    pointer-events: none;
    font-size: 22px;
    line-height: 1;
    z-index: 7;
    --dx: 0px;
    --rot: 0deg;
    transform: translate(-50%, -50%);
    animation: luckyParticleFall 1400ms cubic-bezier(0.4, 0.05, 0.6, 1) forwards;
    text-shadow: 0 0 6px rgba(255, 240, 160, 0.9), 0 2px 4px rgba(0,0,0,0.3);
  }
  @keyframes luckyParticleFall {
    0%   { transform: translate(-50%, -50%) translate(0, 0)              rotate(0deg);          opacity: 0; }
    15%  { transform: translate(-50%, -50%) translate(calc(var(--dx) * 0.35), -28px) rotate(calc(var(--rot) * 0.4));  opacity: 1; }
    100% { transform: translate(-50%, -50%) translate(var(--dx), 140px)  rotate(var(--rot));    opacity: 0; }
  }

  /* Big "LUCKY MODE!" overlay that sweeps across the stage when the
     event fires. Disappears after ~1.4s. */
  .lucky-banner {
    position: absolute;
    left: 50%;
    top: 38%;
    transform: translate(-50%, -50%);
    pointer-events: none;
    z-index: 9;
    font-size: clamp(28px, 8vw, 56px);
    font-weight: 900;
    color: #fff;
    background: linear-gradient(90deg, #ffd766, #ffeb88, #66e0a0);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-stroke: 2px #2b6b3f;
    text-shadow: 0 0 14px rgba(255, 230, 130, 0.9);
    animation: luckyBannerPop 1400ms ease-out forwards;
  }
  @keyframes luckyBannerPop {
    0%   { transform: translate(-50%, -50%) scale(0.4); opacity: 0; }
    20%  { transform: translate(-50%, -50%) scale(1.15); opacity: 1; }
    70%  { transform: translate(-50%, -50%) scale(1.0); opacity: 1; }
    100% { transform: translate(-50%, -50%) scale(0.95); opacity: 0; }
  }

  /* Butterfly Lucky Mode chests — golden glow so the kid knows these
     swim-by chests are special and worth chasing. */
  .swimmer.lucky-chest {
    width: 56px;
    height: 56px;
    filter: drop-shadow(0 0 8px #ffd766)
            drop-shadow(0 0 14px rgba(255, 200, 60, 0.65))
            drop-shadow(0 2px 3px rgba(0,0,0,0.45));
    animation: luckyChestPulse 1100ms ease-in-out infinite;
  }
  @keyframes luckyChestPulse {
    0%,100% { filter: drop-shadow(0 0 6px #ffd766)
                      drop-shadow(0 0 10px rgba(255, 200, 60, 0.6))
                      drop-shadow(0 2px 3px rgba(0,0,0,0.45)); }
    50%     { filter: drop-shadow(0 0 14px #ffeb88)
                      drop-shadow(0 0 22px rgba(255, 215, 100, 0.85))
                      drop-shadow(0 2px 3px rgba(0,0,0,0.45)); }
  }

  /* Obstacles — per-spot terrain hazards. Solid kinds (coral, debris)
     block the hook; sting kinds (jelly) flash the screen on contact
     and freeze the grab loop briefly. */
  .obstacle {
    position: absolute;
    pointer-events: none;
    z-index: 2;
  }
  .obstacle.coral {
    background: linear-gradient(180deg, #ff8aa8 0%, #c54269 60%, #8b234a 100%);
    border-radius: 12px 12px 4px 4px;
    box-shadow: 0 2px 6px rgba(0,0,0,0.3), inset 0 -3px 0 rgba(0,0,0,0.18);
  }
  .obstacle.coral::before {
    content: '🪸';
    position: absolute;
    top: -22px;
    left: 50%;
    transform: translateX(-50%);
    font-size: 26px;
    filter: drop-shadow(0 2px 2px rgba(0,0,0,0.3));
  }
  .obstacle.debris {
    background: linear-gradient(135deg, #6b5a3e 0%, #443220 60%, #2a1d10 100%);
    border-radius: 3px;
    box-shadow: 0 2px 6px rgba(0,0,0,0.4), inset 0 0 6px rgba(0,0,0,0.5);
  }
  .obstacle.debris::after {
    content: '';
    position: absolute;
    inset: 4px;
    background:
      repeating-linear-gradient(45deg, transparent 0 6px, rgba(255,255,255,0.04) 6px 7px);
    border-radius: 2px;
  }
  .obstacle.jelly {
    font-size: 0;
    animation: jellyDrift 4.6s ease-in-out infinite alternate;
  }
  .obstacle.jelly::before {
    content: '🪼';
    font-size: clamp(26px, 6vw, 40px);
    filter: drop-shadow(0 0 8px #aaffff) drop-shadow(0 2px 2px rgba(0,0,0,0.25));
    display: block;
    line-height: 1;
    text-align: center;
    animation: jellyPulse 1.6s ease-in-out infinite;
  }
  /* Whirlpool annoyance — spinning emoji that pulls the hook in. */
  .obstacle.whirlpool {
    font-size: 0;
    pointer-events: none;
  }
  .obstacle.whirlpool::before {
    content: '🌀';
    display: block;
    text-align: center;
    line-height: 1;
    font-size: clamp(40px, 9vw, 64px);
    filter: drop-shadow(0 0 6px #6ad) drop-shadow(0 3px 4px rgba(0,0,0,0.25));
    animation: whirlSpin 1.4s linear infinite;
  }
  @keyframes whirlSpin { to { transform: rotate(360deg); } }

  /* Seagull annoyance — flies left↔right above the water surface. */
  .seagull {
    position: absolute;
    font-size: clamp(28px, 6vw, 36px);
    line-height: 1;
    z-index: 6;
    pointer-events: none;
    text-shadow: 0 2px 4px rgba(0,0,0,0.25);
    animation: seagullFlap 0.5s ease-in-out infinite alternate;
  }
  @keyframes seagullFlap {
    /* 🦅 emoji natively faces LEFT on Apple + Google fonts, so we need
       scaleX(-1) when --dir is +1 (flying right) for the head to lead
       and scaleX(1) when --dir is -1 (flying left). Invert --dir to
       get that mapping. */
    0%   { transform: translateY(0)    scaleX(calc(var(--dir, 1) * -1)); }
    100% { transform: translateY(-3px) scaleX(calc(var(--dir, 1) * -1)); }
  }
  /* Falling rock annoyance — small rock that tumbles down through the water. */
  .rockfall {
    position: absolute;
    font-size: 26px;
    line-height: 1;
    z-index: 5;
    pointer-events: none;
    animation: rockTumble 1.2s linear infinite;
    filter: drop-shadow(0 2px 3px rgba(0,0,0,0.4));
  }
  @keyframes rockTumble { to { transform: rotate(360deg); } }

  /* Pinchy crab annoyance — walks along the seabed. */
  .pinchy-crab {
    position: absolute;
    font-size: clamp(28px, 6vw, 36px);
    line-height: 1;
    z-index: 5;
    pointer-events: none;
    animation: crabWobble 0.32s ease-in-out infinite alternate;
    text-shadow: 0 2px 4px rgba(0,0,0,0.3);
  }
  @keyframes crabWobble {
    0%   { transform: translateY(0)    scaleX(var(--dir, 1)); }
    100% { transform: translateY(-2px) scaleX(var(--dir, 1)); }
  }
  @keyframes jellyDrift {
    0%   { transform: translate(-6px, -4px); }
    100% { transform: translate(6px, 4px); }
  }
  @keyframes jellyPulse {
    0%,100% { opacity: 0.85; transform: scale(1); }
    50%     { opacity: 1;    transform: scale(1.08); }
  }
  /* Sting flash — full-stage white overlay when the hook hits a jelly. */
  #stage.sting-flash::before {
    content: '';
    position: absolute;
    inset: 0;
    background: radial-gradient(ellipse at center, rgba(220,255,255,0.9), rgba(180,230,255,0.4) 60%, transparent 100%);
    pointer-events: none;
    z-index: 6;
    animation: stingFlash 900ms ease-out forwards;
  }
  @keyframes stingFlash {
    0%   { opacity: 0.95; }
    60%  { opacity: 0.45; }
    100% { opacity: 0;    }
  }

  /* Trip conditions — light tints over the whole stage to communicate
     time-of-day / weather. Sunny is the baseline (no tint). */
  #stage.cond-cloudy   { filter: brightness(0.92) saturate(0.92); }
  #stage.cond-twilight { filter: brightness(0.85) saturate(1.1) hue-rotate(-15deg); }
  #stage.cond-storm    { filter: brightness(0.7)  saturate(1.05) contrast(1.08); }
  /* Perfect condition: gentle warm glow, no filter that dims. */
  #stage.cond-perfect  { filter: brightness(1.05) saturate(1.15); }
  /* Storm rain overlay */
  #stage.cond-storm::after {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    background:
      repeating-linear-gradient(110deg, transparent 0 4px, rgba(180,200,220,0.18) 4px 5px);
    opacity: 0.85;
    animation: rainSlide 0.45s linear infinite;
    z-index: 4;
  }
  @keyframes rainSlide {
    0%   { background-position: 0 0; }
    100% { background-position: -22px 30px; }
  }

  /* Banner above the water */
  #banner {
    position: absolute;
    top: 8px;
    left: 50%;
    transform: translateX(-50%);
    background: rgba(255,255,255,0.92);
    color: #1f6f9a;
    font-weight: bold;
    padding: 4px 14px;
    border-radius: 999px;
    box-shadow: 0 2px 0 var(--accent);
    font-size: clamp(13px, 2.4vw, 17px);
    pointer-events: none;
    z-index: 7;
  }

  /* Combo popup */
  .combo-pop {
    position: absolute;
    left: 50%;
    top: 30%;
    transform: translate(-50%, -50%);
    font-weight: bold;
    color: #fff;
    background: var(--gold);
    padding: 6px 18px;
    border-radius: 999px;
    box-shadow: 0 4px 0 #b27a00;
    font-size: clamp(16px, 4vw, 26px);
    z-index: 9;
    animation: comboPop 1100ms ease forwards;
    pointer-events: none;
  }
  @keyframes comboPop {
    0%   { transform: translate(-50%, -20%) scale(0.4); opacity: 0; }
    20%  { transform: translate(-50%, -50%) scale(1.2); opacity: 1; }
    80%  { transform: translate(-50%, -55%) scale(1.0); opacity: 1; }
    100% { transform: translate(-50%, -100%) scale(0.9); opacity: 0; }
  }

  .coin-pop {
    position: absolute;
    color: var(--gold);
    text-shadow: 0 0 4px #fff, 0 2px 0 #b27a00;
    font-weight: bold;
    font-size: 16px;
    pointer-events: none;
    z-index: 8;
    animation: coinFloat 900ms ease forwards;
  }
  @keyframes coinFloat {
    0%   { transform: translate(-50%, 0); opacity: 0; }
    20%  { opacity: 1; }
    100% { transform: translate(-50%, -42px); opacity: 0; }
  }

  /* Controls — single row: ◀  CAST/REEL  ▶. The middle button is a
     toggle: tap from idle = cast (hook drops), tap during cast =
     start the unstoppable reel. Auto-sink handles vertical descent. */
  #controls {
    flex: 0 0 auto;
    width: min(96vw, 600px);
    /* Safe-area: keep the buttons out of the iPhone home-indicator zone
       in installed-PWA mode (env() is live now that viewport-fit=cover). */
    margin: 8px auto calc(env(safe-area-inset-bottom, 0px) + 8px);
    display: grid;
    grid-template-columns: 1fr 2fr 1fr;
    gap: 8px;
  }
  #controls button {
    font-family: inherit;
    font-weight: bold;
    font-size: clamp(16px, 3.4vw, 22px);
    padding: 14px 6px;
    border-radius: 18px;
    border: 4px solid var(--accent);
    background: #fff;
    color: var(--ink);
    cursor: pointer;
    box-shadow: 0 5px 0 var(--accent);
    transition: transform 80ms, box-shadow 80ms;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    user-select: none;
    /* none (not manipulation): hold-to-steer must never lose the pointer
       to a browser pan → pointercancel while a finger wiggles on ◀ ▶. */
    touch-action: none;
  }
  #controls button.holding {
    transform: translateY(2px);
    box-shadow: 0 2px 0 var(--accent);
    background: linear-gradient(135deg, var(--accent), #1f6f9a);
    color: #fff;
  }
  #controls button:disabled {
    opacity: 0.5;
    cursor: default;
    box-shadow: 0 2px 0 var(--accent);
  }
  #cast-btn {
    background: linear-gradient(135deg, #ffd166, #ffb720);
    border-color: #d99a10;
    box-shadow: 0 5px 0 #d99a10;
  }
  #cast-btn:disabled {
    background: #e8e8e8;
    border-color: #aaa;
    box-shadow: 0 2px 0 #aaa;
    color: #888;
  }

  /* Top buttons */
  #home-btn, #music-btn, #shop-btn {
    position: fixed;
    top: 10px;
    font-family: inherit;
    font-size: 14px;
    padding: 6px 11px;
    border-radius: 999px;
    border: 3px solid var(--accent);
    background: #fff;
    color: var(--ink);
    text-decoration: none;
    box-shadow: 0 3px 0 var(--accent);
    z-index: 30;
    cursor: pointer;
    font-weight: bold;
  }
  #home-btn  { left: 10px; }
  #music-btn { right: 10px; }
  #shop-btn  { right: 96px; }
  #music-btn.on {
    background: linear-gradient(135deg, var(--accent), var(--accent-2));
    color: #fff;
  }

  /* When the shared #kg-topbar (Phase 1) is mounted, the right-side
     ❓⏸🎵🔊 cluster lands right where #shop-btn used to live, so
     the two would overlap. Slide #shop-btn down below the topbar.
     home-btn and music-btn already get visually-hidden by the
     shared topbar.css proxy rule, so they don't need this override. */
  body:has(#kg-topbar) #shop-btn {
    top: 56px;
    right: 12px;
  }
  /* Keep the centered title clear of the (topbar-lowered) Shop pill on
     narrow phones — without this the "s" of Seashell Coves slides under it. */
  body:has(#kg-topbar) header { padding-left: 88px; padding-right: 88px; }

  /* Shop overlay */
  #shop {
    position: fixed;
    inset: 0;
    background: rgba(20,49,70,0.55);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    z-index: 40;
    display: none;
    align-items: center;
    justify-content: center;
    padding: 20px;
    overflow-y: auto;
  }
  #shop.show { display: flex; }

  /* Character / Companion picker overlay — same modal shape as #shop
     but its own DOM so opening one doesn't disturb the other. */
  #picker {
    position: fixed;
    inset: 0;
    background: rgba(20,49,70,0.65);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    z-index: 9500;
    display: none;
    align-items: center;
    justify-content: center;
    padding: 16px;
    overflow-y: auto;
  }
  #picker.show { display: flex; }
  #picker-card {
    position: relative;
    background: linear-gradient(180deg, #fff8e7, #fff);
    border-radius: 22px;
    border: 5px solid #ff8ec5;
    width: min(720px, 96vw);
    max-height: calc(100vh - 32px);
    overflow-y: auto;
    padding: 16px 18px 22px;
    box-shadow: 0 10px 28px rgba(0,0,0,0.35);
  }
  #picker-card h2 { text-align: center; margin: 6px 0 14px; color: #6a2e6a; }
  #picker-close {
    position: absolute; top: 8px; right: 10px;
    width: 36px; height: 36px;
    border: none; border-radius: 50%;
    background: #ff8ec5; color: #fff; font-size: 22px; font-weight: bold;
    cursor: pointer; line-height: 1;
  }
  #picker-coins-row {
    text-align: center; font-weight: bold; margin: -6px 0 12px;
    color: #b27a00; font-size: 16px;
  }
  #picker-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
  }
  @media (min-width: 520px) {
    #picker-grid { grid-template-columns: 1fr 1fr 1fr; }
  }
  .picker-section-head {
    grid-column: 1 / -1;
    font-weight: bold; color: #4a2a6a;
    margin: 6px 0 2px; font-size: 15px;
    border-bottom: 2px dashed #ffd1e8;
    padding-bottom: 4px;
  }
  .pick-card {
    background: #fff;
    border: 3px solid #ddd;
    border-radius: 14px;
    padding: 8px;
    text-align: center;
    cursor: pointer;
    display: flex; flex-direction: column; align-items: center;
    transition: transform 80ms, border-color 120ms;
  }
  .pick-card:active { transform: scale(0.96); }
  .pick-card.selected {
    border-color: #ffb547;
    background: linear-gradient(180deg, #fff3c0, #fff);
    box-shadow: 0 0 0 3px rgba(255,181,71,0.35);
  }
  .pick-card.locked { opacity: 0.92; background: #f4f4f6; }
  .pick-card .pick-sprite {
    width: clamp(80px, 18vw, 110px);
    height: clamp(80px, 18vw, 110px);
    background-position: center;
    background-size: contain;
    background-repeat: no-repeat;
    margin-bottom: 4px;
  }
  .pick-card .pick-name {
    font-weight: bold; color: #2a3445;
    font-size: clamp(13px, 2.7vw, 15px);
    line-height: 1.15;
  }
  .pick-card .pick-perk {
    font-size: clamp(11px, 2.3vw, 13px);
    color: #6a4a00;
    margin-top: 4px;
    min-height: 2.4em;
  }
  .pick-card .pick-price {
    margin-top: 6px;
    font-weight: bold;
    font-size: 13px;
    color: #b27a00;
  }
  .pick-card .pick-check {
    color: #ffb547;
    font-size: 18px;
    font-weight: bold;
    margin-top: 4px;
    min-height: 1.2em;
  }
  /* Two Dock-tab buttons that open the pickers — small pill row above
     the big Set Sail button. */
  .dock-style-row {
    display: flex; gap: 8px;
    margin: 8px auto 6px;
    justify-content: center;
    flex-wrap: wrap;
  }
  .dock-style-btn {
    font-family: inherit; font-weight: bold;
    background: linear-gradient(180deg, #ffd1e8, #ff8ec5);
    color: #6a2e6a;
    border: 3px solid #d04a8c;
    border-radius: 14px;
    padding: 8px 14px;
    font-size: clamp(13px, 2.8vw, 15px);
    cursor: pointer;
    box-shadow: 0 3px 0 #a83470, inset 0 -2px 0 rgba(0,0,0,0.12);
  }
  .dock-style-btn:active {
    transform: translateY(2px);
    box-shadow: 0 1px 0 #a83470, inset 0 -2px 0 rgba(0,0,0,0.18);
  }

  #shop-card {
    position: relative;
    background: #fff;
    border-radius: 22px;
    border: 5px solid var(--accent);
    width: min(900px, 96vw);
    max-height: calc(100vh - 40px);
    overflow-y: auto;
    padding: 16px 18px 18px;
    box-shadow: 0 8px 24px rgba(0,0,0,0.25);
  }
  /* Phone: full-screen card so the dock + map fill the viewport.
     Pin the card to all four viewport edges with position: fixed —
     this is more robust than width: 100vw inside a flex parent
     (which various mobile browsers treat inconsistently). 100dvh
     handles the iOS URL-bar-height quirk. */
  @media (max-width: 700px) {
    #shop {
      padding: 0 !important;
      align-items: stretch !important;
      justify-content: stretch !important;
    }
    #shop.show { display: block !important; }
    #shop-card {
      position: fixed !important;
      inset: 0 !important;
      width: 100vw !important;
      max-width: none !important;
      height: 100vh !important;
      height: 100dvh !important;
      max-height: 100vh !important;
      max-height: 100dvh !important;
      border-radius: 0 !important;
      border: none !important;
      box-shadow: none !important;
      margin: 0 !important;
      padding: 12px 12px 14px !important;
      box-sizing: border-box !important;
    }
    /* Full-screen card = the site topbar's floating ❓⏸🎵🔊 circles land
       on the card's top edge, burying the ✕ and the VIP tab. Start the
       card content below them. */
    body:has(#kg-topbar) #shop-card { padding-top: 56px !important; }
    body:has(#kg-topbar) #shop-close { top: 56px; }
  }
  #shop-card h2 {
    margin: 0 0 6px;
    font-size: clamp(22px, 5vw, 30px);
    color: #1f6f9a;
    text-align: center;
  }
  /* Coin bar — appears on each shop sub-view. */
  .shop-coins-bar {
    text-align: center;
    font-size: clamp(15px, 3vw, 19px);
    margin-bottom: 12px;
    color: var(--gold);
    font-weight: bold;
    text-shadow: 0 1px 0 #fff;
  }
  /* Sub-view router: only one shop-view shows at a time. */
  .shop-view[hidden] { display: none; }
  /* Back button — replaced by the tackle-box tabs on top of the card.
     Hidden via CSS so the existing buttons can stay in HTML for any
     fallback callsites. */
  .shop-back { display: none; }

  /* Tackle-box tabs — horizontal pill strip across the top of the
     shop card. One tab per sub-view; the active tab pops up. */
  #shop-tabs {
    display: flex;
    gap: 6px;
    justify-content: center;
    margin: 0 0 12px;
    padding: 6px 60px 6px 6px;  /* room on the right for the close button */
    background:
      repeating-linear-gradient(135deg,
        transparent 0, transparent 6px,
        rgba(255,255,255,0.04) 6px, rgba(255,255,255,0.04) 7px),
      linear-gradient(180deg, #6a7a8a, #44505a);
    border: 3px solid var(--gold);
    border-radius: 14px;
    box-shadow: 0 3px 0 #2d3640, inset 0 0 0 1px rgba(255,255,255,0.15);
  }
  #shop-tabs button {
    flex: 1;
    font-family: inherit;
    font-weight: bold;
    background: linear-gradient(180deg, #d6dee6, #aab5c0);
    border: 2px solid #44505a;
    color: #1a2433;
    border-radius: 10px;
    padding: 6px 8px;
    font-size: clamp(13px, 2.6vw, 15px);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    min-height: 38px;
    box-shadow: inset 0 -2px 0 rgba(0,0,0,0.15);
  }
  #shop-tabs button .ttab-icon { font-size: 18px; line-height: 1; }
  #shop-tabs button.active {
    background: linear-gradient(180deg, #ffd166, #d99a10);
    border-color: #6e4423;
    color: #4a2e00;
    box-shadow: inset 0 -2px 0 rgba(0,0,0,0.18), 0 0 8px rgba(255,200,80,0.55);
    transform: translateY(-1px);
  }
  #shop-tabs button:active { transform: translateY(0); }
  /* VIP tab — sparkly gold gradient that shimmers across, with a
     subtle pulse to draw the eye. */
  #shop-tabs .vip-tab {
    background: linear-gradient(110deg, #fff7c0 0%, #ffd166 30%, #ff8c42 50%, #ffd166 70%, #fff7c0 100%);
    background-size: 240% 100%;
    border-color: #b27a00;
    color: #5a3c00;
    animation: vipShimmer 3.5s linear infinite;
  }
  @keyframes vipShimmer {
    from { background-position: 0% 0; }
    to   { background-position: -240% 0; }
  }
  @media (max-width: 380px) {
    #shop-tabs button .ttab-label { display: none; }
    #shop-tabs button .ttab-icon  { font-size: 22px; }
  }
  /* VIP Pass purchase row — fancy gold-on-gold pill at the top of
     the shop-tools view until owned. */
  .vip-pass-row {
    position: relative;
    background:
      repeating-linear-gradient(135deg,
        rgba(255,255,255,0.18) 0, rgba(255,255,255,0.18) 4px,
        transparent 4px, transparent 9px),
      linear-gradient(135deg, #fff7c0 0%, #ffd166 50%, #ff8c42 100%);
    border: 4px solid #b27a00;
    border-radius: 16px;
    padding: 12px 14px;
    margin-bottom: 12px;
    text-align: center;
    color: #4a2e00;
    font-weight: bold;
    box-shadow: 0 4px 0 #b27a00, inset 0 0 0 1px rgba(255,255,255,0.35);
  }
  .vip-pass-row .vip-title { font-size: clamp(16px, 3.4vw, 20px); }
  .vip-pass-row .vip-progress {
    margin: 6px 0 8px;
    font-size: clamp(13px, 2.6vw, 15px);
    color: #5a3c00;
  }
  .vip-pass-row button {
    font-family: inherit;
    font-weight: bold;
    border: 3px solid #b27a00;
    background: linear-gradient(180deg, #fff8e6, #ffd166);
    color: #4a2e00;
    border-radius: 999px;
    padding: 8px 18px;
    cursor: pointer;
    box-shadow: 0 3px 0 #b27a00;
    font-size: clamp(14px, 2.8vw, 17px);
  }
  .vip-pass-row button:disabled { opacity: 0.55; cursor: default; }
  .vip-pass-row.owned {
    background: linear-gradient(180deg, #fff8e6, #ffd166);
  }
  /* VIP map pins — gold variants on top of the painted parchment. */
  .vip-pin {
    position: absolute;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    background: radial-gradient(circle at 30% 30%, #fff8b0, #ffb720 60%, #b27a00);
    border: 2px solid #6e4423;
    color: #4a2e00;
    font-weight: bold;
    font-size: 13px;
    display: flex;
    align-items: center;
    justify-content: center;
    transform: translate(-50%, -50%);
    cursor: pointer;
    box-shadow: 0 2px 6px rgba(0,0,0,0.3);
  }
  .vip-pin.selected {
    box-shadow: 0 0 14px #ffd166, 0 2px 6px rgba(0,0,0,0.3);
    transform: translate(-50%, -50%) scale(1.15);
  }
  /* Close X — top-right of every sub-view. Big and obvious so the kid
     can always find a way back to the trip. */
  #shop-close {
    position: absolute;
    top: 8px;
    right: 8px;
    width: 44px;
    height: 44px;
    background: linear-gradient(180deg, #fff8e6, #ffd166);
    border: 3px solid #b27a00;
    border-radius: 50%;
    font-size: 26px;
    font-weight: bold;
    line-height: 1;
    color: #5a3c00;
    cursor: pointer;
    padding: 0;
    z-index: 12;
    box-shadow: 0 3px 0 #b27a00, inset 0 -2px 0 rgba(0,0,0,0.18);
    display: flex;
    align-items: center;
    justify-content: center;
  }
  #shop-close:active { transform: translateY(2px); box-shadow: 0 1px 0 #b27a00, inset 0 -2px 0 rgba(0,0,0,0.18); }
  /* ====== Dock home view ======
     Three stacked rows inside the card (no edge-bleed, no overlays):
       1) info bar — coins + current spot + weather pill
       2) painted dock-home.webp shown clean, no buttons on top of it
       3) action bar — 🛒 Shop  •  🎣 Fish here now!  •  🗺 Map */
  .shop-dock {
    display: flex;
    flex-direction: column;
    gap: 10px;
    min-height: 100%;
  }
  /* On phone, the card is full-viewport — let the dock view stretch
     to fill it so the painted art and buttons don't huddle in the
     middle of an otherwise empty screen. */
  @media (max-width: 700px) {
    #shop-menu.shop-dock {
      min-height: calc(100vh - 26px);
      min-height: calc(100dvh - 26px);
    }
  }
  .dock-top-bar {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 10px;
    justify-content: space-between;
    align-items: center;
    background: #f4f9ff;
    border: 2px solid #d6e3ee;
    border-radius: 14px;
    padding: 6px 12px;
    font-size: clamp(13px, 2.6vw, 15px);
    font-weight: bold;
    color: var(--ink);
  }
  .dock-top-bar b { color: #1f6f9a; }
  .dock-top-bar #menu-spot-icon { font-size: 18px; }
  .dock-here .weather {
    display: inline-block;
    margin-left: 4px;
    padding: 1px 8px;
    border-radius: 999px;
    font-size: 12px;
    background: #fff;
    border: 1px solid #d6e3ee;
  }
  .dock-here .weather.w-perfect  { background: linear-gradient(135deg, #fff7d4, #ffd8a0); border-color: #d99a10; color: #8a4a00; font-weight: bold; }
  .dock-here .weather.w-twilight { background: #ffe8d4; border-color: #d99a10; color: #6a3000; }
  .dock-here .weather.w-cloudy   { background: #eef2f6; }
  .dock-here .weather.w-storm    { background: #2c4a6c; color: #fff; border-color: #1a2d44; font-weight: bold; }
  /* Painted dock art — clean, no overlays, just the picture. Grows
     to fill the available card height on phone. */
  .dock-art {
    position: relative;
    flex: 1 1 auto;
    width: 100%;
    min-height: 280px;
    border-radius: 14px;
    background:
      url('./assets/dock-home.webp') center/cover no-repeat,
      linear-gradient(180deg, #c8e3f7 0%, #5eb3e0 70%, #2c80b3 100%);
    box-shadow: inset 0 0 0 3px #d6e3ee;
  }
  /* TEMP CHEAT — invisible hotspot over the tiny pirate flag right
     above Katherine's supply store. No cursor, no outline, no hint
     that anything is tappable here. */
  .cheat-hotspot {
    position: absolute;
    left: 14%;
    top: 5%;
    width: 9%;
    height: 12%;
    z-index: 5;
  }
  /* Big primary CTA on the dock screen — taps straight into a trip. */
  #dock-fish-btn {
    flex: 0 0 auto;
    align-self: stretch;
    margin-top: 10px;
    padding: 14px 18px;
    font-family: inherit;
    font-weight: bold;
    font-size: clamp(17px, 4vw, 22px);
    border-radius: 18px;
    border: 4px solid #d99a10;
    background: linear-gradient(135deg, #ffd166, #ffb720);
    color: #5a3c00;
    box-shadow: 0 4px 0 #d99a10, inset 0 -3px 0 rgba(0,0,0,0.18);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    text-shadow: 0 1px 0 rgba(255,255,255,0.55);
  }
  #dock-fish-btn:active { transform: translateY(2px); box-shadow: 0 2px 0 #d99a10, inset 0 -3px 0 rgba(0,0,0,0.18); }
  #dock-fish-btn:disabled { opacity: 0.55; cursor: default; }
  #dock-fish-btn .dock-fish-icon  { font-size: clamp(22px, 5.5vw, 30px); line-height: 1; }
  #dock-fish-btn .dock-fish-label { letter-spacing: 0.5px; }
  .coin-shower {
    position: absolute;
    top: -32px;
    font-size: 28px;
    pointer-events: none;
    animation: coinShower 1.6s ease-in forwards;
    z-index: 30;
    text-shadow: 0 2px 4px rgba(0,0,0,0.5);
  }
  @keyframes coinShower {
    0%   { transform: translateY(0) rotate(0deg); opacity: 1; }
    85%  { opacity: 1; }
    100% { transform: translateY(540px) rotate(720deg); opacity: 0; }
  }
  /* Action bar — three side-by-side buttons. Fish is the prominent
     gold one in the middle; Shop and Map are secondary on either side. */
  .dock-actions {
    display: flex;
    gap: 8px;
    align-items: stretch;
  }
  .dock-btn {
    flex: 1 1 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    font-family: inherit;
    font-weight: bold;
    font-size: clamp(13px, 2.8vw, 16px);
    line-height: 1.15;
    padding: 10px 6px;
    border-radius: 14px;
    cursor: pointer;
  }
  .dock-btn .dock-btn-icon { font-size: clamp(22px, 5vw, 28px); line-height: 1; }
  .dock-btn-secondary {
    background: #f4f9ff;
    color: var(--ink);
    border: 3px solid var(--accent);
    box-shadow: 0 4px 0 var(--accent);
  }
  .dock-btn-secondary:active {
    transform: translateY(2px);
    box-shadow: 0 2px 0 var(--accent);
  }
  .dock-btn-primary {
    flex: 1.6 1 0;                    /* a touch wider than the others */
    background: linear-gradient(135deg, #ffd166, #ffb720);
    color: #5a3c00;
    border: 4px solid #d99a10;
    box-shadow: 0 5px 0 #d99a10;
    font-size: clamp(15px, 3.4vw, 19px);
  }
  .dock-btn-primary:active {
    transform: translateY(2px);
    box-shadow: 0 3px 0 #d99a10;
  }
  .dock-btn-primary:disabled {
    cursor: not-allowed;
    background: #cfd8e0;
    border-color: #98a4b0;
    color: #5a6678;
    box-shadow: 0 4px 0 #98a4b0;
  }

  /* ====== Pirate Treasure Map ======
     The "map" sub-view is now styled as an old aged-parchment
     treasure map with a compass rose, a kraken in the corner, and
     spot tiles styled as map markers. Sepia palette throughout. */
  .shop-ocean h2 {
    font-family: Georgia, 'Times New Roman', serif;
    color: #5a3614;
    letter-spacing: 0.5px;
    text-shadow: 0 1px 0 rgba(255,255,255,0.6);
  }
  .shop-ocean .ocean {
    position: relative;
    width: 100%;
    aspect-ratio: 4 / 5;     /* matches SVG viewBox 400×500 */
    max-height: 55vh;
    max-height: 55dvh;
    border-radius: 8px;
    overflow: hidden;
    margin: 6px 0 10px;
    /* Aged parchment: cream center, brown edges via radial vignette,
       overlaid with diagonal stains and wood-edge frame. */
    background:
      /* dark vignette around the edges */
      radial-gradient(ellipse 110% 80% at 50% 50%, transparent 50%, rgba(80,40,10,0.35) 80%, rgba(60,30,5,0.65) 100%),
      /* faint diagonal stain bands */
      repeating-linear-gradient(35deg, transparent 0 80px, rgba(120,80,40,0.05) 80px 82px),
      /* soft "ink wash" patches */
      radial-gradient(ellipse 30% 22% at 22% 30%, rgba(150,110,70,0.18), transparent 70%),
      radial-gradient(ellipse 26% 18% at 78% 65%, rgba(150,110,70,0.18), transparent 70%),
      /* base parchment */
      linear-gradient(135deg, #f6e6c2 0%, #e8d199 100%);
    /* Wood-style ridged frame + inner shadow for depth */
    border: 8px ridge #6b4626;
    box-shadow:
      inset 0 0 36px rgba(80,40,10,0.45),
      0 4px 14px rgba(0,0,0,0.35);
    color: #5a3614;
    font-family: Georgia, 'Times New Roman', serif;
  }
  /* Painted fishing map (imagen-standard, generated 2026-05-05). */
  .shop-ocean .map-painted {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    z-index: 0;
    pointer-events: none;
  }
  /* Route-line SVG layers above the painted map (transparent BG). */
  .shop-ocean .map-route-overlay {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    z-index: 1;
    pointer-events: none;
  }
  /* The painted PNG already includes the wooden frame + aged-map
     look; suppress the parchment frame the .ocean container had. */
  .shop-ocean .ocean {
    border: none;
    background: #1a4d70;          /* dark seam while image loads */
  }
  /* Animated red-dotted route line — appears between the home dock
     and the selected spot. Marching-dots animation makes it look
     like it's actively drawing the path. */
  #route-line {
    animation: routeMarch 0.9s linear infinite;
    filter: drop-shadow(0 1px 1px rgba(80,20,10,0.5));
  }
  @keyframes routeMarch { to { stroke-dashoffset: -10; } }
  /* Compass / ship / kraken decorations sit on top of the SVG map. */
  .shop-ocean .map-deco {
    position: absolute;
    pointer-events: none;
    z-index: 2;
    filter: drop-shadow(0 2px 2px rgba(0,0,0,0.4)) sepia(0.3);
  }
  .shop-ocean .map-compass { top: 6px;   left: 8px;   font-size: clamp(34px, 8vw, 48px); transform: rotate(-12deg); }
  .shop-ocean .map-ship    { top: 6px;   right: 10px; font-size: clamp(28px, 6vw, 36px); transform: rotate(-8deg); }
  .shop-ocean .map-kraken {
    bottom: -8px; right: -6px;
    font-size: clamp(72px, 18vw, 110px);
    transform: rotate(-15deg);
    filter: drop-shadow(0 2px 4px rgba(0,0,0,0.5)) sepia(0.4) hue-rotate(-10deg);
    opacity: 0.95;
  }
  /* Map pins — tiny round numbered dots that mark each spot on the
     painted parchment WITHOUT covering it. Pure visual markers; the
     tappable destination rows live in the list below the map. */
  .shop-ocean .map-pin {
    position: absolute;
    transform: translate(-50%, -50%);
    width: clamp(22px, 5vw, 28px);
    height: clamp(22px, 5vw, 28px);
    border-radius: 50%;
    background: #fff8e0;
    border: 3px solid #5a3614;
    color: #3d2410;
    font-family: Georgia, 'Times New Roman', serif;
    font-weight: bold;
    font-size: clamp(11px, 2.4vw, 14px);
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 2px 4px rgba(60,30,5,0.55);
    z-index: 2;
    pointer-events: none;
  }
  .shop-ocean .map-pin.selected {
    background: #c13a18;
    color: #fff;
    border-color: #6b1a08;
    width: clamp(28px, 6.5vw, 36px);
    height: clamp(28px, 6.5vw, 36px);
    box-shadow: 0 0 0 4px rgba(255,255,255,0.4), 0 3px 6px rgba(60,30,5,0.6);
    z-index: 3;
  }
  .shop-ocean .map-pin.locked  { opacity: 0.55; border-style: dashed; }
  .shop-ocean .map-pin.stormy  { background: #2c4a6c; color: #fff; border-color: #1a2d44; }
  /* Geographic pin positions — match the painted spots on fishing-map.webp. */
  .shop-ocean .map-pin[data-spot="pond"]   { left: 33%; top: 26%; }
  .shop-ocean .map-pin[data-spot="tide"]   { left: 14%; top: 35%; }
  .shop-ocean .map-pin[data-spot="cove"]   { left: 80%; top: 30%; }
  .shop-ocean .map-pin[data-spot="dock"]   { left: 60%; top: 30%; }
  .shop-ocean .map-pin[data-spot="reef"]   { left: 64%; top: 51%; }
  .shop-ocean .map-pin[data-spot="trench"] { left: 32%; top: 64%; }
  .shop-ocean .map-pin[data-spot="wreck"]  { left: 78%; top: 62%; }
  .shop-ocean .vip-pin[data-spot="aurora"]  { left: 18%; top: 78%; }
  .shop-ocean .vip-pin[data-spot="volcano"] { left: 50%; top: 84%; }
  .shop-ocean .vip-pin[data-spot="pirate"]  { left: 88%; top: 80%; }

  /* Destination list — vertical rows below the map. Each row is the
     readable, tappable representation of one spot (icon + name +
     weather + state). Tapping selects (or buys) the spot. */
  .dest-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin: 4px 0 12px;
  }
  .dest-row {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    background: #fffaf0;
    border: 3px solid #c8b888;
    border-radius: 12px;
    padding: 8px 10px;
    cursor: pointer;
    font-family: inherit;
    color: var(--ink);
    text-align: left;
    font-size: clamp(13px, 2.6vw, 15px);
  }
  .dest-row:active { transform: translateY(1px); }
  .dest-row .num {
    flex: 0 0 auto;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    background: #fff8e0;
    border: 2px solid #5a3614;
    color: #3d2410;
    font-family: Georgia, 'Times New Roman', serif;
    font-weight: bold;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 13px;
  }
  .dest-row .icon { font-size: clamp(22px, 5vw, 28px); flex: 0 0 auto; }
  .dest-row .body { flex: 1 1 auto; min-width: 0; }
  .dest-row .name { font-weight: bold; }
  .dest-row .state { font-size: 12px; color: #6a584a; }
  .dest-row .price { font-size: 12px; color: #8b3a13; font-weight: bold; }
  .dest-row .weather {
    flex: 0 0 auto;
    padding: 3px 9px;
    border-radius: 999px;
    font-size: 12px;
    background: #fff;
    border: 1px solid #d6e3ee;
    white-space: nowrap;
  }
  .dest-row .weather.w-perfect  { background: linear-gradient(135deg, #fff7d4, #ffd8a0); border-color: #d99a10; color: #8a4a00; font-weight: bold; }
  .dest-row .weather.w-twilight { background: #ffe8d4; border-color: #d99a10; color: #6a3000; }
  .dest-row .weather.w-cloudy   { background: #eef2f6; }
  .dest-row .weather.w-storm    { background: #2c4a6c; color: #fff; border-color: #1a2d44; font-weight: bold; }
  /* Weather Eye next-forecast pill — small, subdued, sits next to current. */
  .dest-row .weather-next {
    margin-left: 4px;
    padding: 3px 7px;
    font-size: 11px;
    background: rgba(255,255,255,0.85);
    border-style: dashed;
    border-color: var(--accent);
    color: var(--accent);
  }
  .dest-row.selected {
    background: linear-gradient(180deg, #ffe9b0 0%, #ffcb6a 100%);
    border-color: #8b3a13;
    box-shadow: 0 0 0 2px #ffd166 inset;
  }
  .dest-row.locked  { background: #efe8d8; border-style: dashed; opacity: 0.85; }
  .dest-row.stormy  { background: #d6dde6; border-color: #6b7e92; }

  /* ====== Travel overlay ======
     Brief boat-sailing animation between the dock home and a fishing
     spot. Shown when player taps "Fish here now!" or "Cast here!". */
  #travel {
    position: fixed;
    inset: 0;
    background: rgba(20,49,70,0.7);
    z-index: 60;
    display: none;
    align-items: center;
    justify-content: center;
    padding: 20px;
  }
  #travel.show { display: flex; }
  #travel-card {
    background: linear-gradient(180deg, #b3d9ff 0%, #5eb3e0 70%, #2c80b3 100%);
    width: min(420px, 92vw);
    border-radius: 22px;
    padding: 18px 16px;
    box-shadow: 0 8px 24px rgba(0,0,0,0.45);
    text-align: center;
    color: #fff;
    text-shadow: 0 1px 2px rgba(0,0,0,0.4);
  }
  .travel-row {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 12px;
  }
  .travel-end {
    background: rgba(255,255,255,0.92);
    color: var(--ink);
    border-radius: 999px;
    padding: 4px 10px;
    font-size: clamp(13px, 2.6vw, 15px);
    font-weight: bold;
    text-shadow: none;
    flex: 0 0 auto;
    white-space: nowrap;
  }
  .travel-track {
    position: relative;
    flex: 1 1 auto;
    height: 44px;
    min-width: 80px;
  }
  .travel-trail {
    position: absolute;
    left: 0; right: 0;
    top: 50%;
    height: 4px;
    transform: translateY(-50%);
    background: repeating-linear-gradient(90deg, #ff5566 0 9px, transparent 9px 18px);
    border-radius: 2px;
  }
  .travel-boat {
    position: absolute;
    font-size: clamp(28px, 6vw, 36px);
    top: 50%;
    transform: translate(-50%, -55%);
    z-index: 2;
    animation: travelOut 3s ease-in-out forwards;
  }
  #travel.travel-back .travel-boat {
    transform: translate(-50%, -55%) scaleX(-1);
    animation: travelHome 3s ease-in-out forwards;
  }
  @keyframes travelOut {
    0%   { left: 4%; }
    100% { left: 96%; }
  }
  @keyframes travelHome {
    0%   { left: 96%; }
    100% { left: 4%;  }
  }
  .travel-msg {
    font-size: clamp(15px, 3vw, 18px);
    font-weight: bold;
  }
  /* Painted dock-board headings — chalkboard slate with chalky white
     font, wrapped in a wooden frame. Used for the section titles in
     the shop-tools / shop-map views. */
  .shop-section h3,
  #shop-card h2 {
    margin: 12px 0 8px;
    font-size: clamp(15px, 3vw, 18px);
    color: #f5f0e0;
    background:
      repeating-linear-gradient(135deg,
        transparent 0,
        transparent 8px,
        rgba(255,255,255,0.03) 8px,
        rgba(255,255,255,0.03) 9px),
      linear-gradient(180deg, #2d3640 0%, #3a4550 50%, #2d3640 100%);
    border: 3px solid #8a5a2e;
    border-radius: 10px;
    padding: 6px 14px;
    display: inline-block;
    text-align: center;
    letter-spacing: 0.5px;
    text-shadow: 0 0 2px rgba(255,255,255,0.25), 0 1px 0 rgba(0,0,0,0.4);
    box-shadow: 0 3px 0 #6e4423, inset 0 0 0 1px rgba(255,255,255,0.08);
  }
  /* The shop-tools / shop-map h2 sits centered, full-width-ish. */
  #shop-card h2 {
    display: block;
    text-align: center;
    margin-left: auto;
    margin-right: auto;
    max-width: max-content;
  }
  .spot-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 8px;
  }
  .spot-tile {
    background: #f4f9ff;
    border: 3px solid var(--accent);
    border-radius: 14px;
    padding: 8px 6px;
    text-align: center;
    cursor: pointer;
    font-family: inherit;
    color: var(--ink);
    font-size: clamp(12px, 2.4vw, 14px);
    line-height: 1.25;
  }
  .spot-tile .icon { font-size: 28px; display: block; margin-bottom: 2px; }
  .spot-tile.locked { opacity: 0.7; background: #eee; border-style: dashed; }
  .spot-tile.selected {
    background: linear-gradient(135deg, var(--accent), var(--accent-2));
    color: #fff;
    border-color: #1f6f9a;
  }
  .spot-tile .price { color: var(--gold); font-weight: bold; }
  .spot-tile.selected .price { color: #fff; }
  /* Weather pill rendered on each spot tile. Variants per condition. */
  .spot-tile .weather {
    display: inline-block;
    margin-top: 4px;
    padding: 2px 6px;
    border-radius: 999px;
    font-size: clamp(11px, 2.2vw, 12px);
    background: rgba(255,255,255,0.85);
    color: var(--ink);
    border: 1px solid #d6e3ee;
  }
  .spot-tile.selected .weather { background: rgba(255,255,255,0.92); }
  .spot-tile .weather.w-perfect  { background: linear-gradient(135deg, #fff7d4, #ffd8a0); border-color: #d99a10; color: #8a4a00; font-weight: bold; }
  .spot-tile .weather.w-twilight { background: #ffe8d4; border-color: #d99a10; color: #6a3000; }
  .spot-tile .weather.w-cloudy   { background: #eef2f6; }
  .spot-tile .weather.w-storm    { background: #2c4a6c; color: #fff; border-color: #1a2d44; font-weight: bold; }
  /* Stormy = locked. Tile gets a different visual treatment than the
     coin-locked variant so the kid knows it's "weather", not money. */
  .spot-tile.stormy {
    background: #d8e2ec;
    border-color: #2c4a6c;
    color: #2c4a6c;
    cursor: not-allowed;
  }
  .spot-tile.stormy.selected { background: #d8e2ec; color: #2c4a6c; }
  /* Perfect-weather spot pulses gently to draw the eye. */
  .spot-tile.perfect-spot {
    border-color: #d99a10;
    box-shadow: 0 0 12px rgba(255, 200, 80, 0.6);
    animation: perfectPulse 1.6s ease-in-out infinite alternate;
  }
  @keyframes perfectPulse {
    0%   { box-shadow: 0 0 6px rgba(255, 200, 80, 0.4); }
    100% { box-shadow: 0 0 18px rgba(255, 200, 80, 0.85); }
  }
  /* Driftwood-plank pills — every shop row gets a cream-on-brown
     plank look with two brass rivets in the upper corners and a
     subtle wood-grain pattern. */
  .upgrade-row {
    position: relative;
    display: flex;
    align-items: center;
    gap: 10px;
    background:
      repeating-linear-gradient(90deg,
        transparent 0,
        transparent 4px,
        rgba(110, 68, 35, 0.07) 4px,
        rgba(110, 68, 35, 0.07) 5px,
        transparent 5px,
        transparent 14px),
      linear-gradient(180deg, #fff5dc 0%, #fff8e6 50%, #f3e3bf 100%);
    border: 3px solid #8a5a2e;
    border-radius: 14px;
    padding: 10px 14px 10px 18px;
    margin-bottom: 8px;
    font-size: clamp(13px, 2.6vw, 15px);
    box-shadow: 0 3px 0 #6e4423, inset 0 0 0 1px rgba(255,255,255,0.4);
  }
  /* Brass rivets in the top-left + top-right of each plank. */
  .upgrade-row::before, .upgrade-row::after {
    content: '';
    position: absolute;
    top: 5px;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: radial-gradient(circle at 30% 30%, #f5d97a, #a8742a 60%, #5a3d12);
    box-shadow: 0 1px 1px rgba(0,0,0,0.3);
  }
  .upgrade-row::before { left: 6px; }
  .upgrade-row::after  { right: 6px; }
  .upgrade-row .icon { font-size: 26px; }
  .upgrade-row .info { flex: 1; line-height: 1.25; color: #4a3010; }
  .upgrade-row .info b { color: #6e4423; }
  .upgrade-row .pips { color: var(--gold); font-weight: bold; letter-spacing: 1px; }
  .upgrade-row button {
    font-family: inherit;
    font-weight: bold;
    border: 3px solid #8a5a2e;
    background: linear-gradient(180deg, #fff8e6, #f3d99a);
    color: #5a3d12;
    border-radius: 999px;
    padding: 6px 12px;
    cursor: pointer;
    box-shadow: 0 3px 0 #6e4423;
    font-size: 14px;
    min-width: 76px;
  }
  .upgrade-row button:disabled {
    opacity: 0.55;
    cursor: default;
    box-shadow: 0 1px 0 #6e4423;
  }
  /* Maxed planks get a green tint + green rivets for "complete!" feel. */
  .upgrade-row.maxed {
    background:
      repeating-linear-gradient(90deg,
        transparent 0, transparent 4px,
        rgba(40, 100, 60, 0.08) 4px, rgba(40, 100, 60, 0.08) 5px,
        transparent 5px, transparent 14px),
      linear-gradient(180deg, #e9f7ec 0%, #d8f0dd 50%, #c4e6cb 100%);
    border-color: var(--good);
    box-shadow: 0 3px 0 #2c8a48, inset 0 0 0 1px rgba(255,255,255,0.4);
  }
  .upgrade-row.maxed::before, .upgrade-row.maxed::after {
    background: radial-gradient(circle at 30% 30%, #b9f5c8, #4faf6c 60%, #225e35);
  }
  .upgrade-row.maxed .info b { color: var(--good); }
  .upgrade-row.locked {
    opacity: 0.7;
    background: linear-gradient(180deg, #e2dac9, #d4cbb6);
    border-style: dashed;
    border-color: #8a7c5c;
  }
  .upgrade-row.locked .info b { color: #6a5e44; }

  #aquarium {
    background: #f7fbff;
    border: 2px dashed var(--accent);
    border-radius: 12px;
    padding: 8px;
    margin-top: 4px;
    min-height: 42px;
    text-align: center;
    font-size: 22px;
    line-height: 1.4;
    letter-spacing: 4px;
  }
  #aquarium .empty {
    color: #88a8c0;
    font-size: 13px;
    font-style: italic;
    letter-spacing: normal;
  }

  /* Big "Cast here now!" button at the bottom of the map view. */
  #play-btn-map {
    display: block;
    width: 100%;
    margin-top: 6px;
    font-family: inherit;
    font-weight: bold;
    font-size: clamp(18px, 4vw, 24px);
    padding: 14px;
    border-radius: 16px;
    border: 4px solid #d99a10;
    background: linear-gradient(135deg, #ffd166, #ffb720);
    color: #5a3c00;
    cursor: pointer;
    box-shadow: 0 5px 0 #d99a10;
  }
  #play-btn-map:active { transform: translateY(2px); box-shadow: 0 3px 0 #d99a10; }
  #play-btn-map:disabled {
    cursor: not-allowed;
    background: #cfd8e0;
    border-color: #98a4b0;
    color: #5a6678;
    box-shadow: 0 4px 0 #98a4b0;
  }

  /* Trip-end card */
  #trip-end, #weather-help {
    position: fixed;
    inset: 0;
    background: rgba(20,49,70,0.55);
    z-index: 50;
    display: none;
    align-items: center;
    justify-content: center;
    padding: 20px;
  }
  #trip-end.show, #weather-help.show { display: flex; }

  /* Weather guide modal — reuses trip-end-card styling. */
  #weather-help-card {
    background: #fff;
    border-radius: 22px;
    border: 5px solid var(--gold);
    width: min(380px, 92vw);
    padding: 18px;
    text-align: center;
    box-shadow: 0 8px 24px rgba(0,0,0,0.25);
  }
  #weather-help-card h2 {
    margin: 0 0 10px;
    font-size: clamp(22px, 5vw, 28px);
    color: #1f6f9a;
  }
  #weather-help-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 8px 0 12px;
    text-align: left;
  }
  #weather-help-list .wh-row {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 8px 10px;
    background: #f4f9fc;
    border-radius: 12px;
    border: 2px solid #d6e6ee;
  }
  #weather-help-list .wh-pill {
    font-weight: bold;
    font-size: 14px;
    flex: 0 0 auto;
    min-width: 96px;
    padding: 4px 10px;
    border-radius: 999px;
    border: 1px solid #d6e3ee;
    background: #fff;
    text-align: center;
  }
  #weather-help-list .wh-pill.w-perfect  { background: linear-gradient(135deg, #fff7d4, #ffd8a0); border-color: #d99a10; color: #8a4a00; }
  #weather-help-list .wh-pill.w-sunny    { background: #fff8e1; border-color: #f0c060; color: #8a5a00; }
  #weather-help-list .wh-pill.w-twilight { background: #ffe8d4; border-color: #d99a10; color: #6a3000; }
  #weather-help-list .wh-pill.w-cloudy   { background: #eef2f6; color: #234; }
  #weather-help-list .wh-pill.w-storm    { background: #2c4a6c; color: #fff; border-color: #1a2d44; }
  #weather-help-list .wh-desc {
    font-size: clamp(13px, 2.4vw, 15px);
    color: #234;
    line-height: 1.3;
  }
  #weather-help-card button {
    font-family: inherit;
    font-weight: bold;
    font-size: clamp(15px, 3vw, 18px);
    padding: 10px 14px;
    border-radius: 14px;
    border: 4px solid #d99a10;
    background: linear-gradient(135deg, #ffd166, #ffb720);
    color: #5a3c00;
    box-shadow: 0 4px 0 #d99a10;
    cursor: pointer;
    margin-top: 4px;
  }
  /* The little ? button next to weather pills. */
  .weather-help-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    border: 2px solid var(--accent);
    background: #fff;
    color: var(--accent);
    font-weight: bold;
    font-size: 13px;
    margin-left: 4px;
    padding: 0;
    cursor: pointer;
    line-height: 1;
    vertical-align: middle;
  }
  .weather-help-btn:active { transform: scale(0.92); }
  #trip-end-card {
    background: #fff;
    border-radius: 22px;
    border: 5px solid var(--gold);
    width: min(380px, 92vw);
    padding: 18px;
    text-align: center;
    box-shadow: 0 8px 24px rgba(0,0,0,0.25);
  }
  #trip-end-card h2 {
    margin: 0 0 8px;
    font-size: clamp(22px, 5vw, 30px);
    color: #1f6f9a;
  }
  #trip-end-card .big {
    font-size: clamp(34px, 8vw, 48px);
    color: var(--gold);
    font-weight: bold;
    margin: 6px 0;
    text-shadow: 0 2px 0 #b27a00;
  }
  #trip-end-card .row {
    font-size: clamp(14px, 2.6vw, 17px);
    margin: 4px 0;
  }
  #trip-end-card .row b { color: #1f6f9a; }
  #trip-end-card .multi { color: var(--gold); font-weight: bold; }
  #trip-end-card button {
    font-family: inherit;
    font-weight: bold;
    font-size: clamp(15px, 3vw, 18px);
    padding: 10px 14px;
    border-radius: 14px;
    border: 4px solid var(--accent);
    background: linear-gradient(135deg, var(--accent), #1f6f9a);
    color: #fff;
    box-shadow: 0 4px 0 #1f6f9a;
    cursor: pointer;
  }
  #trip-end-card .te-actions {
    display: flex;
    gap: 8px;
    justify-content: center;
    flex-wrap: wrap;
    margin-top: 12px;
  }
  #trip-end-card #te-again {
    background: linear-gradient(135deg, #ffd166, #ffb720);
    border-color: #d99a10;
    box-shadow: 0 4px 0 #d99a10;
    color: #5a3c00;
  }
  /* Letter grade — big, colorful, trophy-like. */
  .te-grade {
    font-size: clamp(40px, 9vw, 56px);
    font-weight: bold;
    letter-spacing: 2px;
    margin: 4px 0 2px;
    background: linear-gradient(135deg, #ffd166, #ff8c42);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    text-shadow: 0 2px 0 rgba(0,0,0,0.05);
    line-height: 1;
  }
  /* Per-fish catch breakdown: emoji ×N pills. */
  .te-catch {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    justify-content: center;
    margin: 6px 0 2px;
    font-size: clamp(15px, 3vw, 18px);
  }
  .te-catch span {
    background: #f4f7fb;
    border: 2px solid #d6e3ee;
    border-radius: 10px;
    padding: 3px 8px;
  }
  /* Junk pills: greyed out, dashed border — visually obvious that
     these were the no-coin pickups. */
  .te-catch span.junk {
    background: #efefef;
    border: 2px dashed #b8b8b8;
    color: #777;
    filter: saturate(0.4);
  }

  /* ===== Submarine mini-game ===== */
  /* The launch button — fancy gradient on a chunky pill. */
  .sub-launch-btn {
    width: 100%;
    font-family: inherit;
    font-weight: bold;
    font-size: clamp(15px, 3.2vw, 18px);
    padding: 12px;
    border-radius: 14px;
    border: 4px solid #1f6f9a;
    background: linear-gradient(180deg, #6ad 0%, #1f6f9a 100%);
    color: #fff;
    cursor: pointer;
    box-shadow: 0 4px 0 #1a4f72, inset 0 0 0 1px rgba(255,255,255,0.18);
    text-shadow: 0 1px 0 rgba(0,0,0,0.3);
  }
  .sub-launch-btn:active { transform: translateY(1px); box-shadow: 0 2px 0 #1a4f72; }

  #sub-stage {
    position: fixed;
    inset: 0;
    z-index: 60;
    display: none;
    overflow: hidden;
    touch-action: none;   /* one-finger drag steering owns the water */
    background: linear-gradient(180deg, #2d5a8a 0%, #143a5e 50%, #0a1d3a 100%);
    /* Inside-the-sub porthole frame: dark vignette around the edges. */
    box-shadow: inset 0 0 80px 12px rgba(0, 0, 0, 0.7);
  }
  #sub-stage[hidden] { display: none !important; }
  #sub-stage.show { display: block; }
  /* Inside-the-sub frame overlay — riveted brass border around the
     entire viewport so it feels like looking out a porthole. */
  #sub-stage::before {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 8;
    border: 14px solid transparent;
    border-image-slice: 0;
    background:
      /* Top brass strip */
      linear-gradient(180deg, #6a4423, #4a2e10) top   / 100% 14px no-repeat,
      /* Bottom brass strip */
      linear-gradient(0deg,   #6a4423, #4a2e10) bottom/ 100% 14px no-repeat,
      /* Left brass strip */
      linear-gradient(90deg,  #6a4423, #4a2e10) left  / 14px 100% no-repeat,
      /* Right brass strip */
      linear-gradient(270deg, #6a4423, #4a2e10) right / 14px 100% no-repeat;
  }
  /* Decorative corner rivets on the porthole frame. */
  #sub-stage::after {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 9;
    background-image:
      radial-gradient(circle at 16px 16px,  #f5d97a 0 3px, #5a3d12 3px 5px, transparent 5px),
      radial-gradient(circle at calc(100% - 16px) 16px,  #f5d97a 0 3px, #5a3d12 3px 5px, transparent 5px),
      radial-gradient(circle at 16px calc(100% - 16px),  #f5d97a 0 3px, #5a3d12 3px 5px, transparent 5px),
      radial-gradient(circle at calc(100% - 16px) calc(100% - 16px), #f5d97a 0 3px, #5a3d12 3px 5px, transparent 5px);
    background-repeat: no-repeat;
  }
  #sub-stage-bg {
    position: absolute;
    inset: 14px;
    background:
      /* Light shaft from above — like a sub headlight beam. */
      radial-gradient(ellipse at 50% 0%, rgba(160, 220, 255, 0.22) 0%, transparent 55%),
      radial-gradient(ellipse at 30% 20%, rgba(120, 200, 255, 0.14) 0%, transparent 60%),
      /* Sonar-style horizontal scan-lines that scroll with depth. */
      repeating-linear-gradient(180deg,
        transparent 0, transparent 38px,
        rgba(120, 220, 255, 0.05) 38px, rgba(120, 220, 255, 0.05) 40px);
    background-size: 100% 100%, 100% 100%, 100% 80px;
    background-position: 0 0, 0 0, 0 var(--sub-bg-y, 0px);
    transition: filter 0.6s ease;
  }
  /* Bubble stream rising up from below. */
  #sub-bubbles {
    position: absolute;
    inset: 14px;
    pointer-events: none;
    z-index: 1;
    overflow: hidden;
  }
  #sub-bubbles span {
    position: absolute;
    bottom: -20px;
    left: var(--bx, 50%);
    width: var(--bs, 6px);
    height: var(--bs, 6px);
    background: radial-gradient(circle at 30% 30%, rgba(255,255,255,0.85), rgba(180, 230, 255, 0.35) 70%, transparent);
    border-radius: 50%;
    animation: subBubbleRise var(--bd, 8s) linear infinite;
    animation-delay: calc(var(--bd) * -0.4);
  }
  /* Composited rise: transform-only (animating `bottom` forced continuous
     layout for the whole dive). */
  @keyframes subBubbleRise {
    0%   { opacity: 0; transform: translate(0, 0); }
    20%  { opacity: 0.9; }
    100% { opacity: 0;
            transform: translate(calc(sin(var(--bx) * 1) * 12px), -110vh); }
  }
  /* Sonar pulse ring — emanates outward from the sub. */
  #sub-sonar {
    position: absolute;
    left: 50%; top: 40%;
    transform: translate(-50%, -50%);
    width: 80px; height: 80px;
    border-radius: 50%;
    border: 2px solid rgba(120, 220, 255, 0.45);
    pointer-events: none;
    animation: subSonarPulse 2.4s ease-out infinite;
    z-index: 2;
  }
  /* Composited pulse: scale instead of width/height (no per-frame layout). */
  @keyframes subSonarPulse {
    0%   { transform: translate(-50%, -50%) scale(1);   opacity: 0.7; }
    100% { transform: translate(-50%, -50%) scale(4.5); opacity: 0;   }
  }
  #sub-vehicle {
    position: absolute;
    /* JS sets `left` directly each frame so the sub can be steered
       horizontally via the rudder controls. */
    left: 50%;
    top:  40%;
    transform: translate(-50%, -50%);
    width: 110px;
    height: 56px;
    background:
      radial-gradient(circle at 30% 30%, #fff5dc 0%, #ffd166 30%, #d99a10 60%, #b27a00 100%);
    border-radius: 60px;
    border: 4px solid #6e4423;
    box-shadow: 0 6px 16px rgba(0,0,0,0.5), inset 0 -5px 0 rgba(0,0,0,0.22), inset 0 3px 0 rgba(255,255,255,0.4);
    z-index: 4;
  }
  /* Periscope. */
  #sub-vehicle::before {
    content: '';
    position: absolute;
    top: -18px;
    left: 22%;
    width: 8px;
    height: 22px;
    background: linear-gradient(180deg, #6e4423, #2a1d10);
    border-radius: 3px 3px 0 0;
    box-shadow: 0 -2px 0 #f5d97a, 0 0 4px rgba(0,0,0,0.4);
  }
  /* Porthole. */
  #sub-vehicle::after {
    content: '';
    position: absolute;
    top: 12px;
    left: 58%;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: radial-gradient(circle at 30% 30%, #ffffff, #cce6ff 30%, #6cb3e8 70%, #2e6a9c);
    border: 4px solid #6e4423;
    box-shadow: inset 0 0 0 2px #f5d97a, 0 0 6px rgba(120, 220, 255, 0.5);
  }

  #sub-hud {
    position: absolute;
    top: 22px;
    left: 22px;
    right: 22px;
    display: flex;
    align-items: stretch;
    justify-content: space-between;
    gap: 8px;
    z-index: 5;
    color: #fff;
    font-weight: bold;
    font-family: inherit;
    pointer-events: none;
  }
  /* Brass console plate behind each HUD readout. Rivets in the corners. */
  .brass-plate {
    position: relative;
    background:
      repeating-linear-gradient(135deg,
        transparent 0 6px, rgba(255,255,255,0.04) 6px 7px),
      linear-gradient(180deg, #6a4423 0%, #3a2510 50%, #6a4423 100%);
    border: 3px solid #2a1d10;
    border-radius: 10px;
    padding: 6px 14px 6px 14px;
    box-shadow: 0 3px 0 #1a1008, inset 0 0 0 1px rgba(255,255,255,0.18);
    color: #f5e6c8;
    text-shadow: 0 1px 0 rgba(0,0,0,0.6);
    font-size: clamp(12px, 2.4vw, 14px);
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: 36px;
  }
  .brass-plate .brass-label {
    font-size: 10px;
    letter-spacing: 1px;
    color: #f5d97a;
    opacity: 0.85;
  }
  .brass-plate b {
    font-size: clamp(15px, 3vw, 18px);
    color: #fff;
    background: linear-gradient(180deg, #142030, #0a1424);
    border: 1px solid #f5d97a;
    border-radius: 6px;
    padding: 1px 6px;
    text-shadow: 0 0 4px rgba(120, 220, 255, 0.8);
    font-family: 'Courier New', monospace;
  }
  .brass-plate .unit { color: #f5d97a; font-size: 10px; }
  /* Rivets in the corners of every brass plate. */
  .rivet {
    position: absolute;
    width: 7px; height: 7px;
    top: 3px;
    border-radius: 50%;
    background: radial-gradient(circle at 30% 30%, #f5d97a, #a8742a 60%, #5a3d12);
    box-shadow: 0 1px 1px rgba(0,0,0,0.5);
  }
  .rivet-l { left: 3px; }
  .rivet-r { right: 3px; }
  /* Air gauge — the bar grows wider so it feels like a porthole-shaped tank. */
  #sub-air { flex: 1; padding: 6px 14px; }
  #sub-air-bar {
    flex: 1;
    height: 14px;
    background: linear-gradient(180deg, #0a1424, #142030);
    border-radius: 7px;
    overflow: hidden;
    border: 1px solid #f5d97a;
    box-shadow: inset 0 1px 2px rgba(0,0,0,0.6);
    position: relative;
  }
  #sub-air-bar::after {
    /* Tank notch markers like a real pressure gauge. */
    content: '';
    position: absolute;
    inset: 0;
    background-image: repeating-linear-gradient(90deg,
      transparent 0 24px, rgba(245, 217, 122, 0.4) 24px 25px);
    pointer-events: none;
  }
  #sub-air-fill {
    height: 100%;
    width: 100%;
    background:
      repeating-linear-gradient(90deg,
        transparent 0 8px, rgba(255,255,255,0.18) 8px 9px),
      linear-gradient(90deg, #2e6a9c, #6cb3e8 60%, #aef);
    transition: width 200ms linear;
    box-shadow: inset 0 -2px 0 rgba(0,0,0,0.25);
  }
  #sub-air.low  #sub-air-fill { background:
    repeating-linear-gradient(90deg, transparent 0 8px, rgba(255,255,255,0.18) 8px 9px),
    linear-gradient(90deg, #c97a00, #ffd166); }
  #sub-air.crit #sub-air-fill { background:
    repeating-linear-gradient(90deg, transparent 0 8px, rgba(255,255,255,0.18) 8px 9px),
    linear-gradient(90deg, #c00, #ff4444);
    animation: subFlash 0.6s ease-in-out infinite alternate; }
  #sub-air-text { font-family: 'Courier New', monospace; color: #f5d97a; font-size: 11px; min-width: 28px; text-align: right; }
  @keyframes subFlash { from { opacity: 1; } to { opacity: 0.45; } }

  #sub-banner {
    position: absolute;
    top: 70px;
    left: 22px;
    right: 22px;
    text-align: center;
    color: #4af;
    font-family: 'Courier New', monospace;
    font-weight: bold;
    font-size: clamp(13px, 3vw, 16px);
    letter-spacing: 1.5px;
    background: rgba(8, 16, 32, 0.6);
    border: 2px solid #2e6a9c;
    border-radius: 6px;
    padding: 4px 10px;
    text-shadow: 0 0 6px rgba(80, 200, 255, 0.7);
    z-index: 5;
    pointer-events: none;
    min-height: 22px;
    box-shadow: inset 0 0 8px rgba(120, 220, 255, 0.2);
  }
  #sub-banner:empty { display: none; }

  /* Two-pad cockpit layout. PILOT d-pad on the left (▲▼◀▶ in a + shape),
     DEFENSE buttons (💡 flash, ⚡ zap) on the right. Each pad has a
     brass frame and tank tape label. */
  #sub-controls {
    position: absolute;
    bottom: calc(env(safe-area-inset-bottom, 0px) + 22px);
    left: 16px;
    right: 16px;
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    z-index: 5;
    pointer-events: none;
  }
  .sub-pad {
    pointer-events: auto;
    display: flex;
    padding: 8px 10px 4px;
    background:
      repeating-linear-gradient(135deg, transparent 0 6px, rgba(255,255,255,0.04) 6px 7px),
      linear-gradient(180deg, #4a2e10, #2a1d08);
    border: 3px solid #1a1008;
    border-radius: 14px;
    box-shadow: 0 4px 0 #1a1008, inset 0 0 0 1px rgba(255,255,255,0.12);
    flex-direction: column;
    align-items: center;
  }
  .sub-pad .pad-label {
    margin-top: 4px;
    font-size: 9px;
    letter-spacing: 1.5px;
    color: #f5d97a;
    text-transform: uppercase;
  }
  /* D-pad: 3×3 grid with the four arrows in a + shape. */
  .sub-dpad {
    display: grid;
    grid-template-columns: 44px 44px 44px;
    grid-template-rows: 44px 44px 44px;
    gap: 4px;
  }
  /* Touch screens: 44px is Apple's bare minimum — give real thumbs 54px
     during the twitchiest part of the game. */
  @media (pointer: coarse) {
    .sub-dpad {
      grid-template-columns: 54px 54px 54px;
      grid-template-rows: 54px 54px 54px;
    }
    .dpad-btn { width: 54px; height: 54px; font-size: 22px; }
  }
  /* Hold buttons must never surrender the pointer to a browser gesture. */
  .sub-btn { touch-action: none; }
  .sub-dpad .dpad-up    { grid-column: 2; grid-row: 1; }
  .sub-dpad .dpad-left  { grid-column: 1; grid-row: 2; }
  .sub-dpad .dpad-right { grid-column: 3; grid-row: 2; }
  .sub-dpad .dpad-down  { grid-column: 2; grid-row: 3; }
  /* Action stack: 2 round buttons. */
  .sub-actions {
    display: flex;
    flex-direction: column;
    gap: 10px;
  }
  /* Brass-rimmed dial buttons. */
  .sub-btn {
    border-radius: 50%;
    border: 4px solid #6e4423;
    background:
      radial-gradient(circle at 30% 30%, #fff5dc 0%, #d4a85d 50%, #6e4423 100%);
    color: #2a1d10;
    font-size: 22px;
    font-weight: bold;
    cursor: pointer;
    box-shadow:
      inset 0 -3px 0 rgba(0,0,0,0.28),
      inset 0 2px 0 rgba(255,255,255,0.4),
      0 3px 0 #2a1d10;
    text-shadow: 0 1px 0 rgba(255,255,255,0.5);
    position: relative;
    padding: 0;
  }
  .sub-btn:active {
    transform: translateY(1px);
    box-shadow: inset 0 -3px 0 rgba(0,0,0,0.28), inset 0 2px 0 rgba(255,255,255,0.4), 0 1px 0 #2a1d10;
  }
  .sub-btn.holding {
    background: radial-gradient(circle at 30% 30%, #ffe78a 0%, #ffb720 50%, #b27a00 100%);
    box-shadow: inset 0 -3px 0 rgba(0,0,0,0.28), inset 0 2px 0 rgba(255,255,255,0.5), 0 0 12px rgba(255, 200, 80, 0.7);
  }
  .sub-btn:disabled { opacity: 0.4; cursor: not-allowed; }
  /* D-pad arrows are smaller. */
  .dpad-btn {
    width: 44px;
    height: 44px;
    font-size: 18px;
  }
  /* Action buttons are big and visually distinct. */
  .action-btn {
    width: 64px;
    height: 64px;
    font-size: 28px;
  }
  .action-btn::after {
    content: '';
    position: absolute;
    inset: 8px;
    border-radius: 50%;
    border: 2px dashed rgba(0,0,0,0.22);
    pointer-events: none;
  }
  .action-flash {
    background: radial-gradient(circle at 30% 30%, #fffae0 0%, #ffd166 50%, #b27a00 100%);
  }
  .action-flash:not(:disabled):active {
    box-shadow: inset 0 -3px 0 rgba(0,0,0,0.28), inset 0 2px 0 rgba(255,255,255,0.5), 0 0 18px rgba(255, 240, 120, 0.85);
  }
  .action-zap {
    background: radial-gradient(circle at 30% 30%, #d8eaff 0%, #5fb4dc 45%, #1f4f80 100%);
    color: #fff;
    text-shadow: 0 1px 0 rgba(0,0,0,0.5);
  }
  .action-zap:not(:disabled):active {
    box-shadow: inset 0 -3px 0 rgba(0,0,0,0.28), inset 0 2px 0 rgba(255,255,255,0.5), 0 0 22px rgba(120, 220, 255, 0.95);
  }
  /* Flash + zap on-stage overlay effects. */
  .sub-flash-overlay, .sub-zap-overlay {
    position: absolute;
    inset: 14px;
    pointer-events: none;
    z-index: 7;
    border-radius: 0;
  }
  .sub-flash-overlay {
    background: radial-gradient(circle at 50% 40%, rgba(255,255,200,0.85), rgba(255,255,200,0.0) 60%);
    animation: subFlashOverlay 0.36s ease-out forwards;
  }
  .sub-zap-overlay {
    background: radial-gradient(circle at 50% 40%, rgba(160, 230, 255, 0.85), rgba(80, 180, 255, 0.0) 65%);
    animation: subZapOverlay 0.5s ease-out forwards;
  }
  @keyframes subFlashOverlay { 0% { opacity: 1; } 100% { opacity: 0; } }
  @keyframes subZapOverlay {
    0%   { opacity: 1; transform: scale(0.6); }
    50%  { opacity: 1; transform: scale(1.05); }
    100% { opacity: 0; transform: scale(1.2); }
  }
  /* Surface sky overlay — visible at depth 0, slides offscreen as
     the kid dives past 30m. translate set inline by gameTickSub. */
  #sub-sky {
    position: absolute;
    left: 14px;
    right: 14px;
    top: 14px;
    height: 60%;
    background: linear-gradient(180deg,
      #cfeefe 0%,
      #a3d6f5 50%,
      rgba(80, 160, 220, 0.7) 80%,
      rgba(45, 90, 138, 0) 100%);
    z-index: 2;
    pointer-events: none;
    overflow: hidden;
    transform: translateY(0%);
  }
  #sub-sky .sky-sun {
    position: absolute;
    top: 12%;
    right: 18%;
    font-size: 38px;
    filter: drop-shadow(0 0 8px gold);
  }
  #sub-sky .sky-cloud {
    position: absolute;
    font-size: 36px;
    filter: drop-shadow(0 2px 3px rgba(0,0,0,0.15));
    animation: subSkyDrift 14s linear infinite;
  }
  #sub-sky .sky-cloud-a { top: 8%;  left: 12%; animation-duration: 18s; }
  #sub-sky .sky-cloud-b { top: 22%; left: 50%; animation-duration: 22s; }
  #sub-sky .sky-cloud-c { top: 36%; left: 28%; animation-duration: 16s; }
  @keyframes subSkyDrift {
    0%   { transform: translateX(0); }
    100% { transform: translateX(-30px); }
  }
  #sub-sky .sky-waves {
    position: absolute;
    left: 0; right: 0;
    bottom: -2px;
    height: 18px;
    background:
      repeating-linear-gradient(90deg,
        transparent 0 6px,
        rgba(255,255,255,0.55) 6px 14px,
        transparent 14px 22px);
    border-bottom: 3px solid rgba(80, 160, 220, 0.7);
    border-radius: 0 0 50% 50% / 0 0 8px 8px;
    box-shadow: inset 0 -6px 8px rgba(255,255,255,0.4);
  }

  /* Emergency surface button — red lever with brass cap. */
  #sub-exit {
    position: absolute;
    top: 22px;
    right: 22px;
  }
  /* The shared topbar's ❓⏸🎵🔊 circles land exactly on this corner (same
     collision #shop-btn already ducks) — slide the panic button below them. */
  body:has(#kg-topbar) #sub-exit { top: 64px; }
  #sub-exit {
    width: 64px;
    height: 64px;
    border-radius: 50%;
    border: 5px solid #6e4423;
    background:
      radial-gradient(circle at 30% 30%, #ff7a7a 0%, #c00 60%, #6e0000 100%);
    color: #fff;
    font-family: inherit;
    font-weight: bold;
    cursor: pointer;
    z-index: 7;
    padding: 0;
    box-shadow: 0 4px 0 #2a0000, inset 0 -3px 0 rgba(0,0,0,0.4), inset 0 2px 0 rgba(255,255,255,0.3);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1px;
  }
  #sub-exit .emergency-cap { font-size: 22px; line-height: 1; }
  #sub-exit .emergency-text { font-size: 9px; letter-spacing: 1px; text-shadow: 0 1px 0 rgba(0,0,0,0.5); }
  #sub-exit:active { transform: translateY(2px); box-shadow: 0 2px 0 #2a0000, inset 0 -3px 0 rgba(0,0,0,0.4), inset 0 2px 0 rgba(255,255,255,0.3); }

  /* Sub pickups + sharks share the same .sub-thing class; depth-based
     icons get sized via inline style. */
  .sub-thing {
    position: absolute;
    font-size: 32px;
    line-height: 1;
    pointer-events: none;
    text-shadow: 0 2px 4px rgba(0,0,0,0.4);
    z-index: 3;
  }
  .sub-thing.shark { font-size: 40px; pointer-events: auto; cursor: pointer; }
  /* Real webp art instead of an emoji glyph (subArt in game.js). */
  .sub-thing.has-sprite {
    width: 42px; height: 42px;
    background-size: contain;
    background-position: center;
    background-repeat: no-repeat;
    filter: drop-shadow(0 0 3px rgba(255,255,255,0.7)) drop-shadow(0 2px 3px rgba(0,0,0,0.45));
  }
  .sub-thing.goal.has-sprite { width: 54px; height: 54px; }
  .sub-thing.creature.has-sprite { width: 76px; height: 76px; }
  .sub-thing.flash {
    animation: subPickupFlash 0.4s ease-out forwards;
  }
  @keyframes subPickupFlash {
    0%   { transform: scale(1) translate(0,0); opacity: 1; }
    100% { transform: scale(1.6) translate(0, -28px); opacity: 0; }
  }
  /* Goal item — bigger, glowing, sparkle ring. */
  .sub-thing.goal {
    font-size: 44px;
    filter: drop-shadow(0 0 10px gold) drop-shadow(0 2px 4px rgba(0,0,0,0.4));
    animation: subGoalSparkle 1.6s ease-in-out infinite alternate;
  }
  @keyframes subGoalSparkle {
    from { transform: scale(1.0); }
    to   { transform: scale(1.15); }
  }
  /* Big creature — large silhouette/sprite that drifts then darts. */
  .sub-thing.creature {
    font-size: 56px;
    filter: drop-shadow(0 4px 8px rgba(0,0,0,0.5));
    transition: transform 280ms ease-out;
  }
  .sub-thing.creature.too-shallow {
    /* dim grayscale effect — visible but un-catchable. */
    filter: drop-shadow(0 4px 8px rgba(0,0,0,0.5)) brightness(0.7) contrast(0.85);
  }
  /* The on-stage goal pill that tells the kid what to find. */
  #sub-goal-pill {
    position: absolute;
    top: 100px;
    left: 22px;
    right: 22px;
    text-align: center;
    z-index: 5;
    pointer-events: none;
    font-family: 'Courier New', monospace;
    font-weight: bold;
    font-size: clamp(12px, 2.6vw, 14px);
    letter-spacing: 1px;
    color: #f5d97a;
    background: rgba(58, 37, 16, 0.7);
    border: 2px solid #6e4423;
    border-radius: 6px;
    padding: 4px 10px;
    text-shadow: 0 1px 0 rgba(0,0,0,0.6);
  }
  #sub-goal-pill:empty { display: none; }
  /* Sub trip-end card — fixed overlay above the sub stage. */
  #sub-end {
    position: fixed;
    inset: 0;
    background: rgba(8, 16, 32, 0.7);
    z-index: 70;
    display: none;
    align-items: center;
    justify-content: center;
    padding: 20px;
  }
  #sub-end.show { display: flex; }
  #sub-end[hidden] { display: none !important; }
  #sub-end-card {
    background: linear-gradient(180deg, #2d5a8a 0%, #143a5e 100%);
    color: #fff;
    border: 5px solid #f5d97a;
    border-radius: 22px;
    width: min(380px, 92vw);
    padding: 18px;
    text-align: center;
    box-shadow: 0 8px 24px rgba(0,0,0,0.5), inset 0 0 0 2px rgba(255,255,255,0.1);
    font-family: inherit;
  }
  #sub-end-card h2 {
    margin: 0 0 8px;
    font-size: clamp(22px, 5vw, 28px);
    color: #f5d97a;
    text-shadow: 0 1px 0 rgba(0,0,0,0.4);
  }
  #sub-end-card .row {
    font-size: clamp(13px, 2.6vw, 15px);
    margin: 4px 0;
  }
  #sub-end-card .big {
    font-size: clamp(34px, 8vw, 48px);
    color: #f5d97a;
    font-weight: bold;
    margin: 6px 0;
    text-shadow: 0 2px 0 #b27a00;
  }
  #sub-end-card .se-medal {
    font-size: clamp(22px, 5vw, 28px);
    margin: 6px 0 4px;
    color: #f5d97a;
  }
  #sub-end-card .se-medal:empty { display: none; }
  #sub-end-card #se-best { color: #6cff9a; font-weight: bold; }
  #sub-end-card #se-collection {
    margin-top: 10px;
    padding: 8px;
    border: 1px dashed rgba(255,255,255,0.25);
    border-radius: 8px;
    font-size: clamp(13px, 2.4vw, 15px);
    text-align: left;
    color: #d6e6ee;
  }
  #sub-end-card #se-collection b { color: #f5d97a; }
  #sub-end-card .se-actions { margin-top: 12px; }
  #sub-end-card button {
    font-family: inherit;
    font-weight: bold;
    font-size: clamp(15px, 3vw, 18px);
    padding: 10px 18px;
    border-radius: 14px;
    border: 4px solid #b27a00;
    background: linear-gradient(180deg, #fff8e6, #ffd166);
    color: #5a3c00;
    box-shadow: 0 4px 0 #b27a00;
    cursor: pointer;
  }

  /* Tucked in the stage's lower-left corner, above the button row, so it
     never prints across the CAST/REEL button text on any screen size. */
  #author {
    position: fixed;
    bottom: calc(env(safe-area-inset-bottom, 0px) + 92px);
    left: 12px;
    font-size: 12px;
    color: rgba(255,255,255,0.85);
    text-shadow: 0 1px 2px rgba(20,49,70,0.6);
    font-style: italic;
    pointer-events: none;
    z-index: 21;
  }
  /* Princess-Run-style title screen — full-bleed painted hero art that
     doubles as the asset-loading curtain. Stays up while images decode;
     "Start" button enables once the heavy art is ready. */
  #title-screen {
    position: fixed; inset: 0;
    z-index: 9000;
    display: grid; place-items: center;
    transition: opacity 0.5s ease;
    background: #0b2a44;
    overflow: hidden;
  }
  #title-screen.hide {
    opacity: 0;
    pointer-events: none;
  }
  #title-screen #title-art {
    position: absolute; inset: 0;
    width: 100%; height: 100%;
    object-fit: cover;
    object-position: center;
    z-index: 0;
    pointer-events: none;
  }
  #title-screen #title-text {
    position: absolute; z-index: 1;
    left: 50%; top: 6vh;
    transform: translateX(-50%);
    text-align: center;
    pointer-events: none;
    user-select: none;
    line-height: 0.9;
    font-family: "Fredoka", "Comic Sans MS", system-ui, sans-serif;
    font-weight: 800;
    width: max-content;
  }
  #title-screen #title-text .row1,
  #title-screen #title-text .row2 {
    display: block;
    color: #fff7d6;
    letter-spacing: 2px;
    text-shadow:
      -3px 0 0 #1a3f5c, 3px 0 0 #1a3f5c,
      0 -3px 0 #1a3f5c, 0 3px 0 #1a3f5c,
      -3px -3px 0 #1a3f5c, 3px 3px 0 #1a3f5c,
      -3px 3px 0 #1a3f5c, 3px -3px 0 #1a3f5c,
      0 6px 0 rgba(0,0,0,0.35),
      0 12px 22px rgba(0,0,0,0.55);
    animation: title-bob 2.4s ease-in-out infinite alternate;
  }
  #title-screen #title-text .row1 {
    font-size: clamp(24px, 6.5vw, 76px);
    color: #ffe18f;
    margin-bottom: 4px;
  }
  #title-screen #title-text .row2 {
    font-size: clamp(40px, 11vw, 132px);
    color: #ffdf63;
    letter-spacing: 4px;
    animation-delay: 0.2s;
  }
  @keyframes title-bob {
    from { transform: translateY(0)    rotate(-1deg); }
    to   { transform: translateY(-6px) rotate(1deg); }
  }
  #title-screen .title-actions {
    position: absolute; z-index: 1;
    left: 50%; bottom: 10vh;
    transform: translateX(-50%);
    display: flex; flex-direction: column;
    align-items: center; gap: 14px;
  }
  #title-screen .wood-btn {
    appearance: none;
    border: none;
    cursor: pointer;
    font-family: "Georgia", "Times New Roman", serif;
    font-weight: 900;
    font-size: clamp(20px, 3.4vw, 34px);
    letter-spacing: 0.06em;
    color: #4a2a14;
    text-shadow: 0 1px 0 rgba(255, 240, 210, 0.7);
    padding: 0.5em 1.6em;
    border-radius: 18px;
    background: linear-gradient(180deg, #fbe6b1 0%, #f1c878 45%, #d99a3f 100%);
    box-shadow:
      0 0 0 4px #4a2a14,
      0 0 0 7px #b6803a,
      inset 0 4px 0 rgba(255, 250, 220, 0.65),
      inset 0 -6px 8px rgba(120, 60, 20, 0.45),
      0 8px 14px rgba(0, 0, 0, 0.45);
    transition: transform 0.12s ease;
  }
  #title-screen .wood-btn:hover  { transform: translateY(-2px); }
  #title-screen .wood-btn:active { transform: translateY(2px); }
  #title-screen .wood-btn:disabled {
    cursor: wait;
    filter: saturate(0.5) brightness(0.85);
  }
  /* Secondary "New Game" button — paler, smaller, less shouty than the
     primary Continue/Start button. Sits below Continue for returning
     players so wiping the save isn't the first thing the kid taps.
     Hidden via the [hidden] attribute for brand-new players (no save
     yet, nothing to wipe). */
  #title-screen .wood-btn.secondary {
    font-size: clamp(14px, 2.2vw, 22px);
    padding: 0.42em 1.3em;
    background: linear-gradient(180deg, #f6e4c8 0%, #d9c19a 45%, #a17a4c 100%);
    color: #3a210d;
    box-shadow:
      0 0 0 3px #4a2a14,
      0 0 0 5px #a17a4c,
      inset 0 3px 0 rgba(255, 250, 220, 0.55),
      inset 0 -4px 6px rgba(120, 60, 20, 0.35),
      0 5px 9px rgba(0, 0, 0, 0.35);
  }
  #title-screen .wood-btn[hidden] { display: none; }
