/* ============================================================
   FLIPPY - Mobile-First Stylesheet
   ============================================================ */

@font-face {
  font-family: 'FestivoLC';
  src: url('../fonts/FestivoLCBasic.woff') format('woff');
  font-weight: normal;
  font-style: normal;
  font-display: swap;
}

*, *::before, *::after {
  box-sizing: border-box;
  -webkit-tap-highlight-color: transparent;
}

:root {
  --bg: #c0c0c0;
  --bg2: #c0c0c0;
  --bg3: #c0c0c0;
  /* Darker page surface (preview/frame/timeline) so foreground elements stand out */
  --surface-bg: #a0a0a0;
  --surface-bg-hover: #9a9a9a;
  --border: #808080;
  --accent: #000080;
  --accent2: #00007a;
  --text: #000000;
  --text-muted: #444444;
  --danger: #800000;
  /* Win98 bevel */
  --bevel-ll: #ffffff;
  --bevel-l:  #dfdfdf;
  --bevel-d:  #808080;
  --bevel-dd: #404040;
  /* Win98 button */
  --btn-bg: #c0c0c0;
  --btn-border: 2px solid;
  --btn-bevel: border-color var(--bevel-ll) var(--bevel-d) var(--bevel-d) var(--bevel-ll);
  --gif-panel-height: 56px;
  --timeline-height: 110px;
  --header-height: 56px;
  --controls-height: 46px;
  --frame-controls-height: 52px;
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-left: env(safe-area-inset-left, 0px);
  --safe-right: env(safe-area-inset-right, 0px);
  --thumb-ar: 1.5;           /* timeline thumbnail aspect ratio, updated by JS */
  --thumb-chrome: 8px;       /* .image-item padding (3px x2) + .item-thumb border (1px x2) */
}

html, body {
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
  /* Header grey so the iOS standalone PWA status-bar strip (OS-painted from the
     body background) matches the top header panel. #app paints the darker page
     grey over the full viewport, so the visible page background is unchanged. */
  background: var(--bg);
  color: var(--text);
  font-family: 'MS Sans Serif', 'Microsoft Sans Serif', Tahoma, Arial, sans-serif;
  font-size: 11px;
  overflow: hidden;
}

#app {
  display: flex;
  flex-direction: column;
  height: 100%;
  width: 100%;
  overflow: hidden;
  background: var(--surface-bg);
  padding-bottom: var(--safe-bottom);
}

/* Use the dynamic viewport height so the app always fits the *visible* area.
   Plain 100% can resolve taller than the visible viewport on mobile (retractable
   browser/system UI), which in landscape pushed the timeline off the bottom. */
@supports (height: 100dvh) {
  #app {
    height: 100dvh;
  }
}

body.lite-web-fullscreen-portrait #app::before {
  content: '';
  flex: 0 0 max(calc(env(safe-area-inset-top, 28px) * 0.75), 21px);
  background: var(--bg);
}

/* HEADER */
#header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 4px;
  height: var(--header-height);
  background: var(--bg);
  border-bottom: 2px solid;
  border-color: var(--bevel-ll) var(--bevel-d) var(--bevel-d) var(--bevel-ll);
  flex-shrink: 0;
  z-index: 10;
}

.header-left {
  display: flex;
  align-items: center;
  gap: 8px;
  position: relative;
}

.header-left h1 {
  margin: 0;
  font-family: 'FestivoLC', sans-serif;
  font-size: 1.6rem;
  font-weight: normal;
  letter-spacing: 1px;
  color: var(--text);
}

.header-actions {
  display: flex;
  gap: 4px;
  align-items: center;
}

.header-auth-btn {
  height: 38px;
  padding: 5px 12px;
  white-space: nowrap;
}

.header-user {
  position: relative;
  display: flex;
  align-items: center;
  min-width: 0;
}

.header-user-avatar {
  width: 28px;
  height: 28px;
  border: 1px solid var(--bevel-d);
  object-fit: cover;
  background: var(--bg2);
  display: block;
}

.header-avatar-btn {
  min-width: 38px;
  min-height: 38px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 2px;
  background: var(--btn-bg);
  border: 2px solid;
  border-color: var(--bevel-ll) var(--bevel-d) var(--bevel-d) var(--bevel-ll);
  cursor: pointer;
}

.header-avatar-btn:active,
.header-avatar-btn.is-open {
  border-color: var(--bevel-d) var(--bevel-ll) var(--bevel-ll) var(--bevel-d);
}

/* Site name next to logo — match gallery .header-title style */
.header-site-name {
  font-size: 18px;
  font-weight: bold;
  letter-spacing: 0.5px;
  color: var(--text, #000);
  pointer-events: none;
  white-space: nowrap;
  line-height: 1;
}

#header-project-title {
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: min(34vw, 320px);
}

.autosave-status {
  display: none;
  margin-left: 6px;
  padding: 2px 6px;
  background: #ffffcc;
  border: 1px solid #808080;
  box-shadow: inset 1px 1px 0 #fff;
  color: #333;
  font-size: 11px;
  font-weight: bold;
  line-height: 1.2;
  white-space: nowrap;
}

.autosave-status.is-visible {
  display: inline-flex;
  align-items: center;
}

/* The "Autosaving..." badge shows only while a save is running (JS toggles .is-visible).
   The reskin's after-dark.css has `body.editor-tab-active #autosave-status { display: inline }`,
   an ID selector that would keep it on all the time, so this overrides it for the idle state. */
body.editor-tab-active #autosave-status:not(.is-visible) { display: none !important; }

/* Header menu button uses the shared beveled icon styling from site-header.css. */
#btn-logo-menu.header-avatar-btn {
  flex-shrink: 0;
}

.header-user-menu {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  min-width: 100px;
  background: var(--bg);
  border: 2px solid;
  border-color: var(--bevel-ll) var(--bevel-d) var(--bevel-d) var(--bevel-ll);
  box-shadow: 2px 2px 0 #000;
  padding: 2px;
  z-index: 40;
}

#logo-menu-dropdown {
  min-width: 190px;
}

#logo-menu-dropdown .header-user-menu-item {
  white-space: nowrap;
}

.header-user-menu-email {
  display: block;
  max-width: 220px;
  padding: 5px 10px 6px;
  margin-bottom: 2px;
  border-bottom: 1px solid var(--bevel-d);
  box-shadow: 0 1px 0 0 var(--bevel-ll);
  color: var(--text);
  opacity: 0.65;
  font-size: 11px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.header-user-menu-email ~ .header-user-menu-item {
  padding-left: 16px;
}

.header-user-menu-item {
  display: block;
  width: 100%;
  box-sizing: border-box;
  padding: 7px 10px;
  background: transparent;
  border: 0;
  color: var(--text);
  text-align: left;
  text-decoration: none;
  font: inherit;
  cursor: pointer;
}

.header-user-menu-item:hover,
.header-user-menu-item:focus {
  background: var(--accent);
  color: #fff;
  outline: none;
}

.header-user-menu-separator {
  height: 1px;
  margin: 2px 4px;
  background: #808080;
  border-bottom: 1px solid #fff;
}

.btn-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border: 2px solid;
  border-color: var(--bevel-ll) var(--bevel-d) var(--bevel-d) var(--bevel-ll);
  box-shadow: inset 1px 1px 0 var(--bevel-l), inset -1px -1px 0 var(--bevel-dd);
  border-radius: 0;
  background: var(--btn-bg);
  color: var(--text);
  cursor: pointer;
}

.btn-icon:disabled { opacity: 0.5; cursor: default; pointer-events: none; }

.btn-icon:active {
  border-color: var(--bevel-d) var(--bevel-ll) var(--bevel-ll) var(--bevel-d);
  box-shadow: inset 1px 1px 0 var(--bevel-dd), inset -1px -1px 0 var(--bevel-l);
}

.btn-icon:hover { background: var(--btn-bg); }

.btn-add-files {
  background: var(--btn-bg);
  color: var(--text);
}

/* TIMELINE WRAPPER — sort controls float as overlay over timeline. */
#timeline-wrapper {
  position: relative;
  flex: 0 0 var(--timeline-height);
  height: var(--timeline-height);
  border-top: 2px solid;
  border-color: var(--bevel-d) var(--bevel-ll) var(--bevel-ll) var(--bevel-d);
  overflow: visible;
  background: var(--surface-bg);
}

/* CONTROLS BAR — floating overlay at top-left of timeline */
#controls-bar {
  position: absolute;
  top: 5px;
  left: 8px;
  z-index: 5;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 4px 8px;
  background: var(--bg);
  border: 2px solid;
  border-color: var(--bevel-ll) var(--bevel-d) var(--bevel-d) var(--bevel-ll);
  box-shadow: inset 1px 1px 0 var(--bevel-l), inset -1px -1px 0 var(--bevel-dd);
  border-radius: 0;
  max-width: calc(100% - 16px);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  pointer-events: auto;
}

#controls-bar::-webkit-scrollbar { display: none; }

.sort-group {
  display: flex;
  align-items: center;
  gap: 4px;
  flex-shrink: 0;
}

.sort-label {
  font-size: 0.75rem;
  color: var(--text-muted);
  margin-right: 2px;
  white-space: nowrap;
}

.sort-btn {
  padding: 3px 8px;
  border: 2px solid;
  border-color: var(--bevel-ll) var(--bevel-d) var(--bevel-d) var(--bevel-ll);
  box-shadow: inset 1px 1px 0 var(--bevel-l), inset -1px -1px 0 var(--bevel-dd);
  border-radius: 0;
  background: var(--btn-bg);
  color: var(--text);
  font-size: 11px;
  cursor: pointer;
  white-space: nowrap;
}

.sort-btn:hover { background: var(--btn-bg); }
.sort-btn:active,
.sort-btn.active {
  border-color: var(--bevel-d) var(--bevel-ll) var(--bevel-ll) var(--bevel-d);
  box-shadow: inset 1px 1px 0 var(--bevel-dd), inset -1px -1px 0 var(--bevel-l);
  color: var(--text);
}
.sort-arrow { font-size: 0.92rem; opacity: 0.8; }

.fps-group {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
}

.fps-group label { font-size: 0.75rem; color: var(--text-muted); white-space: nowrap; }

.fps-group input {
  width: 48px;
  padding: 4px 6px;
  background: var(--bg3);
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--text);
  font-size: 0.8rem;
  text-align: center;
}

.fps-group input:focus { outline: none; border-color: var(--accent); }

