/* ============================================================================
   Design Studio (static/js/design_studio.js)

   Brand colours come from design.css (--brand-600 indigo), so the composer
   reads as the same product as the landing page and the other studios. The one
   local variable is the accent used for "this is selected" so the state is
   consistent everywhere and only has to be changed in one place.
   ========================================================================= */

#designStudioView {
  --ds-primary: var(--brand-600, #4f46e5);
  --ds-primary-soft: rgba(79, 70, 229, .10);
  --ds-line: var(--border, #e2e8f0);
  --ds-ink: var(--text, #0f172a);
  --ds-dim: var(--text-3, #64748b);
  --ds-2: var(--text-2, #475569);
  --ds-surface: var(--surface, #f8fafc);
}

#designStudioView .ds-card { margin-bottom: 16px; }

/* `position: sticky` CANNOT work inside an ancestor with `overflow: hidden`: the
   ancestor becomes the scrollport, and because it is not the thing that scrolls,
   the sticky box can never move. The shared `.card` sets exactly that (to clip
   child backgrounds at its rounded corners), which is why the preview column used
   to scroll away despite `.ds-preview-inner` being correctly sticky. Nothing
   inside a studio card needs clipping, so the cards opt out. */
#designStudioView .ds-card { overflow: visible; }

/* ---- header ------------------------------------------------------------- */
#designStudioView .ds-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 14px; flex-wrap: wrap; margin-bottom: 6px;
}
#designStudioView .ds-title { margin: 0; font-size: 19px; font-weight: 800; color: var(--ds-ink); }
#designStudioView .ds-sub { margin: 4px 0 0; font-size: 13px; color: var(--ds-dim); max-width: 70ch; }
#designStudioView .ds-head2 {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 10px;
}
#designStudioView .ds-head2 h3 { margin: 0; font-size: 15px; font-weight: 700; }
#designStudioView .ds-head2 .ds-hint { flex: 1 1 auto; }

/* ---- progress strip ----------------------------------------------------- */
/* ONE bar in place of the five numbered step bubbles. The bubbles wrapped onto two
   or three lines on a phone — they pushed the canvas off the first screen — and the
   row grew every time a step was added, while this band is a fixed ~40px whether the
   flow is two steps or seven. The label underneath is the answer the bubbles were
   really giving: where am I, and how much is left. */
#designStudioView .ds-progress-wrap { margin: 12px 0 14px; }
#designStudioView .ds-progress {
  height: 6px; border-radius: 999px; background: #eef2f7; overflow: hidden;
}
#designStudioView .ds-progress-fill {
  height: 100%; border-radius: 999px; transition: width .28s ease;
  background: linear-gradient(135deg, var(--brand-500, #6366f1), var(--accent-500, #06b6d4));
}
/* Respect a user who has asked for less motion: the fill still moves, it just does
   not animate. A progress bar is information, so it must not disappear entirely. */
@media (prefers-reduced-motion: reduce) {
  #designStudioView .ds-progress-fill { transition: none; }
}
#designStudioView .ds-progress-t {
  display: flex; align-items: baseline; gap: 8px; margin-top: 7px;
  font-size: 12.5px; color: var(--ds-dim);
}
#designStudioView .ds-progress-t b { color: var(--ds-ink); font-weight: 800; }
#designStudioView .ds-progress-t span {
  margin-inline-start: auto; font-weight: 700; color: var(--ds-2);
}
#designStudioView .ds-progress-t span:focus { outline: none; }

/* ---- the bottom navigation bar ------------------------------------------ */
/* The walk controls, pinned to the foot of the view.
   On a phone the primary action belongs in the thumb zone, and the app's own bottom
   nav is already there — so this bar has to sit ABOVE it (64px + the safe area),
   exactly as `.vm-foot` in video_maker.css does. Without the offset it would be
   painted underneath the tabs and the Next button would be unreachable. */
#designStudioView .ds-bottombar {
  display: flex; align-items: center; gap: 10px;
  position: sticky; bottom: 0; z-index: 6;
  margin: 16px -2px -2px; padding: 10px 2px 12px;
  background: linear-gradient(180deg, rgba(255,255,255,0), #fff 38%);
}
#designStudioView .ds-bottombar:empty { display: none; }
#designStudioView .ds-bottombar .ds-flow-btn { flex: 1 1 auto; justify-content: center; }
#designStudioView .ds-bottombar .ds-nav-pos {
  flex: none; font-size: 12.5px; font-weight: 700; color: var(--ds-dim);
}
@media (max-width: 900px) {
  #designStudioView .ds-bottombar {
    bottom: calc(64px + env(safe-area-inset-bottom, 0px));
    padding-bottom: 10px;
    background: rgba(255,255,255,.97);
    -webkit-backdrop-filter: saturate(140%) blur(8px); backdrop-filter: saturate(140%) blur(8px);
    border-top: 1px solid var(--ds-line);
    box-shadow: 0 -6px 18px rgba(15,23,42,.06);
    /* Bleed to the card edges so the bar reads as part of the frame, not as a
       floating pill inside it. */
    margin-inline: -14px; padding-inline: 14px;
  }
}
/* ---- the shared Previous / Next buttons --------------------------------- */
#designStudioView .ds-flow-btn {
  display: inline-flex; align-items: center; gap: 5px; white-space: nowrap;
  cursor: pointer; justify-content: center;
}
#designStudioView .ds-flow-btn[disabled] { opacity: .45; cursor: default; }
#designStudioView .ds-nav-arrow { line-height: 1; }

/* ---- the token pill ----------------------------------------------------- */
/* It was two loud pills (12.5px/700) sitting in the middle of the panel: the least
   useful thing on screen until the moment it blocks a generation. Now it is a small
   muted pill in the header corner, and the figures behind it are the tooltip. */
