/* ==========================================================================
   Blue Marble — "First Light" chrome skeleton (W2 Task 1)
   Flag: web_first_light (apps/globe/views.py::_globe_web_flags).
   Mode dock (#bm-dock) · omni-search (#bm-omni) · instrument rail
   (#bm-rail) · content chips (#bm-chips) — dark glass overlay chrome for
   the customer globe. See docs/superpowers/mockups/
   2026-07-06-globe-web-blue-marble/01-first-light.html.

   Tokens + LOGICAL properties only (inset-inline-*, inset-block-*,
   margin-block-*, etc.) — no bare left:/right:/top:/bottom:. A later
   task's CSS gate greps this file for physical-property violations.
   (Note: never let an asterisk and a slash land back-to-back in this
   comment's prose -- that two-character sequence closes a CSS comment
   early per spec, same as it would in a real browser. An earlier draft of
   this very paragraph did exactly that by writing two logical-property
   wildcards separated only by a slash; Task 11's check_logical_css.sh
   comment-stripper caught it. Use a comma or "and" between wildcards, not
   a slash, and always leave a space before any trailing slash near a
   "*"-suffixed word.)
   ========================================================================== */

/* ── Night-flight surface tokens (dark glass panels) ────────────────────
   design-tokens.css's light-surface text tokens (e.g. --ag-color-text-muted
   = #6B7491) fail WCAG AA against these dark panels, so First Light chrome
   gets its own small token set, scoped to .bm-first-light, defined ONCE
   here for every W2 task to reuse instead of redefining its own. */
.bm-first-light {
  --bm-panel: rgba(14, 22, 46, 0.86);
  --bm-line: rgba(120, 150, 205, 0.22);
  --bm-line-soft: rgba(120, 150, 205, 0.13);
  --bm-text: #EAF0FB;
  --bm-dim: #9DAECC;
  --bm-faint: #6E7FA3;
}

/* ── Retire legacy chrome under the flag ─────────────────────────────────
   Advanced Tools (#ag-dir) is no longer default-open — Trip mode re-shows
   it (Task 2). The FAB stack / near-me chip / commerce date bar are
   superseded by the dock + omni + chips below. */
.bm-first-light #ag-dir { display: none; }
.bm-first-light #ag-map-fabs,
.bm-first-light #ag-nearme,
.bm-first-light #ag-date-bar { display: none; }

@media (prefers-reduced-motion: reduce) {
  .bm-first-light * {
    animation: none !important;
    transition: none !important;
  }
}

/* ── Shared glass panel recipe ────────────────────────────────────────── */
.bm-glass {
  background: var(--bm-panel);
  border: 1px solid var(--bm-line);
  border-radius: var(--ag-radius-3xl);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  box-shadow: var(--ag-shadow-2xl);
}

/* ==========================================================================
   1. Mode dock — #bm-dock
   ========================================================================== */
#bm-dock {
  position: absolute;
  inset-block-start: 50%;
  inset-inline-start: var(--ag-space-4);
  translate: 0 -50%;
  display: flex;
  flex-direction: column;
  gap: var(--ag-space-1);
  padding: var(--ag-space-2);
  z-index: 22;
}

.bm-dock__btn {
  position: relative; /* anchors the .bm-dock__badge dot to this button */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  min-inline-size: 62px;
  min-block-size: var(--ag-hit-target-compact);
  padding: var(--ag-space-2) var(--ag-space-1);
  border: none;
  border-radius: var(--ag-radius-2xl);
  background: transparent;
  color: var(--bm-dim);
  font-family: var(--ag-font-sans);
  font-size: var(--ag-font-size-xs);
  font-weight: var(--ag-font-weight-semibold);
  line-height: var(--ag-line-height-tight);
  letter-spacing: var(--ag-letter-spacing-normal);
  cursor: pointer;
  transition: var(--ag-transition-colors);
}

.bm-dock__btn:hover {
  background: var(--bm-line-soft);
  color: var(--bm-text);
}

.bm-dock__btn:focus-visible {
  outline: 2px solid var(--ag-color-border-focus);
  outline-offset: 2px;
}

.bm-dock__btn[aria-pressed="true"] {
  background: var(--ag-gradient-button);
  color: var(--ag-color-text-on-primary);
  box-shadow: var(--ag-shadow-primary);
}

.bm-dock__icon {
  font-size: var(--ag-font-size-xl);
  line-height: 1;
}

.bm-dock__sep {
  block-size: 1px;
  inline-size: auto;
  background: var(--bm-line-soft);
  margin-block: var(--ag-space-1);
  margin-inline: var(--ag-space-2);
}

/* Fresh-activity badge on the Live button (W4 Task 9, gated web_pulse). The
   dock JS (static/js/globe/dock.js) adds this dot to [data-bm-mode="live"]
   while the shared pulse store reports events newer than the user's last Live
   visit; entering Live clears it. Non-interactive + aria-hidden — the count is
   the store's, not announced here. The 2px panel-colored ring keeps it legible
   over both the resting button and the pressed (gradient) state. Tokens +
   LOGICAL properties only — the RTL gate greps this file. */
.bm-dock__badge {
  position: absolute;
  inset-block-start: var(--ag-space-1);
  inset-inline-end: var(--ag-space-1);
  inline-size: 8px;
  block-size: 8px;
  border-radius: var(--ag-radius-full);
  background: var(--ag-color-warning);
  box-shadow: 0 0 0 2px var(--bm-panel);
  pointer-events: none;
}

/* ==========================================================================
   2. Omni-search — #bm-omni
   ========================================================================== */
#bm-omni {
  position: absolute;
  inset-block-start: var(--ag-space-4);
  /* RTL-safe horizontal centering: inset-inline-start:50% + translate:-50%
     is NOT direction-safe (translate's % always resolves against the
     physical x-axis, unlike inset-inline-start). inset-inline:0 +
     margin-inline:auto centers identically in ltr/rtl by construction,
     given the definite inline-size below. */
  inset-inline: 0;
  margin-inline: auto;
  inline-size: min(520px, 52%);
  display: flex;
  align-items: center;
  gap: var(--ag-space-2);
  padding: var(--ag-space-2) var(--ag-space-4);
  border-radius: var(--ag-radius-full);
  z-index: 20;
}

#bm-omni:focus-within {
  outline: 2px solid var(--ag-color-border-focus);
  outline-offset: 2px;
}

.bm-omni__icon {
  flex: none;
  color: #9cc4ff;
  font-size: var(--ag-font-size-lg);
  line-height: 1;
}

#bm-omni-input {
  flex: 1;
  min-inline-size: 0;
  min-block-size: var(--ag-hit-target-compact);
  border: none;
  background: transparent;
  color: var(--bm-text);
  font-family: var(--ag-font-sans);
  font-size: var(--ag-font-size-md);
  font-weight: var(--ag-font-weight-medium);
}

#bm-omni-input::placeholder {
  color: var(--bm-faint);
}

#bm-omni-input:focus {
  outline: none;
}

/* Search inputs render a native clear ("x") button in WebKit/Blink; recolor
   it for the dark panel instead of leaving the OS-default dark-on-dark glyph. */
#bm-omni-input::-webkit-search-cancel-button {
  filter: invert(1) brightness(1.6);
}

#bm-omni kbd {
  flex: none;
  font-family: var(--ag-font-sans);
  font-size: var(--ag-font-size-xs);
  font-weight: var(--ag-font-weight-semibold);
  color: var(--bm-dim);
  border: 1px solid var(--bm-line);
  border-radius: var(--ag-radius-sm);
  padding-block: 2px;
  padding-inline: var(--ag-space-1);
  background: rgba(10, 17, 38, 0.6);
}

#bm-omni-results {
  position: absolute;
  inset-block-start: calc(100% + var(--ag-space-2));
  /* RTL-safe centering — see #bm-omni comment above. */
  inset-inline: 0;
  margin-inline: auto;
  inline-size: min(560px, 56%);
  max-block-size: 60vh;
  overflow-y: auto;
  border-radius: var(--ag-radius-3xl);
  background: var(--bm-panel);
  border: 1px solid var(--bm-line);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  box-shadow: var(--ag-shadow-2xl);
  z-index: 21;
}