/* IMAGE LIST — horizontal timeline in both orientations. */
#image-list-container {
  width: 100%;
  height: 100%;
  overflow-y: hidden;
  overflow-x: scroll;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain;
}

#image-list {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  height: 100%;
  align-items: stretch;
  padding: 5px;
  gap: 4px;
  overflow: visible;
}

/* ── Live preview canvas (replaces the old encoded <img>/<video> preview) ── */
/* Frames are rendered at PREVIEW_OUTPUT_WIDTH (360px); 360px is a MAX (never upscale
   past it or it pixelates), not a fixed width. `min(100%, 360px)` lets it shrink
   to the panel's content area — matching #frame-canvas below — so on narrow panels
   (e.g. native iOS) the preview fits within the same clearances as the frame
   editor instead of overflowing at a hard 360px. */
#preview-canvas {
  width: auto;
  height: auto;
  max-width: min(100%, 360px);
  max-height: 100%;
  object-fit: contain;
  image-rendering: auto;
}

/* Play/pause preview button — swap the icon by playing state. */
#btn-play-pause .icon-play { display: none; }
#btn-play-pause .icon-pause { display: block; }
#btn-play-pause:not(.is-playing) .icon-play { display: block; }
#btn-play-pause:not(.is-playing) .icon-pause { display: none; }

/* Timeline frame card — thumbnail only. */
.image-item {
  position: relative;
  display: flex;
  flex-direction: column;
  flex-shrink: 0;
  /* --thumb-ar is the shape of the THUMBNAIL IMAGE, and box-sizing is border-box,
     so the card has to be the image plus its chrome — 3px padding each side and the
     1px .item-thumb border each side. Sizing the outer box at --thumb-ar instead
     left the inner box at 1.80 against a 1.73 thumbnail, which object-fit: cover
     then trimmed 3.7% off the top and bottom of: the timeline disagreed with the
     preview on every frame. */
  width: calc((var(--timeline-height) - 18px - var(--thumb-chrome)) * var(--thumb-ar) + var(--thumb-chrome));
  min-width: 60px;
  max-width: 160px;
  height: calc(var(--timeline-height) - 18px);
  padding: 3px;
  gap: 0;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}

.item-thumb {
  width: 100%;
  height: 100%;
  flex: 1;
  /* Contain, never cover: a thumbnail shows the whole frame the preview shows.
     With the card sized above the two agree exactly, so there is nothing to letter-
     box; the fallback only matters where max-width clamps the card. A borderless
     deck whose own shape is not 1.73:1 shrinks to fit here rather than being cut. */
  object-fit: contain;
  border-radius: 0;
  min-height: 0;
  background: var(--bg3);
  border: 1px solid var(--bevel-d);
  -webkit-touch-callout: none;
  user-select: none;
  -webkit-user-select: none;
  pointer-events: none; /* let the parent .image-item handle events */
}

.item-info, .drag-handle, .item-actions { display: none; }

.frame-num {
  position: absolute;
  top: 4px;
  left: 4px;
  z-index: 3;
  font-size: 9px;
  font-weight: 700;
  line-height: 1;
  color: var(--text);
  background: var(--bg);
  border: 1px solid var(--bevel-d);
  padding: 2px 4px;
  pointer-events: none;
  user-select: none;
}

/* Selected frame highlight */
.image-item.selected-frame {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  border-radius: 0;
}

#empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100%;
  padding: 40px 20px;
  text-align: center;
  color: var(--text-muted);
}

.empty-icon { margin-bottom: 16px; }
#empty-state p { margin: 4px 0; font-size: 0.95rem; }
#empty-state .empty-sub { font-size: 0.82rem; margin-top: 8px; }

/* UNIFIED EDITOR / GALLERY TABS */
#workspace-main {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  background: var(--surface-bg);
  overflow: hidden;
}

/* Folder tabs. Each tab's shape is a flat rounded-top face drawn by a ::before,
   matching the flat vertical/landscape tabs. Tabs are the gallery grey
   (--surface-bg) on a darker strip; they overlap each other slightly for a
   layered feel. The tab face stays within the strip so it doesn't cover the panel
   below; the active tab (black text, gallery grey) reads as the front layer.
   Light weight, slightly larger text for legibility. */
#workspace-tabs {
  flex: 0 0 34px;
  display: flex;
  align-items: flex-end;
  gap: 0;
  background: #7f7f7f;              /* darker strip behind the tabs */
  padding: 6px 10px 0;
  z-index: 3;
}

.workspace-tab {
  position: relative;
  flex: 0 0 auto;
  min-width: 84px;
  margin: 0 -10px 0 0;             /* overlap the next tab for a layered look */
  padding: 5px 26px 6px;          /* right padding clears the overlap */
  border: 0;
  background: transparent;
  color: #333;                     /* inactive: dark grey text, not black */
  font: inherit;
  font-size: 13px;
  font-weight: 400;               /* non-bold: easier to read at this size */
  cursor: pointer;
  z-index: 1;
}

/* The rounded tab face — anchored at the bottom so it stays within the strip and
   never overlaps the panel content below. */
.workspace-tab::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  z-index: -1;
  background: #949494;             /* inactive: slightly dimmer than the panel */
  border-radius: 10px 10px 0 0;
  /* Inset top highlight + soft side shadows so each tab casts onto the tab it
     overlaps, giving the stacked strip a layered, depth-cued look. Flat (no
     perspective taper) to match the vertical/landscape tabs. */
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.28),
    -3px 0 5px -2px rgba(0, 0, 0, 0.35),
    3px 0 5px -2px rgba(0, 0, 0, 0.35);
  transform: none;
}

.workspace-tab:hover { color: #000; }
.workspace-tab:hover::before { background: #b0b0b0; }

.workspace-tab.active {
  color: #000;                     /* active: black text */
  font-weight: 500;               /* a touch heavier to mark the selection */
  z-index: 3;                      /* the front layer, above the overlap */
}

.workspace-tab.active::before {
  background: var(--surface-bg);   /* == gallery grey, matches the panel */
  /* No shadow on the active tab: same grey as its panel and in front, so the
     neighbouring tabs' shadows tuck behind it and it merges seamlessly with the
     panel below — matching the seamless active tab in the landscape strip. */
  box-shadow: none;
}

/* Layered depth ordering. The active tab is the front layer; each remaining tab
   recedes behind it. When two background tabs stack on the same side (Editor or
   Admin active), the furthest-back one is dimmer so the layers read distinctly. */
#workspace-tabs[data-active="editor"] #tab-editor { z-index: 30; }
#workspace-tabs[data-active="editor"] #tab-gallery { z-index: 20; }
#workspace-tabs[data-active="editor"] #tab-admin  { z-index: 10; }

#workspace-tabs[data-active="gallery"] #tab-gallery { z-index: 30; }
#workspace-tabs[data-active="gallery"] #tab-editor  { z-index: 20; }
#workspace-tabs[data-active="gallery"] #tab-admin   { z-index: 20; }

#workspace-tabs[data-active="admin"] #tab-admin   { z-index: 30; }
#workspace-tabs[data-active="admin"] #tab-gallery { z-index: 20; }
#workspace-tabs[data-active="admin"] #tab-editor  { z-index: 10; }

#workspace-tabs[data-active="editor"] #tab-admin::before,
#workspace-tabs[data-active="admin"] #tab-editor::before {
  background: #868686;             /* furthest-back layer: dimmer than #949494 */
}

#workspace-tab-panels {
  flex: 1;
  min-width: 0;
  min-height: 0;
  display: flex;
  overflow: hidden;
}

.workspace-panel {
  flex: 1;
  min-width: 0;
  min-height: 0;
  display: none;
}

.workspace-panel.active {
  display: flex;
}

#editor-view {
  flex-direction: column;
}

/* Gated admin tab panel (injected at runtime for admins only). */
#admin-view {
  flex-direction: column;
  overflow: auto;
  -webkit-overflow-scrolling: touch;
}

.workspace-tab.tab-disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

#gallery-view {
  position: relative;
  --gallery-overlay-top: 0px;
  --gallery-overlay-left: 0px;
  --gallery-overlay-width: 100vw;
  --gallery-overlay-height: 100vh;
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  background: var(--body-bg, var(--surface-bg));
}

#gallery-view .gallery-main {
  width: 100%;
  min-height: 100%;
  box-sizing: border-box;
}

body.gallery-tab-active #timeline-wrapper,
body.admin-tab-active #timeline-wrapper {
  display: none;
}

html.initial-gallery-tab #editor-view,
html.initial-gallery-tab #timeline-wrapper {
  display: none;
}

html.initial-gallery-tab #gallery-view {
  display: flex;
}

/* The gallery panel must be a block, not a flex container. Its quick-return
   toolbar uses position:sticky, and a sticky child does NOT stick inside a flex
   scroll container (Chromium/WebKit) — as a flex panel the toolbar scrolled away
   with the grid instead of pinning to the top edge, so it only reappeared near
   the very top. Block display restores sticky; .gallery-main already lays out via
   width:100% + margin:0 auto, so nothing else changes. These override both the
   .workspace-panel.active flex and the initial-gallery-tab flex above. */
#gallery-view.workspace-panel.active,
html.initial-gallery-tab #gallery-view {
  display: block;
}

body.gallery-tab-active #inline-handle-svg,
body.gallery-tab-active #handle-svg,
body.gallery-tab-active #corner-loupe,
body.gallery-tab-active #inline-corner-loupe,
body.gallery-tab-active #onnx-progress-bar,
body.admin-tab-active #inline-handle-svg,
body.admin-tab-active #handle-svg,
body.admin-tab-active #corner-loupe,
body.admin-tab-active #inline-corner-loupe,
body.admin-tab-active #onnx-progress-bar {
  display: none !important;
}

#gallery-view .overlay,
#gallery-view .overlay-backdrop,
#gallery-view .profile-backdrop {
  position: fixed;
  top: var(--gallery-overlay-top);
  left: var(--gallery-overlay-left);
  width: var(--gallery-overlay-width);
  height: var(--gallery-overlay-height);
  inset: auto;
}

#gallery-view .overlay {
  align-items: center;
  justify-content: center;
  z-index: 20;
}

#gallery-view .overlay-backdrop {
  z-index: 19;
}

#gallery-view .profile-backdrop {
  z-index: 29;
}

#gallery-view .profile-popup {
  position: absolute;
  z-index: 30;
}

