/* Phyloca — sunny high-tech UI. */
* { margin: 0; padding: 0; box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
html, body { height: 100%; overflow: hidden; background: #aee7ff; touch-action: none;
  font-family: system-ui, -apple-system, "Segoe UI", sans-serif; user-select: none; -webkit-user-select: none; }
button { font-family: inherit; border: 0; cursor: pointer; }

#phGL, #phFX { position: fixed; inset: 0; width: 100%; height: 100%; display: block; }
#phFX { pointer-events: none; z-index: 5; }
#phFX.aiming { cursor: crosshair; }
/* soft cinematic vignette over live play (DOM-only — never in recorded Moments) */
#phVign { position: fixed; inset: 0; pointer-events: none; z-index: 4;
  background: radial-gradient(ellipse at center, transparent 58%, rgba(8, 18, 10, .07) 78%, rgba(8, 18, 10, .24) 100%); }

/* crosshair (field mode) */
#phCross { position: fixed; left: 50%; top: 44%; transform: translate(-50%, -50%); z-index: 6; pointer-events: none; }
#phCross span { display: block; width: 26px; height: 26px; border: 2px solid rgba(255, 255, 255, .9); border-radius: 50%;
  box-shadow: 0 0 10px rgba(66, 232, 245, .8), inset 0 0 6px rgba(66, 232, 245, .6); }
#phCross span::after { content: ""; position: absolute; left: 50%; top: 50%; width: 4px; height: 4px; margin: -2px;
  background: #42e8f5; border-radius: 50%; }