#bm-omni-results[hidden] {
  display: none;
}

/* ── Trip-context chip + Edit popover (W3 Task 7) ────────────────────────────
   A compact dates/guests chip that sits inside the omni pill (flex:none, at the
   inline-end next to ⌘K). Clicking it opens the .bm-tripctx__pop dialog
   (JS-created) with two date inputs + a guests number and Apply / Clear. Logical
   properties + First-Light tokens only — see this file's header. */
.bm-tripctx {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: var(--ag-space-1);
  min-block-size: var(--ag-hit-target-compact);
  padding-block: var(--ag-space-1);
  padding-inline: var(--ag-space-3);
  border: 1px solid var(--bm-line);
  border-radius: var(--ag-radius-full);
  background: rgba(10, 17, 38, 0.6);
  color: var(--bm-text);
  font-family: var(--ag-font-sans);
  font-size: var(--ag-font-size-sm);
  font-weight: var(--ag-font-weight-medium);
  cursor: pointer;
  white-space: nowrap;
}

.bm-tripctx:hover {
  border-color: var(--bm-text);
}

.bm-tripctx:focus-visible {
  outline: 2px solid var(--ag-color-border-focus);
  outline-offset: 2px;
}

.bm-tripctx__icon {
  flex: none;
  line-height: 1;
}

.bm-tripctx__pop {
  position: absolute;
  inset-block-start: calc(100% + var(--ag-space-2));
  inset-inline-end: 0;
  inline-size: min(280px, 84vw);
  display: flex;
  flex-direction: column;
  gap: var(--ag-space-2);
  padding: var(--ag-space-4);
  z-index: 23;
}

.bm-tripctx__field {
  display: flex;
  flex-direction: column;
  gap: var(--ag-space-1);
  color: var(--bm-dim);
  font-family: var(--ag-font-sans);
  font-size: var(--ag-font-size-xs);
  font-weight: var(--ag-font-weight-semibold);
}

.bm-tripctx__field input {
  min-block-size: var(--ag-hit-target-compact);
  padding-block: var(--ag-space-1);
  padding-inline: var(--ag-space-2);
  border: 1px solid var(--bm-line);
  border-radius: var(--ag-radius-md);
  background: rgba(10, 17, 38, 0.55);
  color: var(--bm-text);
  font-family: var(--ag-font-sans);
  font-size: var(--ag-font-size-sm);
  font-weight: var(--ag-font-weight-medium);
}

.bm-tripctx__field input::-webkit-calendar-picker-indicator {
  filter: invert(1) brightness(1.4);
}

.bm-tripctx__actions {
  display: flex;
  justify-content: space-between;
  gap: var(--ag-space-2);
  margin-block-start: var(--ag-space-1);
}

.bm-tripctx__clear,
.bm-tripctx__apply {
  min-block-size: var(--ag-hit-target-compact);
  padding-block: var(--ag-space-1);
  padding-inline: var(--ag-space-4);
  border-radius: var(--ag-radius-full);
  font-family: var(--ag-font-sans);
  font-size: var(--ag-font-size-sm);
  font-weight: var(--ag-font-weight-semibold);
  cursor: pointer;
}

.bm-tripctx__clear {
  border: 1px solid var(--bm-line);
  background: transparent;
  color: var(--bm-dim);
}

.bm-tripctx__apply {
  border: none;
  background: var(--ag-gradient-primary, linear-gradient(135deg, #2563eb, #4f46e5));
  color: #fff;
}

/* ==========================================================================
   3. Instrument rail — #bm-rail
   ========================================================================== */
#bm-rail {
  position: absolute;
  inset-block-start: 50%;
  inset-inline-end: var(--ag-space-4);
  translate: 0 -50%;
  display: flex;
  flex-direction: column;
  gap: var(--ag-space-1);
  padding: var(--ag-space-2);
  border-radius: var(--ag-radius-full);
  z-index: 22;
}

.bm-rail__btn {
  inline-size: var(--ag-hit-target-compact);
  block-size: var(--ag-hit-target-compact);
  display: grid;
  place-items: center;
  justify-content: center;
  /* Zero the global button padding (styles.css:1349 `button{padding:0 14px}`)
     — on a 36px border-box icon button it left an 8px content box, shoving the
     glyph 14px right (off-centre). place-items can't recover from that. */
  padding: 0;
  border: none;
  border-radius: var(--ag-radius-full);
  background: transparent;
  color: var(--bm-dim);
  font-size: var(--ag-font-size-xl);
  line-height: 1;
  cursor: pointer;
  transition: var(--ag-transition-colors);
}

.bm-rail__btn:hover {
  background: var(--bm-line-soft);
  color: var(--bm-text);
}

.bm-rail__btn:focus-visible {
  outline: 2px solid var(--ag-color-border-focus);
  outline-offset: 2px;
}

.bm-rail__sep {
  inline-size: var(--ag-hit-target-compact);
  block-size: 1px;
  background: var(--bm-line-soft);
  margin-block: var(--ag-space-1);
}

/* --------------------------------------------------------------------------
   3b. Share menu — #bm-share-menu (W7 Task 2)
   A dark-glass popover anchored just inline-start of the rail's Share button.
   -------------------------------------------------------------------------- */
#bm-share-menu {
  position: absolute;
  inset-block-start: 50%;
  inset-inline-end: calc(var(--ag-space-4) + 52px);
  translate: 0 -50%;
  display: flex;
  flex-direction: column;
  gap: var(--ag-space-1);
  padding: var(--ag-space-2);
  border-radius: var(--ag-radius-lg);
  min-inline-size: 172px;
  z-index: 23;
}

#bm-share-menu[hidden] {
  display: none;
}

.bm-share-menu__item {
  display: flex;
  align-items: center;
  gap: var(--ag-space-2);
  inline-size: 100%;
  padding: var(--ag-space-2) var(--ag-space-3);
  border: none;
  border-radius: var(--ag-radius-md);
  background: transparent;
  color: var(--bm-text);
  font: inherit;
  font-size: var(--ag-font-size-sm);
  text-align: start;
  cursor: pointer;
  transition: var(--ag-transition-colors);
}

.bm-share-menu__item[hidden] {
  display: none;
}

.bm-share-menu__item:hover {
  background: var(--bm-line-soft);
}

.bm-share-menu__item:focus-visible {
  outline: 2px solid var(--ag-color-border-focus);
  outline-offset: -2px;
}

.bm-share-menu__icon {
  inline-size: 1.25em;
  text-align: center;
  color: var(--bm-dim);
}

/* Share-action confirmation — a brief "Link copied" / "Embed copied" pill. */
.bm-share-toast {
  position: absolute;
  inset-block-end: var(--ag-space-4);
  inset-inline: 0;
  margin-inline: auto;
  inline-size: fit-content;
  max-inline-size: 88vw;
  padding: var(--ag-space-2) var(--ag-space-4);
  border-radius: var(--ag-radius-full);
  background: var(--bm-panel, rgba(12, 18, 28, 0.92));
  color: #fff;
  font-size: var(--ag-font-size-sm);
  z-index: 40;
  pointer-events: none;
}

/* ==========================================================================
   4. Content chips — #bm-chips
   ========================================================================== */
#bm-chips {
  position: absolute;
  inset-block-start: calc(var(--ag-space-4) + 54px);
  /* RTL-safe centering — see #bm-omni comment above. Unlike #bm-omni,
     this row has no definite width of its own (it shrink-wraps to its
     chips), so inline-size must be given a non-auto value (fit-content,
     not the bare "auto" keyword) or inset-inline:0 would stretch this
     invisible wrapper to full width and dead-zone map clicks/drags on
     either side of the chip row. fit-content preserves the original
     shrink-to-fit footprint while still centering via margin-inline. */
  inset-inline: 0;
  margin-inline: auto;
  inline-size: fit-content;
  display: flex;
  gap: var(--ag-space-2);
  flex-wrap: wrap;
  justify-content: center;
  z-index: 20;
}