@media (orientation: portrait) {
  #workspace-main {
    flex: 0 1 calc(100% - var(--header-height) - var(--timeline-height));
    height: calc(100% - var(--header-height) - var(--timeline-height));
  }

  /* Gallery/Admin tabs hide the timeline, so its reserved band must be reclaimed —
     otherwise it shows through as a gray strip over the bottom of the content. */
  body.gallery-tab-active #workspace-main,
  body.admin-tab-active #workspace-main {
    flex: 0 1 calc(100% - var(--header-height));
    height: calc(100% - var(--header-height));
  }
}

@supports (height: 100dvh) {
  @media (orientation: portrait) {
    #workspace-main {
      flex-basis: calc(100dvh - var(--header-height) - var(--timeline-height) - var(--safe-bottom));
      height: calc(100dvh - var(--header-height) - var(--timeline-height) - var(--safe-bottom));
    }

    body.gallery-tab-active #workspace-main,
    body.admin-tab-active #workspace-main {
      flex-basis: calc(100dvh - var(--header-height) - var(--safe-bottom));
      height: calc(100dvh - var(--header-height) - var(--safe-bottom));
    }
  }
}

/* MAIN PREVIEW — dual panel, stacked in portrait, side-by-side in landscape */
#main-preview {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column; /* portrait: stacked */
  background: var(--surface-bg);
  overflow: hidden;
}

#gif-preview-panel,
#frame-preview-panel {
  position: relative;
  flex: 1;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  cursor: default;
  overflow: hidden;
}

#gif-preview-panel {
  --gif-left-clearance: 54px;
  --gif-right-clearance: 54px;
  padding-left: var(--gif-left-clearance);
  padding-right: var(--gif-right-clearance);
  box-sizing: border-box;
}

#frame-preview-panel {
  --frame-left-clearance: 54px;
  --frame-right-clearance: 54px;
  padding-left: var(--frame-left-clearance);
  padding-right: var(--frame-right-clearance);
  box-sizing: border-box;
}

#frame-preview-panel { border-top: 2px solid; border-color: var(--bevel-d) var(--bevel-ll) var(--bevel-ll) var(--bevel-d); }

/* Panel label badges */
.panel-label {
  position: absolute;
  top: 6px;
  left: 50%;
  transform: translateX(-50%);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text);
  background: var(--bg);
  border: 1px solid var(--bevel-d);
  border-radius: 0;
  padding: 2px 6px;
  pointer-events: none;
  z-index: 2;
}

/* While an animation is actively building (frames rendering or worker encoding),
   lock the frame-editing controls: a mid-build edit races the frame snapshot the
   running job already took and its auto-regen is dropped, so the change silently
   fails to appear. Mirrors the disabled look (opacity 0.5, no pointer events).
   Toggled by syncRegenerateButtons() via isAnimationBuildExecuting(). Frame
   selection, play/pause, and fullscreen stay interactive — they don't mutate the
   build. Drag-reorder is gated separately in drag-reorder.js (the gesture lives on
   .image-item, which must stay tappable for frame selection). */
body.build-executing #btn-camera,
body.build-executing #btn-frame-add,
body.build-executing #btn-frame-dup,
body.build-executing #btn-frame-trash,
body.build-executing #btn-clear,
body.build-executing #btn-detect-corners:not(.detect-stop-active),
body.build-executing #btn-detect-all:not(.detect-stop-active),
body.build-executing #btn-rotate-ccw,
body.build-executing #btn-fps-hover,
body.build-executing #btn-margin-hover,
body.build-executing #image-list .item-btn,
/* While frames are still decoding/importing nothing about the project is safe to
   touch: editing or restructuring frames races the import that's mutating the set.
   Same full lock surface as build-executing (plus corner-snap). Toggled by
   applyBusyUI() via isProjectBusy().loading. */
body.app-loading #btn-camera,
body.app-loading #btn-frame-add,
body.app-loading #btn-frame-dup,
body.app-loading #btn-frame-trash,
body.app-loading #btn-clear,
body.app-loading #btn-detect-corners:not(.detect-stop-active),
body.app-loading #btn-detect-all:not(.detect-stop-active),
body.app-loading #btn-corner-snap,
body.app-loading #btn-rotate-ccw,
body.app-loading #btn-fps-hover,
body.app-loading #btn-margin-hover,
body.app-loading #image-list .item-btn,
/* While the corner-detection queue drains (or an inline detect animates) lock only
   the STRUCTURAL controls — adding/removing/duplicating/clearing frames reorders
   the queue so per-frame results land on the wrong photo. Per-frame editing
   (select, adjust, manual re-detect, rotate) stays live by design. Toggled by
   applyBusyUI() via isProjectBusy().detecting (only when not also loading). */
body.app-detecting #btn-camera,
body.app-detecting #btn-frame-add,
body.app-detecting #btn-frame-dup,
body.app-detecting #btn-clear,
body.app-detecting #btn-detect-all:not(.detect-stop-active),
/* Removing a frame is only locked while detection the user STARTED owns the frame
   set (import loop, project-wide run, inline detect). A passive drain after "Later"
   adds .detect-passive and leaves these live — jobs are keyed by image id, so a
   delete can't misdirect a result, and a quiet drain can run for a minute. */
body.app-detecting:not(.detect-passive) #btn-frame-trash,
body.app-detecting:not(.detect-passive) #image-list .item-btn {
  opacity: 0.5;
  pointer-events: none;
  cursor: default;
}

#frame-filename-overlay {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  width: fit-content;
  max-width: calc(100% - 24px);
  bottom: 10px;
  z-index: 2;
  pointer-events: none;
  color: var(--text);
  font-size: 10px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-align: center;
  background: var(--bg);
  border: 1px solid var(--bevel-d);
  border-radius: 0;
  padding: 2px 6px;
  opacity: 0;
  transition: opacity 0.15s ease;
}

#frame-preview-panel.has-frame #frame-filename-overlay {
  opacity: 1;
}

#gif-size-overlay {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  width: fit-content;
  max-width: calc(100% - 24px);
  bottom: 10px;
  z-index: 2;
  pointer-events: none;
  color: var(--text);
  font-size: 10px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-align: center;
  background: var(--bg);
  border: 1px solid var(--bevel-d);
  border-radius: 0;
  padding: 2px 6px;
  opacity: 0;
  transition: opacity 0.15s ease;
}

#gif-preview-panel.has-size #gif-size-overlay {
  opacity: 1;
}

/* Preview panel overlay action buttons — semi-transparent, top-right corner, stacked vertically */
.preview-overlay-actions {
  position: absolute;
  top: 6px;
  right: 8px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  z-index: 6;
}

/* Left-side overlay buttons */
.preview-overlay-left {
  right: auto;
  left: 8px;
}

.preview-overlay-left .hover-panel {
  left: calc(100% + 6px);
  right: auto;
}

/* Hover button wrapper for popout panels */
.hover-btn-wrap {
  position: relative;
}

.hover-panel {
  position: absolute;
  right: calc(100% + 6px);
  left: auto;
  top: 0;
  background: var(--bg);
  border: 2px solid;
  border-color: var(--bevel-ll) var(--bevel-d) var(--bevel-d) var(--bevel-ll);
  box-shadow: inset 1px 1px 0 var(--bevel-l), inset -1px -1px 0 var(--bevel-dd);
  border-radius: 0;
  padding: 12px 14px;
  min-width: 210px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  z-index: 10;
}

.hover-panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
}

.hover-panel-label {
  font-size: 0.7rem;
  color: var(--text-muted);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  white-space: nowrap;
}

.hover-panel-value {
  font-size: 0.92rem;
  font-weight: 700;
  color: var(--text);
  min-width: 1.75rem;
  text-align: right;
}

.hover-range {
  width: min(220px, 52vw);
  height: 28px;
  -webkit-appearance: none;
  appearance: none;
  background: transparent;
  border-radius: 0;
  outline: none;
  align-self: flex-start;
  cursor: pointer;
}
.hover-range::-webkit-slider-runnable-track {
  height: 4px;
  background: var(--bevel-d);
  border-top: 1px solid var(--bevel-dd);
  border-bottom: 1px solid var(--bevel-ll);
  border-radius: 0;
}
.hover-range::-moz-range-track {
  height: 4px;
  background: var(--bevel-d);
  border-top: 1px solid var(--bevel-dd);
  border-bottom: 1px solid var(--bevel-ll);
  border-radius: 0;
}

.hover-range::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 18px; height: 18px;
  border-radius: 50%;
  background: var(--accent);
  cursor: pointer;
  border: 2px solid var(--bg);
  box-shadow: 0 0 0 2px var(--accent);
  margin-top: -7px;
}

.hover-option {
  padding: 3px 8px;
  border: 2px solid;
  border-color: var(--bevel-ll) var(--bevel-d) var(--bevel-d) var(--bevel-ll);
  box-shadow: inset 1px 1px 0 var(--bevel-l), inset -1px -1px 0 var(--bevel-dd);
  border-radius: 0;
  background: var(--btn-bg);
  color: var(--text);
  font-size: 11px;
  cursor: pointer;
  text-align: left;
  white-space: nowrap;
}

.hover-option:hover { background: var(--btn-bg); }
.hover-option:active,
.hover-option.active {
  border-color: var(--bevel-d) var(--bevel-ll) var(--bevel-ll) var(--bevel-d);
  box-shadow: inset 1px 1px 0 var(--bevel-dd), inset -1px -1px 0 var(--bevel-l);
  font-weight: 600;
}

.preview-overlay-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: 0;
  border: 2px solid;
  border-color: var(--bevel-ll) var(--bevel-d) var(--bevel-d) var(--bevel-ll);
  box-shadow: inset 1px 1px 0 var(--bevel-l), inset -1px -1px 0 var(--bevel-dd);
  background: var(--btn-bg);
  color: var(--text);
  cursor: pointer;
}

.preview-overlay-btn:hover { background: var(--btn-bg); }

.preview-overlay-btn:active {
  border-color: var(--bevel-d) var(--bevel-ll) var(--bevel-ll) var(--bevel-d);
  box-shadow: inset 1px 1px 0 var(--bevel-dd), inset -1px -1px 0 var(--bevel-l);
}

.preview-overlay-btn.active {
  border-color: var(--bevel-d) var(--bevel-ll) var(--bevel-ll) var(--bevel-d);
  box-shadow: inset 1px 1px 0 var(--bevel-dd), inset -1px -1px 0 var(--bevel-l);
  color: #000080;
}

.preview-overlay-btn:disabled {
  opacity: 0.5;
  cursor: default;
  pointer-events: none;
}

