/* ------------------------------------------------------------------
   Crunchyflix dashboard
   Palette and surface treatment follow Seerr: gray-900 base,
   indigo accent, translucent panels ringed in white at low alpha.
   ------------------------------------------------------------------ */

:root {
  --bg:            #0b0e14;
  --bg-raise:      #111827;
  --panel:         rgba(17, 24, 39, .62);
  --panel-solid:   #161d2b;
  --ring:          rgba(255, 255, 255, .10);
  --ring-strong:   rgba(255, 255, 255, .18);
  --accent:        #6366f1;
  --accent-bright: #818cf8;
  --accent-deep:   #4338ca;
  --text:          #f3f4f6;
  --text-dim:      #9ca3af;
  --text-faint:    #8b96a8;   /* small labels over stills need the contrast */
  --up:            #34d399;
  --down:          #f87171;
  --warn:          #fbbf24;

  /* The content column: three tiles across plus the two gaps between them.
     auto-fit decides how many tracks fit using the MAX track size, so the
     column has to be at least this wide or you silently get two. */
  --tile-w:        300px;
  --tile-gap:      14px;
  --lift:          6px;          /* hover travel + a little shadow */
  --col:           calc(var(--tile-w) * 3 + var(--tile-gap) * 2);

  --radius:        14px;
  --radius-lg:     20px;
  --shadow:        0 10px 30px -12px rgba(0, 0, 0, .7);
  --font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
          'Helvetica Neue', Arial, sans-serif;
}

* { box-sizing: border-box; }

/* Several components below set an explicit display, which would otherwise
   beat the hidden attribute the script relies on for filtering. */
[hidden] { display: none !important; }

html, body { height: 100%; }

body {
  margin: 0;
  font-family: var(--font);
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

a { color: inherit; text-decoration: none; }

svg { fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

:focus-visible {
  outline: 2px solid var(--accent-bright);
  outline-offset: 3px;
  border-radius: 6px;
}

/* ---------------------------------------------------------------- backdrop */

.backdrop { position: fixed; inset: 0; z-index: 0; background: var(--bg); }

/* No stills available — the page still needs to look deliberate. */
.backdrop.is-fallback {
  background:
    radial-gradient(90% 60% at 15% 0%, rgba(67, 56, 202, .38), transparent 60%),
    radial-gradient(70% 50% at 90% 20%, rgba(129, 140, 248, .16), transparent 65%),
    var(--bg);
}

.backdrop__layer {
  position: absolute;
  inset: -3%;                     /* overscan so the drift never shows an edge */
  background-position: center center;
  background-size: cover;         /* fills any aspect ratio: PC, tablet, phone */
  opacity: 0;
  transition: opacity 2.2s ease-in-out;
  will-change: opacity, transform;
}

.backdrop__layer.is-active {
  opacity: 1;
  animation: drift 42s ease-in-out forwards;
}

@keyframes drift {
  from { transform: scale(1.00) translate3d(0, 0, 0); }
  to   { transform: scale(1.08) translate3d(-1%, -1.2%, 0); }
}

/* Scrim keeps text legible over any still. Mirrors Seerr's
   bottom-weighted gradient plus a low-alpha wash. */
.backdrop__scrim {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to top, var(--bg) 2%, rgba(11, 14, 20, .72) 38%, rgba(11, 14, 20, .55) 100%),
    radial-gradient(120% 80% at 50% 0%, rgba(67, 56, 202, .30), transparent 100%);
}

/* ------------------------------------------------------------------- page
   The whole page is exactly one viewport tall and never scrolls itself —
   only the board (the middle band of tiles) does. The stack is anchored to
   the bottom of the viewport, so the logo, one row of tiles and the footer
   sit together over the lower third and the rest of the screen stays open
   backdrop. Further rows are reached by scrolling inside the board.       */

.page {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: calc(var(--col) + 76px);   /* the column plus side padding */
  margin: 0 auto;
  padding: clamp(14px, 3vw, 26px) clamp(16px, 4vw, 24px);
  height: 100vh;
  height: 100dvh;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;     /* everything hugs the bottom edge */
}

/* --------------------------------------------------------------- masthead */

.masthead {
  flex: none;                    /* never scrolls */
  margin-bottom: clamp(14px, 3vh, 26px);
}

.masthead__brand {
  display: flex;
  flex-direction: column;
  align-items: center;           /* logo + clock centered */
  gap: 8px;
  max-width: var(--col);         /* lines the logo up with the tile row */
  margin: 0 auto;
}

/* Logo spans the content column, but capped so widening the tile row for
   larger tiles doesn't drag the logo up with it. */
.masthead__logo {
  display: block;
  width: 100%;
  height: auto;
  max-width: 720px;
  max-height: 22vh;
  object-fit: contain;
}

.masthead__clock {
  margin: 0;
  font-size: 13px;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
  text-align: center;
}

.masthead__clock .dot { color: var(--text-faint); margin: 0 2px; }

/* ------------------------------------------------------------------ board
   Sized to about one row of tiles. Any further rows are reached by scrolling
   inside this band, so the first paint shows the logo and a single row over
   an otherwise open backdrop.                                              */

.board {
  flex: 0 1 auto;
  min-height: 0;
  /* JS sets max-height to exactly one row (see fitBoard in app.js). This is
     only a pre-script fallback so the board never flashes full height. */
  max-height: 60dvh;
  padding: var(--lift) 0;        /* room for the hover lift, else it clips */
  overflow-y: auto;
  overscroll-behavior: contain;

  /* One row per scroll. The snapport is inset by the same amount as the
     padding, so a snapped row sits exactly where the unscrolled first row
     does and keeps its headroom for the hover lift. */
  scroll-snap-type: y mandatory;
  scroll-padding: var(--lift) 0;

  /* Scrolls, but shows no scrollbar. The partially cut-off row at the
     bottom edge is what signals there is more below. */
  scrollbar-width: none;               /* Firefox */
  -ms-overflow-style: none;            /* legacy Edge */
}

.board::-webkit-scrollbar { width: 0; height: 0; display: none; }

/* Row indicator — the only cue that the board scrolls, now that it is one
   row tall with no scrollbar. */
.board__pager {
  flex: none;
  display: flex;
  justify-content: center;
  gap: 7px;
  margin-top: 10px;
}

.board__pager:empty { display: none; }

.board__dot {
  width: 7px; height: 7px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: var(--ring-strong);
  cursor: pointer;
  transition: background .2s ease, transform .2s ease;
}

.board__dot:hover { background: var(--text-faint); }

.board__dot.is-current {
  background: var(--text-dim);
  transform: scale(1.3);
}

.grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;   /* short last row centres, not hangs left */
  align-items: stretch;
  max-width: var(--col);     /* caps the line at three tiles */
  margin: 0 auto;
  gap: var(--tile-gap);
}

