:root {
  --bg: #0e1116;
  --panel: #161b22;
  --panel-2: #1c232d;
  --line: #2a333f;
  --text: #e6edf3;
  --muted: #9aa7b4;
  --accent: #3fb950;
  --accent-2: #58c46a;
  --danger: #f85149;
  --radius: 12px;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  background: radial-gradient(1200px 600px at 50% -10%, #16202b, var(--bg));
  color: var(--text);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

.topbar {
  display: flex;
  align-items: baseline;
  gap: 16px;
  padding: 20px 24px;
  border-bottom: 1px solid var(--line);
}

.brand {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 700;
  font-size: 20px;
}

.brand-mark {
  color: var(--accent);
  font-size: 22px;
}

.tagline {
  margin: 0;
  color: var(--muted);
  font-size: 14px;
}

.wrap {
  width: 100%;
  max-width: 1040px;
  margin: 0 auto;
  padding: 32px 24px;
  flex: 1;
}

.hero {
  text-align: center;
  margin-bottom: 28px;
}

.hero h1 {
  font-size: clamp(24px, 4vw, 38px);
  margin: 8px 0;
  line-height: 1.15;
}

.sub {
  color: var(--muted);
  margin: 0 0 24px;
}

.grab {
  display: flex;
  gap: 10px;
  max-width: 640px;
  margin: 0 auto;
}

#url {
  flex: 1;
  padding: 14px 16px;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--text);
  font-size: 16px;
  outline: none;
}

#url:focus {
  border-color: var(--accent);
}

#grab-btn {
  padding: 14px 24px;
  border-radius: var(--radius);
  border: none;
  background: var(--accent);
  color: #04140a;
  font-weight: 700;
  font-size: 16px;
  cursor: pointer;
  transition: background 0.15s ease, transform 0.05s ease;
}

#grab-btn:hover {
  background: var(--accent-2);
}

#grab-btn:active {
  transform: translateY(1px);
}

#grab-btn:disabled {
  opacity: 0.6;
  cursor: default;
}

.status {
  min-height: 20px;
  margin-top: 14px;
  color: var(--muted);
  font-size: 14px;
}

.status.error {
  color: var(--danger);
}

.content-row {
  display: flex;
  gap: 24px;
  align-items: flex-start;
}

.main-col {
  flex: 1;
  min-width: 0;
}

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

.card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.card .thumb {
  aspect-ratio: 16 / 9;
  background: var(--panel-2);
  background-size: cover;
  background-position: center;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--muted);
  font-size: 13px;
}

.card .body {
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  flex: 1;
}

.card .title {
  font-size: 14px;
  line-height: 1.35;
  max-height: 3.7em;
  overflow: hidden;
}

.card .meta {
  color: var(--muted);
  font-size: 12px;
  display: flex;
  gap: 8px;
  align-items: center;
}

