/* The clip player. Dark, narrow, and shaped like the thing it is going to
   become: a 9:16 video. */

* { box-sizing: border-box; }

body {
  margin: 0;
  padding: 0 16px 40px;
  background: #0b1220;
  color: #e6f2ff;
  font: 400 15px/1.5 system-ui, -apple-system, "Segoe UI", sans-serif;
}

.clip-head {
  display: flex;
  align-items: center;
  gap: 14px;
  max-width: 900px;
  margin: 0 auto;
  padding: 14px 0 18px;
}
.clip-brand img { height: 30px; display: block; }
.clip-titles { flex: 1; min-width: 0; }
.clip-who { font-size: 16px; font-weight: 900; }
.clip-meta { font-size: 12.5px; color: #93a6bd; }
.clip-back {
  flex: none;
  color: #062238;
  background: #43dced;
  text-decoration: none;
  font-weight: 800;
  font-size: 13px;
  padding: 9px 14px;
  border-radius: 999px;
}

.clip-status { max-width: 900px; margin: 40px auto; text-align: center; color: #93a6bd; }

.clip-stage { max-width: 430px; margin: 0 auto; }

/* The frame IS the format. aspect-ratio rather than a fixed height so it fills
   a phone and still fits a laptop without two sets of numbers. */
.clip-frame {
  position: relative;
  aspect-ratio: 9 / 16;
  width: 100%;
  overflow: hidden;
  border-radius: 18px;
  border: 1px solid rgba(255, 255, 255, .14);
  background: #05080f;
  box-shadow: 0 24px 60px rgba(0, 0, 0, .5);
}

/* The split. The video takes the top of the frame and the world takes the
   rest, so a phone screen holds both without either being a thumbnail. */
.clip-video {
  position: absolute;
  top: 3.5%;
  left: 5%;
  width: 90%;
  aspect-ratio: 16 / 9;
  z-index: 400;
  overflow: hidden;
  border-radius: 12px;
  border: 2px solid rgba(255, 255, 255, .28);
  background: #000;
  box-shadow: 0 14px 34px rgba(0, 0, 0, .55);
}
.clip-video video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.clip-video.is-empty { display: none; }
.clip-video.is-empty { display: none; }

.clip-world { position: absolute; inset: 0; overflow: hidden; }

/* Everything on the map that does not move. */
.clip-scenery { position: absolute; inset: 0; }
.clip-prop { position: absolute; }
.clip-prop img { width: 100%; height: 100%; display: block; }
/* Platform art hangs from the walk line at its natural aspect, exactly as in
   game: the thin box is the collision, not the picture. */
.clip-prop--platform { overflow: visible; }
.clip-prop--platform img { width: 100%; height: auto; max-width: none; }

/* Stars, and whatever else is in the air. A projectile lives about a second, so
   these are drawn fresh each frame rather than tracked between them. */
.clip-shots, .clip-loose { position: absolute; inset: 0; pointer-events: none; }

/* A coin on the floor. Small, and it should read as a pickup rather than an
   actor — half the size of anything that can be fought. */
.clip-drop {
  position: absolute;
  transform: translate(-50%, -50%);
  z-index: 205;
}
.clip-drop img { width: 100%; height: 100%; object-fit: contain; display: block; }

.clip-pinata {
  position: absolute;
  transform: translate(-50%, -50%);
  z-index: 206;
}
.clip-pinata img { width: 100%; height: 100%; object-fit: contain; display: block; }
.clip-pinata.is-popped { opacity: .35; filter: saturate(.4); }

/* What they say. Above the head, clipped to a couple of lines — a bubble that
   grows with the sentence would cover the fight it is reacting to. */
.clip-actor__bubble {
  position: absolute;
  left: 50%;
  bottom: 104%;
  transform: translateX(-50%);
  max-width: 220px;
  width: max-content;
  padding: 4px 8px;
  border-radius: 9px;
  background: rgba(255, 255, 255, .95);
  color: #14181d;
  font-size: 10px;
  font-weight: 800;
  line-height: 1.25;
  text-align: center;
  box-shadow: 0 4px 12px rgba(0, 0, 0, .35);
  z-index: 500;
  pointer-events: none;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.clip-actor__bubble[hidden] { display: none; }

/* A rope is drawn, not arted — same as in game. */
.clip-prop--rope {
  background: repeating-linear-gradient(180deg, #d8b26a 0 6px, #8a6c34 6px 12px);
  border-radius: 3px;
  opacity: .9;
}
/* ---- Projectiles, copied from game.css ----------------------------------
   These are the ENGINE's rules, not a lookalike. A basic star has no image at
   all — it is a clip-path polygon drawn through ::before and ::after — and each
   ability's projectile has its own class, its own art and its own size. Sizes
   are in the game's own pixels and scaled by --clip-scale, which is what makes
   28px mean "28 world units" inside a 405-unit-wide frame.

   Kept in step with game.css by hand. If a projectile ever looks wrong in a
   clip and right in the game, this block is the first place to look. */
.projectile {
  position: absolute;
  width: calc(28px * var(--clip-scale, 1));
  height: calc(28px * var(--clip-scale, 1));
  transform: translate(-50%, -50%);
  filter: drop-shadow(0 0 8px rgba(255, 255, 255, .45));
  z-index: 210;
}
.projectile::before,
.projectile::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at 50% 50%, #f8fafc 0%, #cbd5e1 28%, #94a3b8 58%, rgba(148,163,184,0) 62%);
  clip-path: polygon(50% 0%, 61% 36%, 98% 36%, 68% 57%, 79% 100%, 50% 72%, 21% 100%, 32% 57%, 2% 36%, 39% 36%);
}
.projectile::after { transform: scale(0.42); filter: blur(0.5px); }
.projectile img { display: block; width: 100%; height: 100%; object-fit: contain; }

/* A projectile carrying real art hides the drawn star underneath it. */
.projectile--duckies-pack {
  width: calc(76px * var(--clip-scale, 1));
  height: calc(36px * var(--clip-scale, 1));
  filter: drop-shadow(0 8px 12px rgba(0, 0, 0, .32)) drop-shadow(0 0 10px rgba(255, 255, 255, .35));
}
.projectile--candy-pack,
.projectile--star-swap {
  width: calc(64px * var(--clip-scale, 1));
  height: calc(64px * var(--clip-scale, 1));
}
.projectile--power-ball {
  width: calc(54px * var(--clip-scale, 1));
  height: calc(54px * var(--clip-scale, 1));
}
.projectile--backpack {
  width: calc(72px * var(--clip-scale, 1));
  height: calc(72px * var(--clip-scale, 1));
}
.projectile--bomb-art {
  width: calc(200px * var(--clip-scale, 1));
  height: calc(200px * var(--clip-scale, 1));
}
/* Anything with its own picture drops the drawn star, exactly as in game. */
.projectile--duckies-pack:has(img)::before,
.projectile--duckies-pack:has(img)::after,
.projectile--candy-pack:has(img)::before,
.projectile--candy-pack:has(img)::after,
.projectile--star-swap:has(img)::before,
.projectile--star-swap:has(img)::after,
.projectile--backpack:has(img)::before,
.projectile--backpack:has(img)::after,
.projectile--power-ball:has(img)::before,
.projectile--power-ball:has(img)::after { display: none; content: none; }

/* A swing. The rig has no attack pose here, so the character leans into it —
   enough to read as "this is the moment they hit something". */
.clip-actor.is-attacking { animation: clipSwing .18s ease-out; }
@keyframes clipSwing {
  0% { transform: translateX(0) scale(1); }
  50% { transform: translateX(2%) scale(1.06); }
  100% { transform: translateX(0) scale(1); }
}

/* Wider than the frame and slid sideways: the camera moves the world, not the
   other way round, which keeps every actor's position a straight percentage. */
.clip-bg {
  position: absolute;
  top: 0;
  background-size: 100% 100%;
  background-position: center;
  background-repeat: no-repeat;
}

/* Above the platforms. Scenery carries its own z-index and an actor carried
   none, so a monster standing on a platform was drawn BEHIND it — the one thing
   in the frame that must never be hidden by scenery. Front-layer decor still
   passes in front, at 300, exactly as it does in game. */
.clip-actor { position: absolute; z-index: 200; }
.clip-actor[hidden] { display: none; }
.clip-actor__art {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}
.clip-actor.is-down .clip-actor__art { opacity: .35; filter: grayscale(1); }

/* The real skin, drawn by the character system over the fallback sprite. Once
   it lands the sprite is hidden rather than removed — a failed render leaves
   the plain character rather than an empty gap where a player was. */
.clip-actor__skin { position: absolute; inset: 0; }
.clip-actor__skin > * { width: 100%; height: 100%; }
.clip-actor.has-skin .clip-actor__art { visibility: hidden; }
.clip-actor.is-down .clip-actor__skin { opacity: .35; filter: grayscale(1); }

.clip-actor__name {
  position: absolute;
  left: 50%;
  bottom: -15px;
  transform: translateX(-50%);
  font-size: 9px;
  font-weight: 800;
  white-space: nowrap;
  color: #fff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .9);
}
.clip-actor--monster .clip-actor__name { display: none; }

.clip-actor__hp {
  position: absolute;
  left: 12%;
  top: -7px;
  width: 76%;
  height: 4px;
  border-radius: 999px;
  background: rgba(0, 0, 0, .55);
  overflow: hidden;
}
.clip-actor__hp i {
  display: block;
  height: 100%;
  width: 100%;
  background: linear-gradient(180deg, #8cf58c, #17a017);
}
.clip-actor--player .clip-actor__hp i { background: linear-gradient(180deg, #9ad4ff, #1256a8); }
.clip-actor.is-down .clip-actor__hp { display: none; }

.clip-transport {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 14px;
}
.clip-play {
  flex: none;
  height: 38px;
  padding: 0 16px;
  font: inherit;
  font-size: 13px;
  font-weight: 900;
  color: #062238;
  background: #43dced;
  border: 0;
  border-radius: 999px;
  cursor: pointer;
}
.clip-sound {
  flex: none;
  width: 38px;
  height: 38px;
  font-size: 15px;
  color: inherit;
  background: rgba(255, 255, 255, .08);
  border: 1px solid rgba(255, 255, 255, .14);
  border-radius: 999px;
  cursor: pointer;
}
.clip-sound.is-on { background: rgba(67, 220, 237, .18); border-color: rgba(67, 220, 237, .5); }

.clip-scrub { flex: 1; min-width: 0; accent-color: #43dced; }
.clip-time { flex: none; font-size: 12.5px; font-weight: 800; color: #93a6bd; min-width: 44px; text-align: right; }

.clip-note {
  margin: 14px 0 0;
  font-size: 12px;
  line-height: 1.45;
  color: #7d8ea6;
  text-align: center;
}

/* ---- The library --------------------------------------------------------- */

.clip-library { max-width: 900px; margin: 0 auto; }
.clip-library__title { font-size: 20px; font-weight: 900; margin: 0 0 14px; }
.clip-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 12px; }

.clip-card {
  display: block;
  padding: 14px 16px;
  border-radius: 14px;
  border: 1px solid rgba(255, 255, 255, .12);
  background: rgba(255, 255, 255, .05);
  color: inherit;
  text-decoration: none;
}
.clip-card:hover { border-color: rgba(67, 220, 237, .5); background: rgba(67, 220, 237, .08); }
.clip-card__who { font-size: 14.5px; font-weight: 900; }
.clip-card__meta { margin-top: 3px; font-size: 12px; color: #93a6bd; }

/* A recorded clip is a plain video in the same 9:16 frame. */
.clip-recorded { width: 100%; height: 100%; object-fit: contain; background: #000; display: block; }
.clip-download { display: inline-block; margin-top: 14px; border: 0; font: inherit; font-weight: 800; cursor: pointer; }
.clip-download.is-busy { opacity: .7; cursor: default; }

.clip-post { display: inline-block; margin: 14px 0 0 10px; border: 0; font: inherit; font-weight: 800; cursor: pointer; }
.clip-post:disabled { opacity: .65; cursor: default; }
