/* ==========================================================================
   Banner Guesser — per-game styles
   --------------------------------------------------------------------------
   Everything fits in one screen height, no scrolling: a compact card (sigil
   + round info + guess controls) anchored to one side, and the map as a
   small floating widget that expands on hover — or, on a touch screen, on
   tap — the same trick GeoGuessr and TimeGuessr use so the map doesn't have
   to permanently occupy half the screen.

   The map itself is a single large image, not real-world tiles — it runs on
   Leaflet's L.CRS.Simple (see game.js). Builds on tokens.css, app.css and
   game.css.
   ========================================================================== */

/* This page's <main> carries this alongside `.game-main` so its own
   top/bottom padding can be zeroed — the board is sized to the exact space
   under the header, and padding here would push it into needing a
   scrollbar. The loading and results screens still carry their own vertical
   padding (from `.loading` / `.results` in game.css). */
.banner-main { padding-block: 0; }

.banner-board {
  position: relative;
  height: calc(100dvh - 63px - env(safe-area-inset-top, 0px));
  padding: clamp(14px, 3vh, 28px);
}
@supports not (height: 100dvh) {
  .banner-board { height: calc(100vh - 63px); }
}

/* --- The sigil + round info card -------------------------------------------
   Centred rather than left-anchored — with the map living independently in
   its own bottom-right corner, centring this leaves the left margin clear
   for an ad rail on wide screens (see #ad-rails) instead of it sitting
   under a card pinned to that edge. Still sized to what it actually needs
   to show rather than a full column — bigger than before, but the sigil
   is still an emblem on a card, not the star of the page the way a photo
   is in TimeGuessr. */
.banner-main-content {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  z-index: 10;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(12px, 2.2vh, 20px);
  width: min(360px, 84vw);
}

/* Wraps the well and the name/words prompt below it with their own tight
   gap, so that pair reads as one unit and .banner-main-content's larger
   gap stays reserved for the space before .banner-hints — adding the
   prompt shouldn't grow the card's overall height by a full extra gap on
   top of what it actually needs. */
.sigil-block {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
}
.sigil-well {
  width: min(230px, 27vw, 32vh);
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  padding: clamp(12px, 2vw, 20px);
  border-radius: var(--r-lg);
  border: 1px solid var(--line);
  background: var(--surface-sunk);
  box-shadow: var(--shadow);
}
.sigil-img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  opacity: 0;
  transition: opacity 240ms var(--ease);
}
.sigil-img.is-ready { opacity: 1; }

/* --- Name + words prompt -----------------------------------------------------
   Shown for the whole round, not just after guessing — a standing hint
   rather than something revealed. Kept plain (no card chrome of its own) so
   it doesn't visually compete with .reveal-card once that appears below. */
.sigil-prompt {
  display: grid;
  gap: 2px;
  text-align: center;
  max-width: min(280px, 84vw);
}
.sigil-prompt__name {
  font-family: "Cinzel", var(--font-display), serif;
  font-weight: 700;
  font-size: 1rem;
  margin: 0;
  text-wrap: balance;
}
.sigil-prompt__words {
  margin: 0;
  font-style: italic;
  color: var(--ink-muted);
  font-size: 0.82rem;
}

.banner-hints {
  width: 100%;
  display: grid;
  gap: 12px;
  padding: 14px 16px;
  border-radius: var(--r-lg);
  border: 1px solid var(--line);
  background: var(--surface);
  box-shadow: var(--shadow);
}
/* Stacked, not side by side — "House 1 of 7" plus seven round-dots already
   wants most of the card's width on its own; squeezing the score in next
   to it on the same line was what caused the label to wrap mid-phrase and
   overlap the card below it. */
.hints-top {
  display: grid;
  gap: 6px;
}
.roundline { font-size: 0.82rem; }

/* --- Score line ------------------------------------------------------------ */
.banner-score { font-size: 0.86rem; color: var(--ink-2); }
.banner-score b {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.05rem;
  color: var(--ink);
  display: inline-block;
  font-variant-numeric: tabular-nums;
}
.banner-score__outof { color: var(--ink-muted); }

/* --- Guess controls ---------------------------------------------------------
   Reuses the dashed "earned hint" look from game.css's .stage-note, since a
   guess that hasn't been placed yet is the same kind of pending-state box. */
.guess-status {
  display: grid;
  gap: 10px;
  padding: 12px 14px;
  border: 1px dashed color-mix(in srgb, var(--pending) 45%, transparent);
  border-radius: var(--r-md);
  background: color-mix(in srgb, var(--pending) 8%, transparent);
}
.guess-status[data-armed="true"] {
  border-color: color-mix(in srgb, var(--accent) 50%, transparent);
  background: var(--accent-soft);
}
#guess-hint { margin: 0; }

/* --- Reveal card -------------------------------------------------------------
   Sits in the same slot the guess controls just vacated, so resolving a
   round doesn't reflow the card around it. */