.preview-overlay-danger:hover,
.preview-overlay-btn.detect-stop-active { color: var(--danger); }

#gif-preview-panel:hover,
#frame-preview-panel:hover { background: var(--surface-bg-hover); }

/* Admin-supplied replacement for the built-in flipbook drawing in the empty
   frame editor (src/app-imagery.js). Matches the SVG's footprint so the panel
   doesn't reflow when one is swapped for the other, but is NOT dimmed the way
   the built-in outline is — uploaded art is meant to be seen as authored. */
.preview-empty-illustration {
  width: 216px;
  max-width: 100%;
  height: 141px;
  max-height: 40vh;
  object-fit: contain;
}

#preview-canvas,
#frame-canvas,
#inline-adjust-wrap,
#inline-adjust-canvas,
#inline-corner-svg {
  cursor: default;
}

#frame-preview-panel #inline-adjust-wrap {
  inset: 0 var(--frame-right-clearance) 0 var(--frame-left-clearance) !important;
  background: transparent !important;
}


#frame-canvas {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  image-rendering: pixelated;
  background: transparent;
}

#gif-status,
#frame-preview-status { display: flex; flex-direction: column; align-items: center; gap: 6px; color: var(--text-muted); font-size: 0.8rem; }

@media (min-width: 900px) {
  #gif-status,
  #frame-preview-status { font-size: 13px; gap: 10px; }
  #frame-processing-status { font-size: 13px; }
  #frame-processing-text { font-size: 13px; }
  #gif-status-text,
  #frame-preview-status-text { font-size: 13px; }
  #empty-state p { font-size: 13px; }
  #gif-size-overlay,
  #frame-filename-overlay { font-size: 13px; padding: 3px 8px; }
}

.preview-empty-icon { flex-shrink: 0; }

#gif-size-text { display: none !important; }

.sample-gif-preview {
  max-width: 92%;
  height: auto;
  object-fit: contain;
  image-rendering: auto;
  display: block;
}

/* Fullscreen mode keeps the header visible so project, account, and exit controls remain available. */
#btn-fullscreen-overlay,
#btn-fullscreen-overlay-gif { display: none; }

/* Frame processing indicator — hidden by default, shown via .is-processing class */
#frame-processing-status {
  display: none;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  font-size: 0.82rem;
  color: var(--text-muted);
}
#frame-preview-status.is-processing .preview-empty-icon,
#frame-preview-status.is-processing #frame-preview-status-text { display: none; }
#frame-preview-status.is-processing #frame-processing-status { display: flex; }

/* FRAME CONTROLS — always visible, frame-level actions */
#frame-controls {
  height: var(--frame-controls-height);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 0 10px;
  background: var(--bg2);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.frame-ctrl-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--bg3);
  color: var(--text);
  cursor: pointer;
  transition: all 0.15s;
}

.frame-ctrl-btn:hover { border-color: var(--accent); color: var(--accent); background: rgba(105,199,225,0.12); }
.frame-trash-btn:hover { border-color: var(--danger); color: var(--danger); background: rgba(217,79,79,0.1); }
.frame-ctrl-spacer { flex: 1; }

/* GIF PANEL — fixed to bottom of viewport */
#gif-panel {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 100;
  height: calc(var(--gif-panel-height) + var(--safe-bottom));
  background: var(--bg2);
  border-top: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  padding-bottom: var(--safe-bottom);
}

.spinner {
  width: 20px;
  height: 20px;
  border: 2px solid var(--border);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
}

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

#download-bar { display: flex; gap: 6px; padding: 6px 8px; border-top: 1px solid var(--border); flex-shrink: 0; }

.btn-download {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  padding: 5px 4px;
  border: 2px solid;
  border-color: var(--bevel-ll) var(--bevel-d) var(--bevel-d) var(--bevel-ll);
  box-shadow: inset 1px 1px 0 var(--bevel-l), inset -1px -1px 0 var(--bevel-dd);
  border-radius: 0;
  background: var(--btn-bg);
  color: var(--text);
  font-size: 11px;
  font-weight: 400;
  cursor: pointer;
}

.btn-download:not(:disabled):hover { background: var(--btn-bg); }
.btn-download:not(:disabled):active {
  border-color: var(--bevel-d) var(--bevel-ll) var(--bevel-ll) var(--bevel-d);
  box-shadow: inset 1px 1px 0 var(--bevel-dd), inset -1px -1px 0 var(--bevel-l);
}
.btn-download:disabled { opacity: 0.4; cursor: not-allowed; }

.dl-adjusted-group { display: flex; flex: 1; gap: 3px; }
.dl-adjusted-group .btn-download { flex: 1; }
.dl-format-select {
  padding: 0 4px;
  border: 2px solid;
  border-color: var(--bevel-d) var(--bevel-ll) var(--bevel-ll) var(--bevel-d);
  box-shadow: inset 1px 1px 0 var(--bevel-dd), inset -1px -1px 0 var(--bevel-l);
  border-radius: 0;
  background: #ffffff;
  color: var(--text);
  font-size: 11px;
  font-weight: 400;
  cursor: pointer;
  appearance: none;
  text-align: center;
  width: 42px;
}

/* OVERLAYS */
.overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  z-index: 1000;
  display: flex;
  align-items: flex-end;
  justify-content: center;
}

/* ADJUSTMENT PANEL */
#adjust-panel {
  width: 100%;
  max-width: 600px;
  max-height: 95vh;
  background: var(--bg);
  border: 2px solid;
  border-color: var(--bevel-ll) var(--bevel-d) var(--bevel-d) var(--bevel-ll);
  box-shadow: inset 1px 1px 0 var(--bevel-l), inset -1px -1px 0 var(--bevel-dd);
  border-radius: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 4px 6px;
  background: linear-gradient(to right, #000080, #1084d0);
  border-bottom: none;
  flex-shrink: 0;
}

.panel-title {
  font-size: 11px;
  font-weight: 700;
  color: #ffffff;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: calc(100% - 40px);
}

.btn-close {
  background: var(--btn-bg);
  border: 2px solid;
  border-color: var(--bevel-ll) var(--bevel-d) var(--bevel-d) var(--bevel-ll);
  box-shadow: inset 1px 1px 0 var(--bevel-l), inset -1px -1px 0 var(--bevel-dd);
  color: var(--text);
  font-size: 11px;
  font-weight: 700;
  cursor: pointer;
  width: 22px;
  height: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 0;
  flex-shrink: 0;
  padding: 0;
}

.btn-close:active {
  border-color: var(--bevel-d) var(--bevel-ll) var(--bevel-ll) var(--bevel-d);
  box-shadow: inset 1px 1px 0 var(--bevel-dd), inset -1px -1px 0 var(--bevel-l);
}

#adjust-canvas-wrap {
  position: relative;
  flex-shrink: 0;
  background: #000;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 280px;
  overflow: hidden;
  border: 2px solid;
  border-color: var(--bevel-d) var(--bevel-ll) var(--bevel-ll) var(--bevel-d);
  box-shadow: inset 1px 1px 0 var(--bevel-dd), inset -1px -1px 0 var(--bevel-l);
  margin: 8px;
}

#adjust-canvas { display: block; max-width: 100%; max-height: 100%; }

#corner-svg {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.corner-handle { cursor: grab; }
.corner-handle:active { cursor: grabbing; }
/* Touch devices (mobile PWA + native iOS/Android) get ~25% larger perspective-corner
   handles for easier fingertip dragging. Desktop (fine pointer) keeps the r="16" from
   the SVG attribute. The CSS `r` property overrides the presentation attribute; JS only
   sets cx/cy, so it never fights this. */
@media (pointer: coarse) {
  .corner-handle { r: 20px; }
}
#corner-poly { cursor: move; }
body.hide-cursor, body.hide-cursor * { cursor: none !important; }
#adjust-zoom-layer { position: absolute; inset: 0; transform-origin: 50% 50%; }

/* Handle-SVGs are position:fixed so corner circles can be dragged beyond the preview edge */
#handle-svg {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  overflow: visible;
}

#inline-handle-svg {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  overflow: visible;
  z-index: 5;
}

/* #corner-loupe and #inline-corner-loupe are position:fixed at body level (see index.html) */
#corner-loupe-canvas { display: block; width: 120px; height: 120px; }

.bg-color-swatch {
  width: 28px; height: 28px;
  border-radius: 50%;
  border: 2px solid var(--border);
  cursor: pointer;
  flex-shrink: 0;
  padding: 0;
  background: #000;
  transition: border-color 0.15s;
}
.bg-color-swatch:hover { border-color: var(--accent); }
#bg-color-input { position: absolute; opacity: 0; pointer-events: none; width: 0; height: 0; }

#adjust-controls {
  flex: 1;
  overflow-y: auto;
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  -webkit-overflow-scrolling: touch;
}

.btn-secondary {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 5px 16px;
  border: 2px solid;
  border-color: var(--bevel-ll) var(--bevel-d) var(--bevel-d) var(--bevel-ll);
  box-shadow: inset 1px 1px 0 var(--bevel-l), inset -1px -1px 0 var(--bevel-dd);
  border-radius: 0;
  background: var(--btn-bg);
  color: var(--text);
  font-size: 11px;
  cursor: pointer;
}

.btn-secondary:hover { background: var(--btn-bg); }
.btn-secondary:active {
  border-color: var(--bevel-d) var(--bevel-ll) var(--bevel-ll) var(--bevel-d);
  box-shadow: inset 1px 1px 0 var(--bevel-dd), inset -1px -1px 0 var(--bevel-l);
}
.btn-secondary:disabled { opacity: 0.4; cursor: not-allowed; pointer-events: none; }
.btn-regen-pending {
  background: #000080 !important;
  border-color: var(--bevel-ll) var(--bevel-d) var(--bevel-d) var(--bevel-ll) !important;
  color: #ffffff !important;
  font-weight: 700;
  animation: regen-pulse 1.6s ease-in-out infinite;
}
.btn-regen-pending:hover { background: #0000aa !important; }
@keyframes regen-pulse {
  0%, 100% {
    box-shadow: inset 1px 1px 0 var(--bevel-l), inset -1px -1px 0 var(--bevel-dd),
      0 0 0 0 rgba(0, 0, 128, 0);
  }
  50% {
    box-shadow: inset 1px 1px 0 var(--bevel-l), inset -1px -1px 0 var(--bevel-dd),
      0 0 8px 3px rgba(0, 0, 128, 0.6);
  }
}
@media (prefers-reduced-motion: reduce) {
  .btn-regen-pending { animation: none; }
}
.btn-full { width: 100%; }

.control-row { display: flex; align-items: center; gap: 10px; }
.control-row label { font-size: 0.78rem; color: var(--text-muted); width: 70px; flex-shrink: 0; }

.control-row input[type="range"] {
  flex: 1;
  height: 3px;
  -webkit-appearance: none;
  appearance: none;
  background: var(--bg3);
  border-radius: 2px;
  outline: none;
}

.control-row input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--accent);
  cursor: pointer;
  border: 2px solid var(--bg);
  box-shadow: 0 0 0 2px var(--accent);
}

