@font-face {
  font-family: 'FlowStudio Pretendard';
  src: url('./fonts/Pretendard-Regular.woff2') format('woff2');
  font-style: normal;
  font-weight: 400;
  font-display: swap;
}

html.fs-active,
html.fs-active body {
  min-width: 0 !important;
  overflow: hidden !important;
}

html.fs-active #app {
  visibility: hidden !important;
  pointer-events: none !important;
}

html.fs-active #login-modal,
html.fs-active #upgrade-modal,
html.fs-active #manage-acct-modal,
html.fs-active #appModal { z-index: 4000 !important; }

/* Unlike the login/upgrade overlays, Manage account and the generic console
   prompt (#appModal — scene naming etc.) live inside the hidden console #app.
   Explicitly opt those fixed descendants back into interaction; without this
   the scene-tab ＋ opens an INVISIBLE name prompt and reads as a dead click. */
html.fs-active #manage-acct-modal,
html.fs-active #appModal {
  visibility: visible !important;
  pointer-events: auto !important;
}

/* Production Asset editors are still owned by UI A and live below the hidden
   #app. Flow opens those existing modals from its inspector, so opt only their
   fixed overlays back into view/interaction instead of exposing the drawer. */
html.fs-active #app .asset-editor-overlay {
  visibility: visible !important;
  pointer-events: auto !important;
  z-index: 4000 !important;
}

/* The console's showToast() appends an UNSTYLED .status-toast to <body>; under
   the fixed Flow Studio surface it was completely invisible — every refusal
   ("No changes detected", credit/safety errors) vanished, so failed actions
   read as dead clicks (recreate/update spam → RepeatSafetyOffender alarm,
   2026-07-25). Surface it above the board. */
html.fs-active .status-toast {
  position: fixed;
  top: 64px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 5000;
  max-width: min(560px, 72vw);
  padding: 10px 16px;
  color: #d9ded9;
  background: rgba(18, 20, 22, .96);
  border: 1px solid rgba(0, 255, 127, .38);
  border-radius: 8px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, .5);
  font: 500 12px/1.5 'DM Mono', monospace;
  pointer-events: none;
}
html.fs-active .status-toast.error { color: #ffc2c6; border-color: rgba(224, 85, 95, .6); }

.flowstudio {
  --fs-bg: #17181a;
  --fs-bg-2: #1e1e22;
  --fs-board: #1e1e22;
  --fs-panel: #1e1e22;
  --fs-panel-2: #25272c;
  --fs-panel-3: #343438;
  --fs-line: rgba(255, 255, 255, .05);
  --fs-line-strong: rgba(255, 255, 255, .11);
  --fs-line-warm: rgba(0, 212, 170, .22);
  --fs-text: #FFFFFF;
  --fs-text-mute: #a6a8ac;
  --fs-text-dim: #7c7c7c;
  --fs-text-75: var(--fs-text-mute);
  --fs-text-60: var(--fs-text-mute);
  --fs-text-45: var(--fs-text-dim);
  --fs-text-32: var(--fs-text-dim);
  --fs-green: #00FF7F;
  --fs-green-2: #5cf2b1;
  --fs-brass-glow: rgba(0, 255, 127, .32);
  --fs-r-sm: 4px;
  --fs-r-md: 6px;
  --fs-r-lg: 8px;
  --fs-r-xl: 14px;
  --fs-r-pill: 999px;
  --fs-r-circle: 50%;
  --fs-sp-1: 4px;
  --fs-sp-2: 8px;
  --fs-sp-3: 12px;
  --fs-sp-4: 16px;
  --fs-sp-5: 24px;
  --fs-elev-1: 0 2px 6px rgba(0, 0, 0, .35);
  --fs-elev-2: 0 6px 14px rgba(0, 0, 0, .45);
  --fs-elev-3: 0 14px 28px rgba(0, 0, 0, .55);
  --fs-dur-fast: .12s;
  --fs-dur: .16s;
  --fs-dur-slow: .32s;
  --fs-ease: cubic-bezier(.4, 0, .2, 1);
  --fs-grad-accent: linear-gradient(180deg, rgba(255, 255, 255, .04) 0%, transparent 50%), linear-gradient(180deg, rgba(0, 255, 127, .10) 0%, rgba(0, 255, 127, .04) 100%);
  --fs-shadow-node: 0 1px 0 rgba(255, 255, 255, .04) inset, 0 4px 14px rgba(0, 0, 0, .45), 0 12px 28px rgba(0, 0, 0, .4);
  --fs-shadow-pop: 0 0 0 1px rgba(0, 0, 0, .5), 0 20px 50px rgba(0, 0, 0, .6);
  --fs-w-image: #d4b270;
  --fs-w-video: #c48560;
  --fs-w-text: #8aa6c4;
  --fs-w-mask: #6fb89c;
  --fs-w-seed: #b69056;
  --fs-w-invalid: #ff6f61;
  --fs-fold: .3s cubic-bezier(.2, .7, .3, 1);
  /* Timeline editor (owner 2026-08-30). --fs-tl-row is the 4th grid track;
     --fs-tl-h is the user's dragged height, restored from cv_fs_tl_h. */
  --fs-tl-row: 0px;
  --fs-tl-h: 300px;
  /* The track-header column, and therefore where the divider falls. The
     TIMELINE label is given the same slot minus the head's two paddings,
     so the timecode begins exactly at the divider — the header and the
     track headers are one column, with no measuring. */
  --fs-tl-col: 104px;
  position: fixed;
  inset: 0;
  z-index: 950;
  display: grid;
  grid-template-rows: 46px 46px 1fr var(--fs-tl-row, 0px);
  /* The one implicit column must never grow past the shell. An `auto` track
     takes the widest row's min-content, so any one row (a long tab strip, a
     nowrap inspector line) widens EVERY row past the viewport and hands the
     shell scrollable overflow it can never show — seen on staging 2026-09-07
     as the whole app shifted 959px sideways. */
  grid-template-columns: minmax(0, 1fr);
  /* clip, NOT hidden. A hidden-overflow box is still a scroll container: any
     focus() or scrollIntoView() on a descendant past its edge scrolls it, no
     gesture scrolls it back, and Chrome fires no `scroll` event for that
     programmatic scroll (a snap-back listener never runs — verified on
     staging 2026-09-07). clip is not a scroll container at all. */
  overflow: clip;
  color: var(--fs-text);
  background: var(--fs-bg);
  font-family: 'DM Sans', Outfit, sans-serif;
  font-size: 12px;
  letter-spacing: -.005em;
  isolation: isolate;
}

.flowstudio *,
.flowstudio *::before,
.flowstudio *::after { box-sizing: border-box; }

.flowstudio ::-webkit-scrollbar { width: 0; height: 0; display: none; }
.flowstudio * { scrollbar-width: none; }
.flowstudio.dragging * { user-select: none; cursor: grabbing !important; }

.flowstudio button,
.flowstudio input,
.flowstudio textarea,
.flowstudio select { font: inherit; }

.flowstudio button { -webkit-tap-highlight-color: transparent; }
/* The house ring for EVERY button (owner 2026-09-18). The reset below used to
   begin with `button:focus-visible`, so no button in the studio showed a focus
   ring at all unless it declared one of its own — the same structural gap that
   left every button without a press. A button that declares its own ring later
   still wins. Editable fields keep the reset: the comment below says why. */
.flowstudio button:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.flowstudio input:focus-visible,
.flowstudio textarea:focus-visible,
/* Editable fields (owner 2026-08-29): Chrome's default focus ring follows the
   OS accent colour (orange on Windows here) and showed on every field that had
   no focus style of its own — tab rename, preset/media titles, plain inputs.
   Zero-specificity reset (:where) so each field's OWN indicator still wins:
   green search borders, the node title's accent outline, the composer glow. */
.flowstudio :where(input, textarea, select, [contenteditable="true"]):focus,
.flowstudio :where(input, textarea, select, [contenteditable="true"]):focus-visible { outline: none; }
.flowstudio .fs-proj-tab span[contenteditable="true"] { outline: none; border-radius: 2px; }
.flowstudio select:focus-visible { outline: 1px solid var(--insp-accent, var(--fs-green)); outline-offset: 2px; }

.flowstudio .fs-brand-bar {
  display: flex;
  align-items: center;
  padding: 0 var(--fs-sp-4);
  background: var(--fs-panel);
  border-bottom: 1px solid var(--fs-line);
  position: relative;
  /* Above the canvas toolbar (80) and composer (100) so the account dropdown
     anchored here paints over board chrome; below context menu / previews. */
  z-index: 120;
}
.flowstudio .fs-brand-bar .fs-brand { display: flex; align-items: center; gap: var(--fs-sp-3); }
/* Right cluster of the brand bar: account status (Pricing + avatar) and guest LOGIN. */
.flowstudio .fs-brand-right { margin-left: auto; display: flex; align-items: center; gap: 8px; }
.flowstudio .fs-brand-bar .fs-brand-mark { width: 30px; height: 30px; display: grid; place-items: center; filter: drop-shadow(rgba(0, 255, 127, .32) 0 0 14px); transition: filter .3s; }
.flowstudio .fs-brand-bar .fs-brand:hover .fs-brand-mark { filter: drop-shadow(rgba(0, 255, 127, .5) 0 0 20px); }
.flowstudio .fs-brand-bar .fs-brand-mark img { width: 100%; height: 100%; object-fit: contain; display: block; }
.flowstudio .fs-brand-title { display: inline-flex; align-items: center; gap: 8px; white-space: nowrap; font: 800 20px 'FlowStudio Pretendard', sans-serif; letter-spacing: .06em; }
.flowstudio .fs-brand-title .fs-brand-clv { color: rgb(0, 255, 127); -webkit-text-fill-color: rgb(0, 255, 127); }
.flowstudio .fs-brand-title .fs-brand-dir { color: var(--fs-text); -webkit-text-fill-color: var(--fs-text); }

.flowstudio .fs-topbar {
  display: flex;
  align-items: center;
  padding: 0 16px;
  gap: 12px;
  background: linear-gradient(rgb(29, 31, 34) 0%, rgb(21, 22, 26) 100%);
  border-bottom: 1px solid rgba(255, 255, 255, .06);
  position: relative;
}
.flowstudio .fs-topbar::after { content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 1px; background: linear-gradient(90deg, transparent 0%, rgba(0, 255, 127, .18) 30%, rgba(0, 255, 127, .3) 50%, rgba(0, 255, 127, .18) 70%, transparent 100%); pointer-events: none; }

/* Project name left of the tab strip (owner 2026-08-29); the tabs shift right. */
/* Plain text (owner 2026-08-29): not a button, no label — just the name. */
.flowstudio .fs-proj-name { flex: 0 0 auto; display: inline-flex; align-items: center; max-width: 280px; margin: 0 18px 0 12px; color: #e8e6de; font: 700 15px 'Outfit', 'FlowStudio Pretendard', sans-serif; letter-spacing: -.01em; }
.flowstudio .fs-proj-name b { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
.flowstudio .fs-proj-tabs-wrap { display: flex; align-items: center; gap: 4px; flex: 1 1 0%; min-width: 0; overflow: hidden; }
.flowstudio .fs-proj-tabs-wrap.busy { pointer-events: none; opacity: .55; }
.flowstudio .fs-proj-tab {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  height: 44px;
  padding: 0 14px;
  color: var(--fs-text-mute);
  border-bottom: 2px solid transparent;
  flex: 1 1 0;
  min-width: 40px;
  max-width: 216px;
  min-height: 0;
  cursor: grab;
  overflow: hidden;
  position: relative;
  font-size: 12px;
  /* The tab is a horizontal drag handle, so the browser must not claim the
     gesture for scrolling first. Safe here: .flowstudio is fixed and
     overflow:hidden, so nothing at this level scrolls. */
  touch-action: none;
}
.flowstudio .fs-proj-tab:active { cursor: grabbing; }
.flowstudio .fs-proj-tab::after { content: ''; position: absolute; right: 0; top: 50%; transform: translateY(-50%); width: 1px; height: 50%; background: rgba(255, 255, 255, .08); pointer-events: none; }
.flowstudio .fs-proj-tab:last-of-type::after,
.flowstudio .fs-proj-tab.on::after,
.flowstudio .fs-proj-tab:has(+ .fs-proj-tab.on)::after { display: none; }
.flowstudio .fs-proj-tab.on { color: var(--fs-text); border-bottom-color: var(--fs-green); background: rgba(201, 169, 106, .05); }
.flowstudio .fs-proj-tab.is-dragging { opacity: .5; }
/* Long-press pick-up on a palette card. touch-action stays default so the
   tool list can still be scrolled with a finger — the recogniser waits out
   the hold and only then claims the gesture (and refuses the scroll's own
   touchmove from then on). */
.flowstudio .fs-toolcard.is-touch-dragging,
.flowstudio .fs-media-card.is-touch-dragging,
.flowstudio .fs-preset-card.is-touch-dragging { opacity: .55; outline: 1px solid var(--fs-green, #00FF7F); }
/* Touch (owner 2026-09-11): the picked-up card rides under the finger as a
   ghost, and a long press never raises the iOS image callout over a
   thumbnail, a node face or the canvas — the long press is ours. */
.flowstudio .fs-touch-ghost { transform: translate(-50%, -70%) scale(.92); transition: none; opacity: .85; }
.flowstudio .fs-board-host,
.flowstudio .fs-left-panel,
.flowstudio .fs-node img,
.flowstudio .fs-node video,
.flowstudio .fs-media-card img { -webkit-touch-callout: none; }

.flowstudio .fs-proj-tab .fs-tab-dot { width: 6px; height: 6px; flex: 0 0 auto; border-radius: 50%; background: var(--fs-text-dim); }
.flowstudio .fs-proj-tab.on .fs-tab-dot { background: var(--fs-green); box-shadow: 0 0 5px var(--fs-green); }
.flowstudio .fs-proj-tab > span:nth-of-type(2) { flex: 1 1 0; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: block; }
.flowstudio .fs-tab-close { width: 16px; height: 16px; flex: 0 0 auto; display: inline-grid; place-items: center; margin-left: 8px; color: rgba(232, 230, 222, .4); background: transparent; border: 0; border-radius: 50%; font: 500 12px/1 'FlowStudio Pretendard', sans-serif; cursor: pointer; padding: 0; transition: background .14s, color .14s, transform .12s; }
.flowstudio .fs-tab-close:hover { background: rgba(232, 230, 222, .16); color: #fff; transform: scale(1.1); }
/* Just the + at rest; a filled circle with NO outline on hover (owner 2026-09-05). */
.flowstudio .fs-seq-add { width: 26px; height: 26px; flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; margin-left: 6px; align-self: center; background: transparent; border: 0; border-radius: 50%; color: rgba(232, 230, 222, .55); cursor: pointer; font: 500 15px/1 Outfit, sans-serif; padding: 0; transition: .16s; }
.flowstudio .fs-seq-add:hover { background: rgba(255, 255, 255, .08); color: #fff; }

.flowstudio .fs-top-pill { position: relative; right: auto; bottom: auto; z-index: 8; display: inline-flex; align-items: center; gap: 8px; height: 28px; padding: 0 12px 0 11px; background: linear-gradient(rgba(255, 255, 255, .04) 0%, transparent 50%), linear-gradient(rgba(0, 255, 127, .1) 0%, rgba(0, 255, 127, .04) 100%); border: 1px solid rgba(0, 255, 127, .32); border-radius: 14px; color: rgb(0, 255, 127); font: 700 10px Outfit, sans-serif; letter-spacing: .1em; text-transform: uppercase; cursor: pointer; box-shadow: rgba(255, 255, 255, .06) 0 1px 0 inset, rgba(0, 255, 127, .18) 0 0 12px; transition: .28s cubic-bezier(.22, 1, .36, 1); }
.flowstudio .fs-top-pill:hover { transform: translateY(-1px); border-color: rgb(0, 255, 127); box-shadow: rgba(255, 255, 255, .08) 0 1px 0 inset, rgba(0, 0, 0, .5) 0 4px 14px, rgba(0, 255, 127, .36) 0 0 22px; }
/* display:inline-flex above beats the UA [hidden] rule — restore it. */
.flowstudio .fs-top-pill[hidden] { display: none !important; }
/* Credits readout — a pill-shaped badge, not a button. */
/* The credits pill is a real button now — it opens the pricing page — so it
   keeps the shared .fs-top-pill cursor and hover lift it used to opt out of. */

.flowstudio .fs-account-slot {
  position: relative;
  z-index: 1100;
  display: flex;
  align-items: center;
  gap: 8px;
  height: 100%;
  flex: 0 0 auto;
}
.flowstudio .fs-account-slot .header-pricing-btn,
.flowstudio .fs-account-slot .acct-wrap {
  flex: 0 0 auto;
  margin: 0;
}
.flowstudio .fs-account-slot .acct-wrap {
  display: flex;
  align-items: center;
}

/* ── Reparented UI A controls, restyled as Flow Studio pills ──────────────
   The slot moves the LIVE console nodes (#header-pricing-btn, #acct-wrap)
   into the topbar, so director.css comes with them: Pricing arrives as an
   8px-radius outlined button in 12px var(--fb), and the avatar as a 32px
   circle ringed in var(--ac) — which body.vid-mode flips to cyan, a console
   state that means nothing here. Next to .fs-top-pill (CREDITS / OUTPUTS /
   guest LOGIN) both read as foreign chrome. Match the pill contract instead:
   28px tall, muted-green hairline, inset highlight + soft glow, lift on
   hover. Scoped to .flowstudio so UI A's own header is untouched when the
   nodes are restored on teardown. Keep these values in sync with
   .fs-top-pill above. */
.flowstudio .fs-account-slot .header-pricing-btn {
  height: 28px;
  padding: 0 12px;
  border: 1px solid rgba(0, 255, 127, .32);
  border-radius: 14px;
  background: linear-gradient(rgba(255, 255, 255, .04) 0%, transparent 50%), linear-gradient(rgba(0, 255, 127, .1) 0%, rgba(0, 255, 127, .04) 100%);
  color: var(--fs-green);
  font: 700 10px Outfit, sans-serif;
  letter-spacing: .1em;
  text-transform: uppercase;
  box-shadow: rgba(255, 255, 255, .06) 0 1px 0 inset, rgba(0, 255, 127, .18) 0 0 12px;
  transition: .28s cubic-bezier(.22, 1, .36, 1);
}
/* UI A's hover floods the button with solid accent and black text; the pill
   language lifts and brightens instead. Repeat the base background so the
   inherited fill can't win. */
.flowstudio .fs-account-slot .header-pricing-btn:hover {
  background: linear-gradient(rgba(255, 255, 255, .04) 0%, transparent 50%), linear-gradient(rgba(0, 255, 127, .1) 0%, rgba(0, 255, 127, .04) 100%);
  color: var(--fs-green);
  border-color: rgb(0, 255, 127);
  transform: translateY(-1px);
  box-shadow: rgba(255, 255, 255, .08) 0 1px 0 inset, rgba(0, 0, 0, .5) 0 4px 14px, rgba(0, 255, 127, .36) 0 0 22px;
}
/* The avatar stays a circle — it reads as an identity token, not a button —
   but takes the pill's height, hairline, fill and glow so it sits in the
   same family. */
.flowstudio .fs-account-slot .acct-avatar {
  width: 28px;
  height: 28px;
  border: 1px solid rgba(0, 255, 127, .32);
  background: linear-gradient(rgba(255, 255, 255, .04) 0%, transparent 50%), linear-gradient(rgba(0, 255, 127, .1) 0%, rgba(0, 255, 127, .04) 100%);
  color: var(--fs-green);
  font-family: var(--fb);
  font-size: 12px;
  font-weight: 700;
  box-shadow: rgba(255, 255, 255, .06) 0 1px 0 inset, rgba(0, 255, 127, .18) 0 0 12px;
  transition: .28s cubic-bezier(.22, 1, .36, 1);
}
.flowstudio .fs-account-slot .acct-avatar:hover,
.flowstudio .fs-account-slot .acct-avatar:focus-visible,
.flowstudio .fs-account-slot .acct-wrap.open .acct-avatar {
  filter: none;
  border-color: rgb(0, 255, 127);
  transform: translateY(-1px);
  box-shadow: rgba(255, 255, 255, .08) 0 1px 0 inset, rgba(0, 0, 0, .5) 0 4px 14px, rgba(0, 255, 127, .36) 0 0 22px;
}
.flowstudio .fs-account-slot button.acct-item {
  font-family: inherit;
  font-size: 14px;
}
.flowstudio .fs-account-slot .acct-avatar:focus-visible,
.flowstudio .fs-account-slot .acct-item:focus-visible {
  outline: none;
}

.flowstudio .fs-shell {
  position: relative;
  display: grid;
  grid-template-columns: 56px minmax(0, 1fr) 14px;
  min-height: 0;
  overflow: hidden;
  transition: grid-template-columns .3s cubic-bezier(.2, .7, .3, 1);
}

.flowstudio .fs-left-panel,
.flowstudio .fs-right-panel {
  position: absolute;
  top: 0;
  bottom: 0;
  z-index: 100;
  transition: width var(--fs-fold), box-shadow var(--fs-fold), background var(--fs-fold);
}
.flowstudio .fs-left-panel {
  left: 0;
  width: 56px;
  height: 100%;
  min-height: 0;
  display: flex;
  flex-direction: column;
  background: linear-gradient(rgb(29, 30, 33) 0%, rgb(23, 24, 27) 100%);
  border-right: 1px solid rgba(255, 255, 255, .04);
  box-shadow: rgba(0, 0, 0, .3) -1px 0 0 inset;
}
/* Folded, the right panel keeps the left panel's strip — its grey and its
   hairline — so the bar reads the same on both sides (owner 2026-09-14). */
.flowstudio .fs-right-panel { right: 0; width: 14px; background: linear-gradient(rgb(29, 30, 33) 0%, rgb(23, 24, 27) 100%); border-left: 1px solid rgba(255, 255, 255, .04); box-shadow: rgba(0, 0, 0, .3) 1px 0 0 inset; }
/* The open widths are root variables (owner 2026-09-18): a full-screen mode
   lets the rails be resized by a grip, and every cover (--fs-cover-l / -r)
   derives from the same numbers — the rail less the 56px / 14px strip. */
.flowstudio.left-open .fs-left-panel { width: var(--fs-left-w, 264px); box-shadow: 8px 0 30px rgba(0, 0, 0, .45); }
.flowstudio .fs-left-panel.closed { box-shadow: none; }
.flowstudio.right-open .fs-right-panel { width: var(--fs-right-w, 376px); background: var(--fs-panel); border-left: 1px solid var(--fs-line); box-shadow: -8px 0 30px rgba(0, 0, 0, .45); }
/* Rail grips: the inner edge of an OPEN rail while a mode is up. */
/* z 4: UNDER the fold arrow (z 5) — the green line never covers the button (owner 2026-09-18, round 5). */
.flowstudio .fs-panel-grip { position: absolute; top: 0; bottom: 0; z-index: 4; width: 10px; display: none; cursor: col-resize; touch-action: none; outline: 0; }
.flowstudio .fs-panel-grip::before { content: ''; position: absolute; top: 0; bottom: 0; left: 4px; width: 2px; background: transparent; transition: background .14s; }
.flowstudio .fs-left-panel .fs-panel-grip { right: -5px; }
.flowstudio .fs-right-panel .fs-panel-grip { left: -5px; }
.flowstudio.genfull-mode.left-open .fs-left-panel .fs-panel-grip, .flowstudio.plan-mode.left-open .fs-left-panel .fs-panel-grip, .flowstudio.tl-mode.left-open .fs-left-panel .fs-panel-grip,
.flowstudio.genfull-mode.right-open .fs-right-panel .fs-panel-grip, .flowstudio.plan-mode.right-open .fs-right-panel .fs-panel-grip, .flowstudio.tl-mode.right-open .fs-right-panel .fs-panel-grip { display: block; }
.flowstudio .fs-panel-grip:hover::before, .flowstudio .fs-panel-grip.is-dragging::before, .flowstudio .fs-panel-grip:focus-visible::before { background: var(--fs-green); }
/* While a grip drags nothing eases — the rail, the covers and the mode follow the pointer. */
.flowstudio.fs-resizing .fs-left-panel, .flowstudio.fs-resizing .fs-right-panel, .flowstudio.fs-resizing .fs-viewer, .flowstudio.fs-resizing .fs-composer, .flowstudio.fs-resizing .fs-canvas-toolbar, .flowstudio.fs-resizing .fs-outliner-wrap, .flowstudio.fs-resizing .fs-help-wrap { transition: none; }
/* A mode shows MEDIA only in the rail (owner 2026-09-18): TOOLS and PRESET step out. */
.flowstudio.genfull-mode .fs-view-tabs, .flowstudio.plan-mode .fs-view-tabs, .flowstudio.tl-mode .fs-view-tabs { grid-template-columns: 1fr; }
.flowstudio.genfull-mode .fs-view-tabs .fs-seg:not([data-tab="media"]), .flowstudio.plan-mode .fs-view-tabs .fs-seg:not([data-tab="media"]), .flowstudio.tl-mode .fs-view-tabs .fs-seg:not([data-tab="media"]) { display: none; }

.flowstudio .fs-fold {
  position: absolute;
  z-index: 5;
  top: 16px;
  width: 26px;
  height: 26px;
  display: grid;
  place-items: center;
  padding: 0;
  color: var(--fs-text-mute);
  background: var(--fs-panel-2);
  border: 1px solid var(--fs-line-strong);
  border-radius: 50%;
  box-shadow: rgba(0, 0, 0, .5) 0 2px 6px;
  cursor: pointer;
  font-size: 11px;
  transition: transform .3s;
}
.flowstudio .fs-fold:hover { color: var(--fs-green); border-color: var(--fs-line-warm); }
.flowstudio .fs-fold svg { display: block; width: 13px; height: 13px; stroke-width: 2.2; transition: transform .2s, stroke-width .15s; }
.flowstudio .fs-fold:hover svg { stroke-width: 2.9; }
.flowstudio .fs-fold-left { right: -13px; }
.flowstudio .fs-fold-right { left: -13px; }
.flowstudio .fs-fold-left svg { transition: transform .18s; transform: scaleX(-1); }
.flowstudio:not(.left-open) .fs-fold-left { transform: rotate(180deg); }
.flowstudio .fs-fold-right svg { transform: scaleX(-1); }
.flowstudio.right-open .fs-fold-right svg { transform: scaleX(1); }

/* Same visual family as the Outputs gallery's ALL / IMAGES / VIDEOS filter:
   quiet neutral container, muted idle text that brightens on hover, and green
   reserved for the ACTIVE segment only (the old all-green frame drowned the
   panel). Font and size deliberately unchanged. */
.flowstudio .fs-view-tabs {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 4px;
  padding: 4px;
  margin: 11px 30px 12px 14px;
  background: var(--fs-panel-2);
  border: 1px solid var(--fs-line-strong);
  border-radius: 8px;
}
.flowstudio .fs-view-tabs .fs-seg {
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 6px 4px;
  color: var(--fs-text-mute);
  background: transparent;
  border: 0;
  border-radius: 5px;
  cursor: pointer;
  text-align: center;
  font: 700 14px Outfit, sans-serif;
  letter-spacing: .12em;
  text-transform: uppercase;
  transition: .18s;
}
.flowstudio .fs-view-tabs .fs-seg:hover {
  color: var(--fs-text);
}
.flowstudio .fs-view-tabs .fs-seg.on {
  color: var(--fs-green);
  background: rgba(0, 255, 127, .14);
  box-shadow: rgba(0, 255, 127, .18) 0 0 8px;
}

.flowstudio .fs-lib-search { position: relative; padding: 6px 10px 8px; }
.flowstudio .fs-lib-search input {
  width: 100%;
  height: 26px;
  padding: 0 24px 0 28px;
  color: #FFFFFF;
  background: #25272c;
  border: 1px solid rgba(255, 255, 255, .05);
  border-radius: 5px;
  font: 500 12px 'FlowStudio Pretendard', sans-serif;
}
.flowstudio .fs-lib-search input:focus { outline: none; border-color: #00FF7F; box-shadow: 0 0 0 2px rgba(0, 255, 127, .32); }
.flowstudio .fs-lib-search input::placeholder { font-size: 12px; }
.flowstudio .fs-lib-search .fs-ic { position: absolute; left: 17px; top: 13px; color: #7c7c7c; }
.flowstudio .fs-lib-search .fs-clr {
  position: absolute;
  right: 18px;
  top: 12px;
  width: 14px;
  height: 14px;
  display: grid;
  place-items: center;
  padding: 0;
  color: rgba(232, 230, 222, .55);
  background: rgba(255, 255, 255, .06);
  border: 1px solid rgba(255, 255, 255, .1);
  border-radius: 50%;
  cursor: pointer;
  font: 500 9px/1 'FlowStudio Pretendard', sans-serif;
  transition: background .14s, color .14s, border-color .14s, transform .12s;
}
.flowstudio .fs-lib-search .fs-clr[hidden] { display: none; }
.flowstudio .fs-lib-search .fs-clr:hover { color: #fff; background: rgba(232, 230, 222, .2); border-color: rgba(232, 230, 222, .34); transform: scale(1.1); }

.flowstudio .fs-lib-body {
  position: relative;
  flex: 1 1 0%;
  min-height: 0;
  overflow: hidden auto;
  padding: 6px 10px 14px;
  scrollbar-width: none;
}
.flowstudio .fs-lib-body::-webkit-scrollbar { width: 0; display: none; }
.flowstudio .fs-step-cat { display: flex; align-items: center; gap: 8px; padding: 10px 6px 6px; }
.flowstudio .fs-step-cat .fs-ix {
  width: 20px;
  height: 20px;
  display: inline-grid;
  place-items: center;
  color: #0a0805;
  background: linear-gradient(180deg, rgba(255, 255, 255, .15) 0%, transparent 50%), var(--accent);
  border-radius: 4px;
  box-shadow: 0 1px 0 rgba(255, 255, 255, .2) inset, 0 2px 5px rgba(0, 0, 0, .45), 0 0 10px rgba(var(--accent-rgb, 0, 255, 127), .3);
  font: 700 12px 'DM Mono', monospace;
  letter-spacing: 0;
}
/* No 01-05 index box anywhere (owner 2026-08-28): open, the section title
   wears the section colour; folded, the rail shows tool buttons only with a
   hairline between sections. The element stays in the DOM (JS builds it). */
.flowstudio .fs-step-cat .fs-ix { display: none; }
.flowstudio .fs-step-cat .fs-nm { color: var(--accent, #FFFFFF); font: 700 13px 'FlowStudio Pretendard', sans-serif; letter-spacing: .1em; text-transform: uppercase; }
.flowstudio .fs-step-cat .fs-ct { margin-left: auto; color: #7c7c7c; font: 500 12px 'FlowStudio Pretendard', sans-serif; font-variant: tabular-nums; }

.flowstudio .fs-toolcard {
  position: relative;
  display: grid;
  grid-template-columns: 32px 1fr;
  align-items: center;
  gap: 10px;
  padding: 9px 10px 9px 12px;
  margin-bottom: 5px;
  color: var(--fs-text);
  background: linear-gradient(rgba(255, 255, 255, .024) 0%, transparent 50%), linear-gradient(rgb(40, 41, 45) 0%, rgb(31, 32, 36) 100%);
  border: 1px solid rgba(255, 255, 255, .06);
  border-radius: 8px;
  box-shadow: rgba(255, 255, 255, .03) 0 1px 0 inset, rgba(0, 0, 0, .3) 0 2px 5px;
  cursor: grab;
  transition: transform .16s, border-color .16s, box-shadow .16s, filter .16s;
}
.flowstudio .fs-toolcard::before {
  content: '';
  position: absolute;
  left: 0;
  top: 6px;
  bottom: 6px;
  width: 3px;
  background: linear-gradient(180deg, var(--accent), rgba(var(--accent-rgb, 0, 255, 127), .5));
  border-radius: 0 2px 2px 0;
  box-shadow: 0 0 8px rgba(var(--accent-rgb, 0, 255, 127), .45);
}
.flowstudio .fs-toolcard:hover {
  transform: translateY(-2px);
  border-color: rgba(0, 255, 127, .36);
  box-shadow: rgba(255, 255, 255, .04) 0 1px 0 inset, rgba(0, 0, 0, .4) 0 8px 16px, rgba(0, 255, 127, .18) 0 0 0 1px, rgba(0, 255, 127, .12) 0 0 14px;
  filter: brightness(1.08);
}
.flowstudio .fs-toolcard .fs-gl {
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  color: var(--accent);
  background: rgba(var(--accent-rgb, 201, 169, 106), .1);
  border-radius: 7px;
  font: 700 14px 'FlowStudio Pretendard', sans-serif;
}
/* The shape sits inset in the accent frame in full mode (owner 2026-09-05) —
   place-items:center on .fs-gl keeps it centred; the collapsed rail stays full-bleed. */
.flowstudio .fs-toolcard .fs-gl > svg { width: 80%; height: 80%; display: block; }
.flowstudio .fs-left-panel.closed .fs-toolcard .fs-gl > svg { width: 100%; height: 100%; }
.flowstudio .fs-toolcard .fs-info { min-width: 0; }
.flowstudio .fs-toolcard .fs-nm {
  overflow: hidden;
  color: #FFFFFF;
  text-overflow: ellipsis;
  white-space: nowrap;
  font: 600 13px 'FlowStudio Pretendard', sans-serif;
  letter-spacing: -.005em;
}
.flowstudio .fs-toolcard .fs-nm .fs-badge {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 5px;
  color: #00FF7F;
  background: rgba(201, 169, 106, .1);
  border-radius: 3px;
  font: 600 12px 'FlowStudio Pretendard', sans-serif;
  letter-spacing: .1em;
  text-transform: uppercase;
}
/* 'beta' tools read amber, not the green AI badge (owner 2026-09-05). */
.flowstudio .fs-toolcard .fs-nm .fs-badge.is-beta { color: #ffd787; background: rgba(246, 183, 67, .12); }
.flowstudio .fs-toolcard .fs-ex {
  overflow: hidden;
  margin-top: 3px;
  color: #a6a8ac;
  text-overflow: ellipsis;
  white-space: nowrap;
  font: 500 12px/1.4 'FlowStudio Pretendard', sans-serif;
  letter-spacing: -.005em;
}
.flowstudio .fs-toolcard .fs-ex i { color: #7c7c7c; font-style: normal; }
.flowstudio .fs-lib-empty-match { padding: 18px 6px; color: var(--fs-text-dim); text-align: center; font: 500 15px 'FlowStudio Pretendard', sans-serif; }

.flowstudio .fs-left-panel.closed .fs-view-tabs,
.flowstudio .fs-left-panel.closed .fs-lib-search,
.flowstudio .fs-left-panel.closed .fs-toolcard .fs-info,
.flowstudio .fs-left-panel.closed .fs-panel-intro,
/* The closed MEDIA rail (owner 2026-08-28): tool-button-sized thumbnails,
   one per item; the control row and notes stay hidden. Hovering a thumb pops
   a preview to the right (.fs-media-peek, JS-positioned). */
.flowstudio .fs-left-panel.closed .fs-media-controls,
.flowstudio .fs-left-panel.closed .fs-lib-empty-match,
.flowstudio .fs-left-panel.closed .fs-media-empty { display: none; }
.flowstudio .fs-left-panel.closed .fs-media-list { display: flex; flex-direction: column; align-items: center; gap: 6px; }
.flowstudio .fs-left-panel.closed .fs-media-card { width: 34px; height: 34px; min-height: 0; padding: 0; display: block; overflow: hidden; border-radius: 8px; }
.flowstudio .fs-left-panel.closed .fs-media-card { contain-intrinsic-size: 34px 34px; }
.flowstudio .fs-left-panel.closed .fs-media-card .thumb { width: 100%; height: 100%; border-radius: 7px; font-size: 12px; }
.flowstudio .fs-left-panel.closed .fs-media-card .thumb img, .flowstudio .fs-left-panel.closed .fs-media-card .thumb video { border-radius: 7px; }
.flowstudio .fs-left-panel.closed .fs-media-card .copy,
.flowstudio .fs-left-panel.closed .fs-media-card .fs-media-eye,
.flowstudio .fs-left-panel.closed .fs-media-card .fs-media-del,
.flowstudio .fs-left-panel.closed .fs-media-card > button { display: none; }
/* Owner 2026-08-29: the 1px hover ring was hard to see on a 34px thumb — a second inset ring makes it 2px. */
.flowstudio .fs-left-panel.closed .fs-media-card:hover { transform: none; border-color: var(--fs-green); box-shadow: inset 0 0 0 1px var(--fs-green); }
/* Node-sized hover preview (owner 2026-08-29): 260 wide, 154px picture box
   (= a node body), FIXED 204px height so JS never has to measure it. One
   singleton element, reused; hidden between hovers. */
/* Lives in document.body, OUTSIDE the Flow Studio root — which is itself
   `position: fixed; z-index: 950`. At 300 the peek painted UNDER the board
   since #400 (owner 2026-08-29: "not seeing the preview"); 960 clears the
   root and stays under the console modals (4000) and toasts (5000). */
.fs-media-peek { position: fixed; z-index: 960; width: 260px; height: 204px; padding: 6px; box-sizing: border-box; background: #17181c; border: 1px solid var(--fs-line-strong); border-radius: 10px; box-shadow: 0 14px 34px rgba(0, 0, 0, .6); pointer-events: none; }
.fs-media-peek[hidden] { display: none; }
.fs-media-peek .pic { position: relative; display: grid; place-items: center; width: 100%; height: 154px; overflow: hidden; background: #0a0c0e; border-radius: 6px; }
.fs-media-peek .pic img, .fs-media-peek .pic video { max-width: 100%; max-height: 100%; display: block; object-fit: contain; }
.fs-media-peek .pic img[hidden], .fs-media-peek .pic video[hidden] { display: none; }
.fs-media-peek.is-video .pic::after { content: '\25B6'; position: absolute; top: 50%; left: 50%; width: 40px; height: 40px; transform: translate(-50%, -50%); display: grid; place-items: center; padding-left: 3px; box-sizing: border-box; color: rgba(240, 241, 243, .92); background: rgba(8, 10, 12, .72); border: 1px solid rgba(255, 255, 255, .28); border-radius: 50%; font: 700 14px/1 'DM Mono', monospace; }
.fs-media-peek b { display: block; margin-top: 6px; overflow: hidden; color: #e8e6de; text-overflow: ellipsis; white-space: nowrap; font: 600 11px 'Outfit', sans-serif; }
.fs-media-peek small { display: block; color: var(--fs-text-32); font: 500 9px 'DM Mono', monospace; letter-spacing: .08em; text-transform: uppercase; }
.flowstudio .fs-left-panel.closed .fs-lib-body { display: flex; flex-direction: column; align-items: center; gap: 0; padding: 8px 4px 14px; }
/* Every closed rail starts at the same line (owner 2026-08-28): the fold
   circle ends at 42px (top 16 + 26); 48px gives it breathing room. One rule
   for all tabs — no per-tab attribute selectors to drift apart. */
.flowstudio .fs-left-panel.closed .fs-lib-body { padding-top: 48px; }
/* No room for the color popup on the 34px rail. */
.flowstudio .fs-left-panel.closed .fs-label-pop { display: none !important; }
.flowstudio .fs-left-panel.closed .fs-preset-del { display: none; }
.flowstudio .fs-left-panel.closed .fs-step-cat { position: relative; justify-content: center; width: 100%; height: 0; padding: 8px 0 0; overflow: visible; }
.flowstudio .fs-left-panel.closed .fs-step-cat::before { content: ''; position: absolute; top: 0; left: 12px; right: 12px; height: 1px; background: var(--fs-line); }
/* The FIRST section only: no spacer and no hairline, so TOOLS' first button
   sits on the same 48px line as MEDIA/PRESET. (`.fs-step-cat:first-child`
   matched every section — each is the first child of its own group.) */
.flowstudio .fs-left-panel.closed .fs-lib-body > :first-child > .fs-step-cat { padding-top: 0; }
.flowstudio .fs-left-panel.closed .fs-lib-body > :first-child > .fs-step-cat::before { display: none; }
.flowstudio .fs-left-panel.closed .fs-step-cat .fs-nm,
.flowstudio .fs-left-panel.closed .fs-step-cat .fs-ct { display: none; }
.flowstudio .fs-left-panel.closed .fs-toolcard {
  width: 34px;
  height: 34px;
  display: grid;
  grid-template-columns: 1fr;
  place-items: center;
  padding: 0;
  margin: 0 0 6px;
  background: var(--fs-panel-2);
  border: 1px solid var(--fs-line);
  border-radius: 7px;
  transition: .16s;
}
.flowstudio .fs-left-panel.closed .fs-toolcard::before { display: none; }
.flowstudio .fs-left-panel.closed .fs-toolcard:hover { transform: none; border-color: var(--accent); background: rgba(var(--accent-rgb), .08); box-shadow: 0 0 10px rgba(var(--accent-rgb), .18); filter: none; }
.flowstudio .fs-left-panel.closed .fs-toolcard .fs-gl { width: 22px; height: 22px; color: var(--accent); background: transparent; font-size: 12px; }

/* ── Preset card extras (owner 2026-08-27) ────────────────────────────────
   Number box (order by position), Mac-style label-color popup on its hover,
   and the media-card × on the card's top right. */
.flowstudio .fs-preset-num { position: relative; overflow: visible; font: 700 13px 'DM Mono', monospace; }
.flowstudio .fs-label-pop { position: absolute; top: 50%; transform: translateY(-50%); left: calc(100% - 2px); z-index: 45; display: none; align-items: center; gap: 5px; padding: 6px 8px; background: #17181c; border: 1px solid var(--fs-line-strong); border-radius: 8px; box-shadow: rgba(0, 0, 0, .5) 0 8px 20px; }
.flowstudio .fs-preset-num:hover .fs-label-pop { display: flex; }
.flowstudio .fs-label-dot { width: 15px; height: 15px; padding: 0; border: 1px solid rgba(255, 255, 255, .25); border-radius: 50%; cursor: pointer; }
.flowstudio .fs-label-dot:hover { transform: scale(1.2); }
.flowstudio .fs-label-dot.on { box-shadow: 0 0 0 2px #17181c, 0 0 0 3.5px #fff; }
.flowstudio .fs-label-dot.is-clear { display: grid; place-items: center; color: var(--fs-text-60); background: transparent; border-style: dashed; font: 600 10px/1 'DM Mono', monospace; }
.flowstudio .fs-preset-del { position: absolute; top: 4px; right: 4px; width: 18px; height: 18px; display: grid; place-items: center; padding: 0; color: rgba(232, 230, 222, .6); background: rgba(8, 10, 11, .85); border: 1px solid var(--fs-line); border-radius: 4px; cursor: pointer; font: 600 12px/1 'DM Mono', monospace; opacity: 0; transition: opacity .14s, color .14s, border-color .14s; }
.flowstudio .fs-preset-card:hover .fs-preset-del, .flowstudio .fs-preset-del:focus-visible { opacity: 1; }
.flowstudio .fs-preset-del:hover { color: #ff8b95; border-color: rgba(224, 85, 95, .5); }
/* Reorder target indicator: a hairline on the receiving edge. */
.flowstudio .fs-preset-card.drop-before { box-shadow: 0 -2px 0 var(--fs-green); }
.flowstudio .fs-preset-card.drop-after { box-shadow: 0 2px 0 var(--fs-green); }
/* Rename-in-place (media-card contract): the armed title shows its edit box. */
.flowstudio .fs-preset-title { cursor: text; }
.flowstudio .fs-preset-title[contenteditable="true"] { outline: 1px dashed rgba(255, 255, 255, .35); border-radius: 3px; }

.flowstudio .fs-panel-intro { position: relative; display: grid; gap: 2px; padding: 5px 5px 10px; }
.flowstudio .fs-panel-intro b { font: 700 14px 'DM Mono', monospace; letter-spacing: .1em; }
.flowstudio .fs-panel-intro span { color: var(--fs-text-32); font: 500 13px 'DM Sans', sans-serif; }
.flowstudio .fs-panel-intro .fs-panel-actions { position: absolute; top: 3px; right: 3px; display: flex; gap: 4px; }
.flowstudio .fs-panel-intro .fs-panel-actions button { position: static; }
.flowstudio .fs-panel-intro button { position: absolute; top: 3px; right: 3px; padding: 3px 5px; color: var(--fs-text-32); background: transparent; border: 1px solid var(--fs-line); border-radius: 4px; cursor: pointer; font: 600 11px 'DM Mono', monospace; letter-spacing: .06em; }
.flowstudio .fs-panel-intro button:hover { color: var(--fs-green); border-color: rgba(0, 255, 127, .35); }
/* Two header buttons used to share the same absolute right:3px spot and
   overlapped ("REFRESH" under "ADD"). The group is absolute; its buttons flow. */
.flowstudio .fs-panel-intro .fs-panel-actions { position: absolute; top: 3px; right: 3px; display: flex; gap: 4px; }
.flowstudio .fs-panel-intro .fs-panel-actions button { position: static; }
/* FILTER + SORT own a line under the header (owner 2026-08-27) — beside
   + ADD they crowded it, and the filter had nowhere to go. */
.flowstudio .fs-media-controls { display: flex; gap: 6px; margin: 0 0 8px; }
.flowstudio .fs-media-controls .fs-media-ctl { flex: 1 1 0; min-width: 0; }
/* LIST / TILE (owner 2026-09-18): two squares left of + ADD. */
.flowstudio .fs-panel-intro .fs-media-view { width: 24px; height: 22px; padding: 0; display: grid; place-items: center; }
.flowstudio .fs-panel-intro .fs-media-view svg { width: 13px; height: 13px; display: block; }
.flowstudio .fs-panel-intro .fs-media-view.on { color: var(--fs-green); border-color: rgba(0, 255, 127, .45); background: rgba(0, 255, 127, .08); }
/* The tile view: square thumbnails, only the name under each. */
/* Fixed 72px tiles with a 60px square (an aspect-ratio box resolved a couple
   of px tall inside the auto-fill grid — staging 2026-09-18); the row spreads
   whatever the rail width leaves. */
.flowstudio .fs-media-list.is-tile { grid-template-columns: repeat(auto-fill, 72px); justify-content: space-between; gap: 8px; }
.flowstudio .fs-media-list.is-tile .fs-media-card { width: 72px; grid-template-columns: 60px; justify-content: center; align-items: start; gap: 5px; min-height: 0; padding: 5px; contain-intrinsic-size: auto 100px; }
.flowstudio .fs-media-list.is-tile .fs-media-card .thumb { width: 60px; height: 60px; padding-bottom: 0; }
.flowstudio .fs-media-list.is-tile .fs-media-card .copy { gap: 0; }
.flowstudio .fs-media-list.is-tile .fs-media-card .copy small, .flowstudio .fs-media-list.is-tile .fs-media-card .fs-media-tag { display: none; }
.flowstudio .fs-media-list.is-tile .fs-media-card b { font-size: 11px; text-align: center; }
/* No hover eye on a tile (owner 2026-09-18, round 5): a click on the picture is the card's click — select and preview — not the lightbox. */
.flowstudio .fs-media-list.is-tile .fs-media-eye { display: none; }
.flowstudio .fs-media-list.is-tile .fs-media-more { grid-column: 1 / -1; }
.flowstudio .fs-media-controls .fs-ctl-value { flex: 1 1 auto; min-width: 0; justify-content: center; text-align: center; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* ── Icon + hover-menu select ─────────────────────────────────────────────
   The shared filter/sort control (left panel AND Media browser): icon
   OUTSIDE the button (click = cycle), value button whose option menu drops
   on hover/focus. The menu is a child of the wrap with no gap, so the
   pointer can travel into it without the :hover chain breaking. */
.flowstudio .fs-media-ctl { position: relative; display: inline-flex; align-items: center; gap: 4px; }
.flowstudio .fs-ctl-icon { width: 26px; height: 26px; flex: 0 0 auto; display: grid; place-items: center; padding: 0; color: var(--fs-text-32); background: transparent; border: 1px solid var(--fs-line); border-radius: 4px; cursor: pointer; transition: color .15s, border-color .15s; }
.flowstudio .fs-ctl-icon svg { width: 13px; height: 13px; }
.flowstudio .fs-ctl-icon:hover { color: var(--fs-green); border-color: rgba(0, 255, 127, .35); }
.flowstudio .fs-ctl-value { flex: 1 1 auto; min-width: 0; height: 26px; padding: 0 8px; display: inline-flex; align-items: center; justify-content: center; color: var(--fs-text-32); background: transparent; border: 1px solid var(--fs-line); border-radius: 4px; cursor: pointer; white-space: nowrap; font: 600 11px 'DM Mono', monospace; letter-spacing: .06em; transition: color .15s, border-color .15s; }
.flowstudio .fs-ctl-value:hover { color: var(--fs-green); border-color: rgba(0, 255, 127, .35); }
.flowstudio .fs-ctl-menu { position: fixed; z-index: 200; display: none; min-width: 92px; padding: 4px; background: #17181c; border: 1px solid var(--fs-line-strong); border-radius: 6px; box-shadow: rgba(0, 0, 0, .5) 0 10px 24px; }
.flowstudio .fs-media-ctl:hover .fs-ctl-menu,
.flowstudio .fs-media-ctl:focus-within .fs-ctl-menu { display: block; }
.flowstudio .fs-ctl-menu button { width: 100%; padding: 5px 8px; display: block; text-align: left; color: var(--fs-text-75); background: transparent; border: 0; border-radius: 4px; cursor: pointer; font: 600 11px 'DM Mono', monospace; letter-spacing: .06em; }
.flowstudio .fs-ctl-menu button:hover { color: #fff; background: rgba(255, 255, 255, .07); }
.flowstudio .fs-ctl-menu button.on { color: var(--fs-green); }

.flowstudio .fs-media-card {
  width: 100%;
  display: grid;
  text-align: left;
  color: var(--fs-text-75);
  background: rgba(255, 255, 255, .025);
  border: 1px solid var(--fs-line);
  border-radius: 8px;
  cursor: pointer;
  transition: border-color .14s ease, background .14s ease;
  /* Off-screen cards skip layout and paint (owner 2026-08-29 — 200+ cards). */
  content-visibility: auto;
  contain-intrinsic-size: auto 90px;
}
.flowstudio .fs-media-card:hover { border-color: rgba(255, 255, 255, .25); background: rgba(255, 255, 255, .045); }
/* .copy is a real class hook — `> span:last-child` never matched (the VIEW
   button is the last child), so name+stamp collapsed onto one cropped line. */
.flowstudio .fs-media-card .copy { display: grid; gap: 3px; min-width: 0; }
.flowstudio .fs-media-card b { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font: 600 14px 'Outfit', sans-serif; }
.flowstudio .fs-media-card small { overflow: hidden; color: var(--fs-text-32); text-overflow: ellipsis; white-space: nowrap; font: 500 12px 'DM Sans', sans-serif; }
/* Taller card, bigger square (owner 2026-08-27). The thumbnail CROPS to fill
   (overflow hidden + absolute cover fill) — the old 100%-height img resolved
   against the stretched grid area and spilled past the box instead of
   cropping inside it. */
.flowstudio .fs-media-card { position: relative; grid-template-columns: 74px 1fr; align-items: center; gap: 10px; min-height: 90px; padding: 8px; }
/* Explorer-style selection (owner 2026-08-29): the selected card(s) wear the
   green tint; keyboard focus shows a ring so ↑ ↓ browsing reads. */
.flowstudio .fs-media-card.is-selected { border-color: rgba(0, 255, 127, .55); background: rgba(0, 255, 127, .08); }
.flowstudio .fs-media-card:focus-visible { outline: 2px solid rgba(0, 255, 127, .5); outline-offset: -2px; }
.flowstudio .fs-left-panel.closed .fs-media-card.is-selected { border-color: rgba(0, 255, 127, .7); }
.flowstudio .fs-media-card .thumb { display: grid; place-items: center; height: 74px; overflow: hidden; color: var(--fs-green); background: radial-gradient(circle, rgba(0, 255, 127, .15), rgba(0, 255, 127, .02)); border: 1px solid rgba(0, 255, 127, .2); border-radius: 6px; font-size: 18px; }
.flowstudio .fs-media-card .thumb img, .flowstudio .fs-media-card .thumb video { position: absolute; inset: 0; width: 100%; height: 100%; display: block; object-fit: cover; border-radius: 5px; pointer-events: none; }
/* The green gradient/border is a placeholder — never painted under a covering image. */
.flowstudio .fs-media-card .thumb:has(img), .flowstudio .fs-media-card .thumb:has(video) { background: none; border-color: transparent; }
.flowstudio .fs-media-more { height: 1px; width: 100%; }
.flowstudio .fs-media-list { display: grid; gap: 6px; }
/* Name line: [IMG|VID] tag + filename. Green = image, cyan = video. */
.flowstudio .fs-media-card .nameline { display: flex; align-items: center; gap: 6px; min-width: 0; }
.flowstudio .fs-media-card .nameline b { flex: 1; min-width: 0; }
.flowstudio .fs-media-tag { flex: 0 0 auto; padding: 1px 4px; color: var(--fs-green, #00FF7F); border: 1px solid rgba(0, 255, 127, .4); border-radius: 3px; font: 700 9px 'DM Mono', monospace; letter-spacing: .08em; font-style: normal; }
.flowstudio .fs-media-tag.is-vid { color: #0cb8e0; border-color: rgba(12, 184, 224, .45); }
/* Thumbnail hover eye = large preview (replaces the VIEW button). */
.flowstudio .fs-media-card .thumb { position: relative; }
.flowstudio .fs-media-eye { position: absolute; inset: 0; display: grid; place-items: center; padding: 0; color: var(--fs-green); background: rgba(8, 10, 12, .5); border: 0; border-radius: 6px; cursor: pointer; opacity: 0; transition: opacity .14s; }
.flowstudio .fs-media-card .thumb:hover .fs-media-eye, .flowstudio .fs-media-eye:focus-visible { opacity: 1; }
.flowstudio .fs-media-eye:hover { color: #5cf2b1; }
/* Top-right ×: delete from the library (hover-revealed, like the vault's). */
.flowstudio .fs-media-del { position: absolute; top: 4px; right: 4px; width: 18px; height: 18px; display: grid; place-items: center; padding: 0; color: rgba(232, 230, 222, .6); background: rgba(8, 10, 11, .85); border: 1px solid var(--fs-line); border-radius: 4px; cursor: pointer; font: 600 12px/1 'DM Mono', monospace; opacity: 0; transition: opacity .14s, color .14s, border-color .14s; }
.flowstudio .fs-media-card:hover .fs-media-del, .flowstudio .fs-media-del:focus-visible { opacity: 1; }
.flowstudio .fs-media-del:hover { color: #ff8b95; border-color: rgba(255, 139, 149, .5); }
/* Double-click opens the rename edit — make the editing state visible. */
.flowstudio .fs-media-card b[contenteditable="true"] { outline: 1px dashed rgba(0, 255, 127, .55); outline-offset: 1px; border-radius: 3px; }
.flowstudio .fs-media-empty { padding: 28px 10px; color: var(--fs-text-32); text-align: center; border: 1px dashed var(--fs-line); border-radius: 7px; font: 500 12px/1.5 'DM Mono', monospace; }

.flowstudio .fs-board-host { position: relative; grid-area: 1 / 2 / auto / 3; min-width: 0; min-height: 0; overflow: hidden; display: flex; flex-direction: column; background: var(--fs-bg-2); }
.flowstudio .fs-board-host::before,
.flowstudio .fs-board-host::after { content: ''; position: absolute; width: 14px; height: 14px; pointer-events: none; z-index: 4; opacity: .15; }
.flowstudio .fs-board-host::before { top: 16px; left: 16px; background: linear-gradient(90deg, currentcolor 0%, currentcolor 30%, transparent 30%) 0 50% / 100% 1px no-repeat, linear-gradient(currentcolor 0%, currentcolor 30%, transparent 30%) 50% 0 / 1px 100% no-repeat; color: rgba(255, 255, 255, .5); }
.flowstudio .fs-board-host::after { top: 16px; right: 16px; background: linear-gradient(270deg, currentcolor 0%, currentcolor 30%, transparent 30%) 100% 50% / 100% 1px no-repeat, linear-gradient(currentcolor 0%, currentcolor 30%, transparent 30%) 50% 0 / 1px 100% no-repeat; color: rgba(255, 255, 255, .5); }
/* Perf: the reference's 24s background-position drift (4px/2% amplitude —
   imperceptible) forced a full-viewport multi-gradient repaint every frame
   (~30%p idle CPU measured). The gradient stack is now static. */
/* Boot reveal: the graph fades in once restore has settled, so nodes never
   appear one batch at a time on top of an already-visible empty canvas. */
.flowstudio .fs-graph { transition: opacity .18s ease-out; }
/* pointer-events MUST ride along with the opacity: an invisible graph still
   hit-tests, so a stray drag on the hidden primary board raised bootGraphDirty
   and the boot graph then won adoption over the user's STORED graph (silent
   data loss). Hidden means untouchable — the canvas below still pans. */
.flowstudio.fs-graph-settling .fs-graph { opacity: 0; pointer-events: none; }

.flowstudio .fs-canvas-wrap { position: relative; width: 100%; height: 100%; overflow: hidden; background: radial-gradient(120% 80% at 22% 28%, rgba(0, 255, 127, .05) 0%, transparent 50%), radial-gradient(120% 80% at 78% 72%, rgba(212, 178, 112, .04) 0%, transparent 55%), radial-gradient(80% 80% at 50% 100%, rgba(0, 0, 0, .5) 0%, transparent 60%), rgb(19, 21, 23); cursor: default; touch-action: none; }
.flowstudio .fs-canvas-wrap:active,
.flowstudio .fs-board-host.is-panning .fs-canvas-wrap { cursor: grabbing; }
.flowstudio .fs-canvas-wrap::before { content: ''; position: absolute; inset: 0; pointer-events: none; box-shadow: rgba(0, 0, 0, .55) 0 0 90px inset, rgba(0, 0, 0, .3) 0 0 250px inset; z-index: 0; }
.flowstudio .fs-canvas-wrap::after { content: ''; position: absolute; inset: 0; pointer-events: none; background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200'><filter id='n'><feTurbulence baseFrequency='0.85' numOctaves='2'/><feColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.03 0'/></filter><rect width='200' height='200' filter='url(%23n)'/></svg>"); opacity: .5; mix-blend-mode: overlay; z-index: 0; }
.flowstudio .fs-dot-grid { position: absolute; inset: 0; pointer-events: none; z-index: 0; }
/* No `will-change: transform` here. It promotes the graph to its own composited
   layer, which the browser rasterises ONCE at the current scale and then just
   stretches — so past 100% every label and border is a scaled-up bitmap rather
   than re-rendered text. Without the hint the layer is re-rasterised at the new
   scale and type stays sharp all the way up. */
.flowstudio .fs-graph { position: absolute; inset: 0; z-index: 5; transform-origin: 0 0; }
/* Two z bands (owner 2026-09-09): small nodes always float above boards.
   bringToFront raises boards below 100000 and everything else above it; this
   floor covers a small node that was never raised, so a raised board cannot
   slide over it. */
.flowstudio .fs-graph > .fs-node:not(.fs-generator-node):not(.fs-board-node) { z-index: 100000; }
.fs-wire-layer { position: absolute; top: 0; left: 0; width: 1px; height: 1px; overflow: visible; pointer-events: none; transition: opacity .18s ease; }
.fs-wire path { fill: none; opacity: .55; filter: drop-shadow(0 1px 1.5px rgba(0, 0, 0, .7)); }
.fs-wire.draft path { opacity: .85; }
.fs-wire circle { stroke: #0a0805; stroke-width: 1px; }
.fs-wire.is-off path { opacity: .35; }
.fs-wire.is-off circle { opacity: .4; }
.fs-wire .hit { pointer-events: stroke; cursor: pointer; }
.fs-wire.is-selected path:not(.hit) { opacity: 1; filter: drop-shadow(0 0 4px currentColor); }
.fs-wire.is-selected circle { opacity: 1; }
.fs-wire-flow-layer path.flow {
  pointer-events: none;
  stroke-width: 3;
  stroke-dasharray: 8 92;
  stroke-linecap: round;
  opacity: .95;
  filter: drop-shadow(0 0 3px currentColor);
  animation: fs-wire-flow .9s linear infinite;
}
.fs-wire.is-synthetic path { stroke-dasharray: 5 5; opacity: .42; }
.fs-wire.is-synthetic circle { opacity: .5; }
@keyframes fs-wire-flow { to { stroke-dashoffset: -100; } }

/* Graph-space overlays share node coordinates. Suggestions opt back into hit
   testing, while drop guides stay completely transparent to board gestures.

   The layer sits ABOVE the whole small-node band, not on its floor (owner
   2026-10-03: the stack appeared behind other nodes). bringToFront raises a
   small node to SMALL_NODE_Z + zCounter, so 100000 — the band's own floor, the
   value this layer used to carry — was under every node that had ever been
   clicked, and the stack hid behind them. The band has no ceiling, so the
   layer simply has to out-rank it by a margin no session can close: a million
   needs 900,000 node raises to reach. Going this high is safe because
   .fs-graph is its own stacking context, so the layer still cannot climb over
   the toolbar, the composer or the panels. */
.fs-suggestion-layer { position: absolute; inset: 0; z-index: 1000000; overflow: visible; pointer-events: none; }
.fs-suggestion-stack {
  position: absolute;
  top: 0;
  left: 0;
  width: 236px;
  /* node_rules.txt can allow up to 8 next/input nodes — the stack scrolls
     rather than running down the canvas. */
  max-height: 342px;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, .16) transparent;
  display: grid;
  gap: 4px;
  padding: 7px;
  color: var(--fs-text);
  background: rgba(17, 19, 21, .97);
  border: 1px solid rgba(0, 255, 127, .32);
  border-radius: 9px;
  box-shadow: 0 18px 42px rgba(0, 0, 0, .62), 0 0 20px rgba(0, 255, 127, .1);
  pointer-events: auto;
  transform-origin: 0 0;
}
.fs-suggestion-stack > header { display: flex; align-items: center; gap: 8px; padding: 3px 5px 5px; }
.fs-suggestion-stack > header b { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font: 700 9px Outfit, sans-serif; letter-spacing: .1em; text-transform: uppercase; }
.fs-suggestion-stack > header span { margin-left: auto; flex: 0 0 auto; color: var(--fs-green); font: 600 8px 'DM Mono', monospace; letter-spacing: .08em; }
.fs-suggestion-stack > button {
  width: 100%;
  min-width: 0;
  display: grid;
  grid-template-columns: 26px minmax(0, 1fr);
  align-items: center;
  gap: 8px;
  padding: 7px 8px;
  color: var(--fs-text-mute);
  background: rgba(255, 255, 255, .025);
  border: 1px solid transparent;
  border-radius: 6px;
  text-align: left;
  cursor: pointer;
}
.fs-suggestion-stack > button:hover,
.fs-suggestion-stack > button:focus-visible { color: var(--fs-text); background: rgba(0, 255, 127, .09); border-color: rgba(0, 255, 127, .3); }
.fs-suggestion-stack > button > i { display: grid; place-items: center; color: var(--fs-green); font: 700 14px 'FlowStudio Pretendard', sans-serif; font-style: normal; }
.fs-suggestion-stack > button > i > svg { width: 18px; height: 18px; display: block; }
.fs-suggestion-stack > button > span { min-width: 0; display: grid; gap: 2px; }
.fs-suggestion-stack > button b,
.fs-suggestion-stack > button small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fs-suggestion-stack > button b { color: inherit; font: 600 10px 'FlowStudio Pretendard', sans-serif; }
.fs-suggestion-stack > button small { color: var(--fs-text-dim); font: 500 8px 'FlowStudio Pretendard', sans-serif; }

/* Disabled node (D / inspector switch): dimmed, body inert; header and ports
   stay live so it can still be selected, renamed, rewired, and re-enabled. */
.fs-node.is-disabled { opacity: .45; filter: saturate(.35); }
.fs-node.is-disabled .fs-node-body { pointer-events: none; }
.fs-node.is-disabled .fs-port { pointer-events: auto; }
/* The footer used to stay live on a bypassed node — Generate there was a
   charged dispatch from a node the graph ignores. (Audit 2026-08-29.) */
.fs-node.is-disabled .fs-node-foot { pointer-events: none; }

/* Auto-wire drop candidate (drag a tool/media card near a node). */
.flowstudio .fs-node.is-wire-target { border-color: rgba(0, 255, 127, .8); box-shadow: 0 0 0 2px rgba(0, 255, 127, .35), 0 0 24px rgba(0, 255, 127, .25); }
/* Palette drag (owner 2026-08-28): every node the dragged tool could legally
   connect to glows in its own accent; once one is hovered (.is-wire-target)
   the rest switch off. Replaces the dashed drop-ghost slots. */
.flowstudio .fs-node.is-wire-candidate { border-color: rgba(var(--node-accent-rgb), .7); box-shadow: 0 0 0 2px rgba(var(--node-accent-rgb), .45), 0 0 18px rgba(var(--node-accent-rgb), .3); }
/* Which half is armed: an accent bar on the side the new node will dock. */
/* Owner 2026-08-29: no thicker edge on the docking side — the hovered target
   wears the plain green glow only (.is-dock-left/right still mark the side
   for the drop logic, unstyled). */
.flowstudio .is-wire-hovering .fs-node.is-wire-candidate:not(.is-wire-target) { border-color: rgba(255, 255, 255, .15); box-shadow: 0 15px 36px rgba(0, 0, 0, .5); }

.flowstudio .fs-help-wrap { position: absolute; top: 16px; left: 18px; z-index: 60; display: flex; align-items: center; gap: 6px; transition: left .3s cubic-bezier(.2, .7, .3, 1); }
/* The same rule on the left: the rail's width less the 38px the fixed 264px
   rail used to leave (owner 2026-09-18). */
.flowstudio.left-open .fs-help-wrap { left: calc(var(--fs-left-w, 264px) - 38px); }
.flowstudio .fs-help-button { position: relative; width: 26px; height: 26px; display: grid; place-items: center; border-radius: 50%; background: rgba(20, 22, 26, .75); border: 1px solid rgba(255, 255, 255, .1); color: rgba(232, 230, 222, .78); font: 700 12px 'FlowStudio Pretendard', sans-serif; cursor: pointer; user-select: none; transition: background .16s, color .16s, border-color .16s, transform .12s; padding: 0; }
.flowstudio .fs-help-button:hover { background: rgba(30, 32, 38, .92); color: #fff; border-color: rgba(255, 255, 255, .22); }
.flowstudio .fs-help-button.open { background: rgba(0, 255, 127, .18); border-color: rgba(0, 255, 127, .55); color: rgb(0, 255, 127); box-shadow: rgba(0, 255, 127, .3) 0 0 14px; }
.flowstudio .fs-help-pop { position: absolute; top: 34px; left: 0; min-width: 280px; padding: 12px 14px 14px; background: rgba(18, 20, 24, .2); border: 1px solid rgba(255, 255, 255, .1); border-radius: 12px; color: rgba(232, 230, 222, .92); font: 500 11px/1.65 'FlowStudio Pretendard', sans-serif; letter-spacing: -.005em; pointer-events: none; opacity: 0; transition: opacity .16s; box-shadow: rgba(0, 0, 0, .55) 0 20px 50px, rgba(0, 0, 0, .3) 0 3px 10px, rgba(255, 255, 255, .08) 0 1px 0 inset; z-index: 61; white-space: nowrap; backdrop-filter: blur(18px) saturate(1.5); max-height: calc(100vh - 70px); overflow-y: auto; scrollbar-width: thin; scrollbar-color: rgba(255, 255, 255, .16) transparent; }
/* The sheet is taller than a laptop viewport — without its own scroll the
   bottom rows (the Workspaces section) simply crop away invisibly. */
.flowstudio .fs-help-pop::-webkit-scrollbar { width: 6px; }
.flowstudio .fs-help-pop::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, .14); border-radius: 3px; }
/* Hover-peek is DISPLAY ONLY. The sheet is ~340x765 and covers the Generator's
   chip row; making it interactive on hover let it swallow every pointer under
   it — and since the sheet is inside .fs-help-wrap, its own hover kept the
   state latched. Only the click-pinned (.open) sheet takes pointers. */
.flowstudio .fs-help-wrap:hover .fs-help-pop { opacity: 1; }
.flowstudio .fs-help-wrap.open .fs-help-pop { opacity: 1; pointer-events: auto; }
/* Pinned help outranks every canvas layer, including the engaged assistant
   (120) and the full-screen galleries (130): pinning IS the intent to keep
   the sheet readable over whatever else comes up. */
.flowstudio .fs-help-wrap.open { z-index: 140; }
.flowstudio .fs-help-hd { font: 700 9px Outfit, sans-serif; letter-spacing: .18em; text-transform: uppercase; color: rgb(0, 255, 127); margin: 10px 0 6px; padding-bottom: 4px; border-bottom: 1px solid rgba(0, 255, 127, .18); }
.flowstudio .fs-help-hd:first-child { margin-top: 0; }
/* Key column wraps instead of running into the label (owner 2026-08-29). */
.flowstudio .fs-help-row { display: grid; grid-template-columns: 190px 1fr; gap: 10px; padding: 1px 0; align-items: start; }
.flowstudio .fs-help-kb { color: rgb(0, 255, 127); font-family: 'DM Mono', monospace; font-size: 10px; letter-spacing: 0; white-space: normal; overflow-wrap: anywhere; }
.flowstudio .fs-help-label { color: rgba(232, 230, 222, .78); font-size: 11px; }
/* Onboarding chips (owner 2026-08-30: moved from the sheet's footer to the
   top, beside the ? button): Tips on/off · Tour. Same surface as the ?, and
   they show only WITH the sheet — hover-peek or pinned — hidden at rest.
   Hidden chips take no pointer, so an invisible chip never wakes the peek. */
.flowstudio .fs-help-act { height: 26px; padding: 0 11px; color: rgba(232, 230, 222, .78); background: rgba(20, 22, 26, .75); border: 1px solid rgba(255, 255, 255, .1); border-radius: 999px; cursor: pointer; font: 600 9px 'DM Mono', monospace; letter-spacing: .08em; text-transform: uppercase; white-space: nowrap; opacity: 0; pointer-events: none; transform: translateX(-4px); transition: opacity .16s, transform .2s cubic-bezier(.22, 1, .36, 1), background .16s, color .16s, border-color .16s; }
.flowstudio .fs-help-wrap:hover .fs-help-act, .flowstudio .fs-help-wrap.open .fs-help-act { opacity: 1; pointer-events: auto; transform: none; }
.flowstudio .fs-help-act:hover { color: #fff; border-color: rgba(0, 255, 127, .4); }
.flowstudio .fs-help-act[aria-pressed="true"] { color: var(--fs-green); background: rgba(0, 255, 127, .12); border-color: rgba(0, 255, 127, .4); }

/* Top-centre of the workspace (owner 2026-08-30): the same visible-span
   centring the composer uses — the panels are overlays, so the centre moves
   with them; `left` transitions on the fold curve. Align · − · % · + · Fit
   is the whole group; Trackpad/Mouse moved to the avatar menu. */
.flowstudio .fs-canvas-toolbar { position: absolute; top: 16px; left: calc(var(--fs-cover-l, 0px) + (100% - var(--fs-cover-l, 0px) - var(--fs-cover-r, 0px)) / 2); transform: translateX(-50%); z-index: 80; display: flex; align-items: center; gap: 4px; height: 28px; padding: 0 8px; background: rgba(18, 20, 24, .72); backdrop-filter: blur(10px) saturate(1.3); border: 1px solid rgba(255, 255, 255, .1); border-radius: 999px; color: rgba(232, 230, 222, .92); font: 500 13px 'FlowStudio Pretendard', sans-serif; letter-spacing: -.005em; user-select: none; transition: left .3s cubic-bezier(.2, .7, .3, 1); }
.flowstudio.left-open .fs-canvas-toolbar { --fs-cover-l: calc(var(--fs-left-w, 264px) - 56px); }
.flowstudio.right-open .fs-canvas-toolbar { --fs-cover-r: calc(var(--fs-right-w, 376px) - 14px); }
/* ── One button contract (owner 2026-09-18) ────────────────────────────────
   "I want the user to feel like they are using the same tool." Every button
   family in the studio answers the pointer the same way, whichever module
   drew it. THE PRESS IS NEW: before this, nothing in Flow Studio had one —
   `:active` existed 9 times in the whole product and 4 were `cursor:
   grabbing`. Declared once, here, rather than in twenty-odd rules, and
   reaching the deferred modules' classes too since they share this document.
   Sizes and the five primary looks are deliberately NOT touched here; they
   move layout, so they are their own pass. */
.flowstudio :is(.fs-toolbar-button, .fs-view-switch, .fs-view-fit, .fs-tl-btn, .fs-tl-play, .fs-tl-fold, .fs-tl-act,
  .fs-gallery-tool, .fs-full-button, .fs-media-view, .fs-ctl-value, .fs-ctl-icon, .fs-nodes-button, .fs-help-act,
  .fs-plan-sq, .fs-plan-btn, .fs-genfull-hbtn, .fs-genfull-tool, .fs-genfull-mini, .fs-genfull-seg,
  .fs-cg-btn, .fs-cg-zoom):active:not(:disabled) { transform: translateY(1px); }
/* One disabled value for those same families: it ran from .38 to .6. */
.flowstudio :is(.fs-toolbar-button, .fs-view-switch, .fs-view-fit, .fs-tl-btn, .fs-tl-act,
  .fs-gallery-tool, .fs-full-button, .fs-media-view, .fs-ctl-value, .fs-ctl-icon,
  .fs-plan-sq, .fs-plan-btn, .fs-genfull-hbtn, .fs-genfull-tool, .fs-cg-btn, .fs-cg-zoom):disabled { opacity: .5; }
.flowstudio .fs-toolbar-button { cursor: pointer; padding: 4px 9px; border: 0; border-radius: 14px; color: rgba(232, 230, 222, .72); background: transparent; transition: background .14s, color .14s; display: inline-flex; align-items: center; font: inherit; }
.flowstudio .fs-toolbar-button:hover { background: rgba(255, 255, 255, .08); color: #fff; }
.flowstudio .fs-zoom-value { padding: 0 4px; min-width: 38px; text-align: center; color: #fff; background: transparent; border: 0; font: 500 13px 'DM Mono', monospace; cursor: pointer; }
.flowstudio .fs-toolbar-sep { width: 1px; height: 14px; background: rgba(255, 255, 255, .12); margin: 0 4px; }
.flowstudio .fs-toolbar-snap,
.flowstudio .fs-toolbar-align,
.flowstudio .fs-toolbar-focus,
.flowstudio .fs-toolbar-fit { letter-spacing: .14em; text-transform: uppercase; font-weight: 700; font-size: 11px; min-width: 38px; text-align: center; justify-content: center; }
/* SNAP is a toggle, so it wears the accent while it is on (owner 2026-09-18). */
.flowstudio .fs-toolbar-snap.is-on { color: var(--fs-green); background: rgba(0, 255, 127, .14); }
.flowstudio .fs-toolbar-snap.is-on:hover { color: var(--fs-green); background: rgba(0, 255, 127, .2); }
/* Neutral flash, not green (owner 2026-09-05) — keeps FIT/ALIGN consistent. */
.flowstudio .fs-toolbar-align.is-flashing { color: #fff; background: rgba(255, 255, 255, .14); box-shadow: 0 0 14px rgba(255, 255, 255, .18); }
.flowstudio .fs-pct-input { width: 44px; background: rgba(255, 255, 255, .08); border: 1px solid rgba(0, 255, 127, .5); border-radius: 5px; color: #fff; font: inherit; text-align: center; padding: 1px 2px; outline: none; }

/* ── Inline generation result (inside a Generator board) ──────────────────── */
/* Fills the framing board the way UI A paints its canvas: the take you are
   iterating on lives here, and only Save puts it on the graph. */
.flowstudio .fs-generator-result { position: absolute; inset: 0; z-index: 3; display: grid; place-items: center; background: rgba(5, 5, 5, .92); border-radius: inherit; overflow: hidden; }
.flowstudio .fs-generator-result[hidden] { display: none; }
.flowstudio .fs-generator-result-media { position: absolute; inset: 0; }
.flowstudio .fs-generator-result-media img,
.flowstudio .fs-generator-result-media video { width: 100%; height: 100%; object-fit: contain; display: block; }
.flowstudio .fs-generator-result-state { position: absolute; left: 50%; bottom: 12px; transform: translateX(-50%); z-index: 1; max-width: 80%; padding: 8px 14px; border-radius: 8px; background: rgba(0, 0, 0, .55); color: var(--fs-text-mute); font: 600 12px 'FlowStudio Pretendard', sans-serif; text-align: center; }
.flowstudio .fs-generator-result-state[hidden] { display: none; }
/* Save sits in the top action row and only appears once a take completed. */
.flowstudio .fs-gen-save { margin-left: 0; padding: 7px 14px; border: 1px solid rgba(0, 255, 127, .5); border-radius: 999px; background: rgba(0, 255, 127, .16); color: var(--fs-green); font: 700 10px Outfit, sans-serif; letter-spacing: .1em; text-transform: uppercase; cursor: pointer; pointer-events: auto; }
.flowstudio .fs-gen-save:hover { background: rgba(0, 255, 127, .3); }
.flowstudio .fs-gen-save[hidden] { display: none; }
.flowstudio .fs-gen-download[hidden], .flowstudio .fs-gen-timeline[hidden] { display: none; }

/* ── Outputs gallery ──────────────────────────────────────────────────────── */
/* Ported from the reference implementation's .v16-gallery. Scoped inside the
   board host (not fixed to the viewport) so it stays inside Flow Studio while
   the hidden console keeps running underneath. */
/* FIXED, not absolute. The backdrop lives inside .fs-board-host (the canvas
   column, position:relative), so `absolute; inset:0` sized it to the canvas —
   the dim layer started below the top bar and stopped at the side panels,
   which is the "wrong offset and size" users saw. It also meant the
   click-outside target only covered part of the screen. No ancestor
   establishes a containing block (no transform/filter/perspective), so fixed
   resolves against the viewport as intended. */
.flowstudio .fs-gallery-back { position: fixed; inset: 0; z-index: 130; display: grid; place-items: center; padding: 24px; background: rgba(0, 0, 0, .72); backdrop-filter: blur(8px); }
.flowstudio .fs-gallery-back[hidden] { display: none; }
.flowstudio .fs-gallery-back.is-drag-through { pointer-events: none; opacity: .12; }
/* 80% of the viewport rather than a fixed 1100x680, which was cramped on a
   large display and overflowed a small one. The min() floor keeps it usable
   on narrow windows where 80vw would be too tight for the grid. */
.flowstudio .fs-gallery { width: 80vw; max-width: 100%; height: 80vh; height: 80dvh; max-height: 100%; min-width: min(100%, 320px); display: grid; grid-template-rows: 56px 1fr; background: linear-gradient(rgb(28, 29, 32) 0%, rgb(21, 22, 26) 100%); border: 1px solid rgba(255, 255, 255, .08); border-radius: 14px; overflow: hidden; box-shadow: rgba(0, 0, 0, .6) 0 24px 60px; font-family: 'FlowStudio Pretendard', sans-serif; }
/* Header shares the body's surface — no divider bar (owner 2026-09-05). */
.flowstudio .fs-gallery-head { display: flex; align-items: center; gap: 14px; padding: 0 20px; border-bottom: 0; background: transparent; }
.flowstudio .fs-gallery-title { display: flex; align-items: center; gap: 12px; flex: 0 0 auto; color: var(--fs-text); font-size: 15px; font-weight: 800; letter-spacing: .01em; }
.flowstudio .fs-gallery-count { display: inline-grid; place-items: center; min-width: 22px; height: 18px; padding: 0 6px; border-radius: 9px; background: rgba(0, 255, 127, .2); border: 1px solid rgba(0, 255, 127, .4); color: var(--fs-green); font: 800 10px 'DM Mono', monospace; }
.flowstudio .fs-gallery-actions { display: flex; align-items: center; gap: 12px; margin-left: auto; }
/* The Visual Framing param-slider look (.fs-param-slider track/fill/knob) on
   a native range input. Webkit cannot paint a progress split natively, so JS
   feeds --fs-zoom-pct; Firefox gets ::-moz-range-progress for free. */
.flowstudio :is(.fs-gallery-zoom, .fs-batch-zoom) { -webkit-appearance: none; appearance: none; width: 140px; height: 18px; margin: 0; padding: 0; background: transparent; cursor: pointer; }
.flowstudio :is(.fs-gallery-zoom, .fs-batch-zoom)::-webkit-slider-runnable-track { height: 5px; border-radius: 3px; background: linear-gradient(90deg, rgb(0, 255, 127) 0%, rgb(92, 242, 177) var(--fs-zoom-pct, 30%), rgb(14, 15, 18) var(--fs-zoom-pct, 30%), rgb(22, 23, 26) 100%); box-shadow: rgba(0, 0, 0, .6) 0 1px 3px inset, rgba(255, 255, 255, .03) 0 1px 0; }
.flowstudio :is(.fs-gallery-zoom, .fs-batch-zoom)::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 14px; height: 14px; margin-top: -4.5px; border: 0; border-radius: 50%; background: radial-gradient(circle at 30% 30%, #fff 0%, rgb(216, 216, 216) 60%, rgb(157, 157, 157) 100%); box-shadow: rgba(255, 255, 255, .08) 0 0 0 3px, rgba(0, 0, 0, .55) 0 2px 6px, rgba(255, 255, 255, .5) 0 1px 0 inset; }
.flowstudio :is(.fs-gallery-zoom, .fs-batch-zoom)::-moz-range-track { height: 5px; border: 0; border-radius: 3px; background: linear-gradient(rgb(14, 15, 18), rgb(22, 23, 26)); box-shadow: rgba(0, 0, 0, .6) 0 1px 3px inset; }
.flowstudio :is(.fs-gallery-zoom, .fs-batch-zoom)::-moz-range-progress { height: 5px; border-radius: 3px; background: linear-gradient(90deg, rgb(0, 255, 127), rgb(92, 242, 177)); }
.flowstudio :is(.fs-gallery-zoom, .fs-batch-zoom)::-moz-range-thumb { width: 14px; height: 14px; border: 0; border-radius: 50%; background: radial-gradient(circle at 30% 30%, #fff 0%, rgb(216, 216, 216) 60%, rgb(157, 157, 157) 100%); box-shadow: rgba(255, 255, 255, .08) 0 0 0 3px, rgba(0, 0, 0, .55) 0 2px 6px; }
.flowstudio :is(.fs-gallery-zoom, .fs-batch-zoom):focus-visible { outline: 0; }
.flowstudio :is(.fs-gallery-zoom, .fs-batch-zoom):focus-visible::-webkit-slider-runnable-track { box-shadow: rgba(0, 0, 0, .6) 0 1px 3px inset, rgba(0, 255, 127, .22) 0 0 0 3px; }
/* Same recipe as the top-bar PROJECTS/OUTPUTS pills (.fs-top-pill), minus
   their green outer glow — owner direction 2026-08-25. */
.flowstudio .fs-gallery-tool { display: inline-flex; align-items: center; height: 28px; padding: 0 12px; background: linear-gradient(rgba(255, 255, 255, .04) 0%, transparent 50%), linear-gradient(rgba(0, 255, 127, .1) 0%, rgba(0, 255, 127, .04) 100%); border: 1px solid rgba(0, 255, 127, .32); border-radius: 14px; color: rgb(0, 255, 127); font: 700 10px Outfit, sans-serif; letter-spacing: .1em; text-transform: uppercase; cursor: pointer; box-shadow: rgba(255, 255, 255, .06) 0 1px 0 inset; transition: .28s cubic-bezier(.22, 1, .36, 1); white-space: nowrap; }
.flowstudio .fs-gallery-tool:hover:not(:disabled) { transform: translateY(-1px); border-color: rgb(0, 255, 127); box-shadow: rgba(255, 255, 255, .08) 0 1px 0 inset, rgba(0, 0, 0, .5) 0 4px 14px; }
.flowstudio .fs-gallery-tool:disabled { opacity: .38; cursor: not-allowed; }
.flowstudio .fs-gallery-filter { display: flex; align-items: center; gap: 4px; padding: 4px; background: var(--fs-panel-2); border: 1px solid var(--fs-line-strong); border-radius: 8px; }
/* Two-row header (owner 2026-08-27): row 1 = title … +ADD/DELETE/USE/EXPORT,
   row 2 = every filter/sort/zoom/search control. Row 2 wears the head dress
   a step quieter and the search hugs its right edge. */
/* The Media browser has THREE rows (title head · controls head · body) since
   #377 split the controls out, but the shell above only declares two: the
   controls row took the flexible track and the body fell into an implicit
   auto row — a one-card library showed the toolbar floating mid-panel with the
   card pinned to the bottom, and a full library clipped instead of scrolling.
   The Projects browser keeps the two-row shell (owner 2026-08-30). */
.flowstudio .fs-gallery:has(.fs-gallery-head-controls) { grid-template-rows: 56px auto minmax(0, 1fr); }
.flowstudio .fs-gallery-head-controls { min-height: 48px; padding: 6px 20px; background: transparent; flex-wrap: wrap; }
.flowstudio .fs-gallery-search { width: 150px; min-width: 0; flex: 1 1 150px; max-width: 280px; margin-left: auto; height: 30px; padding: 0 10px; color: var(--fs-text); background: var(--fs-panel-2); border: 1px solid var(--fs-line-strong); border-radius: 8px; font: 500 12px 'DM Sans', sans-serif; }
.flowstudio .fs-gallery-search::placeholder { color: var(--fs-text-32); }
.flowstudio .fs-gallery-head .fs-media-ctl { flex: 0 0 auto; }
.flowstudio .fs-gallery-filter button { padding: 5px 11px; border: 0; border-radius: 5px; background: transparent; font: 700 10px 'DM Mono', monospace; letter-spacing: .14em; color: var(--fs-text-mute); cursor: pointer; transition: .18s; }
.flowstudio .fs-gallery-filter button:hover { color: var(--fs-text); }
.flowstudio .fs-gallery-filter button.on { background: rgba(0, 255, 127, .14); color: var(--fs-green); box-shadow: rgba(0, 255, 127, .18) 0 0 8px; }
.flowstudio .fs-gallery-close { width: 24px; height: 24px; display: grid; place-items: center; background: transparent; border: 0; border-radius: 50%; color: var(--fs-text-mute); font-size: 18px; line-height: 1; cursor: pointer; }
.flowstudio .fs-gallery-close:hover { background: rgba(255, 255, 255, .08); color: #fff; }
/* grid-auto-rows: max-content is load-bearing. With the default `auto` the
   implicit rows collapsed to ~9px against a column-flex card whose thumb
   sizes itself by aspect-ratio: the thumb's height is indefinite, the row
   never resolved it, and every card rendered as a bare meta strip with no
   image. Caught on staging, not in the static harness — the harness had a
   single row of cards, which hid it. */
.flowstudio .fs-gallery-body { padding: 20px; overflow-y: auto; display: grid; grid-template-columns: repeat(auto-fill, minmax(var(--fs-gal-size, 260px), 1fr)); grid-auto-rows: max-content; gap: 16px; align-content: start; }
.flowstudio .fs-gallery-empty { grid-column: 1 / -1; padding: 48px 0; text-align: center; color: var(--fs-text-dim); font-size: 13px; }
.flowstudio .fs-gallery-card { display: flex; flex-direction: column; background: linear-gradient(rgba(255, 255, 255, .024) 0%, transparent 60%), linear-gradient(rgb(31, 32, 36) 0%, rgb(23, 24, 27) 100%); border: 1px solid rgba(255, 255, 255, .06); border-radius: 10px; overflow: hidden; cursor: pointer; transition: transform .16s, border-color .16s, box-shadow .16s; }
.flowstudio .fs-gallery-card:hover { transform: translateY(-3px); border-color: rgba(0, 255, 127, .34); box-shadow: rgba(0, 0, 0, .55) 0 12px 30px, rgba(0, 255, 127, .16) 0 0 24px; }
/* flex: 0 0 auto so a constrained card cannot shrink the thumb away. */
.flowstudio .fs-gallery-thumb { position: relative; flex: 0 0 auto; aspect-ratio: 16 / 9; overflow: hidden; background: rgb(5, 5, 5); }
.flowstudio .fs-gallery-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.flowstudio .fs-gallery-stamp { position: absolute; top: 8px; left: 8px; padding: 3px 8px; border-radius: 4px; background: rgba(0, 0, 0, .6); border: 1px solid rgba(0, 255, 127, .4); color: var(--fs-green); font: 700 9px 'DM Mono', monospace; letter-spacing: .14em; }
.flowstudio .fs-gallery-play { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 44px; height: 44px; display: grid; place-items: center; background: rgba(0, 255, 127, .18); border: 1.5px solid var(--fs-green); border-radius: 50%; color: var(--fs-green); font-size: 16px; pointer-events: none; }
.flowstudio .fs-gallery-hover { position: absolute; inset: 0; display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: center; gap: 6px; padding-bottom: 12px; background: linear-gradient(transparent 40%, rgba(0, 0, 0, .85) 100%); opacity: 0; transition: opacity .16s; }
.flowstudio .fs-gallery-card:hover .fs-gallery-hover { opacity: 1; }
.flowstudio .fs-gallery-hover button { height: 26px; padding: 0 10px; background: rgba(0, 255, 127, .18); border: 1px solid rgba(0, 255, 127, .45); border-radius: 5px; color: var(--fs-green); font: 700 9px Outfit, sans-serif; letter-spacing: .1em; text-transform: uppercase; cursor: pointer; }
.flowstudio .fs-gallery-hover button:hover { background: rgba(0, 255, 127, .32); }
.flowstudio .fs-gallery-check { position: absolute; top: 8px; right: 8px; z-index: 2; width: 20px; height: 20px; margin: 0; appearance: none; -webkit-appearance: none; display: grid; place-items: center; background: rgba(8, 10, 9, .78); border: 1px solid rgba(255, 255, 255, .3); border-radius: 6px; cursor: pointer; opacity: 0; transition: opacity .16s, background .16s, border-color .16s, box-shadow .16s; }
.flowstudio .fs-gallery-check:hover { border-color: rgba(0, 255, 127, .55); }
.flowstudio .fs-gallery-check::after { content: ''; width: 10px; height: 6px; margin-top: -2px; border: 2px solid var(--fs-green); border-top: 0; border-right: 0; transform: rotate(-45deg); opacity: 0; transition: opacity .12s; }
.flowstudio .fs-gallery-check:checked { background: rgba(0, 255, 127, .16); border-color: var(--fs-green); box-shadow: rgba(0, 255, 127, .28) 0 0 10px; }
.flowstudio .fs-gallery-check:checked::after { opacity: 1; }
.flowstudio .fs-gallery-card:hover .fs-gallery-check,
.flowstudio .fs-gallery-check:checked,
.flowstudio .fs-gallery-check:focus-visible { opacity: 1; }
.flowstudio .fs-gallery-card.is-checked { border-color: rgba(0, 255, 127, .55); box-shadow: rgba(0, 255, 127, .2) 0 0 16px; }
.flowstudio .fs-gal-menu { position: fixed; z-index: 140; min-width: 160px; display: flex; flex-direction: column; padding: 5px; background: rgba(12, 10, 8, .98); border: 1px solid rgba(255, 255, 255, .18); border-radius: 9px; box-shadow: 0 16px 40px rgba(0, 0, 0, .7); }
.flowstudio .fs-gal-menu button { text-align: left; padding: 8px 12px; background: transparent; border: 0; border-radius: 6px; color: var(--fs-text); font: 600 12px Outfit, sans-serif; cursor: pointer; white-space: nowrap; }
.flowstudio .fs-gal-menu button:hover, .flowstudio .fs-gal-menu button:focus-visible { background: rgba(0, 255, 127, .14); color: var(--fs-green); outline: 0; }
.flowstudio .fs-gallery-meta b[contenteditable="true"] { outline: 1px solid rgba(0, 255, 127, .5); border-radius: 4px; padding: 0 4px; white-space: normal; overflow: visible; }
.flowstudio .fs-gallery-meta { padding: 10px 12px 12px; display: grid; gap: 3px; min-width: 0; }
.flowstudio .fs-gallery-meta b { color: var(--fs-text); font-size: 12.5px; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.flowstudio .fs-gallery-meta small { color: var(--fs-text-dim); font: 500 10.5px 'DM Mono', monospace; }

/* ── PROJECTS browser — the gallery shell with a list-shaped body ────────── */
.fs-projects-back { position: fixed; inset: 0; z-index: 130; display: grid; place-items: center; padding: 24px; background: rgba(0, 0, 0, .72); backdrop-filter: blur(8px); }
.fs-projects-back[hidden] { display: none; }
.flowstudio .fs-projects-body { display: block; overflow-y: auto; }
.fs-projects-back.busy .fs-projects { opacity: .65; pointer-events: none; }
/* Explicit minmax so the body row can never lose its scroll constraint: a
   third child in the shell once demoted the body to an implicit auto row,
   which cropped long project lists instead of scrolling them. */
.flowstudio .fs-projects { grid-template-rows: 56px minmax(0, 1fr); }
/* .flowstudio kills every scrollbar globally; the manager is a real scroll
   surface, so it opts back in (same precedent as the full-preview section) —
   a list that scrolls invisibly reads as a list that is cropped. */
.flowstudio .fs-projects-body { scrollbar-width: thin; scrollbar-color: rgba(255, 255, 255, .16) transparent; }
.flowstudio .fs-projects-body::-webkit-scrollbar { width: 8px; display: block; }
.flowstudio .fs-projects-body::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, .14); border-radius: 4px; }
.flowstudio .fs-proj-row { display: flex; align-items: center; gap: 10px; padding: 10px 12px; margin-bottom: 8px; background: rgba(255, 255, 255, .02); border: 1px solid rgba(255, 255, 255, .08); border-radius: 10px; cursor: pointer; }
.flowstudio .fs-proj-row:hover { border-color: rgba(255, 255, 255, .18); }
.flowstudio .fs-proj-row.on { border-color: rgba(0, 255, 127, .35); }
.flowstudio .fs-proj-caret { width: 22px; height: 22px; flex: 0 0 auto; display: grid; place-items: center; color: rgba(232, 230, 222, .6); background: transparent; border: 0; border-radius: 50%; cursor: pointer; font-size: 10px; padding: 0; }
.flowstudio .fs-proj-caret:hover { color: #fff; background: rgba(255, 255, 255, .07); }
.flowstudio .fs-proj-row .fs-proj-name { flex: 0 1 auto; color: var(--fs-text); font: 700 12.5px 'FlowStudio Pretendard', sans-serif; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.flowstudio .fs-proj-meta { flex: 1 1 auto; color: var(--fs-text-dim); font: 500 10px 'DM Mono', monospace; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.flowstudio .fs-proj-actions { display: flex; gap: 6px; flex: 0 0 auto; }
.flowstudio .fs-proj-actions button { padding: 4px 9px; color: rgba(232, 230, 222, .75); background: rgba(255, 255, 255, .05); border: 1px solid rgba(255, 255, 255, .14); border-radius: 6px; cursor: pointer; font: 600 10px 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-proj-actions button:hover { color: #fff; border-color: rgba(255, 255, 255, .35); }
.flowstudio .fs-proj-actions button.danger:hover { color: #ff8d95; border-color: rgba(224, 85, 95, .6); }
.flowstudio .fs-proj-scenes { margin: -2px 0 10px 32px; }
/* Browser drag: the dragged row ghosts; a project row that is the "append
   here" target of a workspace drag lights up; while a PROJECT is being
   dragged every workspace list hides, so row order is the whole story. */
.flowstudio .fs-proj-row.is-dragging,
.flowstudio .fs-scene-row.is-dragging { opacity: .45; }
.flowstudio .fs-proj-row.drop-target { border-color: rgba(0, 255, 127, .55); background: rgba(0, 255, 127, .06); }
.flowstudio .fs-projects-body.drag-project .fs-proj-scenes { display: none; }
/* The cursor-riding snapshot of the grabbed row. pointer-events: none is
   load-bearing — the ghost sits under the pointer, and without it every
   elementFromPoint hit-test during the drag would find the ghost instead of
   the rows beneath it. */
.flowstudio .fs-drag-ghost { position: fixed; z-index: 200; margin: 0; pointer-events: none; opacity: .92; background: rgb(30, 32, 36); border: 1px solid rgba(0, 255, 127, .4); border-radius: 10px; box-shadow: 0 14px 34px rgba(0, 0, 0, .55); }
/* A dragged WORKSPACE TAB keeps its own flat look (owner 2026-08-29): no
   rounded card, just the tab with its accent underline, riding along X only. */
.flowstudio .fs-proj-tab.fs-drag-ghost { background: rgba(30, 32, 36, .96); border: 0; border-bottom: 2px solid var(--fs-green); border-radius: 0; box-shadow: 0 8px 20px rgba(0, 0, 0, .45); }
/* Matches the Media browser's + ADD (fs-gallery-tool); only the ＋/label gap is its own. */
.flowstudio .fs-projects-new { gap: 5px; }
.flowstudio .fs-scene-row { display: flex; align-items: center; gap: 10px; padding: 7px 12px; border-bottom: 1px solid rgba(255, 255, 255, .05); }
.flowstudio .fs-scene-row:last-child { border-bottom: 0; }
.flowstudio .fs-scene-name { flex: 0 1 auto; color: rgba(232, 230, 222, .88); font: 500 11.5px 'FlowStudio Pretendard', sans-serif; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.flowstudio .fs-scene-badge { flex: 0 0 auto; padding: 1px 7px; border-radius: 999px; font: 600 9px 'DM Mono', monospace; }
.flowstudio .fs-scene-badge.open { color: #00FF7F; border: 1px solid rgba(0, 255, 127, .4); }
.flowstudio .fs-scene-badge.closed { color: rgba(232, 230, 222, .5); border: 1px solid rgba(255, 255, 255, .16); }
/* Reference-library add button sits beside Refresh in the Media panel header. */
.flowstudio .fs-media-add { color: var(--fs-green); }

/* ── Navigation chooser sheet ─────────────────────────────────────────────── */
.flowstudio .fs-nav-sheet { position: absolute; inset: 0; z-index: 120; display: grid; place-items: center; padding: 24px; background: rgba(10, 11, 13, .72); backdrop-filter: blur(3px); }
.flowstudio .fs-nav-sheet[hidden] { display: none; }
.flowstudio .fs-nav-card { width: min(560px, 100%); background: var(--fs-panel); border: 1px solid var(--fs-line-strong); border-radius: 16px; padding: 26px 26px 20px; box-shadow: rgba(0, 0, 0, .55) 0 18px 48px; text-align: center; font-family: 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-nav-title { margin: 0 0 8px; font-size: 19px; font-weight: 800; color: var(--fs-text); letter-spacing: -.01em; }
.flowstudio .fs-nav-sub { margin: 0 0 20px; font-size: 13px; line-height: 1.5; color: var(--fs-text-mute); white-space: pre-line; }
.flowstudio .fs-nav-options { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.flowstudio .fs-nav-option { display: grid; gap: 6px; justify-items: center; padding: 20px 14px 16px; background: var(--fs-panel-2); border: 2px solid transparent; border-radius: 12px; cursor: pointer; color: var(--fs-text); font: inherit; transition: border-color .16s, background .16s, transform .12s; }
.flowstudio .fs-nav-option:hover { background: var(--fs-panel-3); transform: translateY(-1px); }
.flowstudio .fs-nav-option.on { border-color: var(--fs-green); background: rgba(0, 255, 127, .08); }
.flowstudio .fs-nav-option:focus-visible { outline: 2px solid var(--fs-green); outline-offset: 2px; }
.flowstudio .fs-nav-figure { color: var(--fs-text-mute); display: block; }
.flowstudio .fs-nav-option.on .fs-nav-figure { color: var(--fs-green); }
.flowstudio .fs-nav-name { font-size: 14px; font-weight: 700; }
.flowstudio .fs-nav-desc { font-size: 11px; line-height: 1.45; color: var(--fs-text-mute); white-space: pre-line; }
/* Start (= save) + Tour wear the top bar's Media pill (owner 2026-08-30). */
.flowstudio .fs-nav-actions { margin-top: 18px; display: flex; justify-content: center; gap: 10px; }
.flowstudio .fs-nav-actions .fs-top-pill { height: 34px; padding: 0 22px; font-size: 11px; border-radius: 17px; }
.flowstudio .fs-nav-actions .fs-top-pill:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
@media (max-width: 560px) {
  .flowstudio .fs-nav-options { grid-template-columns: 1fr; }
}

.flowstudio .fs-outliner-wrap { position: absolute; top: 16px; right: 19px; z-index: 80; font: 500 13px 'FlowStudio Pretendard', sans-serif; color: rgba(232, 230, 222, .92); transition: right .3s cubic-bezier(.2, .7, .3, 1); }
/* Follows a RESIZED inspector (owner 2026-09-18): the rail's own width plus
   the 5px gutter the fixed 376px panel used to leave. Hard-coded, the close
   row slid under a widened panel and was cropped by it. */
.flowstudio.right-open .fs-outliner-wrap { right: calc(var(--fs-right-w, 376px) + 5px); }
.flowstudio .fs-nodes-button { display: inline-flex; align-items: center; gap: 7px; height: 28px; padding: 0 12px 0 10px; background: rgba(18, 20, 24, .72); backdrop-filter: blur(10px) saturate(1.3); border: 1px solid rgba(255, 255, 255, .1); border-radius: 14px; color: rgba(232, 230, 222, .88); font: 700 11px Outfit, sans-serif; letter-spacing: .16em; text-transform: uppercase; cursor: pointer; transition: .16s; }
.flowstudio .fs-nodes-button:hover { background: rgba(28, 32, 38, .85); border-color: rgba(255, 255, 255, .18); }
.flowstudio .fs-outliner-wrap.open .fs-nodes-button { background: rgba(28, 32, 38, .92); border-color: rgba(0, 255, 127, .32); color: rgb(0, 255, 127); }
.flowstudio .fs-nodes-ic { display: inline-grid; place-items: center; }
.flowstudio .fs-nodes-label { letter-spacing: .16em; }
.flowstudio .fs-nodes-count { display: inline-grid; place-items: center; min-width: 16px; height: 16px; padding: 0 4px; border-radius: 8px; background: rgba(0, 255, 127, .18); border: 1px solid rgba(0, 255, 127, .28); color: rgb(0, 255, 127); font: 700 10px 'DM Mono', monospace; letter-spacing: 0; }
.flowstudio .fs-outliner { position: absolute; top: 36px; right: 0; width: 238px; padding: 7px; background: rgba(17, 19, 21, .97); border: 1px solid var(--fs-line-strong); border-radius: 8px; box-shadow: 0 14px 30px rgba(0, 0, 0, .55); }
.flowstudio .fs-outliner[hidden] { display: none; }
.flowstudio .fs-outliner > header { display: flex; justify-content: space-between; padding: 4px 5px 7px; color: var(--fs-text-45); font: 600 8px 'DM Mono', monospace; letter-spacing: .1em; }
.flowstudio .fs-outliner > div { max-height: min(58vh, 460px); display: grid; gap: 3px; overflow-y: auto; }
.flowstudio .fs-outliner-col { min-width: 0; display: grid; gap: 3px; }
.flowstudio .fs-outliner-col + .fs-outliner-col { margin-top: 5px; padding-top: 5px; border-top: 1px solid var(--fs-line); }
.flowstudio .fs-outliner-col-head { min-width: 0; padding: 2px 5px 3px; overflow: hidden; color: var(--fs-text-45); text-overflow: ellipsis; white-space: nowrap; font: 700 8px 'DM Mono', monospace; letter-spacing: .1em; text-transform: uppercase; }
.flowstudio .fs-outliner-row { position: relative; display: grid; grid-template-columns: 14px minmax(0, 1fr) 22px; align-items: center; min-width: 0; border-radius: 5px; }
.flowstudio .fs-outliner-row:hover { background: rgba(255, 255, 255, .06); }
.flowstudio .fs-outliner-row.is-dragging { opacity: .38; }
.flowstudio .fs-outliner-row.drop-before::before,
.flowstudio .fs-outliner-row.drop-after::after { content: ''; position: absolute; z-index: 2; right: 4px; left: 4px; height: 2px; background: var(--fs-green); border-radius: 2px; box-shadow: 0 0 8px rgba(0, 255, 127, .75); pointer-events: none; }
.flowstudio .fs-outliner-row.drop-before::before { top: -2px; }
.flowstudio .fs-outliner-row.drop-after::after { bottom: -2px; }
.flowstudio .fs-outliner-row > i,
.flowstudio .fs-outliner-deleted > i { justify-self: center; width: 6px; height: 6px; border-radius: 50%; }
.flowstudio .fs-outliner-row > button:first-of-type { min-width: 0; display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 6px; padding: 6px 2px; color: var(--fs-text-60); background: transparent; border: 0; text-align: left; cursor: pointer; font: 500 9px 'DM Sans', sans-serif; }
.flowstudio .fs-outliner-row span,
.flowstudio .fs-outliner-deleted span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.flowstudio .fs-outliner-row small { color: var(--fs-text-32); font: 500 8px 'DM Mono', monospace; }
.flowstudio .fs-outliner-row .remove,
.flowstudio .fs-outliner-deleted button { width: 22px; height: 22px; padding: 0; color: var(--fs-text-32); background: transparent; border: 0; border-radius: 4px; cursor: pointer; }
.flowstudio .fs-outliner-row .remove:hover { color: #ff7878; background: rgba(255, 90, 90, .08); }
.flowstudio .fs-outliner-deleted { display: grid; grid-template-columns: 14px minmax(0, 1fr) 22px; align-items: center; min-width: 0; padding: 4px 0; color: var(--fs-text-32); border-top: 1px solid var(--fs-line); font: 500 8px 'DM Mono', monospace; }
.flowstudio .fs-outliner-deleted button:hover { color: var(--fs-green); background: rgba(0, 255, 127, .08); }

.fs-marquee { position: absolute; z-index: 28; pointer-events: none; background: rgba(0, 255, 127, .055); border: 1px solid rgba(0, 255, 127, .72); box-shadow: inset 0 0 18px rgba(0, 255, 127, .04); }
.fs-marquee[hidden] { display: none; }

/* Node context menu — same dress as the canvas quick menu (owner 2026-08-29):
   glyph column, DM Mono rows, kbd hint, one surface for both menus. */
.fs-context-menu { position: fixed; z-index: 900; width: 224px; display: grid; gap: 2px; padding: 5px; box-sizing: border-box; background: rgba(12, 10, 8, .98); border: 1px solid var(--fs-line-strong); border-radius: 9px; box-shadow: 0 16px 40px rgba(0, 0, 0, .7); font: 500 10px 'DM Mono', monospace; }
.fs-context-menu[hidden] { display: none; }
.fs-context-menu button { display: grid; grid-template-columns: 18px minmax(0, 1fr) auto; align-items: center; column-gap: 8px; min-height: 30px; padding: 0 8px 0 11px; color: var(--fs-text-75); background: transparent; border: 0; border-radius: 5px; text-align: left; cursor: pointer; font: inherit; }
.fs-context-menu button[hidden] { display: none; }
.fs-context-menu button:hover { color: #fff; background: rgba(255, 255, 255, .07); }
.fs-context-menu button.danger { color: #ff9393; }
.fs-context-menu button.danger .fs-gl { color: #ff9393; }
.fs-context-menu button:disabled { opacity: .3; cursor: default; }
.fs-context-menu .fs-gl { width: 18px; color: var(--fs-text-75); text-align: center; font: 700 11px 'FlowStudio Pretendard', sans-serif; }
.fs-context-menu .fs-nm { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font: 600 11px 'FlowStudio Pretendard', sans-serif; }
.fs-context-menu .fs-cmenu-kbd { color: var(--fs-text-32); font: 500 9px 'DM Mono', monospace; letter-spacing: .06em; }

/* Canvas quick menu (owner 2026-08-29): right-click on empty canvas. Same
   surface tokens as .fs-context-menu; step colours as left accent bars (the
   toolcard recipe); a fixed flyout per submenu. Opacity-only entry — a
   transform on the menu would become the fixed flyout's containing block. */
.fs-canvas-menu { position: fixed; z-index: 900; width: 224px; padding: 5px; box-sizing: border-box; background: rgba(12, 10, 8, .98); border: 1px solid var(--fs-line-strong); border-radius: 9px; box-shadow: 0 16px 40px rgba(0, 0, 0, .7); font: 500 10px 'DM Mono', monospace; animation: fs-cmenu-in .12s ease-out; }
.fs-canvas-menu .fs-cmenu-search { position: relative; margin-bottom: 4px; }
.fs-canvas-menu .fs-cmenu-search input { width: 100%; height: 26px; padding: 0 8px 0 26px; box-sizing: border-box; color: #FFFFFF; background: #25272c; border: 1px solid rgba(255, 255, 255, .05); border-radius: 5px; font: 500 12px 'FlowStudio Pretendard', sans-serif; }
.fs-canvas-menu .fs-cmenu-search input:focus { outline: none; border-color: rgba(255, 255, 255, .1); box-shadow: none; } /* owner 2026-08-29: no highlight while typing */
.fs-canvas-menu .fs-cmenu-search input::placeholder { font-size: 11px; color: #7c7c7c; }
.fs-canvas-menu .fs-cmenu-search .fs-ic { position: absolute; left: 8px; top: 6px; width: 14px; height: 14px; color: #7c7c7c; pointer-events: none; }
.fs-canvas-menu .fs-cmenu-search .fs-ic svg { width: 14px; height: 14px; display: block; }
.fs-canvas-menu .fs-cmenu-list, .fs-canvas-menu .fs-cmenu-results { display: grid; gap: 2px; max-height: min(60vh, calc(100vh - 120px)); overflow-y: auto; scrollbar-width: none; }
.fs-canvas-menu .fs-cmenu-list[hidden], .fs-canvas-menu .fs-cmenu-results[hidden] { display: none; }
.fs-canvas-menu .fs-cmenu-row { position: relative; display: grid; grid-template-columns: 18px minmax(0, 1fr) auto; align-items: center; column-gap: 8px; min-height: 30px; padding: 0 8px 0 11px; color: var(--fs-text-75); background: transparent; border: 0; border-radius: 5px; text-align: left; cursor: pointer; font: inherit; }
.fs-canvas-menu .fs-cmenu-row:hover, .fs-canvas-menu .fs-cmenu-row.is-active { color: #fff; background: rgba(255, 255, 255, .07); }
.fs-canvas-menu .fs-cmenu-row.is-open { background: rgba(255, 255, 255, .05); }
.fs-canvas-menu .fs-cmenu-row:disabled { opacity: .3; cursor: default; }
.fs-canvas-menu .fs-cmenu-bar { position: absolute; left: 0; top: 6px; bottom: 6px; width: 3px; background: linear-gradient(180deg, var(--accent), rgba(var(--accent-rgb, 0, 255, 127), .5)); border-radius: 0 2px 2px 0; box-shadow: 0 0 8px rgba(var(--accent-rgb, 0, 255, 127), .45); }
.fs-canvas-menu .fs-gl { width: 18px; color: var(--accent, var(--fs-text-75)); text-align: center; font: 700 11px 'FlowStudio Pretendard', sans-serif; }
/* Redesigned tool icons in the menus: the .fs-gl cell is an 18px text box with
   no height, so an inline SVG needs an explicit square size (the toolcard rule
   at :546 sizes the 32/22px card boxes to 100%). */
.fs-context-menu .fs-gl > svg, .fs-canvas-menu .fs-gl > svg { width: 16px; height: 16px; display: inline-block; vertical-align: middle; }
.fs-canvas-menu .fs-nm { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font: 600 11px 'FlowStudio Pretendard', sans-serif; }
.fs-canvas-menu .fs-nm .fs-badge { display: inline-block; margin-left: 6px; padding: 1px 4px; color: #00FF7F; background: rgba(0, 255, 127, .1); border-radius: 3px; font: 700 8px 'DM Mono', monospace; letter-spacing: .06em; vertical-align: 1px; }
.fs-canvas-menu .fs-nm .fs-badge.is-beta { color: #ffd787; background: rgba(246, 183, 67, .12); }
.fs-canvas-menu .fs-arrow, .fs-canvas-menu .fs-cmenu-kbd, .fs-canvas-menu .fs-cmenu-group { color: var(--fs-text-32); font: 500 9px 'DM Mono', monospace; letter-spacing: .06em; white-space: nowrap; }
.fs-canvas-menu .fs-ex { grid-column: 2 / -1; overflow: hidden; color: #7c7c7c; text-overflow: ellipsis; white-space: nowrap; font: 500 9px 'FlowStudio Pretendard', sans-serif; }
.fs-canvas-menu .fs-cmenu-sep { height: 1px; margin: 3px 4px; background: var(--fs-line-strong); }
.fs-canvas-menu .fs-cmenu-empty { padding: 10px 8px; color: var(--fs-text-dim); text-align: center; font: 500 11px 'FlowStudio Pretendard', sans-serif; }
.fs-canvas-menu .fs-cmenu-hint { margin-top: 4px; padding: 3px 6px 0; color: var(--fs-text-32); font: 500 8px 'DM Mono', monospace; letter-spacing: .06em; text-align: right; }
.fs-canvas-menu .fs-cmenu-ask .fs-gl { color: var(--fs-green); }
.fs-canvas-menu .fs-cmenu-flyout { position: fixed; z-index: 901; width: 236px; max-height: min(60vh, calc(100vh - 16px)); overflow-y: auto; scrollbar-width: none; display: grid; gap: 2px; padding: 5px; box-sizing: border-box; background: rgba(12, 10, 8, .98); border: 1px solid var(--fs-line-strong); border-radius: 9px; box-shadow: 0 16px 40px rgba(0, 0, 0, .7); animation: fs-cmenu-in .12s ease-out; }
.fs-canvas-menu .fs-cmenu-flyout .fs-cmenu-row { padding-top: 4px; padding-bottom: 4px; }
@keyframes fs-cmenu-in { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .fs-canvas-menu, .fs-canvas-menu .fs-cmenu-flyout { animation: none; } }

.fs-node {
  --node-accent: var(--fs-green);
  --node-accent-rgb: 0, 255, 127;
  position: absolute;
  top: 0;
  left: 0;
  width: 260px;
  color: var(--fs-text);
  background: #101214;
  border: 1px solid rgba(255, 255, 255, .15);
  border-radius: 10px;
  box-shadow: 0 15px 36px rgba(0, 0, 0, .5), 0 0 0 transparent;
  overflow: visible;
  transition: border-color .15s ease, box-shadow .15s ease;
  /* Deliberately NOT will-change: transform — see .fs-graph. A promoted node
     is rasterised at one scale and stretched, which is what made every node's
     text blur past 100% zoom. */
}
.fs-node.v17-settling { transition: transform 220ms cubic-bezier(.22, 1, .36, 1), border-color .15s ease, box-shadow .15s ease; }
.flowstudio.v19-aligning .fs-node { transition: transform .72s cubic-bezier(.22, 1, .36, 1), border-color .15s ease, box-shadow .15s ease; }
.flowstudio.v19-aligning .fs-wire-layer { opacity: .14; }
.fs-node.selected { border-color: rgba(var(--node-accent-rgb), .75); box-shadow: 0 16px 42px rgba(0, 0, 0, .55), 0 0 24px rgba(var(--node-accent-rgb), .28); }
/* Every family gets the generator's selected bloom in ITS OWN key color
   (owner 2026-09-03: selection must read when zoomed far out, where the
   border hairline vanishes). Same ::after slot the Comet Aura uses — the
   busy-state rules carry .flowstudio (higher specificity), so a generating/
   processing/uploading node's aura still wins over this bloom, and the
   generator's own .selected::after rule outranks this one, keeping the AIO
   exactly as shipped. z-index:-1 puts the halo behind the opaque card. */
.fs-node.selected::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  border-radius: inherit;
  box-shadow: rgba(var(--node-accent-rgb), .3) 0 0 46px, rgba(var(--node-accent-rgb), .16) 0 0 14px;
  animation: fs-generator-selected-glow 3.4s ease-in-out infinite;
  will-change: opacity;
}
@media (prefers-reduced-motion: reduce) { .fs-node.selected::after { animation: none; opacity: 1; } }
/* ── "Comet Aura" (design handoff 2026-08-28) ──────────────────────────────
   A soft spectrum ring orbiting a busy card: white comet head, long tail, a
   dim point exactly opposite. The GRADIENT rotates (animated conic from-angle
   via @property) — colours never hue-shift, that is what reads as a comet.
   0% and 100% stops are identical (seamless wrap); no stop goes transparent.
   Applied through the states every family already toggles: is-generating
   (enhancer/edit/storyboard/sheet/board/output/batch), the result node's
   is-processing and the reference upload's is-uploading. ::after, not
   ::before — the generator's ::before is its sheen. z-index:-1 inside the
   node's own stacking context (nodes carry an inline z-index) puts the halo
   behind the opaque card, so the interior stays dark with no cover layer.
   The pseudo exists only while the class does — nothing to remove. */
@property --fs-aura-a { syntax: '<angle>'; inherits: false; initial-value: 0deg; }
@keyframes fs-aura-rotate { from { --fs-aura-a: 0deg; } to { --fs-aura-a: 360deg; } }
@keyframes fs-aura-pulse { 0%, 100% { opacity: .9; } 50% { opacity: 1; } }
.flowstudio .fs-node.is-generating::after,
.flowstudio .fs-result-node.is-processing::after,
.flowstudio .fs-reference-node.is-uploading::after {
  content: '';
  position: absolute;
  inset: -5px;
  border-radius: 15px;
  z-index: -1;
  pointer-events: none;
  filter: blur(9px) brightness(1.3);
  will-change: filter;
  background: conic-gradient(from var(--fs-aura-a), rgba(0, 255, 127, .62) 0%, rgba(0, 255, 127, .72) 8%, rgba(200, 255, 235, .95) 14%, rgba(255, 255, 255, 1) 17%, rgba(180, 240, 255, .9) 20%, rgba(12, 184, 224, .62) 32%, rgba(140, 130, 255, .45) 44%, rgba(180, 120, 255, .3) 55%, rgba(120, 140, 200, .18) 63%, rgba(90, 150, 160, .12) 67%, rgba(70, 170, 150, .18) 72%, rgba(50, 190, 145, .28) 80%, rgba(30, 210, 140, .4) 88%, rgba(0, 255, 127, .52) 95%, rgba(0, 255, 127, .62) 100%);
  animation: fs-aura-rotate 2.6s linear infinite, fs-aura-pulse 2s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
  .flowstudio .fs-node.is-generating::after,
  .flowstudio .fs-result-node.is-processing::after,
  .flowstudio .fs-reference-node.is-uploading::after { animation: none; opacity: .6; }
}
.flowstudio .fs-generator-node {
  --node-accent: #00FF7F;
  --node-accent-rgb: 0, 255, 127;
  background: linear-gradient(rgb(35, 36, 39) 0%, rgb(26, 27, 29) 100%);
  border: 1px solid rgba(255, 255, 255, .08);
  border-radius: 9px;
  box-shadow: rgba(255, 255, 255, .04) 0 1px 0 inset, rgba(0, 0, 0, .4) 0 -1px 0 inset, rgba(0, 0, 0, .4) 0 4px 10px, rgba(0, 0, 0, .35) 0 14px 32px;
}
.flowstudio .fs-generator-node::before { content: ''; position: absolute; inset: 0; z-index: 0; background: linear-gradient(135deg, rgba(255, 255, 255, .06) 0%, transparent 22%, transparent 78%, rgba(0, 0, 0, .25) 100%); border-radius: inherit; mix-blend-mode: overlay; pointer-events: none; }
/* The selected glow used to animate box-shadow ON THE NODE ITSELF. Animating a
   shadow's spread/blur repaints the element's own box every frame, and on the
   scaled canvas layer that re-rasterizes the chips and text inside it — the
   content visibly shimmers. Move the pulse to a sibling pseudo-element behind
   the node and animate only its opacity, which the compositor can handle
   without touching the node's raster. The static drop shadow stays on the node. */
/* ONE frame when selected (owner request 2026-08-25): the node's own border
   goes luminous green and the pseudo carries only the bloom — no offset ring,
   no `0 0 0 Npx` spread. The double-outline look was the -8px ::after ring
   stacked outside the node's border. */
.flowstudio .fs-generator-node.selected {
  border-color: rgba(0, 255, 127, .55);
  box-shadow: rgba(0, 0, 0, .5) 0 12px 30px;
}
.flowstudio .fs-generator-node.selected::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  border-radius: inherit;
  box-shadow: rgba(0, 255, 127, .3) 0 0 46px, rgba(0, 255, 127, .16) 0 0 14px;
  animation: fs-generator-selected-glow 3.4s ease-in-out infinite;
  will-change: opacity;
}
/* Both states paint the same ::after. The selected glow came later in the
   file and flattened the Comet Aura (inset 0, no rotation) on the very board
   the user pressed Generate on — the busy state has to win. (Audit 2026-08-29.) */
.flowstudio .fs-generator-node.selected.is-generating::after { inset: -5px; border-radius: 15px; box-shadow: none; animation: fs-aura-rotate 2.6s linear infinite, fs-aura-pulse 2s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) { .flowstudio .fs-generator-node.selected.is-generating::after { animation: none; } }
@keyframes fs-generator-selected-glow {
  0%, 100% { opacity: .45; }
  50% { opacity: 1; }
}
.fs-node-head { height: 36px; display: flex; align-items: center; gap: 7px; padding: 0 9px; /* OPAQUE (owner 2026-08-28): a translucent layer lets the Comet Aura (a z:-1 pseudo, painted above the root background) show through. */ background: linear-gradient(180deg, #1b1d20, #101214); border-bottom: 1px solid var(--fs-line); border-radius: 9px 9px 0 0; cursor: grab; user-select: none; }
.fs-node-head:active { cursor: grabbing; }
.fs-node-state { width: 6px; height: 6px; flex: 0 0 auto; border-radius: 50%; background: var(--node-accent); box-shadow: 0 0 8px rgba(var(--node-accent-rgb), .65); }
.flowstudio .fs-standard-node .fs-node-state { cursor: pointer; transition: transform .12s ease, box-shadow .12s ease, filter .12s ease; }
.flowstudio .fs-standard-node .fs-node-state:hover { transform: scale(1.55); filter: brightness(1.25); box-shadow: 0 0 12px rgba(var(--node-accent-rgb), .9); }

/* RUNNING SPINNER.
   `is-generating` was already toggled by every node family — enhancer, edit,
   storyboard, character sheet, board — and styled by nothing, so a working
   node looked identical to an idle one unless you read its status text. This
   renders that existing state.

   A ring AROUND the state dot rather than a replacement for it: the dot is a
   click target on standard nodes (it toggles disabled), so keeping its box
   leaves both the hit area and the layout untouched. `inset` grows the ring
   outside the 6px dot without affecting flex sizing.

   The ring borrows the node's own accent, so each family spins in its own
   colour, and reuses fs-result-spin — the same keyframes the result node and
   the reference upload already spin on. */
.flowstudio .fs-node.is-generating .fs-node-state { position: relative; }
.flowstudio .fs-node.is-generating .fs-node-state::after {
  content: '';
  position: absolute;
  inset: -4px;
  border-radius: 50%;
  border: 1.5px solid rgba(var(--node-accent-rgb), .2);
  border-top-color: var(--node-accent);
  animation: fs-result-spin .8s linear infinite;
  /* The dot underneath owns the click. */
  pointer-events: none;
}
/* The generator's dot is 10px and grey — give its ring room and use the same
   green the board's own busy affordances use. */
.flowstudio .fs-generator-node.is-generating .fs-node-state::after {
  inset: -5px;
  border-color: rgba(0, 255, 127, .2);
  border-top-color: var(--fs-green);
}
@media (prefers-reduced-motion: reduce) {
  .flowstudio .fs-node.is-generating .fs-node-state::after { animation: none; opacity: .55; }
}
/* Header format (owner 2026-08-26): [dot] [tool name in the node's accent]
   [custom label — editable, blank by default]. The kind span IS the tool name
   now — no glyph, no section badge. */
.fs-node-kind { display: inline-flex; align-items: center; flex: 0 0 auto; color: var(--node-accent); font: 700 11px 'Outfit', sans-serif; letter-spacing: .01em; white-space: nowrap; }
.fs-node-title { max-width: 20ch; min-width: 16px; min-height: 14px; margin-left: 4px; overflow: hidden; color: var(--fs-text-75); text-overflow: ellipsis; white-space: nowrap; font: 600 11px 'Outfit', sans-serif; }
/* Blank editable still needs a visible dblclick target. */
.fs-node-title:empty::before { content: '···'; color: var(--fs-text-32); }
.fs-node-title[contenteditable="true"]:empty::before { content: none; }
.fs-node-title[contenteditable="true"] { cursor: text; }
.fs-node-title[contenteditable="true"]:focus { overflow: visible; outline: 1px solid rgba(var(--node-accent-rgb, 0, 255, 127), .5); border-radius: 3px; background: rgba(var(--node-accent-rgb, 0, 255, 127), .06); }
/* Circular, like every other round control on the canvas (the state dot, the
   tab close, the help button, the add-disc). This was the one square affordance
   in the node chrome. */
/* An OUTPUT node's foot IS its Generate button — same 38px footprint the model
   tag used to occupy. Washed green over near-black rather than a solid fill:
   the solid green belongs to the inspector's primary action, and two solid
   greens on screen at once fight each other. */
/* overflow:hidden + radius: with View/Save hidden the Generate button is not
   :last-child, and its square bottom-right corner stuck out past the card
   (owner 2026-08-28). */
.fs-node-foot.is-gen { padding: 0; display: flex; overflow: hidden; border-radius: 0 0 9px 9px; }
/* Generate keeps the room; View/Save are compact and secondary, so the primary
   action does not lose its weight for two utilities. */
.fs-node-foot.is-gen .fs-node-gen { flex: 1 1 auto; width: auto; border-radius: 0 0 0 9px; }
.fs-node-foot.is-gen .fs-node-gen:last-child { border-radius: 0 0 9px 9px; }
.fs-out-act {
  flex: 0 0 auto; height: 100%; padding: 0 11px; display: inline-flex; align-items: center;
  border: 0; border-top: 1px solid var(--fs-line); border-left: 1px solid var(--fs-line);
  background: #0c0e10; color: var(--fs-text-dim); cursor: pointer;
  font: 700 10px 'DM Mono', monospace; letter-spacing: .04em; text-transform: uppercase;
}
.fs-out-act:last-child { border-radius: 0 0 9px 0; }
.fs-out-act:hover { color: #fff; background: rgba(255, 255, 255, .07); }
.fs-out-act[hidden] { display: none; }
.fs-node-gen {
  width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; gap: 8px;
  border: 0; border-top: 1px solid var(--fs-line); border-radius: 0 0 9px 9px; /* owner 2026-08-29: no accent line above the label */
  background: linear-gradient(180deg, rgba(var(--node-accent-rgb, 0, 255, 127), .30), rgba(var(--node-accent-rgb, 0, 255, 127), .12)), #0c0e10;
  color: var(--node-accent, #00FF7F); cursor: pointer;
  font: 800 12px 'Outfit', sans-serif; letter-spacing: .05em; text-transform: uppercase;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .08);
}
.fs-node-gen:hover { filter: brightness(1.12); }
/* No opacity drop while busy — the label already says so, and dimming the one
   affordance that reports progress reads as "broken" rather than "working". */
.fs-node-gen:disabled { cursor: default; }
.fs-node-gen.done { background: #0c0e10; }
.fs-node-close { margin-left: auto; width: 24px; height: 24px; padding: 0; display: grid; place-items: center; color: var(--fs-text-32); background: transparent; border: 0; border-radius: 50%; cursor: pointer; font: 500 17px/1 'FlowStudio Pretendard', sans-serif; }
.fs-node-close:hover { color: #fff; background: rgba(255, 255, 255, .07); }
.fs-node-body { position: relative; height: 154px; overflow: visible; background: #0b0d0f; }
.fs-node-placeholder { position: absolute; inset: 8px; display: grid; place-items: center; align-content: center; gap: 9px; color: rgba(var(--node-accent-rgb, 12, 184, 224), .28); background: radial-gradient(circle at 50% 45%, rgba(var(--node-accent-rgb, 12, 184, 224), .07), transparent 60%); border: 1px dashed rgba(var(--node-accent-rgb, 12, 184, 224), .2); border-radius: 6px; }
.fs-node-placeholder span { color: var(--fs-text-32); font: 500 9px 'DM Mono', monospace; }
/* Production node face (owner 2026-09-13): the story at a glance and the way
   into the full-screen board. */
.fs-node-placeholder.is-plan { display: flex; flex-direction: column; align-items: stretch; justify-content: flex-start; gap: 6px; padding: 12px; text-align: left; overflow: hidden; }
.fs-node-placeholder.is-plan .fs-plan-face-title { color: #FFFFFF; font: 650 13px 'Outfit', sans-serif; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fs-node-placeholder.is-plan .fs-plan-face-line { color: #a6a8ac; font: 500 9px 'DM Mono', monospace; letter-spacing: .12em; text-transform: uppercase; }
.fs-node-placeholder.is-plan .fs-plan-face-list { flex: 1 1 auto; min-height: 0; margin: 2px 0 0; padding: 0; list-style: none; display: grid; align-content: start; gap: 3px; overflow: hidden; }
.fs-node-placeholder.is-plan .fs-plan-face-list li { display: flex; align-items: baseline; gap: 7px; min-width: 0; color: #a6a8ac; font: 500 11px 'FlowStudio Pretendard', sans-serif; white-space: nowrap; }
.fs-node-placeholder.is-plan .fs-plan-face-list i { flex: none; color: rgba(var(--node-accent-rgb, 0, 255, 127), .8); font: 500 9px 'DM Mono', monospace; font-style: normal; }
.fs-node-placeholder.is-plan .fs-plan-face-list b { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; font-weight: 500; }
.fs-node.is-tl-drop { outline: 2px solid var(--node-accent, #00FF7F); outline-offset: 3px; }
.fs-node-placeholder.is-plan .fs-plan-face-list small { flex: none; color: #7c7c7c; font: 500 9px 'DM Mono', monospace; }
/* Prompt·Text nodes: text-only body — no photo glyph; typed text renders as a
   left-aligned multi-line clamp (pre-wrap keeps intentional line breaks, the
   excerpt normalizer in syncPromptNodeBody strips stray indent/blank lines). */
.fs-node-placeholder.is-prompt-text > svg { display: none; }
.fs-node-placeholder.is-prompt-text.has-text { display: block; padding: 10px 12px; overflow: hidden; text-align: left; }
.fs-node-placeholder.is-prompt-text.has-text span {
  display: -webkit-box;
  -webkit-line-clamp: 6;
  -webkit-box-orient: vertical;
  overflow: hidden;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  color: var(--fs-text-60);
  font: 500 10px/1.6 'DM Mono', monospace;
}
/* Output node's own take — a mirror of the latest result, not a second Result
   node: picture + status + click-through, deliberately no actions. */
.fs-out-take { position: absolute; inset: 0; display: grid; grid-template-rows: 1fr auto; gap: 0; padding: 0; border: 0; border-radius: 6px; overflow: hidden; background: #05070a; font: inherit; text-align: center; pointer-events: none; }
/* FIT, never crop (owner 2026-09-06): a node thumbnail shows the whole frame —
   an upscale/edit take cropped to the box hid exactly the edges the user is
   checking. `no-repeat` is mandatory with `contain`, or the letterbox tiles.
   The letterbox reads as the shell's own #05070a. */
/* `padding: 0` is load-bearing. The CONSOLE stylesheet owns a global `.thumb`
   (its media tiles) carrying `padding-bottom: 100%` — the square-aspect hack —
   and it leaks onto this span, forcing the box square (240 + 3px border = 243px)
   inside a 189px grid row. `cover` hid that: the picture bled past the clip and
   looked right. `contain` made it visible — the frame centred in the taller
   square, so it sat low and clipped at the bottom (owner report 2026-09-06).
   Measured on staging: thumb 243px vs row 189px before, 189px after. */
.fs-out-take .thumb { display: block; position: relative; width: 100%; height: 100%; padding: 0; background-size: contain; background-repeat: no-repeat; background-position: center; }
/* ABSOLUTE, not height:100%. The thumb is a grid item whose own height is a
   percentage, so a percentage height on its child resolved to ZERO: the clip
   loaded (readyState 4, 1920x1080, no error) and laid out at 236x0 — a node
   that looked empty for a purely geometric reason. Measured on staging: 0px
   before, 238px after. `inset` gives the box a definite size that does not
   depend on that percentage chain. */
.fs-out-take .thumb video { position: absolute; inset: 0; display: block; width: 100%; height: 100%; object-fit: contain; }
.fs-out-take .thumb.empty { background: repeating-linear-gradient(45deg, rgba(240, 168, 0, .07) 0 8px, transparent 8px 16px); }
.fs-out-take .state { padding: 3px 6px; background: rgba(5, 7, 10, .82); color: var(--fs-text-dim); font: 500 10px 'DM Mono', monospace; letter-spacing: .04em; }
/* A settled take has nothing to say, so its row collapses and the picture takes
   the height (owner 2026-09-06). Explicit — the grid row would otherwise keep
   the span's padding as a visible strip under the thumbnail. */
.fs-out-take .state[hidden] { display: none; }
.fs-out-take.is-running .state { color: var(--fs-green); }
.fs-out-take.is-running .thumb { animation: fs-out-take-pulse 1.4s ease-in-out infinite; }
.fs-out-take.is-error .state { color: #ff6f61; }
/* A take that was still running when the graph was saved — no live job behind
   it, so it must not read as in-flight. */
.fs-out-take.is-stale .state { color: var(--fs-text-dim); font-style: italic; }
.fs-out-take.is-stale .thumb { opacity: .55; }
/* ── Shared play/pause control (owner 2026-08-28) ───────────────────────────
   Hover-revealed on its host (.has-player), SVG glyphs flex-centred; the
   triangle is nudged 2px right for optical centring. Same design on the
   output-take mirror, the result node, clip references and the full-preview
   player (which sizes it up). */
/* Owner 2026-08-29: smaller and more transparent; the triangle is nudged so
   its visual centre (not its bounding box) sits in the circle. */
.fs-play-btn { position: absolute; top: 50%; left: 50%; width: 40px; height: 40px; padding: 0; transform: translate(-50%, -50%); border-radius: 50%; border: 1px solid rgba(255, 255, 255, .22); background: rgba(8, 10, 12, .42); color: rgba(240, 241, 243, .9); display: flex; align-items: center; justify-content: center; cursor: pointer; pointer-events: auto; z-index: 4; opacity: 0; transition: opacity .15s ease, background .15s ease; }
.has-player:hover > .fs-play-btn, .fs-play-btn:focus-visible { opacity: 1; }
.fs-play-btn:hover { color: var(--fs-green); border-color: rgba(0, 255, 127, .55); background: rgba(8, 10, 12, .85); }
.fs-play-btn svg { width: 18px; height: 18px; display: block; }
.fs-play-btn .ic-play { margin-left: 2px; }
.fs-play-btn .ic-pause { display: none; }
.fs-play-btn.is-playing .ic-play { display: none; }
.fs-play-btn.is-playing .ic-pause { display: block; }
.fs-full-preview .fs-pv-player > .fs-play-btn { width: 56px; height: 56px; }
.fs-full-preview .fs-pv-player > .fs-play-btn svg { width: 24px; height: 24px; }
.fs-ref-video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; display: block; background: #05070a; }
/* Hover-scrub timeline bar (owner 2026-08-29, #401): visible only while
   scrubbing a paused clip; the host is the node placeholder. The rules were
   missing from the #401 merge — the bar never rendered. (Audit 2026-08-29.) */
/* Owner 2026-08-29: the playhead is a full-height hairline under the pointer
   (no bottom progress bar); the cursor reads as a left/right scrubber. */
.fs-scrub-bar { position: absolute; top: 0; bottom: 0; left: 0; width: 1px; margin-left: -0.5px; background: rgba(255, 255, 255, .92); box-shadow: 0 0 0 1px rgba(0, 0, 0, .35); opacity: 0; pointer-events: none; z-index: 5; transition: opacity .12s; }
.fs-scrub-bar i { display: none; }
.is-scrubbing { cursor: ew-resize; }
.is-scrubbing > .fs-scrub-bar { opacity: 1; }
.is-scrubbing > .fs-play-btn { opacity: 0; }
.fs-ref-video[hidden] { display: none; }
/* Live batch progress on the generator face (owner 2026-08-28): latest finished
   take + n/N, stacked above the take mirror, pointer-inert, removed at run end. */
.fs-batch-live { position: absolute; inset: 0; z-index: 2; pointer-events: none; background: #05070a; border-radius: 6px; overflow: hidden; }
/* `padding: 0` for the same reason as .fs-out-take .thumb — the console's
   global `.thumb` (padding-bottom: 100%) must not reshape a board thumbnail. */
.fs-batch-live .thumb { display: block; position: absolute; inset: 0; padding: 0; background-size: contain; background-repeat: no-repeat; background-position: center; }
.fs-batch-live .thumb video { position: absolute; inset: 0; display: block; width: 100%; height: 100%; object-fit: contain; }
.fs-batch-live .thumb.empty { background: repeating-linear-gradient(45deg, rgba(0, 255, 127, .08) 0 8px, transparent 8px 16px); animation: fs-out-take-pulse 1.4s ease-in-out infinite; }
.fs-batch-live .count { position: absolute; top: 6px; right: 6px; padding: 2px 7px; border-radius: 999px; background: rgba(5, 8, 6, .82); border: 1px solid rgba(0, 255, 127, .5); color: var(--fs-green, #00FF7F); font: 700 10px 'DM Mono', monospace; letter-spacing: .04em; }
@media (prefers-reduced-motion: reduce) { .fs-batch-live .thumb.empty { animation: none; } }
/* ── Batch on the all-in-one board: the GRID face (owner 2026-08-29) ───────
   Painted last inside .fs-generator-frame; while open it owns the frame (the
   single take, ‹ ›, the subject box — whose pointer-events would eat tile
   clicks — and the framing overlay all step aside). The centre Batch button
   drops to the bottom edge so it never sits on a tile. */
.flowstudio .fs-batch-grid { position: absolute; inset: 0; z-index: 4; display: flex; flex-direction: column; background: #05070a; pointer-events: auto; }
.flowstudio .fs-batch-grid[hidden] { display: none; }
.flowstudio .fs-generator-frame.framing-off > .fs-batch-grid:not([hidden]) { display: flex; }
.flowstudio .fs-generator-node.is-batch-grid :is(.fs-generator-result, .fs-take-nav, .fs-subject-box, .fs-placement, .fs-frame-grid, .fs-frame-bracket) { display: none; }
.flowstudio .fs-batch-grid-bar { flex: 0 0 auto; display: flex; align-items: center; gap: 8px; padding: 6px 8px 0; }
.flowstudio .fs-batch-zoom { width: 120px; }
.flowstudio .fs-batch-grid-tiles { flex: 1 1 auto; min-height: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(var(--fs-tile-size, 96px), 1fr)); grid-auto-rows: max-content; align-content: start; gap: 6px; padding: 8px 8px 88px; overflow: auto; }
.flowstudio .fs-batch-tile { position: relative; aspect-ratio: 1; min-width: 0; padding: 0; border: 1px solid rgba(255, 255, 255, .12); border-radius: 6px; background: #0b0d10; overflow: hidden; cursor: pointer; text-align: left; transition: border-color .12s; }
.flowstudio .fs-batch-tile:hover { border-color: rgba(0, 255, 127, .55); }
.flowstudio .fs-batch-tile .thumb { position: absolute; inset: 0; padding: 0; background-size: contain; background-repeat: no-repeat; background-position: center; }
.flowstudio .fs-batch-tile .thumb video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; }
.flowstudio .fs-batch-tile .label { position: absolute; right: 0; bottom: 0; left: 0; padding: 3px 6px; background: linear-gradient(transparent, rgba(5, 8, 6, .88)); color: rgba(232, 230, 222, .8); font: 500 9px 'DM Mono', monospace; letter-spacing: .04em; text-transform: uppercase; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; pointer-events: none; }
.flowstudio .fs-batch-tile.is-pending .thumb, .flowstudio .fs-batch-tile.is-stale .thumb { background-image: repeating-linear-gradient(45deg, rgba(255, 255, 255, .06) 0 8px, transparent 8px 16px); }
.flowstudio .fs-batch-tile.is-generating .thumb { background-image: repeating-linear-gradient(45deg, rgba(0, 255, 127, .1) 0 8px, transparent 8px 16px); animation: fs-out-take-pulse 1.4s ease-in-out infinite; }
.flowstudio .fs-batch-tile.is-generating { border-color: rgba(0, 255, 127, .45); }
.flowstudio .fs-batch-tile.is-failed { border-color: rgba(255, 111, 97, .6); }
.flowstudio .fs-batch-tile.is-failed .label { color: #ff6f61; }
.flowstudio .fs-batch-tile.is-current { border-color: #00FF7F; box-shadow: 0 0 0 1px rgba(0, 255, 127, .5); }
/* The tile's own full-view square (owner 2026-09-17): a click on the tile
   PICKS the take, this (or a double-click) OPENS it in the single view. */
.flowstudio .fs-batch-tile-open { position: absolute; top: 4px; right: 4px; width: 22px; height: 22px; display: grid; place-items: center; border-radius: 5px; background: rgba(5, 8, 6, .78); border: 1px solid rgba(255, 255, 255, .18); color: #fff; opacity: 0; transition: opacity .12s, border-color .12s, color .12s; }
.flowstudio .fs-batch-tile:hover .fs-batch-tile-open, .flowstudio .fs-batch-tile.is-current .fs-batch-tile-open { opacity: .9; }
.flowstudio .fs-batch-tile-open:hover { opacity: 1; border-color: rgba(0, 255, 127, .7); color: #00FF7F; }
.flowstudio .fs-batch-tile-open svg { width: 11px; height: 11px; display: block; }
/* Shaken loose (owner 2026-09-17): the node flashes red for the wires it shed. */
.flowstudio .fs-node.is-shaken { box-shadow: 0 0 0 2px rgba(255, 111, 97, .9), 0 0 28px rgba(255, 111, 97, .45); transition: box-shadow .25s; }
/* Tile drag (owner 2026-09-08): grab cursor on record tiles, a green bar on
   the side of the tile the drop will land (the Multi-image tile indicator). */
.flowstudio .fs-batch-tile[draggable="true"] { cursor: grab; }
.flowstudio .fs-generator-node.is-tile-dragging .fs-batch-tile { cursor: grabbing; }
.flowstudio .fs-batch-tile.drop-before { box-shadow: -3px 0 0 0 var(--fs-green, #00FF7F); }
.flowstudio .fs-batch-tile.drop-after { box-shadow: 3px 0 0 0 var(--fs-green, #00FF7F); }
.flowstudio .fs-batch-grid .fs-batch-count { margin-left: auto; padding: 2px 7px; border-radius: 999px; background: rgba(5, 8, 6, .82); border: 1px solid rgba(0, 255, 127, .5); color: var(--fs-green, #00FF7F); font: 700 10px 'DM Mono', monospace; letter-spacing: .04em; pointer-events: none; }
.flowstudio .fs-batch-gridchip { display: inline-flex; align-items: center; gap: 5px; padding: 4px 9px; color: #cfd3d6; background: rgba(6, 8, 9, .62); border: 1px solid rgba(255, 255, 255, .16); border-radius: 6px; cursor: pointer; pointer-events: auto; font: 500 10px 'DM Mono', monospace; letter-spacing: .02em; text-transform: uppercase; transition: color .15s, border-color .15s; }
.flowstudio .fs-batch-gridchip[hidden] { display: none; }
/* Lives at the RIGHT end of the top chip row (owner 2026-08-29) — the row is a
   wrapping flex line, so order + auto margin push it past TYPE … RES. */
.flowstudio .fs-gen-top > .fs-batch-gridchip { order: 99; margin-left: auto; }
.flowstudio .fs-batch-gridchip:hover { color: rgba(232, 230, 222, .9); border-color: rgba(255, 255, 255, .32); }
.flowstudio .fs-batch-gridchip.on { color: #00FF7F; border-color: rgba(0, 255, 127, .5); }
/* RESET (owner 2026-09-08): the far-right end of the TYPE … RES row, past
   MATRIX when that shows. Only the first auto margin on the line takes the
   free space, so RESET keeps its own only while MATRIX is hidden. */
.flowstudio .fs-gen-reset { display: inline-flex; align-items: center; gap: 5px; padding: 4px 9px; color: rgba(232, 230, 222, .6); background: rgba(10, 8, 5, .72); border: 1px solid rgba(255, 255, 255, .14); border-radius: 6px; cursor: pointer; pointer-events: auto; font: 500 10px 'DM Mono', monospace; letter-spacing: .02em; white-space: nowrap; }
.flowstudio .fs-gen-top > .fs-gen-reset { order: 100; margin-left: auto; }
.flowstudio .fs-gen-top > .fs-batch-gridchip:not([hidden]) ~ .fs-gen-reset { margin-left: 0; }
.flowstudio .fs-gen-reset:hover { color: rgba(232, 230, 222, .92); border-color: rgba(255, 255, 255, .32); }
.flowstudio .fs-batch-take-row.is-clickable { cursor: pointer; }
.flowstudio .fs-batch-take-row.is-clickable:hover { border-color: rgba(var(--insp-accent-rgb, 0, 255, 127), .45); }
@media (prefers-reduced-motion: reduce) { .flowstudio .fs-batch-tile.is-generating .thumb { animation: none; } }
@keyframes fs-out-take-pulse { 0%, 100% { opacity: .45; } 50% { opacity: .85; } }
@media (prefers-reduced-motion: reduce) { .fs-out-take.is-running .thumb { animation: none; } }
/* A tool with no implementation behind it reads as unavailable rather than ready. */
.flowstudio .fs-node.is-inert { opacity: .62; }
.flowstudio .fs-node.is-inert .fs-node-foot span:last-of-type { color: var(--fs-text-dim); font-style: italic; }
.fs-reference-node .fs-node-placeholder { overflow: hidden; border-style: solid; }
.fs-reference-node.is-dragover .fs-node-placeholder { color: var(--node-accent, #0cb8e0); background: rgba(var(--node-accent-rgb, 12, 184, 224), .12); border-color: var(--node-accent, #0cb8e0); }
.fs-ref-empty { display: grid; place-items: center; gap: 8px; }
.fs-ref-empty[hidden] { display: none; }
/* contain (not cover): reference images must show in full — letterboxed on a
   near-black plate instead of center-cropped. */
.fs-ref-thumb { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; background: #05070a; }
.fs-ref-thumb[hidden] { display: none; }
/* Reference CLIP badge — a named stand-in where an image would be drawn. */
.fs-ref-clip { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; padding: 10px; background: #05070a; text-align: center; }
.fs-ref-clip[hidden] { display: none; }
.fs-ref-clip .glyph { font-size: 26px; line-height: 1; }
.fs-ref-clip b { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--fs-text); font: 600 12px 'FlowStudio Pretendard', sans-serif; }
.fs-ref-clip small { color: var(--fs-text-dim); font: 500 11px 'DM Mono', monospace; }
.fs-reference-node .fs-node-foot { height: 38px; display: flex; padding: 0; }
/* The footer sentence is just the two buttons now (no Use/as words, no
   status tag) - together they take the full row, half each. */
/* grid 1fr 1fr, not flex: equal halves BY CONSTRUCTION - flex-basis 0 still
   let the longer Insert/Replace label out-grow the slot chip. */
.fs-ref-use { flex: 2 1 0; min-width: 0; height: 100%; display: grid; grid-template-columns: 1fr 1fr; gap: 0; align-items: stretch; overflow: hidden; }
/* VIEW is the third footer cell when media exists (top-right overlay retired). */
.fs-ref-view { flex: 1 1 0; min-width: 0; height: 100%; padding: 0 8px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--fs-text-dim); background: #0c0e10; border: 0; border-left: 1px solid var(--fs-line); border-radius: 0 0 9px 0; cursor: pointer; font: 700 10px 'DM Mono', monospace; letter-spacing: .04em; text-transform: uppercase; }
.fs-ref-view:hover { color: #fff; background: rgba(255, 255, 255, .07); }
.fs-ref-view[hidden] { display: none; }
.flowstudio .fs-reference-node .fs-node-foot:has(.fs-ref-view:not([hidden])) .fs-ref-slot-btn { border-radius: 0; }
.fs-ref-use .fs-ref-choose { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Flat footer cells — the Image Generator's button dress (owner 2026-08-26):
   full-height segments split by hairlines, mono uppercase, no boxes. */
.fs-ref-choose { position: static; right: auto; bottom: auto; z-index: auto; height: 100%; padding: 0 8px; color: var(--fs-text-dim); background: #0c0e10; border: 0; border-radius: 0 0 0 9px; cursor: pointer; font: 700 10px 'DM Mono', monospace; letter-spacing: .04em; text-transform: uppercase; }
.fs-ref-choose:hover { color: #fff; background: rgba(255, 255, 255, .07); }
.fs-ref-choose:disabled,
.fs-ref-slot-btn:disabled { opacity: .45; cursor: wait; }
.fs-ref-progress { position: absolute; inset: 0; z-index: 3; display: grid; place-items: center; align-content: center; gap: 8px; color: var(--node-accent, #0cb8e0); background: rgba(6, 8, 9, .78); backdrop-filter: blur(5px); }
.fs-ref-progress[hidden] { display: none; }
.fs-ref-progress i { width: 24px; height: 24px; border: 2px solid rgba(var(--node-accent-rgb, 12, 184, 224), .18); border-top-color: var(--node-accent, #0cb8e0); border-radius: 50%; animation: fs-result-spin .8s linear infinite; }
.fs-ref-slot { min-width: 0; max-width: none; display: inline-flex; align-items: center; }
.fs-ref-slot-btn { width: 100%; min-width: 0; height: 100%; appearance: none; -webkit-appearance: none; padding: 0 8px; overflow: hidden; color: var(--fs-text-dim); background: #0c0e10; border: 0; border-left: 1px solid var(--fs-line); border-radius: 0 0 9px 0; outline: 0; text-overflow: ellipsis; white-space: nowrap; text-align: center; cursor: pointer; font: 700 10px 'DM Mono', monospace; letter-spacing: .04em; text-transform: uppercase; }
/* The cell that NEEDS the user is the colored one (owner 2026-08-26):
   an empty reference lights Insert; loaded nodes are all dim utilities. */
.fs-ref-choose.is-cta { color: var(--node-accent, #0cb8e0); }
.fs-ref-slot-btn:hover,
.fs-ref-slot-btn:focus-visible,
.fs-ref-slot-btn.open { color: #fff; background: rgba(255, 255, 255, .07); }
/* The slot menu anchors to the FOOTER, not to .fs-ref-slot: the sentence row
   clips (overflow:hidden) so a menu inside it would be cut off. Right-aligned
   because the slot chip sits at the end of "Use {img} as {slot}". Options are
   sized like the node title — the whole point of replacing the native select
   was that its OS-drawn list could not scale with the board. */
.flowstudio .fs-reference-node .fs-node-foot { position: relative; }
/* (0,3,0) specificity ON PURPOSE: the base .fs-gen-dropdown rule sits LATER
   in this file, and at (0,2,0) its left:0 won the tie - both edges pinned
   stretched every slot menu to full node width (the 2026-08-16 screenshots).
   Same rule for every reference-family node = the menus finally match. */
.flowstudio .fs-reference-node .fs-ref-slot-menu { left: auto; right: 9px; width: max-content; min-width: 132px; max-width: 210px; }
.flowstudio .fs-ref-slot-menu .fs-gen-option { padding: 7px 10px; font: 500 11px 'DM Mono', monospace; }
.flowstudio .fs-ref-slot-menu .fs-gen-option.on::after { font-size: 10px; }
/* A failed upload used to leave the reference node looking untouched (the
   old .fs-ref-status line no longer exists) — frame it like a failed result. */
.fs-reference-node.is-error { border-color: rgba(255, 92, 92, .65); }
/* Media framed like the reference node (owner request 2026-08-25): the base
   placeholder's inset-8px margin + 6px radius stay, the dashed border goes
   solid-neutral, and the asset letterboxes on the same dark ground. */
.fs-result-node .fs-node-placeholder { overflow: hidden; border-style: solid; border-color: rgba(255, 255, 255, .1); }
.fs-result-node.is-complete .fs-node-placeholder { background: #05070a; }
.fs-result-node .fs-node-placeholder img,
.fs-result-node .fs-node-placeholder video { width: 100%; height: 100%; display: block; object-fit: contain; background: #05070a; }
.fs-result-node.is-error { border-color: rgba(255, 92, 92, .65); }
/* In-flight preview: the pending result node paints the console's live frame
   behind the spinner (flowstudio.js paintInflightPreview). */
.fs-result-node .fs-node-placeholder.has-preview { background-size: contain; background-position: center; background-repeat: no-repeat; border-radius: 5px; }
.fs-node-placeholder.has-preview .fs-result-progress { width: auto; padding: 8px 12px; background: rgba(6, 8, 9, .55); border-radius: 6px; }
.fs-result-progress { width: 100%; display: grid; place-items: center; gap: 8px; color: var(--node-accent, var(--fs-green)); }
.fs-result-progress i { width: 28px; height: 28px; border: 2px solid rgba(var(--node-accent-rgb, 0, 255, 127), .16); border-top-color: var(--node-accent, var(--fs-green)); border-radius: 50%; animation: fs-result-spin .8s linear infinite; }
.fs-result-progress b { font: 700 9px 'DM Mono', monospace; letter-spacing: .14em; }
.fs-result-progress span { color: var(--fs-text-32); }
.fs-result-error { max-width: 210px; display: grid; place-items: center; gap: 9px; color: #ff7878; text-align: center; }
.fs-result-error b { width: 28px; height: 28px; display: grid; place-items: center; border: 1px solid currentColor; border-radius: 50%; font: 700 16px 'DM Mono', monospace; }
.fs-result-error span { color: rgba(255, 180, 180, .72); line-height: 1.4; }
/* The buttons LIVE IN the 38px footer row (model/status spans hide while a
   complete take shows its verbs). Flat full-height cells, hairline-split —
   the Image Generator's button dress (owner 2026-08-26). */
.fs-node-foot.is-actions { padding: 0; }
.fs-node-foot.is-actions span { display: none; }
/* The cells DIVIDE the node's full width between them (owner 2026-08-26). */
.fs-node-foot.is-actions .fs-out-act { flex: 1 1 0; height: 100%; justify-content: center; }
.fs-node-foot.is-actions .fs-out-act:first-of-type { border-left: 0; border-radius: 0 0 0 9px; }
.fs-result-actions { flex: 1 1 auto; min-width: 0; height: 100%; display: flex; gap: 0; }
.fs-result-actions button { flex: 1 1 0; min-width: 0; height: 100%; padding: 0 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--fs-text-dim); background: #0c0e10; border: 0; border-left: 1px solid var(--fs-line); cursor: pointer; font: 700 10px 'DM Mono', monospace; letter-spacing: .04em; text-transform: uppercase; }
.fs-result-actions button:first-child { border-left: 0; border-radius: 0 0 0 9px; }
.fs-result-actions button:last-child { border-radius: 0 0 9px 0; }
.fs-result-actions button:hover { color: #fff; background: rgba(255, 255, 255, .07); }
/* VIEW sits alone at the top-right of the media (the row keeps the WRITE
   actions — Recreate/Update). It left the actions row, so it carries the row's
   button styling itself. */
/* Recreate/Update dispatching: both buttons locked + a working pulse on the
   node until the bridge hands back control (spam guard — runResultAction). */
.fs-result-node.is-action-busy .fs-result-actions button { pointer-events: none; opacity: .35; }
.fs-result-node.is-action-busy .fs-node-state { animation: fs-busy-pulse 1s ease-in-out infinite; }
@keyframes fs-busy-pulse { 50% { opacity: .25; } }
/* vault-dedup attention pulse: media-card click on an item already on canvas */
.flowstudio .fs-node.fs-node-attn { animation: fs-node-attn 1s ease-out 1; }
.flowstudio .fs-node.fs-node-suggest-pulse { animation: fs-node-suggest-pulse .6s ease-out 1; }
/* '#' picker preview: which node the highlighted row points at. Outline only —
   no transform or size change, so peeking never nudges the node under the cursor. */
.flowstudio .fs-node.fs-mention-peek { outline: 2px solid var(--fs-green); outline-offset: 3px; box-shadow: 0 0 0 6px rgba(0, 255, 127, .16), 0 18px 40px rgba(0, 0, 0, .5); }
@keyframes fs-node-attn { 0%, 55% { box-shadow: 0 0 0 2px rgba(12, 184, 224, .85), 0 0 26px rgba(12, 184, 224, .55); } 100% { box-shadow: 0 0 0 2px rgba(12, 184, 224, 0), 0 0 26px rgba(12, 184, 224, 0); } }
@keyframes fs-node-suggest-pulse { 0%, 35% { box-shadow: 0 0 0 3px rgba(0, 255, 127, .82), 0 0 30px rgba(0, 255, 127, .5); } 100% { box-shadow: 0 0 0 3px rgba(0, 255, 127, 0), 0 0 30px rgba(0, 255, 127, 0); } }
.fs-node-foot { height: 38px; display: flex; align-items: center; justify-content: space-between; padding: 0 9px; background: #101214; border-radius: 0 0 9px 9px; color: var(--fs-text-32); border-top: 1px solid var(--fs-line); font: 500 8px 'DM Mono', monospace; }
/* Result footer left slot carries a model displayName (unbounded registry
   text) — ellipsize inside the 38px footer instead of wrapping into the
   status word; the full text lives on the title attr (syncResultModelTag). */
.flowstudio .fs-result-node .fs-node-foot span:first-child { min-width: 0; max-width: 70%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.flowstudio .fs-generator-node .fs-node-head,
.flowstudio .fs-generator-node .fs-generator-body,
.flowstudio .fs-generator-node > .fs-node-foot { position: relative; z-index: 1; }
.flowstudio .fs-generator-node .fs-node-head { gap: 9px; padding: 0 12px; background: linear-gradient(rgba(255, 255, 255, .05) 0%, transparent 100%), linear-gradient(rgba(30, 32, 36, .95), rgba(25, 27, 30, .95)); border-bottom: 1px solid rgba(255, 255, 255, .05); border-radius: 9px 9px 0 0; }
.flowstudio .fs-generator-node .fs-node-head::after { content: ''; position: absolute; top: 0; right: 0; left: 0; height: 1px; background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .1), transparent); pointer-events: none; }
.flowstudio .fs-generator-node .fs-node-state { width: 10px; height: 10px; background: #877c68; box-shadow: none; pointer-events: auto; cursor: default; transition: none; }
/* The board's name matches every other node now — plain accent text, no
   badge box (owner request 2026-08-26; the ALL-IN-ONE pill retired). */
.flowstudio .fs-generator-node .fs-node-kind { display: inline-flex; align-items: center; color: var(--node-accent); font: 700 12px 'Outfit', sans-serif; letter-spacing: .01em; }
/* Same face + size as the board name (owner 2026-08-30): the 10px Pretendard
   title sat visibly higher and smaller than the 12px Outfit kind beside it. */
/* The generator sets min-width:0, so the capped editor collapsed to zero on
   an untitled node. 16px is what every other node gives an empty title. */
.flowstudio .fs-generator-node .fs-node-title[contenteditable="true"] { flex: 0 1 auto; max-width: 20ch; min-width: 16px; }
.flowstudio .fs-generator-node .fs-node-title { min-width: 0; max-width: none; flex: 1 1 0; margin-left: 0; color: #f4ede0; font: 600 12px 'Outfit', sans-serif; letter-spacing: .01em; }
/* Renaming is a text gesture; a delete button one tab-stop from the caret
   is an invitation to lose the node (owner 2026-09-01).
   Keyed on :focus rather than [contenteditable="true"]: focus is the
   browser's to clear, so the button cannot be stranded by a commit path
   that forgets to reset the attribute. */
.flowstudio .fs-generator-node .fs-node-head:has(.fs-node-title:focus) .fs-node-close { display: none; }
/* Match the standard node × (owner 2026-09-05): glyph at rest, a filled circle
   with NO outline on hover, no grow. */
.flowstudio .fs-generator-node .fs-node-close { width: 24px; height: 24px; display: grid; place-items: center; flex: 0 0 auto; margin-left: 0; padding: 0; color: rgba(232, 230, 222, .45); background: transparent; border: 0; border-radius: 50%; font: 500 16px/1 'FlowStudio Pretendard', sans-serif; transition: background .16s, color .16s; }
.flowstudio .fs-generator-node .fs-node-close:hover { color: #fff; background: rgba(255, 255, 255, .1); }
.flowstudio .fs-generator-node > .fs-node-foot { height: 38px; display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 10px; padding: 0 12px; background: linear-gradient(rgba(25, 27, 30, .95) 0%, rgba(20, 22, 25, .95) 100%); border-top: 1px solid rgba(255, 255, 255, .04); border-radius: 0 0 9px 9px; box-shadow: rgba(0, 0, 0, .3) 0 -1px 0 inset; }
.flowstudio .fs-generator-node > .fs-node-foot .mdl { min-width: 0; overflow: hidden; color: #b8aa90; text-overflow: ellipsis; white-space: nowrap; font: 500 8px 'FlowStudio Pretendard', sans-serif; letter-spacing: -.005em; }
.fs-port { position: absolute; z-index: 8; top: calc(50% - 6px); width: 12px; height: 12px; padding: 0; background: var(--node-accent); border: 2px solid #0a0805; border-radius: 50%; box-shadow: 0 0 10px rgba(var(--node-accent-rgb), .4); cursor: crosshair; transition: transform .12s ease, box-shadow .12s ease; }
.fs-port.free { background: #0a0805; border-color: rgba(var(--node-accent-rgb), .78); box-shadow: 0 0 0 1px rgba(var(--node-accent-rgb), .14) inset, 0 0 7px rgba(var(--node-accent-rgb), .24); }
.fs-port.wired { background: var(--node-accent); border-color: #0a0805; box-shadow: 0 0 0 1px rgba(255, 255, 255, .18) inset, 0 0 12px rgba(var(--node-accent-rgb), .62); }
.fs-port:hover { transform: scale(1.28); box-shadow: 0 0 14px rgba(var(--node-accent-rgb), .72); }
/* Magnet snap (owner 2026-08-27): the port a dragged wire end has locked
   onto — bigger and brighter than hover, since the pointer itself may sit
   up to the snap radius away. */
.fs-port.snap-target { transform: scale(1.55); box-shadow: 0 0 18px rgba(var(--node-accent-rgb), .9); }
.fs-port-in { left: -7px; }
.fs-port-out { right: -7px; }
/* Generator input port: the Add-reference disc IS the input anchor now (wires
   land on its centre and dragging it starts a wire), so a second dot 28px above
   it would be a target that nothing connects to. Kept in the DOM — it still
   carries the port's accessible name and works as a keyboard/AT drag handle —
   but visually collapsed onto the disc and hidden from sight. */
.flowstudio .fs-generator-node > .fs-port-in {
  top: calc(50% - 6px); z-index: 7;
  opacity: 0; pointer-events: none;
}
/* The board's BATCH handle (owner 2026-09-08): a plain 12px dot on the node
   root at the registry fraction (inline top), its label floated left like the
   Output node's. The Source disc's own top moves with it (inline). */
.flowstudio .fs-generator-node > .fs-port-batch { left: -7px; margin-top: -6px; z-index: 9; }

.flowstudio .fs-generator-body { overflow: visible; background: rgb(5, 4, 3); box-shadow: rgba(0, 0, 0, .4) 0 0 0 1px inset, rgba(0, 0, 0, .4) 0 2px 6px inset; transition: height .12s ease; }
/* Mid-drag the eased height lags the instant width - the shape sweeps
   through every ratio and snaps at release. The gesture suppresses it. */
.flowstudio .fs-generator-node.is-resizing .fs-generator-body { transition: none; }
/* Perf: the reference's 4.6s filter (saturate/brightness) "breath" re-rasterized
   the whole framing board every frame; removed (±4-8% shift, imperceptible). */
.flowstudio .fs-generator-frame { position: absolute; top: var(--frame-top, 38px); right: 10px; bottom: var(--frame-bottom, 38px); left: 10px; overflow: hidden; isolation: isolate; background: repeating-linear-gradient(45deg, rgba(255, 255, 255, .01) 0, rgba(255, 255, 255, .01) 8px, transparent 8px, transparent 18px), rgb(12, 10, 7); border: 0; border-radius: 4px; }
/* Perf: the flare pulse repainted every frame even without blend-mode (the
   pseudo can't get its own compositor layer inside the isolated overflow-hidden
   frame) — measured ~8%p idle CPU for a 36px blob. Now a static soft glow at
   the pulse's mid state (mix-blend-mode also dropped, alpha .22→.28). */
/* (The warm 36px flare blob retired 2026-08-26 — owner request.) */
.flowstudio .fs-generator-frame::after { content: ''; position: absolute; inset: 0; z-index: 2; background: radial-gradient(at 28% 78%, rgba(255, 196, 128, .1) 0%, transparent 55%), radial-gradient(at 72% 12%, transparent 0%, rgba(0, 0, 0, .3) 100%); mix-blend-mode: overlay; pointer-events: none; }
.flowstudio .fs-generator-frame > * { z-index: 3; }
/* Accessibility + battery: stop all decorative Flow Studio animation for
   users who ask for reduced motion. */
@media (prefers-reduced-motion: reduce) {
  .flowstudio .fs-composer-aura i,
  .flowstudio .fs-node.fs-node-suggest-pulse,
  .flowstudio .fs-wire-flow-layer path.flow,
  .flowstudio .fs-typing span,
  .flowstudio .fs-splash g.spin { animation: none !important; }
  .flowstudio .fs-node.v17-settling,
  .flowstudio.v19-aligning .fs-node { transition: none !important; }
}
.flowstudio .fs-frame-grid { position: absolute; inset: 0; pointer-events: none; }
.flowstudio .fs-frame-grid.is-hidden { display: none; }
.flowstudio .fs-frame-grid i { position: absolute; background: rgba(255, 255, 255, .1); }
.flowstudio .fs-frame-grid .v { top: 0; bottom: 0; width: 1px; }
.flowstudio .fs-frame-grid .h { right: 0; left: 0; height: 1px; }
.flowstudio .fs-frame-grid .one.v { left: 33.33%; }.flowstudio .fs-frame-grid .two.v { left: 66.66%; }
.flowstudio .fs-frame-grid .one.h { top: 33.33%; }.flowstudio .fs-frame-grid .two.h { top: 66.66%; }
.flowstudio .fs-frame-bracket { position: absolute; width: 12px; height: 12px; border: 0 solid rgba(0, 255, 127, .55); pointer-events: none; }
.flowstudio .fs-frame-bracket.tl { top: 5px; left: 5px; border-top-width: 1.5px; border-left-width: 1.5px; }
.flowstudio .fs-frame-bracket.tr { top: 5px; right: 5px; border-top-width: 1.5px; border-right-width: 1.5px; }
.flowstudio .fs-frame-bracket.bl { bottom: 5px; left: 5px; border-bottom-width: 1.5px; border-left-width: 1.5px; }
.flowstudio .fs-frame-bracket.br { right: 5px; bottom: 5px; border-right-width: 1.5px; border-bottom-width: 1.5px; }
.flowstudio .fs-placement { position: absolute; top: 10px; left: 50%; padding: 3px 9px; color: rgba(232, 230, 222, .45); background: rgba(10, 8, 5, .6); border-radius: 5px; transform: translateX(-50%); white-space: nowrap; text-transform: uppercase; pointer-events: none; font: 600 9px 'DM Mono', monospace; letter-spacing: .14em; }
.flowstudio .fs-generator-frame.framing-off > * { display: none; }
/* ...except the generation result. FRAME-off hides the framing overlays
   (grid, brackets, subject box); the take the user is iterating on is not
   one of them. Without this the board rendered empty after a successful
   generation — caught on staging with a real render, since the harness
   never had the framing-off class. */
.flowstudio .fs-generator-frame.framing-off > .fs-generator-result:not([hidden]) { display: grid; }
.flowstudio .fs-subject-box { position: absolute; display: flex; align-items: center; justify-content: center; color: #00FF7F; background: rgba(0, 255, 127, .07); border: 1.5px solid #00FF7F; box-shadow: 0 0 14px rgba(0, 255, 127, .18); cursor: move; pointer-events: auto; }
.flowstudio .fs-subject-box > span { color: #00FF7F; white-space: nowrap; text-shadow: 0 1px 2px rgba(0, 0, 0, .8); font: 600 8px 'DM Mono', monospace; letter-spacing: .1em; }
.flowstudio .fs-subject-handle { position: absolute; z-index: 5; width: 12px; height: 12px; background: #00FF7F; border: 2px solid #0a0805; border-radius: 2px; pointer-events: auto; }
.flowstudio .fs-subject-handle:hover { transform: scale(1.25); }
.flowstudio .fs-subject-handle.tl { top: -6px; left: -6px; cursor: nwse-resize; }.flowstudio .fs-subject-handle.tr { top: -6px; right: -6px; cursor: nesw-resize; }
.flowstudio .fs-subject-handle.bl { bottom: -6px; left: -6px; cursor: nesw-resize; }.flowstudio .fs-subject-handle.br { right: -6px; bottom: -6px; cursor: nwse-resize; }

.flowstudio .fs-gen-top,
.flowstudio .fs-gen-foot { position: absolute; z-index: 6; display: flex; flex-wrap: wrap; align-items: center; gap: 5px; pointer-events: none; }
.flowstudio .fs-gen-top { top: 6px; right: 6px; left: 6px; padding: 0; background: none; }
/* Centre stack (owner 2026-08-28): the board's action buttons sit in the
   middle of the frame as pills — Generate/Regenerate, Save, View. */
/* Owner 2026-08-29: the stack sits LOW on every face (image, clip, MATRIX)
   — the clip's row, nudged up a little — so the buttons never move between
   an image take and a video take. */
.flowstudio .fs-gen-center { position: absolute; inset: 0; z-index: 6; display: flex; align-items: flex-end; justify-content: center; gap: 8px; padding-bottom: 60px; pointer-events: none; opacity: 0; transition: opacity .15s ease; }
/* Always readable (owner 2026-08-29: full transparency was not helping); fully lit on board hover (owner 2026-08-29); always shown while a run is in flight. */
/* Owner 2026-08-29: the centre stack is INVISIBLE until the board is hovered
   or selected (it sat on the picture); a running board keeps it lit. */
.flowstudio .fs-generator-node:hover .fs-gen-center, .flowstudio .fs-generator-node.selected .fs-gen-center, .flowstudio .fs-generator-node.is-generating .fs-gen-center, .flowstudio .fs-gen-center:focus-within { opacity: 1; }
.flowstudio .fs-generator-node .fs-gen-center > * { pointer-events: none; } /* (0,3,0): outranks the old pill rules' pointer-events:auto whatever their order */
.flowstudio .fs-generator-node:hover .fs-gen-center > *, .flowstudio .fs-generator-node.selected .fs-gen-center > *, .flowstudio .fs-generator-node.is-generating .fs-gen-center > *, .flowstudio .fs-gen-center:focus-within > * { pointer-events: auto; }
/* Generate · VIEW · DETACH all wear the top-row chip dress (.fs-gen-chip). */
.flowstudio .fs-gen-center > button { min-height: 0; margin: 0; padding: 7px 14px; display: inline-flex; align-items: center; gap: 6px; color: #00FF7F; background: rgba(10, 8, 5, .82); border: 1px solid rgba(0, 255, 127, .4); border-radius: 7px; box-shadow: none; cursor: pointer; font: 500 12px 'DM Mono', monospace; letter-spacing: .02em; text-transform: uppercase; transition: color .12s, border-color .12s, background .12s; transform: none; }
.flowstudio .fs-gen-center > button:hover { background: rgba(0, 255, 127, .14); border-color: #00FF7F; filter: none; transform: none; box-shadow: 0 0 8px rgba(0, 255, 127, .25); }
.flowstudio .fs-gen-center > .fs-gen-generate .cost-pill { background: rgba(0, 255, 127, .14); }
/* (pointer-events for the centre buttons follow the visibility rules above.) */
.flowstudio .fs-gen-foot { right: 0; bottom: 0; left: 0; padding: 6px; background: linear-gradient(transparent, rgba(8, 6, 4, .9)); pointer-events: auto; }
.flowstudio .fs-gen-chipwrap { position: relative; display: inline-block; pointer-events: auto; }
.flowstudio .fs-gen-chipwrap.is-hidden { display: none; }
.flowstudio .fs-gen-chip { display: inline-flex; align-items: center; gap: 5px; padding: 4px 9px; color: rgba(232, 230, 222, .6); background: rgba(10, 8, 5, .72); border: 1px solid rgba(255, 255, 255, .14); border-radius: 6px; cursor: pointer; font: 500 10px 'DM Mono', monospace; letter-spacing: .02em; transition: color .12s, border-color .12s, background .12s, box-shadow .12s; }
.flowstudio .fs-gen-chip i { color: rgba(232, 230, 222, .32); font-size: 8px; font-style: normal; }
.flowstudio .fs-gen-chip:hover { color: rgba(232, 230, 222, .9); border-color: rgba(255, 255, 255, .32); }
.flowstudio .fs-gen-chip.set { color: #00FF7F; background: rgba(0, 255, 127, .1); border-color: rgba(0, 255, 127, .35); }
.flowstudio .fs-gen-chip.set i { color: rgba(0, 255, 127, .5); }
.flowstudio .fs-gen-chip.open { border-color: #00FF7F; box-shadow: 0 0 8px rgba(0, 255, 127, .25); }
/* Owner 2026-08-29: FRAME is one chip among its row — same padding, type and
   size as .fs-gen-chip, not a bigger button. */
.flowstudio .fs-frame-toggle { display: inline-flex; align-items: center; gap: 5px; padding: 4px 9px; color: #cfd3d6; background: rgba(6, 8, 9, .62); border: 1px solid rgba(255, 255, 255, .16); border-radius: 6px; cursor: pointer; pointer-events: auto; font: 500 10px 'DM Mono', monospace; letter-spacing: .02em; text-transform: uppercase; transition: color .15s, border-color .15s, background .15s; }
/* The board's VIEW (owner 2026-08-26): a footer cell in the standard node
   footer, bottom-right — same dress as .fs-sb-view / .fs-ref-view. */
.flowstudio .fs-generator-node .fs-node-foot { padding-right: 0; }
.flowstudio .fs-full-button { min-height: 30px; padding: 7px 14px; display: inline-flex; align-items: center; justify-content: center; color: rgba(240, 241, 243, .85); background: rgba(8, 10, 12, .72); border: 1px solid rgba(255, 255, 255, .25); border-radius: 999px; cursor: pointer; pointer-events: auto; font: 700 10px 'DM Mono', monospace; letter-spacing: .04em; text-transform: uppercase; transition: color .15s, border-color .15s, background .15s; }
.flowstudio .fs-full-button:hover { color: var(--fs-green); border-color: rgba(0, 255, 127, .55); }
.flowstudio .fs-full-button[hidden] { display: none; }
.flowstudio .fs-frame-toggle.on { color: #00FF7F; border-color: rgba(0, 255, 127, .5); }
.flowstudio .fs-gen-generate {
  min-height: 30px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-left: 0;
  padding: 7px 18px;
  color: #06180f;
  background: linear-gradient(105deg, #00FF7F, #5cf2b1);
  border: 1px solid #00FF7F;
  border-radius: 999px;
  box-shadow: 0 1px 0 rgba(255, 255, 255, .3) inset, 0 0 12px rgba(0, 255, 127, .24);
  cursor: pointer;
  pointer-events: auto;
  font: 700 9px Outfit, sans-serif;
  letter-spacing: .08em;
  text-transform: uppercase;
  transition: filter .15s ease, box-shadow .15s ease, transform .12s ease;
}
.flowstudio .fs-gen-generate:hover { filter: brightness(1.08); box-shadow: 0 1px 0 rgba(255, 255, 255, .38) inset, 0 0 18px rgba(0, 255, 127, .42); transform: translateY(-1px); }
.flowstudio .fs-gen-dropdown { position: absolute; left: 0; z-index: 60; min-width: 150px; max-height: 240px; display: flex; flex-direction: column; overflow-y: auto; padding: 5px; background: rgba(12, 10, 8, .98); border: 1px solid rgba(255, 255, 255, .18); border-radius: 9px; box-shadow: 0 16px 40px rgba(0, 0, 0, .7); }
.flowstudio .fs-gen-dropdown[hidden] { display: none; }
.flowstudio .fs-gen-dropdown.down { top: calc(100% + 5px); }.flowstudio .fs-gen-dropdown.up { bottom: calc(100% + 5px); }
.flowstudio .fs-gen-dropdown-title { padding: 4px 8px 5px; color: rgba(232, 230, 222, .4); font: 600 8px 'DM Mono', monospace; letter-spacing: .14em; }
.flowstudio .fs-gen-option.is-unsupported { opacity: .35; cursor: not-allowed; }
/* Two-level menus (STYLE / MOOD / COLOR — UI A's categorized grids). Level 1
   is a category head that expands in place; level 2 its options, indented.
   Grouped menus hold up to 47 options, so they get more vertical room than
   the flat 240px default. */
.flowstudio .fs-gen-dropdown.has-groups { max-height: 320px; min-width: 190px; }
.flowstudio .fs-gen-group-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; width: 100%; padding: 6px 9px; color: rgba(232, 230, 222, .55); background: none; border: 0; border-radius: 6px; white-space: nowrap; text-align: left; cursor: pointer; font: 600 10px 'DM Mono', monospace; letter-spacing: .08em; text-transform: uppercase; }
.flowstudio .fs-gen-group-head:hover { color: rgba(232, 230, 222, .85); background: rgba(255, 255, 255, .05); }
.flowstudio .fs-gen-group-head i { font-style: normal; font-size: 9px; opacity: .6; transition: transform .12s ease; }
.flowstudio .fs-gen-group-head.open i { transform: rotate(90deg); }
.flowstudio .fs-gen-group-head.open { color: #e8e6de; }
.flowstudio .fs-gen-group-body[hidden] { display: none; }
.flowstudio .fs-gen-option.in-group { padding-left: 20px; }
/* The category that HOLDS the current pick stays marked even collapsed, so a
   closed menu still says where the selection lives. */
.flowstudio .fs-gen-group-head.has-current span { color: #00FF7F; }
/* Dot rides the SPAN, not the flex row: a third flex item under
   space-between parks itself at the edge and shoves the caret mid-row. */
.flowstudio .fs-gen-group-head.has-current span::after { content: '●'; color: #00FF7F; font-size: 7px; margin-left: 5px; vertical-align: 1px; }
/* UI A tile art as row markers (icons / gradient swatches / glyphs). The
   label flexes so the .on ● keeps sitting at the row's right edge. */
.flowstudio .fs-opt-label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; text-align: left; }
.flowstudio .fs-opt-ic { width: 20px; height: 20px; flex: 0 0 auto; object-fit: cover; border-radius: 4px; background: rgba(255, 255, 255, .06); }
.flowstudio .fs-opt-swatch { width: 20px; height: 14px; flex: 0 0 auto; border-radius: 3px; border: 1px solid rgba(255, 255, 255, .14); font-style: normal; }
.flowstudio .fs-opt-glyph { width: 20px; flex: 0 0 auto; text-align: center; font-style: normal; font-size: 13px; line-height: 1; }
.flowstudio .fs-opt-svgic { width: 19px; height: 19px; flex: 0 0 auto; display: inline-flex; font-style: normal; opacity: .85; }
.flowstudio .fs-opt-svgic svg { width: 100%; height: 100%; }
/* Credit pill on the generate buttons. The base .cost-pill styling is
   UI A's (director.css, same document); these two rules only fit it to
   Flow Studio's buttons — the node face's is dark-on-green, the
   inspector's sits on the accent fill. */
.flowstudio .fs-gen-generate, .flowstudio .fs-prompt-generate { display: inline-flex; align-items: center; justify-content: center; gap: 6px; }
.flowstudio .fs-gen-generate .cost-pill, .flowstudio .fs-prompt-generate .cost-pill { margin-left: 0; background: rgba(0, 0, 0, .22); }
.flowstudio .fs-gen-option { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 6px 9px; color: rgba(232, 230, 222, .78); background: none; border: 0; border-radius: 6px; white-space: nowrap; text-align: left; cursor: pointer; font: 500 10px 'DM Mono', monospace; }
.flowstudio .fs-gen-option:hover { color: #fff; background: rgba(255, 255, 255, .07); }
.flowstudio .fs-gen-option.on { color: var(--node-accent, #00FF7F); }.flowstudio .fs-gen-option.on::after { content: '●'; font-size: 8px; }
.flowstudio .fs-generator-node > .fs-add-reference.fs-port {
  /* The disc doubles as the input port (drop-target resolution looks for
     .fs-port). Re-assert the disc's own geometry so the generic 12px port
     rules do not shrink or recolour it. */
  top: 50%; left: -16px; width: 30px; height: 30px;
  background: none; border: 0; border-radius: 0; box-shadow: none;
  transform: translateY(-50%); cursor: pointer;
}
.flowstudio .fs-add-reference { position: absolute; z-index: 9; top: 50%; left: -16px; width: 30px; height: 30px; padding: 0; overflow: visible; color: #0a0805; background: none; border: 0; cursor: pointer; transform: translateY(-50%); }
.flowstudio .fs-add-reference .disc { position: absolute; inset: 0; background: #00FF7F; border: 2px solid #0a0805; border-radius: 50%; box-shadow: 0 4px 12px rgba(0, 0, 0, .5); transition: transform .12s ease; }
.flowstudio .fs-add-reference:hover .disc { transform: scale(1.18); }
.flowstudio .fs-add-reference .plus { position: relative; z-index: 1; width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; font: 700 16px/1 'DM Mono', monospace; }
.flowstudio .fs-add-reference .label { position: absolute; top: 50%; right: calc(100% + 8px); padding: 3px 8px; color: rgba(232, 230, 222, .78); background: rgba(10, 8, 5, .85); border: 1px solid rgba(255, 255, 255, .14); border-radius: 6px; transform: translateY(-50%); white-space: nowrap; pointer-events: none; font: 600 9px 'DM Mono', monospace; letter-spacing: .08em; }
.flowstudio .fs-resize-edge { position: absolute; z-index: 7; display: block; pointer-events: auto; }
.flowstudio .fs-resize-edge.l { top: -36px; bottom: -40px; left: -4px; width: 9px; cursor: ew-resize; }.flowstudio .fs-resize-edge.r { top: -36px; right: -4px; bottom: -40px; width: 9px; cursor: ew-resize; }
.flowstudio .fs-resize-edge.t { top: -41px; right: 0; left: 0; height: 10px; cursor: ns-resize; }.flowstudio .fs-resize-edge.b { right: 0; bottom: -45px; left: 0; height: 10px; cursor: ns-resize; }
.flowstudio .fs-resize-edge.corner { width: 20px; height: 20px; }.flowstudio .fs-resize-edge.corner.tl { top: -45px; left: -7px; cursor: nwse-resize; }.flowstudio .fs-resize-edge.corner.tr { top: -45px; right: -7px; cursor: nesw-resize; }
.flowstudio .fs-resize-edge.corner.bl { bottom: -49px; left: -7px; cursor: nesw-resize; }.flowstudio .fs-resize-edge.corner.br { right: -7px; bottom: -49px; cursor: nwse-resize; }
/* Standard-node resize. The offsets above are tuned to the generator's inset
   body; on a plain node the edges hang off the node box itself, so they need
   their own geometry rather than inheriting negative insets meant for another
   parent. */
/* Eight handles on the node ROOT (the Generator's live inside its body, hence
   its negative offsets above). Edges sit astride the border; corners take the
   last 18px so the edge handles never claim them. The ports (z 8) stay above. */
.flowstudio .fs-resizable-node > .fs-resize-edge.l { top: 8px; bottom: 8px; left: -5px; width: 10px; cursor: ew-resize; }
.flowstudio .fs-resizable-node > .fs-resize-edge.r { top: 8px; right: -5px; bottom: 8px; width: 10px; cursor: ew-resize; }
.flowstudio .fs-resizable-node > .fs-resize-edge.t { top: -5px; right: 8px; left: 8px; height: 10px; bottom: auto; cursor: ns-resize; }
.flowstudio .fs-resizable-node > .fs-resize-edge.b { right: 8px; bottom: -5px; left: 8px; height: 10px; top: auto; cursor: ns-resize; }
.flowstudio .fs-resizable-node > .fs-resize-edge.corner { width: 18px; height: 18px; }
.flowstudio .fs-resizable-node > .fs-resize-edge.corner.tl { top: -6px; left: -6px; right: auto; bottom: auto; cursor: nwse-resize; }
.flowstudio .fs-resizable-node > .fs-resize-edge.corner.tr { top: -6px; right: -6px; left: auto; bottom: auto; cursor: nesw-resize; }
.flowstudio .fs-resizable-node > .fs-resize-edge.corner.bl { bottom: -6px; left: -6px; top: auto; right: auto; cursor: nesw-resize; }
.flowstudio .fs-resizable-node > .fs-resize-edge.corner.br { right: -6px; bottom: -6px; top: auto; left: auto; cursor: nwse-resize; }
/* No grip badge on the corner (owner 2026-08-27): the sheet nodes resize on
   invisible edges exactly like the all-in-one board — the cursor is the only
   affordance. */

.flowstudio .fs-fold-right { background: #25272c; }
.flowstudio .fs-fold-right:hover { color: #00FF7F; border-color: rgba(0, 212, 170, .22); }
.flowstudio .fs-inspector {
  position: relative;
  height: 100%;
  min-height: 0;
  display: none;
  flex-direction: column;
  background: linear-gradient(rgb(29, 30, 33) 0%, rgb(23, 24, 27) 100%);
  border-left: 1px solid rgba(255, 255, 255, .04);
  box-shadow: rgba(0, 0, 0, .3) 1px 0 0 inset;
}
.flowstudio.right-open .fs-inspector { display: flex; }
.flowstudio .fs-inspector::before { content: ''; position: absolute; z-index: 1; top: 0; bottom: 0; left: 0; width: 1px; pointer-events: none; background: linear-gradient(transparent, rgba(0, 255, 127, .1) 30%, rgba(0, 255, 127, .1) 70%, transparent); }
.flowstudio .fs-inspector-head { flex: 0 0 auto; padding: 14px 18px 10px; background: linear-gradient(rgba(255, 255, 255, .02), transparent), linear-gradient(rgb(30, 32, 36), rgb(23, 24, 27)); border-bottom: 1px solid rgba(255, 255, 255, .05); }
.flowstudio .fs-inspector-row1 { display: flex; align-items: center; gap: 10px; }
.flowstudio .fs-inspector-swatch { width: 8px; height: 24px; flex: 0 0 auto; border-radius: 3px; background: linear-gradient(180deg, rgba(255, 255, 255, .3) 0%, transparent 35%), var(--accent, #00FF7F); box-shadow: 0 1px 0 rgba(255, 255, 255, .18) inset, 0 -1px 0 rgba(0, 0, 0, .3) inset, 0 0 14px rgba(var(--accent-rgb, 0, 255, 127), .5); }
.flowstudio .fs-inspector-titles { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; }
.flowstudio .fs-inspector-titles b { overflow: hidden; color: #FFFFFF; font: 700 13px 'Outfit', sans-serif; letter-spacing: -.01em; text-overflow: ellipsis; white-space: nowrap; }
.flowstudio .fs-inspector-titles small { margin-top: 1px; color: #7c7c7c; font: 500 10px 'FlowStudio Pretendard', sans-serif; letter-spacing: .06em; text-transform: uppercase; }
.flowstudio .fs-inspector-actions { flex: 0 0 auto; display: flex; align-items: center; }
.flowstudio .fs-inspector-toggle { width: 40px; height: 22px; padding: 0; background: transparent; border: 0; cursor: pointer; }
.flowstudio .fs-inspector-toggle .track { position: relative; width: 40px; height: 22px; display: block; border-radius: 11px; transition: background .2s, box-shadow .2s; }
.flowstudio .fs-inspector-toggle.on .track { background: var(--insp-accent, rgb(0, 255, 127)); box-shadow: rgba(var(--insp-accent-rgb, 0, 255, 127), .4) 0 0 10px, rgba(255, 255, 255, .1) 0 1px 0 inset; }
.flowstudio .fs-inspector-toggle.off .track { background: rgba(255, 255, 255, .16); box-shadow: rgba(0, 0, 0, .4) 0 1px 2px inset; }
.flowstudio .fs-inspector-toggle .knob { position: absolute; top: 2px; left: 20px; width: 18px; height: 18px; border-radius: 50%; background: #fff; box-shadow: rgba(0, 0, 0, .45) 0 1px 3px; transition: left .2s cubic-bezier(.4, 0, .2, 1); }
.flowstudio .fs-inspector-toggle.off .knob { left: 2px; }
.flowstudio .fs-inspector-row2 { margin-top: 9px; display: flex; gap: 18px; }
.flowstudio .fs-inspector-row2 .item { min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.flowstudio .fs-inspector-row2 .key { color: #7c7c7c; font: 700 10px 'FlowStudio Pretendard', sans-serif; letter-spacing: .14em; text-transform: uppercase; }
.flowstudio .fs-inspector-row2 .value { overflow: hidden; color: #FFFFFF; font: 600 11px 'FlowStudio Pretendard', sans-serif; font-variant-numeric: tabular-nums; text-overflow: ellipsis; white-space: nowrap; }
.flowstudio .fs-inspector-row2 .value.ok { color: #00FF7F; }
.flowstudio .fs-inspector-tabs { flex: 0 0 auto; display: flex; padding: 0 14px; border-bottom: 1px solid rgba(255, 255, 255, .05); }
.flowstudio .fs-inspector-tabs button { position: relative; padding: 11px 12px 10px; color: #a6a8ac; background: transparent; border: 0; cursor: pointer; font: 500 11px 'FlowStudio Pretendard', sans-serif; transition: color .16s; }
.flowstudio .fs-inspector-tabs button:hover { color: #FFFFFF; }
.flowstudio .fs-inspector-tabs button.on { color: var(--insp-accent, rgb(0, 255, 127)); }
.flowstudio .fs-inspector-tabs button.on::after { content: ''; position: absolute; right: 8px; bottom: -1px; left: 8px; height: 2px; border-radius: 1px; background: linear-gradient(90deg, transparent, var(--insp-accent, rgb(0, 255, 127)), transparent); box-shadow: rgba(var(--insp-accent-rgb, 0, 255, 127), .55) 0 0 12px; animation: fs-tab-shimmer 2.4s ease-in-out infinite; }
.flowstudio .fs-inspector-body { flex: 1 1 0; min-height: 0; overflow-y: auto; padding: 16px 18px 24px; scrollbar-width: none; }
.flowstudio .fs-inspector-body::-webkit-scrollbar { width: 0; display: none; }
.flowstudio .fs-inspector-empty { padding: 28px 16px; color: rgba(232, 230, 222, .4); text-align: center; font: 500 13px 'DM Mono', monospace; letter-spacing: .08em; }
.flowstudio .fs-inspector-body > section:not(.fs-form-section) { padding: 0; }
.flowstudio .fs-inspector-body > section:not(.fs-form-section) > header { margin-bottom: 11px; color: #7c7c7c; font: 700 10px 'FlowStudio Pretendard', sans-serif; letter-spacing: .14em; text-transform: uppercase; }
.flowstudio .fs-reference-summary { display: grid; gap: 7px; padding: 10px; background: rgba(12, 184, 224, .04); border: 1px solid rgba(12, 184, 224, .14); border-radius: 7px; }
.flowstudio .fs-reference-summary b { color: var(--insp-accent, #0cb8e0); font: 650 11px 'Outfit', sans-serif; }
.flowstudio .fs-reference-summary span { color: var(--fs-text-60); font: 500 10px/1.45 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-reference-summary small { color: var(--fs-text-32); font: 500 8px 'DM Mono', monospace; }
/* ---- result provenance (completed result inspector) ---- */
.flowstudio .fs-prov-model { display: grid; gap: 3px; margin: 0 0 14px; }
.flowstudio .fs-prov-model b { color: #FFFFFF; font: 650 13px 'Outfit', sans-serif; letter-spacing: .01em; }
.flowstudio .fs-prov-model small { color: var(--fs-text-32); font: 500 8px 'DM Mono', monospace; letter-spacing: .08em; text-transform: uppercase; }
.flowstudio .fs-prov-prompt { margin: 0; padding: 8px 10px; color: #d6d8db; background: linear-gradient(rgb(22, 23, 25), rgb(26, 27, 30)); border: 1px solid rgba(255, 255, 255, .08); border-radius: 6px; user-select: text; cursor: text; white-space: pre-wrap; overflow-wrap: anywhere; font: 500 11px/1.55 'FlowStudio Pretendard', sans-serif; }
/* editable provenance prompt: auto-sizing textarea (~4-12 rows, JS-managed height) */
.flowstudio .fs-prov-prompt-input { display: block; width: 100%; min-height: 68px; max-height: 208px; overflow-y: auto; resize: none; outline: none; }
.flowstudio .fs-prov-prompt-input:focus { border-color: rgba(var(--insp-accent-rgb, 0, 255, 127), .45); }
.flowstudio .fs-prov-prompt-input::placeholder { color: var(--fs-text-32); font-style: italic; }
.flowstudio .fs-prov-edit-meta { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; margin-top: 5px; color: var(--fs-text-32); font: 500 8px/1.5 'FlowStudio Pretendard', sans-serif; letter-spacing: .04em; }
/* display:flex (0,2,0) beats the UA [hidden] rule (0,1,0) — reassert it, or the pristine-state hint/reset stay painted */
.flowstudio .fs-prov-edit-meta[hidden] { display: none; }
.flowstudio .fs-prov-reset { flex: 0 0 auto; padding: 0; color: var(--insp-accent, rgb(0, 255, 127)); background: none; border: 0; cursor: pointer; font: 600 8px 'FlowStudio Pretendard', sans-serif; letter-spacing: .06em; }
.flowstudio .fs-prov-reset:hover { text-decoration: underline; }
.flowstudio .fs-prov-actions { display: flex; justify-content: flex-end; gap: 6px; margin-top: 8px; }
.flowstudio .fs-prov-actions button { padding: 6px 9px; color: #fff; background: rgba(255, 255, 255, .05); border: 1px solid rgba(255, 255, 255, .22); border-radius: 5px; cursor: pointer; font: 600 8px 'DM Mono', monospace; letter-spacing: .04em; }
.flowstudio .fs-prov-actions button:hover:not(:disabled) { border-color: var(--fs-green); color: var(--fs-green); }
.flowstudio .fs-prov-actions button:disabled, .flowstudio .fs-prov-actions.is-action-busy button { pointer-events: none; opacity: .35; }
.flowstudio .fs-prov-expand { margin-top: 6px; padding: 0; color: var(--insp-accent, rgb(0, 255, 127)); background: none; border: 0; cursor: pointer; font: 600 9px 'FlowStudio Pretendard', sans-serif; letter-spacing: .06em; }
.flowstudio .fs-prov-expand:hover { text-decoration: underline; }
.flowstudio .fs-prov-grid { display: grid; grid-template-columns: minmax(64px, auto) 1fr; gap: 7px 12px; align-items: baseline; }
.flowstudio .fs-prov-grid code { color: #7c7c7c; font: 700 8px 'DM Mono', monospace; letter-spacing: .1em; text-transform: uppercase; }
.flowstudio .fs-prov-grid span { color: #d6d8db; text-align: right; user-select: text; overflow-wrap: anywhere; font: 600 10px 'FlowStudio Pretendard', sans-serif; font-variant-numeric: tabular-nums; }
.flowstudio .fs-prov-loading { padding: 6px 0; color: var(--fs-text-32); font: 500 10px 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-form-section { margin: 0 0 16px; padding: 0; border: 0; }
/* Enhance-prompt button (owner 2026-09-05): a full-width accent action above Output Format. */
.flowstudio .fs-insp-enhance { margin: 0 0 16px; }
.flowstudio .fs-insp-enhance-btn { width: 100%; display: inline-flex; align-items: center; justify-content: center; gap: 6px; height: 34px; padding: 0 12px; background: linear-gradient(rgba(255, 255, 255, .04) 0%, transparent 50%), linear-gradient(rgba(0, 255, 127, .12) 0%, rgba(0, 255, 127, .05) 100%); border: 1px solid rgba(0, 255, 127, .34); border-radius: 9px; color: rgb(0, 255, 127); font: 700 11px 'FlowStudio Pretendard', sans-serif; letter-spacing: .04em; cursor: pointer; transition: .16s; }
.flowstudio .fs-insp-enhance-btn:hover:not(:disabled) { border-color: rgb(0, 255, 127); box-shadow: rgba(0, 255, 127, .22) 0 0 14px; }
.flowstudio .fs-insp-enhance-btn:disabled { opacity: .6; cursor: default; }
.flowstudio .fs-insp-enhance-btn.busy { color: rgba(0, 255, 127, .8); }
.flowstudio .fs-insp-enhance-btn:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.flowstudio .fs-section-head { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; color: #7c7c7c; font: 700 10px 'FlowStudio Pretendard', sans-serif; letter-spacing: .14em; text-transform: uppercase; }
.flowstudio .fs-section-head b { font: inherit; }
.flowstudio .fs-section-head .line { flex: 1 1 0; height: 1px; background: linear-gradient(90deg, rgba(255, 255, 255, .08), transparent); }
.flowstudio .fs-section-head .fs-prompt-count { color: #7c7c7c; font: 500 10px 'FlowStudio Pretendard', sans-serif; letter-spacing: .06em; text-transform: none; }
/* General-mode advisory: past the selected model's raw-submit cap. Amber, not
   red — nothing is blocked; the server trims at the cap on submit. */
.flowstudio .fs-section-head .fs-prompt-count.fs-count-over { color: #e8b341; }
.flowstudio .fs-section-head .fs-prompt-clear { flex: none; padding: 2px 8px; color: #a8a8a8; background: transparent; border: 1px solid rgba(255, 255, 255, .14); border-radius: 4px; cursor: pointer; font: 600 10px 'FlowStudio Pretendard', sans-serif; letter-spacing: .06em; text-transform: none; transition: color .15s, border-color .15s; }
.flowstudio .fs-section-head .fs-prompt-clear:hover:not(:disabled) { color: var(--fs-green); border-color: rgba(0, 255, 127, .35); }
.flowstudio .fs-section-head .fs-prompt-clear:disabled { opacity: .35; cursor: default; }
@media (pointer: coarse) { .flowstudio .fs-section-head .fs-prompt-clear { min-height: 28px; padding: 4px 12px; } }
.flowstudio .fs-prompt-trim-note { margin: 6px 0 0; color: #e8b341; font: 500 10px/1.5 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-prompt-input, .flowstudio .fs-enh-output, .flowstudio .fs-anz-desc { box-sizing: border-box; width: 100%; padding: 8px 10px; color: #FFFFFF; background: linear-gradient(rgb(22, 23, 25), rgb(26, 27, 30)); border: 1px solid rgba(255, 255, 255, .08); border-radius: 6px; outline: 0; box-shadow: rgba(255, 255, 255, .02) 0 1px 0 inset, rgba(0, 0, 0, .25) 0 2px 4px inset; font: 500 12px/1.5 'FlowStudio Pretendard', sans-serif; transition: border-color .16s, box-shadow .16s; }
.flowstudio .fs-prompt-input:hover, .flowstudio .fs-enh-output:hover, .flowstudio .fs-anz-desc:hover { border-color: rgba(255, 255, 255, .16); }
.flowstudio .fs-prompt-input:focus, .flowstudio .fs-enh-output:focus, .flowstudio .fs-anz-desc:focus { outline: none; border-color: var(--insp-accent, rgb(0, 255, 127)); box-shadow: rgba(0, 0, 0, .25) 0 2px 4px inset, rgba(var(--insp-accent-rgb, 0, 255, 127), .22) 0 0 0 3px; }
/* Prompt Enhancer inspector */
.flowstudio .fs-enh-source { margin: 0 0 8px; color: #9aa0a6; font: 500 10px/1.4 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-enh-source .fs-enh-src-text { color: #cfd2d6; }
.flowstudio .fs-enh-controls { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.flowstudio .fs-enh-len { display: inline-flex; align-items: center; gap: 6px; color: #7c7c7c; font: 700 8px 'FlowStudio Pretendard', sans-serif; letter-spacing: .12em; text-transform: uppercase; }
.flowstudio .fs-enh-len-sel { color: #FFFFFF; background: rgb(24, 25, 28); border: 1px solid rgba(255, 255, 255, .12); border-radius: 5px; padding: 4px 6px; font: 600 11px 'FlowStudio Pretendard', sans-serif; cursor: pointer; }
.flowstudio .fs-enh-run { margin-left: auto; min-height: 30px; padding: 6px 14px; color: #e0555f; background: rgba(224, 85, 95, .09); border: 1px solid rgba(224, 85, 95, .4); border-radius: 6px; cursor: pointer; font: 700 11px 'FlowStudio Pretendard', sans-serif; letter-spacing: .03em; transition: background .14s, border-color .14s, box-shadow .14s; }
.flowstudio .fs-enh-run:hover { background: rgba(224, 85, 95, .17); border-color: rgba(224, 85, 95, .66); box-shadow: 0 0 14px rgba(224, 85, 95, .16); }
.flowstudio .fs-enh-run:disabled, .flowstudio .fs-enh-mix:disabled { opacity: .5; cursor: default; box-shadow: none; }
.flowstudio .fs-enh-mix { min-height: 30px; padding: 6px 12px; color: #37c8ff; background: rgba(55, 200, 255, .08); border: 1px solid rgba(55, 200, 255, .38); border-radius: 6px; cursor: pointer; font: 700 11px 'FlowStudio Pretendard', sans-serif; transition: background .14s, border-color .14s; }
.flowstudio .fs-enh-mix:hover { background: rgba(55, 200, 255, .16); border-color: rgba(55, 200, 255, .62); }
.flowstudio .fs-enh-mix[hidden] { display: none; }
.flowstudio .fs-enh-status { margin: 8px 0 0; min-height: 14px; color: #9aa0a6; font: 500 10px/1.4 'FlowStudio Pretendard', sans-serif; }
/* Prompt · Graphical inspector */
.flowstudio .fs-gfx-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.flowstudio .fs-gfx-field { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.flowstudio .fs-gfx-field > span { color: #7c7c7c; font: 700 8px 'FlowStudio Pretendard', sans-serif; letter-spacing: .1em; text-transform: uppercase; }
.flowstudio .fs-gfx-field select { width: 100%; color: #FFFFFF; background: rgb(24, 25, 28); border: 1px solid rgba(255, 255, 255, .12); border-radius: 5px; padding: 5px 6px; font: 600 11px 'FlowStudio Pretendard', sans-serif; cursor: pointer; }
.flowstudio .fs-gfx-composed { margin: 0; color: #cfd2d6; font: 500 11px/1.5 'FlowStudio Pretendard', sans-serif; overflow-wrap: anywhere; }
/* Image Analyzer inspector — the Prompt Enhancer inspector's twin (owner
   2026-09-10): same source line, same output textarea (.fs-anz-desc rides the
   .fs-enh-output rules above), same controls row, and the run button in the
   Enhancer's palette. The matched-menu cells are the Enhancer's select skin. */
.flowstudio .fs-anz-source { margin: 0 0 8px; color: #9aa0a6; font: 500 10px/1.4 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-anz-source .fs-anz-src-text { color: #cfd2d6; }
.flowstudio .fs-section-head .fs-anz-count { color: #7c7c7c; font: 500 10px 'FlowStudio Pretendard', sans-serif; letter-spacing: .06em; text-transform: none; }
.flowstudio .fs-anz-controls { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.flowstudio .fs-anz-run { margin-left: auto; min-height: 30px; padding: 6px 14px; color: #e0555f; background: rgba(224, 85, 95, .09); border: 1px solid rgba(224, 85, 95, .4); border-radius: 6px; cursor: pointer; font: 700 11px 'FlowStudio Pretendard', sans-serif; letter-spacing: .03em; transition: background .14s, border-color .14s, box-shadow .14s; }
.flowstudio .fs-anz-run:hover { background: rgba(224, 85, 95, .17); border-color: rgba(224, 85, 95, .66); box-shadow: 0 0 14px rgba(224, 85, 95, .16); }
.flowstudio .fs-anz-run:disabled { opacity: .5; cursor: default; box-shadow: none; }
.flowstudio .fs-anz-status { margin: 8px 0 0; min-height: 14px; color: #9aa0a6; font: 500 10px/1.4 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-anz-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.flowstudio .fs-anz-field { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.flowstudio .fs-anz-field > span { color: #7c7c7c; font: 700 8px 'FlowStudio Pretendard', sans-serif; letter-spacing: .12em; text-transform: uppercase; }
.flowstudio .fs-anz-field > b { color: #7c7c7c; background: rgb(24, 25, 28); border: 1px solid rgba(255, 255, 255, .12); border-radius: 5px; padding: 5px 6px; font: 600 11px 'FlowStudio Pretendard', sans-serif; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.flowstudio .fs-anz-field > b.has { color: #FFFFFF; border-color: rgba(224, 85, 95, .4); }
/* Image-EDIT inspector (upscale / inpaint / outpaint) — REFINE amber accent. */
.flowstudio .fs-edit-source { margin: 0 0 10px; color: #9aa0a6; font: 500 10px/1.4 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-edit-field { display: flex; flex-direction: column; gap: 4px; margin-bottom: 10px; }
.flowstudio .fs-edit-field > span { color: var(--insp-accent, #7c7c7c); font: 700 8px 'FlowStudio Pretendard', sans-serif; letter-spacing: .1em; text-transform: uppercase; }
.flowstudio .fs-edit-field select { width: 100%; color: #FFFFFF; background: rgb(24, 25, 28); border: 1px solid rgba(255, 255, 255, .12); border-radius: 5px; padding: 6px; font: 600 11px 'FlowStudio Pretendard', sans-serif; cursor: pointer; }
.flowstudio .fs-edit-field textarea { min-height: 64px; resize: vertical; }
.flowstudio .fs-edit-nums { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-bottom: 10px; }
.flowstudio .fs-edit-num { display: flex; align-items: center; gap: 6px; min-width: 0; }
.flowstudio .fs-edit-num > span { flex: 0 0 auto; min-width: 44px; color: var(--insp-accent, #7c7c7c); font: 700 8px 'FlowStudio Pretendard', sans-serif; letter-spacing: .08em; }
.flowstudio .fs-edit-num input { width: 100%; min-width: 0; color: #FFFFFF; background: rgb(24, 25, 28); border: 1px solid rgba(255, 255, 255, .12); border-radius: 5px; padding: 5px 6px; font: 600 11px 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-edit-num input:focus { outline: none; border-color: var(--insp-accent, rgb(246, 183, 67)); }
/* The OS-drawn number spinners never matched the UI - hidden everywhere in
   the studio; fields that want steppers render their own themed pair. */
.flowstudio input[type='number']::-webkit-outer-spin-button,
.flowstudio input[type='number']::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.flowstudio input[type='number'] { appearance: textfield; -moz-appearance: textfield; }
.flowstudio .fs-edit-numwrap { position: relative; display: flex; flex: 1 1 auto; min-width: 0; }
.flowstudio .fs-edit-numwrap input { padding-right: 24px; }
.flowstudio .fs-edit-steps { position: absolute; right: 3px; top: 50%; transform: translateY(-50%); display: grid; gap: 2px; }
.flowstudio .fs-edit-steps button { width: 16px; height: 10px; display: grid; place-items: center; padding: 0; color: #7c7c7c; background: rgba(255, 255, 255, .05); border: 1px solid rgba(255, 255, 255, .1); border-radius: 3px; cursor: pointer; font: 600 7px/1 'DM Mono', monospace; transition: color .12s, border-color .12s; }
.flowstudio .fs-edit-steps button:hover { color: var(--insp-accent, rgb(246, 183, 67)); border-color: rgba(var(--insp-accent-rgb, 246, 183, 67), .5); }
.flowstudio .fs-edit-steps button:disabled { opacity: .4; cursor: default; }
.flowstudio .fs-edit-num > i { flex: 0 0 auto; color: #7c7c7c; font: 600 10px 'FlowStudio Pretendard', sans-serif; font-style: normal; }
/* The region preview makes the percent numbers concrete: the box is drawn over
   the very image the server will composite the marker onto. */
/* The frame stands for the OUTPUT canvas; its aspect-ratio is set per-op in JS.
   The diagonal wash is the area that will be GENERATED — for outpaint that is
   the margin around the inset source, so "what is mine / what is new" is
   readable at a glance. */
.flowstudio .fs-edit-preview { position: relative; width: 100%; aspect-ratio: 16 / 9; margin-bottom: 10px; background: repeating-linear-gradient(45deg, rgba(var(--insp-accent-rgb, 168, 85, 216), .10) 0 6px, rgba(var(--insp-accent-rgb, 168, 85, 216), .03) 6px 12px), rgb(18, 19, 21); border: 1px solid rgba(255, 255, 255, .1); border-radius: 6px; overflow: hidden; transition: aspect-ratio .16s ease; }
.flowstudio .fs-edit-preview img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: fill; display: block; box-shadow: 0 0 0 1px rgba(255, 255, 255, .18); }
.flowstudio .fs-edit-preview.is-empty img { display: none; }
.flowstudio .fs-edit-preview b { position: absolute; border: 2px solid var(--insp-accent, rgb(246, 183, 67)); background: rgba(var(--insp-accent-rgb, 246, 183, 67), .16); pointer-events: none; border-radius: 2px; }
.flowstudio .fs-edit-preview b[hidden] { display: none; }
.flowstudio .fs-edit-preview em { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; color: #b9bcc1; text-shadow: 0 1px 3px rgba(0, 0, 0, .9); font: 600 10px 'FlowStudio Pretendard', sans-serif; font-style: normal; pointer-events: none; }
.flowstudio .fs-edit-res { position: absolute; right: 6px; bottom: 5px; padding: 2px 6px; color: #FFFFFF; background: rgba(8, 10, 12, .74); border: 1px solid rgba(255, 255, 255, .12); border-radius: 4px; font: 600 9px 'DM Mono', monospace; pointer-events: none; z-index: 2; }
.flowstudio .fs-brush-cursor { position: absolute; transform: translate(-50%, -50%); border: 1.5px solid rgba(255, 0, 255, .9); background: rgba(255, 0, 255, .12); border-radius: 50%; pointer-events: none; z-index: 3; }
.flowstudio .fs-edit-runstack { display: flex; flex-direction: column; gap: 8px; }
.flowstudio .fs-edit-runrow { display: flex; gap: 8px; }
/* Owner 2026-09-12: the full-screen arrow sits in the run row, not over the
   picture — a rounded SQUARE the height of the row it shares, with the run
   button taking the rest of the width. Scoped to the row so it outranks
   the corner pinning in .fs-edit-zoom, which is declared later in this file. */
.flowstudio .fs-edit-runrow .fs-edit-zoom { position: static; flex: 0 0 auto; width: 32px; height: 32px; top: auto; right: auto; opacity: 1; background: rgba(var(--insp-accent-rgb, 246, 183, 67), .1); border-color: rgba(var(--insp-accent-rgb, 246, 183, 67), .42); }
/* In the row it is a button beside Inpaint, so it takes Inpaint's fill and its
   hover rather than the dark pill the overlay version wears over the picture
   (owner 2026-09-12). */
.flowstudio .fs-edit-runrow .fs-edit-zoom:hover { background: rgba(var(--insp-accent-rgb, 246, 183, 67), .18); border-color: rgba(var(--insp-accent-rgb, 246, 183, 67), .68); box-shadow: 0 0 14px rgba(var(--insp-accent-rgb, 246, 183, 67), .16); }
.flowstudio .fs-run-first .fs-edit-runrow .fs-edit-zoom { width: 40px; height: 40px; }
.flowstudio .fs-edit-runrow .fs-edit-run { flex: 1 1 auto; }
/* Erase shares the secondary-button look with Expand/Fix but MUST NOT carry
   the .fs-edit-expand class: the inspector reads the outpaint expand button as
   `.fs-edit-expand:not(.fs-edit-fix)`, which a class-sharing Erase would also
   match — double-binding Erase to the paid dispatch and painting a paid pill
   on a free op (adversarial review 2026-08-26). Its own class, same style. */
.flowstudio .fs-edit-expand, .flowstudio .fs-edit-erase { flex: 1 1 auto; min-height: 32px; padding: 7px 16px; display: inline-flex; align-items: center; justify-content: center; gap: 7px; color: var(--insp-accent, #f6b743); background: rgba(var(--insp-accent-rgb, 246, 183, 67), .16); border: 1px solid rgba(var(--insp-accent-rgb, 246, 183, 67), .55); border-radius: 6px; cursor: pointer; font: 700 11px 'FlowStudio Pretendard', sans-serif; letter-spacing: .03em; transition: background .14s, border-color .14s; }
.flowstudio .fs-edit-expand:hover:not(:disabled), .flowstudio .fs-edit-erase:hover:not(:disabled) { background: rgba(var(--insp-accent-rgb, 246, 183, 67), .26); border-color: var(--insp-accent, #f6b743); }
.flowstudio .fs-edit-expand:disabled, .flowstudio .fs-edit-erase:disabled { opacity: .45; cursor: default; }
.flowstudio .fs-edit-expand .cost-pill { margin-left: 0; background: rgba(0, 0, 0, .26); }
/* Inpaint: the mask is PAINTED onto the picture. touch-action:none is
   load-bearing — without it iOS Safari pans the inspector instead of firing
   pointermove, and the brush never draws on the device the owner tests on. */
.flowstudio .fs-edit-preview.is-drawable { cursor: crosshair; touch-action: none; -webkit-user-select: none; user-select: none; }
.flowstudio .fs-edit-preview.is-drawable img { -webkit-user-drag: none; pointer-events: none; }
/* The painted mask sits over the image and never eats the pointer — the frame
   owns the gesture so a stroke started on the canvas still reaches it. */
.flowstudio .fs-edit-mask { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
/* Segment overlay (Detect): unpicked shapes, tinted. Same contract as the
   mask canvas — the frame owns the pointer, the canvas never eats it. */
.flowstudio .fs-edit-seg { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.flowstudio .fs-edit-preview.is-drawable.is-picking { cursor: pointer; }
/* The mode highlight lives on the BRUSH/SELECT pair (owner 2026-09-01) —
   Detect went back to being an action button. */
.flowstudio .fs-edit-brush [data-mask-mode].is-on { background: rgba(var(--insp-accent-rgb, 246, 183, 67), .28); border-color: var(--insp-accent, #f6b743); box-shadow: 0 0 0 1px rgba(var(--insp-accent-rgb, 246, 183, 67), .25) inset; }
.flowstudio .fs-seg-num { min-width: 34px; text-align: right; color: var(--insp-accent, #f6b743); font: 700 9px 'FlowStudio Pretendard', sans-serif; font-variant-numeric: tabular-nums; }
.flowstudio .fs-seg-count { color: var(--insp-accent, #f6b743); font: 700 9px 'FlowStudio Pretendard', sans-serif; letter-spacing: .05em; white-space: nowrap; }
/* The way into full-screen Inpaint mode. It rides ON the picture because that
   is the thing being enlarged, and the frame's own pointerdown skips presses
   that land on a button — otherwise opening the editor would leave a dab of
   paint under the icon. z-index clears the mask canvas and the brush circle. */
.flowstudio .fs-edit-zoom { position: absolute; top: 6px; right: 6px; z-index: 4; width: 26px; height: 26px; display: grid; place-items: center; padding: 0; color: var(--insp-accent, #f6b743); background: rgba(8, 10, 12, .72); border: 1px solid rgba(var(--insp-accent-rgb, 246, 183, 67), .38); border-radius: 6px; cursor: pointer; opacity: .82; transition: opacity .14s, background .14s, border-color .14s; }
.flowstudio .fs-edit-zoom:hover { opacity: 1; background: rgba(var(--insp-accent-rgb, 246, 183, 67), .18); border-color: var(--insp-accent, #f6b743); }
.flowstudio .fs-edit-zoom[hidden] { display: none; }
.flowstudio .fs-edit-brush { display: flex; align-items: center; gap: 8px; margin: 8px 0 2px; flex-wrap: wrap; }
.flowstudio .fs-edit-brush label { display: flex; align-items: center; gap: 6px; flex: 1; min-width: 0; }
.flowstudio .fs-edit-brush label span { color: #8b8f96; font: 600 9px 'FlowStudio Pretendard', sans-serif; letter-spacing: .08em; }
/* Native ranges in the inspector wear the param-slider's dark dress — the
   browser default track rendered as a WHITE bar on the dark panel (owner
   report 2026-08-26). Same recipe as the gallery zoom slider. */
.flowstudio .fs-edit-brush input[type=range] { flex: 1; min-width: 0; height: 18px; margin: 0; padding: 0; -webkit-appearance: none; appearance: none; background: transparent; cursor: pointer; }
/* The filled track every other slider in the app has. Chrome has no
   ::-moz-range-progress, so the fill is a gradient stop parked at the value —
   the same recipe as the gallery zoom (owner 2026-09-12: "platform style,
   keeping the purple"). The hue is the node's, never a literal. */
.flowstudio .fs-edit-brush input[type=range]::-webkit-slider-runnable-track { height: 5px; border-radius: 3px; background: linear-gradient(90deg, var(--insp-accent, #f6b743) 0%, var(--insp-accent, #f6b743) var(--fs-range-pct, 0%), rgb(14, 15, 18) var(--fs-range-pct, 0%), rgb(22, 23, 26) 100%); box-shadow: rgba(0, 0, 0, .6) 0 1px 3px inset, rgba(255, 255, 255, .03) 0 1px 0; }
.flowstudio .fs-edit-brush input[type=range]::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 14px; height: 14px; margin-top: -4.5px; border: 0; border-radius: 50%; background: radial-gradient(circle at 30% 30%, #fff 0%, rgb(216, 216, 216) 60%, rgb(157, 157, 157) 100%); box-shadow: rgba(var(--insp-accent-rgb, 246, 183, 67), .35) 0 0 0 3px, rgba(0, 0, 0, .55) 0 2px 6px; }
.flowstudio .fs-edit-brush input[type=range]::-moz-range-track { height: 5px; border: 0; border-radius: 3px; background: linear-gradient(rgb(14, 15, 18), rgb(22, 23, 26)); box-shadow: rgba(0, 0, 0, .6) 0 1px 3px inset; }
.flowstudio .fs-edit-brush input[type=range]::-moz-range-progress { height: 5px; border-radius: 3px; background: var(--insp-accent, #f6b743); }
.flowstudio .fs-edit-brush input[type=range]::-moz-range-thumb { width: 14px; height: 14px; border: 0; border-radius: 50%; background: radial-gradient(circle at 30% 30%, #fff 0%, rgb(216, 216, 216) 60%, rgb(157, 157, 157) 100%); box-shadow: rgba(var(--insp-accent-rgb, 246, 183, 67), .35) 0 0 0 3px, rgba(0, 0, 0, .55) 0 2px 6px; }
.flowstudio .fs-edit-brush button { padding: 4px 9px; border: 1px solid rgba(var(--insp-accent-rgb, 246, 183, 67), .35); border-radius: 6px; background: rgba(var(--insp-accent-rgb, 246, 183, 67), .08); color: var(--insp-accent, #f6b743); font: 600 10px 'FlowStudio Pretendard', sans-serif; cursor: pointer; }
.flowstudio .fs-edit-brush button:hover:not(:disabled) { background: rgba(246,183,67,.18); }
.flowstudio .fs-edit-brush button:disabled { opacity: .35; cursor: default; }
/* Icon-only mode buttons (owner mock 2026-09-02): square, the SVG is the
   label — words live in title + aria-label. is-busy pulses while SELECT's
   own detection poll is out. */
/* Named, not guessed at: an arrow and a crosshair told nobody what they were
   for (owner 2026-09-12). The icon stays, the word joins it. */
.flowstudio .fs-edit-brush [data-mask-mode] { display: inline-flex; align-items: center; justify-content: center; gap: 5px; width: auto; min-width: 26px; height: 24px; padding: 0 8px; flex: 0 0 auto; }
.flowstudio .fs-edit-brush [data-mask-mode][data-mask-mode="brush"] { padding: 0; width: 26px; }
.flowstudio .fs-edit-brush .fs-mode-label { font: 700 9px 'FlowStudio Pretendard', sans-serif; letter-spacing: .06em; text-transform: uppercase; }
/* LOADING (owner 2026-09-03). SELECT's detection is 10-45s and a click ~1s;
   an opacity pulse read as "this button is odd", not as "the app is working".
   The button being waited on swaps its icon for a spinner and keeps full
   contrast — every other control in the two rows greys out and is disabled in
   JS, so the freeze is real and not merely painted. */
.flowstudio .fs-edit-brush [data-mask-mode].is-busy { position: relative; }
.flowstudio .fs-edit-brush [data-mask-mode].is-busy > svg { visibility: hidden; }
.flowstudio .fs-edit-brush [data-mask-mode].is-busy:disabled { opacity: 1; }
.flowstudio .fs-edit-brush [data-mask-mode].is-busy::after { content: ''; position: absolute; width: 12px; height: 12px; border: 2px solid rgba(var(--insp-accent-rgb, 246, 183, 67), .3); border-top-color: var(--insp-accent, #f6b743); border-radius: 50%; animation: fs-result-spin .7s linear infinite; }
.flowstudio .fs-edit-brush.is-loading { cursor: progress; }
.flowstudio .fs-edit-brush.is-loading label,
.flowstudio .fs-edit-brush.is-loading button:not(.is-busy) { opacity: .38; }
.flowstudio .fs-edit-brush input[type=range]:disabled { cursor: default; }
/* The picture itself: grey, and no crosshair — a tap on it is refused while
   the answer that will redraw the mask is still out. */
.flowstudio .fs-edit-preview.is-loading img,
.flowstudio .fs-edit-preview.is-loading canvas { filter: grayscale(.9) brightness(.55); transition: filter .16s ease; }
.flowstudio .fs-edit-preview.is-loading.is-drawable,
.flowstudio .fs-edit-preview.is-loading.is-drawable.is-picking { cursor: progress; }
/* The stage footer: the two mask rows stacked, Done on its own right-
   aligned line (owner mock). */
.flowstudio .fs-inpaint-rows { display: flex; flex-direction: column; gap: 4px; }
.flowstudio .fs-inpaint-done-row { display: flex; justify-content: flex-end; margin-top: 2px; }
/* The inspector is ~340px of usable row — three sliders cannot share one
   line there without crushing their labels (LEVE…, colliding readouts).
   A 120px floor per slider label wraps them two-up instead; the stage is
   wide enough that the same floor keeps the owner's one-line mock. */
/* 200px basis: the ~1400px stage row lays LEVEL/PADDING/FEATHER on ONE
   line (the owner mock); the ~340px inspector wraps them two-up. */
.flowstudio .fs-edit-brush[data-mask-row] label { flex: 1 1 200px; min-width: 120px; }
.flowstudio .fs-edit-cost { margin-left: auto; color: var(--insp-accent, #f6b743); font: 700 9px 'FlowStudio Pretendard', sans-serif; letter-spacing: .06em; }
.flowstudio .fs-edit-run { min-height: 32px; padding: 7px 16px; color: var(--insp-accent, #f6b743); background: rgba(var(--insp-accent-rgb, 246, 183, 67), .1); border: 1px solid rgba(var(--insp-accent-rgb, 246, 183, 67), .42); border-radius: 6px; cursor: pointer; font: 700 11px 'FlowStudio Pretendard', sans-serif; letter-spacing: .03em; transition: background .14s, border-color .14s, box-shadow .14s; }
/* The RUN button wears the same credit pill the Generate buttons do. Placed
   AFTER the base rule on purpose: same specificity (0,2,0), so on any property
   both set the later declaration wins — the ordering trap this file has hit
   before (.fs-ref-slot-menu vs .fs-gen-dropdown). */
.flowstudio .fs-edit-run { display: inline-flex; align-items: center; justify-content: center; gap: 7px; }
.flowstudio .fs-edit-run .cost-pill { margin-left: 0; background: rgba(0, 0, 0, .26); }
.flowstudio .fs-edit-run:disabled .cost-pill { opacity: .55; }
.flowstudio .fs-edit-run:hover { background: rgba(var(--insp-accent-rgb, 246, 183, 67), .18); border-color: rgba(var(--insp-accent-rgb, 246, 183, 67), .68); box-shadow: 0 0 14px rgba(var(--insp-accent-rgb, 246, 183, 67), .16); }
.flowstudio .fs-edit-run:disabled { opacity: .5; cursor: default; box-shadow: none; }
.flowstudio .fs-edit-status { margin: 8px 0 0; color: #9aa0a6; font: 500 10px/1.4 'FlowStudio Pretendard', sans-serif; }
/* Multi-image inspector */
/* Inspector IMAGES (owner 2026-09-09): a grid that uses the panel's full
   width — as many square tiles per row as fit at ≥84px, every row edge to
   edge, tiles growing to fill. */
.flowstudio .fs-multi-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); gap: 8px; min-height: 64px; padding: 8px; border: 1px dashed rgba(255, 255, 255, .14); border-radius: 8px; transition: border-color .14s, background .14s; }
.flowstudio .fs-multi-list.drag { border-color: rgba(55, 200, 255, .6); background: rgba(55, 200, 255, .06); }
.flowstudio .fs-multi-list .fs-multi-empty { grid-column: 1 / -1; }
.flowstudio .fs-multi-item { position: relative; width: auto; height: auto; aspect-ratio: 1; min-width: 0; border-radius: 6px; overflow: hidden; border: 1px solid rgba(255, 255, 255, .1); }
.flowstudio .fs-multi-item img { width: 100%; height: 100%; object-fit: cover; display: block; }
.flowstudio .fs-multi-remove { position: absolute; top: 2px; right: 2px; width: 18px; height: 18px; line-height: 15px; text-align: center; color: #fff; background: rgba(0, 0, 0, .6); border: 0; border-radius: 4px; cursor: pointer; font-size: 13px; }
.flowstudio .fs-multi-remove:hover { background: rgba(224, 85, 95, .85); }
.flowstudio .fs-multi-empty { margin: auto; color: #7c7c7c; font: 500 12px 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-multi-add { width: 100%; margin-top: 8px; min-height: 32px; color: #37c8ff; background: rgba(55, 200, 255, .08); border: 1px solid rgba(55, 200, 255, .35); border-radius: 6px; cursor: pointer; font: 700 11px 'FlowStudio Pretendard', sans-serif; transition: background .14s, border-color .14s; }
.flowstudio .fs-multi-add:hover { background: rgba(55, 200, 255, .16); border-color: rgba(55, 200, 255, .6); }
.flowstudio .fs-multi-count { color: #7c7c7c; font: 500 10px 'FlowStudio Pretendard', sans-serif; letter-spacing: .06em; text-transform: none; }
.flowstudio .fs-multi-add:disabled { opacity: .45; cursor: not-allowed; }
.flowstudio .fs-multi-status { margin: 6px 0 0; min-height: 12px; color: #9aa0a6; font: 500 11px 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-multi-status.is-warning { color: #f2d59c; }
/* Node face: the canvas must show what the node holds, not a generic glyph. */
.flowstudio .fs-node-body.fs-multi-over { outline: 2px dashed rgba(55, 200, 255, .65); outline-offset: -6px; background: rgba(55, 200, 255, .06); }
.flowstudio .fs-node-body.fs-multi-busy { cursor: progress; }
.flowstudio .fs-node-placeholder.has-images > svg,
.flowstudio .fs-node-placeholder.has-images > span { display: none; }
/* The placeholder centres a single glyph; with a thumbnail strip it has to
   stretch and clip instead, or the grid shrink-wraps the tiles into a column. */
.flowstudio .fs-node-placeholder.has-images { place-items: stretch; align-content: start; overflow: hidden; }
/* Multi-image face (owner 2026-09-09): a grid of --fs-multi-cols columns
   filling the whole face — one image is full size like a Reference, two
   split it, three thirds, four quarters, then √n columns. Absolutely placed
   so the rows can share the face's fixed height. */
.flowstudio .fs-multi-strip { position: absolute; inset: 6px; display: grid; grid-template-columns: repeat(var(--fs-multi-cols, 1), minmax(0, 1fr)); grid-auto-rows: minmax(0, 1fr); gap: 4px; }
.flowstudio .fs-multi-strip img,
.flowstudio .fs-multi-strip .fs-multi-video { display: block; width: 100%; height: 100%; min-width: 0; min-height: 0; object-fit: contain; background: #05070a; border-radius: 5px; border: 1px solid rgba(255, 255, 255, .12); }
.flowstudio .fs-multi-pick { margin-top: 8px; padding: 6px 12px; color: #37c8ff; background: rgba(55, 200, 255, .08); border: 1px solid rgba(55, 200, 255, .35); border-radius: 6px; cursor: pointer; font: 700 12px 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-multi-pick:hover { background: rgba(55, 200, 255, .16); border-color: rgba(55, 200, 255, .6); }
/* Storyboard sheet, rendered INSIDE the node. Same stretch/clip treatment the
   thumbnail strip needs — the placeholder otherwise centres a lone glyph. */
.flowstudio .fs-node-placeholder.has-storyboard,
.flowstudio .fs-node-placeholder.is-busy { place-items: stretch; align-content: stretch; overflow: hidden; }
.flowstudio .fs-node-placeholder.has-storyboard > svg,
.flowstudio .fs-node-placeholder.has-storyboard > span,
.flowstudio .fs-node-placeholder.is-busy > svg,
.flowstudio .fs-node-placeholder.is-busy > span { display: none; }
.flowstudio .fs-sb-canvas { position: relative; display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; min-height: 0; border-radius: 5px; overflow: hidden; }
.flowstudio .fs-sb-canvas img { max-width: 100%; max-height: 100%; display: block; object-fit: contain; }
.flowstudio .fs-sb-progress { position: absolute; padding: 7px 13px; color: #cfd3d6; background: rgba(6, 8, 9, .62); border-radius: 6px; font: 600 12px 'FlowStudio Pretendard', sans-serif; }
/* Panels as they land, before (or instead of) the composed sheet. */
.flowstudio .fs-sb-grid { display: grid; grid-template-columns: repeat(var(--sb-cols, 2), 1fr); gap: 6px; width: 100%; height: 100%; padding: 8px; }
.flowstudio .fs-sb-cell { position: relative; min-height: 0; border: 1px solid rgba(255, 255, 255, .16); border-radius: 4px; overflow: hidden; }
.flowstudio .fs-sb-cell img { width: 100%; height: 100%; display: block; object-fit: contain; background: #05070a; }
.flowstudio .fs-sb-cell i { position: absolute; top: 3px; left: 4px; padding: 1px 5px; color: #fff; background: rgba(6, 8, 9, .66); border-radius: 3px; font: 700 10px 'FlowStudio Pretendard', sans-serif; font-style: normal; }
/* Top-right, like every other view affordance (reference nodes, results): one
   corner means one habit, and the bottom edge stays clear of captions and
   video controls. */
/* VIEW is a footer cell (owner 2026-08-26): bottom-right of the standard
   38px footer, flat hairline dress — the hover overlay on the sheet retired.
   Both sheet nodes: Storyboard and Character sheet paint through the same
   syncStoryboardNode. */
.flowstudio .fs-board-node .fs-node-foot { padding-right: 0; }
/* No status word on board-likes (owner 2026-08-26): the right end belongs to
   VIEW when a sheet exists, and stays quiet when it doesn't. */
.flowstudio .fs-board-node .fs-node-foot span:last-of-type { display: none; }
.flowstudio .fs-sb-view { align-self: stretch; margin-left: auto; min-width: 92px; padding: 0 12px; display: inline-flex; align-items: center; justify-content: center; color: var(--fs-text-dim); background: transparent; border: 0; border-left: 1px solid var(--fs-line); border-radius: 0 0 9px 0; cursor: pointer; font: 700 10px 'DM Mono', monospace; letter-spacing: .04em; text-transform: uppercase; transition: color .15s, background .15s; }
.flowstudio .fs-sb-view:hover { color: #fff; background: rgba(255, 255, 255, .07); }
.flowstudio .fs-sb-view[hidden] { display: none; }
/* The Multi-image node wears the same footer VIEW cell (owner 2026-09-06) so
   Space / the context menu can page through the pictures it holds. */
.flowstudio .fs-multi-view { align-self: stretch; margin-left: auto; min-width: 92px; padding: 0 12px; display: inline-flex; align-items: center; justify-content: center; color: var(--fs-text-dim); background: transparent; border: 0; border-left: 1px solid var(--fs-line); border-radius: 0 0 9px 0; cursor: pointer; font: 700 10px 'DM Mono', monospace; letter-spacing: .04em; text-transform: uppercase; transition: color .15s, background .15s; }
.flowstudio .fs-multi-view:hover { color: #fff; background: rgba(255, 255, 255, .07); }
.flowstudio .fs-multi-view[hidden] { display: none; }
/* The VIEW cell sits flush in the footer's corner (owner 2026-09-09): the
   standard footer's 9px right padding left it floating inside the frame with
   its hover wash inset too. Same dress as the board-like footers — no right
   padding, and the status word steps aside so the description keeps its room. */
.flowstudio .fs-node-foot:has(> .fs-multi-view:not([hidden])) { padding-right: 0; }
.flowstudio .fs-node-foot:has(> .fs-multi-view:not([hidden])) > span:last-of-type { display: none; }
/* Storyboard node — larger board-like standard node + inspector */
.flowstudio .fs-storyboard-node { width: 460px; }
.flowstudio .fs-sb-field { display: flex; flex-direction: column; gap: 3px; margin-bottom: 8px; }
.flowstudio .fs-sb-field > span { color: var(--insp-accent, #7c7c7c); font: 700 8px 'FlowStudio Pretendard', sans-serif; letter-spacing: .1em; text-transform: uppercase; }
.flowstudio .fs-sb-input { box-sizing: border-box; width: 100%; color: #FFFFFF; background: rgb(24, 25, 28); border: 1px solid rgba(255, 255, 255, .12); border-radius: 5px; padding: 6px 8px; font: 600 11px 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-sb-text { min-height: 70px; resize: vertical; }
/* Logline/synopsis gets a big square-ish box like the AIO prompt (owner 2026-09-05). */
.flowstudio .fs-sb-text[data-sb="logline"] { min-height: 200px; }
.flowstudio .fs-sb-row { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 8px; }
.flowstudio .fs-sb-row-2 { grid-template-columns: 1fr 1fr; }
/* Chip rows reuse .fs-param-chips for the pressed/hover treatment; this only
   seats them inside an .fs-sb-field, whose label is a block above them. */
.flowstudio .fs-sb-chips { margin-top: 1px; }
.flowstudio .fs-sb-toggles { display: flex; flex-direction: column; gap: 7px; }
.flowstudio .fs-sb-toggle { display: flex; align-items: center; gap: 8px; color: #a6a8ac; cursor: pointer; font: 500 11px 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-sb-toggle:hover { color: #FFFFFF; }
.flowstudio .fs-sb-toggle input { width: 14px; height: 14px; margin: 0; accent-color: var(--insp-accent, #00FF7F); cursor: pointer; }
.flowstudio .fs-sb-toggle input:checked + span { color: #FFFFFF; }
.flowstudio .fs-sb-slots { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.flowstudio .fs-sb-slot { display: flex; flex-direction: column; gap: 4px; }
.flowstudio .fs-sb-slot-label { color: #7c7c7c; font: 700 8px 'FlowStudio Pretendard', sans-serif; letter-spacing: .08em; text-transform: uppercase; }
.flowstudio .fs-sb-slot-btn { position: relative; height: 72px; color: var(--insp-accent, #37c8ff); background: rgba(var(--insp-accent-rgb, 55, 200, 255), .06); border: 1px dashed rgba(var(--insp-accent-rgb, 55, 200, 255), .3); border-radius: 6px; cursor: pointer; font-size: 18px; overflow: hidden; }
.flowstudio .fs-sb-slot-btn.filled { border-style: solid; }
/* Media-panel drag hovering a slot (owner 2026-09-05). */
.flowstudio .fs-sb-slot.fs-slot-drop .fs-sb-slot-btn { border-style: solid; border-color: var(--insp-accent, #37c8ff); background: rgba(var(--insp-accent-rgb, 55, 200, 255), .16); box-shadow: 0 0 0 2px rgba(var(--insp-accent-rgb, 55, 200, 255), .35); }
.flowstudio .fs-sb-slot-btn img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.flowstudio .fs-sb-slot-x { position: absolute; top: 3px; right: 4px; z-index: 1; color: #fff; background: rgba(0, 0, 0, .6); border-radius: 4px; width: 18px; height: 18px; line-height: 16px; font-size: 13px; font-style: normal; }
/* ── Storyboard panel: tabs + hierarchy (owner 2026-09-06) ─────────────────
   The panel was eleven full-width sections in one ~2,000px scroll, every one
   weighted the same. Three tabs now carry it, and the rules below are scoped to
   `.fs-sb-pane` so the Character sheet's inspector — which shares .fs-sb-field
   and .fs-sb-toggle — is untouched. */
.flowstudio .fs-sb-runsection { padding-bottom: 0; }
.flowstudio .fs-sb-tabs { position: sticky; top: 0; z-index: 2; display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 2px; margin: 0 0 12px; padding: 3px; background: rgba(10, 8, 5, .6); border: 1px solid rgba(255, 255, 255, .07); border-radius: 7px; backdrop-filter: blur(6px); }
.flowstudio .fs-sb-tabs button { height: 26px; padding: 0 6px; color: #8b8d92; background: none; border: 0; border-radius: 5px; cursor: pointer; font: 700 10px 'FlowStudio Pretendard', sans-serif; letter-spacing: .1em; text-transform: uppercase; transition: color .14s ease, background .14s ease; }
.flowstudio .fs-sb-tabs button:hover { color: #e8e6de; }
/* The one place the node accent earns its loudness in this panel: which tab you
   are on. Everything else below is deliberately quiet. */
.flowstudio .fs-sb-tabs button.on { color: var(--insp-accent, #00FF7F); background: rgba(var(--insp-accent-rgb, 0, 255, 127), .13); box-shadow: 0 0 0 1px rgba(var(--insp-accent-rgb, 0, 255, 127), .32) inset; }
/* Section heads own the space their fields sit in: brighter than the field
   labels beneath them, which used to be the accent colour and so shouted over
   the head that owned them. */
.flowstudio .fs-sb-pane .fs-section-head { color: #c8c8c8; }
.flowstudio .fs-sb-pane .fs-sb-field > span { color: #7c7c7c; }
.flowstudio .fs-sb-pane .fs-sb-subhead { margin-top: 14px; }
/* Twelve checkboxes in one column read as a wall; two columns fit the panel and
   halve the scroll. */
.flowstudio .fs-sb-pane .fs-sb-toggles { display: grid; grid-template-columns: 1fr 1fr; gap: 7px 10px; }
.flowstudio .fs-sb-pane .fs-sb-toggle { min-width: 0; }
.flowstudio .fs-sb-pane .fs-sb-toggle span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.flowstudio .fs-sb-pane .fs-inputs-section { padding-top: 0; }

/* ── Storyboard: wired Reference inputs (owner 2026-09-06) ──────────────────
   Replaces the four fixed .fs-sb-slot uploads. One row per WIRE on the
   Reference handle — thumbnail, source node, and the role dropdown that says
   what the picture is for. Legacy rows (.is-legacy) are the old slot uploads:
   removable, not addable, so no existing storyboard loses a reference. */
.flowstudio .fs-sb-reflist { display: flex; flex-direction: column; gap: 6px; }
.flowstudio .fs-sb-refrow { display: flex; align-items: center; gap: 8px; padding: 5px 6px; background: rgba(255, 255, 255, .03); border: 1px solid rgba(255, 255, 255, .08); border-radius: 6px; }
.flowstudio .fs-sb-refrow.is-legacy { border-style: dashed; opacity: .78; }
.flowstudio .fs-sb-refthumb { flex: 0 0 auto; width: 34px; height: 34px; background: rgba(0, 0, 0, .35) center/cover no-repeat; border-radius: 4px; }
.flowstudio .fs-sb-refname { flex: 1 1 auto; min-width: 0; overflow: hidden; color: #c8c8c8; text-overflow: ellipsis; white-space: nowrap; font: 600 10px 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-sb-refname i { color: #7c7c7c; font-style: normal; }
.flowstudio .fs-sb-refrole { flex: 0 0 auto; padding: 3px 5px; color: #e8e6de; background: rgba(0, 0, 0, .4); border: 1px solid rgba(255, 255, 255, .14); border-radius: 5px; cursor: pointer; font: 600 10px 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-sb-refdrop { flex: 0 0 auto; width: 20px; height: 20px; color: #9aa0a6; background: none; border: 0; border-radius: 4px; cursor: pointer; font-size: 14px; line-height: 1; }
.flowstudio .fs-sb-refdrop:hover { color: #fff; background: rgba(255, 255, 255, .1); }
.flowstudio .fs-sb-generate { width: 100%; min-height: 36px; color: var(--insp-accent, #00FF7F); background: rgba(var(--insp-accent-rgb, 0, 255, 127), .09); border: 1px solid rgba(var(--insp-accent-rgb, 0, 255, 127), .4); border-radius: 6px; cursor: pointer; font: 700 12px 'FlowStudio Pretendard', sans-serif; }
/* Secondary to Generate on purpose: it rewrites a text field, not the board. */
.flowstudio .fs-sb-enhance { width: 100%; min-height: 30px; margin-top: 6px; color: var(--insp-accent, #37c8ff); background: rgba(var(--insp-accent-rgb, 55, 200, 255), .07); border: 1px solid rgba(var(--insp-accent-rgb, 55, 200, 255), .35); border-radius: 6px; cursor: pointer; font: 700 11px 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-sb-enhance:hover { background: rgba(var(--insp-accent-rgb, 55, 200, 255), .14); border-color: rgba(var(--insp-accent-rgb, 55, 200, 255), .6); }
.flowstudio .fs-sb-enhance:disabled { opacity: .5; cursor: default; }
.flowstudio .fs-sb-generate:hover { background: rgba(var(--insp-accent-rgb, 0, 255, 127), .17); border-color: rgba(var(--insp-accent-rgb, 0, 255, 127), .66); }
.flowstudio .fs-sb-generate:disabled { opacity: .5; cursor: default; }
.flowstudio .fs-sb-status { margin: 8px 0 0; min-height: 14px; color: #9aa0a6; font: 500 10px/1.4 'FlowStudio Pretendard', sans-serif; }
/* Wire-membership hint on the Character sheet. Separate from .fs-sb-status so a
   generation message cannot overwrite "not wired into a Storyboard yet". */
.flowstudio .fs-cs-wire { margin: 6px 0 0; color: #7c7c7c; font: 500 10px/1.4 'FlowStudio Pretendard', sans-serif; }
/* Flow-native production records. These are compact slate cards, not a second
   asset drawer: immutable tag/version metadata stays monospace, the canonical
   image is evidence, and every inactive state says why it contributes nothing. */
.flowstudio .fs-production-node .fs-node-placeholder { place-items: stretch; align-content: stretch; overflow: hidden; border-style: solid; }
.flowstudio .fs-production-node .fs-production-face { --accent-rgb: var(--node-accent-rgb); }
.flowstudio .fs-production-face,
.flowstudio .fs-asset-node-face,
.flowstudio .fs-context-node-face { width: 100%; height: 100%; min-height: 0; display: grid; grid-template-columns: 58px minmax(0, 1fr); gap: 9px; padding: 9px; align-items: stretch; color: var(--fs-text); background: linear-gradient(135deg, rgba(var(--accent-rgb, 55, 200, 255), .11), rgba(15, 17, 20, .84) 62%); }
.flowstudio .fs-context-node-face { grid-template-columns: 1fr; align-content: start; }
.flowstudio .fs-production-thumb,
.flowstudio .fs-asset-thumb { position: relative; width: 58px; min-height: 58px; overflow: hidden; display: grid; place-items: center; color: rgba(var(--accent-rgb, 55, 200, 255), .8); background: rgba(var(--accent-rgb, 55, 200, 255), .08); border: 1px solid rgba(var(--accent-rgb, 55, 200, 255), .24); border-radius: 6px; font: 700 17px 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-production-thumb img,
.flowstudio .fs-asset-thumb img { position: absolute; inset: 0; width: 100%; height: 100%; display: block; object-fit: cover; }
.flowstudio .fs-production-face-copy { min-width: 0; display: flex; flex-direction: column; justify-content: center; gap: 4px; }
.flowstudio .fs-production-eyebrow { overflow: hidden; color: var(--fs-text-dim); text-overflow: ellipsis; white-space: nowrap; font: 700 8px 'FlowStudio Pretendard', sans-serif; letter-spacing: .12em; text-transform: uppercase; }
.flowstudio .fs-production-name { overflow: hidden; color: var(--fs-text); text-overflow: ellipsis; white-space: nowrap; font: 650 12px 'Outfit', sans-serif; letter-spacing: -.01em; }
.flowstudio .fs-production-tag,
.flowstudio .fs-asset-tag { width: fit-content; max-width: 100%; overflow: hidden; padding: 2px 5px; color: #8adfff; background: rgba(55, 200, 255, .09); border: 1px solid rgba(55, 200, 255, .22); border-radius: 3px; text-overflow: ellipsis; white-space: nowrap; user-select: text; font: 600 8px/1.35 'DM Mono', monospace; letter-spacing: .02em; }
.flowstudio .fs-production-node-state { grid-column: 1 / -1; margin: 0; color: var(--fs-text-dim); font: 500 9px/1.4 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-production-face.is-unlinked,
.flowstudio .fs-production-face.is-unavailable,
.flowstudio .fs-production-face.is-disabled { grid-template-columns: 1fr; align-content: center; text-align: center; background: linear-gradient(135deg, rgba(255, 255, 255, .025), rgba(15, 17, 20, .82)); }
.flowstudio .fs-production-face.is-unavailable { border-color: rgba(246, 183, 67, .3); }
.flowstudio .fs-production-face.is-disabled { filter: saturate(.45); opacity: .82; }

/* Inspector mirror: one canonical-image card followed by dense, selectable
   production facts. It intentionally shares Flow's section rhythm and controls. */
.flowstudio .fs-production-card,
.flowstudio .fs-asset-card,
.flowstudio .fs-context-card { display: grid; gap: 9px; padding: 10px; color: var(--fs-text-mute); background: linear-gradient(rgb(25, 27, 30), rgb(21, 23, 26)); border: 1px solid var(--fs-line-strong); border-radius: 8px; box-shadow: rgba(255, 255, 255, .025) 0 1px 0 inset; }
.flowstudio .fs-production-hero { display: grid; grid-template-columns: 72px minmax(0, 1fr); gap: 10px; align-items: stretch; }
.flowstudio .fs-production-hero .fs-production-thumb,
.flowstudio .fs-production-hero .fs-asset-thumb { width: 72px; min-height: 72px; }
.flowstudio .fs-production-meta { min-width: 0; display: flex; flex-direction: column; align-items: flex-start; justify-content: center; gap: 5px; }
.flowstudio .fs-production-meta b { max-width: 100%; overflow: hidden; color: var(--fs-text); text-overflow: ellipsis; white-space: nowrap; font: 650 13px 'Outfit', sans-serif; }
.flowstudio .fs-production-badges { display: flex; flex-wrap: wrap; gap: 4px; }
.flowstudio .fs-production-badge { display: inline-flex; align-items: center; min-height: 17px; padding: 2px 6px; color: var(--fs-text-mute); background: rgba(255, 255, 255, .045); border: 1px solid rgba(255, 255, 255, .09); border-radius: 999px; font: 700 8px/1 'DM Mono', monospace; letter-spacing: .06em; text-transform: uppercase; }
.flowstudio .fs-production-badge.is-approved { color: #8ff3c3; background: rgba(0, 255, 127, .08); border-color: rgba(0, 255, 127, .28); }
.flowstudio .fs-production-badge.is-testing { color: #ffd787; background: rgba(246, 183, 67, .08); border-color: rgba(246, 183, 67, .28); }
.flowstudio .fs-production-badge.is-draft { color: #b9bcc1; }
.flowstudio .fs-production-descriptor { margin: 0; padding: 8px 9px; color: #d6d8db; background: rgba(0, 0, 0, .18); border-left: 2px solid rgba(var(--accent-rgb, 55, 200, 255), .45); border-radius: 0 5px 5px 0; white-space: pre-wrap; overflow-wrap: anywhere; user-select: text; font: 500 10px/1.5 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-production-grid { display: grid; grid-template-columns: minmax(74px, auto) minmax(0, 1fr); gap: 6px 10px; align-items: baseline; }
.flowstudio .fs-production-grid dt { color: var(--fs-text-dim); font: 700 8px 'DM Mono', monospace; letter-spacing: .08em; text-transform: uppercase; }
.flowstudio .fs-production-grid dd { min-width: 0; margin: 0; color: #d6d8db; text-align: right; overflow-wrap: anywhere; user-select: text; font: 600 10px/1.4 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-production-list,
.flowstudio .fs-production-assets-list { display: grid; gap: 5px; margin: 0; padding: 0; list-style: none; }
.flowstudio .fs-production-list > li,
.flowstudio .fs-production-assets-list > li { min-width: 0; display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 6px 7px; color: var(--fs-text-mute); background: rgba(255, 255, 255, .025); border: 1px solid rgba(255, 255, 255, .055); border-radius: 5px; font: 500 10px/1.35 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-production-list code,
.flowstudio .fs-production-assets-list code { min-width: 0; overflow: hidden; color: #8adfff; text-overflow: ellipsis; white-space: nowrap; user-select: text; font: 600 9px 'DM Mono', monospace; }
.flowstudio .fs-production-swatches,
.flowstudio .fs-context-swatches { display: flex; flex-wrap: wrap; gap: 4px; min-height: 14px; }
.flowstudio .fs-production-swatch,
.flowstudio .fs-context-swatch { width: 18px; height: 18px; border: 1px solid rgba(255, 255, 255, .2); border-radius: 4px; background: #30303b; box-shadow: rgba(0, 0, 0, .32) 0 1px 3px; }
.flowstudio .fs-production-ratios,
.flowstudio .fs-context-ratios { display: flex; flex-wrap: wrap; gap: 5px; color: var(--fs-text-dim); font: 600 8px 'DM Mono', monospace; }
.flowstudio .fs-production-ratios span,
.flowstudio .fs-context-ratios span { padding: 3px 6px; background: rgba(167, 139, 250, .07); border: 1px solid rgba(167, 139, 250, .18); border-radius: 4px; }
.flowstudio .fs-production-state,
.flowstudio .fs-production-warning { margin: 0; padding: 8px 9px; color: var(--fs-text-mute); background: rgba(110, 168, 254, .055); border: 1px solid rgba(110, 168, 254, .19); border-radius: 6px; font: 500 10px/1.45 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-production-state.is-warning,
.flowstudio .fs-production-warning { color: #f2d59c; background: rgba(246, 183, 67, .065); border-color: rgba(246, 183, 67, .28); }
.flowstudio .fs-production-state.is-error { color: #ffc2c6; background: rgba(224, 85, 95, .07); border-color: rgba(224, 85, 95, .3); }
.flowstudio .fs-production-state.is-disabled { color: #a6a8ac; background: rgba(255, 255, 255, .025); border-color: rgba(255, 255, 255, .08); }
.flowstudio .fs-production-action { width: 100%; min-height: 32px; padding: 6px 10px; color: #37c8ff; background: rgba(55, 200, 255, .07); border: 1px solid rgba(55, 200, 255, .34); border-radius: 6px; cursor: pointer; font: 700 11px 'FlowStudio Pretendard', sans-serif; transition: background .14s, border-color .14s; }
.flowstudio .fs-production-action:hover { background: rgba(55, 200, 255, .14); border-color: rgba(55, 200, 255, .6); }
.flowstudio .fs-production-action:disabled { opacity: .45; cursor: default; }
.flowstudio .fs-production-wire { margin: 6px 0 0; color: var(--fs-text-dim); font: 500 10px/1.45 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-production-empty { padding: 10px; color: var(--fs-text-dim); text-align: center; font: 500 10px/1.45 'FlowStudio Pretendard', sans-serif; }

/* Guided PREP and stress qualification live in the inspector as compact call
   sheets. The numbered rail makes recipe order legible without introducing a
   second drawer vocabulary; evidence, cost, and refusals stay attached to the
   action that produced them. */
.flowstudio .fs-prep-list,
.flowstudio .fs-prep-recipes { display: grid; gap: 8px; }
.flowstudio .fs-prep-lede,
.flowstudio .fs-prep-summary,
.flowstudio .fs-frame-honesty { margin: 0 0 8px; color: var(--fs-text-dim); overflow-wrap: anywhere; font: 500 9px/1.45 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-prep-card,
.flowstudio .fs-recipe-card {
  --prep-accent: 0, 255, 127;
  position: relative;
  min-width: 0;
  overflow: hidden;
  color: var(--fs-text-mute);
  background: linear-gradient(145deg, rgba(var(--prep-accent), .055), rgba(20, 22, 25, .96) 45%);
  border: 1px solid rgba(var(--prep-accent), .18);
  border-radius: 8px;
  box-shadow: rgba(255, 255, 255, .025) 0 1px 0 inset;
}
.flowstudio .fs-prep-card::before,
.flowstudio .fs-recipe-card::before { position: absolute; inset: 0 auto 0 0; width: 2px; content: ''; background: rgba(var(--prep-accent), .62); }
.flowstudio .fs-prep-card.is-active,
.flowstudio .fs-recipe-card.is-active { border-color: rgba(var(--prep-accent), .4); box-shadow: rgba(255, 255, 255, .025) 0 1px 0 inset, rgba(var(--prep-accent), .09) 0 0 18px; }
.flowstudio .fs-prep-card.is-education,
.flowstudio .fs-recipe-card.is-education { --prep-accent: 55, 200, 255; }
.flowstudio .fs-prep-card.is-unavailable,
.flowstudio .fs-recipe-card.is-unavailable { --prep-accent: 224, 85, 95; background: linear-gradient(145deg, rgba(224, 85, 95, .055), rgba(20, 22, 25, .96) 45%); }
.flowstudio .fs-prep-card-head,
.flowstudio .fs-recipe-card-head {
  box-sizing: border-box;
  width: 100%;
  min-width: 0;
  display: grid;
  grid-template-columns: 28px minmax(0, 1fr) auto;
  gap: 8px;
  align-items: center;
  padding: 10px 10px 10px 12px;
  color: inherit;
  background: transparent;
  border: 0;
  text-align: left;
}
.flowstudio button.fs-prep-card-head,
.flowstudio button.fs-recipe-card-head { cursor: pointer; }
.flowstudio .fs-prep-mark,
.flowstudio .fs-recipe-mark {
  width: 26px;
  height: 26px;
  display: grid;
  place-items: center;
  color: rgb(var(--prep-accent));
  background: rgba(var(--prep-accent), .09);
  border: 1px solid rgba(var(--prep-accent), .25);
  border-radius: 6px;
  font: 700 9px 'DM Mono', monospace;
  letter-spacing: .04em;
}
.flowstudio .fs-prep-card-copy,
.flowstudio .fs-recipe-card-copy { min-width: 0; display: grid; gap: 2px; }
.flowstudio .fs-prep-card-copy b,
.flowstudio .fs-recipe-card-copy b { min-width: 0; overflow: hidden; color: var(--fs-text); text-overflow: ellipsis; white-space: nowrap; font: 650 12px 'Outfit', sans-serif; }
.flowstudio .fs-prep-card-copy small,
.flowstudio .fs-recipe-card-copy small { color: var(--fs-text-dim); white-space: normal; overflow-wrap: anywhere; font: 500 9px/1.4 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-cost-pill,
.flowstudio .fs-recipe-cost-pill {
  max-width: 92px;
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 20px;
  padding: 2px 7px;
  color: #9beccf;
  background: rgba(0, 255, 127, .07);
  border: 1px solid rgba(0, 255, 127, .22);
  border-radius: 999px;
  text-overflow: ellipsis;
  white-space: nowrap;
  font: 700 8px/1.2 'DM Mono', monospace;
  font-variant-numeric: tabular-nums;
  letter-spacing: .02em;
}
.flowstudio .fs-cost-pill.is-loading,
.flowstudio .fs-recipe-cost-pill.is-loading { color: var(--fs-text-dim); background: rgba(255, 255, 255, .025); border-color: rgba(255, 255, 255, .09); }
.flowstudio .fs-cost-pill.is-error,
.flowstudio .fs-recipe-cost-pill.is-error { color: #ffc2c6; background: rgba(224, 85, 95, .07); border-color: rgba(224, 85, 95, .28); }
.flowstudio .fs-recipe-cost { display: grid; grid-template-columns: 1fr auto; gap: 5px 10px; margin: 0 10px 9px 12px; padding: 7px 8px; color: var(--fs-text-dim); background: rgba(0, 0, 0, .16); border-radius: 5px; font: 500 9px/1.35 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-recipe-cost b { color: #d6d8db; text-align: right; font: 700 9px 'DM Mono', monospace; font-variant-numeric: tabular-nums; }
.flowstudio .fs-recipe-cost-breakdown { grid-column: 1 / -1; margin: 0; color: var(--fs-text-dim); overflow-wrap: anywhere; }
.flowstudio .fs-recipe-panel { padding: 0 10px 10px 12px; border-top: 1px solid rgba(255, 255, 255, .055); }
.flowstudio .fs-recipe-panel[hidden] { display: none; }
.flowstudio .fs-recipe-version { display: block; margin-top: 7px; color: var(--fs-text-dim); font: 700 8px 'DM Mono', monospace; }
.flowstudio .fs-recipe-context { display: grid; gap: 7px; margin-top: 7px; }
.flowstudio .fs-recipe-step-title { display: flex; align-items: baseline; justify-content: space-between; gap: 6px; }
.flowstudio .fs-recipe-step-state { flex: 0 0 auto; color: var(--fs-text-dim); font: 700 7px 'DM Mono', monospace; letter-spacing: .04em; text-transform: uppercase; }
.flowstudio .fs-recipe-optional { color: #8adfff !important; }

/* Call-sheet rail: step state is carried by both data-state and is-* classes so
   async updates do not need to rebuild the element merely to change its ink. */
.flowstudio .fs-recipe-stepper { display: grid; gap: 0; margin: 0; padding: 9px 0 1px; list-style: none; counter-reset: fs-recipe-step; }
.flowstudio .fs-recipe-step {
  position: relative;
  min-width: 0;
  display: grid;
  grid-template-columns: 24px minmax(0, 1fr);
  gap: 8px;
  padding: 0 0 12px;
  counter-increment: fs-recipe-step;
}
.flowstudio .fs-recipe-step::after { position: absolute; z-index: 0; top: 23px; bottom: -2px; left: 11px; width: 1px; content: ''; background: linear-gradient(rgba(255, 255, 255, .13), rgba(255, 255, 255, .04)); }
.flowstudio .fs-recipe-step:last-child { padding-bottom: 2px; }
.flowstudio .fs-recipe-step:last-child::after { display: none; }
.flowstudio .fs-recipe-step-index {
  position: relative;
  z-index: 1;
  width: 22px;
  height: 22px;
  box-sizing: border-box;
  display: grid;
  place-items: center;
  color: var(--fs-text-dim);
  background: #1b1d20;
  border: 1px solid rgba(255, 255, 255, .13);
  border-radius: 50%;
  font: 700 8px 'DM Mono', monospace;
  font-variant-numeric: tabular-nums;
}
.flowstudio .fs-recipe-step-index:empty::before { content: counter(fs-recipe-step); }
.flowstudio .fs-recipe-step-copy { min-width: 0; padding-top: 1px; }
.flowstudio .fs-recipe-step-copy b { display: block; color: #d9dcdf; font: 650 10px/1.35 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-recipe-step-copy p,
.flowstudio .fs-recipe-step-copy small { display: block; margin: 2px 0 0; color: var(--fs-text-dim); overflow-wrap: anywhere; font: 500 9px/1.4 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-recipe-step[data-state='running'] .fs-recipe-step-index,
.flowstudio .fs-recipe-step.is-running .fs-recipe-step-index { color: #a4f6d1; background: rgba(0, 255, 127, .1); border-color: rgba(0, 255, 127, .5); box-shadow: rgba(0, 255, 127, .18) 0 0 0 3px; }
.flowstudio .fs-recipe-step[data-state='done'] .fs-recipe-step-index,
.flowstudio .fs-recipe-step.is-done .fs-recipe-step-index { color: #062c1d; background: #00FF7F; border-color: #00FF7F; }
.flowstudio .fs-recipe-step[data-state='done'] .fs-recipe-step-index:empty::before,
.flowstudio .fs-recipe-step.is-done .fs-recipe-step-index:empty::before { content: '\2713'; }
.flowstudio .fs-recipe-step[data-state='failed'] .fs-recipe-step-index,
.flowstudio .fs-recipe-step.is-failed .fs-recipe-step-index { color: #ffc2c6; background: rgba(224, 85, 95, .09); border-color: rgba(224, 85, 95, .55); }
.flowstudio .fs-recipe-step[data-state='skipped'],
.flowstudio .fs-recipe-step.is-skipped { opacity: .58; }
.flowstudio .fs-recipe-step[data-state='skipped'] .fs-recipe-step-index,
.flowstudio .fs-recipe-step.is-skipped .fs-recipe-step-index { border-style: dashed; }
.flowstudio .fs-recipe-step-actions { grid-column: 2; display: flex; flex-wrap: wrap; gap: 5px; margin-top: 6px; }
.flowstudio .fs-recipe-run,
.flowstudio .fs-recipe-skip,
.flowstudio .fs-education-link {
  min-height: 27px;
  padding: 5px 9px;
  border-radius: 5px;
  cursor: pointer;
  font: 700 9px 'FlowStudio Pretendard', sans-serif;
  letter-spacing: .02em;
}
.flowstudio .fs-recipe-run { color: #9bf0cd; background: rgba(0, 255, 127, .075); border: 1px solid rgba(0, 255, 127, .34); }
.flowstudio .fs-recipe-run:hover:not(:disabled) { color: #dffff1; background: rgba(0, 255, 127, .14); border-color: rgba(0, 255, 127, .62); }
.flowstudio .fs-recipe-skip { color: var(--fs-text-mute); background: rgba(255, 255, 255, .03); border: 1px solid rgba(255, 255, 255, .11); }
.flowstudio .fs-recipe-skip:hover:not(:disabled) { color: var(--fs-text); border-color: rgba(255, 255, 255, .25); }
.flowstudio .fs-education-link { display: inline-flex; align-items: center; justify-content: center; color: #8adfff; background: rgba(55, 200, 255, .07); border: 1px solid rgba(55, 200, 255, .3); text-decoration: none; }
.flowstudio .fs-education-link:hover:not(:disabled) { color: #c9f3ff; background: rgba(55, 200, 255, .13); border-color: rgba(55, 200, 255, .55); }
.flowstudio .fs-recipe-run:disabled,
.flowstudio .fs-recipe-skip:disabled,
.flowstudio .fs-education-link:disabled,
.flowstudio .fs-education-link[aria-disabled='true'] { opacity: .42; cursor: not-allowed; }
.flowstudio .fs-recipe-advisories { display: grid; gap: 5px; margin: 8px 0 0; padding: 0; list-style: none; }
.flowstudio .fs-recipe-advisory,
.flowstudio .fs-recipe-advisories > li { position: relative; margin: 0; padding: 6px 7px 6px 22px; color: #e7ce9a; background: rgba(246, 183, 67, .055); border: 1px solid rgba(246, 183, 67, .2); border-radius: 5px; overflow-wrap: anywhere; font: 500 9px/1.4 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-recipe-advisory::before,
.flowstudio .fs-recipe-advisories > li::before { position: absolute; top: 6px; left: 8px; content: '!'; color: #f6b743; font: 800 9px 'DM Mono', monospace; }
.flowstudio .fs-recipe-message,
.flowstudio .fs-inline-refusal,
.flowstudio .fs-frame-error,
.flowstudio .fs-stress-message { margin: 7px 0 0; padding: 7px 8px; color: var(--fs-text-mute); background: rgba(110, 168, 254, .055); border: 1px solid rgba(110, 168, 254, .2); border-radius: 5px; overflow-wrap: anywhere; font: 500 9px/1.45 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-recipe-message.is-error,
.flowstudio .fs-inline-refusal,
.flowstudio .fs-frame-error,
.flowstudio .fs-stress-message.is-error { color: #ffc2c6; background: rgba(224, 85, 95, .065); border-color: rgba(224, 85, 95, .3); }
.flowstudio .fs-inline-refusal:not(.is-error) { color: var(--fs-text-mute); background: rgba(110, 168, 254, .055); border-color: rgba(110, 168, 254, .2); }
.flowstudio .fs-recipe-message.is-warning,
.flowstudio .fs-stress-message.is-warning { color: #f2d59c; background: rgba(246, 183, 67, .06); border-color: rgba(246, 183, 67, .25); }
.flowstudio .fs-recipe-message:empty,
.flowstudio .fs-inline-refusal:empty,
.flowstudio .fs-frame-error:empty,
.flowstudio .fs-stress-message:empty { display: none; }

/* Client-supplied location frame evidence. The preview is deliberately labelled
   as selected media, while the actual canvas can remain hidden after capture. */
.flowstudio .fs-frame-picker { display: grid; gap: 7px; margin-top: 8px; padding: 8px; background: rgba(0, 0, 0, .18); border: 1px solid rgba(55, 200, 255, .16); border-radius: 6px; }
.flowstudio .fs-frame-video,
.flowstudio .fs-frame-selected img,
.flowstudio .fs-frame-selected video { width: 100%; aspect-ratio: 16 / 9; display: block; object-fit: contain; background: #07090a; border: 1px solid rgba(255, 255, 255, .1); border-radius: 5px; }
.flowstudio .fs-frame-video { max-height: 184px; }
.flowstudio .fs-frame-scrub { min-width: 0; display: grid; grid-template-columns: 1fr auto; gap: 5px 8px; align-items: center; color: var(--fs-text-dim); font: 700 8px 'FlowStudio Pretendard', sans-serif; letter-spacing: .08em; text-transform: uppercase; }
.flowstudio .fs-frame-scrub output,
.flowstudio .fs-frame-timecode { color: #8adfff; font: 700 9px 'DM Mono', monospace; font-variant-numeric: tabular-nums; letter-spacing: 0; text-transform: none; }
.flowstudio .fs-frame-range { grid-column: 1 / -1; width: 100%; height: 18px; margin: 0; padding: 0; background: transparent; cursor: pointer; accent-color: var(--fs-green); }
.flowstudio .fs-frame-range::-webkit-slider-runnable-track { height: 4px; background: linear-gradient(90deg, rgba(0, 255, 127, .7), rgba(255, 255, 255, .12)); border-radius: 999px; }
.flowstudio .fs-frame-range::-webkit-slider-thumb { width: 13px; height: 13px; margin-top: -4.5px; appearance: none; -webkit-appearance: none; background: #FFFFFF; border: 2px solid #00FF7F; border-radius: 50%; box-shadow: 0 1px 5px rgba(0, 0, 0, .55); }
.flowstudio .fs-frame-range::-moz-range-track { height: 4px; background: rgba(255, 255, 255, .12); border: 0; border-radius: 999px; }
.flowstudio .fs-frame-range::-moz-range-progress { height: 4px; background: rgba(0, 255, 127, .7); border-radius: 999px; }
.flowstudio .fs-frame-range::-moz-range-thumb { width: 11px; height: 11px; background: #FFFFFF; border: 2px solid #00FF7F; border-radius: 50%; box-shadow: 0 1px 5px rgba(0, 0, 0, .55); }
.flowstudio .fs-frame-selected { display: grid; grid-template-columns: 88px minmax(0, 1fr); gap: 8px; align-items: center; padding: 6px; color: var(--fs-text-dim); background: rgba(55, 200, 255, .045); border: 1px solid rgba(55, 200, 255, .16); border-radius: 5px; font: 500 9px/1.4 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-frame-selected img,
.flowstudio .fs-frame-selected video { border: 0; border-radius: 3px; }
.flowstudio .fs-frame-selected b { display: block; margin-bottom: 2px; color: #cdefff; font-weight: 650; }
.flowstudio .fs-frame-canvas { max-width: 100%; height: auto; border-radius: 5px; }
.flowstudio .fs-frame-actions { display: flex; flex-wrap: wrap; gap: 5px; }
.flowstudio .fs-frame-capture,
.flowstudio .fs-frame-manual { min-height: 29px; padding: 5px 9px; border-radius: 5px; cursor: pointer; font: 700 9px 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-frame-capture { flex: 1 1 130px; color: #9bf0cd; background: rgba(0, 255, 127, .075); border: 1px solid rgba(0, 255, 127, .34); }
.flowstudio .fs-frame-capture:hover:not(:disabled) { background: rgba(0, 255, 127, .14); border-color: rgba(0, 255, 127, .62); }
.flowstudio .fs-frame-manual { flex: 1 1 130px; color: #8adfff; background: rgba(55, 200, 255, .055); border: 1px dashed rgba(55, 200, 255, .36); }
.flowstudio .fs-frame-manual:hover:not(:disabled) { background: rgba(55, 200, 255, .12); border-color: rgba(55, 200, 255, .62); }
.flowstudio .fs-frame-capture:disabled,
.flowstudio .fs-frame-manual:disabled,
.flowstudio .fs-frame-range:disabled { opacity: .42; cursor: not-allowed; }

/* Stress matrix: two production choices feed a dense 2-column contact sheet.
   Tiles reserve their 16:9 evidence slot so generation cannot reflow verdicts. */
.flowstudio .fs-stress-intro,
.flowstudio .fs-stress-tradeoff { margin: 0 0 8px; color: var(--fs-text-dim); font: 500 9px/1.45 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-stress-tradeoff strong { color: #f2d59c; font-weight: 650; }
.flowstudio .fs-stress-matrix { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 7px; }
.flowstudio .fs-stress-choice {
  min-width: 0;
  min-height: 72px;
  display: grid;
  align-content: start;
  gap: 3px;
  padding: 8px;
  color: var(--fs-text-mute);
  background: linear-gradient(rgb(29, 31, 34), rgb(23, 25, 28));
  border: 1px solid rgba(255, 255, 255, .1);
  border-radius: 7px;
  cursor: pointer;
  text-align: left;
}
.flowstudio .fs-stress-radio { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
.flowstudio .fs-stress-choice:has(.fs-stress-radio:focus-visible) { outline: 2px solid var(--fs-green); outline-offset: 2px; }
.flowstudio .fs-stress-choice:has(.fs-stress-radio:disabled) { opacity: .48; cursor: not-allowed; }
.flowstudio .fs-stress-choice:hover:not(:has(.fs-stress-radio:disabled)) { color: var(--fs-text); border-color: rgba(255, 255, 255, .22); }
.flowstudio .fs-stress-choice.is-selected,
.flowstudio .fs-stress-choice[aria-checked='true'],
.flowstudio .fs-stress-choice[aria-pressed='true'] { color: #dffff1; background: linear-gradient(rgba(0, 255, 127, .13), rgba(0, 255, 127, .045)), #191c1d; border-color: rgba(0, 255, 127, .48); box-shadow: rgba(0, 255, 127, .12) 0 0 14px; }
.flowstudio .fs-stress-choice b { overflow: hidden; color: inherit; text-overflow: ellipsis; white-space: nowrap; font: 700 11px 'Outfit', sans-serif; }
.flowstudio .fs-stress-choice small { color: var(--fs-text-dim); white-space: normal; overflow-wrap: anywhere; font: 500 8px/1.35 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-stress-choice .fs-cost-pill { width: fit-content; max-width: 100%; margin-top: 2px; }
.flowstudio .fs-stress-choice:disabled { opacity: .48; cursor: not-allowed; }
.flowstudio .fs-stress-start { width: 100%; min-height: 34px; margin-top: 7px; padding: 6px 10px; color: #082719; background: linear-gradient(105deg, #00FF7F, #5cf2b1); border: 0; border-radius: 6px; box-shadow: rgba(255, 255, 255, .24) 0 1px 0 inset, rgba(0, 255, 127, .16) 0 4px 12px; cursor: pointer; font: 750 11px 'Outfit', sans-serif; letter-spacing: .04em; text-transform: uppercase; }
.flowstudio .fs-stress-start:hover:not(:disabled) { filter: brightness(1.07); }
.flowstudio .fs-stress-start:disabled { filter: none; opacity: .42; cursor: not-allowed; box-shadow: none; }
.flowstudio .fs-stress-run { display: grid; gap: 8px; margin-top: 10px; }
.flowstudio .fs-stress-run-head { min-width: 0; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 5px 8px; padding-bottom: 6px; border-bottom: 1px solid rgba(255, 255, 255, .07); }
.flowstudio .fs-stress-run-head > span,
.flowstudio .fs-stress-run-meta { min-width: 0; color: var(--fs-text-dim); overflow-wrap: anywhere; font: 600 8px/1.4 'DM Mono', monospace; letter-spacing: .03em; }
.flowstudio .fs-stress-aggregate { flex: 0 0 auto; padding: 3px 7px; color: #d6d8db; background: rgba(255, 255, 255, .045); border: 1px solid rgba(255, 255, 255, .1); border-radius: 999px; font: 700 9px 'DM Mono', monospace; font-variant-numeric: tabular-nums; }
.flowstudio .fs-stress-aggregate.is-pass { color: #9bf0cd; background: rgba(0, 255, 127, .07); border-color: rgba(0, 255, 127, .26); }
.flowstudio .fs-stress-grid { min-width: 0; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 7px; }
.flowstudio .fs-stress-cell { min-width: 0; overflow: hidden; display: flex; flex-direction: column; color: var(--fs-text-mute); background: linear-gradient(rgb(25, 27, 30), rgb(20, 22, 25)); border: 1px solid rgba(255, 255, 255, .09); border-radius: 7px; box-shadow: rgba(255, 255, 255, .02) 0 1px 0 inset; }
.flowstudio .fs-stress-cell.is-running,
.flowstudio .fs-stress-cell[data-state='running'] { border-color: rgba(55, 200, 255, .34); }
.flowstudio .fs-stress-cell.is-pass,
.flowstudio .fs-stress-cell[data-verdict='pass'] { border-color: rgba(0, 255, 127, .38); }
.flowstudio .fs-stress-cell.is-fail,
.flowstudio .fs-stress-cell[data-verdict='fail'] { border-color: rgba(224, 85, 95, .42); }
.flowstudio .fs-stress-cell-head { min-width: 0; display: flex; align-items: center; gap: 5px; padding: 5px 7px; border-bottom: 1px solid rgba(255, 255, 255, .06); }
.flowstudio .fs-stress-cell-head b { min-width: 0; overflow: hidden; color: #d9dcdf; text-overflow: ellipsis; white-space: nowrap; font: 650 8px 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-stress-cell-number { flex: 0 0 auto; color: #8adfff; font: 700 7px 'DM Mono', monospace; }
.flowstudio .fs-stress-media,
.flowstudio .fs-stress-thumb { position: relative; width: 100%; aspect-ratio: 16 / 9; overflow: hidden; display: grid; place-items: center; color: var(--fs-text-dim); background: radial-gradient(circle at 50% 42%, rgba(55, 200, 255, .09), #0a0c0d 72%); border-bottom: 1px solid rgba(255, 255, 255, .07); font: 700 9px 'DM Mono', monospace; }
.flowstudio .fs-stress-media img,
.flowstudio .fs-stress-media video,
.flowstudio .fs-stress-thumb img,
.flowstudio .fs-stress-thumb video { position: absolute; inset: 0; width: 100%; height: 100%; display: block; object-fit: cover; }
.flowstudio .fs-stress-cell-no,
.flowstudio .fs-stress-cell-state { position: absolute; z-index: 1; top: 4px; padding: 2px 5px; color: #FFFFFF; background: rgba(6, 8, 9, .72); border: 1px solid rgba(255, 255, 255, .1); border-radius: 3px; font: 700 7px/1.2 'DM Mono', monospace; font-variant-numeric: tabular-nums; }
.flowstudio .fs-stress-cell-no { left: 4px; }
.flowstudio .fs-stress-cell-state { right: 4px; max-width: calc(100% - 38px); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.flowstudio .fs-stress-cell-copy { min-width: 0; display: grid; gap: 2px; padding: 7px 7px 5px; }
.flowstudio .fs-stress-cell-copy b,
.flowstudio .fs-stress-action { min-width: 0; overflow: hidden; color: #d9dcdf; text-overflow: ellipsis; white-space: nowrap; font: 650 9px 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-stress-cell-copy small,
.flowstudio .fs-stress-shot { color: var(--fs-text-dim); overflow-wrap: anywhere; font: 500 8px/1.35 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-stress-action { margin: 0; padding: 6px 7px 2px; white-space: normal; overflow-wrap: anywhere; line-height: 1.35; }
.flowstudio .fs-stress-flags { display: flex; flex-wrap: wrap; gap: 3px; margin-top: 3px; }
.flowstudio .fs-stress-cell > .fs-stress-flags { margin: 3px 7px 6px; }
.flowstudio .fs-stress-flag { max-width: 100%; overflow: hidden; padding: 2px 4px; color: #b8c8d8; background: rgba(110, 168, 254, .06); border: 1px solid rgba(110, 168, 254, .17); border-radius: 3px; text-overflow: ellipsis; white-space: nowrap; font: 600 7px/1.2 'DM Mono', monospace; }
.flowstudio .fs-stress-generate { min-height: 27px; margin: auto 7px 6px; padding: 5px 6px; color: #8adfff; background: rgba(55, 200, 255, .06); border: 1px solid rgba(55, 200, 255, .28); border-radius: 5px; cursor: pointer; font: 700 8px 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-stress-generate:hover:not(:disabled) { background: rgba(55, 200, 255, .13); border-color: rgba(55, 200, 255, .52); }
.flowstudio .fs-stress-generate:disabled { opacity: .4; cursor: not-allowed; }
.flowstudio .fs-stress-verdict { display: grid; grid-template-columns: 1fr 1fr; gap: 4px; padding: 0 7px 7px; }
.flowstudio .fs-stress-verdict button { min-width: 0; min-height: 25px; padding: 4px; color: var(--fs-text-dim); background: rgba(255, 255, 255, .025); border: 1px solid rgba(255, 255, 255, .09); border-radius: 4px; cursor: pointer; font: 700 8px 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-stress-verdict button:hover:not(:disabled) { color: var(--fs-text); border-color: rgba(255, 255, 255, .2); }
.flowstudio .fs-stress-verdict button.is-pass,
.flowstudio .fs-stress-verdict button[data-verdict='pass'][aria-pressed='true'] { color: #9bf0cd; background: rgba(0, 255, 127, .08); border-color: rgba(0, 255, 127, .34); }
.flowstudio .fs-stress-verdict button.is-fail,
.flowstudio .fs-stress-verdict button[data-verdict='fail'][aria-pressed='true'] { color: #ffc2c6; background: rgba(224, 85, 95, .075); border-color: rgba(224, 85, 95, .36); }
.flowstudio .fs-stress-verdict button:disabled { opacity: .42; cursor: not-allowed; }
.flowstudio .fs-stress-failure-wrap { display: grid; gap: 3px; padding: 0 7px 6px; color: var(--fs-text-dim); font: 700 7px 'FlowStudio Pretendard', sans-serif; letter-spacing: .08em; text-transform: uppercase; }
.flowstudio .fs-stress-verdict > .fs-stress-failure-wrap { grid-column: 1 / -1; padding: 3px 0 0; }
.flowstudio .fs-stress-failure { box-sizing: border-box; width: 100%; min-width: 0; height: 27px; padding: 3px 5px; color: #FFFFFF; background: #181a1d; border: 1px solid rgba(224, 85, 95, .26); border-radius: 4px; font: 600 8px 'FlowStudio Pretendard', sans-serif; text-transform: none; }
.flowstudio .fs-stress-guidance { margin: 0 7px 7px; padding: 6px; color: #e7ce9a; background: rgba(246, 183, 67, .055); border-left: 2px solid rgba(246, 183, 67, .42); border-radius: 0 4px 4px 0; overflow-wrap: anywhere; font: 500 8px/1.4 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-stress-failure-wrap .fs-stress-guidance { margin: 0; text-transform: none; letter-spacing: 0; }
.flowstudio .fs-stress-note { min-height: 44px; resize: vertical; text-transform: none; letter-spacing: 0; }
.flowstudio .fs-stress-requote { margin: 0 7px 6px; padding: 5px 7px; color: #f2d59c; background: rgba(246, 183, 67, .06); border: 1px solid rgba(246, 183, 67, .3); border-radius: 5px; cursor: pointer; font: 700 8px 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-stress-requote:hover:not(:disabled) { background: rgba(246, 183, 67, .13); border-color: rgba(246, 183, 67, .55); }
.flowstudio .fs-stress-requote:disabled { opacity: .4; cursor: not-allowed; }
.flowstudio .fs-stress-context { display: grid; gap: 7px; padding: 8px; background: rgba(0, 0, 0, .14); border: 1px solid rgba(255, 255, 255, .07); border-radius: 6px; }
.flowstudio .fs-stress-context > small { color: var(--fs-text-dim); font: 500 8px/1.4 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-stress-cocharacters { min-height: 58px; }
.flowstudio .fs-stress-history { display: grid; gap: 5px; margin-top: 9px; }
.flowstudio .fs-stress-history-head { display: flex; align-items: center; gap: 7px; color: var(--fs-text-dim); font: 700 8px 'FlowStudio Pretendard', sans-serif; letter-spacing: .1em; text-transform: uppercase; }
.flowstudio .fs-stress-history-head::after { height: 1px; flex: 1 1 0; content: ''; background: linear-gradient(90deg, rgba(255, 255, 255, .08), transparent); }
.flowstudio .fs-stress-history-list { display: grid; gap: 4px; margin: 0; padding: 0; list-style: none; }
.flowstudio .fs-stress-history-row { min-width: 0; display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 3px 8px; align-items: center; padding: 6px 7px; color: var(--fs-text-mute); background: rgba(255, 255, 255, .025); border: 1px solid rgba(255, 255, 255, .065); border-radius: 5px; font: 500 9px/1.35 'FlowStudio Pretendard', sans-serif; }
.flowstudio button.fs-stress-history-row { width: 100%; cursor: pointer; text-align: left; }
.flowstudio .fs-stress-history-row b { min-width: 0; overflow: hidden; color: #d6d8db; text-overflow: ellipsis; white-space: nowrap; font-weight: 650; }
.flowstudio .fs-stress-history-row strong { color: #9bf0cd; font: 700 9px 'DM Mono', monospace; font-variant-numeric: tabular-nums; }
.flowstudio .fs-stress-history-row small { grid-column: 1 / -1; color: var(--fs-text-dim); font: 500 8px 'DM Mono', monospace; }

/* Server-owned cinema readiness. Gold distinguishes earned qualification from
   Flow's green mutation controls; neither treatment resembles a toggle. */
.flowstudio .fs-node-cinema-ready { max-width: 92px; min-height: 18px; display: inline-flex; align-items: center; gap: 4px; margin-left: auto; padding: 2px 6px; overflow: hidden; color: #ffe3a2; background: rgba(246, 183, 67, .1); border: 1px solid rgba(246, 183, 67, .38); border-radius: 999px; box-shadow: rgba(246, 183, 67, .12) 0 0 10px; text-overflow: ellipsis; white-space: nowrap; font: 750 7px/1 'DM Mono', monospace; letter-spacing: .04em; text-transform: uppercase; }
.flowstudio .fs-node-cinema-ready::before { flex: 0 0 auto; content: '\25C6'; color: #f6b743; font-size: 6px; }
.flowstudio .fs-node-cinema-ready ~ .fs-node-close { margin-left: 0; }
.flowstudio .fs-cinema-status { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 8px; align-items: center; margin: 0 0 8px; padding: 8px 9px; color: var(--fs-text-mute); background: rgba(255, 255, 255, .025); border: 1px solid rgba(255, 255, 255, .09); border-radius: 6px; }
.flowstudio .fs-cinema-status-mark { width: 24px; height: 24px; display: grid; place-items: center; color: var(--fs-text-dim); background: rgba(255, 255, 255, .04); border: 1px solid rgba(255, 255, 255, .1); border-radius: 50%; font: 700 9px 'DM Mono', monospace; }
.flowstudio .fs-cinema-status-copy { min-width: 0; display: grid; gap: 2px; }
.flowstudio .fs-cinema-status-copy b { color: #d6d8db; font: 650 10px 'Outfit', sans-serif; }
.flowstudio .fs-cinema-status-copy small { color: var(--fs-text-dim); overflow-wrap: anywhere; font: 500 9px/1.4 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-cinema-status.is-ready { color: #ffe3a2; background: rgba(246, 183, 67, .065); border-color: rgba(246, 183, 67, .3); }
.flowstudio .fs-cinema-status.is-ready .fs-cinema-status-mark { color: #241a04; background: #f6b743; border-color: #f6b743; box-shadow: rgba(246, 183, 67, .18) 0 0 12px; }
.flowstudio .fs-cinema-status.is-ready .fs-cinema-status-copy b { color: #ffe3a2; }
.flowstudio .fs-cinema-status.is-missing { border-color: rgba(255, 255, 255, .08); }
.flowstudio .fs-cinema-ready-badge { width: fit-content; max-width: 100%; display: inline-flex; align-items: center; gap: 5px; padding: 3px 7px; color: #ffe3a2; background: rgba(246, 183, 67, .08); border: 1px solid rgba(246, 183, 67, .3); border-radius: 999px; font: 700 8px/1.2 'DM Mono', monospace; letter-spacing: .04em; text-transform: uppercase; }

/* Author-level display rules above otherwise outrank the browser's [hidden]
   stylesheet for flex/grid components. */
.flowstudio .fs-prep-card[hidden],
.flowstudio .fs-recipe-card[hidden],
.flowstudio .fs-frame-picker[hidden],
.flowstudio .fs-frame-selected[hidden],
.flowstudio .fs-frame-canvas[hidden],
.flowstudio .fs-frame-error[hidden],
.flowstudio .fs-stress-run[hidden],
.flowstudio .fs-stress-failure-wrap[hidden],
.flowstudio .fs-stress-guidance[hidden],
.flowstudio .fs-cinema-status[hidden],
.flowstudio .fs-node-cinema-ready[hidden] { display: none; }

/* The global focus ring covers native controls; these composite cards need a
   slightly wider ring so it remains visible against their accented borders. */
.flowstudio .fs-prep-card-head:focus-visible,
.flowstudio .fs-recipe-card-head:focus-visible,
.flowstudio .fs-education-link:focus-visible,
.flowstudio .fs-stress-choice:focus-visible,
.flowstudio .fs-stress-history-row:focus-visible { outline: 2px solid var(--fs-green); outline-offset: 2px; }

/* Assistant multiple-choice chips (composer log) */
/* Multiple choice = a numbered list, one option per line (owner 2026-08-29);
   1-4 / ↑↓ / Enter pick from the keyboard while the input is empty. */
.flowstudio .fs-choice-row { grid-column: 2; display: grid; gap: 2px; min-width: 0; margin: 4px 0 2px; }
.flowstudio .fs-choice-chip { display: grid; grid-template-columns: 18px minmax(0, 1fr); align-items: center; column-gap: 8px; width: 100%; padding: 4px 10px 4px 6px; color: #00FF7F; background: transparent; border: 1px solid transparent; border-radius: 6px; text-align: left; cursor: pointer; font: 500 12px 'DM Mono', monospace; letter-spacing: .005em; transition: background .14s, border-color .14s; }
.flowstudio .fs-choice-chip kbd { display: grid; place-items: center; width: 18px; height: 18px; color: rgba(0, 255, 127, .8); background: rgba(0, 255, 127, .1); border: 1px solid rgba(0, 255, 127, .3); border-radius: 4px; font: 600 9px 'DM Mono', monospace; }
.flowstudio .fs-choice-chip span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.flowstudio .fs-choice-chip:hover, .flowstudio .fs-choice-chip.is-active { background: rgba(0, 255, 127, .1); border-color: rgba(0, 255, 127, .35); }
.flowstudio .fs-choice-chip:disabled { opacity: .45; cursor: default; }
.flowstudio .fs-choice-chip.picked { opacity: 1; background: rgba(0, 255, 127, .18); border-color: rgba(0, 255, 127, .6); color: #eafff4; }
/* A send accepted while the AD is mid-turn: dimmed until its turn drains. */
.flowstudio .fs-ln.is-queued { opacity: .45; transition: opacity .3s; }
/* Idea-mode suggestion pills: .fs-ln-act weight, a wrapping row of them.
   No kbd affordance on purpose — suggestion pills claim no keyboard. */
.flowstudio .fs-suggest-row { grid-column: 2; display: flex; flex-wrap: wrap; gap: 5px; min-width: 0; margin: 5px 0 2px; }
.flowstudio .fs-suggest-pill { max-width: 100%; padding: 3px 10px; overflow: hidden; color: rgba(0, 255, 127, .85); background: transparent; border: 1px solid rgba(0, 255, 127, .3); border-radius: 999px; cursor: pointer; font: 500 11px 'DM Mono', monospace; letter-spacing: .01em; text-overflow: ellipsis; white-space: nowrap; transition: background .14s, border-color .14s; }
.flowstudio .fs-suggest-pill:hover { background: rgba(0, 255, 127, .1); border-color: rgba(0, 255, 127, .5); }
.flowstudio .fs-suggest-pill.picked { color: #eafff4; background: rgba(0, 255, 127, .18); border-color: rgba(0, 255, 127, .6); }
.flowstudio .fs-suggest-pill:disabled { cursor: default; }
.flowstudio .fs-suggest-row.decided .fs-suggest-pill:not(.picked) { opacity: .4; }
.flowstudio .fs-prompt-input::placeholder { color: #7c7c7c; }
/* Find-in-field (owner 2026-09-10): a slim find row above every long inspector
   text field, and a highlight layer painted OVER the textarea — a mirror of
   its text with <mark>s, transparent glyphs, pointer-events none, scrolled in
   step. The textarea keeps its own look; the host only positions the layer. */
.flowstudio .fs-find { display: flex; align-items: center; gap: 6px; margin: 0 0 6px; }
.flowstudio .fs-find-input { flex: 1 1 auto; min-width: 0; height: 26px; padding: 0 8px 0 24px; color: #FFFFFF; background: rgb(24, 25, 28) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%237c7c7c' stroke-width='2.4' stroke-linecap='round'%3E%3Ccircle cx='10.5' cy='10.5' r='6.5'/%3E%3Cpath d='M20 20l-4.6-4.6'/%3E%3C/svg%3E") 7px 50% / 12px 12px no-repeat; border: 1px solid rgba(255, 255, 255, .12); border-radius: 5px; font: 500 11px 'DM Mono', monospace; transition: border-color .16s, box-shadow .16s; }
.flowstudio .fs-find-input::placeholder { color: #7c7c7c; }
.flowstudio .fs-find-input::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }
.flowstudio .fs-find-input:focus { outline: none; border-color: var(--insp-accent, rgb(0, 255, 127)); box-shadow: rgba(var(--insp-accent-rgb, 0, 255, 127), .22) 0 0 0 3px; }
.flowstudio .fs-find-count { flex: 0 0 auto; min-width: 46px; text-align: right; color: #7c7c7c; font: 500 10px 'DM Mono', monospace; white-space: nowrap; }
.flowstudio .fs-find-count.is-none { color: #e0555f; }
.flowstudio .fs-find-nav { flex: 0 0 auto; width: 24px; height: 24px; padding: 0; color: #cfd2d6; background: rgb(24, 25, 28); border: 1px solid rgba(255, 255, 255, .12); border-radius: 5px; cursor: pointer; font: 700 9px 'FlowStudio Pretendard', sans-serif; line-height: 1; }
.flowstudio .fs-find-nav:hover:not(:disabled) { border-color: rgba(255, 255, 255, .3); color: #FFFFFF; }
.flowstudio .fs-find-nav:disabled { opacity: .4; cursor: default; }
/* Up / down arrows (owner 2026-09-17): line chevrons in the ‹ › family, drawn in
   CSS so the buttons carry no glyph and every site shares one stroke — the find
   bar's prev/next, the MEDIA INPUTS / CLIP ORDER / shot-strip move buttons and
   the margin steppers. Dropdown carets (▾ ▸) are not arrows and keep their glyph.
   A bordered square turned 45°; the translate re-centres the V, whose weight sits
   toward its apex. */
.flowstudio .fs-find-nav, .flowstudio .fs-input-move button, .flowstudio .fs-edit-steps button { display: grid; place-items: center; }
.flowstudio .fs-find-nav::before, .flowstudio .fs-input-move button::before, .flowstudio .fs-edit-steps button::before { content: ''; display: block; width: 6px; height: 6px; border: solid currentColor; border-width: 0 1.6px 1.6px 0; transform: translateY(2px) rotate(-135deg); }
.flowstudio .fs-find-next::before, .flowstudio .fs-input-move button:last-child::before, .flowstudio .fs-edit-steps button[data-dir="-1"]::before { transform: translateY(-2px) rotate(45deg); }
.flowstudio .fs-input-move button::before { width: 5px; height: 5px; border-width: 0 1.5px 1.5px 0; }
.flowstudio .fs-edit-steps button::before { width: 4px; height: 4px; border-width: 0 1.4px 1.4px 0; transform: translateY(1.5px) rotate(-135deg); }
.flowstudio .fs-edit-steps button[data-dir="-1"]::before { transform: translateY(-1.5px) rotate(45deg); }
.flowstudio .fs-find-host { position: relative; }
.flowstudio .fs-find-host > textarea { position: relative; z-index: 1; display: block; }
.flowstudio .fs-find-mirror { position: absolute; top: 0; left: 0; right: 0; bottom: 0; z-index: 2; overflow: hidden; pointer-events: none; color: transparent; white-space: pre-wrap; overflow-wrap: break-word; word-break: normal; border-radius: 6px; margin: 0; }
.flowstudio .fs-find-mirror[hidden] { display: none; }
.flowstudio .fs-find-mirror mark { color: transparent; background: rgba(var(--insp-accent-rgb, 0, 255, 127), .28); border-radius: 2px; }
.flowstudio .fs-find-mirror mark.is-active { background: rgba(255, 196, 0, .5); box-shadow: 0 0 0 1px rgba(255, 196, 0, .9); }
.flowstudio .fs-spawn-enhancer {
  width: 100%;
  min-height: 34px;
  margin-top: 8px;
  padding: 7px 10px;
  color: var(--fs-green);
  background: rgba(0, 255, 127, .07);
  border: 1px solid rgba(0, 255, 127, .3);
  border-radius: 6px;
  cursor: pointer;
  white-space: normal;
  overflow-wrap: anywhere;
  font: 700 10px/1.3 'FlowStudio Pretendard', sans-serif;
  letter-spacing: .04em;
  transition: background .14s ease, border-color .14s ease, box-shadow .14s ease;
}
.flowstudio .fs-spawn-enhancer:hover { background: rgba(0, 255, 127, .13); border-color: rgba(0, 255, 127, .58); box-shadow: 0 0 14px rgba(0, 255, 127, .14); }
.flowstudio .fs-prompt-action { margin-top: 14px; }
/* FULL VIEW (owner 2026-09-18): the inspector's FIRST item for the generator,
   the Storyboard and the Timeline — full width, in GENERATE's clothes, in the
   node's own colour (--insp-accent), above the run row. */
.flowstudio .fs-fullview-section { margin: 0 0 14px; }
/* The Storyboard's sits above its tab strip, outside the body: the body's side padding, by hand. */
.flowstudio .fs-inspector > .fs-fullview-section { flex: 0 0 auto; margin: 16px 18px 6px; }
.flowstudio .fs-insp-fullview { width: 100%; height: 42px; display: inline-flex; align-items: center; justify-content: center; gap: 8px; color: rgb(5, 36, 24); background: linear-gradient(105deg, rgb(var(--insp-accent-rgb, 0, 255, 127)) 0%, color-mix(in srgb, rgb(var(--insp-accent-rgb, 0, 255, 127)) 64%, #fff) 50%, rgb(var(--insp-accent-rgb, 0, 255, 127)) 100%) 0 0 / 220% 100%; border: 0; border-radius: 8px; box-shadow: rgba(255, 255, 255, .28) 0 1px 0 inset, rgba(var(--insp-accent-rgb, 0, 255, 127), .24) 0 4px 14px; cursor: pointer; font: 700 14px 'Outfit', sans-serif; letter-spacing: .06em; text-transform: uppercase; transition: background-position .4s; }
.flowstudio .fs-insp-fullview:hover { background-position: 100% 0; }
.flowstudio .fs-insp-fullview svg { width: 15px; height: 15px; display: block; }
.flowstudio .fs-prompt-generate { width: 100%; height: 42px; display: inline-flex; align-items: center; justify-content: center; gap: 8px; color: rgb(5, 36, 24); background: linear-gradient(105deg, rgb(0, 255, 127) 0%, rgb(92, 242, 177) 50%, rgb(0, 255, 127) 100%) 0 0 / 220% 100%; border: 0; border-radius: 8px; box-shadow: rgba(255, 255, 255, .28) 0 1px 0 inset, rgba(0, 255, 127, .24) 0 4px 14px; cursor: pointer; font: 700 14px 'Outfit', sans-serif; letter-spacing: .06em; text-transform: uppercase; transition: background-position .4s; }
.flowstudio .fs-prompt-generate:hover { background-position: 100% 0; }
.flowstudio .fs-prompt-generate .icon { font-size: 14px; }
.flowstudio .fs-section-title { margin: 0 0 10px; color: #7c7c7c; font: 700 10px 'FlowStudio Pretendard', sans-serif; letter-spacing: .14em; text-transform: uppercase; }
.flowstudio .fs-param-field { margin-bottom: 10px; }
.flowstudio .fs-param-label { display: flex; align-items: center; gap: 6px; margin-bottom: 5px; }
.flowstudio .fs-param-label code,
.flowstudio .fs-check-row code { color: var(--insp-accent, #00FF7F); font: 600 11px 'DM Mono', monospace; }
.flowstudio .fs-param-label .value { margin-left: auto; color: #a6a8ac; font: 600 11px 'FlowStudio Pretendard', sans-serif; font-variant-numeric: tabular-nums; }
.flowstudio .fs-param-chips { display: flex; flex-wrap: wrap; gap: 4px; }
.flowstudio .fs-param-chips button { height: 26px; padding: 0 11px; color: #a6a8ac; background: linear-gradient(rgb(37, 39, 43), rgb(28, 29, 32)); border: 1px solid rgba(255, 255, 255, .06); border-radius: 5px; box-shadow: rgba(255, 255, 255, .03) 0 1px 0 inset, rgba(0, 0, 0, .2) 0 2px 4px; cursor: pointer; font: 600 12px 'FlowStudio Pretendard', sans-serif; font-variant-numeric: tabular-nums; transition: .14s; }
.flowstudio .fs-param-chips button:hover { color: #FFFFFF; border-color: rgba(255, 255, 255, .16); }
.flowstudio .fs-param-chips button.on { color: var(--insp-accent, rgb(0, 255, 127)); background: linear-gradient(rgba(var(--insp-accent-rgb, 0, 255, 127), .18) 0%, rgba(var(--insp-accent-rgb, 0, 255, 127), .06) 100%); border-color: var(--insp-accent, rgb(0, 255, 127)); box-shadow: rgba(255, 255, 255, .06) 0 1px 0 inset, rgba(var(--insp-accent-rgb, 0, 255, 127), .3) 0 0 12px, rgba(0, 0, 0, .3) 0 2px 4px; }
.flowstudio .fs-check-row { width: 100%; min-height: 30px; display: flex; align-items: center; gap: 10px; margin-bottom: 10px; padding: 0; color: #a6a8ac; background: transparent; border: 0; cursor: pointer; text-align: left; }
.flowstudio .fs-check-row i { width: 16px; height: 16px; display: grid; place-items: center; flex: 0 0 auto; color: transparent; background: #25272c; border: 1px solid rgba(255, 255, 255, .11); border-radius: 3px; font-style: normal; }
.flowstudio .fs-check-row i svg { opacity: 0; }
.flowstudio .fs-check-row.on i { color: #06090c; background: var(--insp-accent, rgb(0, 255, 127)); border-color: var(--insp-accent, rgb(0, 255, 127)); box-shadow: rgba(255, 255, 255, .3) 0 1px 0 inset, rgba(0, 0, 0, .25) 0 -1px 0 inset, rgba(var(--insp-accent-rgb, 0, 255, 127), .4) 0 0 10px; }
.flowstudio .fs-check-row.on i svg { opacity: 1; }
.flowstudio .fs-param-slider { height: 30px; display: flex; align-items: center; outline: 0; }
.flowstudio .fs-param-slider .track { position: relative; width: 100%; height: 5px; background: linear-gradient(rgb(14, 15, 18), rgb(22, 23, 26)); border-radius: 3px; box-shadow: rgba(0, 0, 0, .6) 0 1px 3px inset, rgba(255, 255, 255, .03) 0 1px 0; cursor: pointer; touch-action: none; }
.flowstudio .fs-param-slider .fill { position: absolute; top: 0; bottom: 0; left: 0; border-radius: 3px; background: var(--insp-accent, rgb(0, 255, 127)); box-shadow: rgba(var(--insp-accent-rgb, 0, 255, 127), .35) 0 0 10px; }
.flowstudio .fs-param-slider .knob { position: absolute; top: 50%; width: 14px; height: 14px; border-radius: 50%; background: radial-gradient(circle at 30% 30%, #fff 0%, rgb(216, 216, 216) 60%, rgb(157, 157, 157) 100%); box-shadow: rgba(255, 255, 255, .08) 0 0 0 3px, rgba(0, 0, 0, .55) 0 2px 6px, rgba(255, 255, 255, .5) 0 1px 0 inset; transform: translate(-50%, -50%); }
.flowstudio .fs-param-slider:focus-visible .track { box-shadow: rgba(0, 0, 0, .6) 0 1px 3px inset, rgba(var(--insp-accent-rgb, 0, 255, 127), .22) 0 0 0 3px; }
/* Step legend under a labelled slider. space-between puts the first and last
   labels flush with the ends of the track, so each label reads as the step it
   names; the active one is the readout (there is no separate value chip). */
.flowstudio .fs-param-ticks { display: flex; justify-content: space-between; gap: 4px; margin-top: -4px; }
.flowstudio .fs-param-ticks span { min-width: 0; color: var(--fs-text-32); text-align: center; white-space: nowrap; font: 500 11px 'FlowStudio Pretendard', sans-serif; transition: color .14s ease; }
.flowstudio .fs-param-ticks span:first-child { text-align: left; }
.flowstudio .fs-param-ticks span:last-child { text-align: right; }
.flowstudio .fs-param-ticks span.on { color: var(--fs-green); font-weight: 700; }
.flowstudio .fs-param-select { position: relative; }
.flowstudio .fs-param-select-button { width: 100%; height: 30px; display: flex; align-items: center; gap: 8px; padding: 0 10px; color: #FFFFFF; background: #25272c; border: 1px solid rgba(255, 255, 255, .05); border-radius: 6px; cursor: pointer; text-align: left; font: 500 12px 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-param-select-button:hover,
.flowstudio .fs-param-select.open .fs-param-select-button { border-color: rgba(255, 255, 255, .11); }
.flowstudio .fs-param-select-button .selected { flex: 1 1 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.flowstudio .fs-param-select-button .chevron { color: #a6a8ac; font-size: 10px; }
.flowstudio .fs-param-select-popover { position: absolute; z-index: 50; top: 34px; right: 0; left: 0; max-height: 248px; overflow: auto; padding: 4px; background: #1e1e22; border: 1px solid rgba(255, 255, 255, .11); border-radius: 8px; box-shadow: rgba(0, 0, 0, .55) 0 12px 32px; }
.flowstudio .fs-param-select-popover[hidden] { display: none; }
.flowstudio .fs-param-option { width: 100%; display: block; padding: 7px 9px; overflow: hidden; color: #FFFFFF; background: transparent; border: 0; border-radius: 5px; cursor: pointer; text-align: left; text-overflow: ellipsis; white-space: nowrap; font: 500 12px 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-param-option:hover { background: #25272c; }
.flowstudio .fs-param-option.on { color: #00FF7F; }
/* Inspector twins of the node-face two-level menu. */
.flowstudio .fs-param-group-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; width: 100%; padding: 7px 9px; color: rgba(240, 241, 243, .55); background: transparent; border: 0; border-radius: 5px; cursor: pointer; text-align: left; font: 600 11px 'FlowStudio Pretendard', sans-serif; letter-spacing: .06em; text-transform: uppercase; }
.flowstudio .fs-param-group-head:hover { background: #25272c; color: rgba(240, 241, 243, .85); }
.flowstudio .fs-param-group-head i { font-style: normal; font-size: 9px; opacity: .6; transition: transform .12s ease; }
.flowstudio .fs-param-group-head.open i { transform: rotate(90deg); }
.flowstudio .fs-param-group-head.open { color: #FFFFFF; }
.flowstudio .fs-param-group-head.has-current span { color: #00FF7F; }
.flowstudio .fs-param-group-body[hidden] { display: none; }
.flowstudio .fs-param-option.in-group { padding-left: 22px; }
/* Rows became [art?, label] flex so UI A's tile art can lead the label;
   ellipsis moves onto the label span. */
.flowstudio .fs-param-option { display: flex; align-items: center; gap: 10px; white-space: nowrap; }

/* The Assistant Director sits in an explicit layer ladder instead of tying
   with the panels at 100 and letting DOM order decide:
     canvas nodes < composer IDLE (90) < panels (100) < composer ACTIVE (120)
     < gallery/manager (130) < previews/modals.
   And it centers on the VISIBLE canvas, not the board box: the open panels
   are absolute overlays that cover the board's edges (left panel covers
   264−56 = 208px of it, right panel 376−14 = 362px), so a plain left: 50%
   reads off-center the moment either panel is open. The cover vars slide the
   anchor to the middle of what the user can actually see, animated with the
   same fold curve the panels use. */
/* A tour step that expands a surface must not be measured mid-animation:
   the spotlight would paint the collapsed rect, then jump to the expanded
   one, and the user sees the step twice (owner 2026-09-01). */
.flowstudio.fs-tour-on .fs-composer,
.flowstudio.fs-tour-on .fs-left-panel,
.flowstudio.fs-tour-on .fs-right-panel,
.flowstudio.fs-tour-on .fs-tl-row { transition: none !important; }
.flowstudio .fs-composer { position: absolute; z-index: 90; bottom: 36px; left: calc(var(--fs-cover-l, 0px) + (100% - var(--fs-cover-l, 0px) - var(--fs-cover-r, 0px)) / 2); width: 320px; max-width: calc(100% - 80px); display: flex; flex-direction: column; color: rgba(232, 230, 222, .92); pointer-events: auto; transform: translateX(-50%); transition: width .36s cubic-bezier(.4, 0, .2, 1), left .36s cubic-bezier(.4, 0, .2, 1); }
/* The composer NEVER shrinks to fit the gap the panels leave. Idle, it keeps
   its natural width at the visible span's center — and when the panels crowd
   it, it simply sits BEHIND them (z 90 under their 100) until made active;
   a squeezed one-word-wide column was worse than a partly covered bar. OPEN,
   it takes its full size, centers on the whole canvas, and paints ABOVE the
   panels (engaged z 120): zeroing the covers restores the centering to
   full-canvas math, and the `left` transition makes the slide between the
   two centers follow the panel fold curve. Geometry is keyed to .open alone,
   never :hover — an element that moves away from under the cursor on hover
   un-hovers itself and oscillates. */
.flowstudio.left-open .fs-composer { --fs-cover-l: calc(var(--fs-left-w, 264px) - 56px); }
.flowstudio.right-open .fs-composer { --fs-cover-r: calc(var(--fs-right-w, 376px) - 14px); }
/* AFTER the cover-setters on purpose: specificity ties at (0,3,0), so file
   order is the tiebreak — placed above them this rule is dead. */
/* Owner 2026-08-29: the expanded terminal keeps the MINI state's centre (the
   visible-canvas centre) — it used to re-centre on the whole canvas, so it
   slid sideways while growing. Width and left now share one curve too. */
/* Active = engaged: hovered, focused into (clicked), or holding the open chat.
   Engaged it rises above both panels so the conversation is never read
   through the inspector; idle it tucks back underneath them. */
.flowstudio .fs-composer:hover,
.flowstudio .fs-composer:focus-within,
.flowstudio .fs-composer.open { z-index: 120; }
/* The first-run navigation chooser is dismissible; the visible assistant
   character must remain a usable entry point before the composer is opened. */
.flowstudio:has(.fs-nav-sheet:not([hidden])) .fs-composer { z-index: 121; }
/* Owner 2026-09-09: the open terminal was too small — wider, and about half
   the workspace tall (the log below carries the height). */
.flowstudio .fs-composer.open { width: 880px; }
/* Assistant-active glow = the same Comet Aura (handoff 2026-08-28): blur 9px /
   inset -2px so the halo hugs the larger surface; the dark ::after cover below
   keeps the interior dark. The old rainbow + hue-rotate spin is gone — that
   cycled colours in place instead of orbiting a head. */
/* Terminal aura = two layers (owner 2026-08-28): a WIDE masked container whose
   interior is cut out at the card edge, holding the ORIGINAL thin gradient
   (inset -2, blur 9). The blur spills softly outward inside the wide box
   (nothing clips it), the hole keeps the spectrum out of the see-through
   terminal body. One pseudo-element could not do both — a mask clips its
   own blur. */
.flowstudio .fs-composer-aura { position: absolute; inset: -40px; padding: 40px; z-index: -1; opacity: 0; pointer-events: none; border-radius: 999px; transition: opacity .32s cubic-bezier(.4, 0, .2, 1), border-radius .36s cubic-bezier(.4, 0, .2, 1); -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); -webkit-mask-composite: xor; mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); mask-composite: exclude; }
.flowstudio .fs-composer.open .fs-composer-aura { border-radius: 70px; }
.flowstudio .fs-composer-aura i { position: absolute; inset: 38px; display: block; border-radius: 999px; transition: border-radius .36s cubic-bezier(.4, 0, .2, 1), inset .3s ease, filter .3s ease; background: conic-gradient(from var(--fs-aura-a), rgba(0, 255, 127, .62) 0%, rgba(0, 255, 127, .72) 8%, rgba(200, 255, 235, .95) 14%, rgba(255, 255, 255, 1) 17%, rgba(180, 240, 255, .9) 20%, rgba(12, 184, 224, .62) 32%, rgba(140, 130, 255, .45) 44%, rgba(180, 120, 255, .3) 55%, rgba(120, 140, 200, .18) 63%, rgba(90, 150, 160, .12) 67%, rgba(70, 170, 150, .18) 72%, rgba(50, 190, 145, .28) 80%, rgba(30, 210, 140, .4) 88%, rgba(0, 255, 127, .52) 95%, rgba(0, 255, 127, .62) 100%); filter: blur(9px) brightness(1.3); }
.flowstudio .fs-composer.open .fs-composer-aura { opacity: 1; }
.flowstudio .fs-composer.open .fs-composer-aura i { animation: fs-aura-rotate 2.6s linear infinite, fs-aura-pulse 2s ease-in-out infinite; }
/* Thinking (owner 2026-09-09): while the Assistant Director's LLM turn runs
   (.is-busy, set by the composer's sync) the ring paints on the MINIMIZED
   pill too, so a collapsed terminal still says "working". Only the EXPANDED
   card steps the ring out a few px and brightens it (owner 2026-09-11): the
   pill keeps the normal-size ring. `.open` alone keeps the calm ring. */
.flowstudio .fs-composer.is-busy .fs-composer-aura { opacity: 1; }
.flowstudio .fs-composer.is-busy .fs-composer-aura i { animation: fs-aura-rotate 2.6s linear infinite, fs-aura-pulse 2s ease-in-out infinite; }
.flowstudio .fs-composer.open.is-busy .fs-composer-aura i { inset: 33px; filter: blur(12px) brightness(1.65); }
/* See-through frosted cover (owner 2026-08-28): the canvas reads through the terminal; the aura above is a ring, so no spectrum inside. */
.flowstudio .fs-composer::after { content: ''; position: absolute; z-index: -1; inset: 0; pointer-events: none; background: rgba(10, 11, 13, .58); backdrop-filter: blur(14px) saturate(1.2); -webkit-backdrop-filter: blur(14px) saturate(1.2); border-radius: 999px; transition: border-radius .36s cubic-bezier(.4, 0, .2, 1); }
.flowstudio .fs-composer.open::after { border-radius: 30px; }
/* ── '#' node mention picker ──────────────────────────────────────────────── */
/* Sits ABOVE the bar (bottom:100%) — the composer is anchored to the bottom of
   the board, so a downward list would open off-screen. */
.flowstudio .fs-mention-pop { position: absolute; left: 12px; right: 12px; bottom: 100%; margin-bottom: 8px; z-index: 30; max-height: 244px; overflow-y: auto; display: flex; flex-direction: column; gap: 2px; padding: 6px; background: var(--fs-panel); border: 1px solid var(--fs-line-strong); border-radius: 12px; box-shadow: 0 18px 44px rgba(0, 0, 0, .55); }
.flowstudio .fs-mention-pop[hidden] { display: none; }
.flowstudio .fs-mention-row { display: flex; align-items: center; gap: 9px; width: 100%; padding: 7px 10px; border: 0; border-radius: 8px; background: transparent; color: var(--fs-text); font: 500 13px 'FlowStudio Pretendard', sans-serif; text-align: left; cursor: pointer; }
.flowstudio .fs-mention-row.on { background: rgba(0, 255, 127, .14); }
.flowstudio .fs-mention-row i { width: 7px; height: 7px; flex: 0 0 auto; border-radius: 50%; }
/* '@' reference rows carry the image itself instead of the accent dot */
.flowstudio .fs-mention-row i.thumb { width: 22px; height: 22px; border-radius: 5px; background-size: cover; background-position: center; box-shadow: 0 0 0 1px rgba(0, 0, 0, .4) inset; }
.flowstudio .fs-mention-row span { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.flowstudio .fs-mention-row small { flex: 0 0 auto; color: var(--fs-text-dim); font: 500 11px 'DM Mono', monospace; }
.flowstudio .fs-mention-row.on small { color: var(--fs-green); }

.flowstudio .fs-composer-card { overflow: hidden; display: flex; flex-direction: column; background: rgba(18, 20, 24, .36); border: 1px solid rgba(255, 255, 255, .1); border-radius: 999px; box-shadow: 0 20px 50px rgba(0, 0, 0, .55), 0 3px 10px rgba(0, 0, 0, .3), inset 0 1px 0 rgba(255, 255, 255, .08); backdrop-filter: blur(18px) saturate(1.5); transition: border-radius .36s cubic-bezier(.4, 0, .2, 1); }
/* Rounder when open (owner 2026-08-30). */
.flowstudio .fs-composer.open .fs-composer-card { border-radius: 30px; }
.flowstudio .fs-composer.open .fs-composer-aura i { border-radius: 32px; }
/* The console sets body { user-select: none } globally with per-surface
   opt-ins (inputs, .terminal-msg — UI A's chat got this same fix once).
   The AD conversation is exactly such a surface: its questions and answers
   must be selectable and copyable. The .prefix glyph column stays opted
   out, so a copied answer doesn't drag '>' and '#' along with it. */
.flowstudio .fs-composer-log { user-select: text; -webkit-user-select: text; cursor: text; flex: 0 0 auto; min-height: 0; max-height: 0; overflow-y: auto; display: flex; flex-direction: column; gap: 4px; padding: 0 18px; opacity: 0; scrollbar-color: rgba(255, 255, 255, .16) transparent; scrollbar-width: thin; font: 400 13px/1.55 'DM Mono', monospace; letter-spacing: .005em; transition: max-height .36s cubic-bezier(.4, 0, .2, 1), padding .36s cubic-bezier(.4, 0, .2, 1), opacity .24s; }
/* Owner 2026-08-30: the first line used to sit under the All/Chat/Log +
   lock/close row (26px top padding vs a 38px chrome row). Top padding now
   clears the row; min-height keeps a one-line terminal from opening cramped,
   with short logs gathering at the bottom (first child margin-top:auto — the
   flex-end recipe that keeps the top reachable once the log scrolls). */
.flowstudio .fs-composer.open .fs-composer-log { min-height: calc(50vh - 120px); max-height: calc(50vh - 120px); padding: 44px 18px 8px; opacity: 1; transition: min-height .36s cubic-bezier(.4, 0, .2, 1), max-height .36s cubic-bezier(.4, 0, .2, 1), padding .36s cubic-bezier(.4, 0, .2, 1), opacity .24s .06s;
  /* Scrolled-away lines fade into the card instead of hard-cropping at the
     top edge — a vignette, not a guillotine. The 44px top padding (owner
     2026-08-30) keeps the first line clear of the filter / lock / close row;
     the fade band reaches BELOW that row (owner 2026-09-03: the old 46px
     stop left scrolled text legible behind the buttons) — invisible through
     the row's top, a quarter at its baseline, full only at 84px. */
  -webkit-mask-image: linear-gradient(to bottom, transparent 16px, rgba(0, 0, 0, .25) 44px, #000 84px);
  mask-image: linear-gradient(to bottom, transparent 16px, rgba(0, 0, 0, .25) 44px, #000 84px); }
.flowstudio .fs-composer-log > :first-child { margin-top: auto; }
/* View filter (owner 2026-08-29): chat = you + the assistant; log = the ✓/✕ action lines. */
.flowstudio .fs-composer[data-filter="chat"] .fs-ln-notice, .flowstudio .fs-composer[data-filter="chat"] .fs-ln-sys.is-log { display: none; }
.flowstudio .fs-composer[data-filter="log"] .fs-ln-user, .flowstudio .fs-composer[data-filter="log"] .fs-ln-ai { display: none; }
.flowstudio .fs-composer-filter { position: absolute; z-index: 2; top: 14px; right: 108px; display: flex; gap: 2px; padding: 2px; background: rgba(255, 255, 255, .06); border-radius: 999px; opacity: 0; pointer-events: none; transform: scale(.8); transition: opacity .2s, transform .24s cubic-bezier(.22, 1, .36, 1); }
.flowstudio .fs-composer.open .fs-composer-filter { opacity: 1; pointer-events: auto; transform: scale(1); transition: opacity .2s .18s, transform .32s cubic-bezier(.22, 1, .36, 1) .16s; }
.flowstudio .fs-composer-filter button { height: 20px; padding: 0 9px; color: rgba(232, 230, 222, .55); background: transparent; border: 0; border-radius: 999px; cursor: pointer; font: 600 9px 'DM Mono', monospace; letter-spacing: .08em; text-transform: uppercase; }
.flowstudio .fs-composer-filter button:hover { color: #fff; }
.flowstudio .fs-composer-filter button.on { color: var(--fs-green); background: rgba(0, 255, 127, .14); }
.flowstudio .fs-composer-log::-webkit-scrollbar { width: 6px; }
.flowstudio .fs-composer-log::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, .14); border-radius: 3px; }
.flowstudio .fs-ln { display: grid; grid-template-columns: 18px 1fr; gap: 10px; animation: fs-chat-line-in .26s cubic-bezier(.22, 1, .36, 1); }
.flowstudio .fs-ln .prefix { opacity: .85; user-select: none; text-align: right; font-weight: 600; }
.flowstudio .fs-ln .text { white-space: pre-wrap; word-break: break-word; }
.flowstudio .fs-ln-user .prefix { color: rgba(0, 255, 127, .78); }
.flowstudio .fs-ln-user .text { color: rgba(244, 242, 234, .96); }
.flowstudio .fs-ln-ai .prefix { color: rgba(232, 230, 222, .42); }
.flowstudio .fs-ln-ai .text { color: rgba(232, 230, 222, .88); }
.flowstudio .fs-ln-sys .prefix { color: rgba(232, 230, 222, .26); }
.flowstudio .fs-ln-sys .text { color: rgba(232, 230, 222, .42); font-size: 13px; font-style: italic; }
/* Notification lines — toasts landing in the terminal (see showFlowToast /
   the toast relocator): green information, red errors. */
.flowstudio .fs-ln-notice.is-ok .prefix,
.flowstudio .fs-ln-notice.is-ok .text { color: #00FF7F; }
.flowstudio .fs-ln-notice.is-error .prefix,
.flowstudio .fs-ln-notice.is-error .text { color: #ff8b95; }
/* Guidance hints (onboarding, owner 2026-08-29): softer than a ✓ line, with an
   optional once-only chip ("tips off") after the text. */
.flowstudio .fs-ln-notice.is-hint .prefix,
.flowstudio .fs-ln-notice.is-hint .text { color: #9fd9c1; }
.flowstudio .fs-ln-notice.is-hint { grid-template-columns: 18px minmax(0, 1fr) auto; }
.flowstudio .fs-ln-act { margin-left: 8px; padding: 1px 8px; color: rgba(232, 230, 222, .6); background: transparent; border: 1px solid rgba(255, 255, 255, .14); border-radius: 999px; cursor: pointer; font: 600 9px 'DM Mono', monospace; letter-spacing: .06em; text-transform: uppercase; white-space: nowrap; }
.flowstudio .fs-ln-act:hover { color: #fff; border-color: rgba(255, 255, 255, .3); }
.flowstudio .fs-ln-act:disabled { opacity: .4; cursor: default; }
/* Per-message copy — absolute so the chat grid never reflows; the reserved
   right padding keeps long paragraphs from running under the button. */
.flowstudio .fs-ln.has-copy { position: relative; padding-right: 26px; }
.flowstudio .fs-ln-copy { position: absolute; top: -1px; right: 0; width: 20px; height: 20px; display: grid; place-items: center; padding: 0; background: rgba(20, 22, 26, .6); border: 1px solid rgba(255, 255, 255, .12); border-radius: 6px; color: rgba(232, 230, 222, .66); font: 500 11px 'DM Mono', monospace; cursor: pointer; opacity: 0; user-select: none; -webkit-user-select: none; transition: opacity .14s, color .14s, border-color .14s; }
.flowstudio .fs-ln.has-copy:hover .fs-ln-copy, .flowstudio .fs-ln-copy:focus-visible { opacity: 1; }
.flowstudio .fs-ln-copy:hover { color: #fff; border-color: rgba(255, 255, 255, .26); }
.flowstudio .fs-ln-copy.copied { opacity: 1; color: #00FF7F; border-color: rgba(0, 255, 127, .5); }
.flowstudio .fs-typing { display: inline-flex; gap: 4px; vertical-align: middle; }
.flowstudio .fs-typing > span { width: 4px; height: 4px; display: inline-block; border-radius: 50%; background: rgba(232, 230, 222, .5); animation: fs-chat-typing 1.2s ease-in-out infinite; }
.flowstudio .fs-typing > span:nth-child(2) { animation-delay: .16s; }
.flowstudio .fs-typing > span:nth-child(3) { animation-delay: .32s; }
.flowstudio .fs-composer-bar { flex: 0 0 auto; min-height: 44px; box-sizing: border-box; display: flex; align-items: center; gap: 10px; padding: 8px 16px; border-top: 1px solid transparent; transition: border-color .36s, padding .36s cubic-bezier(.4, 0, .2, 1), min-height .36s cubic-bezier(.4, 0, .2, 1); }
.flowstudio .fs-composer.open .fs-composer-bar { min-height: 64px; padding: 16px 20px 16px 14px; border-top-color: rgba(255, 255, 255, .06); }
.flowstudio .fs-composer-logo { width: 34px; height: 34px; display: inline-flex; align-self: center; align-items: center; justify-content: center; flex: 0 0 auto; margin-left: -4px; overflow: visible; transition: width .4s cubic-bezier(.22, 1, .36, 1), height .4s cubic-bezier(.22, 1, .36, 1); }
/* A click on the character is a wink, not a control (owner 2026-09-10): the arrow cursor stays. */
.flowstudio .fs-composer-logo { cursor: default; }
.flowstudio .fs-composer.open .fs-composer-logo { width: 44px; height: 44px; }
.flowstudio .fs-composer-logo img { width: 28px; height: 28px; display: block; margin: auto; object-fit: contain; opacity: .92; transition: width .4s cubic-bezier(.22, 1, .36, 1), height .4s cubic-bezier(.22, 1, .36, 1); }
.flowstudio .fs-composer.open .fs-composer-logo img { width: 36px; height: 36px; }
.flowstudio .fs-composer-prompt { width: 0; margin-left: -2px; overflow: hidden; color: rgba(0, 255, 127, .78); opacity: 0; user-select: none; font: 700 15px 'DM Mono', monospace; transition: width .24s, opacity .2s, margin-left .24s; }
.flowstudio .fs-composer.open .fs-composer-prompt { width: 12px; margin-left: 0; opacity: 1; }
.flowstudio .fs-composer-input { min-width: 0; max-height: 200px; flex: 1 1 0; overflow-y: auto; padding: 0; resize: none; color: rgba(244, 242, 234, .96); caret-color: rgba(0, 255, 127, .95); background: transparent; border: 0; outline: 0; font: 500 15px/1.4 'DM Mono', monospace; letter-spacing: .005em; }
.flowstudio .fs-composer textarea:focus { outline: none; }
.flowstudio .fs-composer.closed .fs-composer-input { font: 500 12px 'FlowStudio Pretendard', 'Outfit', sans-serif; letter-spacing: 0; }
.flowstudio .fs-composer-input::placeholder { color: rgba(232, 230, 222, .4); font-weight: 400; }
/* Minimized draft preview: a textarea cannot ellipsize, a span can. When
   the closed bar holds a draft, the textarea hides and this shows exactly
   one line + … — clicking it reopens the composer with the caret at the
   end of the draft. */
.flowstudio .fs-composer-mini { display: block; flex: 1 1 0; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: rgba(244, 242, 234, .96); cursor: text; font: 500 12px 'FlowStudio Pretendard', 'Outfit', sans-serif; }
.flowstudio .fs-composer-mini[hidden] { display: none; }
.flowstudio .fs-composer-input.mini-hidden { display: none; }
.flowstudio .fs-chat-btn { flex: 0 0 auto; padding: 7px 13px; color: rgba(232, 230, 222, .75); background: rgba(255, 255, 255, .06); border: 1px solid rgba(255, 255, 255, .14); border-radius: 8px; cursor: pointer; font: 600 10px 'DM Mono', monospace; letter-spacing: .08em; transition: .18s; }
.flowstudio .fs-chat-btn.chat:hover { color: #fff; border-color: rgba(255, 255, 255, .3); }
.flowstudio .fs-chat-btn.chat.disabled { opacity: .35; pointer-events: none; }
.flowstudio .fs-chat-btn.chat span { margin-left: 2px; opacity: .55; }
.flowstudio .fs-chat-btn.gen { min-height: 32px; display: inline-flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px; padding: 4px 12px 3px; color: rgb(10, 8, 5); background: rgb(0, 255, 127); border-color: rgb(0, 255, 127); line-height: 1; }
.flowstudio .fs-chat-btn.gen b { font: inherit; font-weight: 700; line-height: 1; }
.flowstudio .fs-chat-btn.gen small { color: inherit; opacity: .65; font: 600 9px/1 'DM Mono', monospace; letter-spacing: .06em; }
.flowstudio .fs-chat-btn.gen:hover { background: rgb(61, 240, 160); border-color: rgb(61, 240, 160); }
.flowstudio .fs-chat-btn.gen.disabled { opacity: .35; pointer-events: none; }
.flowstudio .fs-composer:not(.open) .fs-chat-btn { display: none; }
.flowstudio .fs-composer-close { position: absolute; z-index: 2; top: 14px; right: 16px; width: 24px; height: 24px; display: grid; place-items: center; padding: 0; color: rgba(232, 230, 222, .55); background: rgba(255, 255, 255, .06); border: 0; border-radius: 50%; opacity: 0; pointer-events: none; cursor: pointer; transform: scale(.8); font: 500 14px/1 'FlowStudio Pretendard', sans-serif; transition: opacity .2s, transform .24s cubic-bezier(.22, 1, .36, 1), background .16s; }
.flowstudio .fs-composer-lock { position: absolute; z-index: 2; top: 14px; right: 46px; width: 24px; height: 24px; display: grid; place-items: center; padding: 0; color: rgba(232, 230, 222, .55); background: rgba(255, 255, 255, .06); border: 0; border-radius: 50%; opacity: 0; pointer-events: none; cursor: pointer; transform: scale(.8); font: 500 14px/1 'FlowStudio Pretendard', sans-serif; transition: opacity .2s, transform .24s cubic-bezier(.22, 1, .36, 1), background .16s; }
.flowstudio .fs-composer.open .fs-composer-lock { opacity: 1; pointer-events: auto; transform: scale(1); transition: opacity .2s .18s, transform .32s cubic-bezier(.22, 1, .36, 1) .16s, background .16s; }
/* Clear (owner 2026-09-08): third header control, left of the padlock — the workspace's conversation, via the /clear confirm row. */
.flowstudio .fs-composer-clear { position: absolute; z-index: 2; top: 14px; right: 76px; width: 24px; height: 24px; display: grid; place-items: center; padding: 0; color: rgba(232, 230, 222, .55); background: rgba(255, 255, 255, .06); border: 0; border-radius: 50%; opacity: 0; pointer-events: none; cursor: pointer; transform: scale(.8); transition: opacity .2s, transform .24s cubic-bezier(.22, 1, .36, 1), background .16s; }
.flowstudio .fs-composer-clear svg { width: 12px; height: 12px; display: block; }
.flowstudio .fs-composer.open .fs-composer-clear { opacity: 1; pointer-events: auto; transform: scale(1); transition: opacity .2s .18s, transform .32s cubic-bezier(.22, 1, .36, 1) .16s, background .16s; }
.flowstudio .fs-composer-clear:hover { color: #ff6f61; background: rgba(255, 111, 97, .16); }
.flowstudio .fs-composer-lock svg { width: 12px; height: 12px; display: block; }
.flowstudio .fs-composer-lock .ic-locked { display: none; }
/* Locked (owner 2026-08-29): the terminal ignores click-away and Esc; the
   padlock turns green and closes its shackle. × still closes (and unlocks). */
.flowstudio .fs-composer.locked .fs-composer-lock { color: var(--fs-green); background: rgba(0, 255, 127, .14); }
.flowstudio .fs-composer.locked .fs-composer-lock .ic-open { display: none; }
.flowstudio .fs-composer.locked .fs-composer-lock .ic-locked { display: block; }
.flowstudio .fs-composer.open .fs-composer-close { opacity: 1; pointer-events: auto; transform: scale(1); transition: opacity .2s .18s, transform .32s cubic-bezier(.22, 1, .36, 1) .16s, background .16s; }
.flowstudio .fs-composer-close:hover { color: #fff; background: rgba(255, 255, 255, .14); }
.flowstudio .fs-composer-confirm { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin: 7px 0; padding: 8px 9px; color: var(--fs-text-75); background: rgba(0, 255, 127, .06); border: 1px solid rgba(0, 255, 127, .22); border-radius: 7px; font: 500 12px/1.4 'DM Mono', monospace; }
.flowstudio .fs-composer-confirm.video { background: rgba(255, 111, 97, .06); border-color: rgba(255, 111, 97, .25); }
.flowstudio .fs-composer-confirm > div { display: flex; flex: 0 0 auto; gap: 5px; }
.flowstudio .fs-composer-confirm button { padding: 5px 7px; color: var(--fs-text-60); background: rgba(255, 255, 255, .04); border: 1px solid var(--fs-line-strong); border-radius: 5px; cursor: pointer; font: 600 9px 'DM Mono', monospace; }
.flowstudio .fs-composer-confirm button.go { min-height: 32px; display: inline-flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px; padding: 4px 7px 3px; color: #06180f; background: var(--fs-green); border-color: var(--fs-green); line-height: 1; }
.flowstudio .fs-composer-confirm button.go b { font: inherit; font-weight: 700; line-height: 1; }
.flowstudio .fs-composer-confirm button.go small { color: inherit; opacity: .65; font: 600 8px/1 'DM Mono', monospace; letter-spacing: .04em; }
.flowstudio .fs-composer-confirm.done { opacity: .6; }
/* Left/Right confirm-key highlight (class-only — never real focus). GO is a
   solid green block, so its highlight is a ring; CANCEL lifts like a hover. */
.flowstudio .fs-composer-confirm:not(.done) button.is-active { border-color: #00FF7F; box-shadow: 0 0 0 1px rgba(0, 255, 127, .55), 0 0 8px rgba(0, 255, 127, .3); }
.flowstudio .fs-composer-confirm:not(.done) button.cancel.is-active { color: #fff; background: rgba(255, 255, 255, .1); }
/* Confirm-row model picker: the chip is spliced into the confirm sentence (at
   the template's {m} slot); the drop-UP menu reuses the fs-gen-dropdown look
   but is anchored to the COMPOSER root (the card's overflow:hidden would clip
   a menu inside the log) — left/bottom are set inline at open time. */
.flowstudio .fs-composer-confirm .fs-confirm-model { display: inline-flex; align-items: center; gap: 4px; margin: -2px 1px; padding: 1px 6px 2px; vertical-align: -1px; color: inherit; background: rgba(255, 255, 255, .05); border: 1px solid var(--fs-line-strong); border-radius: 5px; cursor: pointer; font: 600 11px/1.3 'DM Mono', monospace; }
.flowstudio .fs-composer-confirm .fs-confirm-model i { font-size: 8px; font-style: normal; opacity: .55; }
.flowstudio .fs-composer-confirm .fs-confirm-model:hover { color: #fff; border-color: rgba(255, 255, 255, .32); }
.flowstudio .fs-composer-confirm .fs-confirm-model.open { border-color: #00FF7F; box-shadow: 0 0 8px rgba(0, 255, 127, .25); }
.flowstudio .fs-confirm-menu { z-index: 120; }

.fs-full-preview { position: absolute; inset: 0; z-index: 800; display: grid; place-items: center; padding: 16px; background: rgba(4, 5, 6, .94); backdrop-filter: blur(9px); }
.fs-full-preview[hidden] { display: none; }

/* ── Full-screen Inpaint mode ───────────────────────────────────────────────
   Same tier as the full preview (800): both fill the viewport, both are opened
   from something inside the board, and both must sit above the gallery (130)
   and below the context menu (900). Deliberately NOT a new tier — the ladder
   in handleEscape is ordered by these numbers, and inventing a level between
   them is how a layer ends up needing two Escapes to close.
   Amber, not the studio green: this is the Inpaint node's accent, so the big
   editor reads as the same tool the inspector was showing. */
/* The same layer and window the Projects and Media browsers use (owner
   2026-09-12): one overlay shape for every full-screen surface. */
/* The POST-PRODUCTION key colour is the standing default here, so the window
   is never amber even for the frame before openInpaintStage writes the node's
   own accent over it. Every rule inside reads --insp-accent; nothing in this
   layer should carry a hue of its own. */
.fs-inpaint-back { position: absolute; inset: 0; z-index: 800; display: grid; place-items: center; padding: 24px; background: rgba(0, 0, 0, .72); backdrop-filter: blur(8px); --insp-accent: #a855d8; --insp-accent-rgb: 168, 85, 216; }
.fs-inpaint-back[hidden] { display: none; }
/* The card HUGS the fitted picture (owner 2026-09-02 — a full-bleed card
   left the image floating between dead bands while the footer overflowed the
   viewport). sizeInpaintStage measures the LAYER, subtracts the header and
   footer, fits the picture, and writes explicit pixels; the card then wraps
   that content and the layer's grid centres it. Every pixel the chrome needs
   is inside the browser, and the margins around the picture are the padding
   and nothing else.
   The fit is measured in JS instead of expressed as `aspect-ratio` + auto
   width/height: .fs-edit-preview holds nothing but absolutely-positioned
   children, so it has no intrinsic size and would collapse in a grid cell. */
.fs-inpaint-card { position: relative; width: 80vw; max-width: 100%; min-width: min(100%, 320px); height: 80vh; height: 80dvh; max-height: 100%; display: flex; flex-direction: column; background: #0c0e10; border: 1px solid var(--fs-line-strong); border-radius: 14px; box-shadow: 0 26px 70px rgba(0, 0, 0, .75); overflow: hidden; }
.fs-inpaint-card header { flex: 0 0 auto; height: 44px; display: flex; align-items: center; gap: 10px; padding: 0 12px 0 16px; border-bottom: 1px solid var(--fs-line); }
.fs-inpaint-card header b { color: var(--insp-accent, #f6b743); font: 700 12px 'Outfit', sans-serif; letter-spacing: .06em; text-transform: uppercase; }
.fs-inpaint-source { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--fs-text-mute); font: 500 10px 'DM Mono', monospace; }
.flowstudio .fs-inpaint-close { width: 28px; height: 28px; color: var(--fs-text-60); background: transparent; border: 0; cursor: pointer; font-size: 18px; }
.flowstudio .fs-inpaint-close:hover { color: var(--fs-text); }
.fs-inpaint-stage { flex: 1 1 auto; min-height: 0; display: grid; place-items: center; padding: 6px; }
/* The frame is the shared .fs-edit-preview. The panel's rule pins it to
   width:100% with a 16/9 aspect-ratio and a bottom margin, none of which belong
   here — sizeInpaintStage writes explicit pixels instead, so `aspect-ratio:auto`
   must clear the inherited one or it fights the measured height. */
.flowstudio .fs-inpaint-stage .fs-edit-preview { margin: 0; max-width: 100%; max-height: 100%; }
/* Sized by its rows — a fixed 52px was built for the single-row footer and
   clipped the two-row + Done layout out of the viewport (owner report). */
.flowstudio .fs-inpaint-card footer { flex: 0 0 auto; height: auto; margin: 0; padding: 6px 14px 8px; border-top: 1px solid var(--fs-line); }
/* Shaping gets a row of its own rather than a place on the brush line: that
   line already carries four controls, and full-screen is the surface with room
   to see the edge these two sliders move. Shorter than the brush row, so the
   picture gives up as little height as possible. */
/* The toolbar is the panel's brush row, so it inherits its slider, Undo and
   Clear verbatim; only Done is new. */
.flowstudio .fs-inpaint-card .fs-inpaint-done { margin-left: 4px; padding: 5px 14px; color: #06120c; background: var(--insp-accent, #f6b743); border: 1px solid var(--insp-accent, #f6b743); border-radius: 6px; cursor: pointer; font: 700 10px 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-inpaint-card .fs-inpaint-done:hover { filter: brightness(1.08); }
/* A phone is where the small frame hurt most, and it has no room to spare for a
   floating card: drop the inset and the chrome so the picture gets the glass. */
@media (max-width: 720px) {
  .fs-inpaint-back { padding: 0; }
  .fs-inpaint-card { border: 0; border-radius: 0; }
}
/* The shell takes the MEDIA's shape, not a frozen landscape one. It used to be
   `min(1120px, 92vw) x min(720px, 82vh)` — a hardcoded ~1.56:1 box with
   overflow:hidden, which silently clipped 551px off the top AND bottom of a 4K
   bible and 672px off a 9:16 sheet. --fs-pv-ar (w/h) and --fs-pv-natw (natural
   width, so a small image is never upscaled) are written by showFullPreview.
   78px = 2*16px overlay padding + 44px header + 2px border — keep in step with
   the padding above and the header height below. */
/* Browse arrows - only visible when the preview was opened from the Media
   panel with an ordered list behind it. */
.fs-full-preview .fs-preview-prev,
.fs-full-preview .fs-preview-next { position: absolute; top: calc(50% + 22px); transform: translateY(-50%); z-index: 3; width: 44px; height: 44px; display: grid; place-items: center; padding: 0; color: rgba(240, 241, 243, .85); background: rgba(8, 10, 12, .72); border: 1px solid var(--fs-line-strong); border-radius: 50%; cursor: pointer; font: 400 24px/1 'DM Mono', monospace; opacity: .75; transition: opacity .14s, color .14s, border-color .14s; }
.fs-full-preview .fs-preview-prev { left: 10px; }
.fs-full-preview .fs-preview-next { right: 10px; }
/* display:grid above beats the UA [hidden] rule — restore it, or the arrows
   sit on every preview (result nodes, sheets) and do nothing. (Audit 2026-08-29.) */
.fs-full-preview .fs-preview-prev[hidden],
.fs-full-preview .fs-preview-next[hidden] { display: none; }
.fs-full-preview .fs-preview-prev:hover,
.fs-full-preview .fs-preview-next:hover { opacity: 1; color: var(--fs-green); border-color: rgba(0, 255, 127, .55); }
/* The shell's width comes from its HEIGHT — available × aspect — so the
   height had better be the one it actually gets. `100vh - 78px` was neither:
   this layer covers the studio stage, not the viewport, and viewport units
   ignore the UI zoom. Too tall a picture then scrolled inside the stage
   instead of shrinking (owner 2026-09-12: "shrink to fit the whole image
   rather than showing a scroll bar"). sizePreviewShellBox MEASURES the layer
   and writes --fs-pv-avail in layout px; the vh form is only the fallback for
   the frame before the first measurement. */
.fs-full-preview > div { position: relative;
  --fs-pv-ar: 1.6;
  --fs-pv-natw: 100000px;
  width: min(100%, var(--fs-pv-natw), calc(var(--fs-pv-avail, calc(100vh - 78px)) * var(--fs-pv-ar)));
  height: auto;
  max-height: 100%;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: #0c0e10;
  border: 1px solid var(--fs-line-strong);
  border-radius: 10px;
  box-shadow: 0 26px 70px rgba(0, 0, 0, .75);
}
/* Document mode — a storyboard board or production bible. Fitting a 3840x6000
   sheet entirely would render it 469px wide, an unreadable sliver, so these fit
   the WIDTH and scroll instead. Keyed off the node being boardLike, never off
   aspect: the bible is 0.64 and a 9:16 frame is 0.5625, so any ratio threshold
   sorts them backwards. */
.fs-full-preview > div.is-doc { width: min(100%, var(--fs-pv-natw), 1280px); height: 100%; }
/* Vault previews carry a details rail: media + 300px. The rail never appears
   in is-doc mode (sheets need the full width), so the two never compose. */
.fs-full-preview > div.has-details { width: min(100%, calc(var(--fs-pv-natw) + 300px), calc(var(--fs-pv-avail, calc(100vh - 78px)) * var(--fs-pv-ar) + 300px)); }
.fs-pv-body { flex: 1 1 auto; min-height: 0; display: flex; }
.fs-pv-body section { flex: 1 1 auto; }
/* ── The details rail: the item's prompt and settings, read-only ── */
/* The rail = a fixed actions bar on top + a scrolling details area below (owner
   2026-09-06). The 300px width, border and background live on the side; the
   details area owns the scroll. */
.fs-pv-side { flex: 0 0 300px; min-height: 0; display: flex; flex-direction: column; border-left: 1px solid var(--fs-line); background: rgba(255, 255, 255, .015); }
.fs-pv-side[hidden] { display: none; }
.fs-pv-details { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 14px; }
/* Rounded metadata boxes (owner 2026-08-28): each block is a card with real
   margins; section titles centred in green; COPY pinned to the right. */
.fs-pv-details .fs-prov-model { margin: 0 0 12px; padding: 12px 14px; border: 1px solid rgba(255, 255, 255, .1); border-radius: 10px; background: rgba(255, 255, 255, .03); }
.fs-pv-details .fs-form-section { margin: 12px 0 0; padding: 12px 14px; border: 1px solid rgba(255, 255, 255, .1); border-radius: 10px; background: rgba(255, 255, 255, .03); }
/* 3-column head: title dead-centre, COPY in its own right column — no overlap
   (owner 2026-08-28). */
/* The card is a centred flex column — stretch the head to the card width or
   the 3-column grid collapses to its content and COPY hugs the title. */
.flowstudio .fs-pv-details .fs-form-section { display: flex; flex-direction: column; align-items: stretch; gap: 6px; }
.flowstudio .fs-pv-details .fs-section-head { width: 100%; display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; margin-bottom: 0; color: var(--fs-green); }
.fs-pv-details .fs-section-head b { grid-column: 2; }
.fs-pv-details .fs-section-head .line { display: none; }
.fs-pv-details .fs-section-head .fs-pv-copy { grid-column: 3; justify-self: end; position: static; transform: none; }
.fs-pv-details .fs-prov-grid { gap: 8px 12px; }
/* The small PROMPT label sits right under the card title — no extra gap. */
.flowstudio .fs-pv-details .fs-pv-prompt-grid { gap: 4px 12px; }
.flowstudio .fs-pv-details .fs-pv-prompt-grid code { margin-top: 0; }
/* The prompt text (what COPY copies) reads left-aligned, unlike the
   right-aligned parameter values. */
.flowstudio .fs-pv-details .fs-pv-prompt-grid span { text-align: left; }
/* Prompt rows hold prose, not chips — let values wrap into paragraphs. */
.flowstudio .fs-pv-prompt-grid { grid-template-columns: 1fr; }
.flowstudio .fs-pv-prompt-grid code { margin-top: 6px; }
/* Long prompts scroll inside their own dark rail (owner 2026-08-27) instead
   of pushing the parameters below the fold. */
.flowstudio .fs-pv-prompt-grid span { white-space: pre-wrap; overflow-wrap: anywhere; max-height: 200px; overflow-y: auto; overscroll-behavior: contain; scrollbar-width: thin; scrollbar-color: rgba(255, 255, 255, .16) transparent; }
.flowstudio .fs-pv-prompt-grid span::-webkit-scrollbar { width: 6px; }
.flowstudio .fs-pv-prompt-grid span::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, .16); border-radius: 999px; }
.flowstudio .fs-pv-prompt-grid span::-webkit-scrollbar-track { background: transparent; }
/* Copy-the-prompt, at the section head's right edge — quiet mono ghost in
   the panel's own palette. */
.flowstudio .fs-pv-copy { flex: 0 0 auto; padding: 2px 7px; color: var(--fs-text-32); background: transparent; border: 1px solid var(--fs-line); border-radius: 4px; cursor: pointer; font: 600 9px 'DM Mono', monospace; letter-spacing: .08em; text-transform: uppercase; transition: color .15s, border-color .15s; }
.flowstudio .fs-pv-copy:hover { color: var(--fs-green); border-color: rgba(0, 255, 127, .35); }
@media (max-width: 860px) {
  .fs-full-preview > div.has-details { width: min(100%, var(--fs-pv-natw), calc(var(--fs-pv-avail, calc(100vh - 78px)) * var(--fs-pv-ar))); }
  .fs-pv-body { flex-direction: column; overflow-y: auto; }
  .fs-pv-body section { flex: 0 0 auto; }
  .fs-pv-side { flex: 0 0 auto; max-height: 45vh; border-left: 0; border-top: 1px solid var(--fs-line); }
}
.fs-full-preview header { flex: 0 0 auto; height: 44px; display: flex; align-items: center; gap: 10px; padding: 0 12px 0 16px; border-bottom: 1px solid var(--fs-line); }
.fs-full-preview header b { font: 700 12px 'Outfit', sans-serif; }
.fs-full-preview .fs-preview-close { margin-left: auto; width: 28px; height: 28px; color: var(--fs-text-60); background: transparent; border: 0; cursor: pointer; font-size: 18px; }
/* Actions bar atop the details rail (owner 2026-09-06): the 1:1/Fit toggle and
   Load to workspace, beside the media and above the metadata — moved out of the
   header so they sit with the content they act on. */
.fs-pv-actions { flex: 0 0 auto; display: flex; flex-wrap: wrap; gap: 6px; padding: 12px 14px; border-bottom: 1px solid var(--fs-line); }
.fs-pv-actions button { padding: 6px 10px; color: var(--fs-text-60); background: rgba(255, 255, 255, .04); border: 1px solid var(--fs-line-strong); border-radius: 5px; cursor: pointer; font: 600 9px 'DM Mono', monospace; letter-spacing: .04em; }
.fs-pv-actions button[hidden] { display: none; }
/* Green, like the rest of the chrome — the popup's cyan hover predated the
   mono+key-color pass (owner consistency check 2026-08-27). */
.fs-pv-actions button:hover { color: var(--fs-green, #00FF7F); border-color: rgba(0, 255, 127, .5); }
/* 1:1/Fit reads as pressed (green) while the image is zoomed. */
.fs-pv-actions .fs-preview-zoom[aria-pressed="true"] { color: var(--fs-green, #00FF7F); border-color: rgba(0, 255, 127, .5); }
/* Load to workspace = green CTA (owner 2026-08-27), pinned to the bar's right;
   Loaded = filled quiet confirmation — the overlay stays open so the user keeps
   browsing. */
.fs-pv-actions .fs-preview-load { margin-left: auto; color: var(--fs-green, #00FF7F); border-color: rgba(0, 255, 127, .5); }
.fs-pv-actions .fs-preview-load:hover { color: #dffff1; background: rgba(0, 255, 127, .14); border-color: var(--fs-green, #00FF7F); }
.fs-pv-actions .fs-preview-load.is-loaded { color: #dffff1; background: rgba(0, 255, 127, .2); border-color: rgba(0, 255, 127, .65); }
/* `align-content: safe center`, not `center`: this is an implicit auto-track
   grid, and plain `center` stops the row stretching AND parks overflowing
   content above the scroll origin where it can never be reached (measured:
   489px permanently unscrollable). `safe` degrades to start-alignment once the
   content is taller than the box, which keeps the whole sheet reachable. */
.fs-full-preview section {
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
  overscroll-behavior: contain;
  display: grid;
  place-items: center;
  align-content: safe center;
  gap: 14px;
  color: var(--fs-text-32);
  background: radial-gradient(circle, #171b1d, #090b0d 70%);
  font: 500 10px 'DM Mono', monospace;
  scrollbar-color: rgba(255, 255, 255, .16) transparent;
  scrollbar-width: thin;
}
/* .flowstudio kills every scrollbar globally (see the reset near the top); this
   is a real scroll surface, so it opts back in — same as the composer log. */
.fs-full-preview section::-webkit-scrollbar { width: 8px; height: 8px; display: block; }
.fs-full-preview section::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, .14); border-radius: 4px; }
.fs-full-preview section svg { width: 64px; height: 64px; }
/* height:auto is the fix. `height: 100%` pinned the media to the full column
   width and let its height explode past the shell, and object-fit had nothing
   left to do because the box already matched the image's aspect. */
.fs-full-preview section img,
.fs-full-preview section video { width: 100%; height: auto; max-width: 100%; display: block; object-fit: contain; background: #050607; }
.fs-full-preview > div:not(.is-doc) section img,
.fs-full-preview > div:not(.is-doc) section video { max-height: min(100%, var(--fs-pv-avail, 100%)); }
/* Image zoom/pan (owner 2026-09-06): fit by default; scroll zooms toward 1:1
   (never past), grab-drags pan once zoomed. The stage clips while zoomed and the
   image carries the transform. transform-origin center pairs with the stage's
   place-items:center so zoom grows about the middle. */
.fs-full-preview section.is-zoomable { cursor: zoom-in; }
.fs-full-preview section.is-zoomed { overflow: hidden; cursor: grab; }
.fs-full-preview section.is-grabbing { cursor: grabbing; }
.fs-pv-img { transform-origin: center center; transition: transform .12s ease-out; will-change: transform; }
.fs-full-preview section.is-grabbing .fs-pv-img { transition: none; }

/* ── Full-preview media player (owner 2026-08-28) ─────────────────────────
   Native chrome off; FS-styled bar + centered big play. The wrap fills the
   stage so the bar pins to the video's bottom edge. */
.fs-full-preview .fs-pv-player { position: relative; width: 100%; max-height: 100%; display: flex; }
.fs-full-preview .fs-pv-player video { cursor: pointer; }
.fs-full-preview .fs-pv-bar { position: absolute; left: 0; right: 0; bottom: 0; z-index: 4; display: flex; align-items: center; gap: 10px; padding: 8px 12px; background: linear-gradient(transparent, rgba(4, 6, 5, .88) 40%); }
.fs-full-preview .fs-pv-bar button { border: 0; background: transparent; color: rgba(255, 255, 255, .85); font: 700 13px/1 'DM Mono', monospace; cursor: pointer; padding: 4px; }
.fs-full-preview .fs-pv-bar button:hover { color: var(--fs-green, #00FF7F); }
.fs-full-preview .fs-pv-time { font: 600 10px 'DM Mono', monospace; color: rgba(255, 255, 255, .65); min-width: 32px; text-align: center; }
.fs-full-preview .fs-pv-seek { flex: 1 1 auto; appearance: none; height: 4px; border-radius: 2px; background: rgba(255, 255, 255, .22); cursor: pointer; }
.fs-full-preview .fs-pv-seek::-webkit-slider-thumb { appearance: none; width: 12px; height: 12px; border-radius: 50%; background: rgba(240, 241, 243, .9); border: 0; }
.fs-full-preview .fs-pv-seek:hover::-webkit-slider-thumb { background: var(--fs-green, #00FF7F); }
.fs-full-preview .fs-pv-seek::-moz-range-thumb { width: 12px; height: 12px; border-radius: 50%; background: rgba(240, 241, 243, .9); border: 0; }
.fs-full-preview .fs-pv-seek:hover::-moz-range-thumb { background: var(--fs-green, #00FF7F); }
/* Volume: the slider unfolds on hover of the speaker button. */
.fs-full-preview .fs-pv-vol { display: inline-flex; align-items: center; gap: 4px; }
/* Always visible (owner 2026-08-28) — no hover fold. */
.fs-full-preview .fs-pv-volume { width: 72px; appearance: none; height: 4px; border-radius: 2px; background: rgba(255, 255, 255, .22); cursor: pointer; }
.fs-full-preview .fs-pv-volume::-webkit-slider-thumb { appearance: none; width: 10px; height: 10px; border-radius: 50%; background: rgba(240, 241, 243, .9); border: 0; }
.fs-full-preview .fs-pv-volume:hover::-webkit-slider-thumb { background: var(--fs-green, #00FF7F); }
.fs-full-preview .fs-pv-volume::-moz-range-thumb { width: 10px; height: 10px; border-radius: 50%; background: rgba(240, 241, 243, .9); border: 0; }
.fs-full-preview .fs-pv-player:fullscreen video { width: 100%; height: 100%; max-height: none; }

/* ── Storyboard v2 / ShotSpec production ledger ───────────────────────────
   Stable IDs and shot numbers form a quiet film-strip spine. The four card
   groups stay distinct through narrow rails, leaving findings as the signal. */
.flowstudio .fs-shot-root {
  --fs-shot-material: #8adfff;
  --fs-shot-direction: #b9a7ff;
  --fs-shot-camera: #5cf2b1;
  --fs-shot-edit: #f2d59c;
  display: grid;
  gap: 18px;
  margin-top: 22px;
  padding-top: 18px;
  border-top: 1px solid rgba(255, 255, 255, .08);
}
.flowstudio .fs-shot-section,
.flowstudio .fs-shot-login,
.flowstudio .fs-shot-sync,
.flowstudio .fs-shot-loading,
.flowstudio .fs-shot-breakdown,
.flowstudio .fs-shot-proposal,
.flowstudio .fs-shot-diff { min-width: 0; }
.flowstudio .fs-shot-section-head { min-width: 0; display: flex; align-items: baseline; justify-content: space-between; gap: 7px 12px; margin-bottom: 9px; }
.flowstudio .fs-shot-section-title { min-width: 0; color: #dfe3e6; font: 750 10px/1.2 'Outfit', sans-serif; letter-spacing: .15em; text-transform: uppercase; }
.flowstudio .fs-shot-section-title::before { width: 4px; height: 4px; display: inline-block; margin: 0 7px 2px 0; content: ''; background: var(--fs-green); border-radius: 50%; box-shadow: 0 0 8px rgba(0, 255, 127, .42); }
.flowstudio .fs-shot-section-subtitle { min-width: 0; overflow: hidden; color: var(--fs-text-dim); text-overflow: ellipsis; white-space: nowrap; font: 600 8px/1.35 'DM Mono', monospace; }
.flowstudio .fs-shot-meta { min-width: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 5px; margin: -2px 0 9px; }
.flowstudio .fs-shot-project-id { min-width: 0; flex: 1 1 auto; overflow: hidden; color: var(--fs-text-dim); text-overflow: ellipsis; white-space: nowrap; font: 600 8px/1.3 'DM Mono', monospace; }
.flowstudio .fs-shot-unsaved,
.flowstudio .fs-shot-readonly-badge,
.flowstudio .fs-shot-proposal-badge,
.flowstudio .fs-shot-dirty-dot { flex: 0 0 auto; padding: 2px 5px; color: #f4d99e; background: rgba(246, 183, 67, .07); border: 1px solid rgba(246, 183, 67, .27); border-radius: 999px; font: 750 7px/1.15 'DM Mono', monospace; letter-spacing: .05em; text-transform: uppercase; }
.flowstudio .fs-shot-readonly-badge { color: #b8c8d8; background: rgba(110, 168, 254, .06); border-color: rgba(110, 168, 254, .24); }
.flowstudio .fs-shot-proposal-badge { color: #cfc4ff; background: rgba(143, 119, 255, .07); border-color: rgba(143, 119, 255, .28); }
.flowstudio .fs-shot-list { display: grid; gap: 9px; }
.flowstudio .fs-shot-card { min-width: 0; overflow: hidden; color: var(--fs-text-mute); background: linear-gradient(145deg, rgba(255, 255, 255, .025), transparent 42%), #151719; border: 1px solid rgba(255, 255, 255, .09); border-radius: 8px; box-shadow: 0 8px 22px rgba(0, 0, 0, .11), inset 0 1px rgba(255, 255, 255, .025); }
.flowstudio .fs-shot-card[open] { border-color: rgba(255, 255, 255, .15); }
.flowstudio .fs-shot-summary { min-width: 0; min-height: 38px; display: grid; grid-template-columns: 25px minmax(0, 1fr) auto; align-items: center; gap: 7px; padding: 7px 9px; cursor: pointer; list-style: none; }
.flowstudio .fs-shot-summary::-webkit-details-marker { display: none; }
.flowstudio .fs-shot-summary::after { grid-column: 3; grid-row: 1; margin-left: 2px; color: var(--fs-text-dim); content: '\203A'; font: 700 15px/1 'DM Mono', monospace; transform: rotate(90deg); transition: transform .14s ease, color .14s ease; }
.flowstudio .fs-shot-card[open] > .fs-shot-summary::after { color: var(--fs-green); transform: rotate(-90deg); }
.flowstudio .fs-shot-summary:hover { background: rgba(255, 255, 255, .025); }
.flowstudio .fs-shot-number { width: 25px; height: 25px; display: grid; place-items: center; color: #071e15; background: linear-gradient(145deg, var(--fs-green-2), var(--fs-green)); border-radius: 5px; box-shadow: inset 0 1px rgba(255, 255, 255, .35), 0 0 11px rgba(0, 255, 127, .13); font: 800 9px/1 'DM Mono', monospace; font-variant-numeric: tabular-nums; }
.flowstudio .fs-shot-id { min-width: 0; overflow: hidden; color: #d9dcdf; text-overflow: ellipsis; white-space: nowrap; font: 650 9px/1.25 'DM Mono', monospace; }
.flowstudio .fs-shot-summary-flags { min-width: 0; grid-column: 3; grid-row: 1; display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 3px; margin-right: 14px; }
.flowstudio .fs-shot-card-body { min-width: 0; display: grid; gap: 8px; padding: 0 8px 9px 40px; border-top: 1px solid rgba(255, 255, 255, .055); }
.flowstudio .fs-shot-identity { min-width: 0; display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 2px 7px; padding: 7px 0 1px; }
.flowstudio .fs-shot-identity-label { color: var(--fs-text-dim); font: 700 7px 'FlowStudio Pretendard', sans-serif; letter-spacing: .08em; text-transform: uppercase; }
.flowstudio .fs-shot-identity-value { min-width: 0; overflow: hidden; color: #a9eccf; text-overflow: ellipsis; white-space: nowrap; font: 600 8px 'DM Mono', monospace; }
.flowstudio .fs-shot-identity-note { grid-column: 1 / -1; color: var(--fs-text-dim); font: 500 7px/1.35 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-shot-group { --fs-shot-rail: var(--fs-shot-material); position: relative; min-width: 0; display: grid; gap: 7px; padding: 8px 8px 8px 11px; background: rgba(255, 255, 255, .018); border: 1px solid rgba(255, 255, 255, .07); border-radius: 6px; }
.flowstudio .fs-shot-group::before { position: absolute; inset: 7px auto 7px 0; width: 2px; content: ''; background: var(--fs-shot-rail); border-radius: 0 2px 2px 0; opacity: .72; }
.flowstudio .fs-shot-group:nth-of-type(2) { --fs-shot-rail: var(--fs-shot-direction); }
.flowstudio .fs-shot-group:nth-of-type(3) { --fs-shot-rail: var(--fs-shot-camera); }
.flowstudio .fs-shot-group:nth-of-type(4) { --fs-shot-rail: var(--fs-shot-edit); }
.flowstudio .fs-shot-group-title,
.flowstudio .fs-shot-subhead { margin: 0; color: var(--fs-shot-rail); font: 750 8px/1.25 'Outfit', sans-serif; letter-spacing: .1em; text-transform: uppercase; }
.flowstudio .fs-shot-subhead { margin-top: 2px; color: var(--fs-text-dim); font-size: 7px; }
.flowstudio .fs-shot-field { min-width: 0; display: grid; gap: 3px; }
.flowstudio .fs-shot-field-row { min-width: 0; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; }
.flowstudio .fs-shot-field-label { min-width: 0; color: var(--fs-text-dim); overflow-wrap: anywhere; font: 650 7px/1.3 'FlowStudio Pretendard', sans-serif; letter-spacing: .04em; }
.flowstudio .fs-shot-input,
.flowstudio .fs-shot-script { box-sizing: border-box; width: 100%; min-width: 0; padding: 6px 7px; color: #e4e6e8; caret-color: var(--fs-green); background: #101214; border: 1px solid rgba(255, 255, 255, .095); border-radius: 5px; outline: 0; font: 500 9px/1.45 'FlowStudio Pretendard', sans-serif; transition: border-color .14s ease, box-shadow .14s ease; }
.flowstudio select.fs-shot-input { min-height: 29px; padding-right: 22px; }
.flowstudio textarea.fs-shot-input,
.flowstudio .fs-shot-script { resize: vertical; white-space: pre-wrap; overflow-wrap: anywhere; }
.flowstudio .fs-shot-json,
.flowstudio .fs-shot-compiled-prompt,
.flowstudio .fs-shot-diff-value { font-family: 'DM Mono', monospace; }
.flowstudio .fs-shot-input:hover:not(:disabled) { border-color: rgba(255, 255, 255, .17); }
.flowstudio .fs-shot-input:focus,
.flowstudio .fs-shot-script:focus { border-color: rgba(0, 255, 127, .52); box-shadow: 0 0 0 2px rgba(0, 255, 127, .08); }
.flowstudio .fs-shot-input:disabled,
.flowstudio .fs-shot-input[readonly],
.flowstudio .fs-shot-script:disabled { color: #a9adb1; background: rgba(8, 10, 11, .58); }
.flowstudio .fs-shot-input:disabled { opacity: .62; }
.flowstudio .fs-shot-field-error { color: #ffc2c6; font: 550 7px/1.35 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-shot-field-hint { color: var(--fs-text-dim); font: 500 7px/1.4 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-shot-checkbox { width: 16px; height: 16px; margin: 2px 0; accent-color: var(--fs-green); }
.flowstudio .fs-shot-dialogue { display: grid; gap: 6px; }
.flowstudio .fs-shot-dialogue-line { min-width: 0; display: grid; gap: 5px; padding: 6px; background: rgba(0, 0, 0, .14); border: 1px solid rgba(255, 255, 255, .065); border-radius: 5px; }
.flowstudio .fs-shot-dialogue-head { display: flex; align-items: center; gap: 5px; }
.flowstudio .fs-shot-dialogue-index { color: var(--fs-text-dim); font: 700 7px 'DM Mono', monospace; }
.flowstudio .fs-shot-lock,
.flowstudio .fs-shot-new-line { padding: 2px 4px; color: #ffe3a2; background: rgba(246, 183, 67, .07); border: 1px solid rgba(246, 183, 67, .25); border-radius: 3px; font: 750 6px/1 'DM Mono', monospace; letter-spacing: .05em; }
.flowstudio .fs-shot-new-line { color: #9bf0cd; background: rgba(0, 255, 127, .06); border-color: rgba(0, 255, 127, .24); }
.flowstudio .fs-shot-dialogue-character { font-family: 'DM Mono', monospace; }
.flowstudio .fs-shot-dialogue-add,
.flowstudio .fs-shot-dialogue-remove,
.flowstudio .fs-shot-apply-split,
.flowstudio .fs-shot-reload,
.flowstudio .fs-shot-retry { min-height: 26px; padding: 5px 7px; color: #8adfff; background: rgba(55, 200, 255, .055); border: 1px solid rgba(55, 200, 255, .25); border-radius: 5px; cursor: pointer; font: 700 8px/1.25 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-shot-dialogue-remove { color: #ffc2c6; background: rgba(224, 85, 95, .045); border-color: rgba(224, 85, 95, .22); }
.flowstudio .fs-shot-dialogue-add:hover,
.flowstudio .fs-shot-apply-split:hover,
.flowstudio .fs-shot-reload:hover,
.flowstudio .fs-shot-retry:hover { background: rgba(55, 200, 255, .12); border-color: rgba(55, 200, 255, .46); }
.flowstudio .fs-shot-slots { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; }
.flowstudio .fs-shot-slot { align-content: start; }
.flowstudio .fs-shot-compile,
.flowstudio .fs-shot-generation { min-width: 0; padding: 8px; background: rgba(0, 0, 0, .11); border: 1px solid rgba(255, 255, 255, .07); border-radius: 6px; }
.flowstudio .fs-shot-actions { display: flex; gap: 6px; }
.flowstudio .fs-shot-compile-button,
.flowstudio .fs-shot-generate,
.flowstudio .fs-shot-save,
.flowstudio .fs-shot-breakdown-run,
.flowstudio .fs-shot-proposal-accept,
.flowstudio .fs-shot-proposal-discard,
/* RED, not green (owner 2026-09-06). The Storyboard's own step accent is
   #e0555f (FLOW_STUDIO_STEPS[2]) — the panel now wears it instead of the app's
   generate-green, which read as if it belonged to the Generator. Scoped to
   .fs-shot-* , which only the Storyboard v2 panel emits, so nothing leaks. */
.flowstudio .fs-shot-login-button { width: 100%; min-height: 31px; padding: 6px 9px; color: #f3b9bf; background: rgba(224, 85, 95, .07); border: 1px solid rgba(224, 85, 95, .32); border-radius: 6px; cursor: pointer; font: 750 9px/1.25 'FlowStudio Pretendard', sans-serif; transition: background .14s ease, border-color .14s ease, opacity .14s ease; }
.flowstudio .fs-shot-compile-button { color: #8adfff; background: rgba(55, 200, 255, .055); border-color: rgba(55, 200, 255, .28); }
.flowstudio .fs-shot-generate { min-height: 34px; color: #fff; background: linear-gradient(105deg, #e0555f, #b8394e); border: 0; box-shadow: inset 0 1px rgba(255, 255, 255, .22), 0 5px 13px rgba(224, 85, 95, .2); font-family: 'Outfit', sans-serif; letter-spacing: .04em; text-transform: uppercase; }
.flowstudio .fs-shot-proposal-discard { color: var(--fs-text-mute); background: rgba(255, 255, 255, .025); border-color: rgba(255, 255, 255, .12); }
.flowstudio .fs-shot-compile-button:hover:not(:disabled),
.flowstudio .fs-shot-save:hover:not(:disabled),
.flowstudio .fs-shot-breakdown-run:hover:not(:disabled),
.flowstudio .fs-shot-proposal-accept:hover:not(:disabled),
.flowstudio .fs-shot-login-button:hover:not(:disabled) { background: rgba(224, 85, 95, .13); border-color: rgba(224, 85, 95, .55); }
.flowstudio .fs-shot-generate:hover:not(:disabled) { filter: brightness(1.06); }
.flowstudio .fs-shot-compile-button:disabled,
.flowstudio .fs-shot-generate:disabled,
.flowstudio .fs-shot-save:disabled,
.flowstudio .fs-shot-breakdown-run:disabled,
.flowstudio .fs-shot-proposal-accept:disabled,
.flowstudio .fs-shot-proposal-discard:disabled,
.flowstudio .fs-shot-login-button:disabled { opacity: .4; cursor: not-allowed; filter: none; box-shadow: none; }
.flowstudio .fs-shot-status { min-width: 0; display: flex; align-items: center; justify-content: space-between; gap: 6px; margin-top: 6px; padding: 6px 7px; color: #b8c8d8; background: rgba(110, 168, 254, .05); border: 1px solid rgba(110, 168, 254, .19); border-radius: 5px; overflow-wrap: anywhere; font: 500 8px/1.4 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-shot-status.is-ok { color: #9bf0cd; background: rgba(0, 255, 127, .05); border-color: rgba(0, 255, 127, .22); }
.flowstudio .fs-shot-status.is-error { color: #ffc2c6; background: rgba(224, 85, 95, .055); border-color: rgba(224, 85, 95, .28); }
.flowstudio .fs-shot-status-text { min-width: 0; }
.flowstudio .fs-shot-findings { display: grid; gap: 5px; margin-top: 7px; }
.flowstudio .fs-shot-finding { min-width: 0; padding: 7px 7px 7px 9px; background: rgba(246, 183, 67, .045); border: 1px solid rgba(246, 183, 67, .2); border-left: 2px solid #f6b743; border-radius: 4px; }
.flowstudio .fs-shot-finding.is-block { background: rgba(224, 85, 95, .055); border-color: rgba(224, 85, 95, .24); border-left-color: #e0555f; }
.flowstudio .fs-shot-finding-head { display: flex; flex-wrap: wrap; align-items: center; gap: 5px; }
.flowstudio .fs-shot-finding-severity { color: #f2d59c; font: 800 6px/1 'DM Mono', monospace; letter-spacing: .08em; }
.flowstudio .fs-shot-finding.is-block .fs-shot-finding-severity { color: #ffc2c6; }
.flowstudio .fs-shot-finding-code { min-width: 0; overflow: hidden; color: var(--fs-text-dim); text-overflow: ellipsis; white-space: nowrap; font: 600 7px 'DM Mono', monospace; }
.flowstudio .fs-shot-finding-copy,
.flowstudio .fs-shot-dropped-line { margin: 4px 0 0; color: #d7c49b; overflow-wrap: anywhere; font: 500 8px/1.4 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-shot-finding.is-block .fs-shot-finding-copy { color: #efc5c8; }
.flowstudio .fs-shot-dropped-line { color: #ffc2c6; }
.flowstudio .fs-shot-split-suggestion { display: grid; gap: 5px; margin-top: 7px; }
.flowstudio .fs-shot-split-item { min-width: 0; display: grid; gap: 4px; padding: 6px; color: var(--fs-text-mute); background: rgba(0, 0, 0, .14); border: 1px solid rgba(255, 255, 255, .07); border-radius: 5px; }
.flowstudio .fs-shot-split-id { color: #cfc4ff; overflow-wrap: anywhere; font: 650 7px 'DM Mono', monospace; }
.flowstudio .fs-shot-split-action,
.flowstudio .fs-shot-split-line { margin: 0; color: #d5d8db; overflow-wrap: anywhere; font: 500 8px/1.4 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-shot-split-dialogue { display: grid; gap: 2px; color: var(--fs-text-dim); font: 650 7px/1.4 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-shot-apply-split { width: 100%; margin-top: 6px; }
.flowstudio .fs-shot-compiled { margin-top: 7px; border: 1px solid rgba(255, 255, 255, .08); border-radius: 5px; }
.flowstudio .fs-shot-compiled-summary { padding: 6px 7px; color: #b8c8d8; cursor: pointer; font: 650 8px 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-shot-compiled-prompt { max-height: 220px; margin: 0; padding: 8px; overflow: auto; color: #c7cbce; background: #0b0d0e; border-top: 1px solid rgba(255, 255, 255, .07); white-space: pre-wrap; overflow-wrap: anywhere; font: 500 7px/1.55 'DM Mono', monospace; }
.flowstudio .fs-shot-repro { display: block; margin-top: 5px; color: var(--fs-text-dim); font: 600 7px/1.35 'DM Mono', monospace; }
.flowstudio .fs-shot-save-area { margin-top: 9px; }
.flowstudio .fs-shot-breakdown { padding-top: 17px; border-top: 1px dashed rgba(255, 255, 255, .09); }
.flowstudio .fs-shot-script { min-height: 150px; max-height: 42vh; }
.flowstudio .fs-shot-script-count { display: block; margin-top: 4px; color: var(--fs-text-dim); text-align: right; font: 600 7px 'DM Mono', monospace; font-variant-numeric: tabular-nums; }
.flowstudio .fs-shot-autosave-warning { margin: 7px 0; padding: 7px 8px; color: #ffe3a2; background: rgba(246, 183, 67, .055); border-left: 2px solid rgba(246, 183, 67, .58); border-radius: 0 4px 4px 0; font: 600 8px/1.45 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-shot-proposal { margin-top: 10px; padding: 8px; background: rgba(143, 119, 255, .025); border: 1px solid rgba(143, 119, 255, .17); border-radius: 7px; }
.flowstudio .fs-shot-proposal-shots { display: grid; gap: 6px; }
.flowstudio .fs-shot-proposal-shot { min-width: 0; overflow: hidden; background: rgba(0, 0, 0, .12); border: 1px solid rgba(255, 255, 255, .075); border-radius: 6px; }
.flowstudio .fs-shot-proposal-shot-summary { min-width: 0; display: grid; grid-template-columns: 25px minmax(0, 1fr); align-items: center; gap: 7px; padding: 6px; cursor: pointer; list-style: none; }
.flowstudio .fs-shot-proposal-shot-summary::-webkit-details-marker { display: none; }
.flowstudio .fs-shot-proposal-shot-body { min-width: 0; display: grid; gap: 5px; padding: 0 6px 6px; }
.flowstudio .fs-shot-proposal-group { min-width: 0; padding: 6px; background: rgba(255, 255, 255, .018); border-left: 2px solid rgba(143, 119, 255, .4); border-radius: 0 4px 4px 0; }
.flowstudio .fs-shot-proposal-value { max-height: 145px; margin: 4px 0 0; overflow: auto; color: #bfc4c8; white-space: pre-wrap; overflow-wrap: anywhere; font: 500 7px/1.5 'DM Mono', monospace; }
.flowstudio .fs-shot-proposal-actions { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, .72fr); gap: 6px; margin-top: 9px; }
.flowstudio .fs-shot-diff { margin-top: 9px; }
.flowstudio .fs-shot-diff-group { display: grid; gap: 5px; margin-top: 6px; padding-left: 7px; border-left: 2px solid rgba(255, 255, 255, .14); }
.flowstudio .fs-shot-diff-group.is-added { border-left-color: rgba(0, 255, 127, .55); }
.flowstudio .fs-shot-diff-group.is-changed { border-left-color: rgba(246, 183, 67, .55); }
.flowstudio .fs-shot-diff-group.is-removed { border-left-color: rgba(224, 85, 95, .58); }
.flowstudio .fs-shot-diff-title { margin: 0; color: var(--fs-text-dim); font: 750 7px 'DM Mono', monospace; letter-spacing: .08em; text-transform: uppercase; }
.flowstudio .fs-shot-diff-item { min-width: 0; display: grid; gap: 4px; padding: 6px; background: rgba(0, 0, 0, .12); border: 1px solid rgba(255, 255, 255, .065); border-radius: 5px; }
.flowstudio .fs-shot-diff-id { color: #d5d8db; overflow-wrap: anywhere; font: 650 7px 'DM Mono', monospace; }
.flowstudio .fs-shot-diff-summary { margin: 0; color: var(--fs-text-mute); overflow-wrap: anywhere; font: 500 8px/1.4 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-shot-diff-field { min-width: 0; display: grid; gap: 3px; padding-top: 4px; border-top: 1px solid rgba(255, 255, 255, .055); }
.flowstudio .fs-shot-diff-path { color: #f2d59c; overflow-wrap: anywhere; font: 650 7px 'DM Mono', monospace; }
.flowstudio .fs-shot-diff-values { min-width: 0; display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); gap: 4px; align-items: start; }
.flowstudio .fs-shot-diff-value { min-width: 0; max-height: 80px; overflow: auto; padding: 4px; color: #bfc4c8; background: rgba(255, 255, 255, .025); border-radius: 3px; white-space: pre-wrap; overflow-wrap: anywhere; font-size: 6px; line-height: 1.45; }
.flowstudio .fs-shot-diff-arrow { color: var(--fs-text-dim); font: 700 8px 'DM Mono', monospace; }
.flowstudio .fs-shot-empty-note,
.flowstudio .fs-shot-login-copy,
.flowstudio .fs-shot-sync-copy,
.flowstudio .fs-shot-loading-copy,
.flowstudio .fs-shot-readonly-note { margin: 0 0 8px; color: var(--fs-text-dim); overflow-wrap: anywhere; font: 500 8px/1.5 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-shot-loading-copy.is-error { color: #ffc2c6; }
.flowstudio .fs-shot-reload-warning { flex-basis: 100%; color: #efb8bb; font: 500 7px/1.4 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-shot-unsaved[hidden],
.flowstudio .fs-shot-status[hidden] { display: none; }

/* ── Cinema P5-2 / SpatialMap + iteration workbench ─────────────────────
   Geography reads like a script-supervisor continuity sheet: cool screen-left,
   warm screen-right, and a restrained luminous 180° line between them. */
.flowstudio .fs-spatial-scene-host { min-width: 0; display: grid; gap: 8px; margin-bottom: 8px; }
.flowstudio .fs-shot-geography-host,
.flowstudio .fs-shot-workbench-host { min-width: 0; }
.flowstudio .fs-spatial-section,
.flowstudio .fs-review-section,
.flowstudio .fs-spatial-login {
  --fs-geo-left: #8adfff;
  --fs-geo-right: #f2d59c;
  min-width: 0;
  padding: 11px;
  background: linear-gradient(145deg, rgba(138, 223, 255, .028), transparent 42%), #151719;
  border: 1px solid rgba(255, 255, 255, .09);
  border-radius: 8px;
  box-shadow: inset 0 1px rgba(255, 255, 255, .025);
}
.flowstudio .fs-spatial-section-head { min-width: 0; display: flex; align-items: baseline; justify-content: space-between; gap: 6px 12px; margin-bottom: 7px; }
.flowstudio .fs-spatial-section-title { min-width: 0; color: #dfe3e6; font: 750 10px/1.2 'Outfit', sans-serif; letter-spacing: .15em; text-transform: uppercase; }
.flowstudio .fs-spatial-section-title::before { width: 4px; height: 4px; display: inline-block; margin: 0 7px 2px 0; content: ''; background: var(--fs-green); border-radius: 50%; box-shadow: 0 0 8px rgba(0, 255, 127, .42); }
.flowstudio .fs-spatial-section-subtitle { min-width: 0; overflow: hidden; color: var(--fs-text-dim); text-overflow: ellipsis; white-space: nowrap; font: 600 8px/1.35 'DM Mono', monospace; }
.flowstudio .fs-spatial-intro,
.flowstudio .fs-review-intro { margin: 0 0 10px; color: var(--fs-text-dim); overflow-wrap: anywhere; font: 500 8px/1.5 'FlowStudio Pretendard', sans-serif; }

.flowstudio .fs-spatial-axis-rail {
  min-width: 0;
  display: grid;
  grid-template-columns: auto minmax(54px, 1fr) auto;
  align-items: center;
  gap: 8px;
  margin: 4px 0 10px;
  padding: 7px 9px;
  background: linear-gradient(90deg, rgba(138, 223, 255, .055), rgba(0, 255, 127, .025) 48%, rgba(242, 213, 156, .055));
  border: 1px solid rgba(255, 255, 255, .075);
  border-radius: 6px;
}
.flowstudio .fs-spatial-axis-side { color: var(--fs-text-dim); font: 750 7px/1 'DM Mono', monospace; letter-spacing: .12em; text-transform: uppercase; }
.flowstudio .fs-spatial-axis-side.is-left { color: var(--fs-geo-left); }
.flowstudio .fs-spatial-axis-side.is-right { color: var(--fs-geo-right); text-align: right; }
.flowstudio .fs-spatial-axis-line { position: relative; height: 9px; }
.flowstudio .fs-spatial-axis-line::before { position: absolute; top: 4px; right: 0; left: 0; height: 1px; content: ''; background: linear-gradient(90deg, var(--fs-geo-left), rgba(0, 255, 127, .78) 50%, var(--fs-geo-right)); box-shadow: 0 0 7px rgba(0, 255, 127, .2); }
.flowstudio .fs-spatial-axis-line::after { position: absolute; top: 0; left: 50%; width: 1px; height: 9px; content: ''; background: var(--fs-green); box-shadow: 0 0 6px rgba(0, 255, 127, .45); transform: translateX(-50%); }

.flowstudio .fs-spatial-map-controls,
.flowstudio .fs-shot-geography-controls { min-width: 0; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 7px; }
.flowstudio .fs-shot-geography-controls > .fs-spatial-field:first-child { grid-column: 1 / -1; }
.flowstudio .fs-spatial-field { min-width: 0; display: grid; align-content: start; gap: 3px; }
.flowstudio .fs-spatial-field-label { min-width: 0; color: var(--fs-text-dim); overflow-wrap: anywhere; font: 650 7px/1.3 'FlowStudio Pretendard', sans-serif; letter-spacing: .04em; }
.flowstudio .fs-spatial-input,
.flowstudio .fs-spatial-select,
.flowstudio .fs-review-note,
.flowstudio .fs-workbench-note {
  box-sizing: border-box;
  width: 100%;
  min-width: 0;
  min-height: 29px;
  padding: 6px 7px;
  color: #e4e6e8;
  caret-color: var(--fs-green);
  background: #101214;
  border: 1px solid rgba(255, 255, 255, .095);
  border-radius: 5px;
  outline: 0;
  font: 500 9px/1.4 'FlowStudio Pretendard', sans-serif;
  transition: border-color .14s ease, box-shadow .14s ease;
}
.flowstudio .fs-spatial-select { padding-right: 22px; }
.flowstudio .fs-workbench-note { resize: vertical; }
.flowstudio .fs-spatial-input:hover:not(:disabled),
.flowstudio .fs-spatial-select:hover:not(:disabled),
.flowstudio .fs-review-note:hover:not(:disabled),
.flowstudio .fs-workbench-note:hover:not(:disabled) { border-color: rgba(255, 255, 255, .17); }
.flowstudio .fs-spatial-input:focus,
.flowstudio .fs-spatial-select:focus,
.flowstudio .fs-review-note:focus,
.flowstudio .fs-workbench-note:focus { border-color: rgba(0, 255, 127, .52); box-shadow: 0 0 0 2px rgba(0, 255, 127, .08); }
.flowstudio .fs-spatial-input:disabled,
.flowstudio .fs-spatial-select:disabled,
.flowstudio .fs-review-note:disabled,
.flowstudio .fs-workbench-note:disabled { color: #a9adb1; background: rgba(8, 10, 11, .58); opacity: .62; }
.flowstudio .fs-spatial-field-error { color: #ffc2c6; overflow-wrap: anywhere; font: 550 7px/1.4 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-spatial-warning { color: #f2d59c; overflow-wrap: anywhere; font: 550 7px/1.4 'FlowStudio Pretendard', sans-serif; }

.flowstudio .fs-spatial-landmarks { min-width: 0; display: grid; gap: 7px; margin-top: 9px; }
.flowstudio .fs-spatial-landmark {
  min-width: 0;
  display: grid;
  grid-template-columns: 22px minmax(0, 1fr) auto;
  align-items: start;
  gap: 7px;
  padding: 7px;
  background: rgba(0, 0, 0, .14);
  border: 1px solid rgba(255, 255, 255, .07);
  border-radius: 6px;
}
.flowstudio .fs-spatial-side-marker { width: 22px; height: 22px; display: grid; place-items: center; color: #07161d; background: var(--fs-geo-left); border-radius: 4px 1px 1px 4px; box-shadow: inset 0 1px rgba(255, 255, 255, .28); font: 850 8px/1 'DM Mono', monospace; }
.flowstudio .fs-spatial-side-marker.is-right { color: #241b0b; background: var(--fs-geo-right); border-radius: 1px 4px 4px 1px; }
.flowstudio .fs-spatial-landmark-fields { min-width: 0; display: grid; grid-template-columns: minmax(70px, .72fr) minmax(0, 1.28fr); gap: 6px; }
.flowstudio .fs-spatial-landmark-fields > .fs-spatial-field:first-child,
.flowstudio .fs-spatial-landmark-id { grid-column: 1 / -1; }
.flowstudio .fs-spatial-landmark-id { min-width: 0; color: var(--fs-text-dim); overflow-wrap: anywhere; font: 550 7px/1.35 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-spatial-landmark-id code { color: #a9eccf; font: 600 7px/1.35 'DM Mono', monospace; }
.flowstudio .fs-spatial-landmark-remove { align-self: start; padding: 4px 5px; color: #ffc2c6; background: rgba(224, 85, 95, .045); border: 1px solid rgba(224, 85, 95, .22); border-radius: 4px; cursor: pointer; font: 700 7px/1.2 'FlowStudio Pretendard', sans-serif; }

.flowstudio .fs-spatial-landmark-add,
.flowstudio .fs-spatial-save,
.flowstudio .fs-spatial-reload,
.flowstudio .fs-shot-scene-bind,
.flowstudio .fs-shot-clear-obsolete,
.flowstudio .fs-review-save,
.flowstudio .fs-workbench-apply,
.flowstudio .fs-workbench-load,
.flowstudio .fs-workbench-refresh,
.flowstudio .fs-workbench-record,
.flowstudio .fs-workbench-retry-verdict {
  min-height: 28px;
  padding: 5px 8px;
  color: #9bf0cd;
  background: rgba(0, 255, 127, .06);
  border: 1px solid rgba(0, 255, 127, .28);
  border-radius: 5px;
  cursor: pointer;
  font: 700 8px/1.25 'FlowStudio Pretendard', sans-serif;
  transition: background .14s ease, border-color .14s ease, opacity .14s ease;
}
.flowstudio .fs-spatial-reload,
.flowstudio .fs-shot-scene-bind,
.flowstudio .fs-shot-clear-obsolete,
.flowstudio .fs-workbench-load,
.flowstudio .fs-workbench-refresh,
.flowstudio .fs-workbench-retry-verdict { color: #8adfff; background: rgba(55, 200, 255, .055); border-color: rgba(55, 200, 255, .25); }
.flowstudio .fs-spatial-landmark-remove:hover:not(:disabled) { background: rgba(224, 85, 95, .11); border-color: rgba(224, 85, 95, .42); }
.flowstudio .fs-spatial-landmark-add:hover:not(:disabled),
.flowstudio .fs-spatial-save:hover:not(:disabled),
.flowstudio .fs-review-save:hover:not(:disabled),
.flowstudio .fs-workbench-apply:hover:not(:disabled),
.flowstudio .fs-workbench-record:hover:not(:disabled) { background: rgba(0, 255, 127, .12); border-color: rgba(0, 255, 127, .5); }
.flowstudio .fs-spatial-reload:hover:not(:disabled),
.flowstudio .fs-shot-scene-bind:hover:not(:disabled),
.flowstudio .fs-shot-clear-obsolete:hover:not(:disabled),
.flowstudio .fs-workbench-load:hover:not(:disabled),
.flowstudio .fs-workbench-refresh:hover:not(:disabled),
.flowstudio .fs-workbench-retry-verdict:hover:not(:disabled) { background: rgba(55, 200, 255, .12); border-color: rgba(55, 200, 255, .46); }
.flowstudio .fs-spatial-landmark-remove:disabled,
.flowstudio .fs-spatial-landmark-add:disabled,
.flowstudio .fs-spatial-save:disabled,
.flowstudio .fs-spatial-reload:disabled,
.flowstudio .fs-shot-scene-bind:disabled,
.flowstudio .fs-shot-clear-obsolete:disabled,
.flowstudio .fs-review-save:disabled,
.flowstudio .fs-workbench-apply:disabled,
.flowstudio .fs-workbench-load:disabled,
.flowstudio .fs-workbench-refresh:disabled,
.flowstudio .fs-workbench-record:disabled,
.flowstudio .fs-workbench-retry-verdict:disabled { opacity: .4; cursor: not-allowed; }
.flowstudio .fs-spatial-actions { min-width: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 7px; margin-top: 9px; }
.flowstudio .fs-spatial-actions > .fs-spatial-status { flex: 1 1 100%; }
.flowstudio .fs-spatial-readonly { color: #b8c8d8; font: 600 8px/1.4 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-spatial-empty,
.flowstudio .fs-spatial-loading-inline,
.flowstudio .fs-review-empty,
.flowstudio .fs-workbench-empty { margin: 0; color: var(--fs-text-dim); overflow-wrap: anywhere; font: 500 8px/1.5 'FlowStudio Pretendard', sans-serif; }

.flowstudio .fs-spatial-status { min-width: 0; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 6px; padding: 6px 7px; color: #b8c8d8; background: rgba(110, 168, 254, .05); border: 1px solid rgba(110, 168, 254, .19); border-radius: 5px; overflow-wrap: anywhere; font: 500 8px/1.4 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-spatial-status.is-ok { color: #9bf0cd; background: rgba(0, 255, 127, .05); border-color: rgba(0, 255, 127, .22); }
.flowstudio .fs-spatial-status.is-error { color: #ffc2c6; background: rgba(224, 85, 95, .055); border-color: rgba(224, 85, 95, .28); }
.flowstudio .fs-spatial-status-text { min-width: 0; flex: 1 1 140px; }
.flowstudio .fs-spatial-reload-warning { flex: 1 1 100%; color: #efb8bb; font: 500 7px/1.4 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-spatial-status[hidden] { display: none; }

.flowstudio .fs-spatial-pins { min-width: 0; display: grid; gap: 5px; margin-top: 8px; }
.flowstudio .fs-spatial-pin-card { min-width: 0; padding: 6px 7px; background: rgba(0, 255, 127, .035); border: 1px solid rgba(0, 255, 127, .17); border-left: 2px solid rgba(0, 255, 127, .56); border-radius: 4px; }
.flowstudio .fs-spatial-pin-card.is-stale { background: rgba(246, 183, 67, .045); border-color: rgba(246, 183, 67, .2); border-left-color: #f6b743; }
.flowstudio .fs-spatial-pin-summary { display: block; color: #a9eccf; overflow-wrap: anywhere; font: 650 8px/1.4 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-spatial-pin-card.is-stale .fs-spatial-pin-summary { color: #f2d59c; }
.flowstudio .fs-spatial-pin-list { margin: 5px 0 0; padding-left: 16px; color: #d7c49b; font: 500 7px/1.45 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-spatial-pin-list li + li { margin-top: 3px; }
.flowstudio .fs-spatial-pin-list code { color: #f2d59c; font: 600 7px/1.45 'DM Mono', monospace; }

/* Shot-card geography stays inside Camera and inherits its mint rail. */
.flowstudio .fs-shot-geography { min-width: 0; display: grid; gap: 7px; margin-top: 2px; padding-top: 8px; border-top: 1px dashed rgba(92, 242, 177, .17); }
.flowstudio .fs-shot-scene-binding { min-width: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 5px 7px; padding: 6px 7px; background: rgba(92, 242, 177, .035); border: 1px solid rgba(92, 242, 177, .13); border-radius: 5px; color: var(--fs-text-dim); font: 600 7px/1.35 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-shot-scene-binding code { min-width: 0; overflow: hidden; color: #a9eccf; text-overflow: ellipsis; white-space: nowrap; font: 650 7px/1.35 'DM Mono', monospace; }
.flowstudio .fs-shot-scene-binding small { flex: 1 1 100%; }
.flowstudio .fs-shot-scene-bind { margin-left: auto; }
.flowstudio .fs-shot-landmark-bindings { min-width: 0; display: grid; gap: 5px; margin: 1px 0 0; padding: 7px; background: rgba(0, 0, 0, .11); border: 1px solid rgba(255, 255, 255, .07); border-radius: 5px; }
.flowstudio .fs-shot-landmark-bindings legend { padding: 0 4px; color: var(--fs-text-dim); font: 700 7px/1.3 'FlowStudio Pretendard', sans-serif; letter-spacing: .04em; }
.flowstudio .fs-shot-landmark-binding { min-width: 0; display: grid; grid-template-columns: minmax(0, 1fr) minmax(72px, .58fr); align-items: center; gap: 5px; padding: 5px; background: rgba(255, 255, 255, .018); border: 1px solid rgba(255, 255, 255, .055); border-radius: 4px; }
.flowstudio .fs-shot-landmark-pick { min-width: 0; display: flex; align-items: center; gap: 6px; color: #d5d8db; cursor: pointer; font: 600 8px/1.35 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-shot-landmark-pick.is-disabled { cursor: default; }
.flowstudio .fs-shot-landmark-pick input { width: 14px; height: 14px; flex: 0 0 auto; margin: 0; accent-color: var(--fs-green); }
.flowstudio .fs-shot-landmark-pick span { min-width: 0; overflow-wrap: anywhere; }
.flowstudio .fs-shot-landmark-note,
.flowstudio .fs-shot-landmark-binding > .fs-spatial-field-error { grid-column: 1 / -1; }
.flowstudio .fs-shot-landmark-retained { grid-column: 1 / -1; color: var(--fs-text-dim); overflow-wrap: anywhere; font: 550 7px/1.4 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-shot-master-role { margin-top: 1px; }
.flowstudio .fs-shot-master-contract { min-width: 0; display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: start; gap: 7px; margin-top: 3px; padding: 7px; color: #d7c49b; background: rgba(246, 183, 67, .045); border: 1px solid rgba(246, 183, 67, .2); border-radius: 5px; }
.flowstudio .fs-shot-master-badge { padding: 3px 5px; color: #2a1c02; background: #f2d59c; border-radius: 4px; font: 850 7px/1 'DM Mono', monospace; letter-spacing: .05em; white-space: nowrap; }
.flowstudio .fs-shot-master-contract p { min-width: 0; margin: 0; overflow-wrap: anywhere; font: 500 7px/1.45 'FlowStudio Pretendard', sans-serif; }

/* Review decisions are compact and revisioned independently from geography. */
.flowstudio .fs-review-section { background: linear-gradient(145deg, rgba(143, 119, 255, .026), transparent 42%), #151719; }
.flowstudio .fs-review-list { min-width: 0; display: grid; gap: 7px; }
.flowstudio .fs-review-row { min-width: 0; display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 7px; padding: 7px; background: rgba(0, 0, 0, .13); border: 1px solid rgba(255, 255, 255, .07); border-radius: 6px; }
.flowstudio .fs-review-identity { min-width: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 5px; }
.flowstudio .fs-review-identity code { min-width: 0; overflow: hidden; color: #d5d8db; text-overflow: ellipsis; white-space: nowrap; font: 650 8px/1.3 'DM Mono', monospace; }
.flowstudio .fs-review-state,
.flowstudio .fs-review-pill { padding: 3px 6px; color: #b8c8d8; background: rgba(110, 168, 254, .055); border: 1px solid rgba(110, 168, 254, .2); border-radius: 999px; font: 750 7px/1.15 'DM Mono', monospace; text-transform: uppercase; }
.flowstudio .fs-review-state.is-approved,
.flowstudio .fs-review-pill.is-approved { color: #9bf0cd; background: rgba(0, 255, 127, .055); border-color: rgba(0, 255, 127, .24); }
.flowstudio .fs-review-state.is-coverage_requested,
.flowstudio .fs-review-pill.is-coverage_requested { color: #f2d59c; background: rgba(246, 183, 67, .06); border-color: rgba(246, 183, 67, .25); }
.flowstudio .fs-review-pills { min-width: 0; grid-column: 1 / -1; display: flex; flex-wrap: wrap; gap: 4px; }
.flowstudio .fs-review-pill { cursor: pointer; text-transform: none; }
.flowstudio .fs-review-pill[aria-pressed='true'] { color: #071e15; background: var(--fs-green); border-color: var(--fs-green); box-shadow: inset 0 1px rgba(255, 255, 255, .28); }
.flowstudio .fs-review-pill.is-coverage_requested[aria-pressed='true'] { color: #281c04; background: #f2d59c; border-color: #f2d59c; }
.flowstudio .fs-review-pill:hover:not(:disabled):not([aria-pressed='true']) { border-color: rgba(255, 255, 255, .34); }
.flowstudio .fs-review-pill:disabled { opacity: .45; cursor: not-allowed; }
.flowstudio .fs-review-note { grid-column: 1 / -1; }
.flowstudio .fs-review-note-readonly { grid-column: 1 / -1; margin: 0; color: var(--fs-text-mute); overflow-wrap: anywhere; font: 500 8px/1.45 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-review-save { align-self: start; white-space: nowrap; }
.flowstudio .fs-review-status { margin-top: 7px; }

/* The workbench is a denser ledger nested under a shot, with immutable attempt
   rows separated from local verdict controls and advisory actions. */
.flowstudio .fs-workbench-section { min-width: 0; overflow: hidden; margin-top: 1px; background: rgba(0, 0, 0, .12); border: 1px solid rgba(255, 255, 255, .075); border-radius: 6px; }
.flowstudio .fs-workbench-section[open] { border-color: rgba(138, 223, 255, .18); }
.flowstudio .fs-workbench-summary { min-width: 0; display: grid; grid-template-columns: minmax(0, 1fr) auto 10px; align-items: center; gap: 7px; padding: 7px 8px; color: var(--fs-text-mute); cursor: pointer; list-style: none; }
.flowstudio .fs-workbench-summary::-webkit-details-marker { display: none; }
.flowstudio .fs-workbench-summary::after { color: var(--fs-text-dim); content: '\203A'; font: 700 14px/1 'DM Mono', monospace; transform: rotate(90deg); transition: transform .14s ease, color .14s ease; }
.flowstudio .fs-workbench-section[open] > .fs-workbench-summary::after { color: #8adfff; transform: rotate(-90deg); }
.flowstudio .fs-workbench-summary:hover { background: rgba(255, 255, 255, .025); }
.flowstudio .fs-workbench-summary b { color: #b8dff0; font: 750 8px/1.2 'Outfit', sans-serif; letter-spacing: .11em; }
.flowstudio .fs-workbench-summary span { color: var(--fs-text-dim); font: 600 7px/1.3 'DM Mono', monospace; }
.flowstudio .fs-workbench-body { min-width: 0; display: grid; gap: 7px; padding: 0 7px 7px; border-top: 1px solid rgba(255, 255, 255, .055); }
.flowstudio .fs-workbench-findings,
.flowstudio .fs-workbench-attempts { min-width: 0; display: grid; gap: 6px; padding-top: 7px; }
.flowstudio .fs-workbench-finding { min-width: 0; padding: 7px; background: rgba(246, 183, 67, .045); border: 1px solid rgba(246, 183, 67, .2); border-left: 2px solid #f6b743; border-radius: 4px; }
.flowstudio .fs-workbench-finding.is-block { background: rgba(224, 85, 95, .055); border-color: rgba(224, 85, 95, .24); border-left-color: #e0555f; }
.flowstudio .fs-workbench-finding-head { min-width: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 5px; }
.flowstudio .fs-workbench-finding-head code { min-width: 0; overflow: hidden; color: var(--fs-text-dim); text-overflow: ellipsis; white-space: nowrap; font: 600 7px/1.3 'DM Mono', monospace; }
.flowstudio .fs-workbench-finding-level { color: #f2d59c; font: 800 6px/1 'DM Mono', monospace; letter-spacing: .08em; }
.flowstudio .fs-workbench-finding.is-block .fs-workbench-finding-level { color: #ffc2c6; }
.flowstudio .fs-workbench-finding-copy { margin: 4px 0 0; color: #d7c49b; overflow-wrap: anywhere; font: 500 8px/1.45 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-workbench-finding.is-block .fs-workbench-finding-copy { color: #efc5c8; }
.flowstudio .fs-workbench-finding-detail,
.flowstudio .fs-workbench-guidance { display: block; margin-top: 4px; color: var(--fs-text-dim); overflow-wrap: anywhere; font: 500 7px/1.4 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-workbench-changed-sections { margin: 5px 0 0; padding-left: 16px; color: #d7c49b; font: 500 7px/1.4 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-workbench-suggestion { margin: 6px 0 0; padding: 6px 7px; color: #cfdde4; background: rgba(55, 200, 255, .045); border-left: 2px solid rgba(55, 200, 255, .42); overflow-wrap: anywhere; font: 500 8px/1.45 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-workbench-split { min-width: 0; display: grid; gap: 4px; margin-top: 6px; }
.flowstudio .fs-workbench-split-row { min-width: 0; display: grid; grid-template-columns: minmax(52px, .35fr) minmax(0, 1fr); gap: 6px; padding: 5px 6px; background: rgba(0, 0, 0, .14); border: 1px solid rgba(255, 255, 255, .06); border-radius: 4px; }
.flowstudio .fs-workbench-split-row code { color: #cfc4ff; overflow-wrap: anywhere; font: 650 7px/1.4 'DM Mono', monospace; }
.flowstudio .fs-workbench-split-row span { color: #d5d8db; overflow-wrap: anywhere; font: 500 8px/1.4 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-workbench-apply { width: 100%; margin-top: 6px; }
.flowstudio .fs-workbench-advisory-status { margin-top: 6px; }

.flowstudio .fs-workbench-attempt { min-width: 0; display: grid; gap: 6px; padding: 7px; background: #101214; border: 1px solid rgba(255, 255, 255, .075); border-radius: 5px; }
.flowstudio .fs-workbench-attempt-head { min-width: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 4px; }
.flowstudio .fs-workbench-attempt-number { color: #8adfff; font: 700 8px/1.25 'DM Mono', monospace; }
.flowstudio .fs-workbench-outcome { padding: 2px 5px; color: #b8c8d8; background: rgba(110, 168, 254, .055); border: 1px solid rgba(110, 168, 254, .2); border-radius: 999px; font: 750 6px/1.15 'DM Mono', monospace; text-transform: uppercase; }
.flowstudio .fs-workbench-outcome.is-delivered { color: #9bf0cd; background: rgba(0, 255, 127, .055); border-color: rgba(0, 255, 127, .24); }
.flowstudio .fs-workbench-outcome.is-error { color: #ffc2c6; background: rgba(224, 85, 95, .055); border-color: rgba(224, 85, 95, .25); }
.flowstudio .fs-workbench-outcome.is-stale { color: #f2d59c; background: rgba(246, 183, 67, .055); border-color: rgba(246, 183, 67, .23); }
.flowstudio .fs-workbench-model { min-width: 0; margin-left: auto; overflow: hidden; color: var(--fs-text-dim); text-overflow: ellipsis; white-space: nowrap; font: 600 7px/1.25 'DM Mono', monospace; }
.flowstudio .fs-workbench-receipt { margin: 0; color: #a9eccf; overflow-wrap: anywhere; font: 600 7px/1.35 'DM Mono', monospace; }
.flowstudio .fs-workbench-item,
.flowstudio .fs-workbench-author { min-width: 0; color: var(--fs-text-dim); overflow-wrap: anywhere; font: 550 7px/1.4 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-workbench-item code { color: #b8c8d8; font: 600 7px/1.4 'DM Mono', monospace; }
.flowstudio .fs-workbench-digests { min-width: 0; display: grid; gap: 2px; padding: 5px 6px; background: rgba(255, 255, 255, .018); border-radius: 4px; }
.flowstudio .fs-workbench-digests small { min-width: 0; display: grid; grid-template-columns: 46px minmax(0, 1fr); color: var(--fs-text-dim); font: 550 6px/1.4 'DM Mono', monospace; }
.flowstudio .fs-workbench-digests code { overflow: hidden; color: #858a8e; text-overflow: ellipsis; white-space: nowrap; }
.flowstudio .fs-workbench-verdict { min-width: 0; display: grid; gap: 6px; padding-top: 6px; border-top: 1px solid rgba(255, 255, 255, .055); }
.flowstudio .fs-workbench-verdict-choices { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 5px; }
.flowstudio .fs-workbench-verdict-choice { min-height: 27px; padding: 5px 7px; color: var(--fs-text-mute); background: rgba(255, 255, 255, .025); border: 1px solid rgba(255, 255, 255, .11); border-radius: 5px; cursor: pointer; font: 700 8px/1.2 'FlowStudio Pretendard', sans-serif; transition: background .14s ease, border-color .14s ease; }
.flowstudio .fs-workbench-verdict-choice.is-pass[aria-pressed='true'] { color: #071e15; background: var(--fs-green); border-color: var(--fs-green); }
.flowstudio .fs-workbench-verdict-choice.is-fail[aria-pressed='true'] { color: #260609; background: #e7868d; border-color: #e7868d; }
.flowstudio .fs-workbench-verdict-choice:hover:not(:disabled):not([aria-pressed='true']) { border-color: rgba(255, 255, 255, .3); }
.flowstudio .fs-workbench-verdict-choice:disabled { opacity: .45; cursor: not-allowed; }
.flowstudio .fs-workbench-verdict-saved { margin: 0; padding: 6px 7px; color: #9bf0cd; background: rgba(0, 255, 127, .045); border-left: 2px solid rgba(0, 255, 127, .55); border-radius: 0 4px 4px 0; font: 500 8px/1.4 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-workbench-verdict-saved.is-fail { color: #efb8bb; background: rgba(224, 85, 95, .045); border-left-color: rgba(224, 85, 95, .58); }
.flowstudio .fs-workbench-verdict-note { margin: 0; color: var(--fs-text-mute); overflow-wrap: anywhere; font: 500 8px/1.45 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-workbench-record,
.flowstudio .fs-workbench-retry-verdict,
.flowstudio .fs-workbench-load,
.flowstudio .fs-workbench-refresh { width: 100%; }
.flowstudio .fs-workbench-verdict-status { margin-top: 1px; }

.flowstudio .fs-spatial-landmark-remove:focus-visible,
.flowstudio .fs-spatial-landmark-add:focus-visible,
.flowstudio .fs-spatial-save:focus-visible,
.flowstudio .fs-spatial-reload:focus-visible,
.flowstudio .fs-shot-scene-bind:focus-visible,
.flowstudio .fs-review-pill:focus-visible,
.flowstudio .fs-review-save:focus-visible,
.flowstudio .fs-workbench-summary:focus-visible,
.flowstudio .fs-workbench-apply:focus-visible,
.flowstudio .fs-workbench-load:focus-visible,
.flowstudio .fs-workbench-refresh:focus-visible,
.flowstudio .fs-workbench-verdict-choice:focus-visible,
.flowstudio .fs-workbench-record:focus-visible,
.flowstudio .fs-workbench-retry-verdict:focus-visible { outline: 1px solid var(--fs-green); outline-offset: 2px; box-shadow: 0 0 0 3px rgba(0, 255, 127, .08); }

@media (max-width: 420px) {
  .flowstudio .fs-shot-card-body { padding-left: 8px; }
  .flowstudio .fs-shot-slots,
  .flowstudio .fs-shot-field-row,
  .flowstudio .fs-spatial-map-controls,
  .flowstudio .fs-shot-geography-controls,
  .flowstudio .fs-spatial-landmark-fields,
  .flowstudio .fs-shot-landmark-binding,
  .flowstudio .fs-review-row { grid-template-columns: minmax(0, 1fr); }
  .flowstudio .fs-shot-proposal-actions { grid-template-columns: minmax(0, 1fr); }
  .flowstudio .fs-spatial-section-head { align-items: flex-start; flex-direction: column; }
  .flowstudio .fs-spatial-section-subtitle { max-width: 100%; white-space: normal; }
  .flowstudio .fs-spatial-axis-rail { grid-template-columns: auto minmax(30px, 1fr) auto; padding-inline: 7px; }
  .flowstudio .fs-spatial-landmark { grid-template-columns: 22px minmax(0, 1fr); }
  .flowstudio .fs-spatial-landmark-remove { grid-column: 2; justify-self: start; }
  .flowstudio .fs-spatial-landmark-fields > .fs-spatial-field:first-child,
  .flowstudio .fs-spatial-landmark-id,
  .flowstudio .fs-shot-geography-controls > .fs-spatial-field:first-child,
  .flowstudio .fs-shot-landmark-note,
  .flowstudio .fs-shot-landmark-binding > .fs-spatial-field-error,
  .flowstudio .fs-review-pills,
  .flowstudio .fs-review-note,
  .flowstudio .fs-review-note-readonly { grid-column: 1; }
  .flowstudio .fs-review-save { width: 100%; }
  .flowstudio .fs-workbench-split-row { grid-template-columns: minmax(0, 1fr); }
  .flowstudio .fs-workbench-model { width: 100%; margin-left: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .flowstudio .fs-spatial-input,
  .flowstudio .fs-spatial-select,
  .flowstudio .fs-review-note,
  .flowstudio .fs-workbench-note,
  .flowstudio .fs-spatial-landmark-remove,
  .flowstudio .fs-spatial-landmark-add,
  .flowstudio .fs-spatial-save,
  .flowstudio .fs-spatial-reload,
  .flowstudio .fs-shot-scene-bind,
.flowstudio .fs-shot-clear-obsolete,
  .flowstudio .fs-review-pill,
  .flowstudio .fs-review-save,
  .flowstudio .fs-workbench-summary::after,
  .flowstudio .fs-workbench-apply,
  .flowstudio .fs-workbench-load,
  .flowstudio .fs-workbench-refresh,
  .flowstudio .fs-workbench-verdict-choice,
  .flowstudio .fs-workbench-record,
  .flowstudio .fs-workbench-retry-verdict { transition: none !important; }
}

/* The connectivity pill's default resting spot (bottom 28px, centered) sits
   exactly on the Flow Studio composer (bottom 36px; open bar ~100px tall +
   glow). Lift it clear of the strip — the slide-in still animates via
   translate(-50%,140%)→(-50%,0); only the resting offset moves. */
html.fs-active .offline-banner { bottom: 152px; }

.flowstudio .fs-splash { position: absolute; inset: 0; z-index: 2000; display: flex; align-items: center; justify-content: center; background: #0c0d0f; opacity: 1; transition: opacity .3s ease, visibility .3s ease; }
.flowstudio .fs-splash.done { opacity: 0; visibility: hidden; pointer-events: none; }
/* Boot splash (owner 2026-09-14): the AD character's boot, over the brand
   row at the top bar's own size with the logo spinning in front of it. */
.flowstudio .fs-splash-stage { display: flex; flex-direction: column; align-items: center; gap: 12px; }
.flowstudio .fs-splash-character { width: 168px; height: 224px; }
.flowstudio .fs-splash-brand { display: flex; align-items: center; gap: var(--fs-sp-3); }
.flowstudio .fs-splash-mark { flex: none; width: 44px; height: 44px; display: block; overflow: visible; filter: drop-shadow(rgba(0, 255, 127, .32) 0 0 14px); }
.flowstudio .fs-splash g.spin { animation: fs-splash-spin 1.6s linear infinite; transform-origin: 0 0; }

@keyframes fs-splash-spin { to { transform: rotate(360deg); } }
@keyframes fs-result-spin { to { transform: rotate(360deg); } }
@keyframes fs-node-pulse { 50% { opacity: .35; box-shadow: 0 0 18px rgba(0, 255, 127, .95); } }
@keyframes fs-tab-shimmer { 0%, 100% { opacity: .85; } 50% { opacity: 1; } }
@keyframes fs-chat-line-in { from { opacity: 0; transform: translateY(3px); } to { opacity: 1; transform: translateY(0); } }
@keyframes fs-chat-typing { 0%, 80%, 100% { opacity: .4; transform: translateY(0); } 40% { opacity: 1; transform: translateY(-3px); } }

@media (max-width: 780px) {
  .flowstudio .fs-proj-tab:not(.on) { display: none; }
  .flowstudio .fs-topbar { gap: 6px; padding-inline: 8px; }
  .flowstudio.right-open .fs-right-panel { width: min(376px, calc(100vw - 42px)); }
}

@media (max-width: 420px) {
  .flowstudio .fs-prep-card-head,
  .flowstudio .fs-recipe-card-head { grid-template-columns: 26px minmax(0, 1fr); gap: 7px; }
  .flowstudio .fs-prep-card-head > .fs-cost-pill,
  .flowstudio .fs-recipe-card-head > .fs-recipe-cost-pill { grid-column: 2; width: fit-content; max-width: 100%; }
  .flowstudio .fs-recipe-step { grid-template-columns: 22px minmax(0, 1fr); gap: 7px; }
  .flowstudio .fs-recipe-step::after { left: 10px; }
  .flowstudio .fs-recipe-step-index { width: 21px; height: 21px; }
  .flowstudio .fs-frame-selected { grid-template-columns: 72px minmax(0, 1fr); }
  .flowstudio .fs-stress-grid,
  .flowstudio .fs-stress-matrix { gap: 5px; }
  .flowstudio .fs-stress-choice { min-height: 68px; padding: 7px 6px; }
  .flowstudio .fs-stress-cell-copy { padding-inline: 6px; }
  .flowstudio .fs-stress-generate { margin-inline: 6px; }
  .flowstudio .fs-stress-verdict { padding-inline: 6px; }
  .flowstudio .fs-stress-failure-wrap { padding-inline: 6px; }
  .flowstudio .fs-stress-guidance { margin-inline: 6px; }
}

@media (prefers-reduced-motion: reduce) {
  .flowstudio *, .flowstudio *::before, .flowstudio *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; scroll-behavior: auto !important; }
  .flowstudio .fs-prep-card,
  .flowstudio .fs-recipe-card,
  .flowstudio .fs-recipe-run,
  .flowstudio .fs-stress-choice,
  .flowstudio .fs-stress-start,
  .flowstudio .fs-stress-cell { transition: none !important; }
}


/* Merged inspector: the prompt now shares one scroll pane with the parameters
   (it used to own a whole tab). Cap its height so a long prompt cannot push
   every parameter below the fold — it scrolls inside itself instead. */
.flowstudio .fs-inspector-body .fs-prompt-inspector { flex: 0 0 auto; }
.flowstudio .fs-inspector-body .fs-prompt-input { max-height: 34vh; overflow-y: auto; resize: vertical; }


/* Narrow screens: the header's title + count + three filters + close button
   cannot fit one 272px row, and .fs-gallery clips overflow, so the controls on
   the right simply vanished. Let it wrap onto a second row and make the grid
   size to content instead of a fixed 56px. */
@media (max-width: 560px) {
  .flowstudio .fs-gallery { grid-template-rows: auto minmax(0, 1fr); }
  .flowstudio .fs-gallery:has(.fs-gallery-head-controls) { grid-template-rows: auto auto minmax(0, 1fr); }
  .flowstudio .fs-gallery-head { flex-wrap: wrap; gap: 8px; padding: 10px 14px; }
  .flowstudio .fs-gallery-title { flex: 1 1 100%; }
  .flowstudio .fs-gallery-actions { flex: 1 1 100%; justify-content: space-between; margin-left: 0; }
  .flowstudio .fs-gallery-zoom { width: 90px; }
}


/* A superseded proposal is spent, not rejected — the user never pressed Cancel.
   Read as quietly retired rather than as a negative outcome. */
.flowstudio .fs-composer-confirm.superseded { opacity: .5; }
.flowstudio .fs-composer-confirm.superseded .label { font-style: italic; }

/* ── Board-like standard nodes (Storyboard, Character sheet) ───────────────
   They present as the all-in-one Generator does: the left add-disc doubles as
   the input port, and FULL sits over the top-right of the body. The disc's
   base look already comes from .fs-add-reference; what needs re-asserting is
   its geometry against the generic 12px .fs-port rules, exactly as the
   Generator does for its own disc. */
.flowstudio .fs-board-node > .fs-node-body > .fs-add-reference.fs-port {
  top: 50%; left: -16px; width: 30px; height: 30px;
  background: none; border: 0; border-radius: 0; box-shadow: none;
  transform: translateY(-50%); cursor: pointer;
}
/* The body is a fixed 154px on a form-shaped node — a board-like one has to
   grow with the node so the dragged height is real space, not padding. */
/* Board nodes are square CARDS: the body is the node's width less the 74px of
   head and foot, so head + body + foot is as tall as the node is wide.
   --fs-board-aspect is written by applyNodeSize as width/height; the fallback
   is the default 680px node. Works because .fs-node-placeholder is absolutely
   positioned and contributes no intrinsic height to fight the ratio — and
   because flex-grow is kept, a user-dragged min-height still stretches past
   it. The sheet inside letterboxes; FULL shows it at its true shape. */
.flowstudio .fs-board-node > .fs-node-body { height: auto; flex: 1 1 auto; min-height: 0; aspect-ratio: var(--fs-board-aspect, 680 / 606); }
.flowstudio .fs-board-node { display: flex; flex-direction: column; }

/* Chrome's customizable <select> (appearance: base-select) lets the option
   popup wear the app's own look — rounded corners, dark ground, and the
   node's key color on the selected row — instead of the OS-native white/blue
   list. Firefox/Safari ignore the value and keep their native picker. */
.flowstudio .fs-inspector select,
.flowstudio .fs-inspector select::picker(select) { appearance: base-select; }
.flowstudio .fs-inspector select::picker(select) { margin-top: 4px; padding: 5px; background: rgb(18, 19, 22); border: 1px solid rgba(255, 255, 255, .16); border-radius: 9px; box-shadow: 0 16px 40px rgba(0, 0, 0, .7); }
.flowstudio .fs-inspector select option { padding: 7px 10px; border-radius: 6px; color: #d6d8db; background: transparent; font: 600 12px 'FlowStudio Pretendard', sans-serif; cursor: pointer; }
.flowstudio .fs-inspector select option:hover,
.flowstudio .fs-inspector select option:focus { background: rgba(255, 255, 255, .07); color: #fff; }
.flowstudio .fs-inspector select option:checked { color: var(--insp-accent, #00FF7F); background: rgba(var(--insp-accent-rgb, 0, 255, 127), .14); }

/* ── Project type tabs + described detail rows (owner redesign 2026-08-26) ──
   The inspector's ptype chips + semantic-shifting slider become a full-width
   5-tab row and a vertical radio list where every option explains itself.
   All key colors ride --insp-accent (G61). */
.flowstudio .fs-ptype-tabs { display: grid; grid-template-columns: repeat(5, 1fr); gap: 4px; padding: 4px; background: var(--fs-panel-2); border: 1px solid var(--fs-line-strong); border-radius: 8px; }
.flowstudio .fs-ptype-tabs button { min-width: 0; display: flex; align-items: center; justify-content: center; padding: 6px 2px; overflow: hidden; color: var(--fs-text-mute); background: transparent; border: 0; border-radius: 5px; cursor: pointer; font: 700 10.5px 'FlowStudio Pretendard', sans-serif; letter-spacing: .02em; white-space: nowrap; text-overflow: ellipsis; transition: .16s; }
.flowstudio .fs-ptype-tabs button:hover { color: var(--fs-text); }
.flowstudio .fs-ptype-tabs button.on { color: var(--insp-accent, var(--fs-green)); background: rgba(var(--insp-accent-rgb, 0, 255, 127), .13); box-shadow: rgba(var(--insp-accent-rgb, 0, 255, 127), .2) 0 0 8px; }
.flowstudio .fs-ptype-note { margin: 7px 1px 0; color: var(--fs-text-dim); font: 500 10.5px/1.5 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-detail-rows { display: grid; gap: 6px; }
.flowstudio .fs-detail-row { display: grid; gap: 2px; padding: 8px 11px; text-align: left; background: linear-gradient(rgba(255, 255, 255, .02), transparent), var(--fs-panel-2); border: 1px solid var(--fs-line-strong); border-radius: 8px; cursor: pointer; transition: border-color .14s, background .14s, box-shadow .14s; }
.flowstudio .fs-detail-row b { color: var(--fs-text); font: 700 11.5px 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-detail-row small { color: var(--fs-text-dim); font: 500 10px/1.45 'FlowStudio Pretendard', sans-serif; white-space: normal; }
.flowstudio .fs-detail-row:hover { border-color: rgba(255, 255, 255, .18); }
.flowstudio .fs-detail-row.on { border-color: var(--insp-accent, var(--fs-green)); background: linear-gradient(rgba(var(--insp-accent-rgb, 0, 255, 127), .1), rgba(var(--insp-accent-rgb, 0, 255, 127), .03)), var(--fs-panel-2); box-shadow: rgba(var(--insp-accent-rgb, 0, 255, 127), .16) 0 0 10px; }
.flowstudio .fs-detail-row.on b { color: var(--insp-accent, var(--fs-green)); }
.flowstudio .fs-detail-note { margin: 2px 1px 0; color: var(--fs-text-dim); font: 500 10.5px/1.5 'FlowStudio Pretendard', sans-serif; }

/* Owner 2026-08-26: NODE STATUS sections and the bottom status lines leave
   every inspector. The writers keep writing into hidden DOM (a zero-risk
   removal); failures speak through the toast rail and the node face. */
.flowstudio .fs-inspector section:has(> .fs-reference-summary) { display: none; }
.flowstudio .fs-edit-status, .flowstudio .fs-anz-status, .flowstudio .fs-sb-status, .flowstudio .fs-out-status { display: none !important; }
/* Board-like resize: edge handles, width-driven, ratio held by the sheet. */

/* 2026-08-26 batch: quiet scrollbars, circled browsing, board take arrows. */
/* 1) Long dropdowns scroll without a visible bar. */
.flowstudio .fs-gen-dropdown, .flowstudio .fs-param-select-popover, .flowstudio .fs-gal-menu { scrollbar-width: none; }
.flowstudio .fs-gen-dropdown::-webkit-scrollbar, .flowstudio .fs-param-select-popover::-webkit-scrollbar, .flowstudio .fs-gal-menu::-webkit-scrollbar { display: none; }
.flowstudio .fs-inspector select::picker(select) { scrollbar-width: none; }
.flowstudio .fs-inspector select::picker(select)::-webkit-scrollbar { display: none; }
/* 2) The preview's prompt rail wears the thin dark rounded scrollbar. */
.fs-pv-details { scrollbar-width: thin; scrollbar-color: rgba(255, 255, 255, .16) transparent; }
.fs-pv-details::-webkit-scrollbar { width: 6px; }
.fs-pv-details::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, .16); border-radius: 999px; }
.fs-pv-details::-webkit-scrollbar-track { background: transparent; }
/* 3) The next arrow hugs the IMAGE's right edge, never the text rail. */
.fs-full-preview > div:has(.fs-pv-details:not([hidden])) .fs-preview-next { right: 310px; }
/* 4) Board take arrows — circles at the frame's mid edges. */
/* Owner 2026-08-29: the take arrows are the size of the + reference disc (30px)
   and carry SVG chevrons so the arrow sits dead-centre in the circle. */
/* Owner 2026-08-31: tucked further in, a little larger, and hidden until the
   pointer is on the node — they sit ON the artwork, so at rest they are two
   discs covering the thing you are trying to look at. */
.flowstudio .fs-take-nav { position: absolute; top: 50%; transform: translateY(-50%); left: 26px; z-index: 6; width: 34px; height: 34px; display: flex; align-items: center; justify-content: center; padding: 0; color: rgba(240, 241, 243, .85); background: rgba(8, 10, 12, .72); border: 1px solid var(--fs-line-strong); border-radius: 50%; cursor: pointer; opacity: 0; transition: opacity var(--fs-dur) var(--fs-ease), color var(--fs-dur) var(--fs-ease); }
.flowstudio .fs-take-nav svg { width: 16px; height: 16px; display: block; }
.flowstudio .fs-take-nav.is-next { left: auto; right: 26px; }
.flowstudio .fs-generator-node:hover .fs-take-nav { opacity: .82; }
.flowstudio .fs-generator-node:hover .fs-take-nav:hover { opacity: 1; color: #fff; }
.flowstudio .fs-take-nav:focus-visible { opacity: 1; color: #fff; }
.flowstudio .fs-take-nav[hidden] { display: none; }
/* 5) Full view (owner 2026-09-17): the board's own ⛶ in the picture area's
   top-right corner, directly under RESET (the chip strip fills the band above
   the frame, RESET right-most). z 6 keeps it reachable over the MATRIX grid. */
.flowstudio .fs-gen-expand { position: absolute; top: calc(var(--frame-top, 38px) + 8px); right: 18px; z-index: 6; width: 30px; height: 30px; display: flex; align-items: center; justify-content: center; padding: 0; color: rgba(240, 241, 243, .85); background: rgba(8, 10, 12, .72); border: 1px solid var(--fs-line-strong); border-radius: 8px; cursor: pointer; opacity: 0; transition: opacity var(--fs-dur) var(--fs-ease), color var(--fs-dur) var(--fs-ease); }
.flowstudio .fs-gen-expand svg { width: 15px; height: 15px; display: block; }
.flowstudio .fs-generator-node:hover .fs-gen-expand { opacity: .82; }
.flowstudio .fs-generator-node:hover .fs-gen-expand:hover, .flowstudio .fs-gen-expand:focus-visible { opacity: 1; color: #fff; }

/* Owner 2026-08-26: the run affordance leads every inspector, one height. */
.flowstudio .fs-run-first { margin-bottom: 20px; }
.flowstudio .fs-run-first .fs-sb-generate, .flowstudio .fs-run-first .fs-edit-run, .flowstudio .fs-run-first .fs-edit-expand, .flowstudio .fs-run-first .fs-edit-erase, .flowstudio .fs-run-first .fs-anz-run, .flowstudio .fs-run-first .fs-enh-run, .flowstudio .fs-run-first .fs-prompt-generate, .flowstudio .fs-run-first .fs-cg-run, .flowstudio .fs-run-first .fs-cg-zoom { box-sizing: border-box; height: 40px; min-height: 40px; padding-top: 0; padding-bottom: 0; display: inline-flex; align-items: center; justify-content: center; }
.flowstudio .fs-run-first .fs-cg-zoom { width: 40px; }
.flowstudio .fs-run-first .fs-anz-run { flex: 1 1 auto; margin-left: 0; width: 100%; }
/* Enhance fills the row like every other run button (owner 2026-08-26) —
   the LENGTH select keeps its natural width beside it. */
.flowstudio .fs-run-first .fs-enh-run { flex: 1 1 auto; margin-left: 0; }
/* Head row: NODE stays left; RUNTIME + STATUS right-align with their values,
   in one shared type (the boxed/odd status look retires). */
.flowstudio .fs-inspector-row2 .item:first-child { margin-right: auto; }
.flowstudio .fs-inspector-row2 .item:not(:first-child) { flex: 0 0 auto; align-items: flex-end; text-align: right; }
.flowstudio .fs-inspector-row2 .value.status { padding: 0; background: none; border: 0; font: 600 11px 'FlowStudio Pretendard', sans-serif; letter-spacing: 0; }

/* ── Batch sections on the Image/Video generator inspectors ─────────────────
   Mono + one key color: everything themes off --insp-accent(-rgb) with the
   standard green fallbacks. The old Single|Batch tab strip is a single
   switch now (owner 2026-09-01) — batch ADDS its sections to the pane
   rather than swapping it, so the control reads as a setting, not a view. */
.flowstudio .fs-out-tabs { margin-bottom: 12px; }
/* A labelled row with the SAME track/knob switch as the enable/disable
   control in the inspector header — the button carries .fs-inspector-toggle,
   so the five track/knob rules above apply verbatim and the two switches can
   never drift apart. Only the row shell is styled here. */
.flowstudio .fs-batch-switch-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 7px 12px; background: var(--fs-panel-2); border: 1px solid var(--fs-line-strong); border-radius: 8px; }
.flowstudio .fs-batch-switch-label { color: var(--fs-text-mute); font: 700 10px 'FlowStudio Pretendard', sans-serif; letter-spacing: .12em; text-transform: uppercase; }
.flowstudio .fs-batch-switch-row:has(.fs-batch-switch.on) .fs-batch-switch-label { color: var(--insp-accent, var(--fs-green)); }
/* Column: full-width run button, take/credit line underneath (owner
   2026-08-28). */
.flowstudio .fs-batch-runrow { display: flex; flex-direction: column; align-items: stretch; gap: 6px; }
.flowstudio .fs-batch-runrow .fs-batch-run-insp { width: 100%; }
.flowstudio .fs-batch-run-insp { height: 40px; flex: 1 1 auto; border-radius: 9px; border: 1px solid rgba(var(--insp-accent-rgb, 0, 255, 127), .55); background: rgba(var(--insp-accent-rgb, 0, 255, 127), .12); color: rgb(var(--insp-accent-rgb, 0, 255, 127)); font: 800 12px 'FlowStudio Pretendard', sans-serif; letter-spacing: .04em; cursor: pointer; }
.flowstudio .fs-batch-run-insp:hover:not(:disabled) { background: rgba(var(--insp-accent-rgb, 0, 255, 127), .22); }
.flowstudio .fs-batch-run-insp:disabled { opacity: .38; cursor: default; }
.flowstudio .fs-batch-counter { font: 600 10px 'DM Mono', monospace; color: rgba(255, 255, 255, .6); min-height: 12px; }
.flowstudio .fs-batch-counter.is-over { color: #ff6f61; }
.flowstudio .fs-batch-modeline { margin: 0 0 8px; font: 500 11px 'FlowStudio Pretendard', sans-serif; color: rgba(255, 255, 255, .55); line-height: 1.45; }
/* Variation blocks + the [Add Variation] menu (owner 2026-08-28 — replaced
   the presets row and the field <select>). */
.flowstudio .fs-batch-varblock { display: flex; flex-direction: column; gap: 8px; margin-bottom: 12px; padding: 8px; border: 1px solid rgba(255, 255, 255, .1); border-radius: 9px; background: rgba(255, 255, 255, .02); }
.flowstudio .fs-batch-varhead { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.flowstudio .fs-batch-varhead b { font: 700 11px 'FlowStudio Pretendard', sans-serif; color: rgba(255, 255, 255, .85); letter-spacing: .02em; }
.flowstudio .fs-batch-var-remove { width: 20px; height: 20px; border: 1px solid rgba(255, 255, 255, .16); background: rgba(255, 255, 255, .04); color: rgba(255, 255, 255, .55); border-radius: 6px; font: 700 12px 'DM Mono', monospace; line-height: 1; cursor: pointer; }
.flowstudio .fs-batch-var-remove:hover { border-color: rgba(255, 111, 97, .55); color: #ff6f61; }
.flowstudio .fs-batch-addvar-wrap { position: relative; margin-bottom: 12px; }
.flowstudio .fs-batch-add-var { width: 100%; height: 32px; border: 1px dashed rgba(var(--insp-accent-rgb, 0, 255, 127), .45); background: rgba(var(--insp-accent-rgb, 0, 255, 127), .05); color: rgba(var(--insp-accent-rgb, 0, 255, 127), .9); border-radius: 8px; font: 700 11px 'FlowStudio Pretendard', sans-serif; cursor: pointer; }
.flowstudio .fs-batch-add-var:hover { background: rgba(var(--insp-accent-rgb, 0, 255, 127), .14); }
.flowstudio .fs-batch-varmenu { position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 30; display: flex; flex-direction: column; padding: 4px; border: 1px solid rgba(255, 255, 255, .16); border-radius: 9px; background: #101311; box-shadow: 0 10px 28px rgba(0, 0, 0, .5); }
/* display:flex above outranks the UA [hidden] rule — restate it. */
.flowstudio .fs-batch-varmenu[hidden] { display: none; }
.flowstudio .fs-batch-varmenu button { text-align: left; border: 0; background: transparent; color: rgba(255, 255, 255, .82); border-radius: 6px; padding: 7px 9px; font: 600 11px 'FlowStudio Pretendard', sans-serif; cursor: pointer; }
.flowstudio .fs-batch-varmenu button:hover { background: rgba(var(--insp-accent-rgb, 0, 255, 127), .12); color: rgb(var(--insp-accent-rgb, 0, 255, 127)); }
.flowstudio .fs-batch-varmenu-sep { height: 1px; margin: 4px 6px; background: rgba(255, 255, 255, .12); }
.flowstudio .fs-batch-vals { display: flex; flex-wrap: wrap; gap: 6px; }
.flowstudio .fs-batch-vals button { border: 1px solid rgba(255, 255, 255, .16); background: rgba(255, 255, 255, .04); color: rgba(255, 255, 255, .7); border-radius: 7px; padding: 4px 9px; font: 600 10px 'FlowStudio Pretendard', sans-serif; cursor: pointer; }
.flowstudio .fs-batch-vals button:hover { border-color: rgba(255, 255, 255, .35); }
.flowstudio .fs-batch-vals button.on { border-color: rgba(var(--insp-accent-rgb, 0, 255, 127), .65); background: rgba(var(--insp-accent-rgb, 0, 255, 127), .14); color: rgb(var(--insp-accent-rgb, 0, 255, 127)); }
.flowstudio .fs-batch-frag { flex: 1 1 120px; min-width: 120px; height: 28px; border-radius: 7px; border: 1px solid rgba(255, 255, 255, .16); background: rgba(255, 255, 255, .05); color: rgba(255, 255, 255, .85); font: 500 11px 'FlowStudio Pretendard', sans-serif; padding: 0 8px; }
.flowstudio .fs-batch-frag:focus { outline: none; border-color: rgba(var(--insp-accent-rgb, 0, 255, 127), .6); }
.flowstudio .fs-batch-seedrow { display: flex; align-items: center; gap: 8px; margin-top: 10px; cursor: pointer; font: 600 11px 'FlowStudio Pretendard', sans-serif; color: rgba(255, 255, 255, .7); }
.flowstudio .fs-batch-seedrow input { appearance: none; width: 15px; height: 15px; border: 1px solid rgba(255, 255, 255, .3); border-radius: 4px; background: rgba(255, 255, 255, .04); cursor: pointer; display: inline-grid; place-items: center; }
.flowstudio .fs-batch-seedrow input:checked { border-color: rgba(var(--insp-accent-rgb, 0, 255, 127), .8); background: rgba(var(--insp-accent-rgb, 0, 255, 127), .18); }
.flowstudio .fs-batch-seedrow input:checked::after { content: '✓'; font: 800 10px 'DM Mono', monospace; color: rgb(var(--insp-accent-rgb, 0, 255, 127)); }
.flowstudio .fs-batch-takes { display: flex; flex-direction: column; gap: 4px; margin-top: 4px; }
/* The gather source list is followed by variation blocks — breathe (owner 2026-08-28). */
.flowstudio .fs-batch-order { margin-bottom: 12px; }
.flowstudio .fs-batch-take-row { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; padding: 6px 8px; border: 1px solid rgba(255, 255, 255, .12); border-radius: 8px; background: rgba(255, 255, 255, .03); }
.flowstudio .fs-batch-take-note { flex: 1 0 100%; font: 500 10px 'FlowStudio Pretendard', sans-serif; color: rgba(var(--insp-accent-rgb, 0, 255, 127), .8); line-height: 1.4; }
.flowstudio .fs-batch-take-row.is-failed { border-color: rgba(255, 111, 97, .5); }
.flowstudio .fs-batch-take-row.is-generating { border-color: rgba(var(--insp-accent-rgb, 0, 255, 127), .45); }
.flowstudio .fs-batch-take-num { min-width: 18px; height: 18px; border-radius: 5px; display: inline-grid; place-items: center; font: 800 10px 'DM Mono', monospace; color: rgba(var(--insp-accent-rgb, 0, 255, 127), .95); background: rgba(var(--insp-accent-rgb, 0, 255, 127), .1); border: 1px solid rgba(var(--insp-accent-rgb, 0, 255, 127), .35); }
.flowstudio .fs-batch-take-row b { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font: 600 11px 'FlowStudio Pretendard', sans-serif; color: rgba(255, 255, 255, .82); }
.flowstudio .fs-batch-take-state { font: 600 9px 'DM Mono', monospace; color: rgba(255, 255, 255, .5); }
.flowstudio .fs-batch-take-row.is-done .fs-batch-take-state { color: rgb(var(--insp-accent-rgb, 0, 255, 127)); }
.flowstudio .fs-batch-take-row.is-failed .fs-batch-take-state { color: #ff6f61; }

/* ── Batch input handle on Image/Video nodes (PR-3) ─────────────────────────
   A STANDARD port dot (no AIO disc — owner 2026-08-28), two left anchors
   spread evenly within the body: in-port at body-1/3, batch at body-2/3.
   These percentages resolve against .fs-node-body (154px below the 36px
   header) and portPosition mirrors the same arithmetic — change one, change
   both, or the wire ends drift off the circles. */
.flowstudio .fs-node.has-batch-port > .fs-node-body > .fs-port-in { top: calc(33.333% - 6px); }
.flowstudio .fs-node.has-batch-port > .fs-node-body > .fs-port-batch { top: calc(66.667% - 6px); left: -7px; }
.flowstudio .fs-port-in .fs-port-in-label,
.flowstudio .fs-port-batch .fs-port-batch-label { position: absolute; top: 50%; right: calc(100% + 8px); padding: 2px 7px; color: rgba(232, 230, 222, .72); background: rgba(10, 8, 5, .85); border: 1px solid rgba(255, 255, 255, .14); border-radius: 5px; transform: translateY(-50%); white-space: nowrap; pointer-events: none; font: 600 8px 'DM Mono', monospace; letter-spacing: .07em; }

/* ── Storyboard's three typed input handles (owner 2026-09-06) ──────────────
   Children of the NODE, not the body: a board-like body is height:auto under
   an aspect-ratio, so a body-relative percentage would not match the wire
   maths. Each handle carries its `top` INLINE, printed from the registry's own
   `fraction` — that one number is the only source for both the circle and
   portPosition, so nothing here can drift out of step. margin-top centres the
   12px dot on that line (the generic .fs-port centres itself with a top calc
   the inline value replaces). */
.flowstudio .fs-node.has-storyboard-ports > .fs-port-sb,
.flowstudio .fs-node.has-cg-ports > .fs-port-cg { left: -7px; margin-top: -6px; }
.flowstudio .fs-port-sb .fs-port-sb-label { position: absolute; top: 50%; right: calc(100% + 8px); padding: 2px 7px; color: rgba(232, 230, 222, .72); background: rgba(10, 8, 5, .85); border: 1px solid rgba(255, 255, 255, .14); border-radius: 5px; transform: translateY(-50%); white-space: nowrap; pointer-events: none; font: 600 8px 'DM Mono', monospace; letter-spacing: .07em; }
.flowstudio .fs-port-cg .fs-port-cg-label { position: absolute; top: 50%; right: calc(100% + 8px); padding: 2px 7px; color: rgba(232, 230, 222, .72); background: rgba(10, 8, 5, .85); border: 1px solid rgba(255, 255, 255, .14); border-radius: 5px; transform: translateY(-50%); white-space: nowrap; pointer-events: none; font: 600 8px 'DM Mono', monospace; letter-spacing: .07em; }

/* Video entries inside a Multi-image node: poster tile + ▶ badge (face strip
   and inspector list share the class). */
.flowstudio .fs-multi-video { position: relative; display: inline-block; width: 46px; height: 46px; border-radius: 6px; overflow: hidden; background: rgba(0, 0, 0, .55) center / cover no-repeat; flex: 0 0 auto; }
.flowstudio .fs-multi-video i { position: absolute; inset: 0; display: grid; place-items: center; font: 700 13px/1 'DM Mono', monospace; font-style: normal; color: rgba(255, 255, 255, .92); text-shadow: 0 1px 4px rgba(0, 0, 0, .8); }
.flowstudio .fs-multi-item .fs-multi-video { width: 100%; height: 100%; }

/* Spotlight tour (onboarding, owner 2026-08-29). Body-level like .fs-media-peek:
   above the Flow Studio root (950) and the peek (960), below the console
   modals (4000) and toasts (5000). The hole is a cut-out drawn by a huge
   box-shadow; the popover is the only interactive part. */
.fs-tour { position: fixed; inset: 0; z-index: 1200; pointer-events: none; font-family: 'FlowStudio Pretendard', sans-serif; }
/* White spotlight (owner 2026-08-30): the green ring vanished against the
   green UI; the surround is much darker so the focus reads at a glance. */
.fs-tour-hole { position: fixed; border-radius: 10px; outline: 2px solid rgba(255, 255, 255, .92); box-shadow: 0 0 0 200vmax rgba(3, 4, 6, .84), 0 0 0 5px rgba(255, 255, 255, .14), 0 0 30px rgba(255, 255, 255, .5), 0 0 70px rgba(255, 255, 255, .2); pointer-events: none; transition: top .25s, left .25s, width .25s, height .25s; }
/* Interactive tutorial (owner 2026-09-04): the user must WORK the real UI, so
   the highlight is an attention GLOW around the target — the dark 200vmax
   surround is dropped entirely (no screen dimming). A white core ring reads on
   any surface; a brand-green halo pulses twice on each new step to draw the
   eye, then settles to a gentle steady marker. The rest of the screen stays
   fully bright and clickable (the .fs-tour root is already pointer-events:none). */
.fs-tour.fs-tutorial .fs-tour-hole { outline: 2px solid rgba(255, 255, 255, .95); box-shadow: 0 0 0 4px rgba(0, 255, 127, .30), 0 0 22px 2px rgba(0, 255, 127, .5), 0 0 46px 6px rgba(0, 255, 127, .22); animation: fs-tut-glow 1.5s cubic-bezier(.22, 1, .36, 1) 2; }
@keyframes fs-tut-glow {
  0%   { box-shadow: 0 0 0 3px rgba(0, 255, 127, .55), 0 0 8px 1px rgba(0, 255, 127, .6), 0 0 14px 2px rgba(0, 255, 127, .4); }
  45%  { box-shadow: 0 0 0 7px rgba(0, 255, 127, .32), 0 0 34px 4px rgba(0, 255, 127, .8), 0 0 70px 10px rgba(0, 255, 127, .42); }
  100% { box-shadow: 0 0 0 4px rgba(0, 255, 127, .30), 0 0 22px 2px rgba(0, 255, 127, .5), 0 0 46px 6px rgba(0, 255, 127, .22); }
}
/* Chapter-complete celebration (owner 2026-09-04): the popover is centred and
   dressed in the brand green so finishing a chapter reads as a reward, not a
   quit. The spotlight hole is hidden (display:none) in JS. */
.fs-tour.fs-tutorial.fs-tutorial-done .fs-tour-pop { border-color: rgba(0, 255, 127, .5); box-shadow: 0 16px 48px rgba(0, 0, 0, .6), 0 0 0 1px rgba(0, 255, 127, .28), 0 0 42px rgba(0, 255, 127, .24); animation: fs-tut-pop-in .32s cubic-bezier(.22, 1, .36, 1); }
.fs-tour.fs-tutorial.fs-tutorial-done .fs-tour-step { color: #00FF7F; }
.fs-tour.fs-tutorial.fs-tutorial-done .fs-tour-title { font-size: 16px; }
@keyframes fs-tut-pop-in { from { opacity: 0; transform: translate(-50%, -46%) scale(.96); } to { opacity: 1; transform: translate(-50%, -50%) scale(1); } }
@media (prefers-reduced-motion: reduce) { .fs-tour.fs-tutorial.fs-tutorial-done .fs-tour-pop { animation: none; } }
.fs-tour-pop { position: fixed; width: 360px; max-width: calc(100vw - 32px); max-height: calc(100vh - 32px); overflow-y: auto; padding: 14px 16px 12px; box-sizing: border-box; pointer-events: auto; color: #e8e6de; background: rgba(18, 20, 24, .98); border: 1px solid rgba(255, 255, 255, .22); border-radius: 12px; box-shadow: 0 16px 48px rgba(0, 0, 0, .6); font-size: 12px; line-height: 1.55; outline: none; }
.fs-tour-step { font: 700 9px 'Outfit', sans-serif; letter-spacing: .18em; color: rgba(255, 255, 255, .6); }
.fs-tour-title { display: block; margin: 4px 0; font-size: 13px; font-weight: 700; }
.fs-tour-text { margin: 0; color: rgba(232, 230, 222, .85); }
/* Tutorial popover carries two lines the tour does not: a muted "what you'll
   learn" line, and the instruction itself in green so the do-this step reads at
   a glance. Scoped to .fs-tutorial so the plain tour keeps neutral copy. */
.fs-tour-learn { margin: 0 0 7px; color: rgba(232, 230, 222, .6); font-size: 11.5px; line-height: 1.5; }
.fs-tour-learn:empty { display: none; }
.fs-tour.fs-tutorial .fs-tour-text { color: #00FF7F; font-weight: 600; }
/* The per-step keyboard map (SVG string from tourKeyboardSvg). Full popover
   width; the SVG scales with it, so the lit caps stay readable as a MAP. */
.fs-tour-kbd { margin: 10px 0 0; }
.fs-tour-kbd svg { display: block; width: 100%; height: auto; }
.fs-tour-kbd[hidden] { display: none; }
/* Post-tour ` callout in the composer log: a cropped quarter-keyboard that
   fades out on its own (SVG masks) — bounded so it reads as an aside. */
.fs-composer-log .fs-tour-callout { max-width: 300px; margin: 8px 0 0 18px; }
/* Shortcut rows under the prose (owner 2026-08-30) — the help sheet's own
   k/l dictionary rows, so the tour and the sheet can never disagree. */
.fs-tour-keys-hd { margin: 10px 0 4px; padding-bottom: 4px; border-bottom: 1px solid rgba(255, 255, 255, .12); font: 700 9px 'Outfit', sans-serif; letter-spacing: .18em; text-transform: uppercase; color: rgba(255, 255, 255, .55); }
.fs-tour-keys { display: grid; grid-template-columns: 150px 1fr; gap: 3px 10px; margin: 0; align-items: start; }
.fs-tour-keys dt { margin: 0; color: rgb(0, 255, 127); font: 500 10px 'DM Mono', monospace; overflow-wrap: anywhere; }
.fs-tour-keys dd { margin: 0; color: rgba(232, 230, 222, .8); font-size: 11px; line-height: 1.4; }
.fs-tour-keys[hidden], .fs-tour-keys-hd[hidden] { display: none; }
.fs-tour-actions { display: flex; justify-content: space-between; gap: 6px; margin-top: 10px; }
.fs-tour-actions span { display: flex; gap: 6px; }
.fs-tour-actions button { padding: 5px 12px; color: #00FF7F; background: rgba(0, 255, 127, .07); border: 1px solid rgba(0, 255, 127, .32); border-radius: 999px; cursor: pointer; font: 600 11px 'FlowStudio Pretendard', sans-serif; }
.fs-tour-actions button:hover { background: rgba(0, 255, 127, .15); border-color: rgba(0, 255, 127, .6); }
.fs-tour-actions button[hidden] { display: none; }
.fs-tour-actions [data-tour="skip"] { color: rgba(232, 230, 222, .55); background: transparent; border-color: rgba(255, 255, 255, .14); }
@media (prefers-reduced-motion: reduce) { .fs-tour-hole { transition: none; } .fs-tour.fs-tutorial .fs-tour-hole { animation: none; } }

/* ── Interactive-tutorial popup (owner 2026-09-04) ─────────────────────────
   Backdrop + size cloned from the gallery browser; the panel wears the help
   sheet's frosted glass. Eight chapter cards in a fixed 4×2 grid. */
/* The backdrop is a transparent click-catcher (owner 2026-09-04): NO screen
   dimming — the panel itself is the liquid glass, exactly like the help sheet. */
.flowstudio .fs-tutorial-back { position: fixed; inset: 0; z-index: 130; display: grid; place-items: center; padding: 24px; background: transparent; }
.flowstudio .fs-tutorial-back[hidden] { display: none; }
/* Size to the 8-card grid with margin instead of the gallery's 80vw×80vh —
   ~4 columns of 190px + gaps + comfortable padding, height fits the content. */
.flowstudio .fs-tutorial-panel { width: min(94vw, 900px); height: auto; max-height: min(90vh, 620px); background: rgba(18, 20, 24, .55); backdrop-filter: blur(22px) saturate(1.5); border: 1px solid rgba(255, 255, 255, .12); box-shadow: rgba(0, 0, 0, .55) 0 24px 60px, rgba(0, 0, 0, .3) 0 3px 10px, rgba(255, 255, 255, .1) 0 1px 0 inset; }
/* Square (rounded) card tiles (owner 2026-09-04): the wide 1fr rectangles are
   replaced by 1:1 tiles — narrower columns, capped and centred, taller to match.
   The number badge pins to the top (margin-bottom:auto) and the title/desc sink
   to the bottom, so each card reads as a numbered tile. */
.flowstudio .fs-tutorial-grid { grid-template-columns: repeat(4, minmax(0, 190px)); grid-auto-rows: auto; gap: 18px; justify-content: center; align-content: center; }
.flowstudio .fs-tutorial-card { display: flex; flex-direction: column; align-items: flex-start; aspect-ratio: 1 / 1; gap: 7px; padding: 18px; border-radius: 16px; text-align: left; color: rgba(232, 230, 222, .92); font-family: 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-tutorial-card .fs-tut-num { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; margin-bottom: auto; border-radius: 8px; background: rgba(0, 255, 127, .12); border: 1px solid rgba(0, 255, 127, .32); color: #00FF7F; font: 700 13px 'DM Mono', monospace; }
.flowstudio .fs-tutorial-card .fs-tut-title { font-size: 14px; font-weight: 700; line-height: 1.25; }
.flowstudio .fs-tutorial-card .fs-tut-sub { font-size: 11.5px; line-height: 1.4; color: rgba(232, 230, 222, .62); }
.flowstudio .fs-tutorial-card.is-soon { cursor: default; opacity: .5; }
.flowstudio .fs-tutorial-card.is-soon:hover { transform: none; border-color: rgba(255, 255, 255, .06); box-shadow: none; }
.flowstudio .fs-tutorial-card .fs-tut-soon { margin-top: 2px; padding: 2px 8px; border-radius: 999px; background: rgba(255, 255, 255, .06); border: 1px solid rgba(255, 255, 255, .12); font: 700 8.5px 'Outfit', sans-serif; letter-spacing: .16em; text-transform: uppercase; color: rgba(232, 230, 222, .55); }
/* Owner 2026-09-05: one continuous glass surface — drop the header bar's own
   background + divider so the title/close float over the same glass as the
   cards; nudge the card grid up with extra bottom padding. */
.flowstudio .fs-tutorial-panel .fs-gallery-head { background: none; border-bottom: 0; }
/* The 8 cards never scroll, so let the top row's hover lift breathe instead of
   being clipped by the scroll body's overflow (owner 2026-09-05). */
.flowstudio .fs-tutorial-panel .fs-gallery-body { overflow: visible; padding-top: 14px; padding-bottom: 40px; }

/* ── MEDIA INPUTS list (owner 2026-08-30) ──────────────────────────────────
   The numbered, re-orderable list of media wired into a consumer node. Wears
   the batch gather list's row dress (.fs-batch-take-row / -num) so the two
   "this is the order" lists read as one idiom. */
.flowstudio .fs-inputs-section { margin-bottom: 16px; }
.flowstudio .fs-inputs-list { margin-top: 6px; }
.flowstudio .fs-input-row { flex-wrap: nowrap; gap: 8px; padding: 5px 8px 5px 6px; }
.flowstudio .fs-input-row[draggable="true"] { cursor: grab; }
.flowstudio .fs-input-row.is-muted { opacity: .55; }
.flowstudio .fs-input-row.is-inherited { border-style: dashed; }
.flowstudio .fs-input-row.is-used { border-color: rgba(var(--insp-accent-rgb, 0, 255, 127), .55); }
.flowstudio .fs-input-thumb { width: 30px; height: 30px; flex: 0 0 auto; display: grid; place-items: center; overflow: hidden; border-radius: 5px; background: rgba(255, 255, 255, .05); border: 1px solid rgba(255, 255, 255, .1); color: var(--fs-text-dim); font: 700 12px 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-input-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.flowstudio .fs-input-tag { flex: 0 0 auto; max-width: 96px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font: 600 9px 'DM Mono', monospace; letter-spacing: .06em; text-transform: uppercase; color: rgba(255, 255, 255, .5); }
.flowstudio .fs-input-row.is-used .fs-input-tag { color: rgb(var(--insp-accent-rgb, 0, 255, 127)); }
.flowstudio .fs-input-move { flex: 0 0 auto; display: inline-flex; flex-direction: column; gap: 1px; }
.flowstudio .fs-input-move button { width: 18px; height: 12px; padding: 0; border: 0; border-radius: 3px; background: transparent; color: rgba(255, 255, 255, .45); font: 700 8px/1 'DM Mono', monospace; cursor: pointer; }
.flowstudio .fs-input-move button:hover:not(:disabled) { color: #fff; background: rgba(255, 255, 255, .08); }
.flowstudio .fs-input-move button:disabled { opacity: .25; cursor: default; }
.flowstudio .fs-inputs-tip, .flowstudio .fs-inputs-empty { margin: 6px 0 0; font: 500 10px/1.45 'FlowStudio Pretendard', sans-serif; color: rgba(255, 255, 255, .45); }
/* Drop indicator — shared with the batch gather list, whose rows toggled
   these classes unstyled (audit 2026-08-29). */
.flowstudio .fs-batch-take-row.drop-before { box-shadow: 0 -2px 0 0 rgb(var(--insp-accent-rgb, 0, 255, 127)); }
.flowstudio .fs-batch-take-row.drop-after { box-shadow: 0 2px 0 0 rgb(var(--insp-accent-rgb, 0, 255, 127)); }
/* Multi-image: numbered tiles, drag to reorder. */
.flowstudio .fs-multi-item[draggable="true"] { cursor: grab; }
.flowstudio .fs-multi-num { position: absolute; top: 3px; left: 3px; z-index: 2; min-width: 16px; height: 16px; padding: 0 4px; display: inline-grid; place-items: center; border-radius: 4px; background: rgba(6, 8, 9, .8); border: 1px solid rgba(var(--insp-accent-rgb, 0, 255, 127), .5); color: rgb(var(--insp-accent-rgb, 0, 255, 127)); font: 800 9px 'DM Mono', monospace; pointer-events: none; }
.flowstudio .fs-multi-item.drop-before { box-shadow: -3px 0 0 0 rgb(var(--insp-accent-rgb, 0, 255, 127)); }
.flowstudio .fs-multi-item.drop-after { box-shadow: 3px 0 0 0 rgb(var(--insp-accent-rgb, 0, 255, 127)); }
/* ── Timeline editor (owner 2026-08-30) ────────────────────────────────────
   The bottom editing surface. It takes a GRID TRACK of its own rather than
   overlaying the board, which is what makes it additive: .fs-shell just gets
   shorter, so the rails (absolute top:0/bottom:0 inside it) and the composer
   (absolute bottom:36px inside the board host) ride up with no CSS change,
   and safeInsets()/fit()/revealNode() stay correct because their numbers are
   board-local. Every colour here is a shipped --fs-* token; the warm palette
   in the design handoff belongs to the retired v31 prototype. */
/* No bottom bar (owner 2026-09-13): closed, the timeline takes no row at all —
   it opens from its node. */
.flowstudio.tl-collapsed { --fs-tl-row: 0px; }
/* The height is capped against the viewport as well as the user's drag, so a
   short laptop can never squeeze the board out: 452px = 46 brand + 46 top bar
   + a 360px floor for the canvas. Belt for the @media guard below. */
.flowstudio.tl-open { --fs-tl-row: clamp(34px, calc(var(--fs-tl-h, 300px) + 6px), max(34px, calc(100vh - 452px))); }

.flowstudio .fs-tl-row { display: none; min-height: 0; min-width: 0; overflow: hidden; background: linear-gradient(rgb(29, 30, 33) 0%, rgb(23, 24, 27) 100%); border-top: 1px solid var(--fs-line-strong); }
.flowstudio.tl-open .fs-tl-row { display: grid; grid-template-rows: 6px minmax(0, 1fr); }
.flowstudio.tl-collapsed .fs-tl-row { display: none; }

/* Divider — a 6px hit area painting a 1px hairline. No precedent to copy (the
   app has no resizable panel), so it borrows .fs-fold's colour move. */
.flowstudio .fs-tl-divider { position: relative; display: grid; place-items: center; cursor: ns-resize; touch-action: none; background: var(--fs-panel); }
.flowstudio .fs-tl-divider i { width: 56px; height: 3px; border-radius: 2px; background: var(--fs-line-strong); transition: background var(--fs-dur) var(--fs-ease); }
.flowstudio .fs-tl-divider:hover i { background: var(--fs-line-warm); }
.flowstudio .fs-tl-divider.is-dragging i,
.flowstudio .fs-tl-divider:focus-visible i { background: var(--fs-green); }
.flowstudio .fs-tl-divider:focus-visible { outline: 2px solid #fff; outline-offset: -2px; }


.flowstudio .fs-tl { min-height: 0; min-width: 0; overflow: hidden; display: flex; flex-direction: column; background: linear-gradient(rgb(29, 30, 33) 0%, rgb(23, 24, 27) 100%); }
.flowstudio .fs-tl[aria-hidden="true"] { display: none; }

/* Header — 46px, the app's chrome-bar height, three zones so nothing overlaps
   at narrow widths (the transport is NOT absolutely centred). */
.flowstudio .fs-tl-head { flex: 0 0 auto; height: 46px; min-width: 0; display: flex; align-items: center; gap: var(--fs-sp-3); padding: 0 var(--fs-sp-3); border-bottom: 1px solid var(--fs-line); background: linear-gradient(rgba(255, 255, 255, .02), transparent), linear-gradient(rgb(30, 32, 36), rgb(23, 24, 27)); }
.flowstudio .fs-tl-head-l { flex: 1 1 0; min-width: 0; display: flex; align-items: center; gap: var(--fs-sp-3); }
.flowstudio .fs-tl-head-c { flex: 0 0 auto; display: flex; align-items: center; gap: 6px; }
.flowstudio .fs-tl-head-r { flex: 1 1 0; min-width: 0; display: flex; align-items: center; justify-content: flex-end; gap: var(--fs-sp-2); }
.flowstudio .fs-tl-label { flex: 0 0 calc(var(--fs-tl-col) - var(--fs-sp-3) * 2); color: var(--fs-green); font: 700 11px 'Outfit', sans-serif; letter-spacing: .16em; text-transform: uppercase; }
.flowstudio .fs-tl-tc { flex: 0 0 auto; display: inline-flex; align-items: center; gap: 6px; height: 28px; padding: 0 12px; background: var(--fs-panel-2); border: 1px solid var(--fs-line-strong); border-radius: var(--fs-r-lg); font: 500 11px 'DM Mono', monospace; font-variant-numeric: tabular-nums; white-space: nowrap; }
.flowstudio .fs-tl-tc-now { color: var(--fs-text); font-weight: 500; }
.flowstudio .fs-tl-tc-sep, .flowstudio .fs-tl-tc-total { color: var(--fs-text-dim); }

/* Transport — .fs-fold's dress at the app's 28px chrome unit. */
.flowstudio .fs-tl-btn, .flowstudio .fs-tl-play, .flowstudio .fs-tl-fold { display: inline-grid; place-items: center; height: 28px; padding: 0; border-radius: var(--fs-r-md); cursor: pointer; transition: color var(--fs-dur-fast) var(--fs-ease), border-color var(--fs-dur-fast) var(--fs-ease), background var(--fs-dur-fast) var(--fs-ease); }
.flowstudio .fs-tl-btn { width: 28px; color: var(--fs-text-mute); background: var(--fs-panel-2); border: 1px solid var(--fs-line-strong); }
.flowstudio .fs-tl-btn:hover { color: var(--fs-green); border-color: var(--fs-line-warm); }
.flowstudio .fs-tl-btn svg { width: 13px; height: 13px; display: block; }
/* The scissors sit beside the timecode (owner 2026-09-07): split at the
   playhead, same chrome as the transport, disabled when nothing is under it. */
.flowstudio .fs-tl-split svg { width: 14px; height: 14px; }
.flowstudio .fs-tl-btn:disabled { color: var(--fs-text-dim); opacity: .45; cursor: not-allowed; }
.flowstudio .fs-tl-btn:disabled:hover { color: var(--fs-text-dim); border-color: var(--fs-line-strong); }
.flowstudio .fs-tl-play { width: 34px; color: var(--fs-bg); background: var(--fs-green); border: 1px solid var(--fs-green); }
.flowstudio .fs-tl-play:hover { background: var(--fs-green-2); border-color: var(--fs-green-2); box-shadow: 0 0 14px var(--fs-brass-glow); }
.flowstudio .fs-tl-play svg { width: 13px; height: 13px; display: block; }
.flowstudio .fs-tl-play .ic-pause { display: none; }
.flowstudio .fs-tl.is-playing .fs-tl-play .ic-play { display: none; }
.flowstudio .fs-tl.is-playing .fs-tl-play .ic-pause { display: inline-grid; }

.flowstudio .fs-tl-zoom { display: flex; align-items: center; gap: 4px; color: rgba(232, 230, 222, .72); font: 500 12px 'FlowStudio Pretendard', sans-serif; }
.flowstudio .fs-tl-zoom-value { min-width: 42px; text-align: center; color: var(--fs-text); font: 500 11px 'DM Mono', monospace; font-variant-numeric: tabular-nums; }
.flowstudio .fs-tl-fit { letter-spacing: .14em; text-transform: uppercase; font-weight: 700; font-size: 10px; }

/* ADD TRACK / EXPORT — the quiet chrome pill, always visible (the repo's own
   audit flagged hover-only controls as a defect; this adds no sixth one). */
.flowstudio .fs-tl-act { height: 26px; padding: 0 11px; color: rgba(232, 230, 222, .78); background: rgba(20, 22, 26, .75); border: 1px solid rgba(255, 255, 255, .1); border-radius: var(--fs-r-pill); cursor: pointer; font: 600 9px 'DM Mono', monospace; letter-spacing: .08em; text-transform: uppercase; white-space: nowrap; transition: color var(--fs-dur) var(--fs-ease), border-color var(--fs-dur) var(--fs-ease); }
.flowstudio .fs-tl-act:hover:not(:disabled) { color: var(--fs-green); border-color: rgba(0, 255, 127, .5); }
.flowstudio .fs-tl-act:disabled { opacity: .38; cursor: not-allowed; }
.flowstudio .fs-tl-export:not(:disabled) { color: var(--fs-green); border-color: rgba(0, 255, 127, .32); background: linear-gradient(rgba(255, 255, 255, .04) 0%, transparent 50%), linear-gradient(rgba(0, 255, 127, .1) 0%, rgba(0, 255, 127, .04) 100%); }
.flowstudio .fs-tl-fold { width: 26px; color: var(--fs-text-dim); background: transparent; border: 0; }
.flowstudio .fs-tl-fold:hover { color: var(--fs-text); }
.flowstudio .fs-tl-fold svg { width: 13px; height: 13px; display: block; }

/* Body: fixed track-header column | horizontally scrolling lane area. */
.flowstudio .fs-tl-body { flex: 1 1 auto; min-height: 0; min-width: 0; overflow: hidden; display: flex; }
.flowstudio .fs-tl-tracks { flex: 0 0 var(--fs-tl-col); width: var(--fs-tl-col); display: flex; flex-direction: column; overflow: hidden; border-right: 1px solid var(--fs-line); }
.flowstudio .fs-tl-tracks-pad { flex: 0 0 26px; height: 26px; border-bottom: 1px solid var(--fs-line); }
.flowstudio .fs-tl-track { flex: 0 1 0; min-height: 0; display: flex; align-items: center; gap: 6px; padding: 0 var(--fs-sp-3); border-bottom: 1px solid var(--fs-line); }
.flowstudio .fs-tl-track:last-child { border-bottom: 0; }
.flowstudio .fs-tl-track-role { flex: 0 1 auto; min-width: 0; overflow: hidden; color: rgba(var(--fs-tl-accent-rgb, 0, 255, 127), .9); text-overflow: ellipsis; white-space: nowrap; font: 700 10px 'DM Mono', monospace; letter-spacing: .12em; text-transform: uppercase; }

.flowstudio .fs-tl-scroll { flex: 1 1 auto; min-width: 0; overflow-x: auto; overflow-y: hidden; }
/* .flowstudio kills every scrollbar globally (width AND height), so a lane
   strip would silently read as cropped. Opt back in, same as the projects
   list does — a list that scrolls invisibly looks like a list that is cut. */
.flowstudio .fs-tl-scroll { scrollbar-width: thin; scrollbar-color: rgba(255, 255, 255, .16) transparent; }
.flowstudio .fs-tl-scroll::-webkit-scrollbar { height: 8px; display: block; }
.flowstudio .fs-tl-scroll::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, .14); border-radius: 4px; }
/* The lane surface always covers the panel, so the timecode and the dark
   track reach the right edge instead of stopping at the last clip and
   leaving a grey gutter. The SCROLLABLE length is still only the programme
   (see paintZoom) — there is nothing to scroll into past the end. */
.flowstudio .fs-tl-inner { position: relative; min-width: 100%; height: 100%; display: flex; flex-direction: column; }

/* Ruler — ticks from one variable so zoom is a single write, not a relayout. */
.flowstudio .fs-tl-ruler { position: relative; flex: 0 0 26px; height: 26px; border-bottom: 1px solid var(--fs-line); background: var(--fs-bg); cursor: ew-resize; }
.flowstudio .fs-tl-tick { position: absolute; top: 0; bottom: 0; padding: 4px 0 0 5px; border-left: 1px solid var(--fs-line-strong); color: var(--fs-text-dim); font: 500 9px 'DM Mono', monospace; letter-spacing: .08em; pointer-events: none; }

.flowstudio .fs-tl-lanes { position: relative; flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.flowstudio .fs-tl-lane { position: relative; flex: 0 1 0; min-height: 0; border-bottom: 1px solid var(--fs-line); background: var(--fs-bg); }
.flowstudio .fs-tl-lane:last-child { border-bottom: 0; }
.flowstudio .fs-tl-lane-v { background: linear-gradient(rgba(0, 255, 127, .03), rgba(0, 255, 127, .015)); }
.flowstudio .fs-tl-lanes.is-empty::after { content: attr(data-empty); position: absolute; top: 50%; left: 24px; transform: translateY(-50%); color: var(--fs-text-dim); font: 500 12px 'FlowStudio Pretendard', sans-serif; pointer-events: none; }

/* Playhead — the shipped .fs-scrub-bar recipe, recoloured, with its cap. */
.flowstudio .fs-tl-playhead { position: absolute; top: 0; bottom: 0; left: var(--fs-tl-pos, 0px); width: 1px; margin-left: -.5px; background: #fff; box-shadow: 0 0 8px rgba(255, 255, 255, .75), 0 0 0 1px rgba(0, 0, 0, .35); pointer-events: none; z-index: 3; }
.flowstudio .fs-tl-playhead i { position: absolute; top: 0; left: 50%; transform: translateX(-50%); width: 0; height: 0; border-left: 5px solid transparent; border-right: 5px solid transparent; border-top: 7px solid #fff; }
/* A trimmed edge has snapped to the playhead: the line turns green for the
   duration of the hold, so the snap is seen, not guessed. */
.flowstudio .fs-tl.is-snapped .fs-tl-playhead { background: var(--fs-green); box-shadow: 0 0 10px var(--fs-green), 0 0 2px var(--fs-green); }
.flowstudio .fs-tl.is-snapped .fs-tl-playhead i { border-top-color: var(--fs-green); }

/* Keyboard claim — the header says so, or the user cannot tell why the arrows
   stopped moving between nodes. */
.flowstudio.tl-focus .fs-tl-label { text-shadow: 0 0 12px rgba(0, 255, 127, .55); }

.flowstudio .fs-tl-row :focus-visible { outline: 2px solid #fff; outline-offset: 2px; }

/* Clips. One formula for every track — .1 fill / .35 border / .95 ink off the
   lane's --fs-tl-accent-rgb, the exact ratios .fs-batch-take-num already uses —
   so a new track type is a data change rather than a CSS change. */
.flowstudio .fs-tl-clip { position: absolute; top: var(--fs-sp-1); bottom: var(--fs-sp-1); overflow: hidden; display: flex; flex-direction: column; border-radius: var(--fs-r-md); background: rgba(10, 11, 13, .92); border: 1px solid rgba(var(--fs-tl-accent-rgb, 0, 255, 127), .35); cursor: grab; transition: border-color var(--fs-dur) var(--fs-ease), box-shadow var(--fs-dur) var(--fs-ease); }
.flowstudio .fs-tl-clip:hover { border-color: rgba(var(--fs-tl-accent-rgb, 0, 255, 127), .55); }
.flowstudio .fs-tl-clip.is-selected { border-color: rgba(var(--fs-tl-accent-rgb, 0, 255, 127), .95); box-shadow: 0 0 14px rgba(var(--fs-tl-accent-rgb, 0, 255, 127), .35); }
/* Media the vault no longer has: the clip KEEPS its slot. A transient load
   failure must never silently destroy an edit. */
.flowstudio .fs-tl-clip.is-missing { border-style: dashed; border-color: rgba(255, 111, 97, .65); background: rgba(255, 111, 97, .08); }
.flowstudio .fs-tl-clip-head { display: flex; align-items: center; justify-content: space-between; gap: 6px; padding: 3px 6px; min-width: 0; }
.flowstudio .fs-tl-clip-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: rgba(var(--fs-tl-accent-rgb, 0, 255, 127), .95); font: 700 9px 'DM Mono', monospace; letter-spacing: .04em; }
.flowstudio .fs-tl-clip-dur { flex: 0 0 auto; color: var(--fs-text-dim); font: 500 9px 'DM Mono', monospace; }
/* In timeline mode the node list is not the thing being worked on, so its
   button steps aside and the viewer switch takes the slot. */
.flowstudio.tl-open .fs-nodes-button, .flowstudio.tl-open .fs-outliner { display: none; }
/* Align / − / % / + / Fit act on a board the viewer has replaced. */
.flowstudio.viewer-on .fs-canvas-toolbar { display: none; }

/* ── Program monitor ──────────────────────────────────────────────────────
   The stage is a sibling of .fs-canvas-wrap inside .fs-board-host, so the
   board's own overflow:hidden clips it and it needs no positioning maths.
   The rails, header, composer and timeline all stay exactly where they are. */
/* Centred the same way the assistant-director composer is: the padding
   carries the width each rail covers, so the stage sits in the middle of
   what is actually VISIBLE and shrinks as the rails and the timeline
   take space, rather than centring on a board hidden underneath them. */
.flowstudio .fs-viewer { position: absolute; inset: 0; z-index: 60; display: grid; place-items: center; background: var(--fs-bg); padding: 24px calc(var(--fs-cover-r, 0px) + 24px) 24px calc(var(--fs-cover-l, 0px) + 24px); transition: padding .36s cubic-bezier(.4, 0, .2, 1); container-type: size; }
.flowstudio.left-open .fs-viewer { --fs-cover-l: calc(var(--fs-left-w, 264px) - 56px); }
.flowstudio.right-open .fs-viewer { --fs-cover-r: calc(var(--fs-right-w, 376px) - 14px); }
.flowstudio .fs-viewer[hidden] { display: none; }
/* The stage is always FITTED to the window (owner 2026-09-18): the picture
   inside it starts fitted without a crop — the smallest it shows — and the
   wheel / 1:1 scale it up to its own pixels, never past; zoomed, a drag pans. */
.flowstudio .fs-viewer-stage { position: relative; width: calc(min(100cqw, calc(100cqh * 16 / 9))); aspect-ratio: 16 / 9; display: grid; place-items: center; overflow: hidden; border: 1px solid var(--fs-line-strong); border-radius: var(--fs-r-lg); background: #000; }
/* Out of flow against the stage, for the reason the generator's full view
   carries verbatim: the stage's only grid row is auto, so a percentage height
   on a replaced element resolves against the image's own intrinsic height and
   the element's box becomes the image's aspect — object-fit is left nothing to
   fit and the picture spills, cut by the stage's overflow. The stage is 16/9,
   so a 16/9 picture hid this exactly; anything squarer or taller was cropped.
   The zoom math reads the STAGE (viewerShownBox), never this element, so the
   fit and the 1:1 ceiling are unaffected. */
.flowstudio .fs-viewer-img, .flowstudio .fs-viewer-video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; transform-origin: center center; }
.flowstudio .fs-viewer-stage.is-zoomable { cursor: zoom-in; }
.flowstudio .fs-viewer-stage.is-zoomed { cursor: grab; }
.flowstudio .fs-viewer-stage.is-grabbing { cursor: grabbing; }
.flowstudio .fs-viewer-img[hidden], .flowstudio .fs-viewer-video[hidden] { display: none; }
.flowstudio .fs-viewer-empty { position: absolute; color: var(--fs-text-dim); font: 600 11px 'DM Mono', monospace; letter-spacing: .16em; text-transform: uppercase; }
.flowstudio .fs-viewer-empty[hidden] { display: none; }
/* The monitor accepts a drop and appends to the programme (owner
   2026-09-01). Green ring rather than a fill: the picture underneath is
   the thing being added to, so it must stay readable. */
.flowstudio .fs-viewer-stage.is-drop-target { border-color: var(--fs-green); box-shadow: inset 0 0 0 1px var(--fs-green), 0 0 18px rgba(0, 255, 127, .28); }
.flowstudio .fs-viewer-stamp { position: absolute; bottom: 10px; padding: 3px 8px; border-radius: var(--fs-r-sm); background: rgba(0, 0, 0, .6); color: var(--fs-text-mute); font: 600 10px 'DM Mono', monospace; letter-spacing: .1em; pointer-events: none; }
.flowstudio .fs-viewer-stamp.is-time { left: 10px; }
.flowstudio .fs-viewer-stamp.is-program { right: 10px; max-width: 60%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* The switch takes the board's top-right and NODES sits below it — they read
   as one cluster, and the right:19px -> 381px inspector transition is free. */
.flowstudio .fs-outliner-wrap { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; }
.flowstudio .fs-view-switch { display: inline-flex; flex: none; white-space: nowrap; align-items: center; gap: 7px; height: 28px; padding: 0 12px 0 10px; border: 1px solid var(--fs-line-strong); border-radius: var(--fs-r-xl); background: rgba(18, 20, 24, .72); backdrop-filter: blur(10px) saturate(1.3); color: var(--fs-text-mute); font: 700 11px Outfit, sans-serif; letter-spacing: .16em; text-transform: uppercase; cursor: pointer; transition: background var(--fs-dur) var(--fs-ease), border-color var(--fs-dur) var(--fs-ease), color var(--fs-dur) var(--fs-ease); }
.flowstudio .fs-view-switch[hidden] { display: none; }
.flowstudio .fs-view-switch:hover { border-color: var(--fs-line-warm); color: var(--fs-text); }
/* In timeline mode the switch is CLOSE ×, like the production board's.
   CLOSE is RED AT REST in every full mode (owner 2026-09-18), with one idle,
   hover and press wherever it appears — the Storyboard's two close buttons
   carry the same three rules in their own module. */
/* `.is-on` is toggled onto this same button in timeline mode and sits later
   in the file at equal specificity, so it took the red away (staging
   2026-09-18). CLOSE names both states and restores the ground `.is-on` sets. */
.flowstudio .fs-view-switch.is-close,
.flowstudio .fs-view-switch.is-on.is-close { border-color: rgba(224, 85, 95, .55); color: #e0555f; background: rgba(18, 20, 24, .72); }
.flowstudio .fs-view-switch.is-close:hover,
.flowstudio .fs-view-switch.is-on.is-close:hover { border-color: #e0555f; color: #ff8b95; background: rgba(224, 85, 95, .14); }
.flowstudio .fs-view-switch.is-close:active,
.flowstudio .fs-view-switch.is-on.is-close:active { background: rgba(224, 85, 95, .24); transform: translateY(1px); }
/* 1:1 / FIT sits left of CLOSE × in one row; the row leaves no gap when hidden. */
.flowstudio .fs-view-row { display: flex; align-items: center; gap: 8px; }
.flowstudio .fs-view-row[hidden] { display: none; }
.flowstudio .fs-view-fit { display: inline-flex; flex: none; white-space: nowrap; align-items: center; justify-content: center; min-width: 48px; height: 28px; padding: 0 12px; border: 1px solid var(--fs-line-strong); border-radius: var(--fs-r-xl); background: rgba(18, 20, 24, .72); backdrop-filter: blur(10px) saturate(1.3); color: var(--fs-text-mute); font: 700 11px Outfit, sans-serif; letter-spacing: .12em; text-transform: uppercase; cursor: pointer; }
.flowstudio .fs-view-fit:hover { border-color: var(--fs-line-warm); color: var(--fs-text); }
.flowstudio .fs-view-fit:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.flowstudio .fs-tl-insp-details { padding: 0; overflow: visible; }
/* Neutral in BOTH states (owner): the label already names what the button
   will do, so the green was signalling nothing the text did not. */
.flowstudio .fs-view-switch.is-on { background: rgba(28, 32, 38, .92); border-color: var(--fs-line-warm); color: var(--fs-text); }
.flowstudio .fs-view-ic { font-size: 10px; line-height: 1; }
/* Green on green chrome disappears — the same reason the tour spotlight is white. */
.flowstudio .fs-view-switch:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }

/* Drag a node's output onto the timeline. display:none unless the panel is
   open, so with the timeline closed the node is byte-identical to before. */
.flowstudio .fs-node-tl-grip { display: none; }
.flowstudio.tl-open .fs-node-tl-grip.is-ready { display: grid; place-items: center; position: absolute; top: 32px; right: 8px; z-index: 4; width: 26px; height: 26px; border: 1px solid var(--fs-line-strong); border-radius: var(--fs-r-sm); background: rgba(23, 24, 26, .9); color: var(--fs-text-mute); font-size: 13px; cursor: grab; opacity: .72; transition: opacity var(--fs-dur) var(--fs-ease), color var(--fs-dur) var(--fs-ease), border-color var(--fs-dur) var(--fs-ease); }
.flowstudio.tl-open .fs-node:hover .fs-node-tl-grip.is-ready, .flowstudio.tl-open .fs-node-tl-grip.is-ready:focus-visible { opacity: 1; }
/* Armed on hover is fine; INVISIBLE until hover is not — the repo's own
   audit flagged hover-only controls, so it sits at .72 by default. */
.flowstudio.tl-open .fs-node-tl-grip.is-ready:hover { color: var(--fs-green); border-color: rgba(0, 255, 127, .55); }

/* Where a dragged clip would land. */
.flowstudio .fs-tl-lane.is-drop-target { background: rgba(0, 255, 127, .07); box-shadow: inset 0 0 0 1px rgba(0, 255, 127, .35); }
/* The snap marker is the GREEN one and the playhead is white (owner). A bare
   line, no cap — the cap is what makes the playhead read as the playhead. */
.flowstudio .fs-tl.is-dropping .fs-tl-lanes::after { content: ''; position: absolute; top: 0; bottom: 0; left: var(--fs-tl-drop-x, 0px); width: 2px; margin-left: -1px; background: var(--fs-green); box-shadow: 0 0 10px rgba(0, 255, 127, .85), 0 0 0 1px rgba(0, 0, 0, .45); pointer-events: none; z-index: 4; }

/* The clip's own first and last frame, so a cut reads without scrubbing. The
   out frame is a <video> parked at the out point via #t=; a clip too narrow to
   show both (.is-narrow) shows the first only. */
/* Full strength and the footage's own shape — no tint over it, and cover
   crops rather than squeezing. Whether TWO fit is decided from the real
   geometry at paint time (see frameNodes), not a fixed pixel guess. */
.flowstudio .fs-tl-clip-frame { position: absolute; top: 0; bottom: 0; width: auto; aspect-ratio: 16 / 9; height: 100%; pointer-events: none; background-position: center; background-size: cover; background-repeat: no-repeat; object-fit: cover; }
.flowstudio .fs-tl-clip-frame.is-in { left: 0; }
.flowstudio .fs-tl-clip-frame.is-out { right: 0; }
.flowstudio .fs-tl-clip.is-narrow .fs-tl-clip-frame.is-out { display: none; }
/* The head rides above the frames, on a scrim so the name stays legible over
   whatever the footage happens to be. */
.flowstudio .fs-tl-clip-head { position: relative; z-index: 1; background: linear-gradient(180deg, rgba(0, 0, 0, .72) 0%, rgba(0, 0, 0, .45) 60%, rgba(0, 0, 0, 0) 100%); }

/* Trim handles — a pointer affordance; [ and ] do the same from the keyboard. */
.flowstudio .fs-tl-clip-edge { position: absolute; top: 0; bottom: 0; z-index: 2; width: 8px; cursor: ew-resize; }
.flowstudio .fs-tl-clip-edge.is-in { left: 0; }
.flowstudio .fs-tl-clip-edge.is-out { right: 0; }
.flowstudio .fs-tl-clip-edge::after { content: ''; position: absolute; top: 50%; left: 50%; width: 2px; height: 16px; margin: -8px 0 0 -1px; border-radius: 1px; background: rgba(var(--fs-tl-accent-rgb, 0, 255, 127), .95); opacity: 0; transition: opacity var(--fs-dur) var(--fs-ease); }
.flowstudio .fs-tl-clip:hover .fs-tl-clip-edge::after, .flowstudio .fs-tl-clip.is-selected .fs-tl-clip-edge::after { opacity: .8; }

/* While a gesture runs the whole panel wears the cursor, the clip tracks the
   pointer with no transition, and clips stop intercepting hits (the listeners
   are on window, so the gesture survives leaving the lane). */
.flowstudio .fs-tl.is-dragging-clip { cursor: grabbing; }
.flowstudio .fs-tl.is-trimming { cursor: ew-resize; }
.flowstudio .fs-tl.is-dragging-clip .fs-tl-clip, .flowstudio .fs-tl.is-trimming .fs-tl-clip { transition: none; pointer-events: none; }

/* Waveform: an honest stand-in. Decoding audio would need a worker we do not have. */
.flowstudio .fs-tl-clip-wave { position: absolute; right: 4px; bottom: 3px; left: 4px; height: 14px; border-radius: 2px; background: repeating-linear-gradient(90deg, rgba(var(--fs-tl-accent-rgb, 111, 184, 156), .55) 0 2px, transparent 2px 5px, rgba(var(--fs-tl-accent-rgb, 111, 184, 156), .3) 5px 7px, transparent 7px 11px); }
.flowstudio .fs-tl-clip:focus-visible { outline: 2px solid #fff; outline-offset: 1px; }

/* Inspector route to the timeline — the shipped dashed ghost row. */
.flowstudio .fs-tl-send-section { margin-top: var(--fs-sp-3); }

@media (max-width: 780px) {
  .flowstudio { --fs-tl-col: 84px; }
  .flowstudio .fs-tl-act { padding: 0 8px; }
}
@media (prefers-reduced-motion: reduce) {
  .flowstudio .fs-tl-row *, .flowstudio .fs-tl-divider i { transition: none; }
}

/* Media associations use native selects for keyboard and touch access. */
.flowstudio .fs-media-scope { display: grid; gap: 6px; margin-bottom: 10px; }
.flowstudio .fs-media-scope label { display: grid; gap: 3px; min-width: 0; color: var(--fs-text-60); font: 500 11px 'DM Sans', sans-serif; }
.flowstudio .fs-media-scope select { width: 100%; min-width: 0; padding: 6px 8px; border: 1px solid var(--fs-line); border-radius: 5px; background: var(--fs-bg); color: var(--fs-text); font: inherit; text-overflow: ellipsis; }
.flowstudio .fs-media-scope select:focus-visible { outline: 2px solid var(--fs-green); outline-offset: 1px; }
.flowstudio .fs-left-panel.closed .fs-media-scope { display: none; }
/* In the rail (owner 2026-09-18) PROJECT · WORKSPACE are the HOUSE control —
   the same pill and the same hover menu as ALL · ANY · NEWEST below them, so
   the row reads as one family. These three rules mirror .fs-media-controls
   exactly. The full browser keeps its labelled native selects. */
.flowstudio .fs-left-panel .fs-media-scope { display: flex; gap: 6px; margin: 0 0 6px; }
.flowstudio .fs-left-panel .fs-media-scope .fs-media-ctl { flex: 1 1 0; min-width: 0; }
.flowstudio .fs-left-panel .fs-media-scope .fs-ctl-value { flex: 1 1 auto; min-width: 0; justify-content: center; text-align: center; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.flowstudio .fs-gallery-associations { grid-template-columns: repeat(2, minmax(0, 1fr)); flex: 1 1 320px; max-width: 480px; margin-bottom: 0; }
.flowstudio .fs-gallery-meta .fs-media-location { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--fs-text-60); font: 500 11px 'DM Sans', sans-serif; }
