/* Pixi effects layer over the radar bowl (prototype, owner flag). */
.fx-layer {
  position:fixed;
  inset:0;
  width:100vw;
  height:100vh;
  pointer-events:none;
  z-index:6
}

/* The radar canvas covers the whole viewport; the tab bar and the header must always sit above it, or the bowl
   dims the tabs and hides their badges whenever the stage runs long (2026-09-17 re-test, frames 044, 091). */
.bottom-nav,
.app-header {
  z-index:8
}

.setup-reminder {
  position:relative;
  z-index:8
}

/* Pixi draws the bubbles, dots, sweep and origin; the DOM versions stay for hits, focus and screen readers. */
body.scene-on .arc-profile .avatar,
body.scene-on .distance-dot>span,
body.scene-on .dot-origin,
body.scene-on .radar-sweep {
  opacity:0!important;
  box-shadow:none!important;
  filter:none!important
}

body.scene-on .arc-profile .bubble-hit:hover,
body.scene-on .arc-profile .bubble-hit:focus-visible {
  transform:none;
  filter:none
}

body.scene-on .here-pill,
body.scene-on .arc-new,
body.scene-on .stack-count {
  position:absolute;
  z-index:7
}


.bubble.photo video {
  display:block;
  width:100%;
  max-height:60vh;
  border-radius:12px;
  background:#000
}

#radial.fan .radial-ring {
  display:none
}

/* Profile accordion */
.acc {
  border:1px solid #2c4252;
  border-radius:14px;
  background:#0f1d27;
  margin:12px 0;
  overflow:hidden
}

.acc-head {
  display:flex;
  justify-content:space-between;
  align-items:center;
  gap:12px;
  width:100%;
  padding:14px 16px;
  background:none;
  border:0;
  color:var(--ink);
  font:inherit;
  font-weight:600;
  text-align:left;
  cursor:pointer
}

.acc-head small {
  display:block;
  font-weight:400;
  font-size:12px;
  color:var(--muted);
  margin-top:2px
}

.acc-head i {
  font-style:normal;
  font-size:22px;
  line-height:1;
  color:var(--muted);
  transition:transform .3s cubic-bezier(.2,.8,.2,1)
}

.acc.open .acc-head i {
  transform:rotate(90deg)
}

.acc-body {
  display:grid;
  grid-template-rows:0fr;
  visibility:hidden;
  transition:grid-template-rows .34s cubic-bezier(.2,.8,.2,1),visibility 0s linear .34s
}

.acc.open .acc-body {
  grid-template-rows:1fr;
  visibility:visible;
  transition:grid-template-rows .34s cubic-bezier(.2,.8,.2,1),visibility 0s
}

.acc-inner {
  min-height:0;
  overflow:hidden
}

.acc-pad {
  padding:2px 16px 16px
}

.acc-pad>fieldset:first-child,.acc-pad>.more-photos {
  margin-top:0
}

/* Me tab reorganisation: one section open at a time, scrolled under the sticky header. */
.me-acc {
  scroll-margin-top:calc(88px + env(safe-area-inset-top) + 12px)
}

.me-identity {
  display:flex;
  gap:14px;
  align-items:flex-start;
  margin:14px 0 6px
}

.me-identity-avatar .avatar {
  width:56px;
  height:56px
}

.me-identity-info {
  min-width:0;
  flex:1
}

.me-identity-info strong {
  display:block;
  font-size:17px
}

.me-identity-info small {
  display:block;
  color:var(--muted);
  font-size:13px;
  margin-top:2px
}

.me-identity-info .completion-card {
  margin:6px 0 0
}

.account-group {
  margin-top:28px;
  padding-top:6px;
  border-top:1px solid #2c4252
}

.account-group .list-heading {
  margin:14px 0 8px
}

.me-section.section-open #profile-form {
  padding-bottom:calc(64px + env(safe-area-inset-bottom))
}

.me-section.section-open #profile-form .profile-save {
  position:sticky;
  bottom:calc(var(--nav-h,calc(69px + env(safe-area-inset-bottom))) + 12px);
  z-index:4;
  box-shadow:0 -6px 18px rgba(0,0,0,.35)
}

