/* Z.TV microsite — dark CRT/terminal aesthetic (task #234, restyled toward
   classic.fishtank.live's WATCH grid + status-bar look in task #237). */

@font-face {
  font-family: "VT323";
  src: local("VT323");
}

:root {
  --ztv-bg: #0a0a0c;
  --ztv-panel: #131316;
  --ztv-border: #23193e;
  --ztv-border-bright: #4a2c96;
  --ztv-purple: #6234d5;
  --ztv-purple-bright: #9253fd;
  --ztv-gold: #d8b45a;
  --ztv-text: #d8d8d8;
  --ztv-text-dim: #8a8a8a;
  --ztv-mono: "Courier New", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }

body.ztv-body {
  margin: 0;
  background-color: var(--ztv-bg);
  background-image:
    repeating-linear-gradient(0deg, rgba(255,255,255,0.012) 0px, rgba(255,255,255,0.012) 1px, transparent 1px, transparent 2px),
    linear-gradient(180deg, rgba(6,5,10,0.45) 0%, rgba(6,5,10,0.52) 55%, rgba(6,5,10,0.62) 100%),
    url("/api/static/ztv/assets/ztv-space-bg.webp");
  background-repeat: repeat, no-repeat, no-repeat;
  background-position: top left, center center, center center;
  background-size: auto, cover, cover;
  background-attachment: scroll, fixed, fixed;
  color: var(--ztv-text);
  font-family: var(--ztv-mono);
  min-height: 100vh;
}

@media (max-width: 768px) {
  /* iOS Safari renders fixed backgrounds unreliably (and repaints on scroll
     are costly on mobile GPUs) — pin the starfield to the document instead. */
  body.ztv-body {
    background-attachment: scroll, scroll, scroll;
  }
}

.ztv-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 20px;
  border-bottom: 2px solid var(--ztv-border-bright);
  background-color: #130a1f;
  background-image:
    linear-gradient(180deg, rgba(10,6,16,0.40) 0%, rgba(8,6,10,0.48) 60%, rgba(6,5,8,0.58) 100%),
    url("/api/static/ztv/assets/ztv-header-nebula.webp");
  background-repeat: no-repeat, no-repeat;
  background-position: center center, center center;
  background-size: cover, cover;
  flex-wrap: wrap;
  position: sticky;
  top: 0;
  z-index: 30;
}

.ztv-logo {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-size: 1.6rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  color: var(--ztv-purple-bright);
  text-decoration: none;
  text-shadow: 0 0 8px rgba(146, 83, 253, 0.6);
}

.ztv-logo-mark {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  object-fit: cover;
  border: 2px solid var(--ztv-purple-bright);
  box-shadow: 0 0 10px rgba(146, 83, 253, 0.55);
}

.ztv-logo-text-img {
  display: block;
  height: 30px;
  width: auto;
  filter:
    drop-shadow(0 0 1px rgba(146, 83, 253, 0.95))
    drop-shadow(0 0 1px rgba(146, 83, 253, 0.95))
    drop-shadow(0 0 6px rgba(146, 83, 253, 0.65))
    drop-shadow(0 1px 2px rgba(0, 0, 0, 0.85));
}

.ztv-nav {
  display: flex;
  gap: 4px;
  flex-wrap: wrap;
}

/* Groups the logged-out nav's sign-in link with its trust note so the two
   stack together as one flex item within the (row) .ztv-nav. */
.ztv-nav-signin {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
}

.ztv-nav a, .ztv-edit-toggle {
  color: var(--ztv-text);
  text-decoration: none;
  font-size: 0.8rem;
  letter-spacing: 0.06em;
  padding: 7px 12px;
  border: 1px solid var(--ztv-border);
  border-radius: 3px;
  background: var(--ztv-panel);
  cursor: pointer;
  font-family: inherit;
  text-transform: uppercase;
}

.ztv-nav a:hover, .ztv-edit-toggle:hover {
  border-color: var(--ztv-border-bright);
  color: var(--ztv-purple-bright);
}

.ztv-main {
  max-width: 1100px;
  margin: 0 auto;
  padding: 28px 20px 60px;
}

/* ── Fixed Bort Cord server widget ───────────────────────────────────────
   Lives in the left rail below the sticky header, matching the placement
   marked in the supplied Z.TV screenshot. The landing page reserves enough
   room for it on desktop so it never covers the clip grid. */

.ztv-discord-widget {
  position: fixed;
  top: 80px;
  left: 12px;
  z-index: 20;
  width: 280px;
  min-height: 430px;
  max-height: calc(100vh - 92px);
  padding: 18px 17px 16px;
  overflow-y: auto;
  border: 1px solid var(--ztv-border-bright);
  border-radius: 3px;
  background:
    linear-gradient(180deg, rgba(98, 52, 213, 0.14), transparent 88px),
    rgba(14, 13, 18, 0.97);
  box-shadow:
    0 0 0 1px rgba(0, 0, 0, 0.75),
    0 12px 30px rgba(0, 0, 0, 0.42),
    inset 0 0 24px rgba(146, 83, 253, 0.035);
  backdrop-filter: blur(8px);
}

.ztv-discord-widget-kicker {
  display: flex;
  align-items: center;
  gap: 7px;
  color: #b8a4e6;
  font-size: 0.62rem;
  letter-spacing: 0.11em;
  text-transform: uppercase;
}

.ztv-discord-mark {
  display: inline-flex;
  color: #a57aff;
}

.ztv-discord-mark svg {
  width: 17px;
  height: 17px;
}

.ztv-discord-widget-heading {
  display: flex;
  align-items: baseline;
  gap: 7px;
  margin: 10px 0 4px;
  white-space: nowrap;
}

