/* =====================================================================
 * Studio — Editor
 * ---------------------------------------------------------------------
 * Design language (matches shell/main/modal):
 *   • Pill header buttons, hairline borders, Paperlogy titles, Pretendard body
 *   • Iridescent accent reserved for primary CTA focus + sync-on state
 *   • All dialogs (share) share the modal token system
 *   • Single source of truth for ease + duration (studio tokens)
 *
 * Every class/id preserved — JS & EJS markup depend on them.
 * ===================================================================== */

/* =====================================================================
 * Text selection
 * ---------------------------------------------------------------------
 * The editor shell is application chrome, not a document: a marquee drag on
 * the canvas must not block-select header / dialog text — including when the
 * pointer leaves the window mid-drag. Suppress selection across the shell,
 * restore it on genuine inputs, and leave the engine surface (#editor-sshow)
 * to govern its own selection state.
 * ===================================================================== */

body.page-editor {
    -webkit-user-select: none;
    user-select: none;
}

body.page-editor #editor-sshow {
    -webkit-user-select: auto;
    user-select: auto;
}

body.page-editor input,
body.page-editor textarea {
    -webkit-user-select: text;
    user-select: text;
}

/* =====================================================================
 * Editor header
 * ===================================================================== */

body.page-editor #header-contents { max-width: 100%; }

/* The editor header carries a scroll-less canvas underneath, so the header
   can safely use backdrop-filter without compositor thrash. */
body.page-editor #wrapper-header {
    backdrop-filter: blur(14px) saturate(160%);
    -webkit-backdrop-filter: blur(14px) saturate(160%);
}
@media (prefers-reduced-transparency: reduce) {
    body.page-editor #wrapper-header {
        backdrop-filter: none;
        -webkit-backdrop-filter: none;
        background: var(--global-body-background);
    }
}

/* ===== Loading overlay (canvas fade-in) ===== */
.editor-main-content { position: relative; }

.editor-overlay {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 14px;
    background: var(--global-background-color, rgba(20, 20, 22, 0.96));
    z-index: 20;
    transition: opacity 240ms var(--studio-ease, cubic-bezier(0.22, 0.61, 0.36, 1));
    pointer-events: auto;
}
.editor-overlay[hidden],
.editor-overlay.is-hidden {
    opacity: 0;
    pointer-events: none;
}
.editor-overlay[hidden] {
    display: flex;
    visibility: hidden;
}

/* Loading card holds the spinner, project title, stage label,
   progress bar and per-asset stats in a single centered column.
   Width is capped so very long titles wrap rather than stretching
   the overlay across the canvas. */
.editor-loading-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    max-width: min(420px, 80vw);
    padding: 0 24px;
    text-align: center;
}

.editor-loading-spinner {
    width: 32px;
    height: 32px;
    border: 2px solid var(--studio-surface-active, rgba(127, 127, 127, 0.18));
    border-top-color: var(--global-text-color);
    border-radius: 50%;
    animation: editor-spin 0.9s linear infinite;
}

.editor-loading-title {
    font-family: var(--studio-font-body, 'Pretendard Variable'), sans-serif;
    font-size: 15px;
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--global-text-color);
    /* Two-line clamp so even very long project titles stay legible
       without pushing the progress bar offscreen. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    word-break: break-word;
}

.editor-loading-label {
    font-family: var(--studio-font-body, 'Pretendard Variable'), sans-serif;
    font-size: 12.5px;
    letter-spacing: -0.005em;
    color: var(--global-text-muted, rgba(var(--global-text-color-rgb, 255, 255, 255), 0.55));
    min-height: 1.2em;
}

/* Slim progress track. Hidden until JS reports a determinate stage
   so the spinner alone covers initial boot (where we can't yet
   estimate work). Track + bar chrome mirrors `.upload-progress-*`
   in main.modal.css so studio's two progress affordances (file
   upload + project load) read as the same component family. */
.editor-loading-progress {
    width: 240px;
    max-width: 100%;
    height: 4px;
    border-radius: 999px;
    background: var(--studio-surface-active, rgba(127, 127, 127, 0.18));
    overflow: hidden;
    opacity: 0;
    transition: opacity 180ms var(--studio-ease, cubic-bezier(0.22, 0.61, 0.36, 1));
}
.editor-loading-progress.is-visible { opacity: 1; }
.editor-loading-progress-bar {
    width: 0%;
    height: 100%;
    /* Monochrome fill — matches `.upload-progress-bar` in main.modal.css.
       Single-tone reads cleaner than a multi-stop brand gradient at
       this size and stays legible against any theme background. */
    background: var(--global-text-color);
    border-radius: inherit;
    transition: width 180ms ease;
}

.editor-loading-stats {
    font-family: var(--studio-font-body, 'Pretendard Variable'), sans-serif;
    font-size: 11px;
    font-variant-numeric: tabular-nums;
    letter-spacing: 0;
    color: var(--global-text-muted, rgba(var(--global-text-color-rgb, 255, 255, 255), 0.45));
    min-height: 1em;
}

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

