/* buka-watch · site.css - home and series chrome for the v2 shell.

   watch.css carries the tokens, the buttons, the episode grid and the
   player; this file is everything around them: the top bar, the hero
   carousel, the rails, the price card, continue watching, the bottom nav
   and the episodes sheet. gate.css stays the only stylesheet for the
   bottom-sheet overlays (the gate, the home signup sheet, the consent
   banner all reuse its .gate / .gate-sheet classes) - nothing here
   duplicates it.

   THE ROUTE SWITCH. One shell, five routes (home plus four series), and
   the middleware stamps which one on <html data-route>. These selectors
   are what makes the right view visible on a COLD LOAD, before any script
   runs - never toggle a view with inline styles or a `hidden` attribute
   set by app.js, or a viewer whose script fails sees every view stacked on
   top of each other.

   EVERY GROUP OF data-route SELECTORS IN THIS FILE IS AN ALLOWLIST, AND A
   SERIES LEFT OUT OF ONE FAILS SILENTLY. Out of the .view switch below it
   is a route that answers 200 with a blank page and nothing in any log;
   out of the .topbar-home / .topbar-share groups it is a series page with
   no way back to home and no share control; out of the .topbar-links group
   (in the desktop media query further down) it is the home navigation
   showing on a series page. Four groups, four series each - add a new
   series to all of them in the same commit. */
@import url('./fonts.css');

.view { display: none; }
html[data-route="home"] .view-home { display: block; }
html[data-route="atb"] [data-series-view="atb"] { display: block; }
html[data-route="mog"] [data-series-view="mog"] { display: block; }
html[data-route="fiela"] [data-series-view="fiela"] { display: block; }
html[data-route="dod"] [data-series-view="dod"] { display: block; }

/* ---- top bar --------------------------------------------------------
   Left-aligned brand at every width (25 Sep 2026: centred on desktop, it sat
   over the empty half of a wide screen and read as "pushed right"). On
   desktop the bar's padding lines the brand up with the page's own content
   column, --shell, set further down. Home and series pages
   share one header; which of the three right-hand controls shows is
   route-dependent, not JS-toggled, for the same cold-load reason as the
   views themselves. */
.topbar { position: relative; justify-content: flex-start; gap: 12px; }
.topbar-links { display: none; }
.topbar-home,
.topbar-share {
  display: none;
  margin-left: auto;
  min-width: var(--tap);
  min-height: var(--tap);
  align-items: center;
  justify-content: center;
  background: none;
  border: 0;
  border-radius: 999px;
  color: var(--text);
  cursor: pointer;
}
html[data-route="atb"] .topbar-home,
html[data-route="mog"] .topbar-home,
html[data-route="fiela"] .topbar-home,
html[data-route="dod"] .topbar-home {
  display: flex;
}
html[data-route="atb"] .topbar-share,
html[data-route="mog"] .topbar-share,
html[data-route="fiela"] .topbar-share,
html[data-route="dod"] .topbar-share {
  display: flex;
  margin-left: 0;
}
html[data-route="home"] .topbar-home,
html[data-route="home"] .topbar-share {
  display: none;
}

/* Home icon and share icon (20 Sep 2026, Phil on an iPhone). These were drawn
   in CSS out of borders and triangles so neither cost a request - and on a
   real handset they read as two grey fragments, not as controls. The mark is
   now an inline <svg> inside the same span in index.html, which still costs
   no request, inherits currentColor and is recognisable at 20px. Nothing here
   paints a shape any more: the span is a box, the svg fills it. */
.icon-home,
.icon-share {
  display: block;
  width: 20px;
  height: 20px;
  opacity: 0.8;
}
.icon-home svg,
.icon-share svg { width: 100%; height: 100%; }
.topbar-home:hover .icon-home,
.topbar-home:active .icon-home,
.topbar-share:hover .icon-share,
.topbar-share:active .icon-share { opacity: 1; }

@media (min-width: 768px) {
  .topbar { padding-inline: max(var(--gutter), calc((100% - var(--shell, var(--max))) / 2 + var(--gutter))); }
  .topbar-links {
    display: flex;
    gap: 24px;
    margin-left: auto;
    font-size: 14px;
    font-weight: 600;
    color: var(--text-mut);
  }
  .topbar-links a { color: inherit; text-decoration: none; }
  .topbar-links a:hover { color: var(--white); }
  html[data-route="home"] .topbar-links { display: flex; }
  html[data-route="atb"] .topbar-links,
  html[data-route="mog"] .topbar-links,
  html[data-route="fiela"] .topbar-links,
  html[data-route="dod"] .topbar-links {
    display: none;
  }
  .topbar-home,
  .topbar-share { position: relative; z-index: 1; }
}

/* ---- home view -------------------------------------------------------- */
.view-home { max-width: var(--max); margin-inline: auto; padding-bottom: 64px; }

.genre-chip {
  display: inline-block;
  font: 500 11px/1.4 var(--mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--amber);
  margin: 0 0 4px;
}