.bm-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--ag-space-1);
  min-block-size: var(--ag-hit-target-compact);
  padding-block: var(--ag-space-2);
  padding-inline: var(--ag-space-3);
  border-radius: var(--ag-radius-full);
  background: var(--bm-panel);
  border: 1px solid var(--bm-line);
  color: var(--bm-dim);
  font-family: var(--ag-font-sans);
  font-size: var(--ag-font-size-sm);
  font-weight: var(--ag-font-weight-semibold);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  cursor: pointer;
  transition: var(--ag-transition-colors);
}

.bm-chip:hover {
  color: var(--bm-text);
}

.bm-chip:focus-visible {
  outline: 2px solid var(--ag-color-border-focus);
  outline-offset: 2px;
}

.bm-chip[aria-pressed="true"] {
  background: var(--ag-gradient-button);
  border-color: transparent;
  color: var(--ag-color-text-on-primary);
  box-shadow: var(--ag-shadow-primary);
}

/* ==========================================================================
   5. Whisper line — #bm-whisper (W2 Task 7)
   ========================================================================== */
#bm-whisper {
  position: absolute;
  inset-block-end: var(--ag-space-4);
  /* RTL-safe horizontal centering — see #bm-omni's comment above. */
  inset-inline: 0;
  margin-inline: auto;
  inline-size: fit-content;
  max-inline-size: min(480px, 90%);
  display: flex;
  align-items: center;
  gap: var(--ag-space-2);
  padding-block: var(--ag-space-2);
  padding-inline: var(--ag-space-4);
  border-radius: var(--ag-radius-full);
  color: var(--bm-text);
  font-family: var(--ag-font-sans);
  font-size: var(--ag-font-size-sm);
  font-weight: var(--ag-font-weight-medium);
  cursor: pointer;
  z-index: 19;
}

#bm-whisper[hidden] {
  display: none;
}

#bm-whisper:hover {
  background: var(--bm-line-soft);
}

#bm-whisper:focus-visible {
  outline: 2px solid var(--ag-color-border-focus);
  outline-offset: 2px;
}

.bm-whisper__icon {
  flex: none;
  font-size: var(--ag-font-size-md);
  line-height: 1;
}

.bm-whisper__text {
  /* min-inline-size:0 overrides the flex-item default (min-width:auto),
     which otherwise refuses to shrink below the line's own intrinsic
     width -- without it, text-overflow:ellipsis never gets a chance to
     trigger and a long line just pushes #bm-whisper past its
     max-inline-size instead of truncating. */
  min-inline-size: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ==========================================================================
   6. Layers sheet — #bm-layers-sheet (W2 Task 8)
   ========================================================================== */
#bm-layers-sheet {
  position: absolute;
  inset-block-start: 50%;
  /* Pops out to the right of #bm-dock (62px min-inline-size + its own
     padding) rather than centering/backdropping the whole map -- keeps the
     open sheet visually anchored to the button that opened it. */
  inset-inline-start: calc(var(--ag-space-4) + 78px);
  translate: 0 -50%;
  inline-size: min(280px, 82%);
  max-block-size: 80vh;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: var(--ag-space-3);
  padding: var(--ag-space-4);
  z-index: 25;
}

#bm-layers-sheet[hidden] {
  display: none;
}

.bm-layers__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--ag-space-2);
}

.bm-layers__title {
  margin: 0;
  color: var(--bm-text);
  font-family: var(--ag-font-sans);
  font-size: var(--ag-font-size-lg);
  font-weight: var(--ag-font-weight-semibold);
}

.bm-layers__close {
  flex: none;
  inline-size: var(--ag-hit-target-compact);
  block-size: var(--ag-hit-target-compact);
  display: grid;
  place-items: center;
  border: none;
  border-radius: var(--ag-radius-full);
  background: transparent;
  color: var(--bm-dim);
  font-size: var(--ag-font-size-md);
  line-height: 1;
  cursor: pointer;
  transition: var(--ag-transition-colors);
}

.bm-layers__close:hover {
  background: var(--bm-line-soft);
  color: var(--bm-text);
}

.bm-layers__close:focus-visible {
  outline: 2px solid var(--ag-color-border-focus);
  outline-offset: 2px;
}

.bm-layers__row {
  display: flex;
  align-items: center;
  gap: var(--ag-space-3);
  min-block-size: var(--ag-hit-target-compact);
  color: var(--bm-text);
  font-family: var(--ag-font-sans);
  font-size: var(--ag-font-size-sm);
  font-weight: var(--ag-font-weight-medium);
  cursor: pointer;
}

.bm-layers__row input[type="checkbox"] {
  inline-size: 18px;
  block-size: 18px;
  accent-color: var(--ag-color-brand-primary);
  cursor: pointer;
}

.bm-layers__row input[type="checkbox"]:focus-visible {
  outline: 2px solid var(--ag-color-border-focus);
  outline-offset: 2px;
}

.bm-layers__sep {
  block-size: 1px;
  background: var(--bm-line-soft);
  margin-block: var(--ag-space-1);
}

.bm-layers__all {
  align-self: flex-start;
  border: none;
  background: transparent;
  color: #9cc4ff;
  font-family: var(--ag-font-sans);
  font-size: var(--ag-font-size-sm);
  font-weight: var(--ag-font-weight-semibold);
  padding: 0;
  cursor: pointer;
}

.bm-layers__all:hover {
  text-decoration: underline;
}

.bm-layers__all:focus-visible {
  outline: 2px solid var(--ag-color-border-focus);
  outline-offset: 2px;
}

/* ==========================================================================
   8. Price pins — .bm-pricepin (W3 Task 2, Window Shopping)
   Flag: web_window_shopping. A separate DOM-marker layer (mapboxgl.Marker
   per priced feature) from the clustered content source — see
   static/js/globe/pricePins.js. White pill showing the pre-formatted
   price_label; the selected pin flips to the brand-active fill.
   ========================================================================== */
.bm-pricepin {
  display: inline-flex;
  align-items: center;
  min-block-size: var(--ag-hit-target-compact);
  padding-block: var(--ag-space-1);
  padding-inline: var(--ag-space-3);
  border: 1px solid var(--ag-color-border-subtle);
  border-radius: var(--ag-radius-full);
  background: var(--ag-color-bg-surface);
  color: var(--ag-color-text-heading);
  font-family: var(--ag-font-sans);
  font-size: var(--ag-font-size-sm);
  font-weight: var(--ag-font-weight-semibold);
  line-height: var(--ag-line-height-tight);
  white-space: nowrap;
  box-shadow: var(--ag-shadow-md);
  cursor: pointer;
  transition: var(--ag-transition-transform), var(--ag-transition-colors);
}

.bm-pricepin:hover {
  background: var(--ag-color-bg-surface-alt);
  scale: 1.05;
}

.bm-pricepin:focus-visible {
  outline: 2px solid var(--ag-color-border-focus);
  outline-offset: 2px;
}

.bm-pricepin--sel {
  background: var(--ag-color-brand-primary-active);
  border-color: transparent;
  color: var(--ag-color-text-on-primary);
  box-shadow: var(--ag-shadow-primary);
}

/* Sponsored pin (W3 Task 9) — the amber, labeled variant of the price pill.
   ONE per viewport, browse ("explore") mode only: static/js/globe/sponsoredPin.js
   reads the #bm-sponsored-ad json_script apps/globe/views.py::index fills from
   the EXISTING ads engine (premium viewers suppressed server-side). Two stacked
   lines — a "Sponsored" eyebrow + the ad title — so it flips the base pill's
   single inline row to a column. Amber via --ag-color-warning-alt (matches
   mockup 03-window-shopping.html's #f4b45c); the base pill's dark
   --ag-color-text-heading carries the contrast. Tokens + LOGICAL properties
   only (the RTL gate greps this file). */