.reveal-card { display: grid; gap: 4px; }
.reveal-card__verdict {
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin: 0 0 2px;
  min-height: 1em; /* holds its line's height while empty, so nothing shifts when the label fades in */
  opacity: 0;
  transition: opacity 320ms var(--ease);
}
.reveal-card__verdict.is-in { opacity: 1; }
.reveal-card__verdict[data-tier="great"] { color: var(--accent); }
.reveal-card__name {
  font-family: "Cinzel", var(--font-display), serif;
  font-weight: 700;
  font-size: 1.08rem;
  margin: 0;
  text-wrap: balance;
}
.reveal-card__meta { margin: 0; color: var(--ink-2); font-size: 0.84rem; }
.reveal-card__words {
  margin: 4px 0 0;
  font-style: italic;
  color: var(--ink-muted);
  font-size: 0.84rem;
}
.reveal-card__points {
  display: flex;
  align-items: baseline;
  gap: 7px;
  margin: 8px 0 10px;
  font-family: var(--font-display);
}
.reveal-card__points b {
  font-weight: 800;
  font-size: 1.5rem;
  color: var(--accent);
  display: inline-block;
  font-variant-numeric: tabular-nums;
}
#reveal-points.is-landed, #running-score.is-landed { animation: score-pop 460ms var(--ease); }
.reveal-card__points span { font-size: 0.78rem; color: var(--ink-muted); }

/* --- The map widget -----------------------------------------------------------
   Small and corner-anchored by default; growing it is purely a CSS size
   transition, so it never reflows the rest of the page — game.js just has
   to keep telling Leaflet its container changed (see the ResizeObserver in
   initMap()). */
.map-widget {
  position: absolute;
  right: clamp(14px, 3vw, 28px);
  bottom: clamp(14px, 3vh, 28px);
  z-index: 20;
  width: min(340px, 42vw);
  height: min(240px, 34vh);
  overflow: hidden;
  border-radius: var(--r-lg);
  border: 2px solid var(--line-hi);
  background: rgb(99, 155, 190); /* matches the image's own sea colour, showing while it loads */
  box-shadow: var(--shadow-hi);
  cursor: pointer;
  transition: width 260ms var(--ease), height 260ms var(--ease), border-color 260ms var(--ease);
}
.map-widget.is-expanded {
  /* Width is deliberately NOT set here — it's derived from the height below
     via aspect-ratio, matched exactly to the source image's own 3375:4830
     proportions. That was the actual cause of the "lots of blank space"
     look: a landscape-ish box (roughly square, or wider than tall) around
     a map that's tall and narrow always left the sides letterboxed, no
     matter how the zoom was tuned. A box shaped like the map has nothing
     left over to be blank. */
  width: auto;
  aspect-ratio: 3375 / 4830;
  height: min(88vh, 940px);
  max-width: 92vw;
  border-color: var(--accent-line);
  cursor: default;
}

/* Used for an instant (see setMapExpanded() in game.js) to jump the widget
   straight to its target size and back, with no animation, so the map can
   be measured and fitted against the real destination size before the
   actual, visible open/close transition plays. `!important` because it
   has to beat the transition rule above regardless of which selector this
   ends up combined with (e.g. `.map-widget.is-expanded.no-transition`,
   where both rules match the same specificity and source order alone
   would otherwise decide the winner). */
.map-widget.no-transition { transition: none !important; }

/* `z-index: 1` looks redundant on an element with nothing else to stack
   against, but it isn't: Leaflet's own panes (tiles, markers, popups)
   carry z-indexes of their own (200-700+) that mean nothing until
   something gives this element a z-index too — only then do they
   actually get contained inside it as one unit, instead of leaking out
   to compete directly with sibling elements outside the map entirely.
   Without this, once the map image grew to fill the widget right up to
   its corners, its internal tile layer started winning that fight
   against .map-toolbar's z-index: 5 and rendering above it, hiding the
   legend and recentre button behind the map. */
.map-stage { position: absolute; inset: 0; z-index: 1; }