/* ============ loading ============ */
#phLoading { position: fixed; inset: 0; z-index: 100; display: flex; flex-direction: column; gap: 14px;
  align-items: center; justify-content: center; color: #1c4a22;
  background: linear-gradient(#aee7ff 0%, #d8f5c8 60%, #8ad058 100%); }
.ph-load-logo { font-size: clamp(42px, 9vw, 72px); font-weight: 900; letter-spacing: .04em; }
#loadbar { width: min(320px, 70vw); height: 10px; background: rgba(255, 255, 255, .5); border-radius: 6px; overflow: hidden; }
#loadbar-fill { height: 100%; width: 0; border-radius: 6px; background: linear-gradient(90deg, #7ec850, #42e8f5); transition: width .15s; }
#loadnote { font-size: 12px; opacity: .6; }

/* logo */
.ph-logo { font-size: clamp(46px, 10vw, 84px); font-weight: 900; letter-spacing: .04em; line-height: 1;
  filter: drop-shadow(0 4px 0 rgba(20, 60, 20, .25)); }
.ph-logo.sm { font-size: clamp(30px, 6vw, 44px); }
.ph-logo-a { color: #2c7a1e; } .ph-logo-b { color: #ff8b3d; }
.ph-tagline { font-size: clamp(14px, 2.6vw, 19px); color: #1c4a22; opacity: .85; margin-top: 6px; font-weight: 600; }

/* ============ menus ============ */
#phMenu { position: fixed; inset: 0; z-index: 40; display: none; overflow-y: auto; touch-action: pan-y;
  background: linear-gradient(#aee7ffee 0%, #d8f5c8ee 55%, #8ad058ee 100%); backdrop-filter: blur(3px);
  padding: max(14px, env(safe-area-inset-top)) max(14px, env(safe-area-inset-right)) max(14px, env(safe-area-inset-bottom)) max(14px, env(safe-area-inset-left)); }
#phMenu.show { display: block; }
/* menus: drifting pollen-bokeh backdrop (pure CSS — two soft dot layers slowly
   floating in opposite directions) + a gentle entrance for the content */
#phMenu::before { content: ""; position: fixed; inset: -20%; pointer-events: none; opacity: .5;
  background:
    radial-gradient(circle 5px at 12% 18%, #ffffffb0 0 40%, transparent 60%),
    radial-gradient(circle 3px at 34% 62%, #fff2b0a8 0 40%, transparent 60%),
    radial-gradient(circle 6px at 58% 30%, #ffffff90 0 40%, transparent 60%),
    radial-gradient(circle 4px at 81% 74%, #ffe9a8b0 0 40%, transparent 60%),
    radial-gradient(circle 3px at 92% 22%, #ffffffa0 0 40%, transparent 60%),
    radial-gradient(circle 5px at 45% 88%, #fff2b098 0 40%, transparent 60%);
  animation: ph-pollen-a 26s ease-in-out infinite alternate; }
#phMenu::after { content: ""; position: fixed; inset: -20%; pointer-events: none; opacity: .35;
  background:
    radial-gradient(circle 4px at 22% 80%, #ffffffa8 0 40%, transparent 60%),
    radial-gradient(circle 6px at 68% 12%, #fff2b0a0 0 40%, transparent 60%),
    radial-gradient(circle 3px at 88% 52%, #ffffffb0 0 40%, transparent 60%),
    radial-gradient(circle 5px at 8% 44%, #ffe9a8a0 0 40%, transparent 60%);
  animation: ph-pollen-b 34s ease-in-out infinite alternate; }
@keyframes ph-pollen-a { from { transform: translate(0, 0); } to { transform: translate(4%, -6%); } }
@keyframes ph-pollen-b { from { transform: translate(0, 0); } to { transform: translate(-5%, 5%); } }
@media (prefers-reduced-motion: reduce) { #phMenu::before, #phMenu::after { animation: none; } }
.ph-home { max-width: 560px; margin: 0 auto; padding: 4vh 8px 24px; text-align: center; display: flex; flex-direction: column; align-items: center; gap: 12px;
  position: relative; animation: ph-rise .3s ease-out; }
@keyframes ph-rise { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
.ph-home.wide { max-width: 860px; }
.ph-h2 { color: #1c4a22; font-size: clamp(20px, 4vw, 30px); }
.ph-h3 { color: #1c4a22; font-size: clamp(15px, 3vw, 20px); }
.ph-blurb { color: #23531f; font-size: 14px; max-width: 60ch; line-height: 1.5; }
.ph-blurb.dim { opacity: .7; font-size: 13px; }
.ph-home-btns { display: flex; flex-direction: column; gap: 10px; width: min(360px, 92%); }
.ph-home-row { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; }
.ph-home-row button { background: rgba(255, 255, 255, .8); border-radius: 12px; padding: 10px 14px; font-weight: 700; color: #1c4a22;
  box-shadow: 0 2px 0 rgba(20, 60, 20, .18); }
.ph-big { position: relative; background: linear-gradient(#fffef4, #ffe9a8); color: #4a3608; font-size: 17px; font-weight: 800;
  border-radius: 16px; padding: 14px 18px; box-shadow: 0 4px 0 #c9962f66, 0 6px 14px rgba(20, 60, 20, .18); transition: transform .08s; }
.ph-big:active { transform: scale(.97); }
.ph-big.go { background: linear-gradient(#c8ffb0, #7ec850); color: #143c14; box-shadow: 0 4px 0 #3f7a35aa, 0 6px 14px rgba(20, 60, 20, .2); }
.ph-big .ph-sub { display: block; font-size: 12px; font-weight: 600; opacity: .65; margin-top: 2px; }
.ph-back { background: rgba(255, 255, 255, .75); border-radius: 12px; padding: 10px 20px; font-weight: 700; color: #1c4a22; }
/* sticky action footer — long selection lists (envoy pick, campaign, league,
   moments) hid the Start/Back button below the fold; pin it so it's always
   visible & tappable. Subtle top fade signals there's scrollable content above. */
.ph-actions { position: sticky; bottom: 0; z-index: 3; width: 100%;
  display: flex; gap: 8px; justify-content: center; align-items: center; flex-wrap: wrap;
  margin: 4px 0 -24px; padding: 12px 6px calc(12px + env(safe-area-inset-bottom));
  background: linear-gradient(to top, #d3f0bd 44%, rgba(211, 240, 189, 0));
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px); }
.ph-actions .ph-big.go { animation: ph-cta-pop .5s ease .1s 1 both; }
@keyframes ph-cta-pop { 0% { transform: scale(.9); } 60% { transform: scale(1.04); } 100% { transform: scale(1); } }
@media (prefers-reduced-motion: reduce) { .ph-actions .ph-big.go { animation: none; } }
.ph-esc { color: #1c4a22; opacity: .7; font-size: 13px; text-decoration: none; margin-top: 10px; }
.ph-backlink { position: fixed; top: max(12px, env(safe-area-inset-top)); left: max(12px, env(safe-area-inset-left));
  z-index: 45; color: #1c4a22; font-weight: 700; font-size: 14px; text-decoration: none;
  background: rgba(255, 255, 255, .75); border-radius: 999px; padding: 8px 14px;
  box-shadow: 0 2px 0 rgba(20, 60, 20, .15); }
.ph-backlink:hover { background: #fff; }
.ph-home-nation { display: flex; align-items: center; gap: 8px; color: #1c4a22; font-weight: 700; font-size: 14px; }
.ph-flag { display: inline-block; border-radius: 3px; box-shadow: 0 0 0 1px rgba(0, 0, 0, .15); vertical-align: middle; flex: none; }

/* nations grid */
.ph-nations { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 8px; width: 100%; }
.ph-nation { display: flex; align-items: center; gap: 8px; background: rgba(255, 255, 255, .82); border-radius: 12px;
  padding: 10px; font-weight: 700; font-size: 13px; color: #1c4a22; }
.ph-nation:hover { background: #fff; }

/* campaign grid */
.ph-missions { display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: 10px; width: 100%; }
.ph-mission { position: relative; background: rgba(255, 255, 255, .85); border-radius: 14px; padding: 14px 10px 12px;
  display: flex; flex-direction: column; gap: 5px; align-items: center; color: #1c4a22;
  box-shadow: 0 3px 0 rgba(20, 60, 20, .12); transition: transform .1s; }
.ph-mission:not(.locked):hover { transform: translateY(-2px); background: #fff; }
.ph-mission.locked { opacity: .45; }
.ph-mission-n { position: absolute; top: 8px; left: 10px; font-size: 12px; font-weight: 800; opacity: .5; }
.ph-mission-name { font-weight: 800; font-size: 14px; margin-top: 4px; }
.ph-mission-stars { color: #e8a13c; font-size: 15px; letter-spacing: 2px; }

/* envoy select */
.ph-envoys { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 10px; width: 100%; }
.ph-envoy { text-align: left; background: rgba(255, 255, 255, .85); border-radius: 14px; padding: 12px;
  display: flex; flex-direction: column; gap: 4px; color: #1c4a22; border: 3px solid transparent; }
.ph-envoy.sel { border-color: #42e8f5; background: #fff; box-shadow: 0 0 14px rgba(66, 232, 245, .5); }
.ph-envoy.locked { opacity: .5; }
.ph-envoy-ic { font-size: 30px; }
.ph-envoy-nm { font-weight: 800; font-size: 15px; } .ph-envoy-nm em { font-style: normal; color: #ff8b3d; }
.ph-envoy-ds { font-size: 12px; line-height: 1.4; opacity: .85; }
.ph-envoy-ab { font-size: 11px; line-height: 1.5; opacity: .65; }

/* league */
.ph-league { width: min(560px, 100%); display: flex; flex-direction: column; gap: 4px; }
.ph-lrow { display: flex; align-items: center; gap: 10px; background: rgba(255, 255, 255, .8); border-radius: 10px;
  padding: 7px 12px; font-size: 14px; color: #1c4a22; }
.ph-lrow.you { background: #fff8d0; box-shadow: 0 0 0 2px #e8a13c, 0 0 14px rgba(232, 161, 60, .4); font-weight: 800; }
.ph-lpos { width: 24px; font-weight: 800; opacity: .6; }
.ph-lname { flex: 1; text-align: left; }
.ph-lscore { font-weight: 800; }

/* settings */
.ph-settings { display: flex; flex-direction: column; gap: 10px; width: min(340px, 92%); }
.ph-settings label { display: flex; justify-content: space-between; align-items: center; background: rgba(255, 255, 255, .8);
  border-radius: 12px; padding: 10px 14px; font-weight: 700; color: #1c4a22; }
.ph-tog { background: #d0d8cc; border-radius: 10px; padding: 7px 16px; font-weight: 800; color: #444; min-width: 74px; }
.ph-tog.on { background: linear-gradient(#c8ffb0, #7ec850); color: #143c14; }

/* moments gallery */
.ph-moments { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 12px; width: 100%; }
.ph-moment { background: rgba(255, 255, 255, .88); border-radius: 14px; overflow: hidden; box-shadow: 0 3px 0 rgba(20, 60, 20, .12); }
.ph-moment video { width: 100%; aspect-ratio: 16/10; object-fit: cover; background: #143c14; display: block; }
.ph-moment-meta { padding: 8px 10px 10px; text-align: left; }
.ph-moment-label { font-weight: 800; color: #a8720e; font-size: 14px; }
.ph-moment-date { font-size: 11px; opacity: .6; color: #1c4a22; margin: 2px 0 6px; }
.ph-moment-btns { display: flex; gap: 6px; flex-wrap: wrap; }
.ph-moment-btns button { background: #e8f5dc; border-radius: 8px; padding: 6px 9px; font-size: 12px; font-weight: 700; color: #1c4a22; }
.ph-moment-btns button.danger { background: #ffe0e0; color: #a02020; }
.ph-moments-empty { color: #1c4a22; opacity: .7; padding: 30px 10px; font-size: 15px; grid-column: 1/-1; }

/* calibration */
.ph-cal-status { font-size: 18px; font-weight: 800; color: #1c4a22; min-height: 26px; }

/* end screen */
.ph-end { font-size: 64px; animation: ph-pop .5s cubic-bezier(.2, 2, .4, 1); }
.ph-endstars { display: flex; gap: 10px; font-size: 46px; }
.ph-star { color: #cfd8c8; transform: scale(0); animation: ph-star .5s cubic-bezier(.2, 2.4, .4, 1) forwards; }
.ph-star.lit { color: #e8a13c; text-shadow: 0 0 18px rgba(232, 161, 60, .8); }
@keyframes ph-star { to { transform: scale(1); } }
.ph-endscore { color: #1c4a22; font-size: 17px; }
.ph-rec { color: #a8720e; font-weight: 900; animation: ph-pulse 1s infinite; }

/* ============ HUD ============ */
#phHud { display: none; }
#phHud.show { display: block; }
.ph-top { position: fixed; top: max(8px, env(safe-area-inset-top)); left: max(8px, env(safe-area-inset-left));
  right: max(8px, env(safe-area-inset-right)); z-index: 20; display: flex; gap: 6px; align-items: center; pointer-events: none; }
.ph-stat { background: rgba(12, 34, 16, .72); color: #fff; border-radius: 12px; padding: 7px 11px; font-size: 14px;
  font-weight: 600; backdrop-filter: blur(4px); white-space: nowrap; }
.ph-stat b { font-weight: 900; }
.ph-stat .dim { opacity: .55; font-size: 12px; }
.ph-stat.hearts { color: #ff9db8; } .ph-stat.scrap { color: #ffd54d; } .ph-stat.mult { color: #ffe9a8; animation: ph-pulse 2s infinite; }
.ph-stat.bump { animation: ph-bump .4s; }
@keyframes ph-bump { 30% { transform: scale(1.25); background: rgba(200, 30, 30, .9); } }
@keyframes ph-pulse { 50% { filter: brightness(1.25); } }
.ph-top-sp { flex: 1; }
.ph-ib { pointer-events: auto; background: rgba(12, 34, 16, .72); color: #fff; border-radius: 12px; width: 38px; height: 38px;
  font-size: 17px; backdrop-filter: blur(4px); }
.ph-ib:active { transform: scale(.92); }

#phMini { position: fixed; top: calc(max(8px, env(safe-area-inset-top)) + 46px); right: max(8px, env(safe-area-inset-right));
  width: clamp(110px, 17vw, 170px); aspect-ratio: 5/4; z-index: 19; border-radius: 10px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, .3); }

.ph-wavebar { position: fixed; top: calc(max(8px, env(safe-area-inset-top)) + 46px); left: 50%; transform: translateX(-50%); z-index: 20; }
.ph-call { background: linear-gradient(#fff8d0, #ffd54d); color: #4a3608; font-weight: 800; font-size: 13px;
  border-radius: 999px; padding: 9px 16px; box-shadow: 0 3px 0 #c9962f88, 0 4px 12px rgba(0, 0, 0, .2); animation: ph-pulse 1.6s infinite; }
.ph-call:active { transform: scale(.96); }
/* next-wave composition preview inside the call button */
.ph-call-prev { display: block; font-size: 12px; font-weight: 700; opacity: .85; margin-top: 2px; letter-spacing: .04em; }
.ph-call-prev:empty { display: none; }
/* active power-up buff chips (tucked under the minimap; minimap is 5/4 aspect,
   so its height = width × 0.8 — mirror its clamp scaled by 0.8) */
.ph-buffs { position: fixed; right: max(8px, env(safe-area-inset-right));
  top: calc(max(8px, env(safe-area-inset-top)) + 46px + clamp(88px, 13.6vw, 136px) + 8px);
  z-index: 20; background: rgba(12, 34, 16, .74); color: #ffd54d; font-weight: 800; font-size: 13px;
  border-radius: 999px; padding: 7px 13px; display: none; box-shadow: 0 2px 8px rgba(0, 0, 0, .3); }
/* 2× speed toggle state */
.ph-ib.on { background: #ffd54d; color: #143c14; }

/* recruit bar */
.ph-recruit { position: fixed; bottom: max(10px, env(safe-area-inset-bottom)); left: 50%; transform: translateX(-50%);
  z-index: 20; display: flex; gap: 7px; padding: 6px; background: rgba(12, 34, 16, .6); border-radius: 16px;
  backdrop-filter: blur(5px); max-width: min(96vw, 720px); overflow-x: auto; scrollbar-width: none; }
.ph-recruit::-webkit-scrollbar { display: none; }
.ph-recruit:empty { display: none; }   /* Cottage Nights has no Wardens */
.ph-card { display: flex; flex-direction: column; align-items: center; gap: 1px; background: rgba(255, 255, 255, .92);
  border-radius: 12px; padding: 6px 8px 5px; min-width: 62px; border: 2.5px solid transparent; transition: transform .09s; }
.ph-card:active { transform: scale(.94); }
.ph-card.sel { border-color: #42e8f5; box-shadow: 0 0 12px rgba(66, 232, 245, .8); transform: translateY(-4px); }
.ph-card.poor { opacity: .45; filter: saturate(.4); }
.ph-card-ic { font-size: 22px; }
.ph-card-nm { font-size: 9px; font-weight: 800; color: #1c4a22; max-width: 64px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ph-card-cost { font-size: 10px; font-weight: 800; color: #a8720e; }

/* envoy bar (left bottom) */
.ph-envoybar { position: fixed; left: max(10px, env(safe-area-inset-left)); bottom: max(10px, env(safe-area-inset-bottom));
  z-index: 21; display: flex; align-items: flex-end; gap: 8px; }
.ph-envoy-face { position: relative; width: 52px; height: 52px; border-radius: 50%; background: linear-gradient(#fffef4, #ffe9a8);
  display: flex; align-items: center; justify-content: center; font-size: 28px; box-shadow: 0 0 0 3px #42e8f5, 0 3px 8px rgba(0, 0, 0, .3); }
.ph-elvl { position: absolute; bottom: -4px; right: -4px; background: #42e8f5; color: #06323a; font-size: 11px; font-weight: 900;
  border-radius: 50%; width: 20px; height: 20px; display: flex; align-items: center; justify-content: center; }
.ph-xp { position: absolute; left: 2px; top: -8px; width: 48px; height: 5px; background: rgba(0, 0, 0, .35); border-radius: 3px; overflow: hidden; }
.ph-xp-fill { height: 100%; background: linear-gradient(90deg, #42e8f5, #7af5c8); border-radius: 3px; transition: width .3s; }
.ph-abils { display: flex; gap: 7px; }
.ph-abil { position: relative; width: 46px; height: 46px; border-radius: 13px; background: rgba(12, 34, 16, .78); overflow: hidden;
  box-shadow: 0 2px 6px rgba(0, 0, 0, .3); }
.ph-abil-ic { position: relative; font-size: 20px; z-index: 2; }
.ph-abil-cd { position: absolute; left: 0; bottom: 0; width: 100%; background: rgba(0, 0, 0, .65); z-index: 3; }
.ph-abil-key { position: absolute; top: 1px; right: 4px; font-size: 9px; color: #fff; opacity: .6; z-index: 4; }
.ph-abil-lk { position: absolute; inset: 0; display: none; align-items: center; justify-content: center; font-size: 16px;
  background: rgba(0, 0, 0, .55); z-index: 5; }
.ph-abil.locked .ph-abil-lk { display: flex; }
.ph-abil.ready { box-shadow: 0 0 12px rgba(66, 232, 245, .9), 0 2px 6px rgba(0, 0, 0, .3); }
.ph-abil.spent { opacity: .4; }
.ph-fire { width: 64px; height: 64px; border-radius: 50%; background: radial-gradient(#ff9d5d, #ff5d3d); font-size: 26px;
  box-shadow: 0 0 0 3px rgba(255, 255, 255, .5), 0 4px 12px rgba(0, 0, 0, .35); margin-left: 8px; }
.ph-fire:active { transform: scale(.9); }

/* selected warden panel */
.ph-sel { position: fixed; right: max(8px, env(safe-area-inset-right)); bottom: calc(max(10px, env(safe-area-inset-bottom)) + 84px);
  z-index: 22; width: min(270px, 74vw); background: rgba(255, 255, 255, .95); border-radius: 14px; padding: 10px 12px;
  color: #1c4a22; box-shadow: 0 6px 18px rgba(0, 0, 0, .25); animation: ph-pop .18s cubic-bezier(.2, 1.6, .4, 1); }
@keyframes ph-pop { from { transform: scale(.7); opacity: 0; } }
.ph-sel-hd { display: flex; align-items: center; gap: 6px; font-size: 15px; }
.ph-sel-lv { color: #a8720e; font-weight: 800; font-size: 12px; }
.ph-sel-x { margin-left: auto; background: none; font-size: 15px; opacity: .5; }
.ph-sel-weapon { font-size: 11.5px; opacity: .8; margin: 3px 0; line-height: 1.35; }
.ph-sel-chips { display: flex; gap: 4px; flex-wrap: wrap; margin: 4px 0; }
.ph-chip { font-size: 10px; font-weight: 800; border-radius: 999px; padding: 2px 8px; }
.ph-chip.up { background: #dcf5c8; color: #2c7a1e; } .ph-chip.dn { background: #ffe0e0; color: #a02020; }
.ph-sel-stats { font-size: 12px; font-weight: 700; margin: 4px 0 8px; }
.ph-sel-btns { display: flex; flex-direction: column; gap: 6px; }
.ph-up { background: linear-gradient(#c8ffb0, #7ec850); color: #143c14; font-weight: 800; border-radius: 10px; padding: 9px; font-size: 13px; }
.ph-up:active { transform: scale(.97); }
.ph-branch { display: flex; flex-direction: column; gap: 5px; }
.ph-branch-t { font-size: 11px; font-weight: 800; opacity: .75; }
.ph-sellb { background: #f0ead8; color: #6b5a28; font-weight: 700; border-radius: 10px; padding: 7px; font-size: 12px; }
.ph-sellb .ph-sellval { color: #2e7d32; font-weight: 800; }

/* under fire prompt */
.ph-underfire { position: fixed; left: 50%; top: 34%; transform: translateX(-50%); z-index: 23;
  background: rgba(200, 60, 30, .92); color: #fff; font-weight: 800; font-size: 15px; border-radius: 999px;
  padding: 10px 20px; box-shadow: 0 0 24px rgba(255, 90, 40, .7); animation: ph-pulse .7s infinite; pointer-events: none; }

/* virtual joystick */
.ph-joy { position: fixed; z-index: 24; width: 96px; height: 96px; margin: -48px; border-radius: 50%;
  background: rgba(255, 255, 255, .14); box-shadow: inset 0 0 0 2px rgba(255, 255, 255, .35); pointer-events: none; }
.ph-joy-k { position: absolute; left: 50%; top: 50%; width: 40px; height: 40px; margin: -20px; border-radius: 50%;
  background: rgba(255, 255, 255, .55); }

/* toasts */
#phToasts { position: fixed; left: max(10px, env(safe-area-inset-left)); top: 34%; z-index: 18; display: flex;
  flex-direction: column; gap: 6px; pointer-events: none; max-width: 62vw; }
.ph-toast { display: flex; gap: 7px; align-items: center; background: rgba(12, 34, 16, .78); color: #fff; border-radius: 11px;
  padding: 7px 11px; font-size: 12.5px; font-weight: 600; animation: ph-toast-in .28s cubic-bezier(.2, 1.5, .4, 1); backdrop-filter: blur(4px); }
.ph-toast.out { opacity: 0; transform: translateX(-16px); transition: all .4s; }
@keyframes ph-toast-in { from { opacity: 0; transform: translateX(-24px); } }

/* ============ banners (celebration tiers) ============ */
.ph-banner { position: fixed; left: 50%; top: 26%; transform: translate(-50%, -50%); z-index: 30; text-align: center;
  pointer-events: none; animation: ph-ban-in .35s cubic-bezier(.2, 2, .4, 1); }
.ph-banner.out { opacity: 0; transform: translate(-50%, -80%); transition: all .45s; }
@keyframes ph-ban-in { from { transform: translate(-50%, -50%) scale(.3); opacity: 0; } }
.ph-banner-main { font-weight: 900; letter-spacing: .03em; line-height: 1.1;
  text-shadow: 0 3px 0 rgba(20, 40, 20, .35), 0 6px 22px rgba(0, 0, 0, .35); }
.ph-banner-sub { font-weight: 700; font-size: 15px; color: #fff; opacity: .92; margin-top: 4px; text-shadow: 0 2px 6px rgba(0, 0, 0, .5); }
.ph-banner.t2 .ph-banner-main { font-size: clamp(26px, 6vw, 44px); color: #baf5ff;
  background: linear-gradient(#fff, #7ae0f5); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; }
.ph-banner.t3 .ph-banner-main { font-size: clamp(34px, 8vw, 62px);
  background: linear-gradient(#fff8d0, #ffb84d); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; }
.ph-banner.t4 { animation: ph-ban-in .35s cubic-bezier(.2, 2, .4, 1), ph-legend-sway 2.4s .3s ease-in-out; }
.ph-banner.t4 .ph-banner-main { font-size: clamp(40px, 10vw, 84px);
  background: linear-gradient(180deg, #fffbe0 10%, #ffd54d 45%, #ff9d2e 80%); -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; filter: drop-shadow(0 0 22px rgba(255, 200, 60, .95)); }
@keyframes ph-legend-sway { 50% { transform: translate(-50%, -50%) scale(1.05) rotate(.6deg); } }

/* ============ Lanternfall-merge HUD ============ */
.ph-big.flag { background: linear-gradient(#fff8d0, #ffd54d); box-shadow: 0 4px 0 #c9962faa, 0 0 22px rgba(255, 213, 77, .5); }
.ph-flagchip { position: absolute; top: -9px; right: 10px; background: #143c14; color: #ffd54d; font-size: 10px;
  font-weight: 900; letter-spacing: .06em; border-radius: 999px; padding: 3px 9px; }
.ph-vitals { position: fixed; left: 50%; transform: translateX(-50%); z-index: 21;
  bottom: calc(max(10px, env(safe-area-inset-bottom)) + 74px);
  display: flex; flex-direction: column; align-items: center; gap: 4px; pointer-events: none; }
.ph-hpbar { width: min(300px, 56vw); height: 9px; background: rgba(12, 34, 16, .6); border-radius: 6px; overflow: hidden;
  box-shadow: 0 1px 4px rgba(0,0,0,.3); }
.ph-hpbar { position: relative; }
.ph-hp-fill { position: absolute; inset: 0 auto 0 0; height: 100%; border-radius: 6px;
  background: linear-gradient(90deg, #8bd45e, #7af5c8); transition: width .2s; }

/* GHOST — the health you just lost, left behind and then draining. It is what makes
   a hit legible: the bar alone only tells you where you ARE, never what just
   happened. Slow transition on purpose, so the eye catches the gap. */
.ph-hp-ghost { position: absolute; inset: 0 auto 0 0; height: 100%; border-radius: 6px;
  /* ⚠⚠ THE SAME TRANSITION AS THE FILL, and it must match. With no transition here
     the ghost tracked health instantly while the fill eased over .2 s, so during
     REGEN the ghost ran ahead of the fill and painted a red sliver on its leading
     edge — damage colour at the exact moment the player is recovering, which is the
     opposite of the thing being communicated. The drain's SHAPE is still the JS
     easing; this only keeps the two layers in step. */
  background: rgba(255, 120, 120, .55); transition: width .2s; }

/* CHARGE — the out-of-combat wait. It grows along the bar's remaining space while
   you are still "in combat", so reaching the end IS regen starting. A countdown you
   can read without a number. */
.ph-hp-charge { position: absolute; top: 0; bottom: 0; border-radius: 6px; width: 0;
  background: linear-gradient(90deg, rgba(122,245,200,0), rgba(122,245,200,.5));
  transition: width .1s linear; }

/* REGEN — the fill itself moves while health is coming back. Static green says
   "you are hurt"; moving green says "you are healing", and that is the difference
   between a player waiting and a player retreating. */
.ph-hpbar.regen .ph-hp-fill { background-size: 200% 100%;
  background-image: linear-gradient(90deg, #8bd45e, #7af5c8, #baffe6, #7af5c8, #8bd45e);
  animation: ph-regen-sheen 1.1s linear infinite; }
@keyframes ph-regen-sheen { from { background-position: 100% 0; } to { background-position: -100% 0; } }
.ph-hpbar.hurt { box-shadow: 0 0 0 1.5px rgba(255,120,120,.85), 0 1px 4px rgba(0,0,0,.3); }

/* DANGER VIGNETTE — the actual "you are about to go down" signal, and the one thing
   a 9 px bar at the bottom of the screen cannot say. Scales with how hurt you are;
   flashes on each hit. pointer-events none so it never eats a tap. */
.ph-hurt { position: fixed; inset: 0; z-index: 19; pointer-events: none; opacity: 0;
  transition: opacity .35s ease-out;
  box-shadow: inset 0 0 min(22vh, 190px) min(4vh, 34px) rgba(190, 20, 20, .78); }
.ph-hurt.flash { opacity: 1 !important; transition: opacity .06s; }
@media (prefers-reduced-motion: reduce) {
  .ph-hpbar.regen .ph-hp-fill { animation: none; }
  .ph-hurt { transition: none; }
}
.ph-ammo { background: rgba(12, 34, 16, .72); color: #fff; border-radius: 10px; padding: 4px 12px; font-size: 13px;
  font-weight: 700; backdrop-filter: blur(4px); }
.ph-ammo b { color: #ffd54d; margin-right: 4px; }
.ph-ammo.low { animation: ph-pulse .5s infinite; color: #ff9d9d; }
.ph-bombs { font-size: 13px; letter-spacing: 2px; filter: drop-shadow(0 1px 2px rgba(0,0,0,.5)); min-height: 16px; }
.ph-lamp { position: fixed; right: max(12px, env(safe-area-inset-right)); z-index: 22;
  bottom: calc(max(10px, env(safe-area-inset-bottom)) + 224px);
  width: 52px; height: 52px; border-radius: 50%; font-size: 24px; background: rgba(12, 34, 16, .78);
  box-shadow: 0 2px 8px rgba(0,0,0,.35); }
.ph-lamp.on { background: radial-gradient(#fff2c8, #ffd54d); box-shadow: 0 0 22px rgba(255, 216, 138, .95), 0 2px 8px rgba(0,0,0,.3); }
.ph-wbtns { position: fixed; right: max(12px, env(safe-area-inset-right)); z-index: 22;
  bottom: calc(max(10px, env(safe-area-inset-bottom)) + 290px); display: flex; flex-direction: column; gap: 8px; }
.ph-wb { width: 46px; height: 46px; border-radius: 50%; font-size: 19px; color: #fff;
  background: rgba(12, 34, 16, .78); box-shadow: 0 2px 8px rgba(0,0,0,.35); }
.ph-wb:active { transform: scale(.9); }
.ph-interact { position: fixed; left: 50%; transform: translateX(-50%); top: 56%; z-index: 23;
  background: linear-gradient(#fffef4, #ffe9a8); color: #4a3608; font-weight: 800; font-size: 14px;
  border-radius: 999px; padding: 11px 20px; box-shadow: 0 4px 0 #c9962f66, 0 4px 14px rgba(0,0,0,.3);
  animation: ph-pulse 1.6s infinite; }
.ph-interact:active { transform: translateX(-50%) scale(.96); }
.ph-downed { position: fixed; left: 50%; top: 40%; transform: translate(-50%, -50%); z-index: 26; text-align: center;
  background: rgba(60, 8, 8, .85); color: #ffd0d0; border-radius: 18px; padding: 16px 30px; font-size: 18px;
  box-shadow: 0 0 40px rgba(255, 60, 60, .5); pointer-events: none; }
.ph-downed b { display: block; font-size: 24px; margin-bottom: 4px; }
.ph-downed span { font-size: 30px; font-weight: 900; color: #fff; }
@media (max-width: 760px) {
  .ph-vitals { bottom: calc(max(10px, env(safe-area-inset-bottom)) + 140px); }
  .ph-lamp { bottom: calc(max(10px, env(safe-area-inset-bottom)) + 210px); width: 46px; height: 46px; }
  .ph-wbtns { bottom: calc(max(10px, env(safe-area-inset-bottom)) + 268px); }
}

/* GPS status chip (top-centre, under the wave banner). Status ONLY — the
   rotate/flip align controls are setup, and live on the pause overlay. */
.ph-gps { position: fixed; left: 50%; transform: translateX(-50%); z-index: 21;
  top: calc(max(8px, env(safe-area-inset-top)) + 92px);
  display: flex; align-items: center; gap: 8px; background: rgba(12, 34, 16, .74);
  border-radius: 14px; padding: 6px 12px; backdrop-filter: blur(4px); box-shadow: 0 2px 10px rgba(0,0,0,.3); }
.ph-gps-lbl { color: #fff; font-size: 13px; font-weight: 700; }
.ph-gps-btn { background: rgba(255,255,255,.14); color: #ffd54d; border-radius: 9px; padding: 5px 9px; font-size: 12px; font-weight: 700; }
.ph-gps-btn:active { transform: scale(.94); }
/* map-alignment row on the pause overlay (Outdoors runs only) */
.ph-align { margin-top: 14px; padding-top: 12px; border-top: 1px solid rgba(255,255,255,.12); }
.ph-align-h { color: rgba(255,255,255,.72); font-size: 12px; font-weight: 700; margin-bottom: 7px; letter-spacing: .02em; }
.ph-align-btns { display: flex; gap: 8px; justify-content: center; }
/* ?gpsdebug=1 field-diagnosis readout */
#phGpsDbg { position: fixed; left: 8px; bottom: max(8px, env(safe-area-inset-bottom)); z-index: 60;
  background: rgba(0, 0, 0, .72); color: #7af5c8; font: 11px/1.5 ui-monospace, Menlo, monospace;
  padding: 5px 9px; border-radius: 8px; pointer-events: none; max-width: 96vw; }

/* legendary recording chip */
#phRec { position: fixed; left: 50%; transform: translateX(-50%); z-index: 31; pointer-events: none;
  top: calc(max(8px, env(safe-area-inset-top)) + 52px);
  display: flex; align-items: center; gap: 7px; background: rgba(20, 14, 2, .78); color: #ffd54d;
  font-weight: 900; font-size: 12.5px; letter-spacing: .08em; border-radius: 999px; padding: 7px 14px;
  box-shadow: 0 0 16px rgba(255, 213, 77, .45); backdrop-filter: blur(4px); }
.ph-rec-dot { width: 9px; height: 9px; border-radius: 50%; background: #ff4d4d; animation: ph-pulse .9s infinite; }

/* full-screen washes */
.ph-gold { position: fixed; inset: 0; z-index: 28; pointer-events: none;
  background: radial-gradient(ellipse at 50% 38%, rgba(255, 214, 80, .5), rgba(255, 160, 40, .16) 55%, transparent 75%);
  animation: ph-gold 2.6s ease-out forwards; }
@keyframes ph-gold { 0% { opacity: 0; } 12% { opacity: 1; } 100% { opacity: 0; } }
.ph-redflash { position: fixed; inset: 0; z-index: 28; pointer-events: none; background: rgba(255, 40, 40, .28); animation: ph-red .4s forwards; }
@keyframes ph-red { to { opacity: 0; } }

/* ============ hint spotlight ============ */
#phHint { display: none; position: fixed; inset: 0; z-index: 34; pointer-events: none; }
#phHint.show { display: block; }
.ph-hint-ring { position: absolute; width: 74px; height: 74px; margin: -37px; border-radius: 50%;
  border: 3px solid #ffd54d; box-shadow: 0 0 0 4000px rgba(0, 20, 6, .28), 0 0 26px rgba(255, 213, 77, .9);
  animation: ph-hintring 1.3s infinite; }
@keyframes ph-hintring { 50% { transform: scale(1.18); border-color: #fff; } }
.ph-hint-card { position: absolute; max-width: min(320px, 80vw); background: #fffef4; color: #4a3608; border-radius: 14px;
  padding: 10px 14px; font-size: 13.5px; font-weight: 700; line-height: 1.45; box-shadow: 0 8px 24px rgba(0, 0, 0, .35);
  display: flex; gap: 8px; align-items: flex-start; animation: ph-pop .3s cubic-bezier(.2, 1.6, .4, 1); }
.ph-hint-paw { font-size: 18px; }

@media (max-width: 760px) {
  .ph-stat { font-size: 12px; padding: 6px 8px; }
  .ph-stat.score { display: none; }
  .ph-card { min-width: 54px; }
  /* stack: abilities row ABOVE the recruit bar so nothing overlaps */
  .ph-envoybar { bottom: calc(max(10px, env(safe-area-inset-bottom)) + 78px); }
  .ph-recruit { left: 8px; right: 8px; transform: none; max-width: none; }
  .ph-envoy-face { width: 44px; height: 44px; font-size: 23px; }
  .ph-xp { width: 40px; }
  .ph-abil { width: 42px; height: 42px; }
  .ph-fire { width: 56px; height: 56px; position: fixed; right: max(12px, env(safe-area-inset-right));
    bottom: calc(max(10px, env(safe-area-inset-bottom)) + 150px); margin: 0; }
  .ph-sel { bottom: calc(max(10px, env(safe-area-inset-bottom)) + 140px); }
  #phMini { width: 96px; }
}

/* ============ UNIT GALLERY (js/gallery.js) ============
   Full-screen inspector for every unit/level/state. Opens at SHIP SIZE on
   purpose — a Rustbug is 10 px tall in play, and judging models at inspect
   distance is how you pay for detail nobody sees. */
#phGal { position: fixed; inset: 0; z-index: 90; background: #8fd4ef; }
#phGalCv { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.pg-top { position: absolute; top: max(8px, env(safe-area-inset-top)); left: 8px; right: 8px;
  display: flex; align-items: center; gap: 10px; }
.pg-name { flex: 1; display: flex; flex-direction: column; line-height: 1.2;
  background: rgba(8, 26, 12, .62); border-radius: 12px; padding: 6px 12px; backdrop-filter: blur(4px); }
.pg-name b { color: #fff; font-size: 15px; }
.pg-name span { color: rgba(255,255,255,.7); font-size: 11px; }
.pg-meas { color: #fff; font: 11px/1.4 ui-monospace, Menlo, monospace;
  background: rgba(8, 26, 12, .62); border-radius: 10px; padding: 6px 10px; text-align: right; }
.pg-meas b { color: #ffd54d; }
.pg-left { position: absolute; left: 8px; top: 50%; transform: translateY(-50%);
  display: flex; flex-direction: column; align-items: center; gap: 8px; }
.pg-left span { color: #fff; font: 11px ui-monospace, Menlo, monospace; text-shadow: 0 1px 3px rgba(0,0,0,.6); }
.pg-bottom { position: absolute; left: 8px; right: 8px; bottom: max(8px, env(safe-area-inset-bottom));
  display: flex; flex-direction: column; gap: 6px; }
.pg-row { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; align-items: center; }
.pg-btn { background: rgba(8, 26, 12, .68); color: #fff; border: 0; border-radius: 10px;
  padding: 7px 11px; font-size: 12px; font-weight: 700; cursor: pointer; backdrop-filter: blur(4px); }
.pg-btn:active { transform: scale(.94); }
.pg-btn.on { background: #ffd54d; color: #16341c; }
.pg-frame { color: #fff; font: 11px ui-monospace, Menlo, monospace; min-width: 34px;
  background: rgba(8,26,12,.68); border-radius: 8px; padding: 5px 7px; text-align: center; }
#pgScrub { flex: 1; min-width: 120px; max-width: 420px; accent-color: #ffd54d; }

/* ---- map view: the minimap, full screen ----
   No third widget and no map tiles (LICENSING.md). On a phone in portrait there
   is no room for a split view, so opening the map hides the rest of the HUD —
   half a map is not a map. The game keeps running behind it. */
.ph-mapbtn { position: fixed; z-index: 20; border-radius: 10px; padding: 6px 9px; font-size: 15px;
  background: rgba(12, 34, 16, .74); color: #fff; backdrop-filter: blur(4px);
  top: calc(max(8px, env(safe-area-inset-top)) + 46px); right: max(8px, env(safe-area-inset-right));
  transform: translateY(-2px) translateX(-2px); }
.ph-mapbtn:active { transform: scale(.92) translateY(-2px) translateX(-2px); }
/* ⚠ A <canvas> is a REPLACED element: with `width:auto` it takes its BITMAP size
   as its intrinsic width, and left/right insets cannot stretch it (CSS 2.1
   §10.3.8). The first version did exactly that and "full screen" came out at
   192x154 — the bitmap. Size it explicitly. */
#phHud.mapopen #phMini { top: max(8px, env(safe-area-inset-top)); left: max(8px, env(safe-area-inset-left));
  right: auto; bottom: auto;
  width: calc(100vw - max(8px, env(safe-area-inset-left)) - max(8px, env(safe-area-inset-right)));
  height: calc(100dvh - max(8px, env(safe-area-inset-top)) - max(8px, env(safe-area-inset-bottom)));
  aspect-ratio: auto; z-index: 46; border-radius: 14px;
  box-shadow: 0 8px 40px rgba(0, 0, 0, .5); }
#phHud.mapopen .ph-mapbtn { z-index: 47; top: calc(max(8px, env(safe-area-inset-top)) + 10px);
  right: calc(max(8px, env(safe-area-inset-right)) + 10px); font-size: 17px; }
/* everything else steps aside while the map is open */
/* ⚠ #phBase must be excluded — it is a HUD child, and hiding it here made the
   basemap invisible while every diagnostic said it was loading and rendering
   fine. What showed through was the 3D game world, not the map. */
#phHud.mapopen > *:not(#phMini):not(.ph-mapbtn):not(#phToasts):not(#phBase) { opacity: 0; pointer-events: none; }

/* real-world basemap: sits BEHIND the expanded minimap canvas (js/basemap.js).
   Hidden and zero-size unless the map view is open, so it costs nothing. */
#phBase { display: none; }
#phBase.show { display: block; position: fixed; z-index: 45; border-radius: 14px; overflow: hidden;
  top: max(8px, env(safe-area-inset-top)); left: max(8px, env(safe-area-inset-left));
  width: calc(100vw - max(8px, env(safe-area-inset-left)) - max(8px, env(safe-area-inset-right)));
  height: calc(100dvh - max(8px, env(safe-area-inset-top)) - max(8px, env(safe-area-inset-bottom)));
  background: #0d1f12; }
#phBase .ph-basemap { position: absolute; inset: 0; }
/* the map is a backdrop — never let it eat a tap meant for the game */
#phBase, #phBase * { pointer-events: none !important; }

/* opt-in card (Outdoors flow). Deliberately wordy: it is the one setting that
   sends anything about the player's location off the device. */
.ph-optin { width: min(360px, 92%); margin-top: 4px; }
.ph-optin button { width: 100%; text-align: left; background: rgba(255,255,255,.8);
  border-radius: 14px; padding: 11px 13px; display: flex; flex-direction: column; gap: 3px;
  box-shadow: 0 2px 0 rgba(20,60,20,.15); }
.ph-optin button.on { background: linear-gradient(#e8ffd8, #c8f0a8); }
.ph-optin b { color: #1c4a22; font-size: 14px; }
.ph-optin span { color: #23531f; font-size: 11.5px; line-height: 1.45; opacity: .8; }
.ph-optin em { font-style: normal; font-size: 11px; font-weight: 800; color: #2c7a1e; margin-top: 2px; }

/* the calibration result, shown on the screen the player lands on. It used to go
   through juice.js toast(), which no-ops unless #phToasts exists — and that only
   exists once the in-game HUD is built, so on the menu it was silent. */
.ph-calnote { border-left: 3px solid var(--ph-cy, #42e8f5); padding-left: .7em; text-align: left; }
.ph-calnote.warn { border-left-color: #ffc93c; }
