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

.pp-app {
  --bg: #f6f2e8;
  --surface: #ffffff;
  --border: #e9e4d6;
  --text: #1f2430;
  --muted: #8a8574;
  --accent: #c9972c;
  --accent-deep: #8f6a1e;
  --accent-soft: #faf3e0;
  --danger: #d05a4e;
  --radius: 16px;
  --shadow: 0 10px 32px rgba(64, 52, 20, 0.10);
  /* Width the floating style panel takes out of the stage: 18 + 350 + 18.
     The stage itself runs full-bleed underneath it, so every piece of canvas
     chrome centres against `50% + var(--panel-inset)/2` instead of 50%. */
  --panel-inset: 386px;

  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;
}

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

/* ---------- stage ---------- */
.stage {
  position: absolute;
  inset: 0;
  overflow: hidden;
}
/* a quiet warm ground: the old scattered sparkles read as clip-art */
.stage::before {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(70% 55% at 62% 34%, rgba(255, 252, 244, 0.9), rgba(255, 252, 244, 0) 70%),
    radial-gradient(90% 80% at 60% 50%, rgba(0, 0, 0, 0) 55%, rgba(96, 78, 40, 0.07) 100%);
}

/* ---------- left panel ---------- */
.side-panel {
  /* A floating window over the gallery, not a column beside it: the stage runs
     full-bleed underneath, so this needs a real lift-off shadow and a hairline
     edge to separate white-on-wall. Stays opaque — the sliding secondary
     screens have to cover the catalog they slide over, and dense style cards
     need a solid ground to stay legible. */
  position: absolute;
  left: 18px;
  top: 18px;
  bottom: 18px;
  width: 350px;
  background: var(--surface);
  border: 1px solid rgba(255, 255, 255, 0.7);
  border-radius: 22px;
  box-shadow:
    0 24px 60px rgba(48, 36, 12, 0.22),
    0 6px 18px rgba(48, 36, 12, 0.12);
  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;
}
.side-view.is-secondary,
.side-view.is-collection { transform: translateX(100%); }
.side-panel.show-history .side-view.is-primary,
.side-panel.show-collection .side-view.is-primary { transform: translateX(-24%); }
.side-panel.show-history .side-view.is-secondary { transform: translateX(0); }
.side-panel.show-collection .side-view.is-collection { transform: translateX(0); }
/* the collection screen must sit above the catalog it slid out of */
.side-view.is-collection { z-index: 2; }
.collection-count { font-size: 12px; color: var(--muted); font-weight: 600; }