/* Interest icons */
.hobby-grid {
  display:flex;
  flex-wrap:wrap;
  gap:8px
}

.hobby-chip,.hobby {
  position:relative
}

.hobby-chip input {
  position:absolute;
  opacity:0;
  width:1px;
  height:1px
}

.hobby-chip span,.hobby {
  display:grid;
  place-items:center;
  width:46px;
  height:46px;
  border-radius:14px;
  background:#132633;
  border:1px solid #2c4252;
  font-size:22px;
  cursor:pointer;
  -webkit-user-select:none;
  user-select:none;
  touch-action:manipulation;
  transition:transform .18s cubic-bezier(.2,.9,.3,1.3),background .18s,border-color .18s,box-shadow .18s
}

.hobby-chip:hover span,.hobby:hover {
  transform:translateY(-2px) scale(1.06)
}

.hobby-chip input:checked+span {
  background:#1e3f52;
  border-color:var(--ice);
  box-shadow:0 0 0 1px #b7deef33,0 6px 18px #0006
}

.hobby-chip input:focus-visible+span,.hobby:focus-visible {
  outline:2px solid var(--ice);
  outline-offset:2px
}

.hobby-chip:not(:has(input:checked)) span {
  filter:saturate(.35);
  opacity:.72
}

.hobby-chip:not(:has(input:checked)):hover span {
  filter:none;
  opacity:1
}

[data-tip]::after {
  content:attr(data-tip);
  position:absolute;
  left:50%;
  bottom:calc(100% + 6px);
  transform:translate(-50%,4px);
  padding:4px 8px;
  border-radius:8px;
  background:#e6f3fa;
  color:#10202b;
  font-size:11px;
  font-weight:600;
  white-space:nowrap;
  pointer-events:none;
  opacity:0;
  transition:opacity .15s,transform .15s;
  z-index:5
}

[data-tip]:hover::after,[data-tip]:focus-visible::after,[data-tip].tip-open::after,.hobby-chip:has(input:focus-visible)::after {
  opacity:1;
  transform:translate(-50%,0)
}

.hobby-row {
  display:flex;
  flex-wrap:wrap;
  gap:6px;
  margin:0 0 12px
}

.profile-interests {
  margin:0 0 18px;
  text-align:center
}

.profile-interests>span {
  display:block;
  margin-bottom:8px;
  color:var(--muted);
  font-size:12px
}

.profile-interests .hobby-row {
  justify-content:center;
  margin:0
}

.hobby {
  width:38px;
  height:38px;
  font-size:19px;
  cursor:default
}

/* Chat bubbles land with a little bounce; reactions pop. */
.msg-row.arrive {
  animation:bubble-in .38s cubic-bezier(.2,.9,.3,1.25) both
}

.msg-row.arrive.outgoing {
  transform-origin:bottom right
}

.msg-row.arrive.incoming {
  transform-origin:bottom left
}

@keyframes bubble-in {
  from {
    opacity:0;
    transform:translateY(14px) scale(.86)
  }

  to {
    opacity:1;
    transform:none
  }
}

.msg-reaction.pop {
  animation:reaction-pop .45s cubic-bezier(.2,.9,.3,1.4) both
}

@keyframes reaction-pop {
  0% {
    transform:scale(0) rotate(-20deg)
  }

  60% {
    transform:scale(1.35) rotate(6deg)
  }

  100% {
    transform:scale(1) rotate(0)
  }
}

@media (prefers-reduced-motion: reduce) {
  .msg-row.arrive,.msg-reaction.pop {
    animation:none
  }

  .acc-body,.acc-head i,.hobby-chip span,.hobby {
    transition:none
  }
}

/* Help */
.help-button {
  flex:none;
  width:34px;
  height:34px;
  margin-left:10px;
  border-radius:50%;
  border:1px solid #2c4252;
  background:#12222e;
  color:var(--ice);
  font:600 16px/1 inherit;
  font-family:inherit;
  cursor:pointer
}

.help-button[aria-expanded="true"] {
  background:var(--ice);
  color:#10202b
}

.help-backdrop {
  position:fixed;
  inset:0;
  z-index:29999;
  border:0;
  padding:0;
  background:#0008;
  opacity:0;
  transition:opacity .3s
}