.grid > .tile { width: var(--tile-w); flex: none; }

/* ------------------------------------------------------------------- tile */

/* Everything inside a tile is sized in cqw - percentages of the tile's own
   width - so a narrow tile is the same design scaled down, never a reflowed
   or truncated one. 100cqw == var(--tile-w), which is where the px values
   these were converted from still hold exactly.
   The tile cannot query itself, so its own padding lives on its children and
   its radius stays in px. */
.tile {
  position: relative;
  scroll-snap-align: start;
  container-type: inline-size;
  display: flex;
  flex-direction: column;
  background: var(--panel);
  backdrop-filter: blur(16px) saturate(140%);
  -webkit-backdrop-filter: blur(16px) saturate(140%);
  border: 1px solid var(--ring);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;
  transition: transform .18s ease, border-color .18s ease, background .18s ease;
}

/* The app's own colour bleeds in from the left edge on hover. */
.tile::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(105deg, var(--tile-color, var(--accent)) -30%, transparent 62%);
  opacity: .13;
  transition: opacity .18s ease;
}

.tile:hover, .tile:focus-within {
  transform: translateY(-3px);
  border-color: var(--tile-color, var(--accent));
  background: rgba(17, 24, 39, .78);
}

.tile:hover::before, .tile:focus-within::before { opacity: .28; }

.tile__link {
  position: relative;
  display: flex;
  align-items: center;
  gap: 4.333cqw;
  /* right inset clears the status dot and the info button */
  padding: 5.333cqw 24cqw 0 5.333cqw;
}

.tile:not(.has-stats) .tile__link { padding-bottom: 5.333cqw; }

.tile__icon {
  flex: none;
  width: 14cqw; height: 14cqw;
  display: grid;
  place-items: center;
  border-radius: 3.333cqw;
  background: rgba(0, 0, 0, .28);
  overflow: hidden;
}

.tile__icon img { width: 100%; height: 100%; object-fit: contain; padding: 2cqw; }

.tile__initial {
  font-size: 5.667cqw;
  font-weight: 700;
  color: #fff;
  width: 100%; height: 100%;
  display: grid;
  place-items: center;
  background: linear-gradient(145deg, var(--tile-color, var(--accent)), rgba(0, 0, 0, .45));
}

.tile__text { min-width: 0; }

