/* ============================================================================
 * spatial.css — The Spatial Feed: a native vertical-scroll feed in distance
 * BANDS with a pinned HERE origin. Gated by html[data-feed="spatial"].
 * Calm = Quiet + Predictable.
 * ========================================================================== */

/* When the Spatial Feed is on, the classic feed chrome is redundant — hide it,
 * and the carousel is parked (its data-tiles flag is independent). */
html[data-feed="spatial"] #nearby-feed,
html[data-feed="spatial"] #nearby-feed-followed-section,
html[data-feed="spatial"] #nearby-feed-other-section,
html[data-feed="spatial"] .filter-bar { display: none !important; }

#spatial-root { display: none; }
html[data-feed="spatial"] #spatial-root { display: block; }

/* (a) Kill the nearby scroller's TOP padding in spatial — it was a transparent
 * band above the sticky breadcrumb where scrolling tiles peeked through. NOTE the
 * nearby .screen-body carries an INLINE `padding-top:8px` (index.html), so this
 * needs `!important` to win; scoped to #nearby-screen so other screens keep their
 * top padding. With it gone the breadcrumb pins flush to the top bar. */
html[data-feed="spatial"] #nearby-screen .screen-body { padding-top: 0 !important; }

/* The wordmark breadcrumb (NEAR.me.<lens>.<show>) is redundant in the Spatial feed:
 * the read-only lens strip on the tiles carries the SAME realm + category PLUS the
 * My Tags/Everything axis the wordmark never had, so it's the fuller breadcrumb.
 * Collapse the top wordmark to a clean "NEAR.me". Nothing is orphaned — the controls
 * live in the Pulse radial (Me → Public/Friends, Show → People/Place/Thing).
 * Flag off → the wordmark breadcrumb returns. */
html[data-feed="spatial"] .wordmark-seg { display: none; }

/* ---- Lens Strip: synced, read-only chips of the active lenses (Realm · Follow ·
 * Category). Warm = mine (Friends/Following) · cool = open (Public/Everything);
 * categories reuse the canonical People-blue / Place-green / Thing-orange. */
/* Right-justified: the breadcrumb chips hug the right edge, mirroring where the
 * wordmark breadcrumb used to sit and leaving the left margin calm.
 * STICKY: the breadcrumb is the orientation device, so it stays pinned at the very
 * top of the scrollport throughout the scroll (z above band heads). Band headers
 * stick just BELOW it via --sp-lens-h (its measured height, set in JS each render). */
.sp-lens-strip {
  display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 6px; padding: 10px 2px 10px;
  position: sticky; top: 0; z-index: 7; background: var(--bg);
}
.sp-lens-chip {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: .7rem; font-weight: 700; padding: 3px 9px; border-radius: 999px;
  border: 1px solid var(--border); background: var(--surface); white-space: nowrap;
}
/* (c) Community-Review badge — LEFT-justified in the (otherwise right-justified)
 * strip via margin-right:auto, shown only when local shares await review. Tap →
 * the review queue. Gives this easily-missed civic function standing presence. */
.sp-review-badge {
  margin-right: auto;            /* pushes itself left, chips stay right */
  display: inline-flex; align-items: center; gap: 4px;
  font-family: inherit; font-size: .7rem; font-weight: 800; line-height: 1;
  padding: 3px 9px; border-radius: 999px; cursor: pointer; white-space: nowrap;
  color: var(--accent);
  border: 1px solid color-mix(in srgb, var(--accent) 50%, var(--border));
  background: color-mix(in srgb, var(--accent) 16%, transparent);
  -webkit-tap-highlight-color: transparent;
}
.sp-review-badge svg { width: 1.3em; height: 1.3em; display: block; }
.sp-review-num { font-variant-numeric: tabular-nums; }
/* Icon sizes in em (not px) so the chips track the a11y Text Size / OS text
 * scale — the breadcrumb was the accessibility complaint (beta, 2026-07-01). */
.sp-lens-chip svg { width: 1.2em; height: 1.2em; display: block; }
/* Live search token — leads the tiles (DOM order, so it lands just left of the
 * right-justified chip cluster). Reads as "the query these tiles are scoping":
 * neutral pill, the term emphasised, an inset ✕ that closes search. */