.help-backdrop.open {
  opacity:1
}

.help-panel {
  position:fixed;
  left:0;
  right:0;
  top:0;
  z-index:30000;
  max-height:88vh;
  overflow:auto;
  margin:0 auto;
  max-width:560px;
  padding:calc(14px + env(safe-area-inset-top,0px)) 16px 20px;   /* clear the notch, clock and battery on phones */
  border-radius:0 0 22px 22px;
  background:#0c1a24;
  border:1px solid #2c4252;
  border-top:0;
  box-shadow:0 24px 60px #000a;
  transform:translateY(-104%);
  transition:transform .36s cubic-bezier(.2,.8,.2,1)
}

.help-panel.open {
  transform:none
}

.help-head {
  display:flex;
  align-items:center;
  justify-content:space-between;
  padding:6px 4px 8px;
  font-size:15px
}

.help-body .acc {
  margin:8px 0
}

.help-body p {
  margin:0;
  font-size:13.5px;
  line-height:1.55;
  color:#c9dae5
}

.legend {
  list-style:none;
  margin:0;
  padding:0;
  display:grid;
  gap:8px;
  font-size:13.5px;
  color:#c9dae5
}

.legend li {
  display:flex;
  align-items:center;
  gap:10px
}

.swatch {
  flex:none;
  width:16px;
  height:16px;
  border-radius:50%;
  background:var(--c);
  box-shadow:0 0 10px var(--c)
}

.swatch.ring {
  background:#1e3f52;
  box-shadow:0 0 0 2px var(--c)
}

.swatch.dashed {
  background:#1e3f52;
  box-shadow:none;
  border:2px dashed var(--c)
}

@media (prefers-reduced-motion: reduce) {
  .help-panel,.help-backdrop {
    transition:none
  }
}

/* Grid tiles wear the same status ring as the radar bubbles: green online, yellow linked, grey recent, amber = starred. */






.grid-profile.is-starred {
  outline:2px solid #ff9f43;
  outline-offset:2px
}

.grid-profile.is-starred:focus-visible {
  outline-color:#c7f6ff
}

/* Pull to refresh (grid, Activity, Chats) */
#pull-refresh {
  position:fixed;
  left:50%;
  top:calc(var(--header-h,59px) + 6px);
  z-index:8;
  display:flex;
  align-items:center;
  gap:8px;
  padding:6px 12px 6px 8px;
  border-radius:999px;
  background:#12222e;
  border:1px solid #2c4252;
  color:#c9dae5;
  font-size:12px;
  box-shadow:0 8px 24px #0008;
  opacity:0;
  transform:translate(-50%,calc(var(--pull,0px) - 48px));
  transition:opacity .2s,transform .15s;
  pointer-events:none
}

#pull-refresh.show {
  opacity:1
}

#pull-refresh i {
  width:16px;
  height:16px;
  border-radius:50%;
  border:2px solid #3b5566;
  border-top-color:var(--ice);
  transform:rotate(calc(var(--pull,0px) * 3deg));
  transition:transform .1s
}

#pull-refresh.armed i {
  border-color:var(--ice);
  border-top-color:#ffe45c
}

#pull-refresh.loading i {
  animation:pull-spin .7s linear infinite
}

@keyframes pull-spin {
  to {
    transform:rotate(360deg)
  }
}

.profile-grid {
  transform:translateY(var(--pull,0px));
  transition:transform .15s
}

/* The grid's next page is on its way, or that was everyone (John, 2026-09-27). */
.grid-more {
  display:flex;
  align-items:center;
  justify-content:center;
  gap:8px;
  min-height:48px;
  margin:10px 0 0;
  color:#9fb3c1;
  font-size:13px
}

.grid-more i {
  width:16px;
  height:16px;
  border-radius:50%;
  border:2px solid #3b5566;
  border-top-color:var(--ice);
  animation:pull-spin .7s linear infinite
}

body.grid-mode {
  overscroll-behavior-y:contain
}

/* Real map tiles are drawn by fx.js; the SVG line maps stand down while they are on. */
body.scene-map .radar-map-layer,
body.scene-map .stack-map-layer {
  display:none
}