.ztv-discord-widget-title {
  margin: 0;
  color: #fff;
  font-size: 1.08rem;
  line-height: 1.2;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  text-shadow: 0 0 10px rgba(146, 83, 253, 0.45);
}

.ztv-discord-presence {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0;
  color: #d3cee0;
  font-size: 0.76rem;
  font-weight: 600;
  line-height: 1.35;
  text-transform: uppercase;
}

.ztv-discord-live-dot {
  width: 7px;
  height: 7px;
  flex: none;
  border-radius: 50%;
  background: #3ba55d;
  box-shadow: 0 0 8px rgba(59, 165, 93, 0.75);
}

.ztv-discord-widget-divider {
  height: 1px;
  margin: 13px 0 10px;
  background: linear-gradient(90deg, var(--ztv-border-bright), transparent);
}

.ztv-discord-members-label {
  margin: 0 0 7px;
  color: #c7bfdd;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.ztv-discord-members {
  display: grid;
  gap: 8px;
  min-height: 104px;
  margin: 0 0 14px;
  padding: 0;
  list-style: none;
}

.ztv-discord-member {
  display: grid;
  grid-template-columns: 27px minmax(0, 1fr) 9px;
  align-items: center;
  gap: 8px;
  min-width: 0;
  color: #eae7f2;
  font-size: 0.8rem;
}

.ztv-discord-member-avatar {
  width: 27px;
  height: 27px;
  border: 1px solid #39333f;
  border-radius: 50%;
  object-fit: cover;
  background: #20182d;
}

.ztv-discord-member-avatar-fallback {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--ztv-purple-bright);
  font-size: 0.68rem;
  font-weight: 700;
}

.ztv-discord-member-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 500;
}

.ztv-discord-member-status {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: #3ba55d;
  cursor: help;
}

.ztv-discord-member-status:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 2px;
}

.ztv-discord-member-status.is-idle {
  background: #faa61a;
}

.ztv-discord-member-status.is-dnd {
  background: #ed4245;
}

.ztv-discord-member-empty {
  display: block;
  padding: 7px 0;
  color: var(--ztv-text-dim);
  line-height: 1.45;
}

.ztv-discord-channels-label {
  margin-top: 2px;
}

.ztv-discord-channels {
  display: grid;
  gap: 5px;
  min-height: 34px;
  margin: 0 0 15px;
  padding: 0;
  list-style: none;
}

.ztv-discord-channel {
  display: grid;
  grid-template-columns: 17px minmax(0, 1fr) auto;
  align-items: center;
  gap: 7px;
  min-width: 0;
  padding: 5px 7px;
  border: 1px solid rgba(118, 85, 198, 0.18);
  border-radius: 3px;
  background: rgba(90, 57, 155, 0.08);
  color: #ddd7ea;
  font-size: 0.74rem;
  font-weight: 500;
}

.ztv-discord-channel-icon {
  width: 15px;
  height: 15px;
  color: #8d72c8;
}

.ztv-discord-channel-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ztv-discord-channel-count {
  min-width: 18px;
  padding: 2px 5px;
  border-radius: 999px;
  background: rgba(87, 62, 149, 0.4);
  color: #d9caff;
  font-size: 0.64rem;
  font-weight: 700;
  text-align: center;
}

.ztv-discord-actions {
  display: grid;
  gap: 7px;
}

.ztv-discord-join {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  width: 100%;
  padding: 9px 10px;
  border: 1px solid #7253cc;
  border-radius: 3px;
  background: #4f36a7;
  color: #fff;
  font-size: 0.76rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-decoration: none;
  text-transform: uppercase;
  transition: border-color 0.15s ease, background 0.15s ease, transform 0.15s ease;
}

.ztv-discord-join-label {
  display: flex;
  flex-direction: column;
  min-width: 0;
  font-weight: 500;
  text-align: left;
}

.ztv-discord-join-label strong {
  color: #fff;
  font-weight: 900;
}

.ztv-discord-join:hover,
.ztv-discord-join:focus-visible {
  border-color: var(--ztv-purple-bright);
  background: #6643d5;
  transform: translateY(-1px);
}

.ztv-discord-join:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 2px;
}

.ztv-discord-verify-note {
  margin: 8px 0 0;
  color: #6f6978;
  font-size: 0.53rem;
  letter-spacing: 0.045em;
  text-align: center;
  text-transform: uppercase;
}

@media (min-width: 901px) and (max-width: 1740px) {
  body.ztv-body:not(.ztv-clip-page) .ztv-main {
    width: calc(100% - 324px);
    margin-left: 304px;
    margin-right: 20px;
  }
}

@media (max-width: 900px) {
  .ztv-discord-widget {
    position: relative;
    top: auto;
    left: auto;
    width: min(520px, calc(100% - 40px));
    min-height: 0;
    max-height: none;
    margin: 20px 0 0 20px;
    overflow: visible;
  }

  .ztv-discord-members {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    min-height: 0;
  }
}

@media (max-width: 480px) {
  .ztv-discord-members {
    grid-template-columns: 1fr;
  }

  .ztv-discord-widget {
    padding: 16px 14px;
  }

  .ztv-discord-widget-heading {
    gap: 5px;
  }
}

.ztv-about {
  border: 1px solid var(--ztv-border);
  background: var(--ztv-panel);
  padding: 20px;
  margin-bottom: 34px;
  position: relative;
}

.ztv-about h1 {
  margin: 0 0 4px;
  font-size: 1.1rem;
  letter-spacing: 0.1em;
  color: var(--ztv-purple-bright);
  text-transform: uppercase;
}