.sp-lens-search {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: .7rem; font-weight: 700; padding: 3px 5px 3px 9px; border-radius: 999px;
  border: 1px solid var(--border); background: var(--surface-2, var(--surface));
  color: var(--text); white-space: nowrap; max-width: 52vw;
}
.sp-lens-search svg { width: 1.2em; height: 1.2em; display: block; opacity: .7; }
.sp-lens-search-tx {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-variant: normal; font-style: italic;
}
.sp-lens-search-x {
  display: inline-flex; align-items: center; justify-content: center;
  margin-left: 1px; padding: 2px; border: 0; border-radius: 999px;
  background: transparent; color: var(--text-dim); cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.sp-lens-search-x:hover { color: var(--text); background: var(--surface); }
.sp-lens-search-x svg { width: 1.2em; height: 1.2em; opacity: 1; }
/* (#1) "just-changed" pulse — the chip whose axis changed flashes once so the
 * confirmation is unmissable even when your eye is on the Pulse. Halo + colour use
 * the chip's OWN hue (currentColor), so a Public flip glows cyan, Friends orange, etc. */
@keyframes sp-lens-pulse {
  0%   { transform: scale(1);    box-shadow: 0 0 0 0 currentColor; }
  35%  { transform: scale(1.12); }
  100% { transform: scale(1);    box-shadow: 0 0 0 8px transparent; }
}
.sp-lens-chip.sp-lens-pulse { animation: sp-lens-pulse .55s ease-out 1; }
@media (prefers-reduced-motion: reduce) { .sp-lens-chip.sp-lens-pulse { animation: none; } }
.lc-public,
.lc-everything { color: #2bb3d6; border-color: color-mix(in srgb, #2bb3d6 42%, var(--border)); background: color-mix(in srgb, #2bb3d6 10%, transparent); }
.lc-friends,
.lc-following  { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 42%, var(--border)); background: color-mix(in srgb, var(--accent) 9%, transparent); }
/* Subscribed = creators you follow: a distinct violet — "mine" like Friends, but
 * its own identity (a public-broadcast pull, not the private Link world). */
.lc-subscribed { color: #9b6cff; border-color: color-mix(in srgb, #9b6cff 42%, var(--border)); background: color-mix(in srgb, #9b6cff 12%, transparent); }
.lc-people { color: var(--info);    border-color: color-mix(in srgb, var(--info) 42%, var(--border));    background: color-mix(in srgb, var(--info) 9%, transparent); }
.lc-place  { color: var(--success); border-color: color-mix(in srgb, var(--success) 42%, var(--border)); background: color-mix(in srgb, var(--success) 9%, transparent); }
.lc-thing  { color: var(--accent);  border-color: color-mix(in srgb, var(--accent) 42%, var(--border));  background: color-mix(in srgb, var(--accent) 9%, transparent); }

/* ---- Distance band ---- */
.sp-band { margin: 0 0 4px; }
/* Sticky header = the wayfinding landmark ("which band am I in"). It occludes
 * scrolling tiles behind it (solid app-bg). top:0 sticks at the scrollport top
 * (the #top-bar banner sits above the scroll area). */
.sp-band-head {
  /* -1px: overlap the breadcrumb's bottom edge by a pixel so sub-pixel rounding of
   * --sp-lens-h can't leave a hairline gap where tiles peek through. The breadcrumb
   * (z7) paints over the overlap, so nothing shifts visually. */
  position: sticky; top: calc(var(--sp-lens-h, 0px) - 1px); z-index: 5;
  display: flex; align-items: center; gap: 8px;
  padding: 8px 2px 7px;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
  cursor: pointer; -webkit-tap-highlight-color: transparent;
}
/* Fold chevron — rotates to point right when the band is collapsed. */
.sp-band-chev { display: inline-flex; color: var(--text-dim); transition: transform .18s ease; }
.sp-band-chev svg { width: 1em; height: 1em; display: block; }
.sp-band-collapsed .sp-band-chev { transform: rotate(-90deg); }
.sp-band-collapsed .sp-band-body { display: none; }
/* Folded pill — a collapsed band must SAY what it's hiding (beta feedback: the
 * rotated chevron alone was overlooked and the band read as empty). Always in
 * the markup; revealed by the collapse class so the in-place toggle needs no
 * re-render. Replaces the right-edge count while folded. */
.sp-band-folded {
  display: none; color: var(--accent); font-size: .7rem; font-weight: 600;
  border: 1px dashed color-mix(in srgb, var(--accent) 45%, var(--border));
  background: color-mix(in srgb, var(--accent) 8%, transparent);
  border-radius: 999px; padding: 2px 9px; white-space: nowrap;
}
.sp-band-collapsed .sp-band-folded { display: inline-block; }
.sp-band-collapsed .sp-band-count { display: none; }
.sp-band-collapsed .sp-band-head { border-bottom-style: dashed; }
/* Collapsed + EMPTY = no tile at all, in every layout (beta 2026-07-02): the
   folded pill is reserved for bands actually concealing shares. The band
   reappears (as the "N hidden" pill) once content lands in its radius. */
.sp-band.sp-band-none.sp-band-collapsed { display: none; }
.sp-band-name { font-weight: 700; font-size: .84rem; letter-spacing: .3px; color: var(--text); }
.sp-band-range { color: var(--text-dim); font-size: .7rem; }
.sp-band-count {
  margin-left: auto; color: var(--text-dim); font-size: .7rem;
  font-variant-numeric: tabular-nums; min-width: 1em; text-align: right;
}

/* The band body hosts the real Share-Tile MOSAIC — the inner `.feed.layout-*`
 * (Grid-Packed columns or List) owns the layout, exactly like the classic feed.
 * Masonry is safe within a band (region-level memory; the band stays constant). */
/* (b) Indent the tile mosaic to the right — a left gutter, the way the
 * single-column layout sat. Header/labels stay at the margin. */
.sp-band-body { padding: 8px 0 14px 16px; }

.sp-band-empty {
  color: var(--text-dim); font-size: .75rem; font-style: italic; opacity: .65;
  padding: 6px 2px 12px;
}

/* ---- Step 2: FELT distance — size + dim stepped BY BAND (aerial perspective).
 * Nearer = full + crisp; farther = a touch smaller + gently hazier, so the world
 * recedes. Applied to the band BODY only (the header stays full-contrast — it's
 * the legible distance label / a11y backbone). `zoom` shrinks tiles AND their
 * footprint (denser horizon) with no transform gaps. Magnitudes are gentle/
 * "subtle" per owner; tune on device. Right Here = untouched (full). */
html[data-feed="spatial"] .sp-band-nearby .sp-band-body { opacity: .90; zoom: .96; }
html[data-feed="spatial"] .sp-band-reach  .sp-band-body { opacity: .76; zoom: .88; }
@media (prefers-reduced-motion: reduce) {
  /* keep the dim (it's static), drop nothing — these are not animations */
}

/* ---- (D) Category badge on the PHOTO — ported from the parked Stage UIX.
 * On photo tiles, lift the People/Place/Thing (+ Friends-only, Public view only)
 * badge out of the body and onto the image's bottom-left. `bottom:100%` of the
 * (relative) body anchors it just above the body = over the photo's bottom edge,
 * with no image-height math. Frees a row of vertical space; a dark chip keeps the
 * category hue legible over any photo. Text tiles keep the inline row. */
html[data-feed="spatial"] .feed-item.has-thumb .feed-body { position: relative; }
/* Span the photo's full width so category sits bottom-LEFT and the score star
 * (margin-left:auto) sits bottom-RIGHT — both riding the image. */
html[data-feed="spatial"] .feed-item.has-thumb .feed-listing-row {
  position: absolute; left: 6px; right: 6px; bottom: 100%; margin: 0 0 6px; z-index: 2; flex-wrap: nowrap;
}
html[data-feed="spatial"] .feed-item.has-thumb .feed-cat-badge,
html[data-feed="spatial"] .feed-item.has-thumb .wallet-score {
  background: rgba(18, 18, 20, 0.72); border-color: rgba(255, 255, 255, 0.18);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);   /* dark chip → stays legible over any photo */
}
html[data-feed="spatial"] .feed-item.has-thumb .feed-private-badge {
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
}

/* ---- Louder NEW (ported from the parked Stage Beta the owner preferred). The
 * subdued tinted border reads as "barely there"; here NEW gets a full accent RING
 * + a bold filled corner pill, so a fresh share is unmissable. Gated to spatial
 * so the classic feed keeps its quiet marker. */
html[data-feed="spatial"] .feed-item {
  position: relative;
  /* ring fades out smoothly when NEW decays (see below); border/bg stay snappy */
  transition: box-shadow .3s ease, border-color .15s, background-color .15s;
}
html[data-feed="spatial"] .feed-item.is-new {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent), 0 10px 26px -8px rgba(0, 0, 0, 0.5);
}
/* The bold corner pill. CRITICAL: its visibility is driven by `.is-new` via OPACITY
 * (not the element's presence) so it leaves at the SAME instant as the ring and
 * FADES rather than popping — and once a tile is seen it can't linger over the
 * category badge. (Bug: when dwell cleared `.is-new`, the ring vanished but the
 * pill element stayed and covered People/Place/Thing on text tiles.) */