/* ---- continue watching ---- */
.continue-card {
  display: grid;
  gap: 2px;
  margin: 16px var(--gutter) 0;
  padding: 14px 16px;
  background: var(--ink-800);
  border: 1px solid var(--ink-600);
  border-radius: var(--r-md);
  text-decoration: none;
}
.continue-label {
  font: 500 10px/1 var(--mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--amber);
}
.continue-title { color: var(--white); font-weight: 700; font-size: 15px; }

/* ---- hero carousel ----
   Swipe on touch via native horizontal scroll-snap - no JS gesture layer,
   which is the one thing this whole build refuses to add to the player and
   is not owed to the carousel either. Auto-advance is deliberately absent
   (plan §4): in-app browsers stutter on timed animation. */
.hero-carousel { margin-top: 8px; }
.hero-track {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.hero-track::-webkit-scrollbar { display: none; }
.hero-slide {
  flex: 0 0 100%;
  scroll-snap-align: start;
  position: relative;
}
.hero-slide picture,
.hero-slide img { width: 100%; }
.hero-slide img {
  height: auto;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  object-position: center 45%;
  max-height: 46svh;
}
.hero-slide::after {
  content: '';
  position: absolute;
  inset: auto 0 0 0;
  height: 55%;
  background: linear-gradient(to bottom, rgba(10, 10, 10, 0), var(--ink) 92%);
  pointer-events: none;
}
.hero-slide-copy {
  position: relative;
  z-index: 1;
  margin-top: -72px;
  padding: 0 var(--gutter);
  display: grid;
  gap: 10px;
}
.hero-slide-copy .synopsis { max-width: 46ch; }
.hero-dots { display: flex; justify-content: center; gap: 6px; margin: 10px 0 4px; }
.hero-dots .dot {
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: var(--ink-600);
}
.hero-dots .dot.is-active { background: var(--amber); }

/* ---- rails ---- */
.rail { padding: 28px var(--gutter) 0; }
.rail h2 { font-size: 15px; font-weight: 700; letter-spacing: -0.01em; margin-bottom: 12px; }
.rail-track {
  display: flex;
  gap: 12px;
  overflow-x: auto;
  scrollbar-width: none;
  padding-bottom: 2px;
}
.rail-track::-webkit-scrollbar { display: none; }
.rail-card {
  flex: 0 0 128px;
  position: relative;
  display: grid;
  gap: 6px;
  color: var(--text);
  text-decoration: none;
}
.rail-card picture,
.rail-card img { width: 100%; border-radius: var(--r-md); }
/* height: auto overrides the HTML width/height attributes' own presentational
   hint, which otherwise wins over aspect-ratio and renders the poster at its
   full intrinsic pixel height inside a 128px-wide card. */
.rail-card img { height: auto; aspect-ratio: 9 / 16; object-fit: cover; background: var(--ink-700); }
.rail-badge {
  position: absolute;
  top: 8px;
  left: 8px;
  font: 500 10px/1 var(--mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink);
  background: var(--amber);
  border-radius: 999px;
  padding: 4px 8px;
}
.rail-card-title { font-size: 13px; font-weight: 700; color: var(--white); line-height: 1.3; }
.rail-card-note { font-size: 11px; color: var(--text-mut); line-height: 1.35; }
.rail-card--soon img { opacity: 0.88; }
.rail-cta { max-width: 320px; margin: 16px auto 0; }

/* ---- series kind tag: what a title IS, read before what it costs ----
   "Buka Original" on mog, atb and fiela, "Dubbed" on dod (17 Sep 2026). The
   label is in the markup rather than generated, so it is in the first paint
   on a handset that never reaches app.js; config.js's `kind` is the same fact
   in the data, and lib/catalogue-lockstep.test.ts asserts the two agree.

   DELIBERATELY QUIETER THAN .rail-badge. The badge is amber on ink because
   the price is the loudest thing on a card and should stay so; this is an
   outlined pill in muted text. It is information a buyer is entitled to, not
   a sales line, and an amber second pill beside an amber first one would read
   as two competing offers.

   `justify-self: start` because all three of its parents - .rail-card,
   .title-card and .hero-slide-copy - are grids, and without it the pill
   stretches the full column and stops looking like a pill. */
.series-tag {
  justify-self: start;
  font: 500 10px/1 var(--mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-mut);
  background: rgba(250, 250, 250, 0.04);
  border: 1px solid var(--ink-600);
  border-radius: 999px;
  padding: 4px 8px;
  white-space: nowrap;
}

/* ---- price card: Hektik's "price before the gate" ---- */
.price-card {
  margin: 4px 0 0;
  padding: 12px 14px;
  background: rgba(245, 180, 5, 0.08);
  border: 1px solid rgba(245, 180, 5, 0.35);
  border-radius: var(--r-md);
  color: var(--text);
  font-size: 13px;
  line-height: 1.5;
  font-family: var(--mono);
}

/* ---- series title card (replaces the old .hero on series pages) ---- */
.title-card { max-width: var(--max); margin-inline: auto; padding: 20px var(--gutter) 0; display: grid; gap: 10px; }
.title-card .subtitle { color: var(--text-mut); font-size: 14px; margin-top: -6px; }
/* THE HEIGHT ATTRIBUTE HAS TO BE RESET HERE TOO, exactly as on .rail-card img
   above (20 Sep 2026, Phil on an iPhone). Every poster ships 800x1434, and the
   tag carries width= and height= to reserve its box - so `width: 100%` on its
   own left height=1434 standing and a 260px card rendered the key art at
   260x1434, a 5.5:1 smear on both Fiela and Duty or Desire. The attributes
   stay (they are what stops the layout shift); this is what turns them back
   into a ratio. The earlier note here said Fiela's master was an uncropped
   2.40:1 frame inside a vertical card - that was the SVG placeholder, and the
   real key art replaced it on 19 Sep 2026. */
.title-card-poster { max-width: 260px; margin: 0 0 4px; }
.title-card-poster img {
  width: 100%;
  height: auto;
  aspect-ratio: 9 / 16;
  object-fit: cover;
  background: var(--ink-700);
  border-radius: var(--r-md);
}
/* mog and atb carry a poster for desktop only; the phone card stays text-first. */
.title-card-poster--wide { display: none; }

/* ---- series page, desktop: poster left, copy right ---------------------
   25 Sep 2026, Phil on a 2000px laptop. Before this there was NO desktop
   layout: the title card was a 640px column centred in the window, mog and
   atb had no poster at all, and .episodes (no max-width) ran from the left
   edge of the window - so the copy floated right of a blank half-screen and
   the episode row sat under nothing. Now the whole view is one 1120px
   container, the poster takes column 1 and every other child column 2.

   THE LAST ROW IS 1fr ON PURPOSE. The poster spans every row; if all rows
   were auto, the grid would spread the poster's extra height across them and
   pull the copy apart. A final flexible row soaks it up, so the copy packs to
   the top. Ten auto rows is more than any card has (dod uses eight). */
@media (min-width: 1024px) {
  html:not([data-route="home"]) { --shell: 1120px; }
  .view-series { max-width: var(--shell); margin-inline: auto; }
  .view-series .title-card {
    max-width: none;
    padding-top: 40px;
    grid-template-columns: 300px minmax(0, 1fr);
    grid-template-rows: repeat(10, auto) 1fr;
    column-gap: 48px;
    align-items: start;
  }
  .view-series .title-card > * { grid-column: 2; max-width: 640px; }
  .view-series .title-card > .title-card-poster {
    display: block;
    grid-column: 1;
    grid-row: 1 / -1;
    max-width: none;
    margin: 0;
  }
  main.view-series .site-foot { max-width: none; }
}

/* ---- footer / bottom nav ---- */
.view-series .site-foot,
.view-home .site-foot { max-width: var(--max); margin-inline: auto; }
.site-foot a { color: var(--amber); text-decoration: underline; }

.bottom-nav {
  display: none;
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 15;
  padding: 6px var(--gutter) calc(6px + env(safe-area-inset-bottom));
  background: var(--ink-800);
  border-top: 1px solid var(--ink-600);
}
@media (max-width: 767px) {
  html[data-route="home"] .bottom-nav { display: flex; justify-content: space-around; }
  html[data-route="home"] .view-home { padding-bottom: calc(84px + env(safe-area-inset-bottom)); }
}
.bn-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  min-width: var(--tap);
  padding: 4px 8px;
  color: var(--text-mut);
  font-size: 10px;
  font-weight: 600;
  text-decoration: none;
}
/* Each .bn-icon used to be `background: currentColor` - a grey rounded
   square, which is what a placeholder looks like, because it was one. The
   span now holds an inline <svg> (index.html) and paints nothing itself. */