/* MapLibre renders off-screen for fx.js; only the canvas positioning rules it needs. */
.ml-offscreen {
  position:fixed;
  left:0;
  top:0;
  width:2048px;
  height:2048px;
  opacity:0;
  pointer-events:none;
  z-index:-1;
  overflow:hidden
}

.ml-offscreen .maplibregl-canvas {
  position:absolute;
  left:0;
  top:0
}

/* Loading screen over the radar until the scene and map are ready (John, 2026-09-11). */
#scene-loader {
  position:fixed;
  inset:0;
  z-index:25000;
  display:flex;
  flex-direction:column;
  align-items:center;
  justify-content:center;
  gap:22px;
  background:radial-gradient(circle at 50% 60%,#0f2230 0,#08131b 60%);
  color:#c9dae5;
  opacity:0;
  visibility:hidden;
  transition:opacity .45s,visibility 0s linear .45s
}

body.scene-loading #scene-loader {
  opacity:1;
  visibility:visible;
  transition:none
}

/* The curtain belongs to the radar. Over the grid it has nothing to wait for, so it goes at once: its fade-out showed
   "Finding who's near you" through the cards after entering (testers, 2026-09-27). */
body.grid-mode #scene-loader {
  transition:none
}

#scene-loader p {
  margin:0;
  text-align:center;
  font-size:15px;
  font-weight:600;
  letter-spacing:.3px
}

#scene-loader p span {
  display:block;
  margin-top:6px;
  font-size:12px;
  font-weight:400;
  color:var(--muted)
}

.loader-rings {
  position:relative;
  width:120px;
  height:120px
}

.loader-rings i {
  position:absolute;
  inset:0;
  border-radius:50%;
  border:1.5px solid var(--ice);
  opacity:0;
  animation:loader-ring 2.1s ease-out infinite
}

.loader-rings i:nth-child(2) {
  animation-delay:.7s
}

.loader-rings i:nth-child(3) {
  animation-delay:1.4s
}

.loader-rings::after {
  content:"";
  position:absolute;
  left:50%;
  top:50%;
  width:8px;
  height:8px;
  margin:-4px 0 0 -4px;
  border-radius:50%;
  background:var(--ice);
  box-shadow:0 0 14px var(--ice)
}

@keyframes loader-ring {
  0% {
    transform:scale(.1);
    opacity:.9
  }

  100% {
    transform:scale(1);
    opacity:0
  }
}

@media (prefers-reduced-motion: reduce) {
  .loader-rings i {
    animation:none;
    opacity:.5;
    transform:scale(.6)
  }
}

/* Pixi draws the cluster stack; the CSS ghost discs would sit on top of it. The credit lives in Help now. */
body.scene-on .arc-profile.is-cluster::before,
body.scene-on .arc-profile.is-cluster::after,
.compass-field .map-credit {
  display:none
}

#scene-loader .credit {
  position:absolute;
  bottom:18px;
  left:0;
  right:0;
  text-align:center;
  font-size:11px;
  color:var(--muted)
}