/* The editor's left header slot is now an outline pill (.header-back-btn),
   defined in studio/index.css. The legacy `body.page-editor #header-logo`
   rules and the old `.header-editor-back` class were removed; markup no
   longer renders either, so styles are no longer needed. */

/* ===== Header editor controls cluster =====
   Pill buttons, single size, consistent spacing.
   Sits in the centered grid column on the editor header (same place
   as the marketing nav) so the toolbar is visually anchored under
   the logo and balanced against the account cluster on the right. */
#header-editor-controls {
    display: flex;
    align-items: center;
    gap: 6px;
    height: 100%;
}

.header-editor-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 32px;
    padding: 0 12px;
    background: transparent;
    border: 1px solid var(--studio-hairline, rgba(var(--global-text-color-rgb), 0.08));
    border-radius: 999px;
    color: var(--global-text-color);
    font-family: var(--studio-font-body, 'Pretendard Variable'), sans-serif;
    font-size: 12.5px;
    font-weight: 500;
    letter-spacing: -0.005em;
    cursor: pointer;
    flex-shrink: 0;
    white-space: nowrap;
    transition: border-color 180ms var(--studio-ease, cubic-bezier(0.22, 0.61, 0.36, 1)),
                background 180ms var(--studio-ease, cubic-bezier(0.22, 0.61, 0.36, 1)),
                color 180ms var(--studio-ease, cubic-bezier(0.22, 0.61, 0.36, 1));
}

.header-editor-btn:hover {
    border-color: var(--studio-hairline-strong, rgba(var(--global-text-color-rgb), 0.18));
    background: var(--studio-surface-hover, rgba(var(--global-text-color-rgb), 0.05));
}

.header-editor-btn:focus-visible {
    outline: 2px solid var(--focus-outline-color);
    outline-offset: 2px;
}

.header-editor-btn:disabled {
    opacity: 0.45;
    cursor: not-allowed;
}

.header-editor-btn svg {
    width: 14px;
    height: 14px;
    color: var(--global-text-muted, rgba(var(--global-text-color-rgb), 0.65));
    transition: color 180ms var(--studio-ease, cubic-bezier(0.22, 0.61, 0.36, 1)),
                transform 400ms var(--studio-ease, cubic-bezier(0.22, 0.61, 0.36, 1));
    flex-shrink: 0;
}
.header-editor-btn:hover svg { color: var(--global-text-color); }

.header-editor-btn em {
    font-style: normal;
    opacity: 0.55;
    font-size: 0.85em;
    margin-left: 2px;
    font-variant-numeric: tabular-nums;
}

/* Primary variant (Save) — iridescent CTA. Same recipe as the
   marketing header's Studio button and `.di-btn-iridescent` in
   designIdentity.css (see docs/DESIGN.md §7.4). The save
   action is the editor's brand moment, so it gets the chromatic
   gradient instead of the dark pill the rest of the toolbar uses. */