.tile__name {
  display: block;
  font-size: 5cqw;
  font-weight: 600;
  letter-spacing: -.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.tile__sub {
  display: block;
  font-size: 4.167cqw;
  color: var(--text-dim);
  margin-top: 0.667cqw;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* status dot */
.tile__dot {
  position: absolute;
  top: 4.667cqw; right: 4.667cqw;
  width: 2.333cqw; height: 2.333cqw;
  border-radius: 50%;
  background: var(--text-faint);
  box-shadow: 0 0 0 1cqw rgba(0, 0, 0, .25);
  transition: background .3s;
}

.tile__dot[data-state="up"]      { background: var(--up); }
.tile__dot[data-state="down"]    { background: var(--down); }
.tile__dot[data-state="unknown"] { background: var(--text-faint); }

/* live stats strip - the Heimdall "enhanced app" row.
   margin-top:auto pins it to the bottom of a stretched tile, so strips line
   up across the row however tall the tile ended up. */
.tile.has-stats .tile__link { margin-bottom: 4.667cqw; }

.tile__stats {
  position: relative;
  display: flex;
  gap: 5.333cqw;
  flex-wrap: wrap;
  margin: auto 5.333cqw 5.333cqw;
  padding-top: 4cqw;
  border-top: 1px solid var(--ring);
}

.stat { min-width: 0; }

.stat__value {
  display: block;
  font-size: 5cqw;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.01em;
}

.stat__label {
  display: block;
  font-size: 3.5cqw;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--text-faint);
  margin-top: 1px;
}

.tile__stats.is-error .stat__value { color: var(--down); font-size: 4.333cqw; font-weight: 500; }

.tile__more {
  position: absolute;
  bottom: 4cqw; right: 4cqw;
  width: 9.333cqw; height: 9.333cqw;
  display: grid;
  place-items: center;
  color: var(--text-dim);
  background: rgba(0, 0, 0, .3);
  border: 1px solid var(--ring);
  border-radius: 2.667cqw;
  cursor: pointer;
  opacity: 0;
  transition: opacity .18s, color .18s, border-color .18s;
}

.tile__more svg { width: 5cqw; height: 5cqw; }

.tile:hover .tile__more,
.tile:focus-within .tile__more { opacity: 1; }

.tile__more:hover { color: #fff; border-color: var(--ring-strong); }

.tile.has-stats .tile__more { bottom: auto; top: 4cqw; right: 10cqw; }

/* ----------------------------------------------------------------- footer */

.footer {
  display: grid;
  /* Sides size to their pills; the disclaimer takes what's left and wraps.
     An `auto` centre track would grow with the TMDB attribution and squeeze
     the donation and credit chips off the row. */
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 16px;
  margin-top: 30px;
  padding-top: 18px;
  border-top: 1px solid var(--ring);
  font-size: 11.5px;
  color: var(--text-faint);
}

.footer__apps   { justify-self: start;  display: flex; gap: 10px; }

/* A footer app is the same markup as a board tile, shrunk to sit alongside
   the credit chip instead of competing with the board above it. */
.footer__apps .tile {
  scroll-snap-align: none;
  width: 210px;                  /* definite, so it can size its own cqw */
  flex: none;
  border-radius: 999px;
}
.footer__apps .tile:hover { transform: none; }

/* Only the insets differ: no status dot or info button to clear on the right. */
.footer__apps .tile__link,
.footer__apps .tile:not(.has-stats) .tile__link { padding: 4cqw 6cqw 4cqw 4cqw; }
.footer__apps .tile__dot,
.footer__apps .tile__more { display: none; }
.footer__meta   { justify-self: center; text-align: center; margin: 0; line-height: 1.5; }

/* Keeps the app count from running straight into the attribution line. */
.footer__attr::before { content: '\00b7 '; margin: 0 7px; color: var(--text-faint); }
.footer__attr:empty::before { content: none; }
.footer .credit { justify-self: end; }

.footer__meta a { color: var(--text-dim); text-decoration: underline; text-underline-offset: 2px; }

/* ----------------------------------------------------------------- credit */

.credit {
  display: flex;
  align-items: center;
  gap: 10px;
  max-width: min(320px, 100%);
  padding: 9px 14px 9px 10px;
  background: rgba(11, 14, 20, .66);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border: 1px solid var(--ring);
  border-radius: 999px;
  box-shadow: var(--shadow);
  transition: opacity .4s;
}

.credit__toggle {
  flex: none;
  width: 26px; height: 26px;
  display: grid;
  place-items: center;
  color: var(--text-dim);
  background: none;
  border: none;
  cursor: pointer;
  padding: 0;
}

.credit__toggle svg { width: 17px; height: 17px; }

.credit__body { min-width: 0; line-height: 1.25; }

.credit__label {
  display: block;
  font-size: 9.5px;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--text-faint);
}

.credit__title {
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  display: block;
}

.credit__title:hover { color: var(--accent-bright); }

.credit__meta { font-size: 11px; color: var(--text-dim); }

.credit.is-detailed {
  border-radius: var(--radius);
  padding: 12px 16px;
}

.credit.is-detailed .credit__title { white-space: normal; }

/* ------------------------------------------------------------------ sheet */

.sheet { position: fixed; inset: 0; z-index: 10; display: grid; place-items: center; padding: 20px; }

.sheet__scrim {
  position: absolute;
  inset: 0;
  background: rgba(3, 5, 9, .72);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  animation: fade .2s ease;
}

.sheet__panel {
  position: relative;
  width: min(520px, 100%);
  max-height: 84vh;
  overflow-y: auto;
  padding: 26px;
  background: var(--panel-solid);
  border: 1px solid var(--ring-strong);
  border-radius: var(--radius-lg);
  box-shadow: 0 30px 70px -20px rgba(0, 0, 0, .85);
  animation: rise .22s cubic-bezier(.16, 1, .3, 1);
}

@keyframes fade { from { opacity: 0; } }
@keyframes rise { from { opacity: 0; transform: translateY(14px) scale(.98); } }

.sheet__close {
  position: absolute;
  top: 16px; right: 16px;
  width: 30px; height: 30px;
  display: grid;
  place-items: center;
  color: var(--text-dim);
  background: rgba(255, 255, 255, .06);
  border: none;
  border-radius: 8px;
  cursor: pointer;
}

.sheet__close svg { width: 16px; height: 16px; }
.sheet__close:hover { color: #fff; background: rgba(255, 255, 255, .12); }

.sheet__head { display: flex; align-items: center; gap: 14px; margin-bottom: 16px; padding-right: 40px; }

.sheet__icon {
  flex: none;
  width: 52px; height: 52px;
  border-radius: 12px;
  overflow: hidden;
  background: rgba(0, 0, 0, .3);
  display: grid;
  place-items: center;
}

.sheet__icon img { width: 100%; height: 100%; object-fit: contain; padding: 8px; }

.sheet__name { margin: 0; font-size: 20px; font-weight: 700; letter-spacing: -.02em; }

.sheet__url { font-size: 12.5px; color: var(--accent-bright); word-break: break-all; }

.sheet__desc { margin: 0 0 18px; font-size: 13.5px; line-height: 1.6; color: var(--text-dim); }

.sheet__stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(112px, 1fr));
  gap: 12px;
  margin-bottom: 18px;
}