.ztv-hero-logo-img {
  display: block;
  height: 22px;
  width: auto;
  max-width: 100%;
  filter:
    drop-shadow(0 0 1px rgba(146, 83, 253, 0.95))
    drop-shadow(0 0 1px rgba(146, 83, 253, 0.95))
    drop-shadow(0 0 6px rgba(146, 83, 253, 0.65))
    drop-shadow(0 1px 2px rgba(0, 0, 0, 0.85));
}

.ztv-about-sub {
  margin: 0 0 14px;
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  color: var(--ztv-text-dim);
  text-transform: uppercase;
}

.ztv-about-text {
  line-height: 1.6;
  font-size: 0.95rem;
  white-space: pre-wrap;
  outline: none;
  color: var(--ztv-purple-bright);
  -webkit-text-stroke: 1px #000;
  paint-order: stroke fill;
}

.ztv-about-text[contenteditable="true"] {
  border: 1px dashed var(--ztv-border-bright);
  padding: 8px;
  background: #0d0d10;
}

.ztv-section-title {
  font-size: 0.85rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ztv-text-dim);
  margin: 0 0 14px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--ztv-border);
}

.ztv-clips-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px 20px;
  margin-bottom: 14px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--ztv-border);
}

.ztv-clips-header .ztv-section-title {
  margin: 0;
  padding-bottom: 0;
  border-bottom: none;
}

.ztv-sort-controls {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px 10px;
  font-size: 0.68rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.ztv-sort-label {
  color: var(--ztv-text-dim);
}

.ztv-sort-link {
  color: var(--ztv-text-dim);
  text-decoration: none;
  padding: 4px 9px;
  border: 1px solid var(--ztv-border);
  border-radius: 3px;
  background: none;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  cursor: pointer;
  transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}

.ztv-sort-link:hover {
  color: var(--ztv-text);
  border-color: var(--ztv-border-bright);
}

.ztv-sort-link.is-active {
  color: var(--ztv-purple-bright);
  border-color: var(--ztv-purple-bright);
  background: rgba(98, 52, 213, 0.15);
}

/* ── Clip grid — fishtank.live "WATCH" tile styling ──────────────────────
   Full-bleed thumbnail/video card with the label pinned to the top-left
   corner over the image, matching classic.fishtank.live's WATCH tab, kept in
   Z.TV's purple/gold palette (recolored to match the Z.TV logo) instead of
   fishtank's neutral grey/gold. */

.ztv-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 14px;
}

.ztv-tile {
  display: flex;
  flex-direction: column;
}

.ztv-tile-media {
  position: relative;
  aspect-ratio: 16 / 9;
  border: 1px solid var(--ztv-border);
  border-radius: 4px;
  background: #131316;
  overflow: hidden;
}

.ztv-tile:hover .ztv-tile-media {
  border-color: var(--ztv-border-bright);
  box-shadow: 0 0 0 1px var(--ztv-border-bright), 0 0 14px rgba(146, 83, 253, 0.25);
}

.ztv-tile-link {
  position: absolute;
  inset: 0;
  display: block;
}

.ztv-thumb {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.ztv-thumb-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 2.2rem;
  color: #2a2a2e;
  background:
    repeating-linear-gradient(45deg, #17171a 0px, #17171a 10px, #131316 10px, #131316 20px);
}

/* CRT-style snap instead of a smooth linear dissolve: the "in" direction
   uses an overshoot ease (rises past its target opacity before settling —
   like a tube surging on) and the "out" direction uses a mirrored ease that
   dips *brighter* before collapsing (the brief flash a CRT gives right as
   it loses signal) rather than fading evenly to nothing. Because the two
   directions are transitions (not a single fixed-duration animation), they
   still always interpolate from whatever the *current* opacity is, so
   rapid hover on/off never leaves a tile stuck mid-fade or snaps instantly
   — see the "governing rule" note below.
   The transition-timing-function that applies is the one declared on the
   state being transitioned *into*, which is why the fade-out curve lives on
   the resting (non-active) rule and the fade-in curve lives on the
   `.is-static-active` / `.is-previewing` rule. A short `filter` animation
   (shared by both elements) layers a couple of brightness blips on top of
   the fade-in for a genuine flicker, and is purely decorative on top of the
   opacity transition, so an interrupted flicker never affects visibility. */
.ztv-static-vfx {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  image-rendering: pixelated;
  opacity: 0;
  filter: brightness(1);
  transition: opacity 0.16s cubic-bezier(0.6, -0.28, 0.735, 0.045);
  pointer-events: none;
  z-index: 1;
}

.ztv-tile-media.is-static-active .ztv-static-vfx {
  opacity: 0.9;
  transition: opacity 0.11s cubic-bezier(0.34, 1.56, 0.64, 1);
  animation: ztv-crt-snap-flicker 0.26s ease-out 1;
}

.ztv-preview-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  filter: brightness(1);
  transition: opacity 0.16s cubic-bezier(0.6, -0.28, 0.735, 0.045);
  pointer-events: none;
  z-index: 2;
}

.ztv-tile-media.is-previewing .ztv-preview-video {
  opacity: 1;
  transition: opacity 0.12s cubic-bezier(0.34, 1.56, 0.64, 1);
  animation: ztv-crt-snap-flicker 0.22s ease-out 1;
}

@keyframes ztv-crt-snap-flicker {
  0% { filter: brightness(2.6) contrast(1.35); }
  10% { filter: brightness(0.55) contrast(0.9); }
  22% { filter: brightness(1.9) contrast(1.2); }
  38% { filter: brightness(0.8) contrast(1.05); }
  60% { filter: brightness(1.15) contrast(1.02); }
  100% { filter: brightness(1) contrast(1); }
}