.header-editor-btn-iridescent {
    padding: 0 16px;
    background: var(--brand-iridescent-gradient,
        linear-gradient(135deg, #FF3889 0%, #FC9254 33%, #F375E7 67%, #69B1FF 100%));
    background-size: 300% 300%;
    border-color: transparent;
    color: #fff;
    font-weight: 600;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
    animation: brand-iridescent-shift 20s ease infinite;
    /* Add `transform` to the inherited transition list so the hover
       lift is smooth — matches `#button-header-studio` in the
       marketing header. */
    transition: border-color 180ms var(--studio-ease, cubic-bezier(0.22, 0.61, 0.36, 1)),
                color 180ms var(--studio-ease, cubic-bezier(0.22, 0.61, 0.36, 1)),
                transform 220ms var(--studio-ease, cubic-bezier(0.22, 0.61, 0.36, 1));
}
/* Re-assert the full iridescent gradient on hover. The base
   `.header-editor-btn:hover` rule sets `background:` (shorthand) to
   the neutral surface tint, which would clobber the gradient
   `background-image` and cause the visible "white flash" / chop on
   hover. We re-apply the same `background` shorthand here so the
   iridescent layer survives, and we keep the lift identical to the
   marketing header Studio button (`#button-header-studio`).
   Scoped to `:not(:disabled)` so the disabled Save button (no dirty
   edits) cannot be re-lit by a hover — without this, `:hover`'s
   `opacity: 1` overrides the disabled rule's `0.45` and the button
   misleadingly looks active when it isn't. */
.header-editor-btn-iridescent:hover:not(:disabled) {
    background: var(--brand-iridescent-gradient,
        linear-gradient(135deg, #FF3889 0%, #FC9254 33%, #F375E7 67%, #69B1FF 100%));
    background-size: 300% 300%;
    border-color: transparent;
    color: #fff;
    transform: translateY(-1px);
    opacity: 1;
}
.header-editor-btn-iridescent:disabled {
    /* Defensive: kill the gradient animation + lift so a disabled
       Save button reads as flat / inert even mid-hover. */
    animation: none;
    transform: none;
    cursor: not-allowed;
}
.header-editor-btn-iridescent:focus-visible {
    outline: 2px solid rgba(255, 255, 255, 0.65);
    outline-offset: 2px;
}
.header-editor-btn-iridescent svg { color: #fff; }
.header-editor-btn-iridescent:hover svg { color: #fff; }

/* Save button 4-state machine — driven by `data-save-state` on
   #save-btn. All three icons + label live in the DOM (stable order),
   and we toggle visibility per state so there's zero layout shift
   between idle ↔ dirty ↔ saving ↔ saved. The iridescent gradient
   only lights up on `dirty`; the other three states fall back to a
   neutral surface tint so a clean (saved) state doesn't pretend it
   has work to commit. */
#save-btn .save-icon { display: none; width: 16px; height: 16px; }
#save-btn[data-save-state="idle"]   .save-icon-check,
#save-btn[data-save-state="saved"]  .save-icon-check,
#save-btn[data-save-state="dirty"]  .save-icon-upload,
#save-btn[data-save-state="saving"] .save-icon-spinner {
    display: inline-block;
}
#save-btn[data-save-state="saving"] .save-icon-spinner {
    animation: header-editor-sync-spin 900ms linear infinite;
    transform-origin: center;
}
/* Non-dirty states: kill the iridescent gradient so the button reads
   as "nothing to do here". We override the iridescent background +
   animation rather than removing the class — keeps markup stable and
   the dirty→idle transition is a plain CSS state flip. */
#save-btn[data-save-state="idle"],
#save-btn[data-save-state="saving"],
#save-btn[data-save-state="saved"] {
    background: rgba(var(--global-text-color-rgb, 17, 17, 17), 0.06);
    color: var(--global-text-color);
    text-shadow: none;
    animation: none;
    cursor: default;
}
#save-btn[data-save-state="idle"] svg,
#save-btn[data-save-state="saving"] svg,
#save-btn[data-save-state="saved"] svg {
    color: var(--global-text-color);
    opacity: 0.62;
}
#save-btn[data-save-state="saved"] {
    /* Brief "committed" beat — slight green tint so the confirmation
       reads as positive without leaving the button stuck in a
       non-canonical colour. JS reverts to `idle` after ~1.2s. */
    background: rgba(46, 160, 67, 0.14);
    color: rgb(40, 130, 56);
}
#save-btn[data-save-state="saved"] svg {
    color: rgb(40, 130, 56);
    opacity: 1;
}
#save-btn[data-save-state="dirty"] {
    cursor: pointer;
}
/* Disabled-state opacity from `.header-editor-btn-iridescent:disabled`
   would dim the idle/saved/saving variants too much (they're already
   muted by design). Override back to a readable level. */
#save-btn:disabled[data-save-state="idle"],
#save-btn:disabled[data-save-state="saving"],
#save-btn:disabled[data-save-state="saved"] {
    opacity: 1;
}

@keyframes header-editor-sync-spin { to { transform: rotate(360deg); } }

/* =====================================================================
 * Main editor area
 * ===================================================================== */
#studio-editor {
    display: flex;
    flex-direction: column;
    width: 100%;
    height: 100%;
    position: relative;
    overflow: hidden;
}

.editor-main {
    flex: 1;
    display: flex;
    flex-direction: column;
    background: var(--global-background-color);
    overflow: hidden;
    min-height: 0;
}

.editor-main-content {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-height: 0;
}

#editor-sshow {
    flex: 1;
    position: relative;
    width: 100%;
    height: 100%;
    /* Touch device path — SSHOW pans / zooms via JS pointer handlers,
       so we strip every native browser touch gesture inside the
       canvas. `none` lets JS see raw pointer streams; without this,
       iOS Safari + Android Chrome interpret a left-edge horizontal
       drag as "swipe to go back". */
    touch-action: none;
}
#editor-sshow canvas {
    display: block;
    touch-action: none;
}

/* =====================================================================
 * Block history-navigation gestures across the entire editor surface
 * ---------------------------------------------------------------------
 * Magic Mouse / trackpad horizontal swipes arrive as wheel events with
 * a non-zero deltaX — touch-action does NOT catch these, and CSS
 * overscroll-behavior only takes effect on the *scrollable container*
 * the browser walks up to when no descendant absorbs the scroll. The
 * editor's canvas host has no own scroll, so without an explicit
 * boundary at the viewport (html / body) the browser escalates the
 * gesture to `history.back()`.
 *
 * Applying overscroll-behavior-x: none on the editor page's viewport
 * fixes both reported symptoms in one rule:
 *   • header-area swipe stops navigating away from the editor
 *   • canvas-area swipe after an earlier header swipe no longer
 *     re-triggers navigation
 *
 * y is set to `contain` (not `none`) so legitimate vertical scroll
 * inside the editor sidebars / panels stays usable while still
 * blocking pull-to-refresh on mobile Chrome from interrupting work.
 *
 * Scoped to body.page-editor (and the html ancestor via :has) so this
 * cannot leak into admin / marketing / play surfaces, which keep the
 * platform's default swipe-back behaviour.
 * ===================================================================== */
