/* Shell: nav, view switching, and the persistent video layer. */
:root {
  --app-bg: #ffffff;
  --app-fg: #0f0f10;
  --app-dim: #606069;
  --app-line: rgba(0, 0, 0, .12);
  --app-hover: rgba(0, 0, 0, .06);
  --app-tile: #e8e8ec;
  --app-accent: #22d37a;
  --app-nav-h: 62px;
}

body {
  margin: 0;
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

/* Light, matching exp-theme.css and the rest of the site. */
html[data-view="home"],
html[data-view="watch"],
body[data-view="home"],
body[data-view="watch"] {
  background: var(--app-bg) !important;
  color: var(--app-fg) !important;
}

/* ---- Header --------------------------------------------------------------- */
.app-header {
  position: sticky;
  top: 0;
  z-index: 300;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 24px;
  height: var(--app-nav-h);
  padding: 0 16px;
  background: var(--app-bg);
  border-bottom: 1px solid var(--app-line);
}
body[data-view="play"] .app-header { display: none; }

.app-header__brand {
  display: inline-flex;
  align-items: center;
  height: 40px;
}
.app-header__brand img { height: 34px; width: auto; display: block; }

.app-search {
  display: flex;
  justify-content: center;
  max-width: 640px;
  width: 100%;
  margin: 0 auto;
}
.app-search__input {
  flex: 1;
  min-width: 0;
  height: 38px;
  padding: 0 14px;
  font: inherit;
  font-size: 15px;
  color: var(--app-fg);
  background: #fff;
  border: 1px solid #c8c8ce;
  border-right: 0;
  border-radius: 19px 0 0 19px;
  outline: none;
}
.app-search__input::placeholder { color: #8b8b93; }
.app-search__input:focus { border-color: var(--app-accent); }
.app-search__go {
  display: grid;
  place-items: center;
  width: 60px;
  height: 38px;
  color: #3a3a42;
  background: #f2f2f4;
  border: 1px solid #c8c8ce;
  border-radius: 0 19px 19px 0;
  cursor: pointer;
}
.app-search__go:hover { background: #e6e6ea; }

.app-header__actions {
  display: flex;
  align-items: center;
  gap: 8px;
}
/* Beats .exp-social-link from exp-theme.css, which is kept on the profile link
   only because shared/auth.js selects it to show/hide on sign-in. */
.app-header .app-header__btn {
  display: inline-flex;
  align-items: center;
  height: 34px;
  padding: 0 13px;
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  text-decoration: none;
  color: var(--app-fg);
  background: transparent;
  border: 1px solid var(--app-line);
  border-radius: 999px;
  cursor: pointer;
  position: static;
  min-width: 0;
}
.app-header .app-header__btn:hover { background: var(--app-hover); }
.app-header .app-header__btn--solid { background: #f2f2f4; }
.app-header .app-header__btn--accent {
  background: var(--app-accent);
  border-color: var(--app-accent);
  color: #06210f;
}
.app-header .app-header__btn--accent:hover { filter: brightness(1.08); background: var(--app-accent); }
.app-header .app-header__btn--live {
  background: #e0203a;
  border-color: #e0203a;
  color: #fff;
}
.app-header .app-header__btn--live:hover { filter: brightness(1.08); background: #e0203a; }
/* Blue rather than the green accent so Play reads as its own thing next to
   Upload. #1b5fd9 is 5.7:1 against white — the label is only 13.5px, so it
   needs the full 4.5:1, which lighter blues like #1a73e8 (4.51) only just meet
   before hover brightness eats the margin. */
.app-header .app-header__btn--play {
  background: #1b5fd9;
  border-color: #1b5fd9;
  color: #fff;
}
.app-header .app-header__btn--play:hover { filter: brightness(1.1); background: #1b5fd9; }

/* ---- Filter chips --------------------------------------------------------- */
.app-chips {
  position: sticky;
  top: var(--app-nav-h);
  z-index: 200;
  display: flex;
  gap: 10px;
  overflow-x: auto;
  padding: 12px 0 14px;
  margin-bottom: 4px;
  background: var(--app-bg);
  scrollbar-width: none;
}
.app-chips::-webkit-scrollbar { display: none; }
.chip {
  flex: 0 0 auto;
  height: 32px;
  padding: 0 13px;
  font: inherit;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--app-fg);
  background: #f0f0f3;
  border: 0;
  border-radius: 999px;
  cursor: pointer;
}
.chip:hover { background: #e2e2e7; }
.chip.is-active { background: var(--app-fg); color: #fff; }

/* Narrow: the actions wrap to their own scrollable row under the search rather
   than being hidden — there is no menu button to bring them back. */
@media (max-width: 900px) {
  .app-header {
    grid-template-columns: auto minmax(0, 1fr);
    height: auto;
    gap: 10px 12px;
    padding: 10px 12px;
  }
  .app-header__actions {
    grid-column: 1 / -1;
    overflow-x: auto;
    padding-bottom: 2px;
    scrollbar-width: none;
  }
  .app-header__actions::-webkit-scrollbar { display: none; }
  .app-chips { top: 0; }
}

/* View switching. Only the active view is in the layout. */
.app-view { display: none; }
body[data-view="home"] #homeView { display: block; }
body[data-view="watch"] #watchView { display: grid; }

#gameRoot { display: none; }
body[data-view="play"] #gameRoot { display: block; }
body[data-view="play"] #viewRoot { display: none; }

/* The game owns the whole screen, including the nav. */
body[data-view="play"] .exp-social-nav { display: none; }
body[data-view="play"] { overflow: hidden; }

/* Home and watch are an ordinary scrolling page, not a locked game viewport.
   game.css locks html/body for the game; undo that outside the play view. */
body:not([data-view="play"]),
body:not([data-view="play"]) > #viewRoot {
  position: static;
  overflow: visible;
  height: auto;
  width: auto;
}
html:has(body:not([data-view="play"])) { overflow-y: auto; height: auto; }

#viewRoot {
  max-width: 1680px;
  margin: 0 auto;
  padding: 20px 24px 96px;
  position: relative;
  z-index: 1;
}

/* Persistent video layer. Never re-parented; positioned per dock target.
   Empty and inert until a slot is opened. */
#videoLayer {
  position: fixed;
  inset: 0;
  z-index: 40;
  pointer-events: none;
}
#videoLayer:empty { display: none; }
#videoLayer > * { pointer-events: auto; }

/* The legacy in-game thumbnail strip is retired — the Video-button picker replaces
   it. legacy-game.js re-parents this to <body> on the home map, so a stylesheet
   rule is the only thing that can guarantee it never covers the world again. */
#expVideoPanel { display: none !important; }

/* Share. Sits on live cards and in the live player bar. */
.share-btn {
  position: relative;
  align-self: flex-start;
  margin-top: 6px;
  padding: 5px 12px;
  font: inherit;
  font-size: 12.5px;
  font-weight: 700;
  color: var(--app-fg);
  background: var(--app-hover);
  border: 1px solid var(--app-line);
  border-radius: 999px;
  cursor: pointer;
}
.share-btn:hover { background: rgba(0, 0, 0, .12); }
.share-btn:disabled { opacity: .5; cursor: default; }
/* The result speaks for itself in a bubble rather than a browser alert. */
.share-btn--said::after {
  content: attr(data-msg);
  position: absolute;
  left: 0;
  bottom: calc(100% + 7px);
  z-index: 20;
  width: max-content;
  max-width: 260px;
  padding: 7px 11px;
  border-radius: 9px;
  background: rgba(12, 14, 18, .95);
  color: #fff;
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.35;
  white-space: normal;
}

/* Shown when a broadcast ends while viewers are still in the channel world. */
.live-ended-banner {
  position: fixed;
  left: 50%;
  bottom: 24px;
  transform: translateX(-50%);
  z-index: 500;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 16px;
  border-radius: 999px;
  background: rgba(12, 14, 18, .94);
  color: #fff;
  font-size: 14px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, .4);
}
.live-ended-banner[hidden] { display: none; }
.live-ended-banner__now {
  border: 1px solid rgba(255, 255, 255, .28);
  background: transparent;
  color: #fff;
  font: inherit;
  font-weight: 600;
  padding: 5px 12px;
  border-radius: 999px;
  cursor: pointer;
}
.live-ended-banner__now:hover { background: rgba(255, 255, 255, .14); }

.feed-status {
  color: var(--app-dim);
  padding: 32px 4px;
  font-size: 15px;
}
.feed-status[hidden] { display: none; }

.shelf-head {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 28px 0 12px;
}
.shelf-head h2 {
  font-size: 19px;
  font-weight: 700;
  margin: 0;
}

@media (max-width: 700px) {
  #viewRoot { padding: 12px 12px 80px; }
  :root { --app-nav-h: 54px; }
}

/* Signup consent. Shown at the moment of account creation, not only in the
   footer — that is where it has to be to mean anything. */
.hq-consent {
  margin: 10px 0 0;
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--app-dim);
}
.hq-consent a { color: #0b7a53; font-weight: 600; }

/* ---- Account overlay reachable outside the game --------------------------- */
/* The sign-in / create-account overlay is legacy game markup and lives inside
   #gameRoot, which the shell hides on every view except play. That left the
   header's Log In button working perfectly and showing nothing: the class was
   added to an element sealed inside a display:none container.
   While the modal is open outside the play view, reveal the container but show
   ONLY the overlay inside it, and pin it to the viewport (it is absolute inside
   the game stage, which is not laid out here). z-index clears the 300 header. */
body.exp-account-modal-open:not([data-view="play"]) #gameRoot { display: block; }
body.exp-account-modal-open:not([data-view="play"]) #gameRoot > *:not(.hq-shell) { display: none; }
body.exp-account-modal-open:not([data-view="play"]) .hq-shell > *:not(.hq-overlay) { display: none; }
body.exp-account-modal-open:not([data-view="play"]) .hq-overlay {
  position: fixed;
  inset: 0;
  z-index: 400;
}

/* The overlay opens on the game's loading card and legacy-game.js is what
   normally swaps it for the account panel once the engine boots. Outside the
   play view the engine never boots, so the modal sat on a spinner forever.
   Swap them here instead — the panel is what the header's Log In button is
   actually asking for. */
body.exp-account-modal-open:not([data-view="play"]) #hqLoadingCard { display: none; }
body.exp-account-modal-open:not([data-view="play"]) #hqEntryPanel { display: block; }

/* Game-only controls inside the shared account panel. "Go to previous map" is
   meaningless to someone signing in from the home page, and the boot status
   line never resolves because the engine is not running here. */
body.exp-account-modal-open:not([data-view="play"]) #hqPreviousMapBtn,
body.exp-account-modal-open:not([data-view="play"]) #hqEnterBtn { display: none; }

/* --------------------------------------------------------------- places */
/* The search suggestions panel and the homepage strip. Both deliberately
   understated: this is a video site, and places are a thing you go and find,
   not a thing that shouts at you on arrival. */

.app-search { position: relative; }

.place-suggest {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  right: 0;
  z-index: 60;
  background: var(--app-bg, #fff);
  border: 1px solid var(--app-line, rgba(0,0,0,.12));
  border-radius: 12px;
  box-shadow: 0 12px 34px rgba(0, 0, 0, .18);
  overflow: hidden;
  max-height: 60vh;
  overflow-y: auto;
}

.place-suggest__head {
  padding: 9px 14px;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--app-dim, #606069);
  border-bottom: 1px solid var(--app-line, rgba(0,0,0,.12));
}

.place-suggest__row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: baseline;
  gap: 4px 10px;
  padding: 10px 14px;
  text-decoration: none;
  color: inherit;
}

.place-suggest__row:hover { background: var(--app-hover, rgba(0,0,0,.06)); }

.place-suggest__type {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--app-dim, #606069);
}

.place-suggest__name {
  font-weight: 650;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.place-suggest__where { grid-column: 2; font-size: 12px; color: var(--app-dim, #606069); }
.place-suggest__count { font-size: 12px; color: var(--app-dim, #606069); white-space: nowrap; }

.places-band { margin: 22px 0; }

.places-band__prompt,
.places-band__card {
  display: block;
  padding: 18px 20px;
  border-radius: 14px;
  border: 1px solid var(--app-line, rgba(0,0,0,.12));
  background: linear-gradient(135deg, rgba(57, 223, 55, .12), rgba(22, 200, 210, .12));
  text-decoration: none;
  color: inherit;
}

.places-band__card:hover { filter: brightness(1.04); }
.places-band__prompt p { margin: 0 0 12px; }

.places-band__cta {
  display: inline-block;
  padding: 8px 18px;
  border-radius: 999px;
  background: linear-gradient(135deg, #39df37, #16c8d2);
  color: #08242c;
  font-weight: 750;
  text-decoration: none;
}

.places-band__name { font-size: 19px; font-weight: 780; }
.places-band__meta { font-size: 13px; color: var(--app-dim, #606069); margin-top: 2px; }
.places-band__exp { margin-top: 8px; font-size: 15px; font-weight: 700; }

/* A city is a different kind of answer to a school, so it does not look like
   one. Tinted and set apart, above the schools it contains. */
.place-suggest__row--city {
  background: linear-gradient(90deg, rgba(22, 200, 210, .13), rgba(22, 200, 210, .04));
  border-left: 3px solid var(--exp-turq, #16c8d2);
}
.place-suggest__row--city:hover { background: linear-gradient(90deg, rgba(22, 200, 210, .2), rgba(22, 200, 210, .07)); }
.place-suggest__row--city .place-suggest__type { color: var(--exp-turq, #16c8d2); font-weight: 800; }
