/* Card Generator — runtime UI styles.
   Injected into the actual runtime mount root (Shadow-DOM safe). */

.card-app {
  /* Clean neutral chrome — the colorful card covers are the only saturated
     thing on screen; a single restrained brand-orange accent ties into the
     Atomm shell. */
  --bg: #f4f4f5;
  --surface: #ffffff;
  --border: #e7e7ea;
  --text: #1b1d23;
  --muted: #85858e;
  --accent: #f97316;
  --accent-deep: #c2410c;
  --accent-soft: #fff3ea;
  --danger: #dc2626;
  --radius: 16px;
  --shadow: 0 10px 32px rgba(24, 24, 27, 0.08);

  position: relative;
  width: 100%;
  height: 100%;
  min-height: 560px;
  overflow: hidden;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  font-size: 14px;
}

.card-app *, .card-app *::before, .card-app *::after { box-sizing: border-box; }
.card-app button { font: inherit; cursor: pointer; border: none; background: none; color: inherit; }
.card-app img { display: block; max-width: 100%; }

/* ---------- stage ---------- */
.stage {
  position: absolute;
  inset: 0;
  overflow: hidden;
}
.stage-star {
  position: absolute;
  font-size: 14px;
  opacity: 0.55;
  pointer-events: none;
  user-select: none;
}

/* ---------- left panel ---------- */
.side-panel {
  position: absolute;
  left: 18px;
  top: 18px;
  bottom: 18px;
  width: 350px;
  background: var(--surface);
  border-radius: 22px;
  box-shadow: var(--shadow);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  z-index: 5;
}
.side-views {
  position: relative;
  flex: 1;
  min-height: 0;
}
.side-view {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  transition: transform 0.28s ease;
}
/* overlay views (Type detail, history) slide in over the primary view */
.side-view.is-overlay { transform: translateX(100%); }
.side-panel.show-detail .side-view.is-primary,
.side-panel.show-history .side-view.is-primary { transform: translateX(-24%); }
.side-panel.show-detail .side-view.is-detail,
.side-panel.show-history .side-view.is-history { transform: translateX(0); }

.side-scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 18px 18px 10px;
  /* native scrollbar fully hidden — a JS overlay thumb (.scroll-ghost) shows
     only while scrolling, so no gutter is reserved and the rails bleed to
     the panel edge */
  scrollbar-width: none; /* Firefox */
  -ms-overflow-style: none; /* legacy Edge */
}
.side-scroll::-webkit-scrollbar { display: none; }
/* overlay scrollbar thumb, appended next to each .side-scroll */
.scroll-ghost {
  position: absolute;
  top: 0;
  right: 4px;
  width: 5px;
  border-radius: 999px;
  background: rgba(24, 24, 27, 0.26);
  opacity: 0;
  transition: opacity 0.25s ease;
  pointer-events: none;
  z-index: 3;
}
.scroll-ghost.is-visible { opacity: 1; }

.cat-section { margin-bottom: 22px; }
.cat-head {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 12px;
}
/* bare line icon next to the Type title — no colored chip, so the covers stay
   the only colorful thing in the panel */
