/* ════════════════════════════════════════════════════════════════════════════
   image_panel.css — THE single owner of the image-panel component.

   Component contract:
     [data-image-panel] / .image-panel    The host container
     .has-preview                          State class — image is loaded
     .canvas-wrap                          Wrapper around the rendered img
     .preview-image                        The rendered img element itself
     .wf-dz-idle / .desktop-dropzone       The upload-zone idle UI

   Sizing contract (CSS variables — set on a parent to override):
     --ip-min-h         min height of the panel when no image
     --ip-min-h-empty   min height when fully idle (smaller, compact)
     --ip-max-h         max height of the panel content area
     --ip-max-h-image   max height of the <img> inside .canvas-wrap
     --ip-max-w-image   max width of the <img> (default 100%)
     --ip-pad           internal padding around content
     --ip-radius        border radius of the preview image
     --ip-overflow      overflow behavior when image is loaded

   Override at the host (.pipeline-popup-mode body, an iframe parent, a
   media query, or a per-tool selector) — NEVER override at the component.
   This is mechanically enforced by .cursor/hooks/check_image_panel_isolation.py.

   Authored 2026-04-25 to consolidate ~110 scattered selectors in 10 files
   that were fighting each other through !important escalation. See
   .cursor/audits/_synthesis.md (8-model code audit) for the full history
   and the convergent fix plan this file implements.
   ════════════════════════════════════════════════════════════════════════════ */

/* ── Root contract: defaults applied to every image panel ───────────────── */
:where([data-image-panel]),
:where(.image-panel) {
    --ip-min-h:         360px;
    --ip-min-h-empty:   120px;
    --ip-max-h:         70vh;
    --ip-max-h-image:   100%;
    --ip-max-w-image:   100%;
    --ip-pad:           0.5rem;
    --ip-radius:        6px;
    --ip-overflow:      hidden;
}

/* ── Base preview-image: hidden until host gets .has-preview ──────────────
   Standalone <img class="preview-image"> elements (legacy custom-route
   screens like .demo-effect-screen-magazine) toggle visibility via a
   .has-preview class on a parent. The base hidden rule used to live in
   03-workspace.css with a 480px cap; the cap was removed (it was the
   actual "image looks tiny" bug) but the hidden default stays. */
.preview-image {
    display: none;
}

/* ── Empty state: panel is compact, idle UI is centred ──────────────────── */
[data-image-panel],
.image-panel,
.paste-box {
    min-height: var(--ip-min-h-empty);
    overflow:   hidden;
    transition: min-height .2s ease;
}

/* The .paste-box variant of the host needs flex when empty so the
   "drop here" icon can naturally fill the gap. */
.paste-box[data-image-panel]:not(.has-preview) {
    display:        flex;
    flex-direction: column;
}

/* ── Loaded state: panel grows, preview is centred and contained ────────── */
[data-image-panel].has-preview,
.image-panel.has-preview,
.paste-box.has-preview {
    min-height: auto;
    /* Allow draw-canvas brush strokes to reach true image edges. */
    overflow:   visible;
}

[data-image-panel].has-preview .canvas-wrap,
.image-panel.has-preview .canvas-wrap,
.paste-box.has-preview .canvas-wrap {
    display:         flex;
    align-items:     center;
    justify-content: center;
    padding:         var(--ip-pad);
    max-height:      var(--ip-max-h);
    overflow:        var(--ip-overflow);
}

[data-image-panel].has-preview .preview-image,
.image-panel.has-preview .preview-image,
.paste-box.has-preview .preview-image {
    display:        block;
    max-width:      var(--ip-max-w-image);
    max-height:     var(--ip-max-h-image);
    width:          auto;
    height:         auto;
    object-fit:     contain;
    border-radius:  var(--ip-radius);
}

/* ── 2-panel workspace context: panels grow, previews can be larger ─────── */
.wf-2panel-workspace [data-image-panel] {
    flex:           1;
    min-height:     var(--ip-min-h);
    display:        flex;
    flex-direction: column;
}

.wf-2panel-workspace--count-1 [data-image-panel] {
    --ip-min-h: 480px;
}

.wf-2panel-workspace .preview-image {
    max-width:  100%;
    max-height: var(--ip-max-h);
    width:      auto;
    height:     auto;
    object-fit: contain;
}