#designStudioView .ds-meter-wrap { display: flex; flex-wrap: wrap; gap: 6px; justify-content: flex-end; }
#designStudioView .ds-meter {
  display: inline-flex; align-items: center; gap: 5px; white-space: nowrap;
  font-size: 11.5px; font-weight: 700; padding: 4px 10px; border-radius: 999px;
  background: var(--ds-surface); color: var(--ds-dim);
  border: 1px solid var(--ds-line);
}
#designStudioView .ds-meter.none { background: #fef3c7; color: #92400e; border-color: #fcd34d; }
#designStudioView .ds-meter.ok { background: #dcfce7; color: #166534; border-color: #86efac; }

/* ---- two columns -------------------------------------------------------- */
/* The preview column must STRETCH to the height of the controls column, and the
   sticky must live on an INNER wrapper. This was the bug behind "the preview
   scrolls away": with `align-items: start` the column was only as tall as the
   canvas, so a sticky element on it had zero travel and never moved. A sticky
   box can only travel INSIDE its containing block, so the containing block has
   to be the tall column and the sticky box has to be the small one inside it. */
#designStudioView .ds-main {
  display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: 18px;
}
#designStudioView .ds-side { min-width: 0; }
#designStudioView .ds-preview-col { min-width: 0; }
#designStudioView .ds-preview-inner { position: sticky; top: 82px; }
#designStudioView .ds-preview {
  display: flex; align-items: center; justify-content: center;
  background: repeating-conic-gradient(#eef2f7 0 25%, #fff 0 50%) 0 0 / 18px 18px;
  border: 1px solid var(--ds-line); border-radius: 14px; padding: 12px;
  min-height: 220px; overflow: hidden;
}
#designStudioView #dsCanvas {
  max-width: 100%; max-height: 62vh; width: auto; height: auto;
  box-shadow: 0 10px 30px rgba(15, 23, 42, .16); border-radius: 4px; display: block;
}
#designStudioView .ds-preview-meta {
  margin-top: 8px; font-size: 12.5px; color: var(--ds-dim); text-align: center;
}
#designStudioView .ds-preview-meta b { color: var(--ds-ink); }

/* ---- the picture door's action, under the preview ------------------------ */
/* The Generate button used to be the last thing in the controls column, a full
   column away from the box the picture appears in. Under the preview it is next to
   its own result, which is also where the spinner runs — one place to look. */
#designStudioView .ds-genbar {
  display: flex; flex-direction: column; gap: 6px; margin-top: 10px;
}
#designStudioView .ds-genbar .btn { width: 100%; justify-content: center; }
#designStudioView .ds-genbar .ds-hint { text-align: center; }
/* The wait, where the thing being waited for will appear. A static "Your image will
   appear here." during a 40-second generation reads as "the press did nothing". */
#designStudioView .ds-cardbusy {
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  padding: 10px; font-size: 12.5px; color: var(--ds-dim); text-align: center;
}
#designStudioView .ds-spin {
  width: 30px; height: 30px; border-radius: 50%; flex: none;
  border: 3px solid #e2e8f0; border-top-color: var(--brand-500, #6366f1);
  animation: ds-spin .9s linear infinite;
}
@keyframes ds-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  /* Still turns, so it still reads as "working" — just slower. */
  #designStudioView .ds-spin { animation-duration: 2.6s; }
}

/* ---- Export: the working / done pop-up ---------------------------------- */
/* Export is a server round-trip (render, encode, write the library row) and it used
   to give no sign of life at all — the button looked like it had done nothing for
   seconds. This is the sign of life, and it then becomes the confirmation, so the
   answer arrives in the same place the question was asked. */
#designStudioView .ds-busy {
  position: fixed; inset: 0; z-index: 90;
  display: flex; align-items: center; justify-content: center; padding: 16px;
  background: rgba(15, 23, 42, .48);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
}
#designStudioView .ds-busy-card {
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  width: 100%; max-width: 380px; padding: 22px 20px 18px;
  background: #fff; border-radius: 18px; text-align: center;
  box-shadow: 0 24px 60px rgba(15, 23, 42, .28);
}
#designStudioView .ds-busy-ico { font-size: 30px; line-height: 1; }
#designStudioView .ds-busy-t { font-size: 15px; font-weight: 800; color: var(--ds-ink); }
#designStudioView .ds-busy-n { font-size: 12.5px; color: var(--ds-dim); line-height: 1.5; }
#designStudioView .ds-busy-act { display: flex; gap: 8px; margin-top: 6px; }
#designStudioView .ds-busy-act .btn { min-width: 96px; justify-content: center; }

/* ---- the arrow glyphs --------------------------------------------------- */
/* The ‹ › inside the bottom bar and the wizard's footer. They used to be hidden on
   desktop (the full words "Previous"/"Next" were wide enough) and shown on a phone;
   now that the buttons sit in a narrow sticky bar the arrow is always drawn. */
#designStudioView .ds-nav-arrow { display: inline-block; }
#designStudioView .ds-nav-pos {
  flex: 1 1 auto; text-align: center; font-size: 12.5px; font-weight: 700; color: var(--ds-2);
}

/* ---- sections ----------------------------------------------------------- */
/* ONE vertical rhythm: every section is 16px above and below its divider, and the
   last element in a section never adds its own bottom margin on top of that. The
   bottom margin is the issue — `.ds-hint` (8px), `.ds-note`/`.ds-warn`/`.ds-cost`
   (8px), `.ds-row` (9px), `.ds-actions` and `.ds-ta` (10px) all shipped one, so the
   gap between a section's content and the next divider was anything from 4 to 16px
   depending on which control happened to come last. Zeroing it on the last child
   makes the cadence the same all the way down the panel. */
#designStudioView .ds-sec {
  border-top: 1px solid var(--ds-line); padding: 16px 0;
}
#designStudioView .ds-sec:first-child { border-top: none; padding-top: 0; }
#designStudioView .ds-sec > :last-child { margin-bottom: 0; }
/* The mode row is the panel's opening line, not a block: when it is collapsed it
   holds a single sentence and should not get a full section's worth of air. */
