/* meta-watch — responsive layer.
 *
 * Loaded LAST (see index.html) so it wins over styles.css / player-ui.css /
 * release-tags.css without needing !important.
 *
 * ONE breakpoint system for the whole app — the ad-hoc 720px block that used to
 * live at the bottom of styles.css and the two 900px blocks in player-ui.css
 * were folded in here:
 *
 *   ≤ 640px   phone    bottom tab bar, compact topbar, 3-column posters
 *   641–1024  tablet   topbar retained, tighter gutters, 4-column posters
 *   > 1024px  desktop  nothing below applies — unchanged from before this file
 *
 * Above 640px the tab bar / sheet are display:none, which also removes them from
 * js/tv-nav.js's spatial navigation (isVisible() rejects zero-rect elements), so
 * the 10-foot UI is untouched.
 */

/* ═══════════════════════════════════════════════════════════════════════════
   Phone-only components: OFF by default, switched on inside the ≤640px block.
   Declared here (not in styles.css) so everything about them lives in one file,
   and so a desktop/TV render never has them in the layout or in tv-nav's
   focusables.
   ═══════════════════════════════════════════════════════════════════════════ */
.tabbar,
.mw-sheet-backdrop { display: none; }

/* ═══════════════════════════════════════════════════════════════════════════
   Coarse-pointer fixes — keyed off the INPUT DEVICE, not the width, because a
   touch laptop and a 1080p tablet both want these and neither is "small".
   ═══════════════════════════════════════════════════════════════════════════ */
@media (pointer: coarse) {
  /* `background-attachment: fixed` (styles.css) forces the compositor to repaint
     the gradient on every scroll frame — a well-known jank source on mobile
     Safari/Chrome. The gradient is decorative, so pin it to the viewport with
     position instead of attachment. */
  html, body { background-attachment: scroll; }
  /* Same reasoning: a blurred backdrop on a sticky element composites per frame.
     The topbar already carries an opaque-enough gradient without it. */
  .topbar { backdrop-filter: none; -webkit-backdrop-filter: none; }

  /* Touch has no hover, so affordances gated on it are invisible. Rails are
     swipeable, so the pager chevrons are redundant — hide them outright rather
     than leaving two dead 48px circles over the artwork. */
  .strip-arrow { display: none; }
  /* NOT unhidden here: `.card-fade`, whose play-dot is also :focus-gated. Its
     scrim would then sit over the bottom of every poster permanently, which
     costs more (dimmed artwork everywhere) than it buys — a poster in a
     streaming grid already reads as tappable. */
}