.tile-new-pill { display: none; }   /* off entirely outside spatial */
html[data-feed="spatial"] .tile-new-pill {
  position: absolute; top: 8px; left: 8px; z-index: 3;
  display: inline-flex; align-items: center; gap: 3px;
  font-size: 10px; font-weight: 800; letter-spacing: .5px; text-transform: uppercase;
  color: #fff; background: var(--accent); border-radius: 8px; padding: 2px 7px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.45); white-space: nowrap;
  opacity: 0; pointer-events: none; transition: opacity .3s ease;   /* hidden until is-new */
}
html[data-feed="spatial"] .feed-item.is-new .tile-new-pill { opacity: 1; }
html[data-feed="spatial"] .tile-new-pill svg { width: 10px; height: 10px; display: block; }
/* Text tiles have no photo, so the corner pill would cover the top inline badge
 * row — drop the body down ONLY while NEW, easing back as it settles (no snap). */
html[data-feed="spatial"] .feed-item.no-thumb .feed-body { transition: padding-top .3s ease; }
html[data-feed="spatial"] .feed-item.no-thumb.is-new .feed-body { padding-top: 28px; }
@media (prefers-reduced-motion: reduce) {
  html[data-feed="spatial"] .feed-item,
  html[data-feed="spatial"] .tile-new-pill,
  html[data-feed="spatial"] .feed-item.no-thumb .feed-body { transition: none; }
}
/* The tiny meta-row "New" chip is redundant with the loud corner pill in spatial. */
html[data-feed="spatial"] .feed-item-meta .meta-new { display: none; }