#designStudioView .ds-sec-mode { padding-top: 0; border-top: none; }
#designStudioView .ds-sec-mode > :last-child { margin-bottom: 0; }
#designStudioView .ds-sec h4 {
  margin: 0 0 8px; font-size: 13px; font-weight: 800; color: var(--ds-ink);
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}
/* A section title with its own action on the right — the result screen's heading
   and its "Edit the setup" button. The heading's own flex would put the button in
   the wrapping line of words, which is where a control must not be. */
#designStudioView .ds-sechead {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
}
#designStudioView .ds-sechead h4 { margin: 0; }
#designStudioView .ds-sechead .btn { margin-inline-start: auto; flex: none; }
#designStudioView .ds-count {
  font-size: 11.5px; font-weight: 700; color: var(--ds-dim); margin-inline-start: auto;
}
#designStudioView .ds-hint { font-size: 12px; color: var(--ds-dim); margin-bottom: 8px; line-height: 1.6; }
#designStudioView .ds-hint.dim { opacity: .82; }
#designStudioView .ds-note {
  font-size: 11.5px; color: var(--ds-dim); background: var(--ds-surface);
  border: 1px solid var(--ds-line); border-radius: 10px; padding: 8px 10px; margin: 8px 0;
}
#designStudioView .ds-warn {
  font-size: 12px; color: #92400e; background: #fffbeb; border: 1px solid #fcd34d;
  border-radius: 10px; padding: 8px 10px; margin: 8px 0; line-height: 1.6;
}
#designStudioView .ds-cost {
  font-size: 12px; font-weight: 700; color: var(--ds-primary); margin: 8px 0;
}
#designStudioView .ds-empty {
  font-size: 12.5px; color: var(--ds-dim); text-align: center; padding: 16px;
  border: 1px dashed var(--ds-line); border-radius: 12px; background: #fcfdff;
}
#designStudioView .ds-err { color: #dc2626; text-align: center; padding: 24px; font-weight: 600; }
#designStudioView .ds-loading { text-align: center; padding: 28px; color: var(--ds-dim); font-weight: 700; }

/* ---- template tiles ----------------------------------------------------- */
#designStudioView .ds-tiles {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px;
}
#designStudioView .ds-tile {
  display: flex; flex-direction: column; gap: 3px; text-align: start; cursor: pointer;
  font-family: inherit; padding: 11px 14px; border-radius: 13px;
  background: #fff; border: 1.5px solid var(--ds-line); transition: all .16s;
}
#designStudioView .ds-tile:hover { border-color: rgba(79, 70, 229, .45); transform: translateY(-1px); }
#designStudioView .ds-tile.on {
  border-color: var(--ds-primary); background: var(--ds-primary-soft);
  box-shadow: 0 4px 14px rgba(79, 70, 229, .18);
}
#designStudioView .ds-tile-ico { font-size: 19px; line-height: 1; }
#designStudioView .ds-tile-t { font-size: 13px; font-weight: 800; color: var(--ds-ink); }
#designStudioView .ds-tile-s { font-size: 11.5px; color: var(--ds-dim); line-height: 1.5; }
#designStudioView .ds-tile.sm { padding: 10px 14px; }

/* ---- the step chooser ("✏️ Edit the setup") ------------------------------ */
/* A box per question, each led by its step number. The number is a small round
   badge rather than the tile's usual 19px emoji slot: these boxes carry no icon,
   and a bare digit at heading size reads as a typo instead of as "Step 6". */
#designStudioView .ds-tile[data-ds-goto] .ds-tile-ico {
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; border-radius: 50%; margin-bottom: 3px;
  font-size: 12.5px; font-weight: 800;
  background: var(--ds-surface); color: var(--ds-2);
  border: 1px solid var(--ds-line);
}
#designStudioView .ds-tile[data-ds-goto].on .ds-tile-ico {
  background: var(--ds-primary); color: #fff; border-color: transparent;
}

/* ---- Text to Image's sub-choice (text card vs AI image) ----------------- */
/* RETIRED. Both were a second pill row under one door, and then a door of their
   own — the picture job is an AI Creative door now, beside AI Design, so there is
   no chooser left for these to label. The rules stay only as a marker; nothing
   renders a `.ds-subpick` any more and test_design_studio.py asserts that. */

/* ---- mode chooser (the five doors) --------------------------------------- */
/* A strip of chips, not five cards. Each mode used to carry its own two-line
   description inside a card, so the panel opened with a wall of grey paragraphs and
   the only description of the mode you were in was one of them. The description now
   lives in the section hint ABOVE the strip and follows the selection (see modeBar),
   which is one line instead of five.

   FIVE across, and there is no submenu: the picture job used to be a second pill row
   inside AI Assist, which was a level of nesting to answer one question. The wrap
   points are explicit rather than `auto-fit`, because `auto-fit` reflows 5 items
   4+1 at some widths and that reads as a mistake rather than a layout. */
#designStudioView .ds-modes {
  display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 7px;
}
@media (max-width: 980px) {
  #designStudioView .ds-modes { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
  #designStudioView .ds-modes { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
#designStudioView .ds-mode {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  text-align: center; font-family: inherit; cursor: pointer;
  /* 12px of side padding, not 13: five chips leave less room per chip, and the
     label still has to clear the frame. */
  padding: 11px 12px; border-radius: 12px; background: #fff;
  border: 1.5px solid var(--ds-line); color: var(--ds-2);
  transition: all .16s;
}
#designStudioView .ds-mode:hover { border-color: var(--ds-primary); background: #fbfbff; }
#designStudioView .ds-mode.on {
  border-color: var(--ds-primary); background: var(--ds-primary-soft);
  box-shadow: 0 4px 14px rgba(79, 70, 229, .14);
}
#designStudioView .ds-mode-ico { font-size: 16px; line-height: 1.1; }
#designStudioView .ds-mode-t {
  font-size: 12.5px; font-weight: 800; color: var(--ds-ink); line-height: 1.35;
}
#designStudioView .ds-mode.on .ds-mode-t { color: var(--ds-primary); }