.control-row input[type="range"]::-moz-range-thumb {
  width: 20px; height: 20px; border-radius: 50%;
  background: var(--accent); cursor: pointer; border: 2px solid var(--bg);
}

.val-display {
  font-size: 11px;
  color: var(--text);
  width: 36px;
  text-align: right;
  flex-shrink: 0;
  font-variant-numeric: tabular-nums;
}

.slider-reset {
  flex-shrink: 0;
  background: var(--btn-bg);
  border: 2px solid;
  border-color: var(--bevel-ll) var(--bevel-d) var(--bevel-d) var(--bevel-ll);
  box-shadow: inset 1px 1px 0 var(--bevel-l), inset -1px -1px 0 var(--bevel-dd);
  border-radius: 0;
  color: var(--text);
  cursor: pointer;
  padding: 1px 5px;
  font-size: 11px;
  line-height: 1.4;
}
.slider-reset:active {
  border-color: var(--bevel-d) var(--bevel-ll) var(--bevel-ll) var(--bevel-d);
  box-shadow: inset 1px 1px 0 var(--bevel-dd), inset -1px -1px 0 var(--bevel-l);
}

.corner-label-text {
  font-size: 9px;
  font-weight: 700;
  fill: #000;
  pointer-events: none;
  user-select: none;
}

.rotation-btns { flex: 1; display: flex; gap: 4px; }

.rot-btn {
  flex: 1;
  padding: 4px 4px;
  border: 2px solid;
  border-color: var(--bevel-ll) var(--bevel-d) var(--bevel-d) var(--bevel-ll);
  box-shadow: inset 1px 1px 0 var(--bevel-l), inset -1px -1px 0 var(--bevel-dd);
  border-radius: 0;
  background: var(--btn-bg);
  color: var(--text);
  font-size: 11px;
  cursor: pointer;
  white-space: nowrap;
}

.rot-btn:hover { background: var(--btn-bg); }
.rot-btn:active {
  border-color: var(--bevel-d) var(--bevel-ll) var(--bevel-ll) var(--bevel-d);
  box-shadow: inset 1px 1px 0 var(--bevel-dd), inset -1px -1px 0 var(--bevel-l);
}

.panel-footer {
  display: flex;
  gap: 6px;
  padding: 8px 10px;
  border-top: 2px solid;
  border-color: var(--bevel-d) var(--bevel-ll) var(--bevel-ll) var(--bevel-d);
  flex-shrink: 0;
  padding-bottom: calc(8px + var(--safe-bottom));
  background: var(--bg);
}

.btn-primary {
  flex: 1.5;
  padding: 5px 16px;
  border: 2px solid;
  border-color: var(--bevel-ll) var(--bevel-d) var(--bevel-d) var(--bevel-ll);
  box-shadow: inset 1px 1px 0 var(--bevel-l), inset -1px -1px 0 var(--bevel-dd);
  border-radius: 0;
  background: var(--btn-bg);
  color: var(--text);
  font-size: 11px;
  font-weight: 700;
  cursor: pointer;
}

.btn-primary:hover { background: var(--btn-bg); }
.btn-primary:active {
  border-color: var(--bevel-d) var(--bevel-ll) var(--bevel-ll) var(--bevel-d);
  box-shadow: inset 1px 1px 0 var(--bevel-dd), inset -1px -1px 0 var(--bevel-l);
}
.panel-footer .btn-secondary { flex: 1; padding: 5px; font-size: 11px; }

.btn-nav-arrow {
  flex: 0 0 28px;
  padding: 0;
  border: 2px solid;
  border-color: var(--bevel-ll) var(--bevel-d) var(--bevel-d) var(--bevel-ll);
  box-shadow: inset 1px 1px 0 var(--bevel-l), inset -1px -1px 0 var(--bevel-dd);
  border-radius: 0;
  background: var(--btn-bg);
  color: var(--text);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.btn-nav-arrow:hover:not(:disabled) { background: var(--btn-bg); }
.btn-nav-arrow:active:not(:disabled) {
  border-color: var(--bevel-d) var(--bevel-ll) var(--bevel-ll) var(--bevel-d);
  box-shadow: inset 1px 1px 0 var(--bevel-dd), inset -1px -1px 0 var(--bevel-l);
}
.btn-nav-arrow:disabled { opacity: 0.4; cursor: default; }

/* CAMERA PANEL */
#camera-panel {
  width: 100%;
  max-width: 600px;
  height: 100%;
  max-height: 100vh;
  background: var(--bg);
  border: 2px solid;
  border-color: var(--bevel-ll) var(--bevel-d) var(--bevel-d) var(--bevel-ll);
  box-shadow: inset 1px 1px 0 var(--bevel-l), inset -1px -1px 0 var(--bevel-dd);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  overflow: hidden;
}

.overlay.camera-active { align-items: stretch; }

#camera-view-wrap {
  flex: 0 0 auto;
  position: relative;
  overflow: hidden;
  background: #000;
  width: min(100%, calc((100vh - 148px) * 3 / 4));
  aspect-ratio: 3 / 4;
  align-self: center;
  /* Container for the guide frame so it can size off the view's real width AND
     height (cqw/cqh) and hold its 1:1.7 ratio in any viewport. */
  container-type: size;
}

/* Clips the video when it is digitally zoomed (scaled up past its own box). */
#camera-video-clip { position: absolute; inset: 0; overflow: hidden; }
#camera-video { width: 100%; height: 100%; object-fit: cover; transform-origin: 50% 50%; }
/* Pinch to zoom: the page must not take the two-finger gesture for itself. */
#camera-view-wrap { touch-action: none; }

/* Zoom control: a pill across the top of the picture (clear of the capture controls,
   the guide frame and the feedback line). 44 px targets, usable with any input. */
#camera-zoom {
  display: none;
  position: absolute;
  top: 4px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 6;
  width: min(80%, 300px);
  align-items: center;
  gap: 2px;
  padding: 2px 8px 2px 4px;
  color: #f4f8fa;
  background: rgba(20, 32, 40, 0.62);
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 28px;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  pointer-events: auto;
}
#camera-zoom.is-available { display: flex; }
#camera-zoom button {
  flex: none;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  padding: 0;
  color: inherit;
  background: none;
  border: 0;
  border-radius: 50%;
  cursor: pointer;
}
#camera-zoom button:disabled { opacity: 0.35; cursor: default; }
#camera-zoom button:focus-visible,
#camera-zoom input[type="range"]:focus-visible { outline: 2px solid #fff; outline-offset: 1px; }
#camera-zoom input[type="range"] {
  flex: 1;
  min-width: 0;
  height: 44px;
  margin: 0;
  background: transparent;
  accent-color: #ede51c;
  cursor: pointer;
}
#camera-zoom output {
  flex: none;
  min-width: 44px;
  text-align: center;
  font-size: 13px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
/* Full-screen native camera: clear the status bar / notch. */
body.native-camera-fullscreen #camera-zoom { top: calc(var(--safe-top, 0px) + 14px); }

/* When native camera-preview plugin renders behind the WebView, the wrap must
   be transparent so the native layer shows through. */
#camera-view-wrap.native-camera-active { background: transparent; }

/* ===== NATIVE CAMERA — FULLSCREEN FEED (Pro Android/iOS) =====
   The @capacitor-community/camera-preview plugin makes the WebView itself
   transparent and renders the live feed FULLSCREEN behind it. For the feed to
   be visible, every web layer painted in front of it must be transparent too —
   otherwise their opaque pixels (the gray rectangle users saw) occlude it.
   So while native camera is active we neutralise the whole paint stack
   (html/body → #app → overlay backdrop → panel) and float the chrome on top. */
body.native-camera-fullscreen,
html:has(> body.native-camera-fullscreen) { background: transparent !important; }

/* Everything else painted in the WebView must stop occluding the feed. Make all
   body-level siblings (except the camera overlay and the shutter-flash, which is
   transparent until a capture) fully transparent. opacity:0 — rather than display
   :none or visibility:hidden — because it (a) can't be re-asserted by descendants
   so stray fixed layers like #inline-handle-svg's circles can't leak through, and
   (b) keeps the editor laid out, so an orientation change while the camera is open
   still repositions the editor's corner handles correctly instead of scattering
   them off zero-size layout. */
body.native-camera-fullscreen > *:not(#camera-overlay):not(#shutter-flash) {
  opacity: 0 !important;
  pointer-events: none !important;
}

/* Overlay + panel become a transparent, edge-to-edge stage for the feed. */
body.native-camera-fullscreen #camera-overlay.overlay {
  background: transparent;
  align-items: stretch;
  justify-content: stretch;
  padding: 0;
}
body.native-camera-fullscreen #camera-panel {
  display: block;
  width: 100%; max-width: none;
  height: 100%; max-height: none;
  margin: 0;
  padding: 0;
  border: none;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
}
body.native-camera-fullscreen #camera-view-wrap {
  position: absolute;
  inset: 0;
  width: 100%; max-width: none;
  height: 100%; max-height: none;
  aspect-ratio: auto;
  margin: 0;
  background: transparent;
}

/* Close button — true upper-right corner, clear of the status bar. */
body.native-camera-fullscreen #btn-camera-close {
  position: fixed;
  top: calc(var(--safe-top) + 12px);
  right: calc(var(--safe-right, 0px) + 12px);
  left: auto;
  width: 40px;
  height: 40px;
  z-index: 30;
  color: #f4f8fa;
  background: rgba(28, 45, 56, 0.78);
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 10px;
  pointer-events: auto;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}