.bm-pricepin--sponsored {
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  padding-block: var(--ag-space-1);
  padding-inline: var(--ag-space-3);
  background: var(--ag-color-warning-alt);
  border-color: var(--ag-color-warning);
}

.bm-pricepin--sponsored:hover {
  /* the base pill flips to a surface tint on hover — keep the sponsored fill amber */
  background: var(--ag-color-warning-alt);
}

.bm-pricepin__sponsor {
  font-size: var(--ag-font-size-xs);
  font-weight: var(--ag-font-weight-bold);
  line-height: var(--ag-line-height-tight);
  letter-spacing: var(--ag-letter-spacing-wide);
  text-transform: uppercase;
}

.bm-pricepin__title {
  font-size: var(--ag-font-size-sm);
  font-weight: var(--ag-font-weight-semibold);
  line-height: var(--ag-line-height-tight);
}

/* ==========================================================================
   9. Entity card — .bm-ecard (W3 Task 4, Window Shopping)
   Flag: web_window_shopping. ONE dark-glass card docked inset-inline-end that
   renders + acts on any focused feature (stay/activity/tour/event/trail) —
   JS-created (static/js/globe/entityCard.js), template stays zero-diff. See
   mockup 03-window-shopping.html.

   Self-gating tokens: web_window_shopping can be ON while web_first_light is
   OFF, so the .bm-first-light ancestor that defines --bm-panel/... may be
   absent under this flag. The card therefore RE-declares the night-flight
   tokens on .bm-ecard itself (identical values — they just shadow the
   ancestor's when it IS present) so its .bm-glass background, border and text
   resolve either way. Same reason section 8's .bm-pricepin leans on --ag-*
   globals. Tokens + LOGICAL properties only — the RTL gate greps this file.
   ========================================================================== */
.bm-ecard {
  --bm-panel: rgba(14, 22, 46, 0.86);
  --bm-line: rgba(120, 150, 205, 0.22);
  --bm-line-soft: rgba(120, 150, 205, 0.13);
  --bm-text: #eaf0fb;
  --bm-dim: #9daecc;
  --bm-faint: #6e7fa3;
  position: absolute;
  inset-block-start: var(--ag-space-4);
  inset-inline-end: var(--ag-space-4);
  inline-size: min(344px, 92%);
  max-block-size: calc(100% - var(--ag-space-4) * 2);
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  color: var(--bm-text);
  font-family: var(--ag-font-sans);
  z-index: 24;
}

.bm-ecard:focus-visible {
  outline: 2px solid var(--ag-color-border-focus);
  outline-offset: 2px;
}

/* Image header (real thumb) or scene-gradient placeholder — same footprint. */
.bm-ecard__img,
.bm-ecard__scene {
  display: block;
  inline-size: 100%;
  block-size: 150px;
  object-fit: cover;
  border-start-start-radius: var(--ag-radius-3xl);
  border-start-end-radius: var(--ag-radius-3xl);
}

.bm-ecard__scene {
  background: linear-gradient(145deg, #155e75, #0b3444);
}

.bm-ecard__close {
  position: absolute;
  inset-block-start: var(--ag-space-2);
  inset-inline-end: var(--ag-space-2);
  inline-size: var(--ag-hit-target-compact);
  block-size: var(--ag-hit-target-compact);
  display: grid;
  place-items: center;
  border: none;
  border-radius: var(--ag-radius-full);
  background: rgba(7, 13, 31, 0.6);
  color: var(--bm-text);
  font-size: var(--ag-font-size-md);
  line-height: 1;
  cursor: pointer;
  z-index: 1;
  transition: var(--ag-transition-colors);
}

.bm-ecard__close:hover {
  background: rgba(7, 13, 31, 0.85);
}

.bm-ecard__close:focus-visible {
  outline: 2px solid var(--ag-color-border-focus);
  outline-offset: 2px;
}

.bm-ecard__body {
  display: flex;
  flex-direction: column;
  gap: var(--ag-space-2);
  padding: var(--ag-space-4);
}

.bm-ecard__title {
  margin: 0;
  color: var(--bm-text);
  font-size: var(--ag-font-size-xl);
  font-weight: var(--ag-font-weight-semibold);
  line-height: var(--ag-line-height-tight);
}

.bm-ecard__price {
  color: var(--bm-text);
  font-size: var(--ag-font-size-lg);
  font-weight: var(--ag-font-weight-bold);
}

/* Trip-context total (W3 Task 7) — "$74 × 4 nights = $296" under the per-night
   price when a trip context (both dates) is set. Dimmer than the headline. */
.bm-ecard__total {
  margin-block-start: calc(var(--ag-space-1) * -1);
  color: var(--bm-dim);
  font-size: var(--ag-font-size-sm);
  font-weight: var(--ag-font-weight-medium);
}

.bm-ecard__meta {
  display: flex;
  align-items: center;
  gap: var(--ag-space-2);
  color: var(--bm-dim);
  font-size: var(--ag-font-size-sm);
  font-weight: var(--ag-font-weight-medium);
}

.bm-ecard__meta-icon {
  flex: none;
  line-height: 1;
}

.bm-ecard__actions {
  display: flex;
  gap: var(--ag-space-2);
  margin-block-start: var(--ag-space-2);
}

.bm-ecard__btn {
  flex: 1;
  min-block-size: var(--ag-hit-target-compact);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--ag-space-1);
  padding-block: var(--ag-space-2);
  padding-inline: var(--ag-space-3);
  border: 1px solid var(--bm-line);
  border-radius: var(--ag-radius-2xl);
  background: transparent;
  color: var(--bm-text);
  font-family: var(--ag-font-sans);
  font-size: var(--ag-font-size-sm);
  font-weight: var(--ag-font-weight-semibold);
  cursor: pointer;
  transition: var(--ag-transition-colors);
}

.bm-ecard__btn:hover {
  background: var(--bm-line-soft);
}

.bm-ecard__btn:focus-visible {
  outline: 2px solid var(--ag-color-border-focus);
  outline-offset: 2px;
}

.bm-ecard__btn--primary {
  border-color: transparent;
  background: var(--ag-gradient-button);
  color: var(--ag-color-text-on-primary);
  box-shadow: var(--ag-shadow-primary);
}

/* ==========================================================================
   9b. Reel peek — .bm-reelpeek + .bm-crosslink (W3 Task 6, Window Shopping)
   Flag: web_window_shopping. A focused REEL renders this VARIANT of the entity
   card: the JS root carries `bm-reelpeek bm-ecard bm-glass`, so it reuses
   section 9's dock/position/glass/tokens for free (static/js/globe/reelPeek.js;
   template stays zero-diff). Adds a thumb with a centered ▶ play overlay (opens
   the reel page in a new tab) and a cross-link to the nearest stay. The reel's
   "🛏 stay" line and the stay card's inverse "🎬 reel" line share .bm-crosslink
   (one affordance, both directions). Tokens + LOGICAL properties only — the RTL
   gate greps this file. See mockup 03-window-shopping.html + task-6-report.md.
   ========================================================================== */
.bm-reelpeek__thumb {
  position: relative;
  display: block;
  inline-size: 100%;
}

.bm-reelpeek__play {
  position: absolute;
  inset-block-start: 50%;
  inset-inline-start: 50%;
  transform: translate(-50%, -50%);
  inline-size: 56px;
  block-size: 56px;
  display: grid;
  place-items: center;
  padding-inline-start: 4px; /* optically center the ▶ glyph */
  border: none;
  border-radius: var(--ag-radius-full);
  background: rgba(7, 13, 31, 0.62);
  color: var(--bm-text);
  font-size: var(--ag-font-size-xl);
  line-height: 1;
  cursor: pointer;
  transition: var(--ag-transition-colors);
}

.bm-reelpeek__play:hover {
  background: rgba(7, 13, 31, 0.85);
}

.bm-reelpeek__play:focus-visible {
  outline: 2px solid var(--ag-color-border-focus);
  outline-offset: 2px;
}