.side-scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 18px 18px 10px;
}
.side-scroll::-webkit-scrollbar { width: 6px; }
.side-scroll::-webkit-scrollbar-thumb { background: #ddd6c2; border-radius: 3px; }

.cat-section { margin-bottom: 18px; }
.cat-head {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 12px;
}
.cat-icon {
  width: 26px;
  height: 26px;
  border-radius: 9px;
  background: var(--accent-soft);
  display: grid;
  place-items: center;
  font-size: 14px;
}
.cat-count { color: var(--muted); font-weight: 600; margin-left: 4px; }
.cat-title {
  font-size: 14px;
  font-weight: 700;
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cat-viewall {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  flex: none;
  font-size: 12px;
  font-weight: 600;
  color: var(--muted);
  border-radius: 8px;
  padding: 4px 2px 4px 6px;
}
.cat-viewall:hover { color: var(--text); }
.cat-viewall .chev { font-size: 13px; }
/* random-style dice at the top of the catalog */
.surprise-bar {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 16px;
  padding: 8px 12px 8px 8px;
  border-radius: 14px;
  border: 1px dashed #e0d3aa;
  background: linear-gradient(135deg, #fdf7e6, #fbf1d8);
  font-weight: 700;
  transition: transform 0.15s ease, border-color 0.15s ease;
}
.surprise-bar:hover { transform: translateY(-1px); border-color: var(--accent); }
.surprise-bar .grow { flex: 1; text-align: left; }
.surprise-bar .dice { font-size: 16px; transition: transform 0.3s ease; }
.surprise-bar:hover .dice { transform: rotate(18deg) scale(1.12); }
.surprise-face {
  width: 34px;
  height: 34px;
  flex: none;
  border-radius: 10px;
  background-color: #efe7d2;
  background-size: cover;
  background-position: center;
  box-shadow: inset 0 0 0 1px rgba(143, 106, 30, 0.25);
}

/* collapsed collection: a horizontal rail, third card deliberately cropped so
   it is obvious the row scrolls */
.style-rail {
  display: flex;
  /* flex-start, or a two-line label stretches its card taller than the rest */
  align-items: flex-start;
  gap: 10px;
  /* bleed into the panel's padding so the next card is cut off at the edge —
     that sliver is what tells people the row scrolls */
  margin-right: -18px;
  padding-right: 18px;
  overflow-x: auto;
  overflow-y: hidden;
  padding-bottom: 2px;
  scroll-snap-type: x proximity;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.style-rail::-webkit-scrollbar { display: none; }
.style-rail .style-card {
  /* width AND min-width: a flex item floors at min-content, so a long word in
     the label (Photograph, Earring) was widening individual cards */
  /* 90px: three full cards plus ~half of the fourth in a 350px panel — the
     half card is the "there is more" cue */
  flex: 0 0 90px;
  width: 90px;
  min-width: 90px;
  scroll-snap-align: start;
}

.style-grid {
  display: grid;
  /* Two per row on the See All screen: three columns in a 350px panel made the
     covers too small to judge. minmax(0, 1fr) because a bare 1fr floors at
     min-content, and a long nowrap label would widen its whole column. */
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  align-items: start;
}
.style-card {
  text-align: center;
  border-radius: 14px;
  padding: 0;
}
.style-thumb {
  aspect-ratio: 3 / 4;
  border-radius: 14px;
  background: #fdf9ee;
  border: 1px solid var(--border);
  display: grid;
  place-items: center;
  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(64, 52, 20, 0.14);
  border-color: #e3d5ac;
}
.style-card:active .style-thumb { transform: scale(0.96); }
.style-card.is-active .style-thumb {
  border: 2px solid var(--accent);
  box-shadow: 0 0 0 3px rgba(201, 151, 44, 0.18);
}
.style-name {
  margin-top: 7px;
  height: 2.6em; /* two lines reserved, so every card is the same height */
  font-size: 12px;
  line-height: 1.3;
  color: var(--text);
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

/* CSS-rendered framed-canvas thumbnail (fallback when a cover is missing) */
.art-thumb {
  width: 68%;
  aspect-ratio: 3 / 4;
  border-radius: 8px;
  position: relative;
  display: grid;
  place-items: center;
}
.art-thumb::before {
  content: '';
  position: absolute;
  inset: 8%;
  border-radius: 4px;
  border: 1.5px dashed rgba(255, 255, 255, 0.6);
  opacity: 0.7;
}
.art-thumb .art-glyph { font-size: 20px; filter: drop-shadow(0 1px 1px rgba(0,0,0,0.3)); }

/* pre-generated cover image inside a card thumb */
.style-cover { width: 100%; height: 100%; display: grid; place-items: center; border-radius: 13px; }
/* skeleton under the cover: rails otherwise flash a column of white holes while
   50 thumbnails stream in */
.style-cover.is-loading {
  background: linear-gradient(100deg, #ece5d5 20%, #f7f1e3 38%, #ece5d5 60%);
  background-size: 300% 100%;
  animation: skeleton-sweep 1.3s linear infinite;
}
@keyframes skeleton-sweep { from { background-position: 150% 0; } to { background-position: -150% 0; } }
.style-cover img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 13px;
}

/* my portraits entry (bottom of the panel) */
.my-works-bar {
  margin: 10px 14px 14px;
  border: 1px solid var(--border);
  background: #fdfbf4;
  border-radius: 16px;
  padding: 13px 16px;
  display: flex;
  align-items: center;
  gap: 10px;
  font-weight: 600;
  transition: background 0.15s ease;
}
.my-works-bar:hover { background: var(--accent-soft); }
.my-works-bar .grow { flex: 1; text-align: left; }
.my-works-bar .chev { color: var(--muted); }

/* ---------- history view ---------- */
.history-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 18px 18px 12px;
}
.history-back {
  width: 32px;
  height: 32px;
  border-radius: 10px;
  display: grid;
  place-items: center;
  background: #f6f2e8;
  font-size: 15px;
}
.history-back:hover { background: #efe9d8; }
.history-title { font-size: 16px; font-weight: 700; flex: 1; }
.history-refresh {
  width: 32px; height: 32px; border-radius: 10px;
  display: grid; place-items: center; color: var(--muted);
}
.history-refresh:hover { background: #f6f2e8; color: var(--text); }

.history-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
  padding: 4px 2px 12px;
}
.history-card {
  border-radius: 14px;
  overflow: hidden;
  border: 1px solid var(--border);
  background: #fdf9ee;
  /* portraits are 3:4 — a square card cropped every head off */
  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(64, 52, 20, 0.16); }
.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;
}
.history-more {
  display: block;
  width: 100%;
  padding: 10px;
  margin: 2px 0 12px;
  border-radius: 12px;
  background: #f6f2e8;
  color: var(--text);
  font-weight: 600;
}
.history-more:hover { background: #efe9d8; }

/* ---------- canvas area (infinite canvas) ---------- */
.canvas-area {
  /* Full-bleed on purpose: the gallery has to run edge to edge behind the
     floating panel. Reserving a column here left a strip of page background
     between the panel and the room, which read as a hard seam. */
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  overflow: hidden;
}
/* Embedded canvas target has no panel over it, so nothing to clear. */
.canvas-area.is-solo { --panel-inset: 0px; }
.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;
}
/* bare images on the canvas — no card chrome, transparency floats directly */
.world-cell {
  position: absolute;
  display: block;
  padding: 0;
  background: transparent;
  border: none;
}

/* ---------- 2D view: the generated image, bare ---------- */
.art-stack {
  --reveal: 0%;
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: #efe8d6;
}
.art-stack img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
}
/* the original photo, wiped in from the left by the handle */
.art-reference {
  position: absolute;
  inset: 0;
  clip-path: inset(0 calc(100% - var(--reveal)) 0 0);
}
.art-reference::after {
  content: 'PHOTO';
  position: absolute;
  left: 10px;
  top: 10px;
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 1.4px;
  color: #fff;
  background: rgba(0, 0, 0, 0.42);
  border-radius: 999px;
  padding: 3px 8px;
  opacity: 0;
  transition: opacity 0.2s ease;
}
.art-stack:hover .art-reference::after,
.art-stack.is-dragging .art-reference::after { opacity: 1; }

.reveal-handle {
  position: absolute;
  top: 0;
  bottom: 0;
  /* keep the grip fully inside the canvas at both extremes (it would be
     half-clipped by the stack's overflow at 0% / 100%) */
  left: clamp(23px, var(--reveal), calc(100% - 23px));
  width: 46px;
  margin-left: -23px;
  cursor: ew-resize;
  touch-action: none;
  display: grid;
  place-items: center;
  opacity: 0;
  transition: opacity 0.22s ease;
}
.art-stack:hover .reveal-handle,
.art-stack.is-dragging .reveal-handle { opacity: 1; }
.art-stack.is-revealing .reveal-handle { opacity: 0; }
.reveal-line {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 2px;
  margin-left: -1px;
  background: rgba(255, 255, 255, 0.9);
  box-shadow: 0 0 8px rgba(0, 0, 0, 0.4);
}
.reveal-grip {
  position: relative;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.96);
  color: #6b5520;
  font-size: 15px;
  display: grid;
  place-items: center;
  box-shadow: 0 4px 14px rgba(40, 30, 10, 0.35);
}
/* during the intro wipe the seam glows like wet paint */
.art-stack.is-revealing .reveal-line {
  opacity: 1;
  box-shadow: 0 0 18px 4px rgba(255, 233, 168, 0.85);
}

/* ---------- stage chrome: view tabs on top, restyle bar at the bottom ---------- */
.stage-topbar {
  position: absolute;
  top: 16px;
  left: calc(50% + var(--panel-inset) / 2);
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  justify-content: center;
  max-width: calc(100% - var(--panel-inset) - 32px);
  z-index: 4;
}
/* the room has its own orbit/zoom gestures — the world zoom row is meaningless */
.canvas-area.is-room .zoom-controls { display: none; }

.stage-actions {
  position: absolute;
  left: calc(50% + var(--panel-inset) / 2);
  /* clear of the zoom row so the two never collide on a narrow viewport */
  bottom: 78px;
  transform: translateX(-50%);
  max-width: calc(100% - var(--panel-inset) - 32px);
  z-index: 3;
  pointer-events: none;
}
.restyle-bar {
  pointer-events: auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 12px 16px 13px;
  border-radius: 20px;
  background: rgba(255, 255, 255, 0.95);
  border: 1px solid var(--border);
  box-shadow: 0 12px 34px rgba(64, 52, 20, 0.2);
  backdrop-filter: blur(8px);
}
.restyle-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
}
.restyle-label { font-size: 13px; font-weight: 700; color: var(--text); }
.restyle-list { display: flex; align-items: flex-start; gap: 10px; }
.restyle-chip {
  width: 62px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  padding: 0;
  border-radius: 12px;
}
.restyle-cover,
.restyle-dice {
  width: 56px;
  height: 56px;
  border-radius: 13px;
  background-size: cover;
  background-position: center;
  box-shadow: inset 0 0 0 1px rgba(143, 106, 30, 0.28);
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.restyle-chip:hover .restyle-cover,
.restyle-chip:hover .restyle-dice {
  transform: translateY(-2px) scale(1.04);
  box-shadow: 0 6px 14px rgba(64, 52, 20, 0.25), inset 0 0 0 2px var(--accent);
}
.restyle-name {
  width: 100%;
  font-size: 10.5px;
  color: var(--muted);
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.restyle-chip.is-dice .restyle-dice {
  display: grid;
  place-items: center;
  color: var(--accent-deep);
  background: linear-gradient(135deg, #fdf7e6, #f6e9c9);
}
.restyle-chip.is-dice:hover .restyle-dice { transform: translateY(-2px) rotate(12deg) scale(1.04); }

/* selection affordance only for legacy multi-image tasks */
.world-cell.is-selected .art-stack {
  outline: 3px solid var(--accent);
  outline-offset: 6px;
}

/* centered overlay for empty / generating / failed states */
.canvas-overlay {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 32px;
  /* empty / painting / failed states centre in the free half, not under the
     floating panel */
  padding-left: calc(32px + var(--panel-inset));
  pointer-events: none;
}
.canvas-overlay .btn-again { pointer-events: auto; }

/* zoom controls, bottom-left (bottom-right belongs to the shell's Export) */
.zoom-controls {
  position: absolute;
  left: calc(18px + var(--panel-inset));
  bottom: 18px;
  display: flex;
  gap: 6px;
  z-index: 4;
}
.canvas-area:not(.has-content) .zoom-controls { display: none; }
.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(64, 52, 20, 0.10);
  font-size: 14px;
  font-weight: 600;
  display: grid;
  place-items: center;
}
.zoom-btn:hover { background: var(--accent-soft); }
.zoom-btn:active { transform: scale(0.94); }
.zoom-pct { font-size: 12px; min-width: 46px; }

.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  max-width: 440px;
  max-height: 100%;
  min-height: 0;
}
/* The photo's own plaster matches the stage, so its edges are dissolved rather
   than framed — a hard rectangle would read as a pasted screenshot. */
.pp-app img.empty-frame-photo {
  /* Height-driven so a short viewport shrinks it instead of clipping: the
     overlay is centred inside a fixed-height stage with overflow hidden. */
  height: min(470px, 48vh);
  width: auto;
  max-width: 78vw;
  margin-bottom: 2px;
  /* Radii are percentages of the element box, and the fade only reaches zero
     alpha at a distance of one radius. So the ellipse must be 50%/50% AND
     centred: with the centre at 44% the top edge was 0.88 radii out, still ~26%
     opaque, which showed up as a hard horizontal cut across the glow. */
  -webkit-mask-image: radial-gradient(50% 50% at 50% 50%, #000 52%, rgba(0, 0, 0, 0) 100%);
  mask-image: radial-gradient(50% 50% at 50% 50%, #000 52%, rgba(0, 0, 0, 0) 100%);
}
.empty-title {
  /* a serif reads gallery, not app — and no webfont to load */
  font-family: ui-serif, Georgia, 'Times New Roman', serif;
  font-size: clamp(20px, 2.4vh + 12px, 25px);
  font-weight: 600;
  letter-spacing: 0.2px;
  margin: 0 0 8px;
}
.empty-sub { color: var(--muted); margin: 0; line-height: 1.65; font-size: 13.5px; }

/* generating */
.gen-state { text-align: center; }
.gen-art {
  width: 140px;
  height: 186px;
  margin: 0 auto 24px;
  border-radius: 10px;
  background: radial-gradient(circle at 35% 30%, #ffe9a8, #e3b64f 55%, #9c6d1c);
  box-shadow: inset 0 0 0 5px rgba(255,255,255,0.55), inset 0 0 0 8px rgba(143,106,30,0.5), 0 12px 30px rgba(64,52,20,0.28);
  position: relative;
  overflow: hidden;
}
.gen-art::after {
  content: '';
  position: absolute;
  top: -60%;
  left: -80%;
  width: 60%;
  height: 220%;
  background: linear-gradient(100deg, transparent, rgba(255,255,255,0.75), transparent);
  transform: rotate(18deg);
  animation: art-shine 1.6s ease-in-out infinite;
}
@keyframes art-shine { to { left: 130%; } }

/* waiting state: the user's own photo being painted, brush edge sweeping down */
.gen-frame {
  position: relative;
  width: 210px;
  height: 280px;
  margin: 0 auto 24px;
  overflow: hidden;
  border-radius: 4px;
  padding: 7px;
  background: linear-gradient(145deg, #f4dfa8, #c99b3f 30%, #8f6a1e 55%, #f4dfa8);
  box-shadow: inset 0 0 0 2px rgba(255,255,255,0.45), 0 18px 40px rgba(52,40,12,0.3);
}
.gen-photo {
  position: absolute;
  left: 7px;
  top: 7px;
  width: calc(100% - 14px);
  height: calc(100% - 14px);
  object-fit: cover;
}
.gen-photo.is-raw { filter: saturate(0.72) brightness(1.03); }
/* the "painted" copy is revealed top→bottom on a loop */
.gen-photo.is-painted {
  filter: saturate(1.45) contrast(1.14) brightness(0.98) blur(0.4px);
  clip-path: inset(0 0 100% 0);
  animation: gen-paint 2.8s cubic-bezier(0.45, 0.05, 0.55, 0.95) infinite;
}
@keyframes gen-paint {
  0% { clip-path: inset(0 0 100% 0); }
  70% { clip-path: inset(0 0 0 0); }
  100% { clip-path: inset(0 0 0 0); }
}
.gen-brush {
  position: absolute;
  left: 7px;
  right: 7px;
  height: 16px;
  top: 7px;
  background: linear-gradient(180deg, rgba(255,240,200,0) 0%, rgba(255,238,190,0.85) 60%, rgba(255,255,255,0) 100%);
  filter: blur(1.5px);
  animation: gen-brush-move 2.8s cubic-bezier(0.45, 0.05, 0.55, 0.95) infinite;
}
@keyframes gen-brush-move {
  0% { transform: translateY(0); opacity: 1; }
  70% { transform: translateY(266px); opacity: 1; }
  71%, 100% { opacity: 0; }
}
.gen-title { font-size: 18px; font-weight: 700; margin: 0 0 6px; }
.gen-sub { color: var(--muted); margin: 0; }

.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 ---------- */
/* ---------- generate modal ---------- */
.modal-overlay {
  position: absolute;
  inset: 0;
  z-index: 30;
  display: grid;
  place-items: center;
  padding: 24px;
  background: rgba(31, 26, 12, 0.5);
  backdrop-filter: blur(3px);
  animation: modal-fade 0.18s ease both;
}
@keyframes modal-fade { from { opacity: 0; } to { opacity: 1; } }
.modal-card {
  position: relative;
  width: min(660px, 100%);
  max-height: 100%;
  display: grid;
  grid-template-columns: 232px 1fr;
  background: var(--surface);
  border-radius: 22px;
  overflow: hidden;
  box-shadow: 0 30px 80px rgba(40, 30, 10, 0.45);
  animation: modal-rise 0.22s cubic-bezier(0.22, 1.1, 0.4, 1) both;
}
@keyframes modal-rise { from { transform: translateY(12px) scale(0.98); } to { transform: none; } }

/* left: the style, big enough to judge */
.modal-preview { position: relative; background: #efe7d4; }
.modal-preview img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.preview-caption {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 34px 16px 14px;
  color: #fff;
  background: linear-gradient(180deg, rgba(20, 14, 4, 0), rgba(20, 14, 4, 0.78));
}
.preview-name { font-size: 17px; font-weight: 800; letter-spacing: 0.2px; }
.preview-cat { font-size: 11.5px; opacity: 0.82; margin-top: 2px; letter-spacing: 0.4px; }

/* right: a tight form */
.modal-form {
  position: relative;
  padding: 20px 22px 18px;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
}
.form-title { font-size: 16px; font-weight: 800; margin: 0 34px 14px 0; }
.modal-form .modal-close {
  position: absolute;
  top: 14px;
  right: 14px;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-size: 13px;
  color: var(--muted);
  background: #f6f2e8;
}
.modal-form .modal-close:hover { color: var(--text); background: #efe9d8; }
.modal-label {
  font-size: 12px;
  font-weight: 700;
  color: var(--text);
  margin-bottom: 6px;
}
.modal-label .opt { font-weight: 600; color: var(--muted); }

/* compact dropzone: it used to be a large empty rectangle */
.dropzone {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 22px 16px 20px;
  margin-bottom: 14px;
  text-align: center;
  cursor: pointer;
  border-radius: 16px;
  border: 2px dashed #d9c68f;
  background: linear-gradient(180deg, #fffdf6, var(--accent-soft));
  transition: border-color 0.15s ease, background 0.15s ease, transform 0.12s ease;
}
.dropzone:hover, .dropzone:focus-visible, .dropzone.is-drag {
  border-color: var(--accent);
  background: linear-gradient(180deg, #fffaea, #f7ead0);
  outline: none;
}
.dropzone.is-drag { transform: scale(1.01); }
.dz-icon { line-height: 0; }
.dz-icon svg { width: 44px; height: 44px; }
.dz-main { font-size: 14px; font-weight: 700; }
.dz-btn {
  display: inline-flex;
  align-items: center;
  border-radius: 999px;
  padding: 7px 16px;
  font-size: 12.5px;
  font-weight: 700;
  color: #fff;
  background: linear-gradient(135deg, #e0b04a, var(--accent-deep));
  box-shadow: 0 3px 10px rgba(143, 106, 30, 0.3);
}
.dropzone:hover .dz-btn { filter: brightness(1.05); }

.upload-preview {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px;
  margin-bottom: 14px;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: #fdfbf4;
}
.upload-frame {
  width: 54px;
  height: 72px;
  flex: none;
  border-radius: 9px;
  overflow: hidden;
  background: #efe7d4;
}
.upload-frame img { width: 100%; height: 100%; object-fit: cover; }
.upload-actions { min-width: 0; flex: 1; }
.upload-filename {
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-bottom: 6px;
}
.upload-btns { display: flex; gap: 8px; }

.name-input, .prompt-input {
  width: 100%;
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 10px 12px;
  font: inherit;
  font-size: 13px;
  color: var(--text);
  background: #fdfbf4;
  margin-bottom: 12px;
}
.prompt-input { min-height: 72px; resize: vertical; line-height: 1.45; }
.name-input:focus, .prompt-input:focus { outline: none; border-color: var(--accent); background: #fff; }

.modal-foot {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
  margin-top: auto;
  padding-top: 4px;
}
.cost-note { font-size: 11px; color: var(--muted); text-align: right; margin-top: 8px; }
/* Free-quota pill — a copy of the shell's export hint so generation and export
   read the same. Source: generator-workbench `.export-credits-hint` /
   `.export-credits-hint-free-value`. Change both together. */
.free-hint {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 2px;
  margin-left: 10px;
  font-size: 12px;
  font-weight: 600;
  line-height: 1;
  color: #ff7c23;
  white-space: nowrap;
}
.free-hint-value {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 2px;
  height: 16px;
  padding: 2px 4px;
  border-radius: 4px;
  background: linear-gradient(90deg, #fce1bf, #ecb678 67.02%, #f9c991);
  font-size: 10px;
  font-weight: 600;
  line-height: 16px;
  color: #581e06;
}
.restyle-head .free-hint { margin-left: 0; }

@media (max-width: 720px) {
  .modal-card { grid-template-columns: 1fr; }
  .modal-preview { height: 180px; }
}

.btn-cancel {
  border-radius: 12px;
  padding: 11px 18px;
  background: #f6f2e8;
  font-weight: 600;
}
.btn-cancel:hover { background: #efe9d8; }
.btn-generate {
  border-radius: 12px;
  padding: 11px 22px;
  min-width: 150px;
  background: linear-gradient(135deg, #e0b04a, var(--accent-deep));
  color: #fff;
  font-weight: 700;
  letter-spacing: 0.2px;
  box-shadow: 0 4px 14px rgba(143, 106, 30, 0.35);
}
.btn-generate:hover { filter: brightness(1.06); }
/* busy: a spinner, not a percentage — upload/submit needs no narration */
.btn-generate.is-busy { opacity: 1; cursor: progress; }
.btn-spinner {
  display: inline-block;
  width: 18px;
  height: 18px;
  vertical-align: -3px;
  border-radius: 50%;
  border: 2.5px solid rgba(255, 255, 255, 0.45);
  border-top-color: #fff;
  animation: spin 0.8s linear infinite;
}
.btn-generate:disabled {
  /* a proper disabled palette — fading the gold gradient turned the white
     price label invisible */
  background: #ece7d8;
  color: #a29b89;
  box-shadow: none;
  cursor: not-allowed;
  filter: none;
}
.btn-generate:disabled .credit-cost { color: #a29b89; }
.btn-generate:disabled .credit-icon { opacity: 0.55; }
.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: #fdfbf4;
  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; } }

/* ---------- 3D room: the default presentation, inside the stage ---------- */
.room-layer {
  position: absolute;
  inset: 0;
  display: none;
  background: #d9d2c4;
}
.room-layer.is-on { display: block; }
.room-layer::after {
  /* gallery falloff: the wall is an unlit photo, so the vignette that makes a
     lit room read as lit is composited over the whole scene */
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  /* centred on the piece, which the camera pushes right of the layer centre to
     clear the floating panel — a vignette centred on the layer would light the
     wall behind the panel instead */
  background:
    radial-gradient(120% 85% at calc(50% + var(--panel-inset) / 2) 34%, rgba(255, 244, 222, 0.1), rgba(255, 244, 222, 0) 45%),
    radial-gradient(115% 95% at calc(50% + var(--panel-inset) / 2) 40%, rgba(28, 18, 6, 0) 52%, rgba(28, 18, 6, 0.3) 100%);
}
.room-canvas {
  position: absolute;
  inset: 0;
  cursor: grab;
}
.room-canvas:active { cursor: grabbing; }
.room-canvas canvas { display: block; width: 100%; height: 100%; }
.room-status {
  position: absolute;
  inset: 0;
  display: none;
  place-items: center;
  align-content: center;
  gap: 10px;
  text-align: center;
}
.room-status.is-on { display: grid; }
/* shown only while the finished painting's bitmap decodes */
.room-hanging {
  position: absolute;
  left: 50%;
  bottom: 26px;
  transform: translateX(-50%);
  display: none;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  border-radius: 999px;
  font-size: 12.5px;
  font-weight: 600;
  color: #5f5545;
  background: rgba(255, 255, 255, 0.9);
  box-shadow: 0 6px 18px rgba(40, 30, 10, 0.18);
  backdrop-filter: blur(6px);
}
.room-hanging.is-on { display: inline-flex; }
.room-hanging .spinner { width: 15px; height: 15px; border-width: 2px; margin: 0; }
.room-status-text { color: #6c6250; font-size: 13px; }

/* the pet's name, as a caption over the room */
.room-caption {
  position: absolute;
  left: 24px;
  bottom: 24px;
  display: none;
  color: #fff;
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.6);
  pointer-events: none;
}
.room-caption.is-on { display: block; }
.caption-name {
  font-size: 20px;
  font-weight: 800;
  letter-spacing: 1.6px;
  text-transform: uppercase;
}
.caption-style { font-size: 12.5px; opacity: 0.85; margin-top: 2px; letter-spacing: 0.6px; }

/* 2D / 3D switch + print-size chips, top centre of the stage */
.view-tabs {
  display: flex;
  gap: 3px;
  padding: 3px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.9);
  border: 1px solid var(--border);
  box-shadow: 0 4px 14px rgba(64, 52, 20, 0.14);
  backdrop-filter: blur(6px);
}
.view-tab {
  border-radius: 999px;
  padding: 7px 15px;
  font-size: 13px;
  font-weight: 700;
  color: var(--muted);
}
.view-tab:hover { color: var(--text); }
.view-tab.is-on {
  color: #fff;
  background: linear-gradient(135deg, #e0b04a, var(--accent-deep));
  box-shadow: 0 2px 8px rgba(143, 106, 30, 0.3);
}
.room-controls {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 5px 6px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.9);
  border: 1px solid var(--border);
  box-shadow: 0 4px 14px rgba(64, 52, 20, 0.14);
  backdrop-filter: blur(6px);
}
.room-chip {
  border-radius: 999px;
  padding: 6px 11px;
  font-size: 12px;
  font-weight: 700;
  color: var(--text);
}
.room-chip:hover { background: #f6f2e8; }
.room-chip.is-on {
  color: #fff;
  background: linear-gradient(135deg, #e0b04a, var(--accent-deep));
}
.room-chip.is-toggle { border: 1px dashed #e0d3aa; }
.room-chip.is-toggle.is-on { border-color: transparent; }

.ui-icon { display: inline-flex; line-height: 0; }
.cat-icon { color: var(--accent-deep); }
.bar-icon { display: inline-flex; color: var(--accent-deep); }
.surprise-bar .dice { display: inline-flex; color: var(--accent-deep); }

/* credits mark — one presentation everywhere a price appears */
.credit-icon { display: inline-flex; line-height: 0; }
.credit-cost {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  font-weight: 700;
  color: var(--text);
  white-space: nowrap;
}
.credit-amount { letter-spacing: 0.2px; }
.credit-note { font-weight: 600; color: var(--muted); }
.btn-generate .credit-cost { color: #fff; font-size: 13px; }
.btn-generate .credit-note { color: rgba(255, 255, 255, 0.8); }
.btn-generate { display: inline-flex; align-items: center; justify-content: center; gap: 8px; }

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

/* My Portraits: skeleton cards instead of a lone spinner — the grid keeps its
   shape while the first page loads, so nothing jumps when the cards arrive. */
.history-skeleton {
  aspect-ratio: 3 / 4;
  border-radius: 14px;
  background: linear-gradient(100deg, #ece5d5 20%, #f7f1e3 38%, #ece5d5 60%);
  background-size: 300% 100%;
  animation: skeleton-sweep 1.3s linear infinite;
}
@media (prefers-reduced-motion: reduce) {
  .style-cover.is-loading, .history-skeleton { animation: none; }
}

@media (max-width: 900px) {
  .side-panel { width: 280px; }
  .pp-app { --panel-inset: 316px; } /* 18 + 280 + 18 */
}

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

/* ---------- host shell overrides ---------- */
/* The Export control belongs to generator-workbench and the shell exposes no
   size option for it (only exportEnabled / exportRequiresResult / exportSvg…).
   It renders inside the workbench's shadow root — and so does this stylesheet,
   which is why the override has to live here and not in document.head.
   Shell markup: div.sidebar-footer-export.sidebar-footer-floating >
   span.sidebar-export-trigger-btn-wrap > button.sidebar-export-trigger-btn
   (utility classes set its default 236x32). !important because those utilities
   are injected at runtime and would otherwise win on order.
   TO RESIZE: change the two numbers below. */
.sidebar-footer-floating {
  /* The container shrink-wraps its content, so a 291px button overflowed it and
     the shell's `right` offset no longer described where the button ended up.
     Pinning the container to the same width makes the offset honest. */
  right: 40px !important;
  width: 291px !important;
  justify-content: flex-end !important;
}
.sidebar-footer-floating .sidebar-export-trigger-btn-wrap {
  width: 291px !important;
}
.sidebar-footer-floating .sidebar-export-trigger-btn {
  width: 291px !important;
  min-width: 291px !important;
  height: 37px !important;
  padding: 0 14px !important;
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
}
/* The dropdown (Download / Open in Studio) is hard-coded to 268px by the shell
   and anchored topLeft, so a 291px trigger left its right edge 23px short.
   The menu has to be resized with it — keep this number in sync with the
   button width above. */
.sidebar-export-dropdown-menu {
  width: 291px !important;
  min-width: 291px !important;
}

/* ---------- Buy Materials (consumables entry) ---------- */
/* Fixed spec from the platform's Buy Materials guide — the same orange on every
   generator, deliberately NOT themed to this one. Lives here because this sheet
   is injected into the workbench shadow root, where the shell footer is. No dark
   rule: this generator has no dark theme. */
/* Sits directly above Export in the shell's floating footer (flex column,
   8px gap, 291px wide), so the two read as one stack. Every metric is copied
   from .sidebar-export-trigger-btn — 291x37, 6px radius, 12px/600, 16px icon —
   because "same size as Export" is the whole point; if the export size changes,
   change it here too. `order: -1` keeps it above even if the shell re-renders
   and re-appends its own children after ours. */
.sidebar-footer-floating .buy-materials {
  order: -1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  width: 291px;
  min-width: 291px;
  height: 37px;
  padding: 0 14px;
  border: 0;
  border-radius: 6px;
  background: #f97316;
  color: #ffffff;
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  flex: 0 0 auto;
  box-shadow: 0 12px 28px rgba(17, 24, 39, 0.18);
  transition: background-color 0.15s ease;
}
.sidebar-footer-floating .buy-materials svg {
  width: 16px;
  height: 16px;
  flex: 0 0 auto;
}
.sidebar-footer-floating .buy-materials:hover { background: #ea580c; }
.sidebar-footer-floating .buy-materials:active { transform: translateY(1px); }