html:has(body.page-editor),
body.page-editor {
    overscroll-behavior-x: none;
    overscroll-behavior-y: contain;
}

/* =====================================================================
 * Responsive — icon-only on narrow viewports, label on wide
 * ===================================================================== */
@media (max-width: 768px) {
    #header-editor-controls { gap: 4px; }

    /* Secondary actions collapse to icon-only; Save keeps its label. */
    #share-btn span {
        display: none;
    }

    .header-editor-btn { padding: 0 10px; }
}

@media (max-width: 480px) {
    .header-editor-btn { padding: 0 9px; }
    .header-editor-btn-iridescent { padding: 0 12px; }
    .header-editor-btn-iridescent span { display: none; }
    /* Back button collapses to icon-only on the smallest viewports so
       the editor controls cluster keeps room. */
    .header-back-btn span { display: none; }
    .header-back-btn { padding: 0 10px; }
}

/* =====================================================================
 * Share dialog — inline "unsaved changes" hint in the footer
 * ---------------------------------------------------------------------
 * Shown when shareDialogDirty is true (any Status / Editor Access /
 * Play Access change). Communicates that Done will save those pending
 * permission edits. margin-right: auto pushes the hint left while
 * Done stays right-aligned via the default .di-dialog-footer.
 * ===================================================================== */
.share-dialog-hint {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-right: auto;
    color: rgb(180, 110, 0);
    font-family: var(--studio-font-body, 'Pretendard Variable'), sans-serif;
    font-size: 12px;
    font-weight: 500;
    letter-spacing: -0.005em;
    line-height: 1.3;
}
.share-dialog-hint[hidden] { display: none; }
.share-dialog-hint svg { flex-shrink: 0; opacity: 0.85; }
@media (prefers-color-scheme: dark) {
    .share-dialog-hint { color: rgb(255, 188, 92); }
}

/* =====================================================================
 * Dialog sections (Share)
 * ===================================================================== */
/* =====================================================================
 * ===================================================================== */
/* Rule URL strip */
/* =====================================================================
 * ===================================================================== */
/* Serial debug log lines */
/* =====================================================================
 * Share Dialog — redesigned
 * ---------------------------------------------------------------------
 *   • Section title: plain 11.5px 600 (no uppercase tracking)
 *   • Status: horizontal segmented pill row with status-colored dots
 *   • Editor/Play access: rich rows with icon + title + subtitle;
 *     active row uses neutral surface-active + a subtle accent ring
 *     drawn with box-shadow so it can't push siblings around
 * ===================================================================== */

/* ---- Tabs (Play / Permissions) -------------------------------------
 * Same animated underline indicator as `.di-dialog-tab` (canonical
 * recipe in designIdentity.css). Tabs are flat — no pills, no border,
 * no background tint — so the dialog body reads as one surface and
 * the active tab is communicated only by the underline + weight.
 * Hidden panels rely on `[hidden]` so JS only toggles the attribute.
 * ------------------------------------------------------------------- */
.share-tab-panel[hidden] { display: none; }

/* ---- Play link / Short URL rows ------------------------------------
 * Reusable row layout for "label-ish header + readonly URL input +
 * copy-or-action button on the right". Used by the play URL block
 * and both short-URL pairs (view / studio). Same density and chrome
 * as the rest of the share dialog so the two tabs feel like one
 * surface, not two stitched-together modals.
 * ------------------------------------------------------------------- */
.share-section-hint {
    display: block;
    margin-top: 4px;
    font-size: 11.5px;
    font-weight: 400;
    color: var(--global-text-muted, rgba(var(--global-text-color-rgb), 0.5));
    letter-spacing: -0.005em;
}

.share-url-row {
    display: flex;
    flex-direction: column;
    gap: 6px;
    width: 100%;
}
/* NOTE: do NOT add `margin-top` between sibling rows here — the
   parent containers (`.share-short-info`, `.share-section`) already
   own the vertical rhythm via flex `gap`. A double-spacing bug used
   to produce ~26px between the View URL and Studio URL rows in the
   Short URL section. Single source of truth = parent gap. */

.share-url-label {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 0;
}
.share-url-title {
    font-size: 12px;
    font-weight: 600;
    color: var(--global-text-color);
    letter-spacing: -0.005em;
}
.share-url-sub {
    font-size: 11px;
    color: var(--global-text-muted, rgba(var(--global-text-color-rgb), 0.5));
    letter-spacing: -0.005em;
}
.share-url-controls {
    display: flex;
    align-items: center;
    gap: 6px;
    flex: 1 1 auto;
    min-width: 0;
    width: 100%;
}