/* ---- "N new" notification pill (canon) — the SINGLE warp affordance now the
 * joystick is retired. Surfaces whenever ANY new share is off-screen (above OR
 * below) so it's never lost; tap WARPS to the next one, closer-first. Filled
 * accent, fixed top-centre. The leading chevron points ↑ (toward HERE/closer)
 * by default and rotates to ↓ (.sp-newcue-down) when only farther ones remain. */
.sp-newcue {
  position: fixed; z-index: 132; display: none;
  /* Below the breadcrumb chip strip, never on it (beta 2026-07-02) — the strip's
     measured height is published on :root as --sp-lens-h. */
  top: calc(var(--top-bar-h, 56px) + env(safe-area-inset-top, 0px) + var(--sp-lens-h, 44px) + 8px);
  left: 50%; transform: translateX(-50%);
  align-items: center; gap: 6px; cursor: pointer;
  font-size: .78rem; font-weight: 700; color: #fff; background: var(--accent);
  border: none; border-radius: 999px; padding: 7px 15px;
  box-shadow: 0 8px 22px -4px rgba(0, 0, 0, 0.55);
  -webkit-tap-highlight-color: transparent;
}
html[data-feed="spatial"] .sp-newcue.on { display: inline-flex; }
.sp-newcue svg { width: 13px; height: 13px; display: block; transition: transform .15s ease; }
/* Only farther new remain → flip the ↑ chevron to ↓ (closer-first is exhausted). */
.sp-newcue.sp-newcue-down svg { transform: rotate(180deg); }
/* Out of the way while a modal / drawer / settings sheet is open. */
html[data-feed="spatial"]:has(.modal.open) .sp-newcue,
html[data-feed="spatial"]:has(.drawer.open) .sp-newcue,
html[data-feed="spatial"]:has(.appearance-overlay.open) .sp-newcue { display: none !important; }
@media (prefers-reduced-motion: reduce) { .sp-newcue { transition: none; } }

