/* =========================================================================
   EMPIRIUM OS — CANVAS
   Full-page image board. Reuses the pinboard visual language from
   .eo-as-pin (empirium.css) and the positioned-canvas shape of the retired
   Vision Board, but namespaced .eo-cv-* so it never collides with either
   surface. The .eo-cv-preview-* rules at the bottom style the read-only
   miniature the Morning Briefing shows in its Vision Board card.
   ========================================================================= */

.eo-cv-head{ align-items:flex-end; }

.eo-cv-toolbar{
  display:flex; flex-wrap:wrap; align-items:center; gap:10px;
  margin-bottom:14px; padding:12px 14px;
  background:var(--card-subtle); border:1px solid var(--line); border-radius:var(--r-lg);
}
.eo-cv-board-select{ min-width:160px; width:auto; }
.eo-cv-board-name{ width:auto; min-width:160px; flex:1 1 180px; max-width:280px; }
.eo-cv-toolbar-spacer{ flex:1 1 auto; }
.eo-cv-toolbar-field{
  display:flex; align-items:center; gap:6px;
  font-size:var(--fs-caption); color:var(--muted);
}
.eo-cv-toolbar-field select{ width:auto; min-width:88px; }
.eo-cv-toolbar-note{ font-size:var(--fs-caption); color:var(--faint); white-space:nowrap; }

/* ---- zoom slider — replaces the old fixed-interval picker ---- */
.eo-cv-zoom-field{ gap:8px; }
.eo-cv-zoom-slider{
  width:120px; accent-color:var(--accent); cursor:pointer;
}
.eo-cv-zoom-readout{
  min-width:34px; text-align:right; font-variant-numeric:tabular-nums; color:var(--text);
}