.share-url-input {
    flex: 1 1 auto;
    min-width: 0;
    height: 36px;
    padding: 0 12px;
    border: 1px solid var(--studio-hairline, rgba(var(--global-text-color-rgb), 0.1));
    border-radius: 10px;
    background: var(--global-input-background-color, rgba(var(--global-text-color-rgb), 0.04));
    color: var(--global-text-color);
    font: 500 12.5px/1 var(--studio-font-body, 'Pretendard Variable'), monospace;
    letter-spacing: -0.005em;
    outline: none;
    transition: border-color 180ms var(--studio-ease, cubic-bezier(0.22, 0.61, 0.36, 1)),
                box-shadow 180ms var(--studio-ease, cubic-bezier(0.22, 0.61, 0.36, 1));
}
.share-url-input:focus {
    border-color: var(--focus-border-color);
    box-shadow: 0 0 0 3px var(--focus-ring-color);
}
.share-url-input[readonly] { cursor: text; }

/* Single-line shortcut: when the row has no label header, keep the
   input + copy button side-by-side instead of stacking. Used by the
   Play URL row. */
.share-url-row:not(:has(.share-url-label)) {
    flex-direction: row;
    align-items: center;
    gap: 8px;
}

.share-url-copy {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    height: 36px;
    padding: 0 14px;
    border: 1px solid var(--studio-hairline, rgba(var(--global-text-color-rgb), 0.1));
    border-radius: 10px;
    background: var(--studio-surface, transparent);
    color: var(--global-text-color);
    font: 600 12px/1 var(--studio-font-body, 'Pretendard Variable'), sans-serif;
    cursor: pointer;
    flex-shrink: 0;
    transition: background 180ms var(--studio-ease, cubic-bezier(0.22, 0.61, 0.36, 1)),
                border-color 180ms var(--studio-ease, cubic-bezier(0.22, 0.61, 0.36, 1));
}
.share-url-copy:hover {
    background: var(--state-hover-bg);
    border-color: var(--studio-hairline-strong, rgba(var(--global-text-color-rgb), 0.18));
}
.share-url-copy.is-copied {
    background: rgba(82, 196, 130, 0.12);
    border-color: rgba(82, 196, 130, 0.45);
    color: rgb(46, 160, 92);
}
.share-url-copy svg { flex-shrink: 0; }
.share-url-copy:focus-visible {
    outline: 2px solid var(--focus-outline-color);
    outline-offset: 2px;
}

/* ---- Short URL — empty / present states ----------------------------
 * IMPORTANT: the next two blocks both set `display: flex`, which would
 * normally override the `[hidden]` attribute (its UA `display: none`
 * loses on specificity). The two `[hidden]` overrides at the top of
 * each rule restore the expected toggle so editor.js can swap states
 * by flipping the `hidden` attribute alone — no need to touch inline
 * styles. Without this, the dialog rendered BOTH the empty-state
 * "Generate Short URL" card AND the present-state View/Studio rows at
 * the same time, producing the bizarre vertical gap reported.
 */
.share-short-empty[hidden] { display: none; }
.share-short-empty {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 14px 16px;
    border: 1px dashed var(--studio-hairline, rgba(var(--global-text-color-rgb), 0.14));
    border-radius: 10px;
    background: var(--studio-surface, transparent);
}
.share-short-empty-text {
    margin: 0;
    font-size: 12px;
    color: var(--global-text-muted, rgba(var(--global-text-color-rgb), 0.6));
    letter-spacing: -0.005em;
}

.share-short-info[hidden] { display: none; }
.share-short-info {
    display: flex;
    flex-direction: column;
    /* Space between the View URL pair, Studio URL pair, alias block,
       and actions row. 18px reads as "separate but related" — 14px
       (previous) made the two URL pairs feel like one collapsed unit
       since each pair already has its own 6px label↔input gap. */
    gap: 18px;
}

.share-short-alias .share-url-controls { gap: 8px; }
.share-short-alias-hint {
    margin: 6px 0 0;
    font-size: 11px;
    color: var(--global-text-muted, rgba(var(--global-text-color-rgb), 0.45));
    letter-spacing: -0.005em;
}

.share-short-actions {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    padding-top: 14px;
    margin-top: 2px;
    border-top: 1px solid var(--studio-hairline, rgba(var(--global-text-color-rgb), 0.06));
}

/* ---- Mobile compaction --------------------------------------------- */
@media (max-width: 520px) {
    .share-url-row { flex-direction: column; align-items: stretch; gap: 6px; }
    .share-url-label { padding-top: 0; min-width: 0; }
    .share-short-empty { flex-direction: column; align-items: stretch; }
}