.bm-crosslink {
  inline-size: 100%;
  margin-block-start: var(--ag-space-1);
  padding-block: var(--ag-space-2);
  padding-inline: var(--ag-space-3);
  display: flex;
  align-items: center;
  gap: var(--ag-space-2);
  border: 1px solid var(--bm-line);
  border-radius: var(--ag-radius-2xl);
  background: var(--bm-line-soft);
  color: var(--bm-text);
  font-family: var(--ag-font-sans);
  font-size: var(--ag-font-size-sm);
  font-weight: var(--ag-font-weight-medium);
  text-align: start;
  cursor: pointer;
  transition: var(--ag-transition-colors);
}

.bm-crosslink:hover {
  background: rgba(120, 150, 205, 0.2);
}

.bm-crosslink:focus-visible {
  outline: 2px solid var(--ag-color-border-focus);
  outline-offset: 2px;
}

/* ── Small screens: the map stays in charge, not the chrome ─────────────── */
@media (max-width: 820px) {
  #bm-dock {
    inset-inline-start: var(--ag-space-2);
  }

  #bm-rail {
    inset-inline-end: var(--ag-space-2);
  }

  #bm-omni {
    inline-size: min(520px, 86%);
  }

  #bm-omni-results {
    inline-size: min(560px, 90%);
  }

  #bm-whisper {
    max-inline-size: min(480px, 92%);
  }

  #bm-layers-sheet {
    inset-inline-start: var(--ag-space-2);
    inline-size: min(280px, 78%);
  }

  .bm-ecard {
    inset-block-start: var(--ag-space-2);
    inset-inline-end: var(--ag-space-2);
    inline-size: min(344px, calc(100% - var(--ag-space-2) * 2));
  }
}

/* ==========================================================================
   7. Mobile-web layout — <=720px (W2 Task 11, wave gate)
   ========================================================================== */
/* Phones: the dock becomes a bottom tab bar, omni spans (almost) full
   width, chips scroll horizontally, and the rail sheds everything but
   zoom + locate. The persistent chrome that reduces map area is dock
   (bottom) + omni (top) + the always-on chips row: #bm-chips ships with
   no [hidden] attribute and is visible the instant First Light chrome
   renders, same as dock/omni. #bm-layers-sheet and #bm-whisper are the
   only genuinely transient pieces here -- both start `hidden` in their
   partial's own markup and are only shown later by JS. (An earlier
   version of this comment miscategorized chips alongside layers-sheet/
   whisper as "transient overlays that don't count against the map's
   share" -- corrected; see task-11-report.md's gate-integrity fix.)

   omni is pinned top, ~54px tall (padding-block var(--ag-space-2) x2 +
   the input's --ag-hit-target-compact). The dock is pinned bottom; a
   real-browser harness measurement, not a plain-text content-box
   estimate, drove its padding here -- emoji glyphs render taller than
   their nominal font-size, and "My planet" wraps to two lines under
   ~360px, so its height varies: ~61px unwrapped, ~80px wrapped at the
   narrowest tested width. chips is forced to one horizontal-scrolling
   row at this breakpoint (flex-wrap:nowrap + overflow-x:auto below), so
   it never grows past one row's height (~39px) regardless of viewport
   width.

   Real Chromium measurements (task-11-report.md's harness; re-verified
   via Playwright when this comment was corrected): dock+omni ALONE --
   320x568 (narrowest+shortest tested, "My planet" wrapped) ~76.4% map
   share, 360x740 ~84.4%, 375x667 ~82.7%. Counting chips too, as the
   correction above says this section should (its ~39px band sits
   directly under omni, not overlapping it): 320x568 drops to ~69.6% --
   BELOW the >=75% floor -- while 360x740 (~79.1%) and 375x667 (~76.9%)
   stay clear (dock is shorter, unwrapped, at those two sizes).

   NOT fixed here: chips' ~36-39px is set by the same
   --ag-hit-target-compact (36px) floor every First Light control uses
   for tap-target accessibility, and #bm-chips carries no extra container
   padding to trim the way #bm-dock's own mobile fix did (that trimmed
   the DOCK CONTAINER's padding, independent of its buttons' 36px floor;
   #bm-chips has no equivalent container padding -- the 36px sits
   directly on each .bm-chip). Zeroing .bm-chip's padding-block entirely
   -- the only even theoretically "minimal" trim available -- recovers
   ~3px (measured) against a ~31px shortfall at 320x568; the rest is the
   accessibility floor itself, which this fix will not shrink just to
   chase a layout number. Flagging as an open concern for a follow-up
   task rather than force-fitting an inadequate trim. */
@media (max-width: 720px) {
  #bm-dock {
    inset-block-start: auto;
    inset-block-end: 0;
    inset-inline: 0;
    translate: none;
    flex-direction: row;
    align-items: center;
    justify-content: space-around;
    gap: 0;
    padding-block: var(--ag-space-1);
    padding-inline: var(--ag-space-2);
  }

  .bm-dock__btn {
    /* A little narrower than the vertical-stack minimum (62px) so all 5
       buttons plus the dock's own inline padding fit without overflow on
       a 320px-wide phone (5 x 56px + 16px padding = 296px, 24px to
       spare). At exactly 320px "My planet" (the longest label) still
       wraps to two lines -- measured harmless (no overflow, no clipping,
       see task-11-report.md's screenshot) but it grows the dock enough to
       leave the ">=75% map share" budget with almost no margin, so
       block-axis padding is trimmed here too (8px total instead of the
       vertical stack's 16px) to buy that margin back in both the wrapped
       and unwrapped case. */
    padding-block: var(--ag-space-1);
    min-inline-size: 56px;
  }

  .bm-dock__sep {
    /* Flips from a horizontal rule (sits between rows in the vertical
       stack) to a vertical divider (sits between columns in the row
       #bm-dock is now) now that the dock itself lays out as a row. */
    inline-size: 1px;
    block-size: 24px;
    margin-block: 0;
    margin-inline: var(--ag-space-1);
  }

  #bm-omni {
    inline-size: auto;
    inset-inline: var(--ag-space-2);
  }

  #bm-chips {
    inline-size: auto;
    max-inline-size: calc(100% - 24px);
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
    /* flex-start, not center: centering an OVERFLOWING flex container can
       leave the start of its content unreachable by scrolling in some
       browsers -- flex-start guarantees the natural, scrollable-from-the-
       first-chip behavior every native horizontal chip/pill row uses.
       Direction-safe by construction: flex-start already resolves against
       the inline-start edge (the right in rtl), so this needs no separate
       rtl override. */
    justify-content: flex-start;
  }

  #bm-chips::-webkit-scrollbar {
    /* scrollbar-width:none (above) is the Firefox/standards knob; Safari
       and Chrome need the -webkit pseudo-element hidden too, same
       cross-browser pairing this file already uses for backdrop-filter. */
    display: none;
  }

  .bm-chip {
    /* flex:none = flex:0 0 auto -- chips never shrink to fit. Overflowing
       (and thus the horizontal scroll just turned on above) is the point,
       not squished or truncated chip text. */
    flex: none;
  }

  .bm-rail__extra {
    /* Compass, projection, fullscreen, and the two separators either side
       of them (see templates/globe/partials/_instrument_rail.html) --
       zoom in/out + locate are the three instruments a one-handed phone
       visit actually needs; the rest stay one tap away on a wider
       viewport instead of crowding a floating rail over the map. */
    display: none;
  }

  #bm-whisper {
    /* #bm-whisper's base rule anchors it var(--ag-space-4) (16px) above
       the viewport's bottom edge -- correct when nothing else lives down
       there, but #bm-dock now permanently occupies that same bottom band
       (this block's header comment: ~61-80px tall depending on whether
       "My planet" wraps) as a bottom bar, so an unmodified whisper would
       render UNDER/overlapping the dock instead of clear above it. First
       measured this with a real browser (see task-11-report.md) rather
       than trusting a hand-rolled icon+label content-box estimate -- that
       estimate (~56px) undershot the real, emoji-inflated dock height by
       13px and would have left whisper and the dock visibly overlapping.
       var(--ag-space-2) + 80px (88px total) clears the dock at every
       tested width, including its tallest (wrapped, ~80px at 320x568,
       an 8px margin) -- reconfirmed overlap=false in the same harness at
       320x568, 360x740, and 375x667 after this fix. */
    inset-block-end: calc(var(--ag-space-2) + 80px);
  }
}