/* The breadcrumb chips are the controls — make them tappable. */
.sp-lens-tap { cursor: pointer; -webkit-tap-highlight-color: transparent; }
.sp-lens-tap:active { transform: scale(0.95); }
/* ⇄ affordance: was 0.82em/0.55 — too faint for low vision (Jody). */
.sp-lens-aff { margin-left: 3px; opacity: 0.8; font-size: 1em; }

/* Arrival pulse on the tile you warped to — a brief accent ring confirms "you're
 * here" WITHOUT marking it seen (warping = travel, not read; canon). */
@keyframes sp-warp-land {
  0%   { box-shadow: 0 0 0 0 var(--accent-glow); }
  100% { box-shadow: 0 0 0 16px transparent; }
}
.feed-item.sp-warp-land { animation: sp-warp-land .9s ease-out 1; }
@media (prefers-reduced-motion: reduce) { .feed-item.sp-warp-land { animation: none; } }

/* ============================================================================
 * First-run teach — two one-time coach cards mirroring PulseUIX's "Meet the
 * Pulse" (.pulse-teach). z BELOW the "N new" cue (132) so the cue pokes above
 * the dim = highlighted; backdrop is pointer-events:none so the chips stay
 * tappable while the card is up. The card hangs top-centre, just under the
 * lens strip + cue it teaches (the strip is in-flow, so no ring spotlight).
 * ========================================================================== */
.sp-teach { position: fixed; inset: 0; z-index: 128; display: none; pointer-events: none; }
html[data-feed="spatial"] .sp-teach.open { display: block; }
.sp-teach-backdrop { position: absolute; inset: 0; background: rgba(0, 0, 0, 0.5); }
.sp-teach-card {
  position: absolute; pointer-events: auto;
  left: 50%; transform: translateX(-50%);
  top: calc(var(--top-bar-h, 56px) + env(safe-area-inset-top, 0px) + var(--sp-lens-h, 44px) + 52px);
  max-width: 272px; width: calc(100vw - 48px);
  background: var(--surface); color: var(--text);
  border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-heavy); padding: 14px 16px;
}
.sp-teach-title { font-weight: 700; margin-bottom: 4px; }
.sp-teach-body { font-size: 13px; color: var(--text-dim); line-height: 1.45; }
.sp-teach-body b { color: var(--text); font-weight: 700; }
/* Inline icons in the teach copy sit on the text baseline. */
.sp-teach-ic { display: inline-flex; align-items: center; gap: 3px; white-space: nowrap; }
.sp-teach-ic svg { width: 14px; height: 14px; vertical-align: -2px; }
.sp-teach-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 12px; }
.sp-teach-skip { background: transparent; border: none; color: var(--text-dim); font: inherit; cursor: pointer; padding: 6px 10px; }
.sp-teach-got { background: var(--accent); color: #fff; border: none; border-radius: var(--radius); font: inherit; font-weight: 600; cursor: pointer; padding: 6px 14px; }

/* ============================================================================
 * THE HORIZON (Step 5) — the outer bookend of the spatial world.
 *   HERE (top, origin)  ⟷  Horizon (bottom, edge).
 * A calm inline end-cap (not a tile, not a popup) marking the radius limit, so the
 * world has a learnable EDGE instead of infinite-scroll amnesia. Voice = calm +
 * companion; the honest "more" is the physical world.
 * ========================================================================== */
.sp-horizon { text-align: center; padding: 28px 24px 16px; margin-top: 4px; }
.sp-horizon-line {
  height: 1px; max-width: 220px; margin: 0 auto 20px;
  background: linear-gradient(90deg, transparent, var(--border) 28%, var(--border) 72%, transparent);
}
.sp-horizon-lead { font-weight: 700; font-size: .9rem; color: var(--text); letter-spacing: .2px; }
.sp-horizon-sub {
  margin: 6px auto 0; max-width: 300px;
  font-size: .78rem; color: var(--text-dim); line-height: 1.5;
}