@media (prefers-reduced-motion: reduce) {
  .ztv-static-vfx,
  .ztv-preview-video {
    transition-duration: 0.01ms !important;
    animation: none !important;
  }
}

.ztv-tile-media.is-static-active .ztv-thumb,
.ztv-tile-media.is-previewing .ztv-thumb {
  opacity: 0;
}

/* Tiny outline behind every text overlay on a tile's media (title, meta,
   view count) so it stays readable over a bright thumbnail/video even when
   the tile isn't hovered and has no gradient scrim behind it. */
.ztv-tile-title,
.ztv-tile-meta,
.ztv-tile-views {
  text-shadow:
    -1px -1px 0 rgba(0,0,0,0.85),
    1px -1px 0 rgba(0,0,0,0.85),
    -1px 1px 0 rgba(0,0,0,0.85),
    1px 1px 0 rgba(0,0,0,0.85),
    0 1px 3px rgba(0,0,0,0.9);
  transition: opacity 0.25s ease;
}

/* Once the real clip is playing, dim the overlay text a bit so it doesn't
   compete with the video itself. */
.ztv-tile-media.is-previewing .ztv-tile-title,
.ztv-tile-media.is-previewing .ztv-tile-meta,
.ztv-tile-media.is-previewing .ztv-tile-views {
  opacity: 0.55;
}

.ztv-tile-title {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 2;
  padding: 7px 34px 14px 8px;
  font-size: 0.76rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  color: var(--ztv-gold);
  text-transform: uppercase;
  word-break: break-word;
  outline: none;
  background: linear-gradient(180deg, rgba(6,6,7,0.88) 0%, rgba(6,6,7,0.55) 65%, transparent 100%);
  pointer-events: none;
}

.ztv-tile-title[contenteditable="true"] {
  pointer-events: auto;
  border-bottom: 1px dashed var(--ztv-border-bright);
  background: rgba(13,13,16,0.95);
}

.ztv-tile-meta {
  position: absolute;
  bottom: 6px;
  left: 8px;
  z-index: 2;
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  color: var(--ztv-purple-bright);
  text-transform: uppercase;
  pointer-events: none;
}

.ztv-tile-views {
  /* z-index 5 deliberately sits above .ztv-tile-title's gradient (z-index 2,
     later in DOM order so it would otherwise paint on top): the view count
     used to render underneath that gradient and go unreadable. The pill
     background below gives it its own contrast so it pops regardless of
     what's behind it (thumbnail, video, or the title gradient). */
  position: absolute;
  top: 6px;
  right: 8px;
  z-index: 5;
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  color: var(--ztv-text);
  text-transform: uppercase;
  pointer-events: none;
  background: rgba(10,10,12,0.75);
  padding: 2px 6px;
  border-radius: 2px;
  white-space: nowrap;
}

.ztv-tile-social {
  /* Sits just under the view-count pill (task #265) — same treatment
     (its own opaque background) so like/comment counts stay legible over
     any thumbnail or video, and the same z-index so they aren't swallowed
     by the title gradient underneath. */
  position: absolute;
  top: 26px;
  right: 8px;
  z-index: 5;
  display: flex;
  gap: 4px;
  pointer-events: none;
}

.ztv-tile-likes,
.ztv-tile-comments {
  font-size: 0.6rem;
  font-weight: 700;
  letter-spacing: 0.03em;
  color: var(--ztv-text);
  background: rgba(10,10,12,0.75);
  padding: 2px 5px;
  border-radius: 2px;
  white-space: nowrap;
}

.ztv-mute-btn,
.ztv-play-btn {
  position: absolute;
  bottom: 6px;
  right: 6px;
  z-index: 3;
  width: 26px;
  height: 26px;
  padding: 0;
  display: none;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--ztv-border-bright);
  border-radius: 50%;
  background: rgba(10,10,12,0.75);
  color: var(--ztv-text);
  font-size: 0.8rem;
  cursor: pointer;
}

.ztv-play-btn {
  right: 38px;
  font-size: 0.7rem;
}

.ztv-tile-media.is-static-active .ztv-mute-btn,
.ztv-tile-media.is-previewing .ztv-mute-btn {
  display: flex;
}

.ztv-tile-media.is-previewing .ztv-play-btn {
  display: flex;
}

.ztv-mute-btn:hover,
.ztv-play-btn:hover {
  border-color: var(--ztv-purple-bright);
  color: #fff;
}

.ztv-progress-track {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  background: rgba(255,255,255,0.08);
  z-index: 2;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.2s ease;
}

.ztv-tile-media.is-previewing .ztv-progress-track {
  opacity: 1;
}

.ztv-progress-fill {
  height: 100%;
  width: 0%;
  background: var(--ztv-purple-bright);
}

/* "Recently watched" bar (YouTube-style) — a red fill along the bottom edge
   of the thumbnail showing how far the visitor previously got into this
   clip. Width is set client-side from localStorage (see
   ztv-watch-progress-script.ts) once we know there's a saved position, so
   it stays hidden by default rather than flashing an empty bar on every
   tile. Hidden while a hover preview is active since the purple
   .ztv-progress-track above already shows live scrub position then. */
.ztv-watched-bar {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 3px;
  z-index: 3;
  pointer-events: none;
  display: none;
}

.ztv-watched-bar.has-progress {
  display: block;
}

.ztv-tile-media.is-previewing .ztv-watched-bar {
  display: none;
}

.ztv-watched-bar-fill {
  height: 100%;
  width: 0%;
  background: #e33b3b;
}