/* ==========================================================================
   10. Booking slide-over — .bm-booksheet (W3 Task 5, Window Shopping)
   Flag: web_window_shopping (mounted on demand from entityCard.js's stay
   Reserve seam — no template diff). A docked panel over the globe hosting the
   stay's REAL booking flow in an iframe (catalog/stay_detail_embed_book.html);
   its success page posts "ag-booking-complete" back up and bookSheet.js toasts
   + closes. Unlike the dark-glass chrome, the panel is a LIGHT surface because
   it frames the light booking form. Tokens + LOGICAL properties only — the RTL
   gate greps this file.
   ========================================================================== */
.bm-booksheet {
  position: absolute;
  inset: 0;
  z-index: var(--ag-z-modal);
  display: flex;
  justify-content: flex-end;
}

.bm-booksheet__backdrop {
  position: absolute;
  inset: 0;
  background: var(--ag-color-bg-overlay);
  cursor: pointer;
}

.bm-booksheet__panel {
  position: relative;
  inline-size: min(440px, 100%);
  max-inline-size: 100%;
  block-size: 100%;
  display: flex;
  flex-direction: column;
  background: var(--ag-color-bg-surface);
  border-start-start-radius: var(--ag-radius-3xl);
  border-end-start-radius: var(--ag-radius-3xl);
  box-shadow: var(--ag-shadow-2xl);
  overflow: hidden;
}

.bm-booksheet__close {
  position: absolute;
  inset-block-start: var(--ag-space-3);
  inset-inline-end: var(--ag-space-3);
  inline-size: var(--ag-hit-target-compact);
  block-size: var(--ag-hit-target-compact);
  display: grid;
  place-items: center;
  border: 1px solid var(--ag-color-border-subtle, rgba(46, 116, 184, 0.18));
  border-radius: var(--ag-radius-full);
  background: var(--ag-color-bg-surface);
  color: var(--ag-color-text-body);
  font-size: var(--ag-font-size-md);
  line-height: 1;
  cursor: pointer;
  z-index: 1;
  box-shadow: var(--ag-shadow-soft, 0 6px 18px rgba(2, 8, 20, 0.12));
  transition: var(--ag-transition-colors);
}

.bm-booksheet__close:hover {
  background: var(--ag-color-bg-surface-alt);
}

.bm-booksheet__close:focus-visible {
  outline: 2px solid var(--ag-color-border-focus);
  outline-offset: 2px;
}

.bm-booksheet__frame {
  flex: 1 1 auto;
  inline-size: 100%;
  block-size: 100%;
  border: 0;
  background: var(--ag-color-bg-surface);
}

/* Success toast — dark chip, docked bottom-center over the globe. Self-styled
   (no dependence on the flag-scoped glass tokens) so it reads either way. */
.bm-booksheet-toast {
  position: absolute;
  inset-block-end: var(--ag-space-6);
  inset-inline: 0;
  margin-inline: auto;
  inline-size: max-content;
  max-inline-size: min(420px, 90%);
  z-index: var(--ag-z-popover);
  padding-block: var(--ag-space-3);
  padding-inline: var(--ag-space-5);
  border-radius: var(--ag-radius-full);
  background: rgba(14, 22, 46, 0.92);
  color: #eaf0fb;
  font-family: var(--ag-font-sans);
  font-size: var(--ag-font-size-sm);
  font-weight: var(--ag-font-weight-semibold);
  box-shadow: var(--ag-shadow-2xl);
}

@media (max-width: 820px) {
  .bm-booksheet__panel {
    inline-size: 100%;
    border-radius: 0;
  }
}

/* ==========================================================================
   11. Activity ripples — .bm-ripple (W4 Task 2, The Pulse)
   Flag: web_pulse. Expanding-ring mapboxgl.Marker overlays dropped where
   public activity is happening (static/js/globe/pulse/ripples.js polls
   /globe/api/activity-events/ every 60s, visibility- + mode-gated). Each ring
   plays ONCE and its JS owns the lifetime (removed after ~2.6s), so the
   animation is finite by construction. Ambient + non-interactive
   (pointer-events:none; the element is aria-hidden). Amber-neutral brand ring
   over the dark globe. Reduced motion -> a static glow dot, no animation —
   guaranteed twice over: ripples.js renders .bm-ripple--static, AND the
   @media (prefers-reduced-motion: reduce) block below forces it even on a
   plain .bm-ripple (this layer can render with web_first_light OFF, so the
   section-0 `.bm-first-light *` reduced-motion reset does not cover it).
   Tokens + LOGICAL properties only — the RTL gate greps this file.
   ========================================================================== */
.bm-ripple {
  inline-size: 16px;
  block-size: 16px;
  border-radius: var(--ag-radius-full);
  border: 2px solid var(--ag-color-brand-primary);
  background: transparent;
  pointer-events: none;
  will-change: transform, opacity;
  animation: bm-ripple 2.6s ease-out both;
}

@keyframes bm-ripple {
  0% {
    transform: scale(0.3);
    opacity: 0.9;
  }
  60% {
    opacity: 0.35;
  }
  100% {
    transform: scale(3.2);
    opacity: 0;
  }
}

/* Static glow dot — the reduced-motion fallback ripples.js opts into (and the
   @media guarantee below mirrors). A soft filled dot instead of an expanding,
   fading ring; no animation. */
.bm-ripple--static {
  border-color: transparent;
  background: radial-gradient(circle, var(--ag-color-brand-primary) 0%, transparent 70%);
  opacity: 0.85;
  transform: none;
  animation: none;
}

@media (prefers-reduced-motion: reduce) {
  .bm-ripple {
    border-color: transparent;
    background: radial-gradient(circle, var(--ag-color-brand-primary) 0%, transparent 70%);
    opacity: 0.85;
    transform: none;
    animation: none;
  }
}

/* ==========================================================================
   12. "Happening Now" feed — .bm-pulse-feed (W4 Task 3, The Pulse)
   Flag: web_pulse (pulse_on). A dark-glass panel docked inset-inline-end that,
   in the dock's Live mode, lists recent public activity (rows populated by
   static/js/globe/pulse/feed.js from the shared store) with kind-filter pills.
   When there's no activity it shows the HONEST empty state — "Quiet right now /
   Popular places instead" listing top hotspots labeled "Popular" (the planet
   never fakes liveness). Hidden until Live mode (the [hidden] attribute the
   partial ships with; feed.js toggles it). See mockup 04-the-pulse.html.

   The partial only renders inside the First Light chrome block, so the
   .bm-first-light ancestor that defines --bm-panel/... is always present; the
   panel re-declares those night-flight tokens on itself anyway (identical
   values — they just shadow the ancestor's) for the same defensive reason
   section 9's .bm-ecard does. Tokens + LOGICAL properties only — the RTL gate
   greps this file.
   ========================================================================== */
.bm-pulse-feed {
  --bm-panel: rgba(14, 22, 46, 0.86);
  --bm-line: rgba(120, 150, 205, 0.22);
  --bm-line-soft: rgba(120, 150, 205, 0.13);
  --bm-text: #eaf0fb;
  --bm-dim: #9daecc;
  --bm-faint: #6e7fa3;
  position: absolute;
  inset-block-start: var(--ag-space-4);
  inset-block-end: var(--ag-space-4);
  inset-inline-end: var(--ag-space-4);
  inline-size: min(316px, 92%);
  display: flex;
  flex-direction: column;
  padding: var(--ag-space-4);
  color: var(--bm-text);
  font-family: var(--ag-font-sans);
  z-index: 23;
}

.bm-pulse-feed[hidden] {
  display: none;
}