.map-toolbar {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 5;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 6px 7px 6px 12px;
  border-radius: var(--r-pill);
  border: 1px solid var(--line);
  background: color-mix(in srgb, var(--surface) 85%, transparent);
  backdrop-filter: blur(10px);
  box-shadow: var(--shadow);
  font-size: 0.74rem;
  color: var(--ink-2);
}
.map-legend { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
.map-legend__dot {
  width: 9px; height: 9px;
  border-radius: 50%;
  display: inline-block;
  box-shadow: 0 0 0 1px rgba(0,0,0,.35);
}
.map-legend__dot--guess  { background: var(--accent); }
.map-legend__dot--answer { background: var(--pending); }
.icon-btn--sm { width: 28px; height: 28px; }

/* The legend and even the toolbar are wasted on the collapsed, small map —
   there's no room to read them and nothing to click precisely yet. They
   fade in once the widget opens up. */
.map-widget:not(.is-expanded) .map-toolbar { opacity: 0; pointer-events: none; }
.map-toolbar { transition: opacity 180ms var(--ease); }
@media (max-width: 559.98px) {
  .map-legend { display: none; }
}

/* The map's own Lock in / Continue button — phone only, see below. */
.map-action { display: none; }

/* --- Phone layout -------------------------------------------------------------
   The card sits in a normal top-to-bottom flow and the map stays a small
   thumbnail in the bottom-right corner, like City Guesser's. Opened, it grows
   up and left from that corner to the largest map-shaped box the screen
   allows. That box covers the card, so the map carries its own green button:
   "Lock in guess" once a pin is down, then "Continue", which closes the map
   again to show the round's score.

   Both sizes are explicit width + height in the map's 3375:4830 proportions
   (not aspect-ratio with one side auto), so the open/close transition
   animates both sides and the box never ends up a different shape from the
   map inside it. */
@media (max-width: 699.98px) {
  .banner-board {
    --map-ratio: 1.4311; /* 4830 / 3375 */
    --map-inset: 8px;
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 12px 12px 0;
  }
  .banner-main-content {
    position: static;
    transform: none;
    width: min(360px, 100%);
    gap: 12px;
  }
  .sigil-well { width: min(150px, 38vw, 20vh); padding: 12px; }
  .banner-hints { padding: 12px 14px; gap: 10px; }
  /* --board-h mirrors .banner-board's own height rule above. */
  .map-widget,
  .map-widget.is-expanded {
    --board-h: calc(100dvh - 63px - env(safe-area-inset-top, 0px));
    --map-w: min(132px, 34vw);
    left: auto;
    right: var(--map-inset);
    bottom: var(--map-inset);
    width: var(--map-w);
    height: calc(var(--map-w) * var(--map-ratio));
    max-width: none;
    aspect-ratio: auto;
    margin: 0;
  }
  .map-widget.is-expanded {
    --map-w: min(100vw - 2 * var(--map-inset), (var(--board-h) - 2 * var(--map-inset)) / var(--map-ratio));
  }
  .map-widget.is-expanded .map-action:not([hidden]) {
    display: inline-flex;
    position: absolute;
    left: 50%;
    bottom: 12px;
    z-index: 5;
    transform: translateX(-50%);
    min-width: 168px;
    justify-content: center;
    box-shadow: var(--shadow-hi);
  }
  /* The points toast would otherwise land right on top of that button. */
  .toast { bottom: calc(84px + env(safe-area-inset-bottom, 0px)); }
}
/* Short phones (iPhone SE and the like): the round's score card would run
   under the corner map, so the sigil moves beside the name instead of above
   it. */
@media (max-width: 699.98px) and (max-height: 760px) {
  .banner-board { padding-top: 8px; }
  .banner-main-content { gap: 8px; }
  .sigil-block { flex-direction: row; gap: 12px; }
  .sigil-well { width: 72px; padding: 8px; }
  .sigil-prompt { text-align: left; }
  .banner-hints { gap: 8px; padding: 10px 12px; }
  .reveal-card__points { margin: 4px 0 6px; }
}

/* --- Leaflet overrides --------------------------------------------------------
   Leaflet ships its own light-chrome control styling; this reskins it to sit
   inside the site's dark surface instead of a stray white box. */
.map-stage .leaflet-container {
  /* Leaflet sets its own inline-ish default (#ddd) with enough specificity
     to otherwise win over this rule, which is what showed as flat grey
     rather than the intended sea-blue in the empty space beyond the map
     image's edges. */
  background: rgb(99, 155, 190) !important;
  font-family: var(--font-ui);
}
.map-stage .leaflet-control-zoom a {
  background: var(--surface);
  color: var(--ink);
  border-color: var(--line-hi) !important;
}
.map-stage .leaflet-control-zoom a:hover { background: var(--surface-hi); }
/* Too fiddly to hit at the widget's collapsed size, and it fades the
   toolbar out for the same reason — see above. */
.map-widget:not(.is-expanded) .leaflet-control-zoom { display: none; }

/* Guess / answer pins. Leaflet divIcon wrappers — see game.js's pinIcon(). */
.pin-marker {
  position: relative;
  width: 22px; height: 22px;
  border-radius: 50% 50% 50% 0;
  transform: rotate(-45deg);
  box-shadow: 0 1px 3px rgba(0,0,0,.5);
  border: 2px solid rgba(0,0,0,.35);
}
.pin-marker--guess  { background: var(--accent); }
.pin-marker--answer { background: var(--pending); }
.pin-marker__dot {
  position: absolute;
  inset: 5px;
  border-radius: 50%;
  background: rgba(0,0,0,.35);
  transform: rotate(45deg);
}

/* Badge showing the revealed seat's type (castle/city/high lord's seat) —
   see seatTypeIcon() in game.js. Anchored to sit just below the answer
   pin's own point rather than overlapping it. */
.seat-type-marker {
  width: 20px; height: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--surface);
  border: 1.5px solid var(--line-hi);
  border-radius: 50%;
  box-shadow: 0 1px 3px rgba(0,0,0,.45);
  color: var(--ink);
}
.seat-type-marker svg {
  width: 12px;
  height: 12px;
}

.pin-line {
  stroke: var(--ink);
  stroke-opacity: 0.6;
  stroke-dasharray: 6 6;
}