.cat-icon {
  width: 20px;
  height: 20px;
  display: grid;
  place-items: center;
  color: #5b5b64;
  flex: 0 0 auto;
}
.icon-slot, .cat-icon, .my-cards-icon {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
}
.my-cards-icon { color: #5b5b64; }
.cat-title { font-size: 15px; font-weight: 700; flex: 1; }
.cat-viewall {
  font-size: 12.5px;
  color: var(--muted);
  display: inline-flex;
  align-items: center;
  gap: 2px;
  border-radius: 8px;
  padding: 4px 6px;
}
.cat-viewall:hover { color: var(--text); background: #f4f4f5; }

/* horizontally scrollable rail of cards, bleeding to the panel edges.
   Card width is tuned so a 4th card peeks in about halfway — that peek is the
   scroll affordance, since the scrollbar itself is hidden. */
.style-rail {
  display: flex;
  gap: 10px;
  overflow-x: auto;
  overflow-y: hidden;
  margin: 0 -18px;
  padding: 2px 18px 4px;
  /* no scroll-snap: snapping to a card's start edge collapses the 18px left
     inset (rail snaps to scrollLeft 18) and pushes cards flush to the panel */
  scrollbar-width: none; /* Firefox */
  -ms-overflow-style: none; /* legacy Edge */
  -webkit-overflow-scrolling: touch;
}
.style-rail::-webkit-scrollbar { display: none; }
.style-rail.is-dragging { cursor: grabbing; }
.style-rail.is-dragging .style-card { pointer-events: none; }
.style-rail .style-card {
  flex: 0 0 auto;
  width: 92px;
}

/* "View all" detail view: every style in the Type, larger */
.detail-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 14px;
  padding-bottom: 14px;
}
.style-card {
  text-align: center;
  border-radius: 14px;
  padding: 0;
}
/* portrait trading-card thumbnail */
/* covers are authored at 2:3 (341×512); match it so the whole card shows
   with object-fit:cover and nothing gets cropped */
.style-thumb {
  aspect-ratio: 2 / 3;
  border-radius: 12px;
  background: #f4f4f5;
  border: 1px solid var(--border);
  display: grid;
  place-items: center;
  overflow: hidden;
  transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}
.style-card:hover .style-thumb {
  transform: translateY(-2px);
  box-shadow: 0 6px 16px rgba(24, 24, 27, 0.12);
  border-color: #d6d6db;
}
.style-card:active .style-thumb { transform: scale(0.96); }
/* selection reads as ink, not another color competing with the cover */
.style-card.is-active .style-thumb {
  border: 2px solid #1b1d23;
  box-shadow: 0 0 0 3px rgba(24, 24, 27, 0.10);
}
.style-name {
  margin-top: 7px;
  font-size: 12px;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* CSS-rendered card thumbnail (fallback art) */
.card-thumb {
  width: 78%;
  aspect-ratio: 2 / 3;
  border-radius: 8px;
  position: relative;
  display: grid;
  place-items: center;
}
.card-thumb .card-glyph {
  font-size: 26px;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.35));
}

/* pre-generated cover image inside a card thumb */
.style-cover { width: 100%; height: 100%; display: grid; place-items: center; }
.style-cover img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 11px;
}

/* my cards entry (bottom of the panel) */
/* `.card-app` prefix needed: the generic `.card-app button` reset would
   otherwise win over a single-class selector and strip the background */
.card-app .my-cards-bar {
  margin: 10px 14px 14px;
  background: #f7f7f8;
  border-radius: 16px;
  height: 43px;
  padding: 0 16px;
  display: flex;
  align-items: center;
  gap: 10px;
  font-weight: 600;
  transition: background 0.15s ease;
}
.my-cards-bar:hover { background: #efeff1; }
.my-cards-bar .grow { flex: 1; text-align: left; }
.my-cards-bar .chev { color: var(--muted); }

/* ---------- history view ---------- */
.panel-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 18px 18px 12px;
}
/* aligned with the Type dropdown pill: same height, radius, border and
   surface fill so the two controls read as one row */
