:root {
  --bg: #0f1216;
  --panel: #1a1f26;
  --border: #2a313b;
  --text: #e6e9ee;
  --muted: #8b95a3;
  --accent: #4f9dff;
  --accent-strong: #2b7cf0;
  --ok: #43c59e;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  background: var(--bg);
  color: var(--text);
  line-height: 1.5;
}

header {
  text-align: center;
  padding: 2rem 1rem 0.5rem;
}

.brand {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
}

.logo {
  width: 40px;
  height: 40px;
  display: block;
}

h1 {
  margin: 0;
  font-size: 2rem;
  letter-spacing: -0.02em;
}

.tagline {
  color: var(--muted);
  margin: 0.25rem 0 0;
}

main {
  max-width: 960px;
  margin: 0 auto;
  padding: 1.5rem 1rem 4rem;
}

.dropzone {
  border: 2px dashed var(--border);
  border-radius: 14px;
  background: var(--panel);
  padding: 3rem 1rem;
  text-align: center;
  cursor: pointer;
  transition: border-color 0.15s, background 0.15s;
}

.dropzone:hover,
.dropzone:focus,
.dropzone.dragover {
  border-color: var(--accent);
  background: #161b22;
  outline: none;
}

.dropzone-inner p {
  margin: 0.2rem 0;
}

.muted {
  color: var(--muted);
}

.controls {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem 1.5rem;
  align-items: center;
  margin: 1.25rem 0;
}

.controls label {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--muted);
  font-size: 0.95rem;
}

.controls select {
  background: var(--panel);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.4rem 0.6rem;
}

.controls .checkbox {
  cursor: pointer;
}

/* Gallery: a wrapping row of cards that all share the same height but take the
   width of their image, so each cutout fills its box with no letterbox margin
   regardless of orientation (landscape = wide card, portrait = narrow card). */
.gallery {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 1.25rem;
  margin-top: 1rem;
}

.card {
  margin: 0;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 0.75rem;
  display: flex;
  flex-direction: column;
}

/* Captions are clamped to one line at the card (image) width: width:0 keeps
   them from widening the card, min-width:100% then fills the image width, and
   ellipsis clips the overflow. Keeps cards the same height; full text on hover. */
.card-name,
.card-status {
  width: 0;
  min-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.card-name {
  margin-top: 0.5rem;
  font-size: 0.85rem;
}

.card-status {
  font-size: 0.8rem;
  margin-top: 0.15rem;
}

.card-status.error {
  color: #ff6b6b;
}

.card-download {
  align-self: flex-start; /* keep the button left-aligned, not stretched */
}

.batch-actions {
  display: flex;
  justify-content: center;
  margin-top: 1rem;
}

/* Fixed-height image box; width follows the image so there's no side margin.
   fit-content stops it stretching to the card so the card sizes to the image.
   min-width keeps the box reasonable while the spinner shows (no image yet). */
.image-wrap {
  border-radius: 8px;
  overflow: hidden;
  height: 260px;
  width: fit-content;
  min-width: 120px;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* The cutout fills the box height; its width is its natural aspect ratio, so it
   reaches both edges of the (image-width) box — no checkerboard letterboxing. */
.image-wrap img {
  height: 100%;
  width: auto;
  display: block;
}

/* Checkerboard so transparency is visible behind the cutout. */
.checkerboard {
  background-color: #e9eef3;
  background-image: linear-gradient(45deg, #c7ced6 25%, transparent 25%),
    linear-gradient(-45deg, #c7ced6 25%, transparent 25%),
    linear-gradient(45deg, transparent 75%, #c7ced6 75%),
    linear-gradient(-45deg, transparent 75%, #c7ced6 75%);
  background-size: 20px 20px;
  background-position: 0 0, 0 10px, 10px -10px, -10px 0;
}

.button {
  display: inline-block;
  margin-top: 0.75rem;
  background: var(--accent-strong);
  color: white;
  text-decoration: none;
  padding: 0.5rem 1rem;
  border-radius: 8px;
  font-weight: 600;
  transition: background 0.15s;
}

.button:hover {
  background: var(--accent);
}

/* The re-run control reuses .button but is a <button> element in the controls
   row, so reset native button styling and remove the download link's top margin. */
button.button {
  margin-top: 0;
  border: none;
  font: inherit;
  cursor: pointer;
}

.button:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

/* Drawn attention when the current result is stale (model/options changed). */
.button.attention:not(:disabled) {
  background: var(--ok);
  animation: pulse 1.4s ease-in-out infinite;
}

@keyframes pulse {
  0%,
  100% {
    box-shadow: 0 0 0 0 rgba(67, 197, 158, 0.5);
  }
  50% {
    box-shadow: 0 0 0 6px rgba(67, 197, 158, 0);
  }
}

.status {
  text-align: center;
  color: var(--muted);
  min-height: 1.5rem;
}

.status.error {
  color: #ff6b6b;
}

.hint {
  text-align: center;
  font-size: 0.85rem;
  margin-top: 0.25rem;
}

.spinner {
  width: 48px;
  height: 48px;
  border: 4px solid var(--border);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}