/* ---- text-to-image card preview ----------------------------------------- */
/* The card comes back from the server as a PNG, so it is an <img> in the same
   box the canvas would use. `object-fit: contain` keeps a 1080x1920 story fully
   visible instead of cropping it to the box. */
#designStudioView #dsCardPreview { object-fit: contain; box-shadow: 0 10px 30px rgba(15, 23, 42, .16); }
#designStudioView #dsCardText { min-height: 84px; }
#designStudioView #dsCardCount { text-align: end; margin-top: 4px; }
#designStudioView .ds-err:empty { display: none; }
#designStudioView .ds-preview-meta.ds-err { color: #dc2626; font-weight: 600; }
#designStudioView .ds-tile.sm .ds-tile-t { font-size: 12.5px; }

/* ---- pills -------------------------------------------------------------- */
#designStudioView .ds-pills { display: flex; flex-wrap: wrap; gap: 7px; }
#designStudioView .ds-pill {
  cursor: pointer; font-family: inherit; font-size: 12.5px; font-weight: 700;
  padding: 7px 13px; border-radius: 999px; background: #fff; color: var(--ds-2);
  border: 1.5px solid var(--ds-line); transition: all .16s;
}
#designStudioView .ds-pill small { font-weight: 600; opacity: .7; font-size: 11px; }
#designStudioView .ds-pill:hover { border-color: rgba(79, 70, 229, .45); }
#designStudioView .ds-pill.on {
  background: var(--ds-primary); border-color: var(--ds-primary); color: #fff;
}
#designStudioView .ds-pill.sm { padding: 6px 11px; font-size: 12px; }

/* ---- photo thumbs ------------------------------------------------------- */
#designStudioView .ds-thumbs {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
  gap: 9px; margin-top: 10px;
}
#designStudioView .ds-thumb {
  position: relative; aspect-ratio: 1 / 1; border-radius: 12px; overflow: hidden;
  border: 2px solid var(--ds-line); background: var(--ds-surface); cursor: pointer;
}
#designStudioView .ds-thumb.on { border-color: var(--ds-primary); box-shadow: 0 0 0 3px var(--ds-primary-soft); }

/* MULTI-SELECTED (Ctrl-click). A dashed ring + a tick, deliberately DIFFERENT from
   `.on`'s solid ring and glow: the user has to be able to tell "the one I am looking
   at" from "the ones this change will also hit", and two identical highlights would
   make a bulk edit impossible to predict. Inset, so a picked photo never looks like
   a focused one. */
#designStudioView .ds-thumb.sel {
  border-color: var(--ds-ink-2, #64748b);
  box-shadow: inset 0 0 0 3px rgba(255, 255, 255, .85);
}
#designStudioView .ds-thumb.on.sel {
  box-shadow: 0 0 0 3px var(--ds-primary-soft), inset 0 0 0 3px rgba(255, 255, 255, .85);
}
#designStudioView .ds-thumb-sel {
  position: absolute; inset-inline-end: 5px; top: 5px;
  width: 18px; height: 18px; border-radius: 999px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--ds-primary); color: #fff; font-size: 12px; font-weight: 800;
}
#designStudioView .ds-note .ds-mini {
  margin-inline-start: 6px; width: 20px; height: 20px; border-radius: 999px;
  background: rgba(255, 255, 255, .9); font-size: 10px;
}
/* ---- the AI source pictures (what a picture is made FROM) ---------------- *
 * Up to four references now, so they are a GRID of small squares like the photo
 * tray rather than the single full-width image this slot used to print (the slot
 * had NO rules at all, so one 1080px photo filled the panel). The ✕ sits on the
 * chip's inline-end; the FILE NAME only rides a lone picture, because four
 * filenames is a wall of grey text. */
#designStudioView .ds-src { margin: 8px 0; }
#designStudioView .ds-src-head { display: flex; flex-wrap: wrap; gap: 6px; align-items: baseline; }
#designStudioView .ds-src-l { font-size: 12px; font-weight: 800; color: var(--ds-ink); }
#designStudioView .ds-src-note { font-size: 11.5px; color: var(--ds-dim); line-height: 1.5; }
#designStudioView .ds-src-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(64px, 76px));
  gap: 7px; margin: 8px 0;
}
#designStudioView .ds-src-on {
  position: relative; aspect-ratio: 1 / 1; border-radius: 10px; overflow: hidden;
  border: 1.5px solid var(--ds-line); background: var(--ds-surface);
}
#designStudioView .ds-src-on img { width: 100%; height: 100%; object-fit: cover; display: block; }
#designStudioView .ds-src-on .ds-mini { position: absolute; inset-inline-end: 4px; top: 4px; }
#designStudioView .ds-src-on .ds-src-name {
  position: absolute; inset-inline: 0; bottom: 0; padding: 3px 6px;
  font-size: 10.5px; color: #fff; background: rgba(15, 23, 42, .62);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* ---- the APPLIED LOOK (AI Creative's style menu) ------------------------- *
 * Picking a look pastes its wording into the prompt, so the note that used to say
 * so in grey is now a STATE: a tinted box the same colour as every other "this is
 * on" surface (`.ds-tile.on`, `.ds-mode.on`), the tick and the look's own name, and
 * the two ways out. `Clear` and `Change style` are text buttons, not the 20px round
 * `.ds-mini` the source slot uses — a round icon button cannot hold the words the
 * user asked for ("[ Clear ] [ Change style ]"). */