.card-app .panel-back {
  width: 40px;
  height: 40px;
  flex: 0 0 auto;
  border-radius: 12px;
  display: grid;
  place-items: center;
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
  font-size: 19px;
  line-height: 1;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.card-app .panel-back:hover { background: #f7f7f8; border-color: #d6d6db; }
.panel-title { font-size: 16px; font-weight: 700; flex: 1; }

/* Type switcher (detail-view header) — a pill that drops a menu of Types */
.type-switch { position: relative; flex: 1; min-width: 0; }
.card-app .type-trigger {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 8px;
  height: 40px;
  padding: 0 14px;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: var(--surface);
  font-size: 15px;
  font-weight: 700;
  color: var(--text);
  transition: background 0.15s ease, border-color 0.15s ease;
}
.card-app .type-trigger:hover { background: #f7f7f8; }
.type-switch.is-open .type-trigger { border-color: #d6d6db; background: #f7f7f8; }
.type-current { flex: 1; text-align: left; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.type-caret {
  flex: 0 0 auto;
  color: var(--muted);
  font-size: 15px;
  line-height: 1;
  transition: transform 0.18s ease;
}
.type-switch.is-open .type-caret { transform: rotate(180deg); }

.type-menu {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  right: 0;
  z-index: 20;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: 0 12px 34px rgba(24, 24, 27, 0.14);
  padding: 6px;
  display: none;
}
.type-switch.is-open .type-menu { display: block; }
.card-app .type-option {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 10px;
  border-radius: 10px;
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  transition: background 0.12s ease;
}
.card-app .type-option:hover { background: #f4f4f5; }
.card-app .type-option.is-current { color: var(--accent-deep); }
.type-option-icon { color: #5b5b64; }
.type-option.is-current .type-option-icon { color: var(--accent-deep); }
.type-option .grow { flex: 1; text-align: left; }

.history-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
  padding: 4px 2px 12px;
}
.card-app .history-card {
  border-radius: 12px;
  overflow: hidden;
  border: 1px solid var(--border);
  background: #f4f4f5;
  aspect-ratio: 3 / 4;
  position: relative;
  padding: 0;
}
.history-card img { width: 100%; height: 100%; object-fit: cover; }
.history-card:hover { box-shadow: 0 6px 16px rgba(24, 24, 27, 0.14); }
.history-card.is-loading { opacity: 0.55; cursor: progress; }
.history-card .badge {
  position: absolute;
  right: 6px;
  bottom: 6px;
  background: rgba(31, 36, 48, 0.72);
  color: #fff;
  font-size: 11px;
  border-radius: 8px;
  padding: 2px 7px;
}
.history-card .center-note {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  color: var(--muted);
  font-size: 12px;
  padding: 8px;
  text-align: center;
}
.history-empty, .history-login {
  color: var(--muted);
  text-align: center;
  padding: 42px 18px;
  font-size: 13px;
  line-height: 1.6;
}
.card-app .history-more {
  display: block;
  width: 100%;
  padding: 10px;
  margin: 2px 0 12px;
  border-radius: 12px;
  background: #f4f4f5;
  color: var(--text);
  font-weight: 600;
}
.history-more:hover { background: #e9e9ec; }

/* ---------- canvas area (infinite canvas) ---------- */
.canvas-area {
  position: absolute;
  --canvas-left: 386px; /* also how far the 3D stage extends back under the panel */
  left: var(--canvas-left);
  right: 0;
  top: 0;
  bottom: 0;
  overflow: hidden;
}
.canvas-area.is-solo { --canvas-left: 0px; left: 0; }
.canvas-area.has-content { cursor: grab; }
.canvas-area.is-panning { cursor: grabbing; }

/* transformed world layer — translate/scale via the view state */
.world-layer {
  position: absolute;
  left: 0;
  top: 0;
  transform-origin: 0 0;
  will-change: transform;
}
.world-cell {
  position: absolute;
  display: block;
  padding: 0;
  background: transparent;
  border: none;
  border-radius: 18px;
  overflow: hidden;
  box-shadow: 0 18px 44px rgba(15, 23, 42, 0.22);
}
/* grow into place instead of popping — the loading card is much smaller than
   the fitted result, so an instant swap reads as a jolt. Only on NEW results;
   re-renders (multi-select) don't replay it. */
.world-cell.is-new { animation: cell-reveal 0.55s cubic-bezier(0.22, 0.9, 0.3, 1); }
@keyframes cell-reveal {
  from { opacity: 0; transform: scale(0.86) translateY(14px); }
}
.world-cell img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
}
/* selection affordance only for legacy multi-image tasks */
.world-cell.is-selected {
  outline: 3px solid var(--accent);
  outline-offset: 6px;
}
.world-cell .check {
  position: absolute;
  top: -4px;
  right: -4px;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  display: grid;
  place-items: center;
  font-size: 14px;
  box-shadow: 0 2px 6px rgba(24, 24, 27, 0.28);
}

/* centered overlay for empty / generating / failed states */
.canvas-overlay {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 32px;
  pointer-events: none;
}
.canvas-overlay .btn-again { pointer-events: auto; }

/* floating top bar: the 2D/3D stage switch, top-right of the canvas */
.canvas-topbar {
  position: absolute;
  top: 16px;
  left: 18px;
  right: 18px;
  display: flex;
  justify-content: flex-end;
  align-items: flex-start;
  gap: 8px;
  z-index: 4;
  pointer-events: none;
}
.canvas-topbar > * { pointer-events: auto; }
.stage-mode {
  display: flex;
  gap: 4px;
  padding: 4px;
  margin-left: auto;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 999px;
  box-shadow: 0 2px 10px rgba(24, 26, 38, 0.08);
}
.stage-mode:empty { display: none; }
.view-tab {
  border-radius: 999px;
  padding: 7px 14px;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  transition: background 0.15s ease, color 0.15s ease;
}
.view-tab:hover { color: var(--text); }
.view-tab.is-active {
  background: var(--text);
  color: #fff;
}

/* 3D stage */
.three-stage {
  position: absolute;
  inset: 0;
  display: none;
  user-select: none;
}
.three-stage.is-active { display: block; }
.three-stage canvas { display: block; width: 100%; height: 100%; }
.canvas-area.is-3d { cursor: default; }
/* The 3D scene paints its own backdrop and reflective floor. Confined to the
   canvas area it would stop dead at the panel's edge, leaving a slab of flat
   page background on the left instead of the panel floating over a whole
   scene. Extend it back under the panel; safe to unclip here because the 2D
   world layer and zoom controls are hidden in 3D anyway. The renderer
   compensates for the covered strip so the card stays centred in what you
   can see. */
.canvas-area.is-3d { overflow: visible; }
.canvas-area.is-3d .three-stage {
  left: calc(-1 * var(--canvas-left));
  z-index: 0;
}
.canvas-area.is-3d .world-layer,
.canvas-area.is-3d .zoom-controls,
.canvas-area.is-3d .stage-star { display: none; }

/* zoom controls, bottom-left (bottom-right belongs to the shell's Export) */
.zoom-controls {
  position: absolute;
  left: 18px;
  bottom: 18px;
  display: flex;
  gap: 6px;
  z-index: 4;
}
.canvas-area:not(.has-content) .zoom-controls { display: none; }
.card-app .zoom-btn {
  min-width: 32px;
  height: 32px;
  padding: 0 8px;
  border-radius: 10px;
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: 0 2px 8px rgba(24, 24, 27, 0.08);
  font-size: 14px;
  font-weight: 600;
  display: grid;
  place-items: center;
}
.zoom-btn:hover { background: #f4f4f5; }
.zoom-btn:active { transform: scale(0.94); }
.zoom-pct { font-size: 12px; min-width: 46px; }

.empty-state { text-align: center; max-width: 440px; }
/* a dealt hand of three REAL covers (one per Type) — the empty state
   advertises the product itself, not a placeholder drawing */
.empty-fan {
  position: relative;
  width: 296px;
  height: 236px;
  margin: 0 auto 22px;
  animation: placeholder-float 6s ease-in-out infinite;
}
.fan-card {
  position: absolute;
  width: 132px;
  aspect-ratio: 2 / 3;
  border-radius: 12px;
  overflow: hidden;
  background: #e9e9ec;
  box-shadow: 0 16px 36px rgba(24, 24, 27, 0.22), 0 0 0 4px #fff;
}
.fan-card img { width: 100%; height: 100%; object-fit: cover; }
.fan-left { left: 4px; top: 28px; transform: rotate(-11deg); z-index: 1; }
.fan-center { left: 82px; top: 4px; z-index: 2; box-shadow: 0 22px 44px rgba(24, 24, 27, 0.26), 0 0 0 4px #fff; }
.fan-right { left: 160px; top: 28px; transform: rotate(11deg); z-index: 1; }
@keyframes placeholder-float {
  0%, 100% { transform: translateY(0) rotate(-0.6deg); }
  50% { transform: translateY(-12px) rotate(0.6deg); }
}
@media (prefers-reduced-motion: reduce) {
  .empty-fan { animation: none; }
}
.empty-title { font-size: 21px; font-weight: 700; margin: 0 0 8px; }
.empty-sub { color: var(--muted); margin: 0; line-height: 1.6; }

/* generating */
.gen-state { text-align: center; }

/* ---------- generating cutscene ----------
   The picked style's REAL cover floats in soft light while a scan beam
   "develops" it — real artwork, few elements, slow soft motion. A CSS-drawn
   fake card always reads cheap next to the covers; never draw one. */
.gen-stage {
  position: relative;
  width: 280px;
  height: 300px;
  margin: 0 auto 20px;
  perspective: 900px;
}
/* soft breathing light behind the card */
.gen-glow {
  position: absolute;
  left: 50%;
  top: 46%;
  width: 300px;
  height: 300px;
  margin: -150px 0 0 -150px;
  background: radial-gradient(circle, rgba(255, 196, 120, 0.30), rgba(255, 196, 120, 0.10) 44%, transparent 68%);
  filter: blur(6px);
  animation: glow-breathe 3.4s ease-in-out infinite;
}
@keyframes glow-breathe {
  0%, 100% { opacity: 0.85; transform: scale(1); }
  50% { opacity: 0.55; transform: scale(0.94); }
}
/* gentle hover, split into two independent SYMMETRIC loops (bob + sway) with
   different periods — piecewise keyframe paths have velocity kinks that read
   as tiny drops; two sines can't. */
.gen-float {
  position: absolute;
  left: 50%;
  top: 12px;
  width: 176px;
  height: 246px;
  margin-left: -88px;
  transform-style: preserve-3d;
  animation: float-bob 5.2s ease-in-out infinite;
}
@keyframes float-bob {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-12px); }
}
.gen-card2 {
  position: absolute;
  inset: 0;
  border-radius: 14px;
  overflow: hidden;
  /* light neutral fallback fill — a dark card flashing before the face
     decodes reads as a glitch on this light stage */
  background: linear-gradient(160deg, #ececef, #d9d9de);
  box-shadow:
    0 24px 48px rgba(24, 24, 27, 0.30),
    0 0 0 1px rgba(255, 255, 255, 0.55),
    0 0 44px rgba(255, 190, 110, 0.28);
  animation: card-sway 7.8s ease-in-out infinite alternate;
}
@keyframes card-sway {
  from { transform: rotateY(-7deg) rotateX(2deg); }
  to { transform: rotateY(7deg) rotateX(3.2deg); }
}
/* the card face fades in once its image has decoded */
.gen-face {
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 0.45s ease;
}
.gen-face.is-loaded { opacity: 1; }
/* text-only runs: the style cover is only a tone-setting ghost — blurred past
   recognition so it never reads as someone else's finished card */
.gen-card2.is-ghost .gen-face {
  filter: blur(10px) saturate(0.8) brightness(1.05);
  transform: scale(1.12); /* hide the blur's soft edges */
}
.gen-card2.is-ghost .gen-face.is-loaded { opacity: 0.6; }
/* printer-style scan beam developing the card */
.gen-scan {
  position: absolute;
  left: -10%;
  right: -10%;
  top: 0;
  height: 34%;
  background: linear-gradient(180deg,
    transparent,
    rgba(255, 255, 255, 0.35) 42%,
    rgba(255, 244, 214, 0.75) 50%,
    rgba(255, 255, 255, 0.35) 58%,
    transparent);
  filter: blur(1px);
  mix-blend-mode: screen;
  animation: scan-sweep 2.8s cubic-bezier(0.45, 0, 0.55, 1) infinite;
}
@keyframes scan-sweep {
  0% { transform: translateY(-110%); opacity: 0; }
  8% { opacity: 1; }
  62% { transform: translateY(310%); opacity: 1; }
  70%, 100% { transform: translateY(310%); opacity: 0; }
}
/* slow diagonal holo sheen */
.gen-sheen {
  position: absolute;
  inset: 0;
  background: linear-gradient(115deg,
    transparent 32%,
    rgba(255, 255, 255, 0.30) 44%,
    rgba(255, 205, 250, 0.22) 50%,
    rgba(185, 235, 255, 0.26) 56%,
    transparent 68%);
  background-size: 250% 100%;
  mix-blend-mode: soft-light;
  animation: sheen-sweep 4.2s ease-in-out infinite;
}
@keyframes sheen-sweep {
  0%, 12% { background-position: 130% 0; }
  70%, 100% { background-position: -50% 0; }
}
/* a few quiet twinkles around the card */
.gen-spark2 {
  position: absolute;
  color: #dcae62;
  opacity: 0;
  font-size: var(--s);
  animation: twinkle var(--t) ease-in-out infinite;
  animation-delay: var(--d);
  pointer-events: none;
}
@keyframes twinkle {
  0%, 100% { opacity: 0; transform: scale(0.5) rotate(0deg); }
  50% { opacity: 0.85; transform: scale(1) rotate(24deg); }
}
/* grounded soft shadow, breathing in sync with the 6s hover */
.gen-shadow2 {
  position: absolute;
  left: 50%;
  bottom: 6px;
  width: 150px;
  height: 20px;
  margin-left: -75px;
  border-radius: 50%;
  background: radial-gradient(ellipse at center, rgba(24, 24, 27, 0.26), transparent 70%);
  animation: shadow-breathe 5.2s ease-in-out infinite; /* synced with float-bob */
}
@keyframes shadow-breathe {
  0%, 100% { transform: scale(1); opacity: 0.55; }
  50% { transform: scale(0.85); opacity: 0.32; }
}

@media (prefers-reduced-motion: reduce) {
  .gen-glow, .gen-float, .gen-card2, .gen-scan, .gen-sheen, .gen-spark2, .gen-shadow2 { animation: none; }
  .gen-scan { display: none; }
}
.gen-title { font-size: 18px; font-weight: 700; margin: 0 0 6px; }
.gen-sub {
  color: var(--muted);
  margin: 0;
  transition: opacity 0.2s ease, transform 0.2s ease;
}
.gen-sub.is-swapping { opacity: 0; transform: translateY(5px); }

.btn-again {
  background: var(--text);
  color: #fff;
  border-radius: 999px;
  padding: 8px 16px;
  font-weight: 600;
  font-size: 13px;
}
.btn-again:hover { background: #343b4d; }

/* failed */
.fail-state { text-align: center; max-width: 420px; }
.fail-icon { font-size: 40px; margin-bottom: 14px; }
.fail-title { font-size: 17px; font-weight: 700; margin: 0 0 8px; }
.fail-sub { color: var(--muted); margin: 0 0 18px; line-height: 1.6; }

/* ---------- modal ---------- */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(31, 36, 48, 0.45);
  display: grid;
  place-items: center;
  z-index: 60;
  animation: fade-in 0.18s ease;
}
@keyframes fade-in { from { opacity: 0; } }
.modal-card {
  width: min(520px, calc(100vw - 48px));
  max-height: calc(100vh - 64px);
  overflow-y: auto;
  background: var(--surface);
  border-radius: 22px;
  box-shadow: 0 24px 80px rgba(15, 23, 42, 0.3);
  padding: 0;
  animation: pop-in 0.2s ease;
  /* Head and foot stay pinned; only .modal-body scrolls. Keeping the card
     itself clipped means the scrollbar never runs behind the close button
     or the Generate button, and the rounded corners stay clean. */
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
@keyframes pop-in { from { transform: scale(0.96); opacity: 0; } }

/* clean white header: small cover thumb + title + one guidance line
   (reference-design layout — no hero backdrop, no chips) */
.modal-head {
  flex: none;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 22px 24px 16px;
}
.head-thumb {
  width: 56px;
  height: 84px;
  flex: none;
  border-radius: 10px;
  overflow: hidden;
  background: #f4f4f5;
  border: 1px solid var(--border);
  display: grid;
  place-items: center;
}
.head-thumb .style-cover img { border-radius: 0; }
.head-thumb .card-thumb { width: 88%; }
.head-text { flex: 1; min-width: 0; }
.modal-title { font-size: 19px; font-weight: 800; margin: 0; letter-spacing: 0.1px; }
.modal-subtitle { font-size: 13px; color: var(--muted); margin-top: 4px; line-height: 1.5; }
.card-app .modal-close {
  align-self: flex-start;
  flex: none;
  width: 34px;
  height: 34px;
  border-radius: 11px;
  display: grid;
  place-items: center;
  color: #52525b;
  font-size: 14px;
  background: #f4f4f5;
  transition: background 0.15s ease;
}
.card-app .modal-close:hover { background: #e9e9ec; }

/* the only scrolling region — head and foot are pinned. A slim inset pill
   scrollbar (visible when an external mouse forces classic scrollbars);
   the 3px transparent border makes the thumb read as a 6px pill floating
   inside the body rather than a bar glued to the edge. */
.modal-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 4px 24px 8px;
  scrollbar-width: thin; /* Firefox */
  scrollbar-color: #d4d4d9 transparent;
}
.modal-body::-webkit-scrollbar { width: 12px; }
.modal-body::-webkit-scrollbar-track { background: transparent; }
.modal-body::-webkit-scrollbar-thumb {
  background: #d4d4d9;
  border-radius: 999px;
  border: 3px solid transparent;
  background-clip: padding-box;
}
.modal-body::-webkit-scrollbar-thumb:hover { background-color: #bcbcc4; background-clip: padding-box; }

/* `.card-app` prefix needed: the dropzone is a <button>, so the generic
   `.card-app button` reset would strip the dashed border and the fill */
.card-app .dropzone {
  width: 100%;
  border: 1.5px dashed #d6d6db;
  background: linear-gradient(180deg, #fcfcfd 0%, #f4f4f5 100%);
  border-radius: 16px;
  padding: 28px 16px;
  text-align: center;
  color: var(--muted);
  transition: border-color 0.15s ease, background 0.15s ease, transform 0.15s ease;
}
.card-app .dropzone:hover,
.card-app .dropzone.is-drag {
  border-color: var(--accent);
  background: linear-gradient(180deg, #fffaf5 0%, #ffefe2 100%);
}
.dropzone:active { transform: scale(0.99); }
.dropzone .dz-icon { margin-bottom: 6px; }
.dropzone .dz-icon svg { display: inline-block; filter: drop-shadow(0 2px 4px rgba(24, 24, 27, 0.10)); transition: transform 0.15s ease; }
.dropzone:hover .dz-icon svg, .dropzone.is-drag .dz-icon svg { transform: translateY(-2px); }
.dropzone:hover .dzi-frame, .dropzone.is-drag .dzi-frame { stroke: var(--accent); }
.dropzone:hover .dzi-hill, .dropzone.is-drag .dzi-hill { stroke: var(--accent); }
.dropzone .dz-main { font-weight: 700; color: var(--text); margin-bottom: 4px; font-size: 14px; }
.dropzone .dz-sub { font-size: 12px; }

.upload-preview {
  display: flex;
  gap: 14px;
  align-items: center;
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 10px;
  background: #fafafa;
}
.upload-frame {
  width: 96px;
  height: 96px;
  flex: none;
  border-radius: 12px;
  overflow: hidden;
  border: 1px solid var(--border);
  background:
    conic-gradient(#eee 0 25%, #fff 0 50%, #eee 0 75%, #fff 0) 0 0 / 16px 16px;
}
.upload-frame img { width: 100%; height: 100%; object-fit: cover; }
.upload-actions { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.upload-filename {
  font-size: 12.5px;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 260px;
}
.upload-btns { display: flex; gap: 8px; }
.card-app .btn-ghost {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 7px 14px;
  font-size: 13px;
  font-weight: 600;
  background: #fff;
}
.btn-ghost:hover { background: #f4f4f5; }
.btn-ghost.is-danger:hover { background: #fdeeee; border-color: #efc7c5; color: var(--danger); }

.modal-label { font-size: 13px; font-weight: 700; margin: 20px 0 8px; }
.modal-body .modal-label:first-child { margin-top: 0; }
/* consistent 18px gap between unlabeled sections (dropzone → field grid) */
.modal-body .slot-grid { margin-top: 18px; }
/* …but not when the grid opens the body (e.g. tarot: no photo section) */
.modal-body > .slot-grid:first-child { margin-top: 0; }
.modal-label .opt { color: var(--muted); font-weight: 400; }
/* the freeform "Anything else" label sits among the quieter slot labels in
   More details — match their weight/color so it doesn't out-shout them */
.adv-body .modal-label { font-size: 12px; font-weight: 600; color: #63636b; }
.adv-body .modal-label .opt { color: #b0b0b8; }
.prompt-input {
  width: 100%;
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 10px 12px;
  font: inherit;
  font-size: 13px;
  resize: vertical;
  min-height: 64px;
  background: #fafafa;
  color: var(--text);
}
.prompt-input:focus { outline: 2px solid rgba(249, 115, 22, 0.28); border-color: var(--accent); }
/* demoted freeform box — no longer the primary input */
.modal-body .prompt-input { min-height: 52px; }

/* magic wand inside the More-details textarea: taps in a ready-made example */
.prompt-wrap { position: relative; }
.prompt-wrap .prompt-input { padding-right: 40px; }
.card-app .wand-btn {
  position: absolute;
  right: 8px;
  top: 8px;
  width: 28px;
  height: 28px;
  border-radius: 9px;
  display: grid;
  place-items: center;
  font-size: 14px;
  background: var(--accent-soft);
  box-shadow: inset 0 0 0 1px rgba(249, 115, 22, 0.25);
  transition: transform 0.12s ease, background 0.12s ease;
}
.card-app .wand-btn:hover { background: #ffe6d2; transform: rotate(-8deg) scale(1.08); }
.card-app .wand-btn:active { transform: scale(0.92); }

/* guided slot fields: labeled inputs with example placeholders */
.slot-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px 12px;
}
.slot-field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.slot-label { font-size: 12px; font-weight: 600; color: #63636b; }
/* quieter "(optional)" suffix on every optional field label */
.slot-opt { font-weight: 400; color: #b0b0b8; }
.req-star { color: var(--accent-deep); font-weight: 700; }
.card-app .slot-input {
  width: 100%;
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 8px 10px;
  font: inherit;
  font-size: 13px;
  background: #fafafa;
  color: var(--text);
}
.card-app .slot-input:focus { outline: 2px solid rgba(249, 115, 22, 0.25); border-color: var(--accent); }
/* a lone primary field spans the full width instead of sitting half-empty */
.slot-grid .slot-field:only-child { grid-column: 1 / -1; }
/* …same for a field left alone on its row after a full-row chips field */
.slot-grid .slot-field.slot-chips + .slot-field:last-child { grid-column: 1 / -1; }
/* chip fields (e.g. Tarot theme) always take the full row */
.slot-field.slot-chips { grid-column: 1 / -1; }
.chip-row { display: flex; flex-wrap: wrap; gap: 8px; }
.card-app .chip {
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 6px 12px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text);
  background: #fafafa;
  transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}
/* two-part chip labels ("Love · The Lovers"): meaning leads, card name recedes */
.chip .chip-sub { font-weight: 500; color: #a2a2aa; }
.card-app .chip.is-on .chip-sub { color: rgba(255, 255, 255, 0.85); }
.card-app .chip:hover { border-color: #fdba74; background: var(--accent-soft); }
.card-app .chip.is-on {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
/* inline input revealed by the "Custom ✏️" chip */
.card-app .chip-custom-input { margin-top: 8px; }

/* required-photo dropzone is the hero of the first screen — taller, still light */
.card-app .dropzone.is-hero { padding: 40px 16px; }

/* "More options" disclosure keeps advanced inputs out of the way */
.card-app .adv-toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 16px;
  padding: 6px 2px;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
}
.card-app .adv-toggle:hover { color: var(--text); }
.adv-toggle .adv-caret { font-size: 11px; }
.adv-section { margin-top: 10px; }
.adv-section[hidden] { display: none; }
/* the freeform box follows other advanced content without its own label */
.adv-body > * + .prompt-wrap,
.adv-body > * + .prompt-input { margin-top: 14px; }

/* footer: one full-width primary action, credits beside it (reference design) */
.modal-foot {
  flex: none;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 16px 24px 24px;
}
.cost-note { font-size: 12.5px; color: var(--muted); line-height: 1.5; }
.cost-note[hidden] { display: none; }
.foot-row {
  display: flex;
  align-items: center;
  gap: 16px;
}
/* `.card-app` prefix needed on these buttons: the generic `.card-app button`
   reset (higher specificity) would otherwise strip their backgrounds */
.card-app .btn-generate {
  flex: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  border-radius: 14px;
  height: 48px;
  padding: 0 22px;
  background: linear-gradient(135deg, #fb923c, #ea580c);
  color: #fff;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.2px;
  box-shadow: 0 4px 14px rgba(234, 88, 12, 0.30);
}
.foot-credits {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  white-space: nowrap;
}
.foot-credits:empty { display: none; }
.credits-icon { display: inline-block; vertical-align: -2px; flex: 0 0 auto; }
.btn-generate:hover { filter: brightness(1.06); }
.btn-generate:disabled { opacity: 0.55; cursor: not-allowed; filter: none; }
.btn-generate:active:not(:disabled) { transform: scale(0.98); }

/* ---------- embed panel ---------- */
.embed-panel { padding: 16px; background: var(--surface); }
.embed-panel .field { display: flex; flex-direction: column; gap: 6px; margin-bottom: 14px; }
.embed-panel label { font-size: 12.5px; color: var(--muted); font-weight: 600; }
.embed-panel select, .embed-panel input {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 8px 10px;
  font: inherit;
  font-size: 13px;
  background: #fafafa;
  color: var(--text);
}

/* ---------- toast ---------- */
.toast-root {
  position: fixed;
  bottom: 28px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 80;
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: center;
  pointer-events: none;
}
.toast {
  background: rgba(31, 36, 48, 0.92);
  color: #fff;
  border-radius: 12px;
  padding: 10px 18px;
  font-size: 13px;
  max-width: 420px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
  animation: toast-in 0.22s ease;
}
@keyframes toast-in { from { transform: translateY(8px); opacity: 0; } }

.world-cell.is-previewable { cursor: zoom-in; }

/* spinner */
.spinner {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 2.5px solid #e4e4e7;
  border-top-color: var(--accent);
  animation: spin 0.8s linear infinite;
  margin: 0 auto;
}
@keyframes spin { to { transform: rotate(360deg); } }

@media (max-width: 900px) {
  .side-panel { width: 280px; }
  .canvas-area { --canvas-left: 310px; padding: 18px; }
}

@media (prefers-reduced-motion: reduce) {
  .card-app *, .card-app *::before, .card-app *::after { animation: none !important; transition: none !important; }
}