/* Capture controls float as a pill above the home indicator. */
body.native-camera-fullscreen #camera-controls {
  position: fixed;
  left: 50%;
  bottom: calc(var(--safe-bottom) + 18px);
  transform: translateX(-50%);
  width: min(calc(100vw - 32px), 264px);
  margin: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 18px;
  background: rgba(20, 32, 40, 0.5);
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 30px;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
body.native-camera-fullscreen .btn-torch,
body.native-camera-fullscreen .camera-control-spacer {
  position: static !important;
  transform: none !important;
}
body.native-camera-fullscreen .btn-torch      { order: 1; margin: 0 auto 0 0; }
body.native-camera-fullscreen .btn-capture     { order: 2; }
body.native-camera-fullscreen .camera-control-spacer { order: 3; margin: 0 0 0 auto; }

/* Feedback pill sits clear above the floating controls pill (which is ~96px
   tall starting 18px off the bottom) so its dark background never overlaps. */
body.native-camera-fullscreen #camera-feedback {
  bottom: calc(var(--safe-bottom) + 132px);
}

/* Portrait fullscreen: trim the guide a touch (vs the 82cqw web box) so its
   bottom edge stays clear of the feedback pill. Landscape overrides this below. */
body.native-camera-fullscreen #camera-guide-frame {
  width: min(78cqw, calc(84cqh / 1.7));
}

/* ===== NATIVE CAMERA — LANDSCAPE =====
   Mirror the PWA's rotated layout: X in the top-left, capture controls down the
   right edge, messages along the bottom, and the guide frame centred + shortened
   (1.7:1) so the bottom messages clear it. */
@media (orientation: landscape) {
  body.native-camera-fullscreen #btn-camera-close {
    top: calc(var(--safe-top) + 12px);
    left: calc(var(--safe-left, 0px) + 12px);
    right: auto;
  }
  body.native-camera-fullscreen #camera-controls {
    flex-direction: column;
    justify-content: center;
    left: auto;
    right: calc(var(--safe-right, 0px) + 16px);
    top: 50%;
    bottom: auto;
    transform: translateY(-50%);
    width: auto;
    padding: 14px 12px;
    gap: 14px;
  }
  body.native-camera-fullscreen .btn-torch,
  body.native-camera-fullscreen .btn-capture,
  body.native-camera-fullscreen .camera-control-spacer { margin: 0; }
  body.native-camera-fullscreen .camera-control-spacer { order: 1; }
  body.native-camera-fullscreen .btn-capture      { order: 2; }
  body.native-camera-fullscreen .btn-torch         { order: 3; }
  body.native-camera-fullscreen #camera-feedback {
    left: 50%;
    right: auto;
    transform: translateX(-50%);
    bottom: calc(var(--safe-bottom) + 16px);
  }
  body.native-camera-fullscreen #camera-guide-frame {
    aspect-ratio: 1.7 / 1;
    /* Shorter than the PWA box (62cqh) so the centred frame leaves a clear band
       at the bottom for the messages, and never reaches the right-edge controls. */
    width: min(80cqw, calc(62cqh * 1.7));
    height: auto;
    max-width: none;
    max-height: none;
  }
}

#camera-guide-frame {
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  aspect-ratio: 1 / 1.7;
  /* Largest 1:1.7 (w:h) box that fits within 82% of the view's width and 84%
     of its height. Sizing only the width (height follows from aspect-ratio)
     means the ratio is never broken by a clamp, so the holes stay round and
     the frame never stretches to the screen's length. */
  width: min(82cqw, calc(84cqh / 1.7));
  height: auto;
  max-width: none;
  max-height: none;
  border: 2px solid rgba(255, 255, 255, 0.4);
  border-radius: 8px;
  pointer-events: none;
}

#camera-guide-frame::before,
#camera-guide-frame::after {
  content: '';
  position: absolute;
  width: clamp(12px, 6.2%, 18px);
  aspect-ratio: 1 / 1;
  height: auto;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, 0.4);
}
#camera-guide-frame::before { left: 28%; top: 7.5%; transform: translate(-50%, -50%); }
#camera-guide-frame::after  { left: 72%; top: 7.5%; transform: translate(-50%, -50%); }

@media (orientation: portrait) {
  #camera-overlay.overlay {
    align-items: center;
    justify-content: center;
  }
  #camera-panel {
    width: min(calc(100vw - 20px), 430px);
    max-width: min(calc(100vw - 20px), 430px);
    height: min(calc(100dvh - 16px), 860px);
    max-height: calc(100dvh - 16px);
    margin: 0 auto;
    border-radius: 24px;
    border-style: solid;
    border-color: var(--border);
    border-width: 0 1px;
    display: grid;
    grid-template-columns: 1fr;
    grid-template-rows: 36px minmax(0, 1fr) auto;
    gap: 12px;
    padding: calc(12px + var(--safe-top)) 12px calc(12px + var(--safe-bottom));
    background: var(--bg2);
  }
  #camera-panel .panel-header {
    display: contents;
  }
  #camera-panel .panel-title {
    display: none;
  }
  #btn-camera-close {
    position: static;
    grid-row: 1;
    justify-self: end;
    align-self: start;
    width: 36px;
    height: 36px;
    color: #f4f8fa;
    background: rgba(28, 45, 56, 0.78);
    border: 1px solid rgba(255,255,255,0.14);
    border-radius: 10px;
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
  }
  #camera-view-wrap {
    grid-row: 2;
    width: min(100%, calc((100dvh - 184px) * 3 / 4));
    max-width: 100%;
    max-height: 100%;
    aspect-ratio: 3 / 4;
    margin: 0;
    justify-self: center;
    align-self: center;
  }
  /* Sizing is handled by the container-unit rule above (holds 1:1.7 in every
     viewport); only the hole positions are tweaked for portrait here. */
  #camera-guide-frame::before { left: 28%; top: 6.8%; transform: translate(-50%, -50%); }
  #camera-guide-frame::after  { left: 72%; top: 6.8%; transform: translate(-50%, -50%); }
  #camera-controls {
    grid-row: 3;
    position: static;
    width: min(100%, 264px);
    margin: 0 auto;
    padding: 12px 18px calc(12px + var(--safe-bottom));
    background: rgba(232, 240, 245, 0.9);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    border-top: none;
    border: 1px solid rgba(0,0,0,0.1);
    border-radius: 30px;
  }
  .btn-torch,
  .camera-control-spacer {
    position: static !important;
    transform: none !important;
  }
  .btn-torch { order: 1; margin-right: auto; margin-left: 0; }
  .btn-capture { order: 2; }
  .camera-control-spacer { order: 3; margin-left: auto; margin-right: 0; }
}

@media (orientation: landscape) and (max-height: 500px) {
  #camera-overlay.overlay {
    align-items: center;
    justify-content: center;
  }
  #camera-panel {
    width: min(calc(100vw - 20px), calc((100dvh - 12px) * 4 / 3 + 168px));
    max-width: min(calc(100vw - 20px), calc((100dvh - 12px) * 4 / 3 + 168px));
    height: min(calc(100dvh - 12px), 520px);
    max-height: calc(100dvh - 12px);
    margin: 0 auto;
    border-radius: 16px;
    border-style: solid;
    border-color: var(--border);
    border-width: 0 1px;
    display: grid;
    grid-template-columns: 56px minmax(0, 1fr) 96px;
    grid-template-rows: 1fr;
    align-items: center;
    gap: 12px;
    padding: 4px 12px;
    background: var(--bg2);
  }

  #camera-panel .panel-header {
    display: contents;
  }

  #camera-panel .panel-title {
    display: none;
  }

  #btn-camera-close {
    position: static;
    grid-column: 1;
    align-self: start;
    justify-self: start;
    width: 36px;
    height: 36px;
    color: #f4f8fa;
    background: rgba(28, 45, 56, 0.78);
    border: 1px solid rgba(255,255,255,0.14);
    border-radius: 10px;
    pointer-events: auto;
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
  }
}

#camera-feedback {
  position: absolute;
  bottom: 20px;
  left: 50%;
  transform: translateX(-50%);
  padding: 8px 16px;
  background: rgba(0, 0, 0, 0.7);
  border-radius: 20px;
  font-size: 0.85rem;
  font-weight: 500;
  color: #fff;
  text-align: center;
  white-space: nowrap;
  pointer-events: none;
  transition: opacity 0.3s, background 0.3s;
}

#camera-feedback.good { background: rgba(0, 200, 100, 0.8); }
#camera-feedback.warn { background: rgba(255, 180, 0, 0.8); }
#camera-feedback.bad { background: rgba(200, 50, 50, 0.8); }

#camera-diag {
  position: absolute;
  top: 12px;
  left: 12px;
  right: 12px;
  padding: 10px 14px;
  background: rgba(0, 0, 0, 0.82);
  border-radius: 10px;
  font-family: monospace;
  font-size: 0.75rem;
  line-height: 1.6;
  color: #e0f4ff;
  white-space: pre;
  cursor: pointer;
  z-index: 20;
}

#camera-diag::after {
  content: '  ✕ tap to dismiss';
  display: block;
  margin-top: 4px;
  color: rgba(255,255,255,0.4);
  font-size: 0.7rem;
}

@keyframes focus-lock {
  0%   { opacity: 1; transform: translate(-50%, -50%) scale(1.4); border-color: #fff; }
  40%  { opacity: 1; transform: translate(-50%, -50%) scale(1.0); border-color: #69c7e1; }
  100% { opacity: 0; transform: translate(-50%, -50%) scale(1.0); border-color: #69c7e1; }
}
@keyframes focus-hunt {
  0%, 100% { opacity: 1;   transform: translate(-50%, -50%) scale(1.1); border-color: #fff; }
  50%       { opacity: 0.5; transform: translate(-50%, -50%) scale(0.9); border-color: #aaa; }
}

#focus-indicator {
  position: absolute;
  width: 62px;
  height: 62px;
  border: 2px solid #69c7e1;
  border-radius: 6px;
  pointer-events: none;
  display: none;
  animation: focus-lock 1.1s ease-out forwards;
  z-index: 15;
}
#focus-indicator.hunting {
  animation: focus-hunt 0.5s ease-in-out infinite;
}

/* Corner tick marks */
#focus-indicator::before,
#focus-indicator::after {
  content: '';
  position: absolute;
  width: 10px;
  height: 10px;
  border-color: inherit;
  border-style: solid;
}
#focus-indicator::before { top: -2px; left: -2px; border-width: 2px 0 0 2px; }
#focus-indicator::after  { bottom: -2px; right: -2px; border-width: 0 2px 2px 0; }

#camera-controls {
  position: relative;
  padding: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg2);
  border-top: 1px solid var(--border);
  padding-bottom: calc(20px + var(--safe-bottom));
}