#designStudioView .ds-style-on {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  border-color: var(--ds-primary); background: var(--ds-primary-soft);
  font-size: 11.5px;
}
#designStudioView .ds-style-on-t { font-weight: 800; color: var(--ds-ink); }
#designStudioView .ds-style-link {
  cursor: pointer; font-family: inherit; font-size: 11px; font-weight: 700;
  line-height: 1; padding: 6px 10px; border-radius: 999px;
  border: 1px solid #cbd5e1; background: #fff; color: var(--ds-2);
}
#designStudioView .ds-style-link:hover { border-color: var(--ds-primary); color: var(--ds-primary); }
#designStudioView .ds-style-link:focus-visible { outline: 2px solid var(--ds-primary); outline-offset: 1px; }

/* Compact strip: the same thumbnails inside the per-photo editor, where they are a
   selector rather than a gallery — smaller, no reorder/remove buttons, and always
   visible so switching photo is one tap instead of a scroll to the preview column.

   KEPT: `thumbsHtml(compact)` is still called with `true` from nowhere now that the
   ◀ ▶ picker is gone, but the class is harmless and the strip is exactly the shape a
   future compact picker would want. */
#designStudioView .ds-thumbs.sm {
  grid-template-columns: repeat(auto-fill, minmax(56px, 1fr)); gap: 6px; margin: 8px 0 4px;
}
#designStudioView .ds-thumbs.sm .ds-thumb { border-radius: 9px; }
#designStudioView .ds-thumbs.sm .ds-thumb-n { min-width: 15px; height: 15px; font-size: 10px; }

/* The ◀ ▶ picker and its position label are gone with the photo arrows — a thumbnail
   is the control. Their rules were DELETED rather than left behind, because a rule
   nobody renders reads as "this still exists" to the next person changing it. */
#designStudioView .ds-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
#designStudioView .ds-thumb-ph {
  display: flex; align-items: center; justify-content: center; height: 100%; font-size: 22px;
}
#designStudioView .ds-thumb-n {
  position: absolute; inset-inline-start: 5px; top: 5px; min-width: 18px; height: 18px;
  display: inline-flex; align-items: center; justify-content: center;
  background: rgba(15, 23, 42, .72); color: #fff; font-size: 11px; font-weight: 800;
  border-radius: 999px; padding: 0 5px;
}
#designStudioView .ds-thumb-act {
  position: absolute; inset-inline-end: 4px; bottom: 4px; display: flex; gap: 3px;
}
#designStudioView .ds-mini {
  cursor: pointer; font-family: inherit; font-size: 11px; line-height: 1;
  width: 24px; height: 24px; border-radius: 7px; border: none;
  background: rgba(255, 255, 255, .93); color: var(--ds-ink);
  box-shadow: 0 1px 4px rgba(15, 23, 42, .22);
}
#designStudioView .ds-mini:hover { background: #fff; }
#designStudioView .ds-mini.danger { color: #dc2626; }

/* ---- form rows ---------------------------------------------------------- */
#designStudioView .ds-actions { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 0; }
#designStudioView .ds-grid2 {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px;
}
#designStudioView .ds-row {
  display: flex; align-items: center; gap: 9px; margin-bottom: 9px; flex-wrap: wrap;
}
#designStudioView .ds-label {
  font-size: 12px; font-weight: 700; color: var(--ds-2); min-width: 104px;
}
#designStudioView .ds-range { flex: 1 1 120px; min-width: 110px; accent-color: var(--ds-primary); }
#designStudioView .ds-val {
  font-size: 11.5px; font-weight: 700; color: var(--ds-dim); min-width: 44px; text-align: end;
}
#designStudioView .ds-color {
  width: 46px; height: 32px; padding: 2px; border: 1px solid var(--ds-line);
  border-radius: 9px; background: #fff; cursor: pointer;
}
#designStudioView .ds-check {
  display: flex; align-items: center; gap: 7px; font-size: 12.5px; color: var(--ds-2);
  cursor: pointer; margin: 6px 0; font-weight: 600;
}
#designStudioView .ds-check input { accent-color: var(--ds-primary); width: 16px; height: 16px; }
#designStudioView .ds-ta {
  width: 100%; box-sizing: border-box; font-family: inherit; font-size: 13.5px;
  padding: 10px 12px; border-radius: 11px; border: 1px solid var(--ds-line);
  resize: vertical; margin-bottom: 10px; line-height: 1.7;
}
#designStudioView .ds-ta:focus { outline: none; border-color: var(--ds-primary); }
#designStudioView select.inp-c, #designStudioView input.inp-c {
  flex: 1 1 130px; min-width: 110px; font-family: inherit;
}

/* ---- layer list --------------------------------------------------------- */
#designStudioView .ds-layers { display: flex; flex-direction: column; gap: 6px; margin: 8px 0; }
#designStudioView .ds-lay {
  display: flex; align-items: center; gap: 8px; cursor: pointer; font-family: inherit;
  text-align: start; font-size: 12.5px; padding: 8px 11px; border-radius: 10px;
  background: #fff; border: 1.5px solid var(--ds-line); color: var(--ds-2);
}
#designStudioView .ds-lay.on { border-color: var(--ds-primary); background: var(--ds-primary-soft); }
#designStudioView .ds-lay-t {
  flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
#designStudioView .ds-lay-x { color: #dc2626; font-weight: 800; padding: 0 3px; }

/* ---- brand mark --------------------------------------------------------- */
/* The current mark, shown as a thumbnail + caption. There is no built-in shelf
   any more, so this is the only thing telling the user WHICH logo the sliders
   below are resizing. `.ds-marks`/`.ds-mark` are gone with the built-in list. */
#designStudioView .ds-brand-cur {
  display: flex; align-items: center; gap: 9px; margin: 8px 0;
  padding: 7px 9px; border: 1px solid var(--ds-line); border-radius: 10px;
  background: var(--ds-surface); font-size: 12px; color: var(--ds-dim); font-weight: 600;
}
#designStudioView .ds-brand-cur img {
  width: 42px; height: 42px; object-fit: contain; border-radius: 7px;
  background: #fff; border: 1px solid var(--ds-line); flex: none;
}

