/**
 * App frame: viewport sizing, safe areas, and portrait lock.
 *
 * Colour and type values are referenced as tokens with literal fallbacks so
 * this file renders correctly on its own; tokens.css supplies the real values.
 */

:root {
  /*
   * Safe-area insets. These resolve to 0px unless the document declares
   * `viewport-fit=cover` -- see index-v3.html, where that is load-bearing
   * rather than decorative.
   */
  --sat: env(safe-area-inset-top, 0px);
  --sar: env(safe-area-inset-right, 0px);
  --sab: env(safe-area-inset-bottom, 0px);
  --sal: env(safe-area-inset-left, 0px);

  /*
   * Conservative starting values. viewport.js overwrites --app-h with a
   * measured height on first frame; until then 100svh is correct but assumes
   * browser chrome is showing.
   */
  --app-h: 100svh;
  --kb: 0px;

  /* Persistent bottom chrome, and the space screens must leave for it. */
  --bar-h: 46px;
  --bar-inset: max(var(--space-xl, 18px), calc(var(--sab) + var(--space-sm, 8px)));

  /*
   * The bar is held back for this launch (see main.js), so screens reserve
   * only the home-indicator inset rather than the bar's height as well --
   * otherwise the composition leaves a band of empty space for chrome that is
   * not rendered. Swap these two lines back when the bar returns.
   */
  --bar-space: var(--bar-inset);
  /* --bar-space: calc(var(--bar-h) + var(--bar-inset)); */
}

* {
  box-sizing: border-box;
}