/* =====================================================================
 * Reduced motion
 * ===================================================================== */
@media (prefers-reduced-motion: reduce) {
    .editor-loading-spinner { animation: none; }
}

/* Stage submission section styles live in studio/stage-shared.css —
 * shared with the studio main page's project-settings sharing tab so
 * both surfaces look identical. */

/* ===========================================================================
 * Feedback dialog body
 * The dialog shell, header, footer, and buttons reuse the di-* primitives
 * (designIdentity.css); only the screenshot/annotation body is bespoke. All
 * neutral tokens so it tracks light/dark parity like the rest of the editor.
 * ========================================================================= */
.feedback-shot { display: flex; flex-direction: column; gap: 10px; }

/* JS toggles these via the `hidden` attribute, but the `display:*` rules below
 * would otherwise win over the UA `[hidden] { display:none }` on specificity
 * (same paired-guard convention the share dialog uses). Without these the
 * toolbar, crop actions, empty state, and remove-link all show at once. */
.feedback-tools[hidden],
.feedback-canvas-wrap[hidden],
.feedback-shot-empty[hidden],
.feedback-shot-actions[hidden],
.feedback-shot-status[hidden] { display: none; }

/* Annotation toolbar */
.feedback-tools {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    padding: 6px;
    background: var(--studio-surface);
    border: 1px solid var(--studio-hairline);
    border-radius: 10px;
}
.feedback-tools-group { display: inline-flex; align-items: center; gap: 4px; }
.feedback-tools-group + .feedback-tools-group {
    padding-left: 6px;
    border-left: 1px solid var(--studio-hairline);
}
.feedback-tools-end { margin-left: auto; border-left: none; padding-left: 0; }

.feedback-tool {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0;
    background: transparent;
    border: 1px solid transparent;
    border-radius: 8px;
    color: var(--global-text-muted);
    cursor: pointer;
    transition: background-color 180ms var(--studio-ease, ease),
                color 180ms var(--studio-ease, ease);
}
.feedback-tool:hover { background: var(--state-hover-bg); color: var(--global-text-color); }
.feedback-tool.is-active {
    background: var(--state-active-bg);
    color: var(--global-text-color);
}
.feedback-tool:focus-visible { outline: 2px solid var(--focus-outline-color); outline-offset: 2px; }

/* Color swatches */
.feedback-color {
    width: 20px;
    height: 20px;
    padding: 0;
    border-radius: 999px;
    border: 2px solid var(--global-card-background);
    background: var(--fb-c, #ff3b30);
    box-shadow: 0 0 0 1px rgba(var(--global-text-color-rgb), 0.18);
    cursor: pointer;
}
.feedback-color.is-active { box-shadow: 0 0 0 2px var(--fb-c, #ff3b30); }
.feedback-color:focus-visible { outline: 2px solid var(--focus-outline-color); outline-offset: 2px; }

/* Stroke-width swatches — a centered dot whose size hints the width */
.feedback-size {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0;
    background: transparent;
    border: 1px solid transparent;
    border-radius: 8px;
    cursor: pointer;
    transition: background-color 180ms var(--studio-ease, ease);
}
.feedback-size span { display: block; border-radius: 999px; background: var(--global-text-muted); }
.feedback-size:hover { background: var(--state-hover-bg); }
.feedback-size.is-active { background: var(--state-active-bg); }
.feedback-size.is-active span { background: var(--global-text-color); }
.feedback-size:focus-visible { outline: 2px solid var(--focus-outline-color); outline-offset: 2px; }

/* Crop confirm/cancel occupy the SAME middle slot as the pen options
 * (colors/sizes): hidden in pen mode, shown only while the crop tool is active.
 * Swapping the contextual group instead of popping buttons in/out on drag-release
 * keeps the toolbar row stable (no jolt) and the controls in a consistent place. */
.feedback-crop-actions { display: none; align-items: center; gap: 6px; }
.feedback-tools.is-crop .feedback-crop-actions { display: inline-flex; }
.feedback-tools.is-crop .feedback-colors,
.feedback-tools.is-crop .feedback-sizes { display: none; }

/* Canvas stage */
.feedback-canvas-wrap {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--studio-surface);
    border: 1px solid var(--studio-hairline);
    border-radius: 10px;
    overflow: hidden;
    touch-action: none; /* let pointer drawing own the gesture */
}
#feedback-canvas {
    display: block;
    max-width: 100%;
    max-height: 46vh;
    width: auto;
    height: auto;
}
.feedback-crop-marquee {
    position: absolute;
    border: 1px solid #fff;
    box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.45);
    pointer-events: none;
}
.feedback-shot-status {
    position: absolute;
    padding: 6px 12px;
    border-radius: 999px;
    background: rgba(var(--global-text-color-rgb), 0.7);
    color: var(--global-card-background);
    font-family: var(--studio-font-body);
    font-size: 12.5px;
}