/* ---- caption suggestions ------------------------------------------------ */
#designStudioView .ds-sug {
  border: 1px solid var(--ds-line); border-radius: 12px; padding: 11px 12px;
  margin-bottom: 9px; background: #fff;
}
#designStudioView .ds-sug-t {
  font-size: 13px; line-height: 1.85; color: var(--ds-ink); white-space: normal;
}
#designStudioView .ds-sug-a { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 9px; }

/* ---- export summary ----------------------------------------------------- */
#designStudioView .ds-sizebox {
  font-size: 12.5px; color: var(--ds-2); background: var(--ds-surface);
  border: 1px solid var(--ds-line); border-radius: 10px; padding: 9px 11px; margin: 8px 0;
}
/* The exported file, once it is in the Media Library. Green because its whole
   job is to say "this worked and the file now exists" — the download button
   lives inside it, so the state has to read as a result, not as another form. */
#designStudioView .ds-result {
  margin-top: 12px; padding: 11px 13px; border-radius: 12px;
  background: #f0fdf4; border: 1.5px solid #86efac;
}
#designStudioView .ds-result-t { font-size: 13px; font-weight: 700; color: #166534; }
#designStudioView .ds-result-f {
  font-size: 12px; color: var(--ds-2); margin: 3px 0 9px; word-break: break-all;
}
#designStudioView .ds-result .ds-actions { margin: 0; }

/* ---- saved designs ------------------------------------------------------ */
#designStudioView .ds-projects #dsProjects {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 10px;
}
/* TWO columns: the thumbnail on one side, spanning both rows, and everything
   else on the other. The text is the MAJORITY of the width — the actions sit on
   a second line UNDER it, not beside it. In a 240 px card a text "Open" button +
   ⋯ beside the name ate ~130 px and left the name/meta wrapping one word per
   line with the rest of the card empty. */
#designStudioView .ds-pj {
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  align-items: center; gap: 3px 10px; padding: 9px 10px; border-radius: 12px;
  border: 1.5px solid var(--ds-line); background: #fff;
}
#designStudioView .ds-pj.on { border-color: var(--ds-primary); background: var(--ds-primary-soft); }
#designStudioView .ds-pj-thumb {
  grid-row: 1 / span 2; width: 46px; height: 46px; border-radius: 9px; overflow: hidden;
  background: var(--ds-surface); display: flex; align-items: center; justify-content: center;
}
#designStudioView .ds-pj-thumb img { width: 100%; height: 100%; object-fit: cover; }
#designStudioView .ds-pj-ph { font-size: 20px; }
#designStudioView .ds-pj-body {
  grid-column: 2; grid-row: 1; min-width: 0;
  display: flex; flex-direction: column; gap: 2px;
}
#designStudioView .ds-pj-body b {
  font-size: 12.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
#designStudioView .ds-pj-body span {
  font-size: 11px; color: var(--ds-dim);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* The design's auto-deletion DATE, in red. It replaced the relative
   "Kept for N day(s) on your plan": the deadline is what the user acts on
   (asked 2026-10-01 — deletion shown as a date, in red). The `.ds-pj-body span`
   rule above is more specific than a bare class, so this one has to name the
   element too or the grey wins. */
#designStudioView .ds-pj-body span.ds-pj-del { color: var(--danger, #dc2626); font-weight: 700; }
#designStudioView .ds-pj-act {
  grid-column: 2; grid-row: 2; display: flex; gap: 6px;
  align-items: center; justify-content: flex-end;
}

/* List view (the shared ▦/☰ toggle, window.SSViews): the SAME cards, one
   full-width row each. The grid is switched to flex here so the cards' explicit
   grid-row/grid-column placement goes inert and the three parts fall into a row
   behind the tick box. Nothing is hidden — the row keeps the thumbnail, the name,
   the deletion date, Open and the ⋯ menu, so switching views loses no action. */
#designStudioView .ds-projects #dsProjects.st-list {
  grid-template-columns: 1fr; gap: 8px;
}
#designStudioView .ds-projects #dsProjects.st-list .ds-pj {
  display: flex; align-items: center; gap: 10px;
}
#designStudioView .ds-projects #dsProjects.st-list .ds-pj-thumb { flex: 0 0 auto; }
#designStudioView .ds-projects #dsProjects.st-list .ds-pj-body {
  flex: 1 1 auto; min-width: 0; flex-direction: row; align-items: center; gap: 10px;
}
#designStudioView .ds-projects #dsProjects.st-list .ds-pj-body b { flex: 0 1 auto; }
#designStudioView .ds-projects #dsProjects.st-list .ds-pj-act {
  flex: 0 0 auto; display: flex; gap: 6px; align-items: center;
}

/* ---- dropdown menus (the ⋯ and "Use this image" popovers) --------------- */
/* One shared menu, so the AI result's actions and the saved-design cards read as
   the same control. The wrapper is the anchor: the menu is absolutely positioned
   under it, OUT of flow, so opening it never reflows the row it hangs from. */
#designStudioView .ds-menuwrap { position: relative; display: inline-flex; }
#designStudioView .ds-menu {
  position: absolute; top: calc(100% + 6px); inset-inline-start: 0; z-index: 40;
  min-width: 178px; padding: 6px; border-radius: 12px;
  background: #fff; border: 1.5px solid var(--ds-line);
  box-shadow: 0 12px 30px rgba(15, 23, 42, .16);
  display: flex; flex-direction: column; gap: 2px;
}
/* Anchored to the wrap's end so a ⋯ on the far edge of a row opens inwards
   instead of off the side of a phone. */