.bm-pulse-feed__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--ag-space-2);
}

.bm-pulse-feed__title {
  color: var(--bm-text);
  font-size: var(--ag-font-size-md);
  font-weight: var(--ag-font-weight-bold);
  line-height: var(--ag-line-height-tight);
}

.bm-pulse-feed__sub {
  color: var(--bm-faint);
  font-size: var(--ag-font-size-xs);
  font-weight: var(--ag-font-weight-medium);
}

/* Kind-filter pills (All/Reels/Events/Trails/Rifts). */
.bm-pulse-feed__tabs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ag-space-1);
  margin-block: var(--ag-space-2);
}

.bm-pulse-feed__pill {
  min-block-size: var(--ag-hit-target-compact);
  padding-block: var(--ag-space-1);
  padding-inline: var(--ag-space-2);
  border: 1px solid var(--bm-line);
  border-radius: var(--ag-radius-full);
  background: rgba(18, 28, 56, 0.7);
  color: var(--bm-dim);
  font-family: var(--ag-font-sans);
  font-size: var(--ag-font-size-xs);
  font-weight: var(--ag-font-weight-semibold);
  cursor: pointer;
  transition: var(--ag-transition-colors);
}

.bm-pulse-feed__pill:hover {
  color: var(--bm-text);
  border-color: var(--bm-line);
}

.bm-pulse-feed__pill.is-on {
  background: var(--ag-gradient-button);
  border-color: transparent;
  color: var(--ag-color-text-on-primary);
}

.bm-pulse-feed__pill:focus-visible {
  outline: 2px solid var(--ag-color-border-focus);
  outline-offset: 2px;
}

/* Scrollable rows region — takes the remaining panel height. */
.bm-pulse-feed__rows {
  flex: 1;
  overflow-y: auto;
  min-block-size: 0;
}

.bm-pulse-feed__row {
  display: flex;
  align-items: center;
  gap: var(--ag-space-2);
  inline-size: 100%;
  padding-block: var(--ag-space-2);
  padding-inline: var(--ag-space-1);
  border: none;
  border-block-end: 1px solid var(--bm-line-soft);
  background: transparent;
  color: var(--bm-text);
  font-family: var(--ag-font-sans);
  text-align: start;
  cursor: pointer;
  transition: var(--ag-transition-colors);
}

.bm-pulse-feed__row:last-child {
  border-block-end: none;
}

.bm-pulse-feed__row:hover {
  background: rgba(120, 150, 205, 0.08);
}

.bm-pulse-feed__row:focus-visible {
  outline: 2px solid var(--ag-color-border-focus);
  outline-offset: -2px;
}

.bm-pulse-feed__ic {
  flex: none;
  inline-size: 32px;
  block-size: 32px;
  display: grid;
  place-items: center;
  border-radius: var(--ag-radius-md);
  background: rgba(24, 36, 74, 0.9);
  font-size: var(--ag-font-size-sm);
  line-height: 1;
}

.bm-pulse-feed__row-body {
  flex: 1;
  min-inline-size: 0;
}

.bm-pulse-feed__row-title {
  display: block;
  color: var(--bm-text);
  font-size: var(--ag-font-size-xs);
  font-weight: var(--ag-font-weight-semibold);
  line-height: var(--ag-line-height-tight);
}

.bm-pulse-feed__ago {
  flex: none;
  margin-inline-start: auto;
  color: var(--bm-faint);
  font-size: var(--ag-font-size-xs);
  font-weight: var(--ag-font-weight-semibold);
}

/* "Popular" badge on empty-state hotspot rows — labeled as popular, NOT as
   live activity (the emptiness-honesty rule). */
.bm-pulse-feed__badge {
  flex: none;
  margin-inline-start: auto;
  padding-block: 2px;
  padding-inline: var(--ag-space-1);
  border-radius: var(--ag-radius-sm);
  background: rgba(120, 150, 205, 0.16);
  color: var(--bm-dim);
  font-size: var(--ag-font-size-xs);
  font-weight: var(--ag-font-weight-semibold);
}

/* Honest empty state. */
.bm-pulse-feed__empty {
  padding-block: var(--ag-space-2);
}

.bm-pulse-feed__empty-title {
  color: var(--bm-text);
  font-size: var(--ag-font-size-sm);
  font-weight: var(--ag-font-weight-semibold);
}

.bm-pulse-feed__empty-sub {
  margin-block-end: var(--ag-space-2);
  color: var(--bm-dim);
  font-size: var(--ag-font-size-xs);
  font-weight: var(--ag-font-weight-medium);
}

@media (max-width: 820px) {
  .bm-pulse-feed {
    inline-size: min(280px, 88%);
  }
}

/* ==========================================================================
   13. Time machine — .bm-timemachine (W4 Task 7, The Pulse)
   Flag: web_pulse (pulse_on). A dark-glass scrubber panel docked
   inset-inline-start / inset-block-end that replays the map through time via the
   existing premium /globe/timelapse/ endpoint (gate() from W4 Task 6). Ships
   hidden (the [hidden] attribute the partial carries); the Layers-sheet's
   `data-bm-timemachine-open` row reveals it. Free / admin users get the honest
   client-side "last 3 h preview" — never a padlock wall. See mockup
   04-the-pulse.html.

   Same defensive token re-declaration as .bm-pulse-feed (section 12): the
   partial only renders inside the First Light chrome block so .bm-first-light is
   always present, but the panel re-declares its night-flight tokens anyway.
   Tokens + LOGICAL properties only — the RTL gate greps this file.
   ========================================================================== */
.bm-timemachine {
  --bm-panel: rgba(14, 22, 46, 0.86);
  --bm-line: rgba(120, 150, 205, 0.22);
  --bm-text: #eaf0fb;
  --bm-dim: #9daecc;
  --bm-faint: #6e7fa3;
  position: absolute;
  inset-block-end: var(--ag-space-4);
  inset-inline-start: var(--ag-space-4);
  inline-size: min(400px, 92%);
  display: flex;
  flex-direction: column;
  gap: var(--ag-space-2);
  padding: var(--ag-space-4);
  color: var(--bm-text);
  font-family: var(--ag-font-sans);
  z-index: 23;
}

.bm-timemachine[hidden] {
  display: none;
}

.bm-timemachine__head {
  display: flex;
  align-items: center;
  gap: var(--ag-space-2);
}

.bm-timemachine__title {
  color: var(--bm-text);
  font-size: var(--ag-font-size-md);
  font-weight: var(--ag-font-weight-semibold);
}

.bm-timemachine__badge {
  padding-block: 2px;
  padding-inline: var(--ag-space-1);
  border-radius: var(--ag-radius-sm);
  background: rgba(139, 92, 246, 0.18);
  color: #c4b5fd;
  font-size: var(--ag-font-size-xs);
  font-weight: var(--ag-font-weight-bold);
}

.bm-timemachine__close {
  margin-inline-start: auto;
  border: 0;
  background: transparent;
  color: var(--bm-dim);
  font-size: var(--ag-font-size-md);
  line-height: 1;
  cursor: pointer;
}

.bm-timemachine__close:focus-visible {
  outline: 2px solid var(--bm-text);
  outline-offset: 2px;
}

.bm-timemachine__scrubrow {
  display: flex;
  align-items: center;
  gap: var(--ag-space-2);
}

.bm-timemachine__play {
  flex: none;
  inline-size: 34px;
  block-size: 34px;
  border: 1px solid var(--bm-line);
  border-radius: var(--ag-radius-pill);
  background: rgba(120, 150, 205, 0.12);
  color: var(--bm-text);
  font-size: var(--ag-font-size-sm);
  cursor: pointer;
}

.bm-timemachine__play:hover {
  background: rgba(120, 150, 205, 0.2);
}

.bm-timemachine__play:focus-visible {
  outline: 2px solid var(--bm-text);
  outline-offset: 2px;
}

.bm-timemachine__scrub {
  flex: 1 1 auto;
  inline-size: 100%;
  accent-color: #2563eb;
}