.bn-icon { width: 20px; height: 20px; display: block; opacity: 0.6; }
.bn-icon svg { width: 100%; height: 100%; }
.bn-item:active .bn-icon,
.bn-item:hover .bn-icon { opacity: 1; }
.bn-item:active,
.bn-item:hover { color: var(--amber); }

/* ---- episodes sheet: slides over #stage ----
   Same visual language as the gate's bottom sheet in gate.css, kept
   separate because it sits over the player rather than the episode list
   and must not compete with the gate's own z-index. */
.ep-sheet { position: fixed; inset: 0; z-index: 25; display: flex; align-items: flex-end; justify-content: center; }
.ep-sheet-backdrop { position: absolute; inset: 0; background: rgba(10, 10, 10, 0.72); }
.ep-sheet-panel {
  position: relative;
  width: 100%;
  max-width: 520px;
  max-height: 78svh;
  overflow-y: auto;
  background: var(--ink-800);
  border: 1px solid var(--ink-600);
  border-bottom: 0;
  border-radius: var(--r-lg) var(--r-lg) 0 0;
  padding: 16px var(--gutter) calc(20px + env(safe-area-inset-bottom));
}
.ep-sheet-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
.ep-sheet-title { font-weight: 700; color: var(--white); font-size: 15px; }
.ep-sheet-close {
  min-width: var(--tap);
  min-height: var(--tap);
  background: none;
  border: 0;
  color: var(--text-mut);
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
}

/* ---- consent banner actions ---- */
.consent-actions { display: flex; gap: 10px; margin-top: 4px; }
.consent-actions .btn { width: auto; flex: 1; }