.ztv-empty {
  color: var(--ztv-text-dim);
  font-size: 0.85rem;
}

.ztv-save-status {
  position: fixed;
  bottom: 16px;
  right: 16px;
  max-width: min(420px, calc(100vw - 32px));
  padding: 8px 14px;
  border: 1px solid var(--ztv-border-bright);
  background: var(--ztv-panel);
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  display: none;
  z-index: 10001;
}

.ztv-save-status.is-visible { display: block; }
.ztv-save-status.is-error { border-color: var(--ztv-purple-bright); color: var(--ztv-purple-bright); }

/* ── Clip page ─────────────────────────────────────────────────────── */

.ztv-clip-stage {
  margin-bottom: 18px;
}

.ztv-clip-page .ztv-video-wrap {
  border: 1px solid var(--ztv-border);
  background: #000;
  margin-bottom: 0;
}

.ztv-clip-page video {
  width: 100%;
  display: block;
  max-height: 70vh;
  background: #000;
}

/* True fullscreen (task: dock controls to the bottom edge, immersive fade).
   requestFullscreen() is called on .ztv-video-wrap (see
   ztv-clip-controls-script.ts), so the wrapper itself becomes the
   fullscreen element and gets stretched to fill the viewport by the
   browser. Without this rule the video keeps its normal max-height and the
   control bar ends up floating mid-screen with dead black space below it
   instead of sitting flush against the bottom edge. Making the wrapper a
   column flexbox and letting the video grow to fill the remaining space
   (object-fit: contain to preserve letterboxing) pins the bar to the very
   bottom on every aspect ratio, including mobile landscape. */
.ztv-video-wrap:fullscreen,
.ztv-video-wrap:-webkit-full-screen {
  display: flex;
  flex-direction: column;
  width: 100vw;
  height: 100vh;
  border: none;
}

.ztv-video-wrap:fullscreen video,
.ztv-video-wrap:-webkit-full-screen video {
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  max-height: none;
  object-fit: contain;
}

.ztv-video-wrap:fullscreen .ztv-controls,
.ztv-video-wrap:-webkit-full-screen .ztv-controls {
  flex: 0 0 auto;
}

/* Custom control bar (task #306) — replaces the native <video controls> UI
   (which can't be reordered or host extra buttons) so "Next"/"Auto" can live
   next to the sound controls instead of in a separate side rail. Layout
   order in the markup is: play/pause, time, seek bar, mute, volume (to the
   mute button's right), Auto, Next, fullscreen. */
.ztv-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-top: 1px solid var(--ztv-border);
  background: var(--ztv-panel);
  opacity: 1;
  transform: translateY(0);
  transition: opacity 0.5s ease, transform 0.5s ease;
}

/* Idle auto-hide (immersive viewing, all devices) — set by
   ztv-clip-controls-script.ts after a few seconds of no pointer/keyboard
   activity while the clip is playing. Fades the bar down out of view
   instead of just hiding it, per the "fade down" request. Pointer events
   are dropped so the faded bar can't eat clicks meant for the video. */
.ztv-video-wrap.is-idle .ztv-controls {
  opacity: 0;
  transform: translateY(100%);
  pointer-events: none;
}

.ztv-ctrl-btn {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border: 1px solid var(--ztv-border);
  background: #1a1224;
  color: var(--ztv-purple-bright);
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
  padding: 0;
  transition: border-color 0.12s, color 0.12s, background 0.12s;
}

.ztv-ctrl-btn:hover,
.ztv-ctrl-btn:focus-visible {
  border-color: var(--ztv-border-bright);
  color: #fff;
  background: #241a34;
}

.ztv-ctrl-btn:focus-visible {
  outline: 2px solid var(--ztv-purple-bright);
  outline-offset: 2px;
}

.ztv-ctrl-btn.is-active {
  color: #fff;
  border-color: var(--ztv-border-bright);
}

.ztv-ctrl-time {
  flex: 0 0 auto;
  font-size: 0.75rem;
  color: var(--ztv-text-dim);
  white-space: nowrap;
  min-width: 84px;
  text-align: center;
}

.ztv-ctrl-seek {
  flex: 1 1 140px;
  min-width: 80px;
  accent-color: var(--ztv-purple-bright);
  cursor: pointer;
}

.ztv-ctrl-volume {
  flex: 0 0 80px;
  width: 80px;
  accent-color: var(--ztv-purple-bright);
  cursor: pointer;
}

/* "Next"/"Auto" (tasks #294/#296) now sit inline in the control bar next to
   the sound controls, restyled from their old vertical-rail look to compact
   horizontal buttons. IDs and click logic are unchanged — see
   ztv-next-clip-script.ts. */
.ztv-autoplay-btn,
.ztv-next-btn {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 1px solid var(--ztv-border);
  background: var(--ztv-panel);
  color: var(--ztv-purple-bright);
  font-family: inherit;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  cursor: pointer;
  padding: 8px 10px;
  transition: border-color 0.12s, color 0.12s, background 0.12s;
}

.ztv-autoplay-btn:hover,
.ztv-autoplay-btn:focus-visible,
.ztv-next-btn:hover,
.ztv-next-btn:focus-visible {
  border-color: var(--ztv-border-bright);
  background: #1a1224;
  color: #fff;
}

.ztv-autoplay-btn:focus-visible,
.ztv-next-btn:focus-visible {
  outline: 2px solid var(--ztv-purple-bright);
  outline-offset: 2px;
}

.ztv-next-btn:disabled {
  opacity: 0.5;
  cursor: default;
}

.ztv-autoplay-btn.is-active {
  color: var(--ztv-purple-bright);
  background: rgba(98, 52, 213, 0.15);
  border-color: var(--ztv-border-bright);
}