.btn-capture {
  width: 72px;
  height: 72px;
  border-radius: 50%;
  border: 4px solid var(--accent2);
  background: rgba(105, 199, 225, 0.15);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.15s;
}

.btn-capture:hover, .btn-capture:active { background: rgba(105, 199, 225, 0.3); transform: scale(0.95); }

.capture-inner {
  display: block;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  background: var(--accent);
  transition: transform 0.15s;
}

.btn-capture:active .capture-inner { transform: scale(0.88); }

.btn-torch {
  position: absolute;
  left: 24px;
  top: 50%;
  transform: translateY(-50%);
  width: 52px;
  height: 52px;
  border-radius: 50%;
  border: 2px solid var(--border);
  background: var(--bg3);
  color: var(--text-muted);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.15s;
}
.btn-torch:hover { background: var(--bg2); color: var(--text); }
.btn-torch.active {
  background: rgba(255, 224, 0, 0.12);
  border-color: #c8a800;
  color: #c8a800;
}

/* UTILITY */
body { overscroll-behavior-y: none; }
.image-item.dragging * { user-select: none; }

#toast {
  position: fixed;
  font-family: 'MS Sans Serif', 'Microsoft Sans Serif', Tahoma, Arial, sans-serif;
  bottom: 16px;
  left: 50%;
  transform: translateX(-50%);
  padding: 5px 12px;
  background: var(--bg);
  border: 2px solid;
  border-color: var(--bevel-ll) var(--bevel-d) var(--bevel-d) var(--bevel-ll);
  box-shadow: inset 1px 1px 0 var(--bevel-l), inset -1px -1px 0 var(--bevel-dd);
  border-radius: 0;
  font-size: 11px;
  color: var(--text);
  z-index: 2000;
  opacity: 0;
  transition: opacity 0.25s;
  pointer-events: none;
  white-space: nowrap;
}

#toast.show { opacity: 1; }

/* Panel toast — absolutely centered in a positioned container (adjust canvas, gif preview, etc.) */
.panel-toast {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  font-family: 'MS Sans Serif', 'Microsoft Sans Serif', Tahoma, Arial, sans-serif;
  font-size: 11px;
  color: var(--text);
  background: var(--bg);
  border: 2px solid;
  border-color: var(--bevel-ll) var(--bevel-d) var(--bevel-d) var(--bevel-ll);
  box-shadow: inset 1px 1px 0 var(--bevel-l), inset -1px -1px 0 var(--bevel-dd);
  padding: 5px 12px;
  white-space: nowrap;
  pointer-events: none;
  z-index: 500;
  opacity: 0;
  transition: opacity 0.2s;
}
.panel-toast.show { opacity: 1; }

/* Timeline scrollbar — collapses to 0px when not hovered, fades in on hover. */
#image-list-container { scrollbar-width: none; }
#image-list-container:hover { scrollbar-width: thin; scrollbar-color: rgba(0,0,0,0.25) transparent; }
#image-list-container::-webkit-scrollbar { height: 0; transition: height 0.3s; }
#image-list-container:hover::-webkit-scrollbar { height: 6px; }
#image-list-container::-webkit-scrollbar-track { background: transparent; }
#image-list-container::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.25); border-radius: 3px; }
#adjust-controls::-webkit-scrollbar { width: 3px; }
#adjust-controls::-webkit-scrollbar-track { background: transparent; }
#adjust-controls::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.15); border-radius: 2px; }

@media (min-width: 600px) {
  #adjust-canvas-wrap { height: 340px; }
}

@media (orientation: landscape) and (max-height: 500px) {
  #camera-view-wrap {
    grid-column: 2;
    flex: 0 0 auto;
    width: auto;
    height: 100%;
    max-width: 100%;
    aspect-ratio: 4 / 3;
    margin: 0;
    align-self: center;
    justify-self: center;
  }
  #camera-guide-frame {
    aspect-ratio: 1.7 / 1;
    width: min(84cqw, calc(82cqh * 1.7));
    height: auto;
    max-width: none;
    max-height: none;
  }
  #camera-guide-frame::before { left: 6.8%; top: 28%; transform: translate(-50%, -50%); }
  #camera-guide-frame::after  { left: 6.8%; top: 72%; transform: translate(-50%, -50%); }
  #camera-controls {
    grid-column: 3;
    position: static;
    transform: none;
    z-index: 25;
    flex-direction: column;
    gap: 14px;
    padding: 12px 8px;
    background: rgba(232, 240, 245, 0.9);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    border-top: none;
    border: 1px solid rgba(0,0,0,0.1);
    border-radius: 28px;
    padding-bottom: 12px;
    align-self: center;
    justify-self: stretch;
  }
  #camera-panel {
    justify-content: flex-start;
  }
  .btn-torch,
  .camera-control-spacer {
    position: static !important;
    transform: none !important;
  }
  .camera-control-spacer { order: 1; }
  .btn-capture { order: 2; }
  .btn-torch { order: 3; }
  .btn-capture {
    width: 68px;
    height: 68px;
  }
  .capture-inner {
    width: 48px;
    height: 48px;
  }
}

.camera-control-spacer {
  position: absolute;
  right: 24px;
  top: 50%;
  transform: translateY(-50%);
  width: 52px;
  height: 52px;
  flex: 0 0 52px;
  visibility: hidden;
  pointer-events: none;
}

/* TIMELINE DRAG-TO-REORDER */
.drag-ghost {
  position: fixed;
  pointer-events: none;
  z-index: 600;
  border-radius: 0;
  overflow: hidden;
  border: 2px solid var(--bevel-dd);
  box-shadow: 3px 3px 0 var(--bevel-dd);
  opacity: 0.9;
  transform: rotate(2deg) scale(1.05);
}
.drag-ghost img { width: 100%; height: 100%; object-fit: cover; display: block; }

.drag-source { opacity: 0.25; }

.drag-placeholder {
  flex-shrink: 0;
  width: 3px;
  min-width: 3px;
  max-width: 3px;
  height: calc(var(--timeline-height) - 16px);
  background: var(--accent);
  border-radius: 2px;
  align-self: center;
}

/* SHUTTER FLASH */
#shutter-flash {
  position: fixed;
  inset: 0;
  background: white;
  opacity: 0;
  pointer-events: none;
  z-index: 2000;
}

@keyframes shutterFlash {
  0%   { opacity: 0.85; }
  100% { opacity: 0; }
}

.shutter-flashing { animation: shutterFlash 0.35s ease-out forwards; }

/* NEW ITEM DROP-IN */
@keyframes itemDropIn {
  0%   { transform: translateY(-12px) scale(0.96); opacity: 0; }
  100% { transform: translateY(0) scale(1);        opacity: 1; }
}

.image-item.new-item { animation: itemDropIn 0.28s ease-out; }

/* ============================================================
   LANDSCAPE LAYOUT — preview panels side-by-side.
   ============================================================ */
@media (orientation: landscape) {
  /* Anchor for the full-height tab strip below. */
  #app {
    position: relative;
  }

  #workspace-main {
    flex-direction: row;
    padding-left: 36px;            /* clear the absolute tab strip on the left */
  }

  /* The tab strip owns the whole left edge — from just under the header down to
     the bottom of the display — so both the preview panels and the timeline sit
     to its right. It's taken out of flow and pinned to #app so it can span past
     the workspace panels over the timeline row too. */
  #workspace-tabs {
    position: absolute;
    top: calc(var(--header-height) + 2px);   /* header carries a 2px bottom bevel */
    left: 0;
    bottom: 0;
    width: 36px;
    flex: initial;
    flex-direction: column;
    align-items: flex-end;
    padding: 10px 0 10px 6px;
    background: #7f7f7f;
    gap: 0;
    z-index: 6;                    /* above the timeline (controls-bar is z-index 5) */
  }

  /* Timeline shifts fully to the right of the strip — the whole area, not just
     the thumbnails inside it. */
  #timeline-wrapper {
    margin-left: 36px;
  }

  .workspace-tab {
    min-width: 0;
    width: 30px;
    min-height: 96px;
    margin: 0 0 -12px 0;             /* overlap the tab below for a layered look */
    padding: 12px 5px;
    writing-mode: vertical-rl;
    transform: rotate(180deg);
    text-align: center;
  }

  /* The tab is rotated 180°, so CSS right-side corners land on the visual left
     (the outer edge, away from the panel) — where the rounding belongs. */
  .workspace-tab::before {
    border-radius: 0 11px 11px 0;
    transform: none;
    /* Extend the painted cap a little past the top of each tab. The tab is
       rotated 180°, so its CSS bottom is the visual top — pushing `bottom`
       negative lengthens the visual top without moving the text or the tab. */
    bottom: -6px;
    /* Tabs stack top-to-bottom here, so the layering shadow runs vertically. */
    box-shadow:
      inset 1px 0 0 rgba(255, 255, 255, 0.28),
      0 -3px 5px -2px rgba(0, 0, 0, 0.35),
      0 3px 5px -2px rgba(0, 0, 0, 0.35);
  }

  .workspace-tab.active {
    width: 33px;                     /* stands proud toward the panel */
  }

  .workspace-tab.active::before {
    background: var(--surface-bg);   /* matches the panel */
    /* No shadow on the active tab: it's the same grey as its panel and sits in
       front (z-index), so the neighbouring tabs' shadows tuck behind it — the
       tab reads as a seamless protrusion of the panel, like before. */
    box-shadow: none;
  }

  /* Previews go side by side in landscape */
  #main-preview { flex-direction: row; }

  #frame-preview-panel {
    border-top: none;
    border-left: 1px solid var(--border);
  }
}

/* ============================================================
   LANDSCAPE MOBILE — popups split preview / controls side-by-side
   Phones in landscape are ~350–430 px tall; desktops are 768 px+,
   so max-height: 500px safely targets only mobile landscape.
   ============================================================ */
@media (orientation: landscape) and (max-height: 500px) {

  /* Fill the full viewport and switch to a 2-column grid */
  #adjust-panel {
    width: 100%;
    max-width: 100%;
    height: 100vh;
    max-height: 100vh;
    border-radius: 0;
    display: grid;
    grid-template-rows: auto 1fr auto;
  }

  /* Column split: adjust panel gives canvas a bit more room */
  #adjust-panel   { grid-template-columns: 48% 1fr; }

  /* Header spans both columns */
  #adjust-panel .panel-header { grid-column: 1 / -1; }

  /* Canvas / preview fills rows 2 + 3 in the left column */
  #adjust-canvas-wrap {
    grid-column: 1;
    grid-row: 2 / 4;
    height: auto;           /* override fixed 280px */
    border-right: 1px solid var(--border);
  }

  /* Controls scroll in the right column, row 2 */
  #adjust-controls   { grid-column: 2; grid-row: 2; }

  /* Footer sticks to bottom of the right column, row 3 */
  #adjust-panel .panel-footer   { grid-column: 2; grid-row: 3; padding-bottom: 10px; }
}