/* The pitched ground map: a DOM layer under the Pixi canvas, sized and placed over the stage by fx.js. */
.ml-ground {
  position:fixed;
  left:0;
  top:0;
  z-index:5;
  pointer-events:none;
  overflow:hidden;
  opacity:.92;
  -webkit-mask-image:linear-gradient(to bottom,transparent 0,#000 14%,#000 84%,transparent 100%);
  mask-image:linear-gradient(to bottom,transparent 0,#000 14%,#000 84%,transparent 100%)
}

.ml-ground .maplibregl-canvas {
  position:absolute;
  left:0;
  top:0
}

body.scene-ground .stack-map-layer {
  display:none
}







.online-now {
  margin-left:auto;
  margin-right:6px;
  font-size:12px;
  color:var(--muted);
  white-space:nowrap
}

.online-now:empty {
  display:none
}

@media (max-width:480px) {
  .online-now {
    font-size:11px;
    margin-right:2px
  }

  .online-now .now {
    display:none
  }

  .header-discovery {
    gap:6px
  }
}

/* Header logo (John's art, 2026-09-12): background keyed out so it sits on any header colour. */
.wordmark img {
  display:block;
  height:34px;
  width:auto
}

@media (max-width:480px) {
  .wordmark img {
    height:30px
  }
}

/* Filter bar, slim and right-aligned, no pills (John, 2026-09-12: "less vertical.. maybe not in pills"). */
.discovery-filters,
.discover>.discovery-filters {
  justify-content:flex-end;
  gap:14px;
  height:30px;
  min-height:30px
}










/* The loading screen (John, 2026-09-19: "a cool loading screen with a suggestive animation, curtain stays up"):
   two silhouettes drift in from the edges toward the pulse and lean into each other, breathing; when the map is
   fully painted the whole thing lifts with a short zoom-through instead of a plain fade. */
.loader-scene {position:relative;width:220px;height:140px;display:flex;align-items:center;justify-content:center}
.loader-scene .loader-rings {position:absolute;left:50px;top:10px}
.loader-man {
  position:absolute;
  top:38px;
  width:64px;
  height:64px;
  border-radius:50%;
  overflow:hidden;
  background:#10293a;
  border:1.5px solid #6fffe066;
  box-shadow:0 0 22px #6fffe033;
  animation:loader-breathe 2.6s ease-in-out infinite
}
.loader-man>img {position:absolute;width:300%;height:300%;max-width:none;object-fit:fill;opacity:.92}
.loader-man>img.body-1 {left:-100%;top:0}
.loader-man>img.body-4 {left:-100%;top:-100%}
.loader-man.left {left:0;animation-name:loader-drift-left}
.loader-man.right {right:0;animation-name:loader-drift-right;animation-delay:.3s}
@keyframes loader-drift-left {
  0% {transform:translateX(-18px) rotate(-6deg);opacity:.55}
  50% {transform:translateX(26px) rotate(4deg);opacity:1}
  100% {transform:translateX(-18px) rotate(-6deg);opacity:.55}
}
@keyframes loader-drift-right {
  0% {transform:translateX(18px) rotate(6deg) scaleX(-1);opacity:.55}
  50% {transform:translateX(-26px) rotate(-4deg) scaleX(-1);opacity:1}
  100% {transform:translateX(18px) rotate(6deg) scaleX(-1);opacity:.55}
}
@keyframes loader-breathe {0%,100% {box-shadow:0 0 18px #6fffe022} 50% {box-shadow:0 0 34px #6fffe066}}
#scene-loader.lifting {opacity:0;visibility:hidden;transform:scale(1.14);transition:opacity .55s ease-in,transform .7s ease-in,visibility 0s linear .7s}
body.scene-loading #scene-loader.slow p span::after {content:" · still painting the map, one moment"}
@media (prefers-reduced-motion: reduce) {.loader-man {animation:none} #scene-loader.lifting {transform:none;transition:opacity .3s}}
/* Face swapped (John, 2026-09-27, U1): both faces shared with each other. A quiet mark, not a colour. */
.swatch.glyph {background:none;box-shadow:none;width:16px;text-align:center;font-style:normal;font-size:13px;line-height:16px;color:var(--c)}
.profile-top .face-swapped {display:inline-flex;align-self:center;align-items:baseline;gap:6px;width:auto;max-width:100%;margin:4px auto 6px;padding:3px 12px;border-radius:999px;border:1px solid #8fe3ff66;background:#8fe3ff14;color:#cfefff;font-size:12.5px;font-weight:600}
.profile-top .face-swapped b {color:#8fe3ff}
.profile-top .face-swapped small {font-weight:400;color:#9fb8c8;font-size:11.5px}
.grid-profile .grid-faceswap {flex:0 0 auto;font-size:11px;line-height:1;color:#8fe3ff;font-weight:700}
/* About's own "Who sees" (John, 2026-09-27, U4), right under the About field: same look as the health choice. */
/* Sexual health's "Who sees this" is the same kind of legend: on its own lines, clear of the chips (it sat 0 px from them). */
.stats-field .about-legend,.stats-field .health-legend {display:block;margin:4px 0 8px;font-weight:700}
.stats-field .about-legend small,.stats-field .health-legend small {display:block;font-weight:400;color:var(--muted);margin-top:2px}
.stats-field .about-vis {margin-bottom:14px}