/* ═══════════════════════════════════════════════════════════════════════════
   Tablet — 641px … 1024px
   The topbar still fits; this is purely a density pass.
   ═══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 1024px) {
  :root { --gutter: 28px; --pad-x: 28px; --card-w: 140px; }

  .topbar { gap: 16px; padding: 12px 20px; }
  .topbar .nav-search { width: 170px; }
  .topbar .nav-search:focus-within { width: 200px; }

  .hero { height: 48vh; min-height: 320px; }
  .hero h1 { font-size: 40px; }
  .detail-inner { gap: 24px; padding: 32px var(--pad-x); }
  .detail-poster { width: 170px; }
  .detail-info h1 { font-size: 32px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Phone — ≤ 640px
   ═══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 640px) {
  /* ── Density tokens ──────────────────────────────────────────────────────
     --card-w drives BOTH the rails (fixed .card width) and the grid
     (minmax(--card-w, 1fr)). 96px is chosen so the grid lands on exactly 3
     columns and holds on a 360px device:
        360 − 2×14 gutter = 332 available
        3 cols: 3×96 + 2×10 gap = 308  ≤ 332  ✓
        4 cols: 4×96 + 3×10 gap = 414  > 332  ✓ (never 4)
     At 390px the tracks resolve to ~104px each, and rails show ~3.5 cards so the
     clipped card advertises that the row scrolls. */
  :root { --gutter: 14px; --pad-x: 14px; --card-w: 96px; }
  /* ── Topbar ───────────────────────────────────────────────────────────────
     Reduced to brand + search shortcut. Everything else moved to the sheet
     below, which is what removes the 839–919px overflow row. */
  .topbar {
    gap: 12px;
    padding: 10px 14px;
    padding-left: max(14px, env(safe-area-inset-left));
    padding-right: max(14px, env(safe-area-inset-right));
    padding-top: max(10px, env(safe-area-inset-top));
  }
  .brand { font-size: 17px; white-space: nowrap; min-height: 44px; }
  /* The bottom bar owns primary navigation now. */
  .topbar .nav { display: none; }
  .topbar-search-btn {
    display: inline-grid; place-items: center;
    width: 44px; height: 44px; border-radius: 50%;
    background: var(--bg-elev); border: 1px solid #262838;
    font-size: 17px; line-height: 1; flex: 0 0 auto;
  }

  /* ── The "More" sheet ─────────────────────────────────────────────────────
     Same nodes as the desktop topbar's secondary chrome; only the box they sit
     in changes (see index.html). Sits directly above the tab bar.

     ⚠ The sheet is a CHILD of .topbar, and `position: sticky` ALWAYS creates a
     stacking context — z-index plays no part in that rule. So the sheet's
     z-index below is scoped to the topbar's own layer (50, styles.css) and can
     never out-stack the backdrop (80), which lives in the root stacking
     context: the sheet painted *behind* the scrim and every tap landed on the
     backdrop, closing it again. Since the sheet must not be re-parented (see
     index.html), lift the whole topbar layer above the backdrop instead. The
     visible cost is that the scrim no longer dims the topbar — like the tab
     bar, which has always sat above it. Still below the tab bar (100), the
     stream drawer (100) and the identity modal (200). */
  .topbar { z-index: 90; }
  .topbar-extra {
    display: flex;
    position: fixed;
    left: 0; right: 0;
    bottom: calc(56px + env(safe-area-inset-bottom));
    z-index: 90;
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
    padding: 16px;
    background: var(--bg-card);
    border-top: 1px solid #262838;
    border-radius: 16px 16px 0 0;
    box-shadow: 0 -12px 32px rgba(0, 0, 0, .55);
    /* Closed state. Kept in the layout (not display:none) so the slide reads as
       a transition. `visibility: hidden` is what matters for correctness: it
       drops the sheet's controls out of the tab order and the a11y tree, which
       display:none-less alternatives like opacity:0 would not. */
    transform: translateY(110%);
    visibility: hidden;
    pointer-events: none;
    transition: transform .22s ease, visibility 0s linear .22s;
  }
  .topbar-extra.sheet-open {
    transform: translateY(0);
    visibility: visible;
    pointer-events: auto;
    transition: transform .22s ease, visibility 0s;
  }
  /* Overrides the default-off rule at the top of this file. */
  .mw-sheet-backdrop {
    display: block;
    position: fixed; inset: 0; z-index: 80;
    background: rgba(6, 7, 11, .6);
  }
  .mw-sheet-backdrop[hidden] { display: none; }
  body.mw-sheet-lock { overflow: hidden; }

  /* Inside the sheet each control is a full-width, comfortably tappable row. */
  .topbar-extra .nav-search { width: 100%; min-height: 44px; padding: 4px 14px; }
  .topbar-extra .nav-search:focus-within { width: 100%; }
  /* The <input> is the only focusable part of the pill, so it — not just the
     wrapper — has to carry the tap height. */
  .topbar-extra .nav-search input { align-self: stretch; min-height: 36px; }
  .topbar-extra .nav-ext,
  .topbar-extra .identity-chip,
  .topbar-extra .lang-pref-mini {
    justify-content: center;
    width: 100%;
    min-height: 44px;
    margin-left: 0;
    border-radius: 12px;
    font-size: 14px;
  }
  .topbar-extra .nav-ext { display: inline-flex; align-items: center; }
  /* [hidden] must still win over the display rules above. */
  .topbar-extra .nav-ext[hidden],
  .topbar-extra .identity-chip[hidden],
  .topbar-extra .qx-indicator[hidden] { display: none; }
  /* Popovers anchored to the desktop topbar would open off-screen (or upward
     into nothing) from inside the sheet — pin them to the sheet's own box. */
  .qx-popover {
    position: fixed;
    left: 14px; right: 14px; top: auto;
    bottom: calc(56px + env(safe-area-inset-bottom) + 12px);
    min-width: 0; max-width: none;
  }
  .lang-pref-popover {
    position: fixed;
    left: 14px; right: 14px; top: auto;
    bottom: calc(56px + env(safe-area-inset-bottom) + 12px);
    min-width: 0;
  }
  /* The 🐛 popover is a .qx-popover too, so it inherits the pinning above —
     only its desktop width has to let go, or it fights left/right. */
  .mw-report-popover { width: auto; }
  /* A lone emoji in a full-width sheet row says nothing; name it there. */
  .topbar-extra .mw-report-btn::after { content: " Report a problem"; }

  /* ── Bottom tab bar ───────────────────────────────────────────────────────*/
  /* Clear the tab bar — the badge's default 6px would put it behind it. */
  #mw-build { bottom: calc(56px + env(safe-area-inset-bottom) + 6px); }
  #mw-update { bottom: calc(56px + env(safe-area-inset-bottom) + 12px); }

  .tabbar {
    display: grid;
    /* Home · Search · Library · More. Column count is explicit, so it must be
       bumped alongside any tab added to `index.html`. */
    grid-template-columns: repeat(4, 1fr);
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 100;
    height: calc(56px + env(safe-area-inset-bottom));
    padding-bottom: env(safe-area-inset-bottom);
    background: rgba(16, 17, 26, .97);
    border-top: 1px solid #20222f;
  }
  .tabbar-item {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 2px;
    appearance: none; background: none; border: 0;
    color: var(--muted-2); font: inherit; font-size: 10.5px; font-weight: 600;
    cursor: pointer;
    /* The ring from styles.css's :focus rule would clip against the viewport
       edge on the outer tabs. */
    border-radius: 0;
  }
  .tabbar-icon { font-size: 19px; line-height: 1; }
  .tabbar-item.active { color: var(--fg); }
  .tabbar-item.active .tabbar-icon { filter: drop-shadow(0 0 8px var(--accent-glow)); }

  /* Content must clear the fixed bar. (.app already reserved 90px for its own
     bottom breathing room; this replaces it with bar + safe-area + the same.) */
  .app { padding-bottom: calc(56px + env(safe-area-inset-bottom) + 34px); }

  /* ── Rows / grid ──────────────────────────────────────────────────────────*/
  .grid { gap: 10px; padding: 8px var(--gutter) 16px; }
  .strip { gap: 10px; padding: 12px 0 16px; }
  .row { margin: 22px 0; }
  .row-head h2 { font-size: 17px; }
  .card-title { font-size: 12px; }
  .card-sub { font-size: 11px; }
  .card-meta { padding: 7px 2px 0; }

  /* ── Hero ─────────────────────────────────────────────────────────────────*/
  .hero { height: auto; min-height: 62vw; max-height: none; padding-top: 34vw; }
  .hero-inner { padding: 0 var(--pad-x) 26px; }
  .hero h1 { font-size: 27px; }
  .hero p { font-size: 14px; -webkit-line-clamp: 3; }
  .hero .actions { flex-wrap: wrap; gap: 10px; margin-top: 16px; }
  .hero .actions .btn { flex: 1 1 auto; justify-content: center; }

  /* ── Detail ───────────────────────────────────────────────────────────────
     Poster beside the title (Stremio-style), synopsis and actions full-width
     underneath — a synopsis crammed into a ~245px right-hand column is the
     thing to avoid here.
     `.detail-info` is `display: contents` so its five children (h1, .chips,
     .detail-desc, .hero-resume, .detail-actions — see js/detail/hero.js
     buildHero) become grid items of .detail-inner directly, letting the
     description and actions escape the poster's column without any DOM change.
     Keep this in sync if hero.js ever grows a SIXTH child: an unplaced item
     would land in an implicit row. */
  .detail-hero { min-height: 0; }
  .detail-inner {
    display: grid;
    /* `min-content`, not a fixed 100px: buildHero always emits .detail-poster
       but leaves it EMPTY when the record has no poster (common for raw gateway
       hits). Paired with the :empty rule below the whole column then collapses
       to 0 instead of indenting the title behind 100px of nothing. */
    grid-template-columns: min-content 1fr;
    grid-template-areas:
      "poster title"
      "poster chips"
      "desc    desc"
      "resume  resume"
      "actions actions";
    gap: 10px 14px;
    align-items: start;
    padding: 22px var(--pad-x) 20px;
  }
  .detail-poster { grid-area: poster; width: 100px; }
  .detail-poster:empty { display: none; }
  .detail-info { display: contents; }
  .detail-info h1 { grid-area: title; align-self: end; margin: 0; font-size: 21px; line-height: 1.2; }
  .detail-info .chips { grid-area: chips; align-self: start; margin: 0; }
  .detail-desc { grid-area: desc; font-size: 14px; line-height: 1.6; margin: 0; }
  /* Full width here rather than the desktop 420px — the bar is the answer to
     "how far in am I", and on a phone there's no competing content beside it.
     Its row collapses to zero height when hidden (no position yet); the one
     leftover 10px row-gap just reads as breathing room above the buttons. */
  .hero-resume { grid-area: resume; margin: 0; max-width: none; }
  .detail-actions { grid-area: actions; margin: 0; gap: 10px; }
  .detail-actions .btn { flex: 1 1 auto; justify-content: center; padding: 13px 14px; font-size: 14px; }

  /* ── Episodes ─────────────────────────────────────────────────────────────*/
  .season-tabs { gap: 6px; padding-bottom: 10px; margin-bottom: 14px; }
  .season-tab { padding: 9px 13px; font-size: 13px; min-height: 44px; }
  .ep-row { gap: 10px; padding: 8px 10px 8px 8px; }
  .ep-thumb { width: 104px; }
  .ep-name { font-size: 13.5px; }
  .ep-verinfo { font-size: 12px; white-space: normal; }
  .ep-cta { width: 36px; height: 36px; }

  /* ── Raw source rows ──────────────────────────────────────────────────────
     Two lines instead of one: chips on top, release name below, so nothing has
     to fit in a 290px single line. */
  .raw-row { flex-wrap: wrap; gap: 6px 8px; padding: 8px 10px; }
  .raw-row .raw-name { flex: 1 0 100%; white-space: normal; word-break: break-word; }
  .raw-note { font-size: 12px; }

  /* ── Stream drawer → bottom sheet ─────────────────────────────────────────*/
  /* Overlay mode only. The detail page's INLINE source view is in flow inside
     the releases section (it replaced the episode list); dragging it into a
     fixed bottom sheet here would put it back over the page it just took the
     place of. */
  .stream-drawer:not(.inline) .drawer-panel {
    top: auto; bottom: 0; right: 0; left: 0;
    width: 100%; height: 88vh;
    padding: 18px 16px calc(18px + env(safe-area-inset-bottom));
    border-left: 0;
    border-top: 1px solid #23263a;
    border-radius: 16px 16px 0 0;
    box-shadow: 0 -12px 40px rgba(0, 0, 0, .5);
    transform: translateY(100%);
  }
  .stream-drawer:not(.inline).open .drawer-panel { transform: translateY(0); }
  .drawer-title { font-size: 18px; }
  .drawer-close { width: 44px; height: 44px; }
  /* The inline Back button is a labelled pill, not a round dismiss — keep the
     touch height, drop the square. */
  .stream-drawer.inline .drawer-close { width: auto; height: 44px; }
  .stream-drawer.inline .drawer-list,
  .stream-drawer.inline .drawer-filters { max-width: none; }
  /* Narrow column → let the release name take three lines before clamping;
     two lines of a 290px row is barely half a scene name. */
  .stream-sub { max-width: none; -webkit-line-clamp: 3; }

  /* "Find more episodes" popover: 22rem inside a ~360px column overflows. */
  .findmore-pop {
    position: fixed;
    left: 14px; right: 14px; top: auto;
    bottom: calc(56px + env(safe-area-inset-bottom) + 12px);
    min-width: 0; max-width: none;
  }

  /* ── Search view ──────────────────────────────────────────────────────────*/
  .search-hero { padding: 20px var(--gutter) 4px; }
  .search-form { flex-wrap: wrap; }
  .search-form input { flex: 1 1 100%; }
  .search-form .btn { flex: 1 1 auto; justify-content: center; }
  /* The harvested suggestions wrapped to 7 rows and pushed the results grid off
     the first screen. One horizontally-scrollable line instead — the same shape
     as the poster rails, so it reads as swipeable. */
  .search-suggest {
    gap: 6px; margin-top: 10px;
    flex-wrap: nowrap; overflow-x: auto;
    scrollbar-width: none; -ms-overflow-style: none;
    padding-bottom: 2px;
  }
  .search-suggest::-webkit-scrollbar { display: none; }
  .search-suggest .chip { flex: 0 0 auto; white-space: nowrap; }
  .view-status { padding: 34px var(--gutter); font-size: 15px; }

  /* ── Player chrome ────────────────────────────────────────────────────────
     The watch view is immersive (body.mw-watching in styles.css), so the tab
     bar it used to have to reserve room for is hidden while it is up and the
     player owns the whole viewport, notch to home indicator. What is left here
     is density: the overlay is a lot of text on a 360px-wide screen, so it
     loses the synopsis and keeps only what identifies the stream.

     The safe-area insets matter more than they did: with no top bar above it,
     the overlay is what sits under the notch. */
  .now-playing-overlay {
    top: max(0.6rem, env(safe-area-inset-top));
    left: max(0.6rem, env(safe-area-inset-left));
    max-width: calc(100% - 1.6rem);
  }
  /* Two lines of synopsis is a third of a phone screen laid over the picture,
     and the ⓘ panel has the full text one tap away. */
  .now-playing-overlay .player-synopsis { display: none; }
  .mw-overlay-title { font-size: 15px; }

  .player-controls {
    padding-left: max(0.9rem, env(safe-area-inset-left));
    padding-right: max(0.9rem, env(safe-area-inset-right));
    padding-bottom: max(0.75rem, env(safe-area-inset-bottom));
  }
  .player-panel__head { padding-top: max(12px, env(safe-area-inset-top)); }
  .player-tech-grid { padding: 4px 14px 16px; }

  /* ── Modals ───────────────────────────────────────────────────────────────*/
  .identity-modal-card { margin-top: 4vh; padding: 16px; }
  .mw-acct-actions { flex-wrap: wrap; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Touch ergonomics — ≤ 1024px (phone AND tablet)
   ═══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 1024px) {
  /* iOS Safari zooms the page whenever a focused field is under 16px and never
     zooms back out. Every input in this app was 12–14px.
     The per-component selectors are repeated because a bare `input` rule loses
     the cascade to `.topbar .nav-search input` (0,2,1) and `.lang-pref-input`
     (0,1,0) — a specificity fight, not a source-order one, so `!important` is
     the only alternative and this is the cheaper option. */
  input, select, textarea,
  .topbar .nav-search input,
  .lang-pref-input,
  .identity-input,
  .search-form input { font-size: 16px; }

  /* 44px is the platform minimum for a reliable tap. These were 31–39px. */
  .nav a { padding: 12px 4px; min-height: 44px; display: inline-flex; align-items: center; }
  /* The pill is the visual control but only the <input> inside it takes focus,
     so the height has to reach both. */
  .topbar .nav-search { min-height: 44px; }
  .topbar .nav-search input { align-self: stretch; }
  .identity-chip { min-height: 44px; padding: 4px 12px; }
  .topbar .nav-ext { min-height: 44px; display: inline-flex; align-items: center; }
  .topbar .nav-ext[hidden] { display: none; }
  .lang-pref-mini { min-height: 44px; }
  /* Tap targets. `.filter-toggle` joins them; the inert `.stream-facet .stream-chip`
     deliberately does NOT — sizing it like a control is the first thing that
     would make a legend read as a row of buttons. */
  .lang-pref-chip, .filter-chip, .filter-reset, .filter-toggle { min-height: 34px; padding-top: 7px; padding-bottom: 7px; }
  .qx-item-stop { width: 32px; height: 32px; }
  .drawer-close { min-width: 44px; min-height: 44px; }
}