.bm-timemachine__ticks {
  display: flex;
  justify-content: space-between;
  color: var(--bm-faint);
  font-size: var(--ag-font-size-xs);
  font-weight: var(--ag-font-weight-semibold);
}

.bm-timemachine__status {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.bm-timemachine__day {
  color: var(--bm-text);
  font-size: var(--ag-font-size-sm);
  font-weight: var(--ag-font-weight-semibold);
}

.bm-timemachine__note {
  color: var(--bm-dim);
  font-size: var(--ag-font-size-xs);
  font-weight: var(--ag-font-weight-medium);
}

/* --- Task 8: time-layer tab (tabs + panes + Past/Present/Future modes +
   the active-mode `bm-timelayer` chip). Tokens + logical properties only —
   the RTL gate greps this file. See templates/globe/partials/_time_machine.html
   and static/js/globe/pulse/timeMachine.js. --- */
.bm-timemachine__tabs {
  display: flex;
  gap: var(--ag-space-1);
}

.bm-timemachine__tab {
  flex: 1 1 auto;
  padding-block: var(--ag-space-1);
  padding-inline: var(--ag-space-2);
  border: 1px solid var(--bm-line);
  border-radius: var(--ag-radius-pill);
  background: rgba(120, 150, 205, 0.1);
  color: var(--bm-dim);
  font-size: var(--ag-font-size-xs);
  font-weight: var(--ag-font-weight-bold);
  cursor: pointer;
}

.bm-timemachine__tab[aria-selected="true"] {
  background: #2563eb;
  border-color: #2563eb;
  color: #fff;
}

.bm-timemachine__tab:focus-visible {
  outline: 2px solid var(--bm-text);
  outline-offset: 2px;
}

.bm-timemachine__pane {
  display: flex;
  flex-direction: column;
  gap: var(--ag-space-2);
}

.bm-timemachine__pane[hidden] {
  display: none;
}

.bm-timemachine__modes {
  display: flex;
  gap: var(--ag-space-1);
}

.bm-timemachine__mode {
  flex: 1 1 auto;
  padding-block: var(--ag-space-2);
  padding-inline: var(--ag-space-2);
  border: 1px solid var(--bm-line);
  border-radius: var(--ag-radius-md);
  background: rgba(120, 150, 205, 0.12);
  color: var(--bm-text);
  font-size: var(--ag-font-size-sm);
  font-weight: var(--ag-font-weight-semibold);
  cursor: pointer;
}

.bm-timemachine__mode:hover {
  background: rgba(120, 150, 205, 0.2);
}

.bm-timemachine__mode[aria-pressed="true"] {
  background: rgba(37, 99, 235, 0.9);
  border-color: #2563eb;
  color: #fff;
}

.bm-timemachine__mode:focus-visible {
  outline: 2px solid var(--bm-text);
  outline-offset: 2px;
}

/* Active-mode chip in the header — a blue accent distinct from the static
   purple "Globe Plus" badge; hidden until a Past/Present/Future mode is on. */
.bm-timelayer {
  padding-block: 2px;
  padding-inline: var(--ag-space-1);
  border-radius: var(--ag-radius-sm);
  background: rgba(37, 99, 235, 0.2);
  color: #bfdbfe;
  font-size: var(--ag-font-size-xs);
  font-weight: var(--ag-font-weight-bold);
}

.bm-timelayer[hidden] {
  display: none;
}

@media (max-width: 820px) {
  .bm-timemachine {
    inline-size: min(320px, 88%);
  }
}

/* ===========================================================================
   11. First-Light coexistence with the legacy globe chrome (flag-ON only).
   The Blue Marble overlay chrome (#bm-omni / #bm-rail / #bm-whisper) mounts
   as a sibling of the legacy controls, which previously kept rendering at
   the same coordinates: the legacy search pill (z=85) sat ON TOP of the
   omni (z=20), the legacy FAB stack (z=140, top:198px) occluded the rail's
   upper buttons, the whisper (z=19) was buried by #ag-date-bar (z=130),
   and the native Mapbox zoom/compass/fullscreen duplicated the rail one
   half-overlapped column to its right. Real user clicks hit the top layer,
   so "buttons did nothing". Everything below is scoped to .bm-first-light
   (stamped on #ag-globe-shell only when web_first_light is ON) — flag-off
   markup and layout stay byte-identical.
   ======================================================================== */

/* The omni + mode dock own search/filtering under First Light. */
.bm-first-light .ag-service-filters-floating {
  display: none !important;
}

/* Legacy FABs keep their unique tools (fit-all, list view, style, more) but
   move to the free bottom-right zone below the rail (rail ends ~y588; the
   date bar spans x273-927 so x~1146 stays clear). */
.bm-first-light .ag-map-fab-group {
  top: auto !important;
  bottom: 90px !important;
}
/* "Go to my location" duplicates the rail's Locate button. */
.bm-first-light #ag-fab-my-location {
  display: none !important;
}

/* Lift the whisper clear of the legacy date bar (54px tall, bottom-anchored). */
.bm-first-light #bm-whisper {
  bottom: 84px;
}

/* The rail provides zoom / compass / fullscreen — hide the duplicated native
   Mapbox control groups (keep any custom controls, e.g. rotation toggle). */
.bm-first-light .mapboxgl-ctrl-top-right .mapboxgl-ctrl-group:has(.mapboxgl-ctrl-zoom-in),
.bm-first-light .mapboxgl-ctrl-top-right .mapboxgl-ctrl-group:has(.mapboxgl-ctrl-compass),
.bm-first-light .mapboxgl-ctrl-top-right .mapboxgl-ctrl-group:has(.mapboxgl-ctrl-fullscreen) {
  display: none;
}

/* The legacy Drift toggle mounts on camera-idle at the same right-edge slot
   the relocated FABs use (it wasn't in the initial overlap map). Move it one
   column inboard so both stay fully hit-testable. */
.bm-first-light .ag-drift-btn {
  inset-inline-end: 76px !important;
}

/* ── Omni results: readable rows (they previously inherited the page ink →
   dark-on-dark over the globe) + paint ABOVE the mode dock. ─────────────── */
#bm-omni-results {
  z-index: 30;
  padding: 6px;
  /* open BELOW the mode dock (which sits directly under the omni pill) so the
     first group header isn't tucked behind the chips */
  inset-block-start: calc(100% + 56px);
}
#bm-omni-results [role="option"] {
  padding: 9px 12px;
  border-radius: 10px;
  color: var(--bm-text);
  font-size: 13.5px;
  line-height: 1.35;
  cursor: pointer;
}
#bm-omni-results [role="option"]:hover,
#bm-omni-results [role="option"][aria-selected="true"] {
  background: rgba(120, 150, 205, 0.16);
}
#bm-omni-results .bm-omni__group {
  padding: 10px 12px 3px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--bm-dim);
}

/* The "Advanced Tools" fab (#ag-dir-fab) OWNS the planner (#ag-dir) under
   First Light — the redundant dock "Trip" button was removed (2026-07-11,
   user request: keep Advanced Tools, drop the conflicting duplicate). The fab
   keeps its top-left slot; the mode dock is vertically centred on the left
   edge (#bm-dock top:50%), so they occupy different zones.
   Base .ag-dir__fab is display:none and only unhides via a sibling-class rule
   the First-Light planner (display:none, this file line ~40) never triggers —
   so force it available, and swap fab<->planner on a .bm-planner-open state
   toggled by a small inline controller in index.html (full-page first light
   only; it adds .bm-adv-tools so embeds keep the fab hidden). The
   .bm-planner-open !important flex beats both line-40 display:none and dock.js's
   stale inline display:none from an earlier mode switch. */
.bm-first-light.bm-adv-tools #ag-dir-fab { display: inline-flex !important; align-items: center; justify-content: center; }
.bm-first-light.bm-adv-tools.bm-planner-open #ag-dir-fab { display: none !important; }
.bm-first-light.bm-planner-open #ag-dir { display: flex !important; }