.wf-2panel-workspace .canvas-wrap {
    margin-top: 14px;
    display:    flex;
    justify-content: center;
    width:      100%;
}

.wf-2panel-workspace .wf-dz-idle.desktop-dropzone {
    margin:     auto;
    text-align: center;
    padding:    28px 18px;
}

/* Compact upload variant — smaller panel for preview+upload pairings. */
.wf-2panel-upload-compact [data-image-panel] {
    --ip-min-h: 220px;
    min-height: 220px;
}

.wf-2panel-upload-compact .preview-image {
    max-height: 240px;
}

/* ── Wired-from-pipeline state: hide upload affordances ─────────────────── */
/*
   When a tool's image input is fed from an upstream pipeline node, the
   panel marks itself with data-pipeline-wired="1" (image_panel.js). The
   image source lives on the canvas node, not in this popup, so the
   upload zone, paste button, mobile camera row, and shelf bar are
   suppressed. The preview itself stays visible.
   This was previously scoped to .pipeline-popup-mode only — but a wired
   panel is wired regardless of where it renders, so the new rules drop
   the popup-mode prefix.
*/
[data-image-panel][data-pipeline-wired="1"] .wf-dz-idle,
[data-image-panel][data-pipeline-wired="1"] .desktop-dropzone,
[data-image-panel][data-pipeline-wired="1"] .mobile-upload-row,
[data-image-panel][data-pipeline-wired="1"] .wf-shelf-bar,
[data-image-panel][data-pipeline-wired="1"] [data-dz-open-rail],
[data-image-panel][data-pipeline-wired="1"] [data-dz-paste] {
    display: none !important;
}

[data-image-panel][data-pipeline-wired="1"] {
    min-height:   0;
    border-style: dashed;
    border-color: rgba(255, 122, 26, 0.25);
}

[data-image-panel][data-pipeline-wired="1"]::before {
    content:        "From pipeline";
    display:        block;
    font-size:      10px;
    font-weight:    700;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color:          rgba(255, 122, 26, 0.55);
    padding:        4px 8px 0;
}

/* ── Preview action links (Replace / Remove) ────────────────────────────── */
.wf-preview-actions {
    display:         none;
    justify-content: center;
    gap:             1.25rem;
    padding:         .35rem 0 .25rem;
}

.has-preview .wf-preview-actions {
    display: flex;
}