.sheet__stats:empty { display: none; }

.sheet__stats .stat {
  padding: 12px 14px;
  background: rgba(255, 255, 255, .04);
  border: 1px solid var(--ring);
  border-radius: 10px;
}

.sheet__stats .stat__value { font-size: 19px; }
.sheet__stats .stat__label { font-size: 10.5px; }
.sheet__icon .tile__initial { font-size: 20px; }

.sheet__links { display: flex; gap: 10px; flex-wrap: wrap; }

.sheet__links a {
  font-size: 13px;
  font-weight: 550;
  padding: 10px 16px;
  border-radius: 9px;
  background: rgba(255, 255, 255, .06);
  border: 1px solid var(--ring);
  transition: background .16s, border-color .16s;
}

.sheet__links a:hover { background: rgba(255, 255, 255, .12); border-color: var(--ring-strong); }

.sheet__links a.is-primary {
  background: linear-gradient(180deg, var(--accent), var(--accent-deep));
  border-color: transparent;
  color: #fff;
}

.sheet__links a.is-primary:hover { filter: brightness(1.12); }

/* ------------------------------------------------------------ responsive */

/* 660px is where a second 300px tile stops fitting on a line, so below it a
   tile may as well use the full width instead of sitting narrow and centred. */
@media (max-width: 660px) {
  .grid > .tile { width: 100%; }

  /* Donation and credit share the top line, disclaimer runs full width under
     them. Stacking all three put roughly a third of a phone screen into the
     footer. */
  .footer {
    grid-template-columns: auto minmax(0, 1fr);
    row-gap: 10px;
    column-gap: 12px;
  }
  .footer__apps   { grid-column: 1; grid-row: 1; justify-self: start; }
  .footer .credit { grid-column: 2; grid-row: 1; justify-self: end; min-width: 0; }
  .footer__meta   { grid-column: 1 / -1; grid-row: 2; }

  .footer__apps .tile { width: 170px; }
  .credit { max-width: 100%; }

  .tile__more { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .board__dot { transition: none; }
  .backdrop__layer.is-active { animation: none; }
  .backdrop__layer { transition-duration: .6s; }
  .sheet__panel, .sheet__scrim { animation: none; }
  .tile { transition: none; }
  .tile:hover, .tile:focus-within { transform: none; }
}