.ztv-autoplay-icon,
.ztv-next-btn-arrow {
  font-size: 0.85rem;
  line-height: 1;
}

@media (max-width: 640px) {
  /* Keep the bar usable at narrow widths: push the seek bar onto its own
     full-width row above the rest of the compact controls instead of
     letting everything cram onto one line. */
  .ztv-controls {
    padding: 8px;
    gap: 6px;
  }

  .ztv-ctrl-seek {
    order: -1;
    flex: 1 1 100%;
  }

  .ztv-ctrl-time {
    min-width: 68px;
    font-size: 0.68rem;
  }

  .ztv-ctrl-volume {
    flex: 0 0 56px;
    width: 56px;
  }

  .ztv-ctrl-btn {
    width: 30px;
    height: 30px;
  }

  .ztv-autoplay-btn,
  .ztv-next-btn {
    padding: 7px 8px;
    font-size: 0.65rem;
  }
}

.ztv-clip-title {
  font-size: 1.3rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  margin: 0 0 6px;
  outline: none;
}

.ztv-clip-title[contenteditable="true"] {
  border: 1px dashed var(--ztv-border-bright);
  padding: 6px;
  background: #0d0d10;
}

.ztv-clip-meta {
  color: var(--ztv-text-dim);
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin-bottom: 20px;
}

.ztv-back-link {
  display: inline-block;
  margin-bottom: 18px;
  color: var(--ztv-text-dim);
  text-decoration: none;
  font-size: 0.8rem;
}

.ztv-back-link:hover { color: var(--ztv-purple-bright); }

/* ── Comments (task #237) — YouTube-style, terminal-flavored ─────────── */

.ztv-comments {
  margin-top: 40px;
  padding-top: 24px;
  border-top: 1px solid var(--ztv-border);
}

.ztv-comment-form {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  margin-bottom: 22px;
}

.ztv-comment-avatar {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  flex: none;
  object-fit: cover;
  border: 1px solid var(--ztv-border);
}

span.ztv-comment-avatar-fallback {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--ztv-panel);
  color: var(--ztv-gold);
  font-weight: 700;
  font-size: 0.85rem;
}

.ztv-comment-input {
  flex: 1;
  resize: vertical;
  min-height: 40px;
  background: #0d0d10;
  border: 1px solid var(--ztv-border);
  color: var(--ztv-text);
  font-family: inherit;
  font-size: 0.85rem;
  padding: 8px 10px;
  border-radius: 3px;
}

.ztv-comment-input:focus {
  outline: none;
  border-color: var(--ztv-border-bright);
}

.ztv-comment-submit {
  flex: none;
  align-self: flex-start;
  background: var(--ztv-purple);
  color: #fff;
  border: 1px solid var(--ztv-border-bright);
  border-radius: 3px;
  padding: 9px 16px;
  font-family: inherit;
  font-size: 0.8rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  cursor: pointer;
}

.ztv-comment-submit:hover { background: var(--ztv-purple-bright); }
.ztv-comment-submit:disabled { opacity: 0.5; cursor: default; }

.ztv-comment-login {
  color: var(--ztv-text-dim);
  font-size: 0.85rem;
  margin-bottom: 20px;
}

.ztv-comment-login a { color: var(--ztv-purple-bright); }

.ztv-comment-list {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.ztv-comment {
  display: flex;
  gap: 10px;
  align-items: flex-start;
}

.ztv-comment-body { flex: 1; min-width: 0; }

.ztv-comment-meta {
  display: flex;
  gap: 10px;
  align-items: baseline;
  flex-wrap: wrap;
}

.ztv-comment-username {
  font-size: 0.8rem;
  font-weight: 700;
  color: var(--ztv-gold);
}

.ztv-comment-date {
  font-size: 0.68rem;
  color: var(--ztv-text-dim);
  letter-spacing: 0.04em;
}

.ztv-comment-text {
  margin: 4px 0 0;
  font-size: 0.85rem;
  line-height: 1.5;
  white-space: pre-wrap;
  word-break: break-word;
}

.ztv-comment-delete {
  flex: none;
  background: none;
  border: 1px solid transparent;
  color: var(--ztv-text-dim);
  border-radius: 3px;
  padding: 4px 6px;
  cursor: pointer;
  font-size: 0.8rem;
}

.ztv-comment-delete:hover {
  color: var(--ztv-purple-bright);
  border-color: var(--ztv-border-bright);
}

.ztv-comment-delete:disabled { opacity: 0.4; cursor: default; }

/* ── Edit panel — mirrors the BurtyBurt game dev panel (task #237) ───── */

#ztv-dev-tog {
  position: fixed; bottom: 14px; left: 14px; z-index: 10000;
  background: #170c26; border: 1px solid var(--ztv-border-bright); border-radius: 5px;
  color: var(--ztv-purple-bright); font-size: 11px; font-weight: 700; letter-spacing: 0.08em;
  padding: 7px 13px; cursor: pointer; font-family: var(--ztv-mono);
  text-transform: uppercase;
  box-shadow: 0 2px 10px rgba(0,0,0,0.6);
}
#ztv-dev-tog:hover { background: #260f0f; }

#ztv-dev-panel {
  position: fixed; left: 14px; bottom: 56px; width: 280px; max-width: calc(100vw - 28px);
  background: #0c0e11; border: 1px solid var(--ztv-border-bright); border-radius: 6px;
  z-index: 10000; display: none; flex-direction: column;
  font-family: var(--ztv-mono); font-size: 12px; color: var(--ztv-text);
  box-shadow: 0 6px 30px rgba(0,0,0,0.8);
}
#ztv-dev-panel[data-open] { display: flex; }