/* Empty state (no screenshot) */
.feedback-shot-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    padding: 28px 20px;
    text-align: center;
    background: var(--studio-surface);
    border: 1px dashed var(--studio-hairline-strong, var(--studio-hairline));
    border-radius: 10px;
    color: var(--global-text-muted);
    font-family: var(--studio-font-body);
    font-size: 13px;
    word-break: keep-all;
    overflow-wrap: anywhere;
}

/* Remove-screenshot link row */
.feedback-shot-actions { display: flex; justify-content: flex-end; }
.feedback-link-btn {
    background: transparent;
    border: none;
    padding: 2px 4px;
    color: var(--global-text-muted);
    font-family: var(--studio-font-body);
    font-size: 12.5px;
    cursor: pointer;
    transition: color 180ms var(--studio-ease, ease);
}
.feedback-link-btn:hover { color: var(--global-text-color); text-decoration: underline; }
.feedback-link-btn:focus-visible { outline: 2px solid var(--focus-outline-color); outline-offset: 2px; }

/* Comment field — boxed input per DESIGN §7.5 */
.feedback-textarea {
    width: 100%;
    min-height: 88px;
    padding: 10px 12px;
    background: var(--global-input-background-color, var(--global-background-color));
    border: 1px solid rgba(var(--global-text-color-rgb), 0.14);
    border-radius: 10px;
    color: var(--global-text-color);
    font-family: var(--studio-font-body);
    font-size: 13.5px;
    line-height: 1.6;
    resize: vertical;
    box-sizing: border-box;
    transition: border-color 180ms var(--studio-ease, ease),
                box-shadow 180ms var(--studio-ease, ease);
    word-break: keep-all;
    overflow-wrap: anywhere;
}
.feedback-textarea:hover { border-color: rgba(var(--global-text-color-rgb), 0.28); }
.feedback-textarea:focus {
    outline: none;
    border-color: var(--focus-border-color);
    box-shadow: 0 0 0 3px var(--focus-ring-color);
}

.feedback-privacy,
.feedback-meta-notice {
    margin: 0;
    color: var(--global-text-muted);
    font-family: var(--studio-font-body);
    font-size: 11.5px;
    line-height: 1.5;
    word-break: keep-all;
    overflow-wrap: anywhere;
}
.feedback-meta-notice { margin-top: -4px; } /* sit close to the privacy hint as one fine-print block */
.feedback-meta-notice a {
    color: var(--global-text-muted);
    text-decoration: underline;
    text-underline-offset: 2px;
    transition: color 180ms var(--studio-ease, ease);
}
.feedback-meta-notice a:hover { color: var(--global-text-color); }
.feedback-meta-notice a:focus-visible { outline: 2px solid var(--focus-outline-color); outline-offset: 2px; border-radius: 3px; }



/* Success (thank-you) state — replaces the form after a successful send.
 * Toggled by `.is-sent` on the overlay; the form fields + footer hide so the
 * review/email-reply notice is the only thing shown. */
.feedback-success {
    display: none;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 12px;
    padding: 28px 20px 8px;
}
.feedback-success-icon { color: var(--global-success-color, #2e7dcc); }
.feedback-success-title {
    margin: 0;
    font-family: var(--studio-font-body);
    font-size: 16px;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--global-text-color);
}
.feedback-success-desc {
    margin: 0;
    max-width: 40ch;
    font-family: var(--studio-font-body);
    font-size: 13px;
    line-height: 1.6;
    color: var(--global-text-muted);
    word-break: keep-all;
    overflow-wrap: anywhere;
}
#feedback-dialog.is-sent .feedback-success { display: flex; }
#feedback-dialog.is-sent .di-dialog-body > :not(.feedback-success) { display: none; }
#feedback-dialog.is-sent .di-dialog-footer { display: none; }

/* =====================================================================
 * Shortcuts dialog — keyboard-shortcut reference (#shortcuts-dialog).
 * Command-palette chrome (dashboard main.css .cmd-palette vocabulary):
 * blurred fixed overlay + rising card, theme-aware neutral tokens. The
 * list body is populated by shortcuts.js from the engine catalog; a
 * two-column layout keeps ~50 rows glanceable, collapsing on narrow
 * windows.
 * ===================================================================== */
/* di-btn-icon's inline-flex beats the UA [hidden] rule — explicit pair so the
 * button truly disappears when the engine bundle predates the catalog export. */
#shortcuts-btn[hidden] { display: none; }

.shortcuts-overlay {
    position: fixed;
    inset: 0;
    z-index: 2050;
    display: flex;
    justify-content: center;
    align-items: flex-start;
    padding: 9vh 16px 16px;
    background: rgba(0, 0, 0, 0.32);
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
    animation: shortcuts-fade 140ms var(--studio-ease, cubic-bezier(0.22, 0.61, 0.36, 1));
}
.shortcuts-overlay[hidden] { display: none; }

@keyframes shortcuts-fade {
    from { opacity: 0; }
    to   { opacity: 1; }
}

.shortcuts-panel {
    width: min(760px, 100%);
    max-height: 78vh;
    display: flex;
    flex-direction: column;
    background: var(--global-card-background);
    border: 1px solid var(--studio-hairline-strong, rgba(0, 0, 0, 0.14));
    border-radius: 14px;
    box-shadow: 0 24px 60px -20px rgba(0, 0, 0, 0.35);
    overflow: hidden;
    animation: shortcuts-rise 180ms var(--studio-ease, cubic-bezier(0.22, 0.61, 0.36, 1));
}
@keyframes shortcuts-rise {
    from { opacity: 0; transform: translateY(-8px) scale(0.985); }
    to   { opacity: 1; transform: translateY(0)    scale(1); }
}

.shortcuts-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 14px 18px 12px;
    border-bottom: 1px solid var(--studio-hairline, rgba(0, 0, 0, 0.08));
}
.shortcuts-title {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0;
    font-family: var(--studio-font-body);
    font-size: 15px;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--global-text-color);
}
.shortcuts-title svg { color: var(--global-text-muted); }