.eo-cv-warning{
  margin:-4px 0 14px; padding:8px 14px;
  border:1px solid rgba(var(--danger-rgb,220,80,80),.4); border-radius:var(--r-md);
  background:rgba(var(--danger-rgb,220,80,80),.1);
  color:var(--danger-soft, #e08a8a); font-size:var(--fs-small);
}

/* ---- tab strip — sits between the settings bar and the canvas. Each board
   carries up to 10 tabs; the active one is the surface being drawn on. Styled
   as real folder-ish tabs (square top corners, seam-less into the canvas) so
   it reads as "these are pages of this canvas", not another row of buttons. ---- */
.eo-cv-tabs{
  display:flex; flex-wrap:wrap; align-items:flex-end; gap:4px;
  margin-bottom:10px; padding:0 2px;
}
.eo-cv-tab{
  display:flex; align-items:center; gap:6px; max-width:200px;
  padding:6px 8px 6px 12px; cursor:pointer; user-select:none;
  border:1px solid var(--line);
  border-radius:var(--r-md) var(--r-md) var(--r-sm) var(--r-sm);
  background:var(--card-subtle); color:var(--muted);
  font-size:var(--fs-small); line-height:1.3;
  transition:background-color var(--t-snap) var(--ease), color var(--t-snap) var(--ease),
             border-color var(--t-snap) var(--ease), transform var(--t-snap) var(--ease);
}
.eo-cv-tab:hover{ background:var(--card-hover, rgba(var(--text-rgb),.06)); color:var(--text); }
.eo-cv-tab.active{
  background:var(--card); color:var(--text); font-weight:700;
  border-color:var(--line-strong); box-shadow:inset 0 2px 0 var(--accent);
}
.eo-cv-tab.dragging{ opacity:.45; }
.eo-cv-tab.drop-target{ border-color:var(--accent); transform:translateY(-2px); }
.eo-cv-tab-name{
  flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.eo-cv-tab-rename{
  width:100%; min-width:60px; padding:0; margin:0;
  border:0; outline:0; background:transparent; color:var(--text);
  font:inherit;
}
.eo-cv-tab-x{
  flex:0 0 auto; width:16px; height:16px; padding:0;
  border:none; border-radius:50%; cursor:pointer; font-size:9px; line-height:1;
  background:transparent; color:var(--faint); opacity:0;
  transition:opacity var(--t-snap) var(--ease), background-color var(--t-snap) var(--ease);
}
.eo-cv-tab:hover .eo-cv-tab-x, .eo-cv-tab.active .eo-cv-tab-x{ opacity:1; }
.eo-cv-tab-x:hover{ background:rgba(var(--danger-rgb,220,80,80),.25); color:var(--danger-soft, #e08a8a); }
.eo-cv-tab-add{
  padding:5px 10px; cursor:pointer; font-size:var(--fs-caption); line-height:1.4;
  color:var(--muted); background:transparent;
  border:1px dashed var(--line-strong); border-radius:var(--r-md);
  transition:color var(--t-snap) var(--ease), border-color var(--t-snap) var(--ease);
}
.eo-cv-tab-add:hover{ color:var(--accent); border-color:var(--accent); }
.eo-cv-tab-full{ align-self:center; font-size:var(--fs-caption); color:var(--faint); padding-left:6px; }

/* ---- Board area: the image library (when open) sits beside the canvas
   viewport as a fixed-width shelf; the viewport takes the rest of the row. ---- */
.eo-cv-board-area{ display:flex; align-items:flex-start; gap:16px; }

.eo-cv-library{
  flex:0 0 210px; display:flex; flex-direction:column; gap:10px;
  padding:12px; border:1px solid var(--line); border-radius:var(--r-lg);
  background:var(--card-subtle); max-height:calc(100vh - 220px); position:sticky; top:0;
}
.eo-cv-library-head{ display:flex; align-items:center; justify-content:space-between; gap:8px; }
.eo-cv-library-head b{ font-size:var(--fs-small); color:var(--text); }
.eo-cv-library-grid{
  display:grid; grid-template-columns:repeat(2, 1fr); gap:8px;
  overflow-y:auto; padding:2px; border-radius:var(--r-md);
  transition:background-color var(--t-snap) var(--ease);
}
.eo-cv-library-grid.dragging{ background-color:rgba(var(--accent-rgb),.1); outline:1px dashed var(--accent); }
.eo-cv-library-empty{
  grid-column:1 / -1; padding:16px 8px; text-align:center; font-size:var(--fs-caption);
  color:var(--faint); border:1px dashed var(--line-strong); border-radius:var(--r-md); line-height:1.5;
}
.eo-cv-lib-item{
  position:relative; aspect-ratio:1; border-radius:var(--r-sm); overflow:hidden;
  border:1px solid var(--line); cursor:grab; background:var(--card);
}
.eo-cv-lib-item img{ display:block; width:100%; height:100%; object-fit:cover; pointer-events:none; }
.eo-cv-lib-del{
  position:absolute; top:2px; right:2px; width:18px; height:18px;
  border:none; border-radius:50%; cursor:pointer; font-size:10px; line-height:1;
  background:rgba(0,0,0,.65); color:#fff; opacity:0; transition:opacity var(--t-snap) var(--ease);
}
.eo-cv-lib-item:hover .eo-cv-lib-del{ opacity:1; }

/* ---- Viewport reserves the zoomed layout footprint; canvas holds the true
   logical size and is visually scaled via transform (origin 0 0) so every
   pointer coordinate can be converted with a single division by scale. ---- */
/* margin-bottom leaves room for the extend bar, which hangs below the canvas. */
.eo-cv-viewport{ position:relative; margin-bottom:46px; flex:1 1 auto; min-width:0; }
.eo-cv-canvas{
  position:relative; transform-origin:0 0;
  border:1px solid var(--line-strong); border-radius:var(--r-lg);
  background-color:var(--card-subtle);
  background-image:radial-gradient(circle at 1px 1px, rgba(var(--text-rgb),.1) 1px, transparent 0);
  background-size:24px 24px;
  box-shadow:inset 0 1px 0 rgba(var(--text-rgb),.04), var(--sh-1);
  transition:border-color var(--t-snap) var(--ease), background-color var(--t-snap) var(--ease);
}
.eo-cv-canvas.dragging{ border-color:var(--accent); background-color:rgba(var(--accent-rgb),.08); }

.eo-cv-empty{
  position:absolute; inset:24px; display:flex; flex-direction:column;
  align-items:center; justify-content:center; gap:6px;
  border:1px dashed var(--line-strong); border-radius:var(--r-md);
  color:var(--muted); cursor:pointer; text-align:center;
}
.eo-cv-empty b{ color:var(--text); font-size:16px; }
.eo-cv-empty span{ font-size:var(--fs-small); color:var(--faint); }

/* ---- one pinned photo ----
   The card is a flex column: title strip, image, caption strip. Only the
   image has a fixed pixel height (the resize handle's doing); the two text
   strips are auto-height and grow purely because their textarea's own
   scrollHeight grows — an empty card stays paper-thin at top and bottom. */
.eo-cv-item{
  position:absolute; margin:0; cursor:grab; touch-action:none; user-select:none;
  display:flex; flex-direction:column;
}
.eo-cv-item.dragging{ cursor:grabbing; z-index:999; }
.eo-cv-item.selected{ outline:2px solid var(--accent); outline-offset:3px; border-radius:4px; }

.eo-cv-item-frame{ position:relative; width:100%; flex:0 0 auto; }
.eo-cv-item-frame img{ display:block; width:100%; height:100%; object-fit:cover; pointer-events:none; }

/* Shared title/caption textareas — auto-grown by JS (growTextarea), never
   pre-reserved with padding or a fixed row count. */
.eo-cv-title-bar, .eo-cv-cap-bar{ flex:0 0 auto; }
.eo-cv-title-input, .eo-cv-cap-input{
  display:block; width:100%; margin:0; padding:0; resize:none; overflow:hidden;
  border:0; outline:0; background:transparent; font-family:var(--font-body); text-align:center;
}
.eo-cv-title-input{ font-size:13.5px; font-weight:700; line-height:1.3; }
.eo-cv-cap-input{ font-size:var(--fs-caption); font-weight:600; line-height:1.35; }
.eo-cv-title-input::placeholder, .eo-cv-cap-input::placeholder{ opacity:.65; }

/* Polaroid frame: paper card, thumbtack, jaunty tilt — title lives in the
   top margin, caption in the bottom "chin". Same paper white as .eo-as-pin
   (empirium.css:745) so the two surfaces read as one family. */
.eo-cv-item-polaroid{
  background:#f3efe6; border-radius:2px; box-sizing:border-box; padding:8px 8px 0;
  transform:rotate(var(--cv-rot, 0deg)); transform-origin:50% 8px;
  filter:drop-shadow(0 8px 14px rgba(0,0,0,.45));
  transition:transform .18s var(--ease);
}
.eo-cv-item-polaroid .eo-cv-title-bar{ padding-bottom:4px; }
.eo-cv-item-polaroid .eo-cv-title-input{ color:#2c2718; }
.eo-cv-item-polaroid .eo-cv-cap-bar{ padding:6px 2px 16px; }
.eo-cv-item-polaroid .eo-cv-cap-input{ color:#5c5442; }
.eo-cv-item-polaroid::after{
  content:""; position:absolute; top:-6px; left:50%; margin-left:-8px;
  width:16px; height:16px; border-radius:50%;
  background:radial-gradient(circle at 34% 28%, #ff9d94, #e5423a 55%, #7e1410);
  box-shadow:0 3px 4px rgba(0,0,0,.55), inset 0 -2px 3px rgba(0,0,0,.35);
  z-index:2;
}
.eo-cv-item-polaroid:hover{ transform:rotate(var(--cv-rot, 0deg)) scale(1.02); z-index:50; }
.eo-cv-item-polaroid.dragging{
  transition:none; transform:rotate(var(--cv-rot, 0deg)) scale(1.05);
  filter:drop-shadow(0 16px 22px rgba(0,0,0,.55));
}

/* Clean frame: borderless rounded image, no tack, no tilt, no paper. */
.eo-cv-item-clean{ transition:transform var(--t-snap) var(--ease); }
.eo-cv-item-clean .eo-cv-title-bar{ padding:0 2px 4px; }
.eo-cv-item-clean .eo-cv-title-input{ color:var(--text); }
.eo-cv-item-clean .eo-cv-cap-bar{ padding:4px 2px 0; }
.eo-cv-item-clean .eo-cv-cap-input{ color:var(--muted); }
.eo-cv-item-clean .eo-cv-item-frame{
  border:1px solid rgba(var(--text-rgb),.14); border-radius:var(--r-md);
  overflow:hidden; box-shadow:0 8px 24px rgba(0,0,0,.2);
  transition:box-shadow var(--t-snap) var(--ease), border-color var(--t-snap) var(--ease);
}
.eo-cv-item-clean:hover .eo-cv-item-frame{ border-color:var(--line-bright); box-shadow:0 12px 30px rgba(0,0,0,.28); }
.eo-cv-item-clean.dragging .eo-cv-item-frame{ box-shadow:0 18px 40px rgba(0,0,0,.36); }

/* ---- hover delete — anchored to the whole card's top-right corner ---- */
.eo-cv-item-x{
  position:absolute; top:6px; right:-6px; width:22px; height:22px;
  border:none; border-radius:50%; cursor:pointer; font-size:11px; line-height:1;
  background:rgba(0,0,0,.6); color:#fff; opacity:0; z-index:3;
  transition:opacity var(--t-snap) var(--ease);
}
.eo-cv-item:hover .eo-cv-item-x{ opacity:1; }

/* ---- resize handle — anchored to the photo itself (not the text strips),
   same nwse-resize square as .eo-as-pin-resize ---- */
.eo-cv-resize{
  position:absolute; right:-5px; bottom:-5px; width:12px; height:12px; border-radius:3px;
  background:var(--accent); border:2px solid var(--bg); cursor:nwse-resize;
  opacity:0; transition:opacity var(--t-snap) var(--ease); z-index:4;
}
.eo-cv-item:hover .eo-cv-resize{ opacity:1; }
.eo-cv-resize:hover{ transform:scale(1.2); }

/* ---- sections (dividers) — colored, titled background regions. Mostly
   pointer-events:none so an empty stretch of section still passes clicks
   through to the canvas beneath (click-to-add still works); only the header
   bar, color swatch, delete button and resize handles opt back in. Items are
   always z-indexed above every section (see itemHTML's +1000 offset). ---- */
.eo-cv-zone{
  position:absolute; margin:0; pointer-events:none; touch-action:none;
  border-radius:var(--r-md); border:1px solid var(--cv-zone-color, var(--accent));
  background:color-mix(in srgb, var(--cv-zone-color, var(--accent)) 16%, transparent);
  transition:background-color var(--t-snap) var(--ease), box-shadow var(--t-snap) var(--ease);
}
.eo-cv-zone.dragging{
  box-shadow:0 18px 40px rgba(0,0,0,.4);
  background:color-mix(in srgb, var(--cv-zone-color, var(--accent)) 26%, transparent);
}

/* Header bar: spans the section's whole width so it can be grabbed anywhere
   along the top, instead of the old centred pill that was a small target. */
.eo-cv-zone-bar{
  position:absolute; top:0; left:0; right:0; height:32px;
  display:flex; align-items:center; gap:8px; padding:0 8px;
  pointer-events:auto; cursor:grab;
  background:color-mix(in srgb, var(--cv-zone-color, var(--accent)) 42%, rgba(8,8,10,.72));
  border-radius:var(--r-md) var(--r-md) 0 0;
  backdrop-filter:blur(3px);
  transition:background-color var(--t-snap) var(--ease);
}
.eo-cv-zone-bar:hover{ background:color-mix(in srgb, var(--cv-zone-color, var(--accent)) 58%, rgba(8,8,10,.72)); }
.eo-cv-zone-bar:active, .eo-cv-zone.dragging .eo-cv-zone-bar{ cursor:grabbing; }
/* The six-dot grip is the affordance that says "this whole strip drags". */
.eo-cv-zone-grip{
  flex:0 0 auto; width:12px; height:16px; opacity:.75;
  background-image:radial-gradient(circle, rgba(255,255,255,.95) 1.2px, transparent 1.3px);
  background-size:6px 5px; background-position:0 2px;
}
.eo-cv-zone-title{
  flex:1 1 auto; min-width:0; border:0; outline:0; background:transparent;
  color:#fff; text-align:left; font:700 var(--fs-caption)/1.4 var(--font-body);
  padding:3px 4px; cursor:text;
}
.eo-cv-zone-title::placeholder{ color:rgba(255,255,255,.6); }
.eo-cv-zone-color{
  flex:0 0 auto; width:20px; height:20px;
  pointer-events:auto; cursor:pointer; border:2px solid rgba(255,255,255,.5);
  border-radius:50%; padding:0; background:none; overflow:hidden;
}
.eo-cv-zone-color::-webkit-color-swatch-wrapper{ padding:0; }
.eo-cv-zone-color::-webkit-color-swatch{ border:none; border-radius:50%; }
.eo-cv-zone-del{
  flex:0 0 auto; width:20px; height:20px;
  pointer-events:auto; border:none; border-radius:50%; cursor:pointer;
  font-size:11px; line-height:1; background:rgba(0,0,0,.5); color:#fff;
  opacity:.55; transition:opacity var(--t-snap) var(--ease);
}
.eo-cv-zone-bar:hover .eo-cv-zone-del{ opacity:1; }

/* Eight-way resize handles. Edge handles are invisible strips (a wide,
   forgiving hit area); corner handles are the familiar small squares. */
.eo-cv-zone-h{ position:absolute; pointer-events:auto; opacity:0; transition:opacity var(--t-snap) var(--ease); }
.eo-cv-zone:hover .eo-cv-zone-h{ opacity:1; }
.eo-cv-zone-h-n, .eo-cv-zone-h-s{ left:12px; right:12px; height:8px; cursor:ns-resize; }
.eo-cv-zone-h-e, .eo-cv-zone-h-w{ top:12px; bottom:12px; width:8px; cursor:ew-resize; }
.eo-cv-zone-h-n{ top:-4px; }
.eo-cv-zone-h-s{ bottom:-4px; }
.eo-cv-zone-h-e{ right:-4px; }
.eo-cv-zone-h-w{ left:-4px; }
.eo-cv-zone-h-nw, .eo-cv-zone-h-ne, .eo-cv-zone-h-sw, .eo-cv-zone-h-se{
  width:12px; height:12px; border-radius:3px;
  background:var(--cv-zone-color, var(--accent)); border:2px solid var(--bg);
}
.eo-cv-zone-h-nw{ top:-5px; left:-5px; cursor:nwse-resize; }
.eo-cv-zone-h-ne{ top:-5px; right:-5px; cursor:nesw-resize; }
.eo-cv-zone-h-sw{ bottom:-5px; left:-5px; cursor:nesw-resize; }
.eo-cv-zone-h-se{ bottom:-5px; right:-5px; cursor:nwse-resize; }

/* ---- per-image frame toggle — the one-click path between polaroid and clear
   frame for THIS picture only. The right-click menu has the full three-way
   choice including "use board default". ---- */
.eo-cv-item-frame-btn{
  position:absolute; top:6px; left:-6px; width:22px; height:22px;
  border:none; border-radius:50%; cursor:pointer; font-size:11px; line-height:1;
  background:rgba(0,0,0,.6); color:#fff; opacity:0; z-index:3;
  transition:opacity var(--t-snap) var(--ease);
}
.eo-cv-item:hover .eo-cv-item-frame-btn{ opacity:1; }
.eo-cv-item-frame-btn:hover{ background:var(--accent); }

/* ---- connection anchors — four dots at the edge midpoints of every node.
   Hidden until the card is hovered or selected so a finished board stays
   clean. cursor:crosshair signals "drag me somewhere" rather than "move me". ---- */
.eo-cv-anchor{
  position:absolute; width:11px; height:11px; border-radius:50%;
  background:var(--accent); border:2px solid var(--bg);
  opacity:0; pointer-events:auto; cursor:crosshair; z-index:6;
  transition:opacity var(--t-snap) var(--ease), transform var(--t-snap) var(--ease);
}
.eo-cv-item:hover .eo-cv-anchor,
.eo-cv-item.selected .eo-cv-anchor,
.eo-cv-text:hover .eo-cv-anchor,
.eo-cv-text.selected .eo-cv-anchor{ opacity:.9; }
.eo-cv-anchor:hover{ opacity:1; transform:scale(1.45); }
.eo-cv-anchor-top{    top:-6px;    left:50%;   margin-left:-5.5px; }
.eo-cv-anchor-bottom{ bottom:-6px; left:50%;   margin-left:-5.5px; }
.eo-cv-anchor-left{   left:-6px;   top:50%;    margin-top:-5.5px; }
.eo-cv-anchor-right{  right:-6px;  top:50%;    margin-top:-5.5px; }
/* While a connection is being dragged, show every card's dots so the target
   is obvious, and light up the one under the cursor. */
.eo-cv-canvas.linking .eo-cv-anchor{ opacity:.55; }
.eo-cv-canvas.linking .eo-cv-item, .eo-cv-canvas.linking .eo-cv-text{ cursor:crosshair; }
.link-target{ outline:2px dashed var(--accent); outline-offset:4px; border-radius:4px; }

/* ---- connection layer — one SVG spanning the canvas, sitting between the
   sections (z<1000) and the nodes (z>=1000). pointer-events:none on the svg
   itself so it never steals a click from the board; only the fat invisible
   hit paths opt back in. ---- */
.eo-cv-links{
  position:absolute; top:0; left:0; pointer-events:none; z-index:999; overflow:visible;
}
.eo-cv-link-hit{ pointer-events:stroke; cursor:pointer; }
.eo-cv-link-path{ pointer-events:none; transition:stroke-width var(--t-snap) var(--ease); }
.eo-cv-link-hit:hover + .eo-cv-link-path{ filter:drop-shadow(0 0 4px rgba(var(--accent-rgb),.9)); }
.eo-cv-link-draft{ pointer-events:none; opacity:.85; }

/* The per-connection X. Parked at the curve's midpoint by redrawLinks and only
   painted while the pointer is on that connection, so a board full of arrows
   never turns into a board full of buttons. */
.eo-cv-link-x{
  pointer-events:none; opacity:0; cursor:pointer;
  transition:opacity var(--t-snap) var(--ease);
}
.eo-cv-link-x.visible{ pointer-events:auto; opacity:1; }
.eo-cv-link-x-bg{
  fill:rgba(8,8,10,.86); stroke:var(--line-bright); stroke-width:1;
  transition:fill var(--t-snap) var(--ease);
}
.eo-cv-link-x-mark{ stroke:#fff; stroke-width:1.8; stroke-linecap:round; fill:none; }
.eo-cv-link-x:hover .eo-cv-link-x-bg{ fill:var(--danger, #d64545); stroke:var(--danger, #d64545); }

/* ---- standalone text block — words on the board with no photo attached.
   The grip strip along the top is the drag handle; the textarea below is left
   directly clickable so a cursor can be placed in the text normally. ---- */
.eo-cv-text{
  position:absolute; touch-action:none;
  display:flex; flex-direction:column;
  border-radius:var(--r-sm);
  transition:box-shadow var(--t-snap) var(--ease);
}
.eo-cv-text.selected{ outline:2px solid var(--accent); outline-offset:3px; }
.eo-cv-text.dragging{ z-index:999; box-shadow:0 18px 40px rgba(0,0,0,.36); }

.eo-cv-text-grip{
  display:flex; align-items:center; gap:6px; height:24px; padding:0 6px;
  cursor:grab; opacity:0; border-radius:var(--r-sm) var(--r-sm) 0 0;
  background:rgba(8,8,10,.72); backdrop-filter:blur(3px);
  transition:opacity var(--t-snap) var(--ease);
}
.eo-cv-text:hover .eo-cv-text-grip, .eo-cv-text.selected .eo-cv-text-grip{ opacity:1; }
.eo-cv-text-grip:active, .eo-cv-text.dragging .eo-cv-text-grip{ cursor:grabbing; }
.eo-cv-text-grip-dots{
  flex:0 0 auto; width:12px; height:14px; opacity:.75;
  background-image:radial-gradient(circle, rgba(255,255,255,.95) 1.2px, transparent 1.3px);
  background-size:6px 5px; background-position:0 1px;
}
.eo-cv-text-tools{ display:flex; align-items:center; gap:4px; margin-left:auto; }
.eo-cv-text-tools button{
  min-width:20px; height:18px; padding:0 4px; cursor:pointer;
  border:1px solid rgba(255,255,255,.22); border-radius:3px;
  background:rgba(255,255,255,.08); color:#fff; font-size:11px; line-height:1;
}
.eo-cv-text-tools button:hover{ background:rgba(255,255,255,.2); }
.eo-cv-text-tools button.active{ background:var(--accent); border-color:var(--accent); }
.eo-cv-text-tools input[type=range]{ width:56px; accent-color:var(--accent); cursor:pointer; }
.eo-cv-text-tools input[type=color]{
  width:20px; height:18px; padding:0; border:1px solid rgba(255,255,255,.3);
  border-radius:3px; background:none; cursor:pointer;
}

/* The text itself. Height is never set — the textarea auto-grows (growTextarea)
   exactly like the polaroid title/caption strips do, so the block is always
   the height of its content and connection anchors stay on its true edges. */
.eo-cv-text-input{
  display:block; width:100%; margin:0; padding:4px 6px; resize:none; overflow:hidden;
  border:0; outline:0; background:transparent;
  font-family:var(--font-body);
  font-size:var(--cv-text-size, 18px);
  font-weight:var(--cv-text-weight, 400);
  text-align:var(--cv-text-align, left);
  color:var(--cv-text-color, var(--text));
  line-height:1.35;
  text-shadow:0 1px 3px rgba(0,0,0,.45);
}
.eo-cv-text-input::placeholder{ opacity:.45; }
.eo-cv-text-resize{
  position:absolute; right:-5px; bottom:-5px; width:12px; height:12px; border-radius:3px;
  background:var(--accent); border:2px solid var(--bg); cursor:ew-resize;
  opacity:0; z-index:4; transition:opacity var(--t-snap) var(--ease);
}
.eo-cv-text:hover .eo-cv-text-resize{ opacity:1; }

/* ---- extend the canvas downwards — a grab bar under the board. Sits inside
   the viewport (which is already sized to the zoomed footprint) so it tracks
   the bottom edge at every zoom level. ---- */
.eo-cv-extend{
  position:absolute; left:0; right:0; top:100%; height:22px;
  display:flex; align-items:center; justify-content:center; gap:10px;
  cursor:ns-resize; touch-action:none; user-select:none;
  border-radius:0 0 var(--r-lg) var(--r-lg);
  background:linear-gradient(to bottom, rgba(var(--text-rgb),.05), transparent);
  transition:background-color var(--t-snap) var(--ease);
}
.eo-cv-extend:hover, .eo-cv-extend.dragging{ background-color:rgba(var(--accent-rgb),.12); }
.eo-cv-extend-grip{
  width:56px; height:4px; border-radius:999px;
  background:var(--line-strong); transition:background-color var(--t-snap) var(--ease);
}
.eo-cv-extend:hover .eo-cv-extend-grip, .eo-cv-extend.dragging .eo-cv-extend-grip{ background:var(--accent); }
.eo-cv-extend-btn{
  padding:1px 8px; cursor:pointer; font-size:var(--fs-caption); line-height:1.5;
  color:var(--muted); background:var(--card-subtle);
  border:1px solid var(--line); border-radius:999px;
  opacity:0; transition:opacity var(--t-snap) var(--ease);
}
.eo-cv-extend:hover .eo-cv-extend-btn{ opacity:1; }
.eo-cv-extend-btn:hover{ color:var(--text); border-color:var(--accent); }

/* ---- drop-in animation, plays once per fresh pin (same choreography as
   eoPinDrop/eoTackIn in empirium.css, renamed to stay in this file's namespace) ---- */
@keyframes eoCvDrop{
  0%  { transform:translateY(-110px) rotate(calc(var(--cv-rot, 0deg) - 16deg)) scale(1.2); opacity:0; }
  45% { transform:translateY(6px)    rotate(calc(var(--cv-rot, 0deg) + 6deg))  scale(.92, .86); opacity:1; }
  62% { transform:translateY(-10px)  rotate(calc(var(--cv-rot, 0deg) - 4deg))  scale(1.05); }
  78% { transform:translateY(3px)    rotate(calc(var(--cv-rot, 0deg) + 2deg))  scale(.98, .96); }
  90% { transform:translateY(-2px)   rotate(calc(var(--cv-rot, 0deg) - 1deg))  scale(1.01); }
  100%{ transform:translateY(0)      rotate(var(--cv-rot, 0deg))               scale(1); }
}
.eo-cv-item.fresh{ animation:eoCvDrop .7s cubic-bezier(.3,1.2,.5,1) both; }
@keyframes eoCvTackIn{
  0%,70%{ opacity:0; transform:scale(.4); }
  85%   { opacity:1; transform:scale(1.35); }
  100%  { opacity:1; transform:scale(1); }
}
.eo-cv-item-polaroid.fresh::after{ animation:eoCvTackIn .8s var(--ease) both; }

/* ---- right-click context menu ---- */
.eo-cv-ctxmenu{
  position:fixed; z-index:2000; min-width:170px; padding:4px;
  background:var(--panel); border:1px solid var(--line-bright); border-radius:var(--r-md);
  box-shadow:0 12px 30px rgba(0,0,0,.4);
}
.eo-cv-ctxmenu-item{
  display:block; width:100%; text-align:left; padding:7px 10px; border:0; background:none;
  border-radius:var(--r-sm); color:var(--text); font-size:var(--fs-small); cursor:pointer;
}
.eo-cv-ctxmenu-item:hover{ background:var(--card-hover, rgba(var(--text-rgb),.06)); }
.eo-cv-ctxmenu-item.danger{ color:var(--danger-soft, #e08a8a); }
/* The currently-applied frame gets a tick, so the menu doubles as a readout
   of what this particular picture is set to. */
.eo-cv-ctxmenu-item.checked{ font-weight:700; }
.eo-cv-ctxmenu-item.checked::after{ content:"✓"; float:right; color:var(--accent); }
.eo-cv-ctxmenu-label{
  padding:6px 10px 3px; font-size:var(--fs-caption); font-weight:700;
  color:var(--faint); text-transform:uppercase; letter-spacing:.06em;
}
.eo-cv-ctxmenu hr{ border:0; border-top:1px solid var(--line); margin:4px 6px; }

/* ---- connection editor (colour / thickness / arrowheads) ---- */
.eo-cv-linkmenu{ min-width:210px; }
.eo-cv-linkmenu-row{
  display:flex; align-items:center; gap:8px; padding:5px 10px;
  font-size:var(--fs-small); color:var(--text);
}
.eo-cv-linkmenu-row > span{ flex:0 0 52px; color:var(--muted); font-size:var(--fs-caption); }
.eo-cv-linkmenu-row > b{ min-width:16px; text-align:right; font-variant-numeric:tabular-nums; }
.eo-cv-linkmenu-row input[type=range]{ flex:1 1 auto; width:0; accent-color:var(--accent); cursor:pointer; }
.eo-cv-linkmenu-row input[type=color]{
  width:26px; height:22px; padding:0; border:1px solid var(--line-bright);
  border-radius:var(--r-sm); background:none; cursor:pointer;
}
.eo-cv-linkmenu-seg{ display:flex; gap:3px; }
.eo-cv-linkmenu-seg button{
  min-width:30px; padding:3px 6px; cursor:pointer; font-size:13px; line-height:1.3;
  background:var(--card-subtle); color:var(--muted);
  border:1px solid var(--line); border-radius:var(--r-sm);
}
.eo-cv-linkmenu-seg button.active{ background:var(--accent); border-color:var(--accent); color:#fff; }

@media (max-width:800px){
  .eo-cv-toolbar{ flex-direction:column; align-items:stretch; }
  .eo-cv-board-name{ max-width:none; }
  .eo-cv-board-area{ flex-direction:column; }
  .eo-cv-library{ flex:0 0 auto; width:100%; max-height:260px; position:static; }
}

/* ---- Miniature preview (Morning Briefing → Vision Board card) --------------
   Read-only: images only, laid out in percentages of the canvas box so the
   whole tab scales down to whatever width the card gives it. */
/* No max-height: the box's aspect-ratio is computed from the pictures' own
   bounding box (eo-canvas.js → previewViewport), and capping the height of an
   aspect-ratio box squashes every image rectangle inside it — which reads as
   heavy cropping once object-fit:cover runs. Height is controlled by widening
   the viewport instead. */
.eo-cv-preview{
  position:relative; width:100%; overflow:hidden;
  border-radius:var(--r-md); background:var(--card-subtle); border:1px solid var(--line);
}
.eo-cv-preview img{
  position:absolute; object-fit:cover; border-radius:4px;
  box-shadow:0 3px 12px rgba(0,0,0,.3); outline:1px solid rgba(255,255,255,.1);
}
.eo-cv-preview>span{
  position:absolute; left:10px; bottom:10px; z-index:1000; padding:5px 8px;
  border-radius:var(--r-sm); background:rgba(8,8,10,.78); color:#fff;
  font:700 var(--fs-caption)/1 var(--font-mono);
}
.eo-cv-preview-empty{
  min-height:120px; display:grid; place-items:center; color:var(--faint);
  background:var(--card-subtle); border:1px dashed var(--line); border-radius:var(--r-md);
}
.eo-cv-preview-pick{ display:flex; align-items:center; gap:8px; margin-bottom:10px; }
.eo-cv-preview-pick>span{ color:var(--faint); font:600 var(--fs-caption)/1 var(--font-mono); text-transform:uppercase; letter-spacing:.06em; }
.eo-cv-preview-pick select{ width:auto; min-width:180px; max-width:100%; }