#ztv-dev-hdr {
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px 12px; background: #130a1f; border-bottom: 1px solid var(--ztv-border);
  font-weight: 700; font-size: 12px; letter-spacing: 0.07em; color: var(--ztv-purple-bright);
  text-transform: uppercase;
}
#ztv-dev-hdr button {
  background: none; border: none; color: var(--ztv-text-dim); font-size: 18px;
  cursor: pointer; line-height: 1; padding: 0 2px;
}
#ztv-dev-hdr button:hover { color: #fff; }

#ztv-dev-body { padding: 12px; display: flex; flex-direction: column; gap: 10px; }

.ztv-dev-row {
  display: flex; align-items: center; gap: 8px; cursor: pointer;
  text-transform: uppercase; letter-spacing: 0.04em; font-size: 11.5px;
}
.ztv-dev-row input[type="checkbox"] { accent-color: var(--ztv-purple-bright); width: 15px; height: 15px; }

.ztv-dev-hint {
  font-size: 10.5px; color: var(--ztv-text-dim); line-height: 1.4; margin: 0;
}

.ztv-dev-status {
  font-size: 10.5px; color: var(--ztv-gold); margin: 0;
}

.ztv-dev-btn {
  display: block; width: 100%; font-family: inherit;
  background: var(--ztv-panel); border: 1px solid var(--ztv-border); border-radius: 4px;
  color: var(--ztv-text); padding: 8px 10px; font-size: 11.5px; letter-spacing: 0.04em;
  cursor: pointer; text-transform: uppercase;
}
.ztv-dev-btn:hover:not(:disabled) { border-color: var(--ztv-border-bright); }
.ztv-dev-btn:disabled { opacity: 0.4; cursor: default; }
.ztv-dev-btn-primary { background: var(--ztv-purple); border-color: var(--ztv-border-bright); color: #fff; }
.ztv-dev-btn-primary:hover:not(:disabled) { background: var(--ztv-purple-bright); }
.ztv-dev-btn-danger { color: #e07070; }
.ztv-dev-btn-danger:hover:not(:disabled) { border-color: #7a3030; }

/* ── Upload Clip (task #313) ──────────────────────────────────────────── */

.ztv-dev-divider {
  height: 1px;
  background: var(--ztv-border);
  margin: 2px 0;
}

.ztv-dev-section-title {
  font-size: 11px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--ztv-purple-bright); margin: 0;
}

.ztv-dev-field {
  display: flex; flex-direction: column; gap: 4px;
  font-size: 10.5px; letter-spacing: 0.04em; text-transform: uppercase; color: var(--ztv-text-dim);
}

.ztv-dev-field input[type="text"],
.ztv-dev-field input[type="file"] {
  font-family: inherit; font-size: 11.5px; color: var(--ztv-text);
  background: var(--ztv-panel); border: 1px solid var(--ztv-border); border-radius: 4px;
  padding: 7px 8px; width: 100%; box-sizing: border-box;
  text-transform: none; letter-spacing: normal;
}

.ztv-dev-field input[type="text"]:focus,
.ztv-dev-field input[type="file"]:focus {
  outline: none; border-color: var(--ztv-border-bright);
}

.ztv-upload-progress-track {
  height: 5px; border-radius: 3px; overflow: hidden; background: rgba(255,255,255,0.08);
}

.ztv-upload-progress-fill {
  height: 100%; width: 0%; background: var(--ztv-purple-bright); transition: width 0.15s ease;
}

.ztv-dev-status.is-error { color: #e07070; }

/* ── Clip like button (task #256) ─────────────────────────────────────── */

.ztv-clip-meta-row {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  margin-top: 6px;
  margin-bottom: 4px;
}

.ztv-clip-meta-row .ztv-clip-meta {
  margin: 0;
}

.ztv-clip-actions {
  display: flex;
  gap: 8px;
  align-items: center;
}

.ztv-clip-like-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--ztv-panel);
  border: 1px solid var(--ztv-border);
  border-radius: 20px;
  color: var(--ztv-text);
  font-family: inherit;
  font-size: 0.85rem;
  padding: 6px 14px;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}

.ztv-clip-like-btn:hover {
  border-color: var(--ztv-border-bright);
  color: var(--ztv-purple-bright);
}

.ztv-clip-like-btn.is-liked {
  background: rgba(98, 52, 213, 0.25);
  border-color: var(--ztv-purple-bright);
  color: var(--ztv-purple-bright);
}

.ztv-clip-like-btn:disabled {
  opacity: 0.5;
  cursor: default;
}

.ztv-clip-like-login {
  color: var(--ztv-text-dim);
  font-size: 0.85rem;
  margin: 0;
}

.ztv-clip-like-login a { color: var(--ztv-purple-bright); }

/* ── Comment action bar (like / dislike / reply) (task #256) ──────────── */

.ztv-comment-actions {
  display: flex;
  gap: 6px;
  align-items: center;
  margin-top: 6px;
  flex-wrap: wrap;
}

.ztv-vote-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: none;
  border: 1px solid transparent;
  border-radius: 3px;
  color: var(--ztv-text-dim);
  font-family: inherit;
  font-size: 0.78rem;
  padding: 3px 8px;
  cursor: pointer;
  transition: color 0.12s, border-color 0.12s, background 0.12s;
}

.ztv-vote-btn:hover {
  color: var(--ztv-text);
  border-color: var(--ztv-border);
}

.ztv-vote-btn.is-voted {
  color: var(--ztv-purple-bright);
  border-color: var(--ztv-border-bright);
  background: rgba(98, 52, 213, 0.15);
}