#designStudioView .ds-menu-end { inset-inline-start: auto; inset-inline-end: 0; }
#designStudioView .ds-menu-item {
  display: block; width: 100%; text-align: start; cursor: pointer; font-family: inherit;
  font-size: 13px; font-weight: 600; color: var(--ds-ink); background: none; border: none;
  padding: 9px 11px; border-radius: 8px; white-space: nowrap;
}
#designStudioView .ds-menu-item:hover { background: var(--ds-surface); }
#designStudioView .ds-menu-item.danger { color: #dc2626; }
#designStudioView .ds-more { padding-inline: 12px; font-weight: 800; line-height: 1; }
#designStudioView .ds-ai-acts { align-items: flex-start; }

/* ---- the photos drop zone ---------------------------------------------- */
/* Replaces a 96px-tall dashed rectangle with "No photos yet" wrapped over two lines
   inside it: a thin sliver in the corner of a full-width section, which on a phone
   read as a broken image rather than as somewhere to put one. This is the whole
   width, tall enough to be an obvious target, and it IS the button — the file picker
   opens from anywhere inside it, so the target is the size of the thing being aimed
   at. Drag-and-drop lands here too on a desktop. */
#designStudioView .ds-drop {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 3px; width: 100%; cursor: pointer; font-family: inherit;
  padding: 26px 16px; border-radius: 14px;
  border: 2px dashed #c7d2fe; background: linear-gradient(180deg, #fbfbff, #f7f8ff);
  color: var(--ds-2); transition: border-color .16s, background .16s, transform .16s;
}
#designStudioView .ds-drop.sm { padding: 18px 14px; }
#designStudioView .ds-drop:hover:not([disabled]),
#designStudioView .ds-drop.over { border-color: var(--ds-primary); background: #f3f4ff; }
#designStudioView .ds-drop.over { transform: scale(1.006); }
#designStudioView .ds-drop[disabled] { opacity: .5; cursor: default; }
#designStudioView .ds-drop-ico { font-size: 26px; line-height: 1.1; }
#designStudioView .ds-drop-t { font-size: 13.5px; font-weight: 800; color: var(--ds-ink); }
#designStudioView .ds-drop-s { font-size: 11.5px; color: var(--ds-dim); }
/* The library / clipboard / file-input row, directly under the zone it belongs to. */
#designStudioView .ds-actions-in { justify-content: center; margin-top: 8px; }

/* ---- the wizard's door cards ------------------------------------------- */
/* Full-width rows rather than the editor's five-across chip strip: this is the first
   screen of the product, and the only place where the difference between "AI Design"
   and "AI Creative" has to be READ rather than merely tapped. */
#designStudioView .ds-doors { display: flex; flex-direction: column; gap: 8px; }
#designStudioView .ds-door {
  display: grid; grid-template-columns: 34px 1fr; align-items: center;
  gap: 2px 10px; text-align: start; cursor: pointer; font-family: inherit;
  padding: 12px 14px; border-radius: 13px; background: #fff;
  border: 1.5px solid var(--ds-line); color: var(--ds-2); transition: all .16s;
}
#designStudioView .ds-door:hover { border-color: var(--ds-primary); background: #fbfbff; }
#designStudioView .ds-door.on {
  border-color: var(--ds-primary); background: var(--ds-primary-soft);
  box-shadow: 0 4px 14px rgba(79, 70, 229, .14);
}
#designStudioView .ds-door-ico { grid-row: span 2; font-size: 22px; line-height: 1; }
#designStudioView .ds-door-t { font-size: 13.5px; font-weight: 800; color: var(--ds-ink); }
#designStudioView .ds-door-s { font-size: 11.5px; color: var(--ds-dim); line-height: 1.45; }
#designStudioView .ds-door.on .ds-door-t { color: var(--ds-primary); }

/* A template that cannot hold the photos already in the tray is dimmed, not hidden:
   it stays visible so the reason it is unavailable can be read off its capacity note. */
#designStudioView .ds-tile.off { opacity: .55; }
#designStudioView .ds-tile-cap {
  font-size: 10.5px; font-weight: 700; color: var(--ds-dim);
  background: var(--ds-surface); border-radius: 999px; padding: 1px 7px;
  margin-top: 3px; align-self: flex-start;
}

/* ---- the wizard overlay ------------------------------------------------- */
/* Fixed, and a child of #designStudioView, so a phone gets a bottom sheet with the
   actions under the thumb and a desktop gets a centred card — while every `.ds-*`
   rule above still applies inside it. */
#designStudioView .ds-wiz {
  position: fixed; inset: 0; z-index: 80;
  display: flex; align-items: center; justify-content: center; padding: 16px;
  background: rgba(15, 23, 42, .48);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
}
#designStudioView .ds-wiz-card {
  display: flex; flex-direction: column;
  width: 100%; max-width: 560px; max-height: min(86vh, 720px);
  background: #fff; border-radius: 18px; overflow: hidden;
  box-shadow: 0 24px 60px rgba(15, 23, 42, .28);
}
#designStudioView .ds-wiz-head {
  display: flex; align-items: center; gap: 10px; padding: 14px 16px 0;
}
#designStudioView .ds-wiz-eyebrow {
  font-size: 12px; font-weight: 800; color: var(--ds-dim); letter-spacing: .02em;
}
#designStudioView .ds-wiz-x {
  margin-inline-start: auto; cursor: pointer; font-family: inherit;
  width: 28px; height: 28px; border-radius: 50%; border: none;
  background: #f1f5f9; color: var(--ds-dim); font-size: 13px; line-height: 1;
}
#designStudioView .ds-wiz-x:hover { background: #e2e8f0; color: var(--ds-ink); }
#designStudioView .ds-wiz-prog { padding: 10px 16px 0; margin: 0; }
#designStudioView .ds-wiz-prog .ds-progress-t { margin-top: 6px; }
#designStudioView .ds-wiz-body {
  flex: 1 1 auto; overflow-y: auto; padding: 4px 16px 16px;
  -webkit-overflow-scrolling: touch;
}
#designStudioView .ds-wiz-body .ds-sec:first-child { border-top: none; padding-top: 4px; }
#designStudioView .ds-wiz-foot {
  display: flex; align-items: center; gap: 10px; flex: none;
  padding: 12px 16px calc(12px + env(safe-area-inset-bottom, 0px));
  border-top: 1px solid var(--ds-line); background: #fff;
}
#designStudioView .ds-wiz-foot .ds-flow-btn { flex: 1 1 auto; }
#designStudioView .ds-wiz-why {
  padding: 0 16px 12px; font-size: 11.5px; color: var(--ds-dim); text-align: center;
}
@media (max-width: 640px) {
  /* Bottom sheet: on a phone the two actions want to be where the thumb already is,
     which is the bottom edge — and a centred card puts them level with the keyboard
     as soon as a text field on the step has focus. */
  #designStudioView .ds-wiz { align-items: flex-end; padding: 0; }
  #designStudioView .ds-wiz-card {
    max-width: 100%; border-radius: 18px 18px 0 0; max-height: 92vh;
  }
}