.shortcuts-list {
    overflow-y: auto;
    padding: 8px 18px 18px;
    column-count: 2;
    column-gap: 32px;
}
.shortcuts-section { break-inside: avoid; }
.shortcuts-section-title {
    font-family: var(--studio-font-body);
    font-size: 10.5px;
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--global-text-muted);
    padding: 12px 0 4px;
}
.shortcuts-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 5px 0;
    font-family: var(--studio-font-body);
    font-size: 13px;
    color: var(--global-text-color);
}
.shortcuts-row-label {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.shortcuts-keys {
    display: flex;
    align-items: center;
    gap: 4px;
    flex-shrink: 0;
}
.shortcuts-kbd {
    font-family: var(--studio-font-body);
    font-size: 10.5px;
    font-weight: 600;
    letter-spacing: 0.05em;
    padding: 2px 6px;
    border: 1px solid var(--studio-hairline-strong, rgba(0, 0, 0, 0.18));
    border-bottom-width: 2px;
    border-radius: 5px;
    color: var(--global-text-muted);
    background: var(--state-hover-bg, rgba(0, 0, 0, 0.04));
    white-space: nowrap;
}
.shortcuts-or {
    font-size: 10px;
    color: var(--global-text-muted);
}

@media (max-width: 760px) {
    .shortcuts-list { column-count: 1; }
}

/* =====================================================================
 * Playground header (/playground, /playground/:id)
 * ---------------------------------------------------------------------
 * The editor.s.show trial-bar moved onto the studio shell: brand lockup
 * (SOLID glyph + Paperlogy wordmark, reusing the #header-logo layout
 * from studio/index.css) on the left, a sign-in cue on the right. The
 * CTA is the page's single iridescent moment (DESIGN.md §0.2) — the
 * glyph stays solid because §1 bars the iridescent mark from UI chrome.
 * ===================================================================== */
.playground-mark {
    height: 20px;
    width: auto;
    aspect-ratio: 603 / 958;
    flex-shrink: 0;
    fill: currentColor;
}
#playground-actions {
    grid-column: 3;
    justify-self: end;
    display: inline-flex;
    align-items: center;
    gap: 14px;
    min-width: 0;
}
.playground-note {
    margin: 0;
    font-size: 12.5px;
    font-weight: 400;
    letter-spacing: -0.005em;
    white-space: nowrap;
    color: var(--global-text-muted);
}
.playground-cta {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    height: 32px;
    padding: 0 15px;
    border-radius: 999px;
    font-size: 13px;
    font-weight: 600;
    letter-spacing: -0.005em;
    white-space: nowrap;
    color: #fff;
    background: var(--brand-iridescent-gradient);
    background-size: 300% 300%;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
    animation: brand-iridescent-shift 20s ease infinite;
    transition: transform 0.18s var(--studio-ease), opacity 0.18s var(--studio-ease);
}
.playground-cta:hover { transform: translateY(-1px); opacity: 0.96; }
.playground-cta svg { flex-shrink: 0; transition: transform 0.3s var(--studio-ease); }
.playground-cta:hover svg { transform: translateX(2px); }
.playground-cta:focus-visible {
    outline: 2px solid var(--focus-outline-color);
    outline-offset: 2px;
}
.playground-cta[hidden] { display: none; }
.playground-note[hidden] { display: none; }

@media (max-width: 640px) {
    .playground-note { display: none; }
    .playground-cta { height: 30px; padding: 0 12px; font-size: 12px; }
}
@media (prefers-reduced-motion: reduce) {
    .playground-cta,
    .playground-cta svg { transition: none; animation: none; }
    .playground-cta:hover { transform: none; }
    .playground-cta:hover svg { transform: none; }
}