html,
body {
  height: 100%;
  margin: 0;
  overflow: hidden;
  /* No page-level scroll, so nothing rubber-bands behind the app. */
  overscroll-behavior: none;
  background: var(--surface-page, #050505);
  color: var(--text-primary, rgba(255, 255, 255, 0.9));
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  font-family: var(--font-sans, system-ui, sans-serif);
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
}

/**
 * The app frame. Height tracks the real visible area; the lvh clamp keeps a
 * transiently bogus measurement from overflowing the screen.
 */
.app {
  position: relative;
  width: 100%;
  height: min(var(--app-h), 100lvh);
  margin-inline: auto;
  overflow: hidden;
  background: var(--surface-app, #0a0a09);
  /* Own stacking context, so overlay z-indexes stay local to the app. */
  isolation: isolate;
}

/**
 * Portrait lock.
 *
 * The archive and curated tabs must never adopt a landscape layout. The
 * platform cannot enforce this: iOS Safari honours neither the manifest
 * `orientation` member nor screen.orientation.lock(). The manifest declaration
 * covers installed Chromium; this rule covers everything else, including
 * desktop browsers, by keeping the portrait composition and letterboxing it.
 *
 * The fullscreen player opts out of this via its own rotated layer -- it is the
 * only landscape surface in the app.
 */
@media (orientation: landscape) {
  body {
    display: grid;
    place-items: center;
  }

  .app {
    width: auto;
    max-width: 100%;
    aspect-ratio: 390 / 844;
    /*
     * Letterboxed and centred, so the frame no longer touches the device's
     * side edges -- consuming the horizontal insets here would add phantom
     * padding. Vertical insets still apply.
     */
    --sal: 0px;
    --sar: 0px;
  }
}

/**
 * Screens stack inside the frame. Only one browse-level screen is mounted at a
 * time; overlays (chat sheet, player) layer above.
 */
.screen-host,
.screen {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
}

.overlay-host {
  position: absolute;
  inset: 0;
  z-index: 10;
  /* Empty most of the time -- must not swallow taps meant for the screen. */
  pointer-events: none;
}

.overlay-host > * {
  pointer-events: auto;
}

/**
 * Backdrop, beneath everything including the dial.
 *
 * Three layers, topmost first:
 *   1. the draft's faint warm wash (written as a gradient because only the
 *      last layer of a background shorthand may be a plain colour)
 *   2. a scrim weighted to the left. The dial sweeps the left ~58% of the
 *      frame and draws its ticks at 10-32% white; the artwork's brightest ring
 *      striations sit in that same lower-left area and would swallow them.
 *      The right side is left lighter, where the content is opaque cards.
 *   3. the artwork itself
 */
.app::before {
  content: '';
  position: absolute;
  inset: 0;
  background:
    linear-gradient(var(--surface-tint), var(--surface-tint)),
    linear-gradient(
      100deg,
      rgba(10, 10, 9, 0.92),
      rgba(10, 10, 9, 0.78) 46%,
      rgba(10, 10, 9, 0.62)
    ),
    url('../assets/saturn-rings.png') center / cover no-repeat;
  pointer-events: none;
}

/* ---- Persistent bottom bar ---- */

.app-bar {
  position: absolute;
  left: max(var(--space-xl), var(--sal));
  right: max(var(--space-xl), var(--sar));
  bottom: var(--bar-inset);
  height: var(--bar-h);
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  pointer-events: none;
}

.app-bar > * {
  pointer-events: auto;
}

.tabs {
  height: 100%;
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 0 5px;
  background: rgba(35, 35, 32, 0.85);
  border: 1px solid var(--line-soft);
  border-radius: calc(var(--bar-h) / 2);
  backdrop-filter: blur(8px);
}

.tab {
  position: relative;
  border: 0;
  background: none;
  font-family: var(--font-sans);
  font-size: var(--fs-md);
  font-weight: 400;
  color: var(--text-muted);
  padding: 9px 16px;
  border-radius: var(--radius-lg);
  cursor: pointer;
  transition: background var(--dur-ui) var(--ease-out), color var(--dur-ui) var(--ease-out);
}

/*
 * Extends the touch target to a comfortable height without changing the pill.
 * The two-value shorthand matters: a single value would resolve its percentage
 * against the element's width on the inline sides and shrink the tap area
 * horizontally rather than growing it vertically.
 */
.tab::after {
  content: '';
  position: absolute;
  inset: calc((var(--tap-min) - 100%) / -2) 0;
}

.tab.is-active {
  background: var(--accent);
  color: var(--on-accent);
  font-weight: 500;
}

.fab {
  flex: none;
  width: var(--bar-h);
  height: var(--bar-h);
  border: 0;
  border-radius: 50%;
  background: #fff;
  color: var(--on-accent);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

/* The bar belongs to the browse-level screens, not to fullscreen overlays. */
.app.is-player-open .app-bar {
  display: none;
}

/* ---- Curated (contents not yet designed) ---- */

.curated {
  align-items: center;
  justify-content: center;
  padding: var(--gutter);
  padding-bottom: var(--bar-space);
}

.curated__empty {
  margin: 0;
  font-size: var(--fs-md);
  color: var(--text-dim);
  text-align: center;
}

/* ---- Controls ---- */

button {
  font: inherit;
  color: inherit;
  /* Removes the ~300ms double-tap-zoom delay on touch. */
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  -webkit-user-select: none;
  user-select: none;
}

/*
 * Visible focus for keyboard and switch access, without drawing a ring around
 * every tap target on touch.
 */
:where(button, a, input, [tabindex]):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}

/* Scroll containers keep their overscroll to themselves. */
.chat__list,
.player__topic-list {
  overscroll-behavior: contain;
}

/* On-device readout, enabled with ?debug=viewport. */
.debug-panel {
  position: fixed;
  z-index: 999;
  left: 8px;
  top: calc(env(safe-area-inset-top, 0px) + 8px);
  margin: 0;
  padding: 8px 10px;
  max-width: calc(100% - 16px);
  background: rgba(0, 0, 0, 0.82);
  border: 1px solid var(--accent-line);
  border-radius: 6px;
  font-family: var(--font-mono);
  font-size: 9.5px;
  line-height: 1.5;
  color: var(--accent);
  white-space: pre;
  pointer-events: none;
}

/* Utility: honour reduced-motion globally rather than per-component. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