/* ---- the editor's one-line mode summary --------------------------------- */
/* What the door strip above every editor step became. The wizard asks the question
   first now, so drawing the five doors again here was re-asking it on the screen it
   had just been answered on. One line keeps the answer visible (you need to know
   which flow you are in — it decides what "Next" means) and "Change" reopens the
   wizard at the doors, which is the only place that can re-plan the flow. */
#designStudioView .ds-modesum {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 9px 12px; border-radius: 12px;
  background: var(--ds-surface); border: 1px solid var(--ds-line);
}
#designStudioView .ds-modesum-ico { font-size: 17px; line-height: 1; }
#designStudioView .ds-modesum-t { font-size: 13px; font-weight: 800; color: var(--ds-ink); }
#designStudioView .ds-modesum-w {
  font-size: 11.5px; color: var(--ds-dim); flex: 1 1 160px; min-width: 0;
  line-height: 1.45;
}
#designStudioView .ds-modesum .btn { flex: none; margin-inline-start: auto; }

/* ---- the collapsed RESULT card ------------------------------------------ */
/* The setup, once it has made something, folded into ONE line: a tick, what was
   made and on which door, then the way back in. Green like `.ds-result`, because
   its whole job is to say "this worked". See setupSummaryHtml. */
#designStudioView .ds-sumcard {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 11px 13px; border-radius: 13px;
  background: #f0fdf4; border: 1.5px solid #86efac;
}
#designStudioView .ds-sumcard-ico { font-size: 17px; line-height: 1; }
#designStudioView .ds-sumcard-body {
  flex: 1 1 150px; min-width: 0; display: flex; flex-direction: column; gap: 1px;
}
#designStudioView .ds-sumcard-t { font-size: 13px; font-weight: 800; color: #166534; }
#designStudioView .ds-sumcard-s {
  font-size: 11.5px; color: var(--ds-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
#designStudioView .ds-sumcard .btn { flex: none; }

/* ---- RTL --------------------------------------------------------------- */
[dir="rtl"] #designStudioView .ds-label { text-align: right; }
[dir="rtl"] #designStudioView .ds-tile,
[dir="rtl"] #designStudioView .ds-lay { text-align: right; }
[dir="rtl"] #designStudioView .ds-door { text-align: right; }

/* ---- phones ------------------------------------------------------------ */
@media (max-width: 900px) {
  #designStudioView .ds-main { grid-template-columns: 1fr; }
  /* The preview comes FIRST on a phone: it is the thing being edited, and the
     controls are a long scroll away from it otherwise. Sticky is off there —
     there is no second column to scroll past. */
  #designStudioView .ds-preview-col { order: -1; }
  #designStudioView .ds-preview-inner { position: static; }
  #designStudioView #dsCanvas { max-height: 46vh; }
  /* The walk controls live in the sticky bottom bar now, so the old "hide the word,
     keep the arrow" rule for the preview-column photo navbar is gone with it. */

  /* ---- the RESULT STATE, in the order the eye wants --------------------- */
  /* After a door has produced something, the screen reads top-down:
     what was made → the thing itself → the actions → the caption. `display:contents`
     DISSOLVES the two column wrappers, so their children become direct flex items of
     `.ds-main` and can be RE-ORDERED without moving them in the DOM — which is what
     keeps the desktop two-column layout exactly as it was. `#designStudioView.ds-result`
     is set by render() whenever doorResultReady() (see design_studio.js). */
  #designStudioView.ds-result .ds-main { display: flex; flex-direction: column; gap: 14px; }
  #designStudioView.ds-result .ds-side,
  #designStudioView.ds-result .ds-preview-col,
  #designStudioView.ds-result .ds-preview-inner { display: contents; }
  /* The collapsed result card first, then the picture. */
  #designStudioView.ds-result #dsBody > .ds-sec-mode { order: 1; }
  #designStudioView.ds-result #dsPreviewBox { order: 2; }
  /* The picture's own actions, directly under it. There is no caption row any more
     — AI Creative's picture travels to the Compose window, where the words are
     written (asked 2026-10-02). */
  #designStudioView.ds-result #dsPreviewActions { order: 3; }
  /* Everything else the door still draws (Export, the token meter) follows. */
  #designStudioView.ds-result #dsBody > * { order: 5; }
  #designStudioView.ds-result #dsSizeLabel,
  #designStudioView.ds-result #dsCardStatus { order: 6; }
}
@media (max-width: 560px) {
  #designStudioView .ds-label { min-width: 84px; font-size: 11.5px; }
  #designStudioView .ds-thumbs { grid-template-columns: repeat(auto-fill, minmax(76px, 1fr)); }
  #designStudioView .ds-tiles { grid-template-columns: repeat(auto-fit, minmax(132px, 1fr)); }
  #designStudioView .ds-head2 .ds-hint { display: none; }
  #designStudioView .ds-meter-wrap { justify-content: flex-start; }
}