.ztv-vote-btn:disabled {
  opacity: 0.4;
  cursor: default;
}

.ztv-vote-count {
  font-variant-numeric: tabular-nums;
  min-width: 1ch;
  text-align: left;
}

.ztv-reply-toggle-btn {
  background: none;
  border: none;
  color: var(--ztv-text-dim);
  font-family: inherit;
  font-size: 0.78rem;
  padding: 3px 8px;
  cursor: pointer;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  border-radius: 3px;
  transition: color 0.12s;
}

.ztv-reply-toggle-btn:hover {
  color: var(--ztv-purple-bright);
}

/* ── Reply form (task #256) ───────────────────────────────────────────── */

.ztv-reply-form-wrap {
  margin-top: 10px;
}

.ztv-reply-form {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.ztv-reply-form-btns {
  display: flex;
  gap: 8px;
}

.ztv-reply-cancel-btn {
  background: none;
  border: 1px solid var(--ztv-border);
  border-radius: 3px;
  color: var(--ztv-text-dim);
  font-family: inherit;
  font-size: 0.8rem;
  padding: 8px 14px;
  cursor: pointer;
}

.ztv-reply-cancel-btn:hover {
  border-color: var(--ztv-border-bright);
  color: var(--ztv-text);
}

/* ── Nested replies (task #256) ───────────────────────────────────────── */

.ztv-replies {
  margin-top: 12px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  border-left: 2px solid var(--ztv-border);
  padding-left: 14px;
}

.ztv-reply .ztv-comment-avatar {
  width: 24px;
  height: 24px;
  font-size: 0.7rem;
}

/* ── Username tooltip (task #256) ────────────────────────────────────── */

.ztv-has-tooltip {
  position: relative;
  cursor: default;
}

.ztv-tooltip {
  position: absolute;
  left: 0;
  top: calc(100% + 4px);
  z-index: 50;
  background: #0c0e11;
  border: 1px solid var(--ztv-border-bright);
  border-radius: 4px;
  color: var(--ztv-text-dim);
  font-size: 0.7rem;
  font-family: var(--ztv-mono);
  white-space: nowrap;
  padding: 3px 7px;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.18s;
  box-shadow: 0 4px 14px rgba(0,0,0,0.7);
}

.ztv-has-tooltip:hover .ztv-tooltip {
  opacity: 1;
}

/* ── Nav identity dropdown (task #256) ───────────────────────────────── */

.ztv-user-menu {
  position: relative;
}

.ztv-user-trigger {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  background: none;
  border: 1px solid var(--ztv-border);
  border-radius: 3px;
  color: var(--ztv-text);
  font-family: inherit;
  font-size: 0.8rem;
  letter-spacing: 0.04em;
  padding: 6px 10px;
  cursor: pointer;
  transition: border-color 0.12s, color 0.12s;
}

.ztv-user-trigger:hover {
  border-color: var(--ztv-border-bright);
  color: var(--ztv-purple-bright);
}

.ztv-nav-avatar {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  object-fit: cover;
  border: 1px solid var(--ztv-border);
  flex: none;
}

span.ztv-nav-avatar-fallback {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--ztv-panel);
  color: var(--ztv-gold);
  font-weight: 700;
  font-size: 0.7rem;
}

.ztv-user-caret {
  font-size: 0.6rem;
  color: var(--ztv-text-dim);
}

.ztv-user-dropdown {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  width: 280px;
  max-width: calc(100vw - 24px);
  background: #141416;
  border: 1px solid var(--ztv-border-bright);
  border-radius: 6px;
  box-shadow: 0 8px 30px rgba(0,0,0,0.8);
  z-index: 200;
  display: none;
  flex-direction: column;
  gap: 0;
  font-family: var(--ztv-mono);
}

.ztv-user-dropdown[data-open] {
  display: flex;
}

.ztv-dropdown-section {
  padding: 12px 14px;
  border-bottom: 1px solid var(--ztv-border);
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.ztv-dropdown-section:last-child {
  border-bottom: none;
}

.ztv-dropdown-label {
  font-size: 0.72rem;
  color: var(--ztv-text-dim);
  text-transform: uppercase;
  letter-spacing: 0.07em;
  font-weight: 700;
}

.ztv-dropdown-input {
  background: #0d0d10;
  border: 1px solid var(--ztv-border);
  color: var(--ztv-text);
  font-family: inherit;
  font-size: 0.82rem;
  padding: 6px 8px;
  border-radius: 3px;
  width: 100%;
}

.ztv-dropdown-input:focus {
  outline: none;
  border-color: var(--ztv-border-bright);
}

.ztv-dropdown-hint {
  font-size: 0.68rem;
  color: var(--ztv-text-dim);
  margin: 0;
  line-height: 1.4;
}

.ztv-dropdown-toggle-row {
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  font-size: 0.82rem;
  color: var(--ztv-text);
}

.ztv-dropdown-toggle-row input[type="checkbox"] {
  accent-color: var(--ztv-purple-bright);
  width: 15px;
  height: 15px;
  cursor: pointer;
}

.ztv-dropdown-save-btn {
  display: block;
  width: 100%;
  background: var(--ztv-purple);
  border: 1px solid var(--ztv-border-bright);
  border-radius: 3px;
  color: #fff;
  font-family: inherit;
  font-size: 0.8rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  padding: 9px 12px;
  cursor: pointer;
  transition: background 0.12s;
}

.ztv-dropdown-save-btn:hover:not(:disabled) {
  background: var(--ztv-purple-bright);
}

.ztv-dropdown-save-btn:disabled {
  opacity: 0.5;
  cursor: default;
}