.tag {
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 1px 8px;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* Quality and frame rate picker. Only rendered when the source published more
   than one rendition, so it is never a control with a single choice in it. */
.card .quality {
  margin-top: auto;
  width: 100%;
  padding: 8px 10px;
  border-radius: 8px;
  border: 1px solid var(--line);
  background: var(--panel-2);
  color: var(--text);
  font-size: 13px;
  font-family: inherit;
  cursor: pointer;
}

.card .quality:hover {
  border-color: var(--accent);
}

.card .quality:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* The picker takes the auto margin when present, so the button must not also
   claim it, or the two would be pushed apart. The body's own 8px gap already
   separates them; adding a margin on top of it would double the spacing here
   and nowhere else in the card. */
.card .quality + .dl {
  margin-top: 0;
}

.card .dl {
  margin-top: auto;
  text-align: center;
  padding: 10px;
  border-radius: 8px;
  background: var(--panel-2);
  border: 1px solid var(--line);
  color: var(--text);
  font-weight: 600;
  cursor: pointer;
  font-size: 14px;
}

.card .dl:hover {
  border-color: var(--accent);
}

.promo {
  border: 1px dashed var(--line);
  border-radius: var(--radius);
  color: var(--muted);
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 90px;
}

.promo-banner {
  max-width: 1040px;
  margin: 16px auto 0;
  width: calc(100% - 48px);
}

.promo-rail {
  width: 300px;
  min-height: 600px;
  flex: 0 0 auto;
}

/* Divvy house ad -----------------------------------------------------------
   Fills both ad slots until a real ad client is configured, and points at the
   live game. This is Divvy's own surface, not ThreadSnag's, so it uses Divvy's
   tokens rather than this site's palette. The values are the dark-mode set from
   divvy/brand/tokens.css, chosen because this ad sits on a dark ground; do not
   substitute ThreadSnag's green for Divvy's, they are different greens.

   Divvy's typefaces (Jost, IBM Plex Sans) are self-hosted in the divvy repo and
   are not shipped with this app, so these fall back to the stacks Divvy declares
   in its own tokens file. */
.promo.has-house-ad {
  border: none;
  min-height: 0;
  padding: 0;
}

.house-ad {
  --divvy-green: #2fc183;
  --divvy-gold: #f0c368;
  --divvy-paper: #0d1310;
  --divvy-ink: #edf2ee;
  --divvy-slate: #8a9a91;
  --divvy-line: #1f2a24;

  --divvy-ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --divvy-divide: 280ms;

  display: flex;
  width: 100%;
  background: var(--divvy-paper);
  border: 1px solid var(--divvy-line);
  border-radius: var(--radius);
  color: var(--divvy-ink);
  font-family: "IBM Plex Sans", system-ui, "Segoe UI", sans-serif;
  text-decoration: none;
  overflow: hidden;
}

.house-ad .divvy-mark {
  flex: 0 0 auto;
}

/* The mark's one gesture: the wedge divides further off the disc. It translates
   along its own bisector (equal parts right and up, which is what the mark's own
   5.5-unit offset does) rather than scaling or spinning, because the idea is a
   share being separated out, not a shape being decorated.

   Nothing else in this ad moves. */
.house-ad .divvy-wedge {
  transition: transform var(--divvy-divide) var(--divvy-ease);
}

.house-ad:hover .divvy-wedge {
  transform: translate(1.5px, -1.5px);
}

/* The first-paint reveal: the same gesture played from flush. The wedge starts
   seated in the disc, at exactly the negative of the mark's built-in offset, and
   divides out to its resting position. One idea, seen twice.

   The class is dropped on animationend, so the animation's fill state stops
   outranking the hover transition once the mark has landed. */
.house-ad.is-dividing .divvy-wedge {
  animation: divvy-divide 760ms var(--divvy-ease) 180ms both;
}

@keyframes divvy-divide {
  from {
    transform: translate(-5.5px, 5.5px);
  }
  to {
    transform: translate(0, 0);
  }
}

.house-ad .divvy-word {
  font-family: "Jost", "Century Gothic", Futura, system-ui, sans-serif;
  font-weight: 600;
  letter-spacing: -0.025em;
  font-size: 26px;
  line-height: 1;
}

.house-ad .divvy-head {
  font-family: "Jost", "Century Gothic", Futura, system-ui, sans-serif;
  font-size: 17px;
  line-height: 1.3;
  font-weight: 600;
  margin: 0;
}

.house-ad .divvy-body {
  color: var(--divvy-slate);
  font-size: 14px;
  line-height: 1.5;
  margin: 0;
}

.house-ad .divvy-cta {
  display: inline-block;
  align-self: flex-start;
  border: 1px solid var(--divvy-green);
  border-radius: 8px;
  padding: 9px 16px;
  font-size: 14px;
  font-weight: 600;
  color: var(--divvy-green);
  transition: background 150ms ease, color 150ms ease;
}

.house-ad:hover .divvy-cta {
  background: var(--divvy-green);
  color: var(--divvy-paper);
}

.house-ad .divvy-tag {
  color: var(--divvy-slate);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

/* Sidebar: the 300x600 slot. */
.house-ad.is-side {
  flex-direction: column;
  align-items: flex-start;
  gap: 18px;
  padding: 28px 24px;
  min-height: 600px;
}

.house-ad.is-side .divvy-head {
  font-size: 21px;
}

/* Top banner: short and wide, so the copy sits beside the mark. */
.house-ad.is-top {
  flex-direction: row;
  align-items: center;
  gap: 20px;
  padding: 16px 22px;
}

.house-ad.is-top .divvy-copy {
  flex: 1;
  min-width: 0;
}

.house-ad.is-top .divvy-body {
  font-size: 13px;
}

@media (prefers-reduced-motion: reduce) {
  /* Hold the wedge where it rests: the resting state is the mark, so a share that
     has finished being divided off is the correct thing to show, not a half-cut
     one. */
  .house-ad .divvy-wedge,
  .house-ad .divvy-cta {
    transition: none;
  }
  .house-ad:hover .divvy-wedge {
    transform: none;
  }
  .house-ad.is-dividing .divvy-wedge {
    animation: none;
  }
}

.foot {
  border-top: 1px solid var(--line);
  padding: 20px 24px;
  color: var(--muted);
  font-size: 13px;
  text-align: center;
}

.foot p {
  max-width: 720px;
  margin: 0 auto;
  line-height: 1.5;
}

@media (max-width: 820px) {
  .promo-rail {
    display: none;
  }
}