/* ============================================================
   HELP MODAL
   ============================================================ */

#help-modal.overlay,
#confirm-modal.overlay,
#classifier-modal.overlay {
  align-items: center;
  justify-content: center;
}

#help-modal-panel {
  width: min(calc(100vw - 32px), 640px);
  max-height: 95vh;
  background: var(--bg);
  border: 2px solid;
  border-color: var(--bevel-ll) var(--bevel-d) var(--bevel-d) var(--bevel-ll);
  box-shadow: inset 1px 1px 0 var(--bevel-l), inset -1px -1px 0 var(--bevel-dd);
  border-radius: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* CONFIRM MODAL */
#confirm-modal-panel {
  width: min(calc(100vw - 32px), 320px);
  background: var(--bg);
  border: 2px solid;
  border-color: var(--bevel-ll) var(--bevel-d) var(--bevel-d) var(--bevel-ll);
  box-shadow: inset 1px 1px 0 var(--bevel-l), inset -1px -1px 0 var(--bevel-dd);
  border-radius: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

#confirm-modal.is-warning .panel-header {
  background: linear-gradient(to right, #7b0000, #bb0000);
}

.document-viewer-body {
  max-height: min(72vh, 620px);
  overflow: auto;
  padding: 16px 20px;
  background: #fff;
  border: 2px inset #c0c0c0;
  line-height: 1.5;
}

.document-viewer-body h1 {
  font-size: 20px;
  border-bottom: 2px solid #000080;
  padding-bottom: 4px;
  margin: 16px 0 10px;
}

.document-viewer-body h2 {
  font-size: 16px;
  border-bottom: 1px solid #808080;
  padding-bottom: 2px;
  margin: 14px 0 8px;
}

.document-viewer-body h3 { font-size: 14px; margin: 12px 0 6px; }
.document-viewer-body p { margin: 6px 0; }
.document-viewer-body ul,
.document-viewer-body ol { margin: 6px 0 6px 22px; }
.document-viewer-body li { margin: 2px 0; }
.document-viewer-body pre {
  background: #f0f0f0;
  border: 1px solid #c0c0c0;
  padding: 10px 14px;
  overflow-x: auto;
  margin: 8px 0;
  font-size: 12px;
  white-space: pre-wrap;
  word-break: break-word;
}
.document-viewer-body code { background: #f0f0f0; padding: 1px 4px; font-size: 12px; }
.document-viewer-body pre code { background: none; padding: 0; }
.document-viewer-body a { color: #000080; }
.document-viewer-body a:hover { color: #1084d0; }
.document-viewer-body hr { border: none; border-top: 1px solid #808080; margin: 12px 0; }
.document-viewer-body blockquote { border-left: 3px solid #000080; margin: 8px 0; padding: 4px 12px; color: #404040; }
.document-viewer-body strong { font-weight: bold; }
.document-viewer-body em { font-style: italic; }
.document-viewer-body.document-viewer-plain pre { background: none; border: none; padding: 0; }
.document-viewer-loading { color: #666; font-style: italic; }
.document-viewer-error { color: #800000; margin-bottom: 10px; }

#classifier-modal-panel {
  width: min(calc(100vw - 32px), 360px);
  max-height: min(92vh, 700px);
  background: var(--bg);
  border: 2px solid;
  border-color: var(--bevel-ll) var(--bevel-d) var(--bevel-d) var(--bevel-ll);
  box-shadow: inset 1px 1px 0 var(--bevel-l), inset -1px -1px 0 var(--bevel-dd);
  border-radius: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

#classifier-preview-wrap {
  padding: 0 16px 12px;
  flex-shrink: 0;
}

#classifier-preview-canvas {
  display: block;
  width: 100%;
  height: auto;
  max-height: 180px;
  object-fit: contain;
  border-radius: 6px;
  background: #111;
}

#confirm-modal-body {
  padding: 16px 16px 10px;
  font-size: 12px;
  line-height: 1.6;
  color: var(--text);
}

#classifier-modal-body {
  padding: 16px;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
}

#classifier-prefilter-wrap {
  padding: 0 16px 12px;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 6px 10px;
  font-size: 11px;
  overflow-y: auto;
  max-height: 200px;
}

.classifier-prefilter-title {
  grid-column: 1 / -1;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  margin-top: 2px;
}

.classifier-prefilter-option {
  display: flex;
  align-items: center;
  gap: 6px;
}

.classifier-prefilter-option input {
  margin: 0;
}

#confirm-modal-body p { margin: 0; }

#confirm-modal-footer {
  justify-content: flex-end;
  padding-bottom: calc(10px + var(--safe-bottom));
}

#classifier-modal-footer {
  justify-content: flex-end;
  padding-bottom: calc(10px + var(--safe-bottom));
}

.btn-dialog {
  flex: 0 0 auto;
  min-width: 72px;
  padding: 4px 14px;
  font-size: 11px;
}

.btn-classifier-choice {
  width: 100%;
  padding: 6px 8px;
  font-size: 11px;
}

.btn-dialog-default {
  box-shadow: inset 1px 1px 0 var(--bevel-l), inset -1px -1px 0 var(--bevel-dd), 0 0 0 1px var(--text);
  font-weight: 700;
}

.btn-dialog-default:active {
  box-shadow: inset 1px 1px 0 var(--bevel-dd), inset -1px -1px 0 var(--bevel-l), 0 0 0 1px var(--text);
}

/* Alert mode — reuse confirm modal with Cancel hidden */
#confirm-modal.is-alert #btn-confirm-cancel { display: none; }

#help-modal-body {
  flex: 1;
  overflow-y: auto;
  padding: 16px;
}

#help-video-wrap {
  position: relative;
  width: 100%;
  padding-bottom: 56.25%; /* 16:9 */
  height: 0;
  border-radius: 8px;
  overflow: hidden;
  background: #000;
}

#help-video-wrap iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: none;
}

@media (orientation: landscape) and (max-height: 500px) {
  #help-modal-panel {
    width: min(calc(100vw - 32px), 430px);
    max-height: min(calc(100vh - 24px), 860px);
  }

  #help-modal-body {
    padding: 12px;
  }

  #help-video-wrap {
    padding-bottom: 0;
    height: auto;
    aspect-ratio: 16 / 9;
    max-height: calc(100vh - 120px);
  }
}

/* ============================================================
   FLIPBOOK LOGO ANIMATION
   ============================================================ */

.fp-logo {
  display: block;
  flex-shrink: 0;
  object-fit: contain;
  background: transparent;
}

/* ============================================================
   ACCOUNT POPUP (Phase 3, editor-only)
   ============================================================ */

/* win98 frames for the account popup's sub-dialogs (crop / delete / user list).
   The main shell reuses ensureWin98Shell's inline styling. */
.win98-window {
  --win98-bg: #c0c0c0;
  background: #c0c0c0;
  border: 2px solid;
  border-color: #fff #808080 #808080 #fff;
  box-shadow: 2px 2px 0 #000;
  font-family: "Arial", "MS Sans Serif", sans-serif;
  font-size: 12px;
  color: #000;
}
.win98-titlebar {
  background: linear-gradient(to right, #000080, #1084d0);
  color: #fff;
  font-weight: bold;
  font-size: 12px;
  padding: 3px 5px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  user-select: none;
}
.win98-close {
  background: #c0c0c0;
  border: 1px solid;
  border-color: #fff #808080 #808080 #fff;
  color: #000;
  font-family: inherit;
  font-size: 11px;
  padding: 0 5px;
  line-height: 16px;
  cursor: pointer;
  min-width: 20px;
  font-weight: bold;
}
.btn-auth {
  background: #c0c0c0;
  border: 2px outset #c0c0c0;
  padding: 4px 12px;
  font-family: inherit;
  font-size: 12px;
  cursor: pointer;
  color: #000;
}
.btn-auth:active { border-style: inset; }

.acct-card { display: flex; gap: 12px; align-items: flex-start; padding: 4px 0 12px; }
.acct-avatar-label { position: relative; width: 72px; height: 72px; flex-shrink: 0; border: 2px inset #c0c0c0; cursor: pointer; display: block; background: #fff; }
.acct-avatar { width: 100%; height: 100%; object-fit: cover; display: block; }
.acct-avatar-edit { position: absolute; right: 2px; bottom: 2px; background: rgba(0, 0, 0, 0.6); color: #fff; font-size: 11px; padding: 0 4px; border-radius: 2px; }
.acct-info { flex: 1; min-width: 0; }
.acct-row { display: flex; align-items: center; gap: 6px; }
.acct-name { font-weight: bold; font-size: 14px; word-break: break-word; }
.acct-bio-wrap { display: flex; align-items: flex-start; gap: 6px; margin-top: 4px; }
.acct-bio { font-size: 12px; color: #333; margin: 0; word-break: break-word; white-space: pre-wrap; }
.acct-edit-btn { background: none; border: none; cursor: pointer; font-size: 12px; color: #000080; padding: 0 2px; }
.acct-stats { display: flex; gap: 12px; margin-top: 8px; }
.acct-stat { background: none; border: none; cursor: pointer; font-size: 12px; color: #000; padding: 0; }
.acct-stat:hover { text-decoration: underline; }
.acct-field-input { font-size: inherit; font-family: inherit; width: 100%; box-sizing: border-box; }
.acct-notif { border-top: 1px solid #808080; padding: 10px 0; margin-top: 4px; }
.acct-notif-label { display: flex; align-items: center; gap: 8px; font-size: 12px; cursor: pointer; }
.acct-notif-chk { width: 16px; height: 16px; cursor: pointer; }
.acct-notif-note { font-size: 11px; color: #666; margin-top: 4px; }
.acct-danger { border-top: 1px solid #808080; padding-top: 12px; margin-top: 4px; }
.acct-delete { background: #c0c0c0; color: #800000; font-weight: bold; }
.acct-list-body { flex: 1; overflow-y: auto; padding: 8px; background: #c0c0c0; }
.acct-list-row { display: flex; align-items: center; gap: 8px; padding: 6px 4px; border-bottom: 1px solid #c0c0c0; }