.wf-preview-action {
    background:  none;
    border:      none;
    color:       var(--muted, #777);
    font-size:   11px;
    cursor:      pointer;
    font-family: inherit;
    padding:     2px 4px;
    transition:  color .15s;
}

.wf-preview-action:hover {
    color: var(--text, #eee);
}

.wf-preview-action--remove:hover {
    color: #e55;
}

/* ── Drop-target hover affordance ──────────────────────────────────────── */
[data-image-panel]:hover .drop-icon-hint,
[data-image-panel].is-drop-target .drop-icon-hint {
    opacity: 0.55;
}

[data-image-panel].has-preview .drop-icon-hint {
    display: none;
}

/* ════════════════════════════════════════════════════════════════════════════
   HOST-LEVEL OVERRIDES — set CSS variables, never properties.

   These are the ONLY places where context (popup, mobile, per-tool) is
   allowed to redefine sizing. Adding a new context = adding a one-line
   variable redefinition here, NOT a new selector chain elsewhere.
   ════════════════════════════════════════════════════════════════════════════ */

/* Pipeline popup mode: panels render inside an iframe whose height IS the
   modal frame minus its chrome. Cap previews to ~half the iframe so the
   form controls (Generate, options, textareas) stay visible without
   forcing the user to scroll past a wall of pixels. The 420px ceiling
   stops tall portraits from dominating on tall displays.

   BEFORE this rule existed as one variable override, the same effect
   was achieved by calc(100dvh - 230px) split across FIX.css,
   FORCE_IMAGE_FIT.css, workflow_unified.css:1341, 12-2panel.css:290,
   12-2panel.css:457 — five !important rules fighting each other. */
.pipeline-popup-mode {
    --ip-max-h: min(420px, calc(50dvh - 40px));
}

/* Texture Transfer popup: a busier left column (gallery + material grid +
   two textareas). Tighter cap keeps Generate bar reachable.
   Replaces the 31-selector block formerly at 12-2panel.css:307–470. */
.pipeline-popup-mode [data-wf-form][data-wf-slug="texture-aifi-it"] {
    --ip-max-h: min(360px, calc(50dvh - 40px));
}

/* ════════════════════════════════════════════════════════════════════════════
   STREAM HISTORY PICKER (Track 2 — t2-image-history)

   When a tool panel opens inside a pipeline popup we expose a "Stream" button
   in the drop zone actions row. Clicking it reveals a horizontal strip of
   thumbnails for every image that already exists on the active stream
   (Photo source nodes + tool outputs). Clicking a thumbnail loads it into
   THIS panel via the existing __loadShelfAsset entry point.

   Why this lives in image_panel.css: the strip is a child of [data-image-panel]
   and inherits the wired/has-preview hide rules above for free. Keeping the
   styling co-located with the panel means the rules can never drift apart
   from the host they target.
   ════════════════════════════════════════════════════════════════════════════ */

/* Stream button — same visual weight as the other drop-zone actions.
   Hidden by default; image_panel.js reveals it once the parent editor
   responds to aifi-stream-history-request with a non-empty payload. */
.wf-dz-btn--stream {
    /* Inherits .wf-dz-btn base styling (defined in 09-home.css). The only
       reason to override here is so the count badge can sit inline. */
    align-items: center;
    gap: 6px;
}

.wf-dz-btn--stream[hidden] {
    display: none !important;
}

.wf-dz-stream-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    margin-left: 2px;
    padding: 0 6px;
    min-width: 18px;
    height: 16px;
    font-size: 10px;
    font-weight: 600;
    line-height: 1;
    background: rgba(201, 168, 76, 0.22);
    border-radius: 8px;
    color: rgba(245, 233, 200, 0.95);
}

.wf-dz-stream-count:empty {
    display: none;
}

/* Thumbnails strip — appears below the actions row when the user clicks
   "Stream". Horizontal scroll if the stream is long. */
.wf-stream-history {
    display: flex;
    flex-wrap: wrap;
    align-content: flex-start;
    gap: 8px;
    padding: 10px;
    margin-top: 10px;
    background: rgba(15, 13, 11, 0.62);
    border: 1px solid rgba(201, 168, 76, 0.22);
    border-radius: 10px;
    max-height: 220px;
    overflow-y: auto;
    backdrop-filter: blur(8px) saturate(115%);
    -webkit-backdrop-filter: blur(8px) saturate(115%);
}

.wf-stream-history[hidden] {
    display: none !important;
}

.wf-stream-history-empty {
    flex: 1;
    text-align: center;
    font-size: 11px;
    color: rgba(245, 233, 200, 0.55);
    padding: 14px 8px;
}

.wf-stream-history-item {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    width: 76px;
    padding: 0;
    background: rgba(20, 18, 16, 0.55);
    border: 1px solid rgba(201, 168, 76, 0.20);
    border-radius: 8px;
    cursor: pointer;
    overflow: hidden;
    transition: border-color 0.18s ease, transform 0.18s ease;
    font-family: inherit;
}

.wf-stream-history-item:hover,
.wf-stream-history-item:focus-visible {
    border-color: rgba(201, 168, 76, 0.62);
    transform: translateY(-1px);
    outline: none;
}

.wf-stream-history-item img {
    display: block;
    width: 100%;
    height: 56px;
    object-fit: cover;
    background: rgba(0, 0, 0, 0.35);
}

.wf-stream-history-item-label {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    padding: 3px 4px 5px;
    font-size: 9px;
    font-weight: 500;
    line-height: 1.2;
    text-align: center;
    color: rgba(245, 233, 200, 0.78);
    white-space: normal;
}

/* The "source" / "output" affordance — a tiny corner dot so the user knows
   if a thumb came from a Photo source node vs a tool render. */
.wf-stream-history-item[data-stream-kind="output"] {
    border-left: 2px solid rgba(255, 122, 26, 0.55);
}
.wf-stream-history-item[data-stream-kind="source"] {
    border-left: 2px solid rgba(140, 200, 255, 0.45);
}
