@font-face{font-family:'Material Symbols Rounded';font-style:normal;font-weight:100 700;
  src:url(data:font/truetype;base64,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) format('truetype');
  font-display:block;}
*{margin:0;padding:0;box-sizing:border-box;}
:root{
  /* Redesign 2026-07-09 (Claude Design handoff, StrokeMotion.dc.html) —
     values pulled straight from the mockup's inline styles. Every panel in
     the app reads through these vars (not hardcoded per-element colors),
     so retargeting the palette here reskins the whole UI without touching
     layout/structure. */
  --gutter:#0b0a0d;--bg:#131215;--panel:#201f25;--panel2:#17161a;--panel3:#26242a;
  --border:rgba(255,255,255,.05);--border2:rgba(255,255,255,.12);
  --text:#ECEAE7;--text-dim:rgba(236,234,231,.45);--text-dark:rgba(236,234,231,.3);
  --accent:#3F6BF5;--accent-hover:#7EA0FA;--accent-dim:rgba(63,107,245,.18);
  --key-color:#c8c8d4;--tween-color:rgba(63,107,245,.16);
  --red:#ff5555;--green:#5FA875;--orange:#F0A585;--purple:#B49BE6;
  --tool-size:36px;--fc:30px;
}
/* In-place canvas text editing (2026-08-16, Cyril: "LE TEXT DEVRAIT
   POUVOIR S'EDITER DIRECTEMENT sur le canvas... comme tout les logiciel
   d'édition de text type ai ou figma") — a named face distinct from the
   plain 'Roboto' keyword already used as a generic fallback in the app's
   own UI font stack a few lines down, so the two never collide. Same
   bundled TTFs vector-text-bridge.js already fetches for real glyph
   outlines (fonts/Roboto-Regular.ttf, fonts/Roboto-Bold.ttf) — loading
   them here too lets the #tp-inplace-editor overlay (timeline.js) render
   in the SAME face while the user is typing, so the illusion holds:
   what's on screen during editing looks like the vector glyphs it's about
   to become, not a generic system font standing in for them. */
@font-face{font-family:'Nemo Vector Text';font-weight:400;src:url('../fonts/Roboto-Regular.ttf') format('truetype');}
@font-face{font-family:'Nemo Vector Text';font-weight:700;src:url('../fonts/Roboto-Bold.ttf') format('truetype');}
#tp-inplace-editor{position:fixed;z-index:210;background:transparent;border:none;outline:none;resize:none;
  overflow:hidden;padding:0;margin:0;font-family:'Nemo Vector Text',sans-serif;white-space:pre;}
/* Resize handle for the orange in-place text box (feedback #83, "la box de
   texte orange n'est pas resizable") — resize:none above is deliberate (a
   native textarea resize handle has no way to feed back into d.fixedWidth
   or reflow world-space glyph geometry), so this is the custom stand-in:
   a small square pinned to the box's bottom-right corner, dragged in
   timeline.js's openInPlaceTextEditor. */
#tp-inplace-resize-handle{position:fixed;z-index:211;width:10px;height:10px;margin:-5px 0 0 -5px;
  background:#ffb86c;border:1.5px solid #1a1a1a;border-radius:2px;cursor:nwse-resize;}
html,body{width:100%;height:100%;overflow:hidden;background:var(--gutter);color:var(--text);
  font-family:'Manrope',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;
  /* -webkit-user-select alongside the unprefixed property (2026-07,
     "avec l'outil de sélection quand on essaye de drag un menu ça
     sélectionne plein de texte") — Nemo ships as a Tauri app, rendered by
     WKWebView (WebKit) on macOS; WebKit's drag-selection code path has a
     long-documented history of needing the vendor-prefixed property even
     where the unprefixed one already works for click-based selection, so
     relying on user-select alone left a real gap specifically on that
     platform (not reproducible in a Chromium-based dev/automation
     browser, which already honored the unprefixed property everywhere
     tested). */
  -webkit-user-select:none;user-select:none;font-size:13px;-webkit-font-smoothing:antialiased;}
.material-symbols-rounded{font-family:'Material Symbols Rounded';font-weight:normal;font-style:normal;
  font-size:20px;line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;
  white-space:nowrap;word-wrap:normal;direction:ltr;-webkit-font-feature-settings:'liga';
  -webkit-font-smoothing:antialiased;font-variation-settings:'FILL' 0,'wght' 300,'GRAD' 0,'opsz' 20;}
#app{display:flex;flex-direction:column;height:100vh;box-sizing:border-box;background:var(--gutter);padding:8px;gap:8px;}
/* position:relative — positioning ancestor for the dockable tools panel's
   top/right/bottom overlay modes (tools-panel-dock.js) and their drop-zone
   overlay, both anchored with position:absolute against this box. */
#top-area{flex:1;display:flex;overflow:hidden;min-height:0;gap:8px;position:relative;}
/* App-wide top bar (2026-07 redesign): burger menu + app-mode segmented
   switcher, full width, above everything (tools panel, canvas, right
   panel alike) — distinct from #project-tabs-bar, which is scoped to the
   canvas column only (see #canvas-col below). */
#app-topbar{flex:none;height:34px;display:flex;align-items:center;gap:10px;padding:0 10px;background:var(--panel2);border-radius:8px;}
#app-menu-btn{flex:none;width:26px;height:26px;border-radius:6px;background:transparent;border:none;color:var(--text-dim);cursor:pointer;display:flex;align-items:center;justify-content:center;}
#app-menu-btn:hover{background:var(--panel3);color:var(--text);}
/* Comment tool button, relocated from the left tools panel into the top
   bar (feedback 2026-07) — same .tool-btn/.active styling elsewhere still
   applies (so it still highlights while the Comment tool is selected),
   just sized down to match its new compact neighbors (avatar/help/
   settings) instead of the left panel's larger 34px icons. The shortcut
   badge (.sk, a small "C") only makes sense against the left panel's
   taller buttons — dropped here, the title tooltip already says "(C)". */
#topbar-comment-btn{width:26px;height:26px;flex:none;}
#topbar-comment-btn .sk{display:none;}
#app-mode-switch{display:flex;align-items:center;gap:2px;background:var(--bg);border-radius:7px;padding:2px;}
.app-mode-btn{flex:none;border:none;background:transparent;color:var(--text-dim);font-size:11px;font-weight:500;padding:5px 12px;border-radius:5px;cursor:pointer;}
.app-mode-btn:hover:not(:disabled){color:var(--text);}
.app-mode-btn.active{background:var(--panel3);color:var(--text);}
.app-mode-btn:disabled{color:var(--text-dark);cursor:default;}
/* Freeze badge (2026-08, PR #209 — Rig/StoryBoard/import 3D "in Dev"):
   small amber pill, reused on both the text mode-switch button and the
   icon-only toolbar button (.tool-btn.in-dev-locked gets it via ::after
   since it has no room for inline text). */
.in-dev-badge{display:inline-block;margin-left:5px;padding:1px 5px;border-radius:8px;
  font-size:8px;font-weight:700;letter-spacing:.02em;text-transform:uppercase;
  background:rgba(255,180,60,.18);color:#ffb43c;vertical-align:1px;}
.tool-btn.in-dev-locked{opacity:.45;cursor:default;}
.tool-btn.in-dev-locked::after{content:'dev';position:absolute;bottom:-1px;right:-1px;
  padding:0 3px;border-radius:4px;font-size:6px;font-weight:700;line-height:1.3;
  background:rgba(255,180,60,.85);color:#1a1206;pointer-events:none;}
#app-topbar-spacer{flex:1;min-width:8px;}
/* macOS overlay titlebar (tauri.conf.json's titleBarStyle:"Overlay") — the
   native traffic lights float over our content at macOS's own default
   inset (no trafficLightPosition override — an explicit (12,12) made the
   lights themselves render oversized/off-corner vs. a normal window, so
   left it to Tauri's own default instead of guessing at a replacement).
   This strip is the drag region behind them (data-tauri-drag-region, same
   effect as dragging a normal title bar) plus the update button parked
   right after the 3 lights, continuing their own spacing. Confirmed live
   (real window, real traffic lights) that a 12px dot at 20px spacing read
   as visibly smaller than the lights and a touch low — bumped to 18px
   at ~28px spacing and nudged up to match. Still an estimate refined
   against real screenshots, not derived from a spec — nudge left/top/
   width/height here again if the 4th dot still doesn't sit on the same
   row/rhythm as the other 3. Both stay display:none until
   #mac-chrome-init (updater-bridge.js) confirms macOS+Tauri — a no-op
   everywhere else, including this browser preview. */
#mac-titlebar-strip{display:none;}
body.mac-overlay-titlebar #mac-titlebar-strip{display:block;position:fixed;top:0;left:0;width:100%;height:28px;z-index:500;}
body.mac-overlay-titlebar #app{padding-top:28px;}
#mac-update-btn{position:fixed;top:8px;left:79px;width:15px;height:15px;border-radius:50%;border:none;padding:0;
  display:none;align-items:center;justify-content:center;cursor:pointer;z-index:501;color:#fff;
  background:var(--accent);box-shadow:0 0 0 0 rgba(63,107,245,0);transition:box-shadow .2s;}
#mac-update-btn.state-available,#mac-update-btn.state-installed{display:flex;}
#mac-update-btn.state-available:hover,#mac-update-btn.state-installed:hover{box-shadow:0 0 0 5px rgba(63,107,245,.28);}
#mac-update-btn svg{width:10px;height:10px;pointer-events:none;}
#mac-update-btn.state-downloading{display:flex;cursor:default;}
#mac-update-btn.state-downloading svg{animation:mac-update-spin 1s linear infinite;}
@keyframes mac-update-spin{from{transform:rotate(0deg);}to{transform:rotate(360deg);}}
/* Canvas column: the project tabs bar sits directly above the canvas
   only, not above the tools panel or right panel, so it's wrapped here
   as a flex column sharing #canvas-area's old flex:1 row slot. Zero gap
   + matching radii so the tabs bar reads as flush with the canvas below
   it, no gutter-colored seam between them. */
#canvas-col{flex:1;display:flex;flex-direction:column;min-width:0;min-height:0;gap:0;}
/* v12: flat dot+label pattern (mockup's own "● Composition · StrokeMotion
   ● random_logo.png" header tabs — no boxed/boxed-top-corners browser-tab
   look at all, just plain inline items separated by gaps on one flat
   background), replacing the earlier browser-style rounded-top tab strip. */
#project-tabs-bar{flex:none;height:32px;display:flex;align-items:center;gap:14px;padding:0 14px;background:var(--panel2);border-radius:8px 8px 0 0;}
/* Tabs list hugs its own content (not flex:1 anymore) so "+" sits right
   after the last tab, not stretched to the bar's far edge. #project-tabs-
   settings now lives in the top titlebar strip, not as a sibling of this
   list, so there's no spacer element to push apart here anymore. */
#project-tabs-list{flex:0 1 auto;display:flex;align-items:center;gap:22px;overflow-x:auto;min-width:0;height:100%;}
#project-tabs-settings{flex:none;width:24px;height:24px;border-radius:6px;background:transparent;border:none;color:rgba(236,234,231,.45);cursor:pointer;display:flex;align-items:center;justify-content:center;}
#project-tabs-settings:hover{background:var(--panel3);color:var(--text);}
/* Collaborator avatars: current profile + everyone who's left a feedback
   comment on this project — Figma-style overlapping circle stack, left of
   the settings gear. Click opens #fb-avatars-pop listing the comments. */
#fb-avatars{flex:none;display:flex;align-items:center;cursor:pointer;}
#fb-avatars .fb-av{flex:none;width:22px;height:22px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:600;color:#fff;border:2px solid var(--panel2);margin-left:-8px;}
#fb-avatars .fb-av:first-child{margin-left:0;}
#fb-avatars .fb-av.fb-av-more{background:var(--panel3);color:var(--text-dim);font-size:9px;}
#fb-avatars-pop{display:none;position:fixed;width:280px;max-height:360px;overflow-y:auto;background:var(--panel2);border:1px solid var(--border);border-radius:8px;box-shadow:0 8px 24px rgba(0,0,0,.4);z-index:600;padding:6px;}
#fb-avatars-pop.open{display:block;}
#fb-avatars-pop .fb-pop-item{display:flex;gap:8px;padding:7px 8px;border-radius:6px;font-size:11px;}
#fb-avatars-pop .fb-pop-item:hover{background:var(--panel3);}
#fb-avatars-pop .fb-pop-av{flex:none;width:18px;height:18px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:9px;font-weight:600;color:#fff;margin-top:1px;}
#fb-avatars-pop .fb-pop-body{flex:1;min-width:0;}
#fb-avatars-pop .fb-pop-note{color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
#fb-avatars-pop .fb-pop-meta{color:var(--text-dim);font-size:10px;margin-top:2px;display:flex;gap:6px;align-items:center;}
#fb-avatars-pop .fb-pop-status{font-size:9px;padding:1px 5px;border-radius:3px;background:var(--panel3);}
#fb-avatars-pop .fb-pop-status.resolved{color:#7cd992;}
#fb-avatars-pop .fb-pop-empty{padding:12px 8px;color:var(--text-dim);font-size:11px;text-align:center;}
/* History Panel (2026-07) — same trigger-button + fixed popover pattern as
   #fb-avatars/#fb-avatars-pop just above. Lists state.undoStack (past) then
   the current position then state.redoStack (available redo, dimmed) —
   see history-panel.js. */
#history-btn{flex:none;width:24px;height:24px;border-radius:6px;background:transparent;border:none;color:rgba(236,234,231,.45);cursor:pointer;display:flex;align-items:center;justify-content:center;}
#history-btn:hover{background:var(--panel3);color:var(--accent-hover);}
#history-pop{display:none;position:fixed;width:280px;max-height:420px;overflow-y:auto;background:var(--panel2);border:1px solid var(--border);border-radius:8px;box-shadow:0 8px 24px rgba(0,0,0,.4);z-index:600;padding:6px;}
#history-pop.open{display:block;}
#history-pop .hist-item{display:flex;gap:8px;align-items:center;padding:7px 8px;border-radius:6px;font-size:11px;cursor:pointer;color:var(--text);}
#history-pop .hist-item:hover{background:var(--panel3);}
#history-pop .hist-item.future{opacity:.4;}
#history-pop .hist-item.current{background:var(--panel3);cursor:default;}
#history-pop .hist-item.current:hover{background:var(--panel3);}
#history-pop .hist-dot{flex:none;width:6px;height:6px;border-radius:50%;background:var(--text-dim);}
#history-pop .hist-item.current .hist-dot{background:var(--accent-hover);}
#history-pop .hist-body{flex:1;min-width:0;}
#history-pop .hist-label{color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
#history-pop .hist-meta{color:var(--text-dim);font-size:10px;margin-top:1px;}
#history-pop .hist-empty{padding:12px 8px;color:var(--text-dim);font-size:11px;text-align:center;}
#history-pop .hist-header{display:flex;align-items:center;justify-content:space-between;padding:2px 4px 8px;color:var(--text-dim);font-size:10px;text-transform:uppercase;letter-spacing:.03em;}
#history-pop .hist-clear{cursor:pointer;color:var(--text-dim);}
#history-pop .hist-clear:hover{color:var(--text);}
.project-tab{flex:none;display:flex;align-items:center;gap:9px;height:100%;padding:0;background:transparent;border-radius:0;font-size:12.5px;font-weight:500;color:rgba(236,234,231,.35);cursor:pointer;max-width:180px;user-select:none;}
.project-tab:hover{color:rgba(236,234,231,.7);}
.project-tab.act{background:transparent;color:var(--text);font-weight:600;}
.project-tab .pt-dot{width:9px;height:9px;border-radius:50%;background:#4a4852;flex:none;}
.project-tab.act .pt-dot{background:var(--green);}
.project-tab .pt-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.project-tab .pt-dirty{width:6px;height:6px;border-radius:50%;background:var(--orange);flex:none;display:none;}
.project-tab.dirty .pt-dirty{display:block;}
.project-tab .pt-close{flex:none;width:16px;height:16px;border-radius:4px;display:flex;align-items:center;justify-content:center;font-size:13px;line-height:1;color:rgba(236,234,231,.3);opacity:0;transition:opacity .1s;}
.project-tab:hover .pt-close,.project-tab.act .pt-close{opacity:1;}
.project-tab .pt-close:hover{background:var(--panel3);color:var(--text);}
#project-tab-add{flex:none;width:22px;height:22px;border-radius:6px;background:transparent;border:none;color:rgba(236,234,231,.35);font-size:15px;cursor:pointer;display:flex;align-items:center;justify-content:center;}
#project-tab-add:hover{background:var(--panel3);color:var(--text);}
.pt-rename-input{width:90px;background:var(--panel3);border:1px solid var(--accent);border-radius:3px;color:var(--text);font:inherit;font-size:12.5px;padding:0 3px;outline:none;}

/* TOOLS */
#tools-panel{width:50px;flex-shrink:0;background:var(--panel);border-right:none;
  display:flex;flex-direction:column;align-items:center;padding:10px 0;gap:3px;overflow-y:auto;}
/* Panel resize grips — same idiom as #tl-resize: fully invisible until
   hover, and they occupy exactly the layout gap that was already between
   the panels (width 8px with -8px side margins cancels the flex gap on
   both sides), so nothing about the page's spacing changes. The hover
   indicator is deliberately NOT the whole gap lighting up (too heavy —
   user feedback): a small vertically-centered rounded pill via ::after,
   while the full 8px×full-height div stays the grab/hit area. */
/* Dockable tools panel (2026-07) — default stays exactly the left-column
   layout above. Right dock stays fully IN-FLOW (just reordered to the end
   of #top-area's flex row via `order`) so canvas-col/props-panel naturally
   share the remaining space with zero overlap. Top/bottom can't do the
   same trick (they'd need to span perpendicular to #top-area's own row
   axis, which would mean restructuring canvas-col+props-panel under a
   shared wrapper) — those float as a position:absolute overlay instead,
   compensated by matching padding on canvas-col/props-panel (below) so
   the project-tabs bar and top-of-canvas content never end up hidden
   underneath it (confirmed live: without the padding, #project-tabs-bar
   sat exactly under the floated bar, unclickable). */
.tools-dock-handle{width:100%;height:14px;display:flex;align-items:center;justify-content:center;color:rgba(236,234,231,.3);cursor:grab;font-size:11px;touch-action:none;user-select:none;flex:none;}
.tools-dock-handle:hover{color:rgba(236,234,231,.6);}
.tools-dock-handle:active{cursor:grabbing;}
#tools-panel.tools-dock-top,#tools-panel.tools-dock-bottom{
  position:absolute;z-index:20;box-shadow:0 2px 16px rgba(0,0,0,.45);border-radius:8px;
  top:auto;bottom:auto;left:8px;right:8px;width:auto;height:50px;
  flex-direction:row;align-items:center;padding:0 10px;overflow-x:auto;overflow-y:hidden;
}
#tools-panel.tools-dock-top{top:0;}
#tools-panel.tools-dock-bottom{bottom:0;}
#tools-panel.tools-dock-top .tools-dock-handle,#tools-panel.tools-dock-bottom .tools-dock-handle{width:14px;height:100%;}
#tools-panel.tools-dock-top .tool-sep,#tools-panel.tools-dock-bottom .tool-sep{width:1px;height:24px;margin:0 4px;}
#tools-panel.tools-dock-top .color-wells,#tools-panel.tools-dock-bottom .color-wells{flex-direction:row;margin-top:0;margin-left:auto;padding-bottom:0;}
body.tools-dock-top-active #canvas-col,body.tools-dock-top-active #props-panel{padding-top:58px;box-sizing:border-box;}
body.tools-dock-bottom-active #canvas-col,body.tools-dock-bottom-active #props-panel{padding-bottom:58px;box-sizing:border-box;}
/* Resize handle only makes sense for the default left dock — hidden the
   moment the panel floats elsewhere (canvas-col grows into its place). */
body.tools-docked-away #tools-panel-resize{display:none;}
/* Drop-zone overlay shown only while actively dragging the handle. */
#tools-dock-zones{position:absolute;inset:0;z-index:50;pointer-events:none;}
.tools-dock-zone{position:absolute;background:rgba(63,107,245,.06);border:2px dashed rgba(63,107,245,.25);border-radius:6px;pointer-events:auto;transition:background .1s,border-color .1s;}
.tools-dock-zone.active{background:var(--accent-dim);border-color:var(--accent);}
.tools-dock-zone-left{left:4px;top:4px;bottom:4px;width:64px;}
.tools-dock-zone-right{right:4px;top:4px;bottom:4px;width:64px;}
.tools-dock-zone-top{left:76px;right:76px;top:4px;height:64px;}
.tools-dock-zone-bottom{left:76px;right:76px;bottom:4px;height:64px;}
#tools-panel-resize,#props-panel-resize{width:8px;margin:0 -8px;cursor:ew-resize;background:transparent;flex-shrink:0;z-index:5;position:relative;}
#tools-panel-resize::after,#props-panel-resize::after{content:'';position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:3px;height:44px;border-radius:99px;background:transparent;transition:background .15s;}
#tools-panel-resize:hover::after,#tools-panel-resize.active::after,
#props-panel-resize:hover::after,#props-panel-resize.active::after{background:var(--accent);}
.tool-btn{width:34px;height:34px;border:none;background:transparent;color:rgba(236,234,231,.75);
  border-radius:8px;cursor:pointer;display:flex;align-items:center;justify-content:center;
  position:relative;transition:background .15s,color .15s;}
.tool-btn:hover{background:rgba(255,255,255,.06);color:var(--text);}
.tool-btn.active{background:var(--accent-dim);color:var(--accent-hover);box-shadow:none;}
/* bottom-LEFT, not right (feedback #85, "le lettre de raccourcis doivent
   être en bas à gauche... car elles cachent les submenu") — the submenu
   hint triangle for a stacked shape tool (.tool-stack .stack-front::before,
   just below) sits bottom-right, same corner this used to occupy, so the
   shortcut letter was drawn right on top of it. */
.tool-btn .sk{position:absolute;bottom:0;left:1px;font-size:7px;color:var(--text-dark);pointer-events:none;font-family:monospace;}
.tool-btn.active .sk{color:rgba(255,255,255,.5);}
.tool-sep{width:24px;height:1px;background:var(--border);margin:4px 0;}
/* Shape-tool group (timeline.js, 2026-08) — Illustrator/Rive-style single
   toolbar slot: all 5 shape buttons occupy the SAME 34x34 cell, stacked via
   absolute positioning; only `.stack-front` is visible/clickable, the rest
   sit `visibility:hidden` (not display:none — keeps real geometry so
   tutorial.js's getBoundingClientRect spotlight still lands correctly even
   on a backed button, see index.html's own comment on #shape-tool-stack).
   The tiny corner triangle is the standard hint that long-press reveals more. */
.tool-stack{position:relative;width:34px;height:34px;flex:none;}
.tool-stack .tool-btn{position:absolute;inset:0;visibility:hidden;pointer-events:none;}
.tool-stack .tool-btn.stack-front{visibility:visible;pointer-events:auto;}
.tool-stack .tool-btn.stack-front::before{content:'';position:absolute;bottom:1px;right:1px;
  width:0;height:0;border-style:solid;border-width:0 0 4px 4px;
  border-color:transparent transparent rgba(236,234,231,.4) transparent;pointer-events:none;}
.tool-stack .tool-btn.stack-front.active::before{border-bottom-color:rgba(255,255,255,.55);}
/* Uniformize the shape-tool icons as solid/filled forms (feedback #85,
   "pour les icons de shape uniformisé en formes pleine les icons") —
   Speech bubble and Star are already solid custom SVGs (fill=currentColor),
   but Rectangle/Line/Ellipse use Material Symbols Rounded glyphs, which
   render OUTLINE-style by the app-wide default just above ('FILL' 0) —
   the same 5-tool group mixed two icon styles. Scoped to just this group
   (not the global .material-symbols-rounded rule) so every other Material
   icon in the app keeps its intentional outline look. Two selectors: the
   toolbar stack itself, and the long-press flyout, which clones the SAME
   button markup (openFlyout, timeline.js) into a sibling DOM tree outside
   .tool-stack — a rule scoped to only one of the two would leave the other
   inconsistent.*/
.tool-stack .material-symbols-rounded,.shape-tool-flyout-item .material-symbols-rounded{font-variation-settings:'FILL' 1,'wght' 300,'GRAD' 0,'opsz' 20;}
.shape-tool-flyout{position:fixed;z-index:9999;display:flex;gap:2px;padding:4px;
  background:var(--panel,#2a2a2e);border:1px solid var(--border);border-radius:8px;
  box-shadow:0 4px 16px rgba(0,0,0,.4);}
.shape-tool-flyout-item{width:34px;height:34px;border:none;background:transparent;
  color:rgba(236,234,231,.75);border-radius:6px;cursor:pointer;display:flex;
  align-items:center;justify-content:center;position:relative;}
.shape-tool-flyout-item:hover{background:rgba(255,255,255,.08);color:var(--text);}
.shape-tool-flyout-item.active{background:var(--accent-dim);color:var(--accent-hover);}
/* v9: overlapping diagonal swatches (mockup pattern) instead of a stacked
   S/F pair with text labels — stroke top-left, fill bottom-right, fill
   drawn after (higher z-index) so it visually sits "in front" like the
   mockup's own overlap. */
.color-wells{margin-top:auto;padding-bottom:4px;display:flex;flex-direction:column;align-items:center;gap:12px;}
/* Mockup layout: one slot per swatch, eye badge overlapping its bottom-right
   corner (round dark chip, above the swatch), stacked vertically. */
.cw-slot{position:relative;width:30px;height:30px;flex:none;}
.color-well{position:absolute;inset:0;width:30px;height:30px;border-radius:9px;border:2px solid var(--border2);cursor:pointer;overflow:hidden;}
.color-well input{position:absolute;inset:0;opacity:0;cursor:pointer;width:100%;height:100%;}
.cw-eye{position:absolute;right:-8px;bottom:-8px;width:19px;height:19px;border-radius:50%;background:#17171d;border:2px solid var(--panel3);display:flex;align-items:center;justify-content:center;z-index:3;cursor:pointer;color:var(--text-dim);}
.cw-eye svg{width:11px;height:11px;display:block;}
.cw-eye:hover{color:var(--text);}
.cw-eye.off{color:var(--text-dark);}
/* Stroke shows as a colored RING, not a solid square — reads as "outline"
   at a glance, distinguishing it from the solid-filled Fill swatch right
   next to it. The element's own background is still set to the actual
   stroke color by every existing JS call site (setStrokeColor, eyedropper,
   vector-brush endpoint pickup, etc. — all untouched), this just masks the
   center with an inset panel-colored square so only a border-width ring of
   that color remains visible. */
#stroke-well{background:#000;z-index:1;}
#stroke-well::after{content:'';position:absolute;inset:5px;border-radius:5px;background:var(--panel3);pointer-events:none;}
#fill-well{background:#ff0000;z-index:1;}
/* "No fill" state: checkerboard (so it never gets mistaken for a flat color,
   including the swatch's own inline background from the last-picked color
   underneath) plus a clean corner-to-corner diagonal strike — the previous
   version rotated a small square BORDER, which rendered as a barely-visible
   diamond rather than reading as "disabled" at a glance. */
#fill-well.none,.pr .cw-mini.none{
  background-image:linear-gradient(45deg,#3a3a48 25%,transparent 25%),linear-gradient(-45deg,#3a3a48 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#3a3a48 75%),linear-gradient(-45deg,transparent 75%,#3a3a48 75%);
  background-size:8px 8px;background-position:0 0,0 4px,4px -4px,-4px 0;background-color:#232330;
}
#fill-well.none::after,.pr .cw-mini.none::after{content:'';position:absolute;inset:0;
  background:linear-gradient(to top right,transparent calc(50% - 1px),var(--red) calc(50% - 1px),var(--red) calc(50% + 1px),transparent calc(50% + 1px));}

/* Quick fill/stroke enable/disable toggle in the panel header — same
   checkerboard+red-slash "off" convention as .cw-mini.none above, just
   shrunk into a header button so toggling doesn't require opening the
   color popover and hunting for its "None" option. */
.phdr-toggle{order:2;margin-left:auto;width:15px;height:15px;border-radius:3px;border:1px solid rgba(255,255,255,.18);background:rgba(236,234,231,.55);cursor:pointer;padding:0;position:relative;flex:none;}
.phdr-toggle:hover{border-color:rgba(255,255,255,.35);}
.phdr-toggle.off{
  background-image:linear-gradient(45deg,#3a3a48 25%,transparent 25%),linear-gradient(-45deg,#3a3a48 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#3a3a48 75%),linear-gradient(-45deg,transparent 75%,#3a3a48 75%);
  background-size:6px 6px;background-position:0 0,0 3px,3px -3px,-3px 0;background-color:#232330;
}
.phdr-toggle.off::after{content:'';position:absolute;inset:0;
  background:linear-gradient(to top right,transparent calc(50% - 1px),var(--red) calc(50% - 1px),var(--red) calc(50% + 1px),transparent calc(50% + 1px));}

/* CANVAS */
/* v3: the mockup's center panel (canvas viewport included) shares the same
   --panel tone as the left toolbar and right props panel — no separate
   darker box around the working area, just one continuous panel surface
   with the drawing surface itself floating on top. */
/* min-width:0 — a flex item's default min-width is its content's intrinsic
   width, and the drawing canvas's pixel size is set by JS: without this,
   growing a side panel can't shrink the canvas area, so the props panel
   gets pushed straight off the window edge instead (reported layout bug). */
#canvas-area{flex:1;min-width:0;min-height:0;position:relative;overflow:hidden;background:var(--panel);}
#drawing-canvas{width:100%;height:100%;cursor:crosshair;}
#canvas-info{position:absolute;top:16px;left:20px;pointer-events:none;font-size:11.5px;color:rgba(236,234,231,.38);font-weight:500;}
/* Rulers + guides (rulers-bridge.js) — RULER_SIZE (18px) must match the
   JS constant of the same name, both places comment each other. */
#ruler-h,#ruler-v,#ruler-corner{position:absolute;z-index:40;background:var(--panel2);}
#ruler-corner{top:0;left:0;width:18px;height:18px;z-index:41;border-right:1px solid var(--border);border-bottom:1px solid var(--border);}
#ruler-h{top:0;left:18px;right:0;height:18px;cursor:s-resize;}
#ruler-v{top:18px;left:0;bottom:0;width:18px;cursor:e-resize;}
body.rulers-off #ruler-h,body.rulers-off #ruler-v,body.rulers-off #ruler-corner{display:none;}
.guide-line{position:absolute;z-index:39;pointer-events:none;}
.guide-line.h{left:0;right:0;height:1px;border-top:1px dashed var(--accent);}
.guide-line.v{top:0;bottom:0;width:1px;border-left:1px dashed var(--accent);}
.guide-hit{position:absolute;z-index:42;background:transparent;}
.guide-hit.h{left:18px;right:0;height:7px;cursor:ns-resize;}
.guide-hit.v{top:18px;bottom:0;width:7px;cursor:ew-resize;}
#canvas-info .fnum{font-size:28px;font-weight:700;letter-spacing:-.5px;color:var(--text);}
.canvas-info-row{display:flex;align-items:center;gap:6px;}
.canvas-info-row .badge{margin-left:0;}
.badge{display:inline-block;padding:3px 8px;border-radius:5px;font-size:10px;font-weight:600;letter-spacing:.6px;margin-left:6px;vertical-align:middle;}
.badge.key{background:rgba(255,255,255,.08);color:rgba(236,234,231,.65);}
.badge.tw{background:var(--green);color:#000;}
#match-info{position:absolute;top:16px;right:20px;font-size:10px;color:var(--green);pointer-events:none;text-align:right;max-width:200px;}
/* #zoom-ind removed (v13) — the scrubbable zoom pill below is the sole
   zoom readout now, moved to bottom-right in its place. */
/* v10: bottom-left zoom%/Fit pills (mockup) */
#canvas-zoom-pills{position:absolute;bottom:14px;right:16px;display:flex;gap:8px;align-items:center;}
.zoom-pill{padding:6px 11px;background:var(--panel2);border-radius:7px;display:flex;gap:4px;align-items:center;font-size:11px;font-weight:500;color:rgba(236,234,231,.5);cursor:pointer;user-select:none;}
.zoom-pill:hover{background:var(--panel3);color:var(--text);}
.zoom-pill .zoom-caret{opacity:.4;font-size:9px;}
#zoom-scrub{width:28px;background:transparent;border:none;color:rgba(236,234,231,.5);font:inherit;padding:0;text-align:right;cursor:ew-resize;-moz-appearance:textfield;}
#zoom-scrub::-webkit-inner-spin-button{-webkit-appearance:none;}
/* Labs floating panel (2026-07) — draggable-anywhere strip of icon
   toggles, contextual to the active tool (labs-float-panel.js), plus an
   optional params row below. z-index above the canvas but below any modal
   (settings-modal etc sit at a higher stack, unaffected). touch-action:none
   on the handle so drag isn't fought by the browser's own touch-scroll
   gesture recognition. position:fixed, not absolute — this panel is a
   SIBLING of #canvas-area (see its HTML comment for why), so it has no
   positioning ancestor of its own; labs-float-panel.js computes left/top
   in viewport coordinates from #canvas-area's live bounding rect and
   keeps it clamped there. Background is --gutter (near-black, the
   darkest token already in the palette) rather than --panel2 — live
   feedback: "le fond de ce panel doit être noir pour plus de visibilité". */
#labs-float-panel{position:fixed;z-index:6;display:flex;flex-direction:column;padding:4px;background:var(--gutter);border-radius:9px;box-shadow:0 4px 14px rgba(0,0,0,.45);}
#labs-float-row1{display:flex;align-items:center;gap:2px;}
#labs-float-handle{width:16px;height:26px;display:flex;align-items:center;justify-content:center;color:rgba(236,234,231,.35);cursor:grab;font-size:13px;touch-action:none;user-select:none;}
#labs-float-handle:active{cursor:grabbing;}
#labs-float-icons{display:flex;align-items:center;gap:2px;}
.labs-float-btn{width:26px;height:26px;border:none;border-radius:6px;background:transparent;color:rgba(236,234,231,.7);display:flex;align-items:center;justify-content:center;cursor:pointer;transition:background .12s,color .12s;}
.labs-float-btn:hover{background:rgba(255,255,255,.09);color:var(--text);}
.labs-float-btn.active{background:var(--accent-dim);color:var(--accent-hover);}
.labs-float-divider{width:1px;height:18px;background:var(--border2);margin:0 3px;flex:none;}
/* Tween reassign badge (2026-07) — pill positioned in JS (updateReassignBadge,
   tweens.js), right at the selection's bounding-box corner. green = has a
   tween, click to start reassigning; yellow = reassignment pending, click
   confirms the current selection as the new target. */
#tween-reassign-badge{position:fixed;z-index:7;padding:2px 7px;border-radius:10px;font:600 10px/1.6 var(--font-mono,monospace);color:#111;cursor:pointer;box-shadow:0 2px 8px rgba(0,0,0,.4);white-space:nowrap;transition:transform .08s;}
#tween-reassign-badge:hover{transform:scale(1.08);}
#tween-reassign-badge.green{background:#4ade80;}
#tween-reassign-badge.yellow{background:#facc15;}
/* Params row — [-] value [+] steppers, one pill per adjustable param,
   styled after the reference floating panel (dark rounded pill, minus/
   value/plus in one flat strip). */
#labs-float-params{display:flex;flex-direction:column;align-items:stretch;gap:4px;padding:5px 3px 2px 3px;margin-top:2px;border-top:1px solid rgba(255,255,255,.08);max-height:220px;overflow-y:auto;}
.labs-float-stepper{display:flex;align-items:center;background:var(--panel3);border-radius:7px;overflow:hidden;min-height:24px;}
/* Vertical rule inside a .pr row — separates two groups of controls that
   share one line (BG swatch vs the view/overlay toggles in the Document
   section). Sized off the row's own content height rather than a fixed px
   so it stays visually centred if the row's controls change height. */
.pr .pr-vsep{width:1px;align-self:stretch;margin:2px 4px;background:rgba(236,234,231,.14);flex:none;}
.labs-float-stepper .lfs-tool-icon{width:22px;display:flex;align-items:center;justify-content:center;color:rgba(236,234,231,.32);flex:none;}
.labs-float-stepper .lfs-tool-icon svg{width:13px;height:13px;}
.labs-float-stepper .lfs-label{font-size:9px;color:var(--text-dim);padding:0 6px 0 8px;white-space:nowrap;}
.labs-float-stepper .lfs-btn{width:20px;height:22px;border:none;background:transparent;color:rgba(236,234,231,.75);font-size:13px;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;}
.labs-float-stepper .lfs-btn:hover{background:rgba(255,255,255,.09);color:var(--text);}
.labs-float-stepper .lfs-val{width:42px;min-width:42px;text-align:center;font-size:10.5px;font-weight:600;color:var(--text);padding:2px;background:transparent;border:0;outline:0;cursor:ew-resize;-moz-appearance:textfield;}
.labs-float-stepper .lfs-val::-webkit-inner-spin-button{-webkit-appearance:none;}
/* Wide toggle/action pills (Extend/Lock/Reset, moved here from the removed
   right-panel Perspective/Symmetry sections) — same stepper pill shell,
   just one full-width button instead of −/value/+. .on marks a toggle
   (Extend/Lock) as currently active; a plain action (Reset) never gets it. */
.labs-float-stepper .lfs-btn.wide{width:auto;padding:0 9px;font-size:10px;font-weight:600;color:var(--text-dim);}
.labs-float-stepper .lfs-btn.wide.on{background:var(--accent-dim);color:var(--accent-hover);}
#vector-sculpt-cursor{position:fixed;z-index:12;display:none;pointer-events:none;border:1.5px solid rgba(255,255,255,.92);border-radius:50%;box-shadow:0 0 0 1px rgba(0,0,0,.65),inset 0 0 0 1px rgba(0,0,0,.25);}
#vector-sculpt-cursor.resizing{border-color:var(--accent-hover);background:rgba(74,158,255,.08);}
#zoom-scrub:focus{color:var(--text);outline:none;}
#zoom-scrub.scrubbing{color:var(--accent-hover);}

/* PROPS */
/* #props-panel-resize styled with #tools-panel-resize in the TOOLS section */
/* Cards/background inverted (2026-07-17, explicit request) — swapped
   which var each side uses rather than editing --panel/--panel2
   themselves: those two custom properties are shared by ~10-18 OTHER
   selectors app-wide (topbar, tools-panel, canvas-area, timeline,
   layer rows, modals, StoryBoard…), so redefining them would have
   reskinned the whole app instead of just this panel. Scoped to
   #props-panel only: the panel itself now sits on the (darker) card
   tone, each accordion card now sits on the (lighter) panel tone —
   cards read as raised/inset relative to their surroundings either
   way, just the two roles trade places. `.psec` has no other DOM users
   (grepped: every `.psec` in index.html lives inside #props-panel), so
   editing its base rule directly is exactly as scoped as an explicit
   `#props-panel .psec` prefix would be, without the extra specificity
   fight against the unprefixed rule below.  */
/* No width transition (feedback #30, 2026-08-21: "quand on collapse ou
   expand le panel droit, le canvas scintille pendant l'animation") — every
   intermediate frame of an animated width change fires app.js's
   #canvas-area ResizeObserver, which fires engine-bridge.js's own
   ResizeObserver on #drawing-canvas, which eagerly calls engine.resize()
   and forces a full scene rebuild (lastSceneJson='') — dozens of times
   over a 150ms transition, each one a real WebGPU resize+redraw. No
   existing panel transition elsewhere in the app animates width for the
   same reason; collapsing/expanding here snaps instantly instead. */
#props-panel{width:280px;flex-shrink:0;background:var(--panel2);border-left:none;overflow-y:auto;padding:0;}
/* Collapse-to-rail (2026-08) — see index.html's own comment on
   #props-panel-collapse-btn for why this is a label rail, not fixed icons. */
#props-panel-collapse-btn{flex:none;width:22px;height:22px;margin-right:6px;border:none;background:transparent;
  color:var(--text-dim);cursor:pointer;border-radius:5px;display:flex;align-items:center;justify-content:center;}
#props-panel-collapse-btn:hover{background:rgba(255,255,255,.06);color:var(--text);}
#props-panel-collapse-btn svg{transition:transform .15s;}
/* min-width:0 is load-bearing, not decorative — a flex item's default
   min-width:auto floors its size at its CONTENT's min-content width
   whenever overflow-x is visible (only overflow-y:auto is set above), so
   without this the panel refused to shrink below whatever width a user had
   last dragged it to (real bug found live: collapsed to visually 343px
   instead of 36px after a resize+collapse, only ever caught because panel
   widths started persisting across reloads in this same change — previously
   every reload reset to the 280px default, which happened to already be
   narrow enough that the clamped floor was never visibly wrong). */
#props-panel.collapsed{width:36px;min-width:0;}
#props-panel.collapsed #props-context-hdr{display:none;}
#props-panel.collapsed #props-panel-collapse-btn{margin:0 auto;}
#props-panel.collapsed #props-panel-collapse-btn svg{transform:rotate(180deg);}
#props-panel.collapsed .psec{display:none!important;}
#props-panel.collapsed #sel-props-sec{display:none!important;}
#props-panel-rail{display:none;flex-direction:column;}
#props-panel.collapsed #props-panel-rail{display:flex;}
.rail-item{width:100%;padding:10px 0;border:none;background:transparent;cursor:pointer;
  color:var(--text-dim);border-bottom:1px solid var(--border);
  writing-mode:vertical-rl;text-orientation:mixed;font-size:9px;font-weight:600;
  letter-spacing:.03em;text-transform:uppercase;white-space:nowrap;}
.rail-item:hover{background:rgba(255,255,255,.06);color:var(--text);}
/* v3 (2026-07-09): each accordion section is its own rounded card
   (mockup wraps every header+body pair in background:#17161a;radius:8px,
   with a 5px gap between cards) rather than a flat divided list. */
.psec{border:none;border-radius:8px;background:var(--panel);border-bottom:none;margin:0 10px 5px;overflow:hidden;}
.psec:first-of-type{margin-top:5px;}
.psec.drag-sec{opacity:.75;}
.psec.drag-over-sec{border-color:var(--accent);}
#panel-drop-indicator{position:fixed;display:none;height:3px;background:var(--accent);border-radius:2px;z-index:320;pointer-events:none;transform:translateY(-1px);box-shadow:0 0 0 1px rgba(74,158,255,.28),0 0 8px rgba(74,158,255,.8);}
.psec.floating{position:fixed;width:280px;z-index:150;margin:0;box-shadow:0 14px 44px rgba(0,0,0,.6);background:var(--panel);border-radius:8px;border-bottom:none;}
.psec.floating .phdr{cursor:grab;background:var(--panel3);}
/* 5px, was 10px (2026-07-27: "la hauteur des onglets peut aussi être
   réduite") — 40px per header down to 30px, and with eleven of them stacked
   in the panel that is ~110px of scrolling saved before any content shows.
   Not halved outright: the row is still the section's click target, and 30px
   is the floor where it stays comfortable to hit. */
.phdr{display:flex;align-items:center;padding:5px 14px;background:transparent;cursor:pointer;font-size:12.5px;font-weight:600;color:rgba(236,234,231,.85);gap:6px;user-select:none;}
.phdr:active{cursor:grabbing;}
.phdr .ar{font-size:14px;color:rgba(236,234,231,.3);transition:none;order:2;margin-left:auto;}
.phdr.closed .ar{transform:none;}
.pbdy{padding:2px 14px 12px;display:flex;flex-direction:column;gap:8px;}
.pbdy.hid{display:none;}
.pr{display:flex;align-items:center;gap:6px;}
/* FIXED label column, not a minimum (2026-07-27: "dans rive sur la capture
   les value sont quand même bien aligné, nous c'est un peu le bazard… ça ne
   respecte pas bien les règles de mise en page"). min-width:50px meant every
   label longer than 50px pushed its OWN value field right and no further, so
   the value column started at a different x on almost every row — measured
   five distinct positions in one panel (1030/1051/1052/1060/1061/1064).
   One width for all of them puts every field on the same grid line, which is
   what the Rive reference does.
   Labels that outrun the column ellipsize rather than shove the field: at
   68px, English and French all fit (longest: "Dash Offset", 63px), Spanish
   and Japanese don't (104px and 103px for that same row), and widening the
   column to fit them would cost a third of a 220px panel on every row. The
   full text stays reachable — i18n.js titles each label after its sweep. */
.pl{font-size:11.5px;color:rgba(236,234,231,.45);width:68px;flex:none;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
/* Panel fields (.pi/.psel/.pbtn) were sized for a ~13px value inside a
   ~31px-tall box — reduced from 8px/10px vertical/horizontal padding to
   5px/8px so the whole right panel column of sections takes noticeably
   less vertical space without shrinking the text itself. */
.pi{flex:1;background:var(--panel3);border:none;color:var(--text);border-radius:6px;padding:5px 8px;font-size:12.5px;font-weight:600;outline:none;box-shadow:inset 0 0 0 1px transparent;transition:box-shadow .15s;}
.pi:focus{box-shadow:inset 0 0 0 1px var(--accent);}
.pi[type="range"]{padding:0;border:none;background:transparent;accent-color:var(--accent);}
/* Unified checkbox design (feedback 2026-07: "tous les checkbox qui
   apparraissent dans l'app devrait avoir cette apparence") — a single
   global rule on the type selector, not a class, so every existing
   `<input type="checkbox">` across the app (right panel toggles, brush
   menu, Labs float panel, dynamically-built rows) picks it up automatically
   with zero HTML changes. Custom-drawn (appearance:none) rather than
   relying on accent-color alone — native checkbox rendering still varies
   subtly across browsers/OSes even with accent-color set, which read as
   "inconsistent" across the app's own controls. */
input[type="checkbox"]{-webkit-appearance:none;appearance:none;width:14px;height:14px;flex:none;margin:0;border:1px solid var(--border2);border-radius:3px;background:var(--panel3);cursor:pointer;position:relative;transition:background .12s,border-color .12s;}
input[type="checkbox"]:hover{border-color:rgba(255,255,255,.3);}
input[type="checkbox"]:focus-visible{box-shadow:0 0 0 2px var(--accent-dim);}
input[type="checkbox"]:checked{background:var(--accent);border-color:var(--accent);}
input[type="checkbox"]:checked::after{content:'';position:absolute;left:4px;top:1px;width:4px;height:8px;border:solid #fff;border-width:0 2px 2px 0;transform:rotate(45deg);}
input[type="checkbox"]:disabled{opacity:.4;cursor:not-allowed;}
/* min-width:0 — with flex:1 these grow, but the default min-width:auto kept
   them from ever shrinking below width+padding (~70px); in rows that also
   carry a fixed-width widget (Position/Size/Rotate + the 9-dot anchor grid)
   the row overflowed the 280px panel and the inputs slid UNDER the grid. */
.pi[type="number"]{width:50px;min-width:0;text-align:center;-moz-appearance:textfield;}
.pi[type="number"]::-webkit-inner-spin-button{-webkit-appearance:none;}
/* Rive-style scrubbable numeric field: no spinner, drag left/right to
   change the value, click to place a caret and type. A small double-arrow
   cursor and a subtle hover tint are the only hint it's draggable — same
   affordance Rive/After Effects use instead of a slider. */
.pi.scrub{cursor:ew-resize;user-select:none;}
.pi.scrub:hover{box-shadow:inset 0 0 0 1px var(--border2);}
.pi.scrub.scrubbing{box-shadow:inset 0 0 0 1px var(--accent);cursor:ew-resize;}
.pi.scrub.editing{cursor:text;user-select:text;}
/* appearance:none + a hand-drawn chevron, INSET from the edge with real
   padding-right (not the native OS arrow, which rendered flush against —
   and visually past — the box's rounded right edge). background-position
   is measured from the padding box, so "right 8px" reliably keeps the
   chevron clear of the border-radius regardless of box width. */
.psel{background-color:var(--panel3);border:none;color:var(--text);border-radius:6px;padding:5px 24px 5px 8px;font-size:12px;outline:none;flex:1;appearance:none;-webkit-appearance:none;-moz-appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6' fill='none'%3E%3Cpath d='M1 1l4 4 4-4' stroke='rgba(236,234,231,.45)' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 8px center;}
/* Blend-mode custom dropdown list (hover = live canvas preview, see
   initBlendDropdown in timeline.js) */
#blend-pop,#matte-pop{display:none;position:fixed;z-index:300;width:180px;max-height:340px;overflow-y:auto;background:var(--panel2);border:1px solid var(--border);border-radius:8px;box-shadow:0 8px 24px rgba(0,0,0,.4);padding:4px;}
#blend-pop .blend-opt,#matte-pop .blend-opt{padding:6px 10px;border-radius:5px;font-size:12px;color:var(--text);cursor:pointer;}
#blend-pop .blend-opt:hover,#matte-pop .blend-opt:hover{background:var(--accent-dim);color:var(--accent-hover);}
#blend-pop .blend-opt.sel,#matte-pop .blend-opt.sel{background:var(--panel3);font-weight:600;}
.pbtn{background:var(--panel3);border:none;color:rgba(236,234,231,.75);border-radius:6px;padding:6px 8px;font-size:12px;font-weight:600;cursor:pointer;transition:background .15s,color .15s;}
/* Icon-only .pbtn variant (2026-07) — square instead of text-padded, icon
   centered; the title tooltip carries the label, same as every .tool-btn
   in the left toolbar. */
.icon-only-btn{width:30px;height:30px;padding:0;display:flex;align-items:center;justify-content:center;flex:none;}
.icon-only-btn svg{display:block;}
/* Toggle state for icon-only buttons used as on/off switches (2026-07 —
   Clip to canvas/Safety zones converted from checkboxes) — same "tint the
   icon, don't fully invert" convention as .tb.active elsewhere, so a
   toggled icon button reads as "on" without looking like an accent CTA. */
.icon-only-btn.active{color:var(--accent-hover);background:var(--accent-dim);}
.pbtn:hover{background:#2c2a31;color:var(--text);}
.pbtn.ac{background:var(--accent);border-color:var(--accent);color:#fff;}
.pbtn.ac:hover{background:#5254d9;}
.fb-tag.active{background:var(--accent);color:#fff;}
.icon-grp{display:flex;flex:1;background:var(--panel3);border:none;border-radius:7px;overflow:hidden;}
/* Value boxes/dropdowns/buttons inside the right panel darkened to match
   (2026-07-17, follow-up to the card/background swap above — "dans les
   box de value ou de bouton tu n'as pas changé les couleurs par le
   foncé"): .pi/.psel/.pbtn/.icon-grp all default to --panel3, the
   LIGHTEST of the three panel tones, everywhere else in the app too
   (toast, project tabs, media rows, settings…) — same reasoning as the
   #props-panel/.psec swap, redefining --panel3 itself would reskin
   those too. --bg (#131215) sits below both panel tones now in use
   here (--panel2 page bg, --panel card bg), giving a genuinely recessed
   "inset field" look against the now-lighter cards instead of nearly
   blending into them. Hover/accent/focus states untouched — #2c2a31,
   var(--accent) etc. still read as "lighter than resting" against the
   new darker base, same relative contrast the original design intended. */
#props-panel .pi{background:var(--bg);}
#props-panel .pi[type="range"]{background:transparent;}
#props-panel .psel{background-color:var(--bg);}
#props-panel .pbtn{background:var(--bg);}
#props-panel .pbtn.ac{background:var(--accent);}
#props-panel .icon-grp{background:var(--bg);}
.icon-btn{flex:1;background:transparent;border:none;border-right:1px solid var(--border);color:var(--text-dim);cursor:pointer;padding:4px 0;display:flex;align-items:center;justify-content:center;}
.icon-btn:last-child{border-right:none;}
.icon-btn svg{width:18px;height:14px;display:block;}
.icon-btn:hover{color:var(--text);background:var(--panel3);}
.icon-btn.sel{color:#fff;background:var(--accent);}
.pr .cw-mini{width:24px;height:20px;border:1px solid var(--border2);border-radius:5px;cursor:pointer;position:relative;overflow:hidden;flex-shrink:0;}
.pr .cw-mini input{position:absolute;inset:0;opacity:0;cursor:pointer;width:100%;height:100%;}
/* Figma-style color row (Fill/Stroke, 2026-07) — swatch + editable hex +
   opacity% + eye toggle, one line. */
.color-row{gap:6px;}
.color-hex-input{flex:1;min-width:0;text-transform:uppercase;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;letter-spacing:.02em;}
.color-opacity-input{flex:0 0 40px;width:40px;text-align:right;padding-right:4px;}
.color-pct{font-size:10px;color:var(--text-dim);flex:none;margin-left:-3px;}
.color-eye-toggle{flex:none;cursor:pointer;color:rgba(236,234,231,.7);width:20px;height:20px;display:flex;align-items:center;justify-content:center;border-radius:5px;}
.color-eye-toggle:hover{background:rgba(255,255,255,.08);color:var(--text);}
.color-eye-toggle.off{color:var(--text-dark);}
.color-eye-toggle svg{width:15px;height:15px;display:block;}
/* Selected Colors panel (2026-07) — crosshair "select shapes with this
   color" button, same sizing/hover language as .color-eye-toggle. */
.color-select-btn{flex:none;cursor:pointer;color:rgba(236,234,231,.5);width:20px;height:20px;display:flex;align-items:center;justify-content:center;border-radius:5px;}
.color-select-btn:hover{background:rgba(255,255,255,.08);color:var(--text);}
.color-select-btn svg{display:block;}
/* Effects stack (2026-07 rewrite, feedback: "voir les effet appliqué au
   calque... et voir les paramètre de ces effets un peu comme ici ci on
   clic sur l'effet") — a click-to-expand effect list matching the shared
   reference mockup's own "Risograph"-style panel, built by effects-
   panel.js from ld.effects. */
.fx-row{display:flex;align-items:center;gap:6px;padding:5px 2px;border-radius:5px;cursor:pointer;}
.fx-row:hover{background:rgba(255,255,255,.04);}
.fx-row.expanded{background:rgba(255,255,255,.06);}
.fx-row-chevron{flex:none;width:12px;height:16px;display:flex;align-items:center;justify-content:center;color:rgba(236,234,231,.4);cursor:pointer;transition:transform .12s ease;}
.fx-row-chevron:hover{color:var(--text);}
.fx-row-chevron svg{display:block;}
.fx-row.expanded .fx-row-chevron{transform:rotate(90deg);}
.fx-row-eye{flex:none;width:16px;height:16px;display:flex;align-items:center;justify-content:center;color:rgba(236,234,231,.5);cursor:pointer;}
.fx-row-eye:hover{color:var(--text);}
.fx-row-eye svg{display:block;}
.fx-row.disabled .fx-row-name{color:var(--text-dim);text-decoration:line-through;opacity:.6;}
.fx-row-name{flex:1;font-size:11.5px;color:var(--text);}
.fx-row-del{flex:none;width:16px;height:16px;display:flex;align-items:center;justify-content:center;color:rgba(236,234,231,.35);border-radius:4px;}
.fx-row-del:hover{background:rgba(255,80,80,.15);color:#ff8080;}
.fx-row-params{padding:2px 2px 8px 22px;display:flex;flex-direction:column;gap:4px;}
.fx-row-param{display:flex;align-items:center;gap:6px;}
.fx-row-param .pl{width:70px;flex:none;}
/* Add Effect flyout (2026-07, feedback: "on a pas de préviz vignette et
   de sous menu. Pense bien l'architecture ui qui marcherait le mieux") —
   a two-level category → preview-tile submenu, position:fixed + appended
   to <body> (built by effects-panel.js's openAddMenu/openSubmenu) so it
   escapes the right panel's own overflow/stacking context, same pattern
   as showContextMenu's .ctx-menu elsewhere in this app. */
.fx-addmenu,.fx-submenu{position:fixed;z-index:300;background:var(--panel2);border:1px solid var(--border2);border-radius:8px;box-shadow:0 8px 28px rgba(0,0,0,.45);padding:4px;min-width:150px;}
.fx-addmenu{min-width:230px;max-height:70vh;overflow-y:auto;}
.fx-addmenu-search{display:block;width:100%;height:28px;margin:0 0 4px;padding:0 9px;border:1px solid var(--border2);border-radius:6px;background:var(--bg);color:var(--text);font:inherit;font-size:11.5px;outline:none;box-sizing:border-box;}
.fx-addmenu-search:focus{border-color:var(--accent);box-shadow:0 0 0 2px var(--accent-dim);}
.fx-addmenu-search::placeholder{color:var(--text-dim);}
.fx-addmenu-results{display:flex;flex-direction:column;min-width:280px;}
.fx-search-result>span{display:flex;min-width:0;flex-direction:column;line-height:1.2;}
.fx-search-result>span>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.fx-search-result small{color:var(--text-dim);font-size:9px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.fx-search-empty{padding:10px 8px;color:var(--text-dim);font-size:11px;text-align:center;}
.fx-addmenu-cat{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:6px 8px;border-radius:5px;cursor:pointer;font-size:11.5px;color:var(--text);}
.fx-addmenu-cat:hover{background:rgba(255,255,255,.06);}
.fx-addmenu-arrow{color:var(--text-dim);font-size:12px;}
.fx-submenu{max-height:70vh;overflow-y:auto;}
.fx-submenu-item{display:flex;align-items:center;gap:8px;padding:5px 8px;border-radius:5px;cursor:pointer;font-size:11.5px;color:var(--text);white-space:nowrap;}
.fx-submenu-item:hover{background:rgba(255,255,255,.06);}
/* Preview thumbnails — small CSS-filter/gradient approximations of each
   WGSL effect (not a live GPU render — cheap, always in sync, good enough
   as a visual identifier at menu size). Same base swatch + per-type trick
   as the effect-library PR's original tile grid. */
.fx-prev{flex:none;width:26px;height:19px;border-radius:3px;overflow:hidden;position:relative;background:linear-gradient(135deg,#ff6b57 0%,#f4c542 45%,#5b8dfc 100%);}
.fx-prev-generic{background:var(--panel3);display:flex;align-items:center;justify-content:center;}
.fx-prev-generic::after{content:'{ }';font-size:8px;color:var(--text-dim);}
.fx-prev-blur{filter:blur(1.4px);}
.fx-prev-colorAdjust{filter:contrast(1.35) brightness(1.1);}
.fx-prev-vignette{box-shadow:inset 0 0 7px 3px rgba(0,0,0,.75);}
.fx-prev-glow{filter:saturate(1.6) brightness(1.15) blur(.3px);box-shadow:0 0 4px 1px rgba(255,220,150,.6) inset;}
.fx-prev-sepia{filter:sepia(1) saturate(1.4);}
.fx-prev-invert{filter:invert(1);}
.fx-prev-grayscale{filter:grayscale(1);}
.fx-prev-posterize{filter:contrast(1.6) saturate(1.8) brightness(1.05);}
.fx-prev-pixelate{background-size:400% 400%;image-rendering:pixelated;filter:contrast(1.1);}
.fx-prev-chromaticAberration{background:linear-gradient(135deg,#ff3b3b 0%,#f4c542 45%,#3ba0ff 100%);}
.fx-prev-chromaticAberration::after{content:'';position:absolute;inset:0;background:linear-gradient(135deg,rgba(255,0,60,.5),transparent 55%,rgba(0,180,255,.5));mix-blend-mode:screen;transform:translateX(1.5px);}
.fx-prev-scanlines::after{content:'';position:absolute;inset:0;background:repeating-linear-gradient(to bottom,rgba(0,0,0,.55) 0,rgba(0,0,0,.55) 1px,transparent 1px,transparent 3px);}
.fx-prev-grain{filter:contrast(1.1) brightness(.95);}
.fx-prev-grain::after{content:'';position:absolute;inset:0;opacity:.5;background-image:radial-gradient(rgba(255,255,255,.9) .5px,transparent .5px),radial-gradient(rgba(0,0,0,.9) .5px,transparent .5px);background-size:3px 3px,4px 4px;}
.fx-prev-sharpen{filter:contrast(1.5) saturate(1.3);}
.fx-prev-sharpen::after{content:'';position:absolute;inset:0;box-shadow:inset 0 0 0 1px rgba(255,255,255,.4);}
.fx-prev-edgeDetect{background:#0a0a0a;}
.fx-prev-edgeDetect::after{content:'';position:absolute;inset:12% 22%;border:1.2px solid #eee;border-radius:2px;opacity:.85;}
.fx-prev-groundShadow{background:linear-gradient(to bottom,#dfe6f0 0%,#dfe6f0 62%,#aab4c4 62%,#aab4c4 100%);}
.fx-prev-groundShadow::after{content:'';position:absolute;left:30%;top:14%;width:22%;height:38%;background:#556;border-radius:3px 3px 0 0;}
.fx-prev-groundShadow::before{content:'';position:absolute;left:38%;top:58%;width:46%;height:16%;background:rgba(0,0,0,.45);border-radius:50%;filter:blur(1px);transform:skewX(-25deg);}
.fx-prev-contourBrut{background:var(--panel3);}
.fx-prev-contourBrut::after{content:'';position:absolute;inset:3px;border:1.5px dashed rgba(236,234,231,.65);border-radius:3px 5px 4px 6px/4px 3px 6px 4px;}
.fx-prev-threshold{background:linear-gradient(90deg,#050505 50%,#f5f5f5 50%);}
.fx-prev-halftone{background-color:#fff;background-image:radial-gradient(circle,#111 38%,transparent 40%),radial-gradient(circle,#111 38%,transparent 40%);background-size:6px 6px,6px 6px;background-position:0 0,3px 3px;}
/* Shipped shader-library previews.  These are intentionally CSS-only: the
   menu opens before a render surface exists, so a tiny deterministic visual
   is more reliable than trying to render a second GPU scene for every tile. */
/* Shader-specific rules below intentionally override the base .fx-prev
   gradient.  Do not add a higher-specificity catch-all here: it would make
   every tile look identical. */
.fx-prev-shader_exposure{filter:brightness(1.35);}
.fx-prev-shader_hue_saturation{background:linear-gradient(120deg,#f04b6a,#ffc43d 38%,#4ed6aa 68%,#667cff);filter:saturate(1.65);}
.fx-prev-shader_tint{background:linear-gradient(135deg,#38255e,#e8b26e);}
.fx-prev-shader_tritone{background:linear-gradient(135deg,#151a55,#ec5b3a 52%,#fff1a0);}
.fx-prev-shader_channel_mixer{background:linear-gradient(90deg,#f33 0 33%,#3d6 33% 66%,#48f 66%);}
.fx-prev-shader_levels{background:linear-gradient(90deg,#08090e,#777 45%,#fff);}
.fx-prev-shader_photo_filter{background:linear-gradient(135deg,#e66d3b,#f5d36a);}
.fx-prev-shader_black_white_mix{filter:grayscale(1) contrast(1.35);}
.fx-prev-shader_vibrance{filter:saturate(2.2) contrast(1.1);}
.fx-prev-shader_color_map{background:linear-gradient(90deg,#161850,#a63280 45%,#ffd26a);}
.fx-prev-shader_colorama{background:linear-gradient(90deg,#1b155c,#df3e92 48%,#ffe36e);}
.fx-prev-shader_emboss{background:linear-gradient(135deg,#e9edf2 0 44%,#727985 46% 54%,#f7f8fa 56%);filter:contrast(1.35);}
.fx-prev-shader_find_edges{background:#111;}
.fx-prev-shader_find_edges::after{content:'';position:absolute;inset:3px;border:1px solid #fff;border-radius:50%;box-shadow:8px 3px 0 -2px #111,8px 3px 0 -1px #fff;}
.fx-prev-shader_threshold_rgb{background:linear-gradient(90deg,#070707 33%,#777 33% 66%,#fff 66%);}
.fx-prev-shader_roughen_alpha{background:linear-gradient(135deg,#ff9a63,#725cff);}
.fx-prev-shader_roughen_alpha::after{content:'';position:absolute;inset:2px;background:repeating-linear-gradient(135deg,transparent 0 3px,rgba(255,255,255,.35) 3px 4px);}
.fx-prev-shader_minimax{filter:contrast(1.75);}
.fx-prev-shader_cinematic_glow{filter:brightness(1.25) saturate(1.45);box-shadow:0 0 7px 2px rgba(255,190,90,.8) inset;}
.fx-prev-shader_chroma_smear{background:linear-gradient(90deg,#ff335d 0 28%,#ffbf45 45%,#46e3cd 72%,#4d6dff);}
.fx-prev-shader_mirror{background:linear-gradient(90deg,#ff775d 0 50%,#5e8dff 50%);}
.fx-prev-shader_mosaic{background:conic-gradient(#ff765c 25%,#5b8eff 0 50%,#ffd166 0 75%,#65d3b0 0) 0 0/7px 7px;}
.fx-prev-shader_ripple{background:repeating-radial-gradient(ellipse at 50% 50%,#f36 0 2px,#58d 3px 4px,#f8c 5px 6px);}
.fx-prev-shader_spherize{background:radial-gradient(circle at 50% 50%,#fff 0 13%,#f36 15% 38%,#568dff 42% 70%,#192345 72%);}
.fx-prev-shader_displacement{background:repeating-linear-gradient(155deg,#ff745f 0 3px,#6b7fea 3px 7px,#55d2b1 7px 11px);}
.fx-prev-shader_fill{background:linear-gradient(135deg,#25357a,#4cbece);}
.fx-prev-shader_color_balance{background:linear-gradient(90deg,#5d3d9e,#e8a455 50%,#7bd6c2);}
.fx-prev-shader_radial_wipe{background:conic-gradient(from -90deg,#ffcb63 0 48%,#1c1e2b 48%);}
.fx-prev-shader_gradient_wipe{background:linear-gradient(90deg,#f4c45c 0 48%,#252536 52%);}
.fx-prev-shader_drop_shadow{background:linear-gradient(135deg,#ff8b64 0 48%,#121521 50%);}
.fx-prev-shader_inner_shadow{background:radial-gradient(circle,#ff9f67 0 35%,#172033 60%);box-shadow:inset 0 0 5px 2px rgba(0,0,0,.8);}
.fx-prev-shader_bevel{background:linear-gradient(135deg,#fff3b0 0 16%,#d96754 32%,#3d5faa 68%,#9ee8df 86%);}
.fx-prev-shader_soft_outline{background:linear-gradient(135deg,#151722,#151722);box-shadow:inset 0 0 0 2px rgba(255,255,255,.85),0 0 3px rgba(255,255,255,.8);}
.fx-prev-shader_soft_light{background:linear-gradient(135deg,#4f3b8f,#f0a05c);filter:brightness(1.15);}
.fx-prev-shader_kaleidoscope{background:conic-gradient(#ff725d 0 12%,#ffd166 12% 24%,#58d6bd 24% 36%,#657cff 36% 48%,#ff725d 48% 60%,#ffd166 60% 72%,#58d6bd 72% 84%,#657cff 84%);border-radius:50%;}
.fx-prev-shader_polar_coordinates{background:repeating-radial-gradient(circle at 50% 50%,#ffcf68 0 2px,#557dff 3px 4px,#e45885 5px 6px);}
.fx-prev-shader_motion_tile{background:repeating-conic-gradient(#f06 0 25%,#4dd 0 50%,#fd6 0 75%,#67f 0) 0 0/9px 9px;}
.fx-prev-shader_light_sweep{background:linear-gradient(135deg,#29304f,#f4d073 48%,#29304f 58%);}
.fx-prev-shader_color_dodge{background:linear-gradient(135deg,#3e4ca4,#f4c566);filter:brightness(1.25);}
.fx-prev-shader_difference{background:linear-gradient(135deg,#f45,#5be);filter:invert(.1) contrast(1.35);}
.fx-prev-shader_grid{background-color:#20263e;background-image:linear-gradient(rgba(155,190,255,.65) 1px,transparent 1px),linear-gradient(90deg,rgba(155,190,255,.65) 1px,transparent 1px);background-size:6px 6px;}
.fx-prev-shader_checkerboard{background:conic-gradient(#f2f2f2 25%,#282a34 0 50%,#f2f2f2 0 75%,#282a34 0) 0 0/8px 8px;}
.fx-prev-shader_gradient_ramp{background:linear-gradient(90deg,#120b42,#ec3f84 50%,#ffe27a);}
.fx-prev-shader_fractal_noise{background:radial-gradient(circle at 25% 35%,#eee 0 1px,transparent 2px),radial-gradient(circle at 75% 65%,#222 0 1px,transparent 2px),linear-gradient(135deg,#334,#aaa 48%,#223);background-size:5px 5px,7px 7px,100% 100%;}
.fx-prev-shader_lens_flare{background:radial-gradient(circle at 50% 50%,#fff 0 1px,#ffe18b 2px,transparent 5px),linear-gradient(90deg,transparent 20%,rgba(255,210,120,.65) 50%,transparent 80%),#25345f;}
.fx-prev-shader_four_color_gradient{background:radial-gradient(circle at 0 0,#f54,transparent 65%),radial-gradient(circle at 100% 0,#4df,transparent 65%),radial-gradient(circle at 0 100%,#72f,transparent 65%),radial-gradient(circle at 100% 100%,#fd5,transparent 65%);}
.fx-prev-shader_lightning{background:#0e1532;}.fx-prev-shader_lightning::after{content:'〽';position:absolute;inset:-2px 0 0 7px;color:#dff8ff;font-size:18px;text-shadow:0 0 5px #7deaff;}
.fx-prev-shader_radio_waves{background:repeating-radial-gradient(circle at 50% 50%,transparent 0 2px,rgba(130,215,255,.9) 3px 4px,transparent 5px 7px),#17264b;}
.fx-prev-shader_caustics{background:repeating-radial-gradient(ellipse at 30% 20%,rgba(255,255,255,.75) 0 1px,transparent 2px 6px),linear-gradient(135deg,#0a6790,#6ce0c3);}
.fx-prev-shader_twirl{background:conic-gradient(from 30deg,#f64,#5bf,#f64,#fb5,#f64);border-radius:50%;}
.fx-prev-shader_bulge{background:radial-gradient(circle,#fff 0 10%,#f66 30%,#48f 72%);}
.fx-prev-shader_wave_warp{background:repeating-linear-gradient(175deg,#ff745f 0 3px,#ffd36b 3px 6px,#5596ff 6px 9px);}
.fx-prev-shader_turbulent_displace{background:repeating-linear-gradient(125deg,#ed617b 0 4px,#6d78e9 4px 8px,#54c8ae 8px 12px);filter:blur(.35px);}
.fx-prev-shader_optics_compensation{background:radial-gradient(ellipse,#ffcf67 0 16%,#e34e6b 18% 43%,#3863b8 45% 70%,#151b3d 72%);}
.fx-prev-shader_heat_haze{background:linear-gradient(180deg,#ffcf7d,#d85d4a 58%,#4c6ea3);filter:blur(.7px);}
.fx-prev-shader_directional_blur{filter:blur(2px);transform:skewX(-14deg);}
.fx-prev-shader_radial_blur{filter:blur(1px);transform:scale(1.12);}
.fx-prev-shader_soft_directional_blur{filter:blur(1.5px);transform:skewX(9deg);}
.fx-prev-shader_luma_key{background:linear-gradient(90deg,#050505 45%,#f5f5f5 55%);}
.fx-prev-shader_color_key{background:linear-gradient(135deg,#39d58f 0 45%,#3a69e8 45% 70%,#f45 70%);}
.fx-prev-shader_particle_field{background-color:#101827;background-image:radial-gradient(circle,#fff 0 1px,transparent 1.5px),radial-gradient(circle,#63d7ff 0 1px,transparent 1.5px);background-size:7px 7px,11px 11px;}
.fx-prev-shader_particle_streaks{background:repeating-linear-gradient(160deg,transparent 0 5px,rgba(106,207,255,.9) 6px 7px),#132544;}
.fx-prev-shader_particle_vortex{background:repeating-radial-gradient(ellipse at 50% 50%,transparent 0 2px,rgba(255,210,106,.9) 3px 4px,transparent 5px 7px),#39245d;}
.fx-prev-shader_particle_burst{background:radial-gradient(circle,#fff 0 2px,transparent 3px),repeating-conic-gradient(from 5deg,rgba(255,220,120,.9) 0 3deg,transparent 3deg 18deg),#29214a;}
.fx-prev-shader_plexus_field{background-color:#121c30;background-image:radial-gradient(circle,#8fe8ff 0 1px,transparent 1.5px),linear-gradient(25deg,transparent 47%,rgba(120,215,255,.55) 48% 50%,transparent 51%);background-size:9px 8px,18px 12px;}
.fx-prev-shader_depth_starfield{background-color:#050914;background-image:radial-gradient(circle at 20% 35%,#fff 0 1px,transparent 1.5px),radial-gradient(circle at 70% 65%,#8ad9ff 0 1px,transparent 1.5px),radial-gradient(circle at 90% 15%,#fff 0 1px,transparent 1.5px);}
/* Figma-style paired W/H row (Document, 2026-07) — a small link icon
   between the two fields toggles proportion-lock (tools-panel-dock.js
   sibling pattern: JS toggles .on, CSS just reflects it). */
.dims-row{gap:5px;}
/* Paired rows (W/H, X/Y, Opacity/Offset) fit TWO label+field pairs on one
   line, so their labels are deliberately hug-width — they opt out of the
   single-column grid above rather than fighting it. */
.dims-row .pl{min-width:0!important;width:auto!important;flex:none;overflow:visible;}

/* ...but hug-width labels mean each pair starts wherever its own text ends,
   so W/H and FPS/Frames — stacked in the same section — put their fields on
   four different x at four different widths (2026-07-27: "dans rive les
   value sont quand même bien aligné, nous c'est un peu le basard"). This
   replaces the flex flow with a real four-column grid: two FIXED label
   columns and two equal value columns, so every paired row in the panel
   shares the same grid lines whatever its labels say. A fifth `auto` track
   takes an optional trailing control (the W/H proportion lock); rows without
   one leave it empty and it collapses to nothing.
   Only the canonical label|field|label|field rows carry this class — the BG
   icon strip and the P.min/P.max row (which interleaves unit suffixes
   between the fields) are genuinely different shapes and stay on flex. */
.pair-grid{display:grid!important;grid-template-columns:44px minmax(0,1fr) 44px minmax(0,1fr) 22px;gap:5px;align-items:center;}
.pair-grid .pl{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
/* The trailing 22px track is FIXED, not auto: a row without a lock button
   would otherwise size that track to 0 and shift its own columns 3 and 4
   left of the row above's (measured: 11px out). Reserved on every row, it
   reads as a consistent right gutter — same as the Rive reference, whose
   stopwatch column is present on every line whether or not it is lit.
   The fields must FILL their track too, or they sit 50px wide at the track's
   left edge and the columns only look aligned when the tracks happen to be
   equal. */
.pair-grid .pi{width:100%;min-width:0;}

/* Position / Size / Rotate in the selection panel, one grid for the three.
   Size was a .dims-row (hug label, so its lock button fits) while Position
   and Rotate were ordinary rows with the 68px label column — so Size's two
   fields sat ~35px left of Position's, which is the ragged block in the
   reported screenshot. Rotate's single field spans both value columns so its
   box ends on the same right edge as the pairs above, and the degree symbol
   shares the trailing column with Size's lock. */
/* Narrower label column and tighter gaps than the panel default here: this
   block shares its row with the 9-dot anchor picker, so the whole grid has
   ~172px to spend. At the default 68px label + 6px gaps the value boxes
   came out 32px and clipped their own numbers ("586" -> "58(") — alignment
   is not worth buying with legibility. 54px still fits "Position", the
   longest label of the three. */
.sp-xform-row{display:grid;grid-template-columns:54px minmax(0,1fr) minmax(0,1fr) 22px;gap:4px;align-items:center;}
.sp-xform-row .pl{width:auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.sp-xform-row .pi{width:100%;min-width:0;}
#sp-rot{grid-column:2 / span 2;}
.dims-lock-btn{flex:none;width:22px;height:22px;border:none;background:transparent;color:rgba(236,234,231,.4);cursor:pointer;border-radius:5px;display:flex;align-items:center;justify-content:center;}
.dims-lock-btn:hover{background:rgba(255,255,255,.08);color:var(--text);}
.dims-lock-btn.on{color:var(--accent-hover);background:var(--accent-dim);}
#curve-canvas-wrap{position:relative;display:inline-block;}
#curve-canvas{width:200px;height:200px;border-radius:4px;cursor:crosshair;background:#111;display:block;}
#curve-resize-handle{position:absolute;right:-2px;bottom:-2px;width:12px;height:12px;cursor:nwse-resize;background:var(--border2);border-radius:2px 0 4px 0;}
#curve-resize-handle:hover{background:var(--accent);}
#curve-presets,#curve-custom-presets{display:grid;grid-template-columns:repeat(4,1fr);gap:4px;width:100%;}
#curve-presets button,#curve-custom-presets button{background:var(--bg);border:1px solid var(--border);color:var(--text-dim);padding:3px 2px 4px;border-radius:4px;cursor:pointer;display:flex;flex-direction:column;align-items:center;gap:1px;}
#curve-presets button:hover,#curve-presets button.active,#curve-custom-presets button:hover,#curve-custom-presets button.active{border-color:var(--accent);color:var(--text);background:var(--panel3);}
#curve-presets button svg,#curve-custom-presets button svg{display:block;}
#curve-presets button span,#curve-custom-presets button span{font-size:7px;line-height:1.1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%;}
#curve-custom-presets:empty{display:none;}
#curve-save-preset{font-weight:700;width:100%;background:var(--bg);border:1px solid var(--border);color:var(--text-dim);padding:5px;border-radius:4px;cursor:pointer;font-size:10px;}
#curve-save-preset:hover{border-color:var(--accent);color:var(--text);}
#curve-coords{font-size:9px;color:var(--text-dim);text-align:center;font-family:monospace;}

/* TIMELINE */
#timeline-area{flex-shrink:0;background:var(--panel);border-top:none;display:flex;flex-direction:column;height:250px;min-height:80px;}
#tl-resize{height:4px;cursor:ns-resize;background:transparent;flex-shrink:0;}
#tl-resize:hover{background:var(--accent);}
/* v12: matches --panel (not --panel2) — the mockup's own darker header
   shade read as an unwanted leftover "gray bar" once seen against this
   app's actual content (flagged twice), so this flushes it to the same
   tone as the rest of the timeline instead of keeping a separate band. */
/* ONE source of spacing for this row (2026-07-27: "les gap sont trop grand
   des boutons et boutons pas forcément bien aligné"). Nine buttons carried
   an inline margin-left:4px ON TOP of this gap, so the row alternated 6px
   and 10px between otherwise identical 28px buttons — a rhythm that reads as
   accidental because it is. Margins removed; 4px here, tighter than the old
   6px, since these are icon buttons that group better close together. */
#tl-toolbar{display:flex;align-items:center;gap:4px;padding:0 16px;background:var(--panel);border-bottom:none;flex-shrink:0;height:44px;}
#tl-toolbar .toolbar-user-hidden{display:none!important;}
/* Motion keeps transport + timing + motion display controls in the main
   toolbar. Drawing-review controls remain untouched and return immediately
   in Animation 2D; hiding them here is a mode view, never a stored choice. */
body.mode-motion #btn-os,
body.mode-motion #btn-os-outline,
body.mode-motion #btn-ghost-all,
body.mode-motion #btn-ghost-select,
body.mode-motion #btn-shadow-guides,
body.mode-motion #btn-revision-view,
body.mode-motion #btn-cycle,
body.mode-motion #btn-tween-curves{display:none;}
.toolbar-custom-pop{width:228px;max-height:min(420px,60vh);overflow-y:auto;padding:6px;}
.toolbar-custom-row{display:flex;align-items:center;gap:8px;padding:5px 6px;border-radius:5px;color:var(--text);font-size:11px;cursor:pointer;}
.toolbar-custom-row:hover{background:var(--panel3);}
/* Fixed icon column so every name starts at the same x — the icon is what
   the eye actually matches against the toolbar, the name only disambiguates. */
.toolbar-custom-row .toolbar-custom-ico{width:16px;height:16px;flex:none;display:flex;align-items:center;justify-content:center;color:var(--text-dim);}
.toolbar-custom-row .toolbar-custom-ico svg{width:14px;height:14px;}
.toolbar-custom-row .toolbar-custom-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.toolbar-custom-row input[type=checkbox]{flex:none;margin:0;}
.tb{background:transparent;border:none;color:rgba(236,234,231,.55);cursor:pointer;padding:2px;border-radius:7px;display:flex;align-items:center;justify-content:center;width:28px;height:28px;transition:background .15s,color .15s;}
.tb:hover{background:rgba(255,255,255,.06);color:var(--text);}
.tb.active{color:var(--accent-hover);}
.tb.playing{color:var(--green);}
.tb.pingpong{color:#ffaa28;}
.tb .material-symbols-rounded{font-size:18px;}
.ti{font-size:11.5px;color:rgba(236,234,231,.45);display:flex;align-items:center;gap:7px;}
.ti b{color:var(--text);}
.ti input[type="number"]{width:36px;background:var(--panel3);border:none;color:var(--text);border-radius:6px;padding:5px 3px;font-size:11px;font-weight:600;text-align:center;outline:none;-moz-appearance:textfield;}
.ti input::-webkit-inner-spin-button{-webkit-appearance:none;}
#tl-content{flex:1;display:flex;overflow:hidden;min-height:0;}
#layer-panel{width:220px;flex-shrink:0;background:#1a1920;border-right:1px solid rgba(0,0,0,.5);display:flex;flex-direction:column;}
#layer-panel-resize{width:4px;cursor:ew-resize;background:var(--border);flex-shrink:0;}
#layer-panel-resize:hover,#layer-panel-resize.active{background:var(--accent);}
#layer-list{flex:1;overflow-y:auto;}
.lrow{display:flex;align-items:center;height:34px;padding:0 6px;border-bottom:1px solid rgba(255,255,255,.035);cursor:pointer;gap:3px;font-size:11.5px;}
.layer-drop-indicator{position:fixed;height:2px;z-index:400;pointer-events:none;background:var(--accent);box-shadow:0 0 0 1px rgba(74,158,255,.28),0 0 8px rgba(74,158,255,.7);transform:translateY(-1px);}
.layer-drop-indicator::before{content:'';position:absolute;left:0;top:50%;width:7px;height:7px;border-radius:50%;background:var(--accent);transform:translate(-2px,-50%);}
.layer-reorder-grip{position:sticky;left:0;z-index:9;width:12px;height:100%;flex:0 0 12px;margin-right:-12px;cursor:grab;pointer-events:auto;background:linear-gradient(90deg,rgba(15,16,22,.78),rgba(15,16,22,0));}
.layer-reorder-grip::after{content:'';position:absolute;left:3px;top:50%;width:4px;height:12px;transform:translateY(-50%);opacity:.38;background:radial-gradient(circle,rgba(230,234,244,.8) 1px,transparent 1.4px) 0 0/4px 4px;}
.layer-reorder-grip:hover::after{opacity:.72;}
.layer-reorder-grip:active{cursor:grabbing;}
.layer-drag-ghost{--layer-drag-color:var(--accent);position:fixed;left:0;top:0;z-index:450;pointer-events:none;box-sizing:border-box;border:1px solid color-mix(in srgb,var(--layer-drag-color) 55%,rgba(255,255,255,.3));border-radius:4px;background:transparent;box-shadow:0 0 0 1px rgba(0,0,0,.22),0 4px 14px rgba(0,0,0,.16);will-change:transform;}
.frow.dragging,.lrow.dragging{opacity:.42;}
/* Camera layer row (v18): same 34px rhythm as .lrow/.frow so the panel and
   grid stay perfectly aligned; a warm accent to read as "not a draw layer". */
.lrow.camrow{background:rgba(255,170,40,.05);}
.lrow.camrow.act{box-shadow:inset 3px 0 0 #ffaa28;background:rgba(255,170,40,.10);}
/* Compact camera row (feedback: la ligne caméra prend toujours la même
   place que les calques de dessin, même quand on ne l'édite pas) — shrunk
   to a thin strip while the camera tool isn't active; back to the normal
   34px the instant it's reselected. .lrow and .frow MUST shrink to the
   exact same height (see the "must stay in lockstep" comment on .frow
   below) or the panel/grid columns drift out of alignment for every row
   below this one. */
.lrow.camrow.compact{height:16px;}
.lrow.camrow.compact .lico{width:14px;height:14px;}
.frow.camrow{display:flex;border-bottom:1px solid rgba(255,170,40,.18);}
.frow.camrow.compact{height:16px;}
.frow.camrow.compact .fc{height:16px;}
.frow.camrow.compact .fc.camkey::before{width:6px;height:6px;}
.fc.camkey::before{content:'';position:absolute;left:50%;top:50%;width:9px;height:9px;transform:translate(-50%,-50%) rotate(45deg);background:#ffaa28;border:1px solid rgba(0,0,0,.5);}
/* Motion mode (v1, 2026-07): expandable Transform-property rows in the
   layer panel + matching keyframe-track rows in the grid — see motion.js.
   Reuses .lrow/.frow's 34px rhythm; group/property rows below an expanded
   layer are visually indented and slightly recessed. */
.motion-group-row{padding-left:24px;padding-right:8px;color:var(--text-dim);font-size:10.5px;text-transform:uppercase;letter-spacing:.04em;cursor:default;background:rgba(255,255,255,.015);display:flex;align-items:center;justify-content:space-between;margin-top:6px;}
.motion-group-row:first-child{margin-top:0;}
.motion-filter-btn{display:flex;align-items:center;justify-content:center;width:16px;height:16px;border-radius:3px;cursor:pointer;color:var(--text-dark);flex-shrink:0;}
.motion-filter-btn:hover{background:var(--panel3);color:var(--text);}
.motion-filter-btn.on{color:var(--accent);}
.motion-prop-row{padding-left:24px;gap:6px;}
.motion-prop-row:hover{background:rgba(255,255,255,.03);}
.motion-prop-select-target{cursor:pointer;border-radius:3px;}
.motion-prop-row.prop-selected{background:rgba(74,158,255,.12);box-shadow:inset 2px 0 0 rgba(92,183,255,.9);}
.motion-track-row.prop-selected{background:rgba(74,158,255,.055);box-shadow:inset 0 1px 0 rgba(92,183,255,.12),inset 0 -1px 0 rgba(92,183,255,.12);}
.motion-val.mixed,.motion-prop-row input.mixed{color:var(--text-dim);font-style:italic;}
/* Élément rows (2026-07, "shape layer" feedback): one per stroke/shape
   visible in the layer at the current frame, nested under its own
   "Éléments" group — each independently keyframeable, fixing the layer-
   wide Anchor Point pivoting into empty space between unrelated shapes. */
.motion-elem-row{padding-left:24px;gap:6px;}
.motion-elem-row:hover{background:rgba(255,255,255,.03);}
.motion-elem-swatch{width:12px;height:12px;border-radius:3px;border:1px solid rgba(255,255,255,.25);flex-shrink:0;}
.motion-elem-swatch.has-motion{box-shadow:0 0 0 1.5px var(--accent);}
/* Icon variant (group/raster rows, shapes-panel.js) — same slot as the
   color swatch above, but holding a monochrome ICO_* SVG instead of a
   fill/stroke color, so it needs no border/background of its own. */
.motion-elem-swatch.icon{border:none;background:transparent;color:var(--text-dim);display:flex;align-items:center;justify-content:center;}
.motion-elem-swatch.icon svg{width:100%;height:100%;display:block;}
/* Single diamond per property row, three states (2026-07 — merged with what
   used to be a second, redundant .motion-addkey diamond further along the
   same row): neutral/hollow when unanimated, accent-outline hollow when
   animated but no key at the current frame, accent-filled when a key sits
   right here (fill vs stroke decided by motion.js's inline SVG markup). */
.motion-stopwatch{color:var(--text-dark);cursor:pointer;}
.motion-stopwatch:hover{background:var(--panel3);color:var(--text);}
.motion-stopwatch.on{color:var(--accent);}
/* ƒx expression toggle (2026-07) — sits right after the stopwatch, same
   hollow/on visual language: neutral when no expression, accent when one is
   enabled, red when it's enabled but currently throwing (lastError set),
   so a broken expression is visible on the row itself, not just in a log. */
.motion-expr-btn{color:var(--text-dark);cursor:pointer;}
.motion-expr-btn:hover{background:var(--panel3);color:var(--text);}
.motion-expr-btn.on{color:var(--accent);}
.motion-expr-btn.err{color:var(--red);}
.motion-expr-editor{height:auto;flex-direction:column;align-items:stretch;gap:4px;padding:6px 8px 8px 30px;cursor:default;background:rgba(255,255,255,.02);}
.motion-expr-toggle{display:flex;align-items:center;gap:5px;font-size:10.5px;color:var(--text-dim);cursor:pointer;}
.motion-expr-code{width:100%;box-sizing:border-box;background:var(--bg);border:1px solid var(--border2);border-radius:4px;color:var(--text);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;padding:6px;resize:vertical;}
.motion-expr-code:focus{outline:none;border-color:var(--accent);}
.motion-expr-error{font-size:10px;color:var(--red);white-space:pre-wrap;}
/* Anchor Point 3x3 grid selector (2026-07-29, LottieFiles-inspired) — icon
   toggle on the anchor row + its inline popover row, same open/close
   convention as the ƒx expression editor just above. */
.motion-anchor-grid-btn{color:var(--text-dark);cursor:pointer;}
.motion-anchor-grid-btn:hover{background:var(--panel3);color:var(--text);}
.motion-anchor-grid-btn.on{color:var(--accent);}
.motion-anchor-grid-row{height:auto;justify-content:center;padding:6px 8px;cursor:default;background:rgba(255,255,255,.02);}
.motion-anchor-grid{display:grid;grid-template-columns:repeat(3,18px);grid-template-rows:repeat(3,18px);gap:3px;}
.motion-anchor-cell{width:18px;height:18px;padding:0;border:1px solid var(--border2);border-radius:3px;background:var(--panel2);cursor:pointer;position:relative;}
.motion-anchor-cell:hover{border-color:var(--accent);background:var(--panel3);}
.motion-anchor-cell::after{content:'';position:absolute;top:50%;left:50%;width:4px;height:4px;transform:translate(-50%,-50%);border-radius:50%;background:var(--text-dim);}
.motion-anchor-cell:hover::after{background:var(--accent);}
.motion-anchor-cell.center::after{background:var(--accent);width:5px;height:5px;}
/* Right-panel "Propriétés du calque" section (motion.js
   renderMotionPropsPanel) — Motion mode only; the rows inside reuse the
   global .lrow/.motion-prop-row styles, which aren't scoped to
   #layer-list, so no per-panel duplicates needed. */
body:not(.mode-motion) #motion-props-sec{display:none;}
.motion-props-layername{padding:4px 8px 6px;font-size:11px;font-weight:600;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
#motion-props-body .lrow{height:24px;font-size:10.5px;cursor:default;}
/* The expression editor row must grow to fit its textarea — an ID-scoped
   selector (specificity 1-0-1) beats the plain-class .motion-expr-editor
   {height:auto} override below it, which is why fixing that lower rule
   alone wasn't enough (still 24px/clipped when rendered inside this right-
   panel mirror specifically). */
#motion-props-body .lrow.motion-expr-editor{height:auto;}
.motion-prop-name{display:flex;align-items:center;gap:5px;flex:1;color:var(--text-dim);}
.motion-prop-name svg{flex-shrink:0;}
.motion-fields{display:flex;align-items:center;gap:3px;flex-shrink:0;}
/* Bug found 2026-07 ("les box de value de calques sont trop grosses") —
   .motion-val only overrode width, still inheriting .pi's global
   padding:5px 8px/font-size:12.5px (sized for the wider Properties panel
   elsewhere) into Motion's much tighter Transform rows. Shrunk padding/
   font-size/border-radius here too, scoped to Motion only — .pi itself
   stays untouched for every other panel using it. `.pi.motion-val` (not
   plain `.motion-val`) because `.pi[type="number"]{width:50px}` above has
   higher specificity (class+attribute) than a single class — a bare
   `.motion-val{width:...}` was silently losing that fight regardless of
   file order, confirmed live (computed width stayed 50px).*/
.pi.motion-val{width:34px;padding:2px 3px;font-size:10.5px;border-radius:4px;}
.motion-unit{color:var(--text-dark);font-size:10px;width:14px;flex-shrink:0;}
/* Compact per-dimension label ("X"/"Y") before each field of a multi-dim
   property (2026-07-29, LottieFiles-inspired) — purely visual, no click
   handler needed (the field itself is the interactive part). */
.motion-dim-label{color:var(--text-dark);font-size:9px;flex-shrink:0;width:7px;text-align:center;}
/* Stopwatch moved to the row's right edge (2026-07-29, "keyframe button à
   droite... plus rapide à aller chercher") — margin only, so the icon's own
   fixed width/height (.lico) stays untouched and centered. */
.motion-prop-row .motion-stopwatch{margin-left:4px;}
.motion-track-row{position:relative;}
/* Per-property tracks (Position/Rotation/.../each element's own) are mostly
   empty space between the sparse diamonds that actually matter — the plain
   .fc per-frame border-right (shared with Animation 2D's dense frame grid,
   where it's load-bearing) just reads as a flat grey grid wall here.
   Reported live with a screenshot ("la grille visuelle de keyframes en gris
   clair... derrière les keyframes de la timeline"). Motion-only override —
   .fc alone (Animation 2D's own grid) is untouched. */
.fc.motion-fc{cursor:pointer;border-right:none;}
/* Design audit 2026-07: added a soft dark halo (box-shadow, not a bigger
   border — Motion mode shrinks this to 7px via body.mode-motion below, no
   room to spare) so an unselected/non-current key stays readable sitting
   on top of the accent-tinted connection bar (trackRowHtml, motion.js)
   instead of partly blending into it. */
/* 2026-08-16 restyle (nemo-timeline-inout-spec.html): "un seul dessin quel
   que soit le voisinage — losange en contour, sans remplissage... le
   remplissage devient EXCLUSIVEMENT le marqueur de sélection". Base is now
   an outline-only diamond (transparent center — the connector bar behind
   it shows through by design, same "ring sitting on the bar" read the
   spec's own mockup uses) instead of a permanently solid-filled one; .sel
   is the only state that fills it. Kept the dark halo box-shadow for
   legibility against the accent-tinted connector either way — unrelated
   axis, still needed on a thin-bordered shape sitting on varied
   backgrounds. */
/* z-index:2 (2026-08-16, mirrors the spec's own .kf-conn{z-index:1} vs
   .kf{z-index:3}) — a connector's rect spans EXACTLY diamond-center to
   diamond-center (so it lines up visually with both endpoints), which
   means at every interior key its edge pixel geometrically sits on top of
   that key's own diamond. Without an explicit z-index here to win that
   tie, elementFromPoint (real mouse hit-testing, unlike a synthetic
   dispatchEvent aimed straight at a target) could resolve a click on a
   diamond to the neighbouring connector instead — found live right after
   fixing the connector's own click-through bug (see trackRowHtml's
   rowEl.appendChild(svg) comment, motion.js). */
.motion-key{position:relative;z-index:2;width:9px;height:9px;border-radius:2px;background:transparent;border:1.5px solid #cfcfcf;box-shadow:none;transform:rotate(45deg);transition:background-color .08s,border-color .08s,transform .08s;}
.motion-key.cur{background:#ffaa28;border-color:#ffaa28;width:11px;height:11px;}
/* Flat selected treatment: accent fill + crisp white edge, deliberately no
   halo. The interpolation silhouette remains the primary visual language. */
.motion-key.sel{z-index:4;background:var(--accent-hover);border-color:#fff;box-shadow:none;}
.motion-key.linear{border-radius:1px;transform:rotate(45deg);}
.motion-key.hold{border-radius:1px;transform:rotate(0deg);}
.motion-key.smooth{border-radius:50%;transform:rotate(0deg);}
.motion-key.hold:not(.sel):not(.cur):not(.tinted){background:#cfcfcf;}
.motion-key.linear.sel{transform:rotate(45deg) scale(1.14);}
.motion-key.hold.sel,.motion-key.smooth.sel{transform:scale(1.14);}
.motion-key.sel.cur{background:var(--accent-hover);border-color:#fff;}
/* Connector rect (task #101, nemo-timeline-inout-spec.html: "le trait est
   une cible, pas une décoration"). Colours are the spec's .kf-conn ramp
   verbatim — a solid deep teal at rest, brightening on hover, fully lit
   when selected:
       .kf-conn{background:#2E6B60}  :hover{#3E8C7E}  .sel{#6FD9C4}
   2026-08-16 fix (Cyril: "tu as pas fait les ligne de connexion comme dans
   la doc"): the first pass drew these as var(--accent) BLUE at opacity .35,
   which is neither the spec's colour nor solid — the line read as a faint
   wash instead of the deliberate teal cord the doc shows running between
   two diamonds. Painting them here rather than via presentation attributes
   on the <rect> is what makes the :hover state reachable at all (a
   presentation attribute can't have states), and `fill` beats a
   presentation attribute in the cascade regardless. */
.motion-key-connect{fill:#2E6B60;pointer-events:auto;cursor:ew-resize;transition:fill .1s linear;}
.motion-key-connect:hover{fill:#3E8C7E;}
.motion-key-connect.sel{fill:#6FD9C4;}
/* Alt = retime (first key planted, second one slides). Driven by the SAME
   #frame-grid.timelink-alt class layer-inout.js already toggles for the
   Parent-in-Time dot reveal, mirroring the spec's own .kstage.alt container
   switch — the doc flags this shared-modifier overlap in its "Non résolu"
   section and concludes the two contexts don't collide (link dots live on
   LAYER bars, retiming on PROPERTY tracks), so one reveal class serving
   both is the consistent reading. Container-driven, not a per-element
   mousemove handler: the cursor has to change the instant Alt goes down,
   without waiting for the pointer to move a pixel. */
#frame-grid.timelink-alt .motion-key-connect{cursor:e-resize;}
/* Marquee rectangle (motion.js, screen-fixed since it spans multiple .frow
   rows, unlike per-row overlays elsewhere in this file). */
.motion-marquee-rect{position:fixed;border:1px solid var(--accent);background:rgba(63,107,245,.15);pointer-events:none;z-index:50;}
/* Selection box + stagger edges (motion.js updateKeySelectionBox /
   updateLayerStaggerBox) — wraps the current multi-selection (keyframe
   diamonds OR whole layers). Box itself is a pure visual frame (pointer-
   events none, same screen-fixed positioning as the marquee above).
   Grab target evolved twice on feedback: a hidden Alt+drag gesture wasn't
   discoverable, then a small centered pill handle was "impossible à
   attraper" AND didn't match the reference anyway — "j'ai juste à glisser
   la box qui entoure peu importe où je suis et le haut et le bas de cette
   box pour stagger". Now: the box's own top AND bottom edges are each a
   full-width draggable strip (.motion-keysel-edge) — grab anywhere along
   either one — and the interior (.motion-keysel-fill) is a hand-cursor
   surface that MOVES the whole selection uniformly ("j'ai la hand qui
   permet de déplacer partout dans la box"), matching the reference's
   move-inside / skew-on-edges split. */
.motion-keysel-box{position:fixed;border:1.5px solid var(--accent);pointer-events:none;z-index:51;box-sizing:border-box;}
.motion-keysel-fill{position:absolute;inset:0;pointer-events:auto;cursor:grab;background:rgba(63,107,245,.07);}
.motion-keysel-fill:hover{background:rgba(63,107,245,.13);}
.motion-keysel-fill:active{cursor:grabbing;}
/* ew-resize, not ns-resize — feedback: "l'icon sur le haut et bas montre
   des fleche à drag vers le haut ou le bas alors que c'est sur le côté" —
   the skew drag is HORIZONTAL (slides keys left/right along the timeline),
   the cursor must show sideways arrows. */
.motion-keysel-edge{position:absolute;left:-4px;right:-4px;height:14px;pointer-events:auto;cursor:ew-resize;z-index:1;}
.motion-keysel-edge-top{top:-9px;}
.motion-keysel-edge-bottom{bottom:-9px;}
/* 2026-08-16 (Cyril: "la ligne de rectangle soit uniforme juste quand on
   hover et grab grossis un peu") — this bar used to sit at opacity:.85
   ALWAYS, on top of the plain 1.5px box border, so the box read as
   uneven: a crisp thin line on the sides, a bright thick one top/bottom,
   regardless of whether anyone was even near it. Now transparent at rest
   (the box's own border alone is the uniform outline), lights up to the
   SAME accent only on hover (matching the box's border colour, not a
   brighter one — "uniforme"), and grows a touch further only while
   actually gripped (.grabbing, toggled by the skew-drag start/end in
   motion.js) rather than on hover alone. */
.motion-keysel-edge::after{content:'';position:absolute;left:0;right:0;top:50%;height:3px;transform:translateY(-50%);background:var(--accent);border-radius:2px;opacity:0;transition:opacity .1s linear,height .1s linear;}
.motion-keysel-edge:hover::after{opacity:.85;}
.motion-keysel-edge.grabbing::after{opacity:1;height:5px;}
/* Side edges = SPACE (spread/compress the selection along time, the opposite
   edge staying anchored). Vertical strips, so they reset the top/bottom
   geometry the shared .motion-keysel-edge rule sets for the skew edges. */
/* z-index 2 + the top/bottom edges inset below: on a selection spanning ONE
   track row the box is ~11px tall, so the 14px-tall skew edges covered the
   whole thing and swallowed every click meant for the side edges (they are
   later siblings, so they won the hit test). The corners now belong to the
   side edges, the usual resize-handle convention — and skew on a single row
   is a no-op anyway (its handler refuses under 2 rows). */
.motion-keysel-edge-left,.motion-keysel-edge-right{left:auto;right:auto;top:-4px;bottom:-4px;
  height:auto;width:14px;z-index:2;}
.motion-keysel-edge-top,.motion-keysel-edge-bottom{left:10px;right:10px;}
.motion-keysel-edge-left{left:-9px;}
.motion-keysel-edge-right{right:-9px;}
.motion-keysel-edge-left::after,.motion-keysel-edge-right::after{left:50%;right:auto;top:0;bottom:0;
  height:auto;width:3px;transform:translateX(-50%);}
.motion-keysel-edge-left:hover::after,.motion-keysel-edge-right:hover::after{opacity:.85;}
.motion-keysel-edge-left.grabbing::after,.motion-keysel-edge-right.grabbing::after{opacity:1;width:5px;}
body.mode-motion #layer-panel{width:260px;}
/* Motion mode row height (feedback 2026-07: 34px — Animation 2D's default —
   read as needlessly sparse once a layer's 5 Transform properties, its
   Elements sub-list, and each element's own 5 properties all stack up).
   22px MUST match motion.js's own `ROW_H` constant exactly (drives the
   SVG connection-bar/keyframe positioning in trackRowHtml) — the two are
   two different files that can't share a literal, so this comment is the
   sync point; changing one without the other reintroduces the panel/grid
   misalignment this was explicitly built to avoid. */
body.mode-motion .lrow{height:22px;font-size:10.5px;}
/* The expression editor (checkbox + textarea, appended as a .lrow so it
   slots into the same list flow) is NOT a fixed-height grid row like every
   other .lrow above — it needs to grow to fit its textarea, same as
   .motion-expr-editor{height:auto} already declares outside Motion mode.
   Without this override, the higher-specificity 22px rule above clips the
   whole editor to a sliver in Motion mode: the "Activer l'expression"
   checkbox is visible but the textarea to actually type into is squashed
   to nothing — reported as "impossible d'y voir quelquechose... ça ouvre
   plus grand la partie expression pour écrire" (comparing to how After
   Effects opens a real writable box, not a hairline). */
body.mode-motion .lrow.motion-expr-editor{height:auto;}
body.mode-motion .frow{height:22px;}
/* Grid half of a selected layer's row — same active/selected split as
   .lrow just below, so one row reads the same across both panels
   (2026-07-27: "cette partie n'est pas hightlight quand select"). The
   selected tint has to sit ABOVE the in/out bar that fills this row, hence
   the ::after overlay rather than a background the bar would cover. */
body.mode-motion .frow.act{box-shadow:inset 3px 0 0 #4E6FF2;background:none;}
body.mode-motion .frow.act.motion-selected{position:relative;box-shadow:inset 3px 0 0 #4E6FF2,inset 0 0 0 1px rgba(255,255,255,.35);}
body.mode-motion .frow.act.motion-selected::after{content:'';position:absolute;inset:0;background:rgba(63,107,245,.16);pointer-events:none;}
body.mode-motion .fc{height:22px;}
body.mode-motion .lico{width:16px;height:16px;}
body.mode-motion .motion-key{width:7px;height:7px;}
body.mode-motion .motion-key.cur{width:9px;height:9px;}
body.mode-motion .larrow{font-size:10px;}
/* Feedback: "la selection d'un calque peut mettre un liserais blanc autour
   aussi" — a thin white outline in ADDITION to the existing left accent
   bar, so the selected layer/element/property row reads clearly against
   the now-colored in/out bars (layer-inout.js) sharing the same row.
   2026-07-27: the outline now belongs to .motion-selected, not .act. Motion
   tags a SELECTED row `act motion-selected` and a merely-active one `act`,
   but .motion-selected had no rule anywhere — so the two states were
   pixel-identical and deselecting changed nothing on screen. Clicking empty
   space really did drop the selection; it just never looked like it
   ("ça doit deselect aussi les calques"). Active keeps the left accent bar
   alone (it's a position, not a selection); selected adds the outline and a
   stronger tint. */
body.mode-motion .lrow.act{box-shadow:inset 3px 0 0 #4E6FF2;}
body.mode-motion .lrow.act.motion-selected{background:rgba(63,107,245,.16);box-shadow:inset 3px 0 0 #4E6FF2,inset 0 0 0 1px rgba(255,255,255,.35);}
.lrow:hover{background:rgba(255,255,255,.03);}
/* v4: matches the mockup's "Layer 1 Stroke" selected-row treatment — the
   tint and left accent bar span the FULL row (name column + frame-grid
   area, see .frow.act below), not just the name column like before, and
   the row's own label picks up the accent-tinted text color too. */
.lrow.act{background:rgba(63,107,245,.08);box-shadow:inset 3px 0 0 #4E6FF2;}
.lrow.act .lnm{color:#9FB4FA;}
.lrow.sel{background:rgba(99,102,241,.10);box-shadow:inset 0 0 0 1px rgba(99,102,241,.35);}
.lico{width:20px;height:20px;display:flex;align-items:center;justify-content:center;cursor:pointer;border-radius:4px;color:var(--text-dim);}
.lico .material-symbols-rounded{font-size:14px;}
.lico svg{width:14px;height:14px;display:block;}
.lico:hover{background:var(--panel3);color:var(--text);}
.lico.off{color:var(--text-dark);}
.solo-btn{font-size:10px;font-weight:800;}
.solo-btn.on{color:#000;background:#ffcc00;}
.solo-btn.on:hover{background:#ffd633;}
.lnm{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding:0 4px;}
/* Header row of the layers column — 42px, matching #frame-hdr (20) +
   #bars-row (22) on the grid side. That equality is what keeps every .lrow
   aligned with its .frow, so it must not drift. */
#layer-hdr{height:42px;flex-shrink:0;border-bottom:1px solid var(--border);background:var(--panel2);display:flex;align-items:center;padding:0 6px;}
#layer-ctrls{display:flex;align-items:center;gap:6px;}
#layer-ctrls button{width:24px;height:24px;background:var(--panel3);border:none;color:rgba(236,234,231,.55);cursor:pointer;padding:2px;border-radius:7px;display:flex;align-items:center;justify-content:center;}
#layer-ctrls button:hover{background:#2c2a31;color:var(--text);}
#layer-ctrls .material-symbols-rounded{font-size:13px;}
#layer-ctrls svg{width:13px;height:13px;display:block;}
/* Motion header uses the existing 42px alignment band: no extra left-only
   row is introduced, preserving the panel/grid row invariant. */
#motion-header-tools{display:none;align-items:center;gap:5px;min-width:0;margin-left:auto;}
body.mode-motion #motion-header-tools{display:flex;}
body.mode-motion #layer-ctrls{gap:3px;}
body.mode-motion #layer-ctrls #btn-camera,
body.mode-motion #layer-ctrls #btn-audio,
body.mode-motion #layer-ctrls #btn-comp{display:none;}
#motion-context-label{min-width:0;max-width:74px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:10px;color:var(--text-dim);}
#motion-filter-trigger{width:24px;height:24px;flex:none;border:0;border-radius:6px;background:var(--panel3);color:var(--text-dim);display:flex;align-items:center;justify-content:center;cursor:pointer;}
#motion-filter-trigger:hover{color:var(--text);background:#2c2a31;}
.motion-filter-pop{width:218px;padding:8px;display:grid;grid-template-columns:72px 1fr;gap:7px;align-items:center;}
.motion-filter-search{grid-column:1/-1;width:100%;box-sizing:border-box;background:var(--bg);border:1px solid var(--border2);border-radius:5px;color:var(--text);font-size:11px;padding:6px 8px;outline:none;}
.motion-filter-search:focus{border-color:var(--accent);}
.motion-filter-pop>label:not(.motion-filter-check){font-size:10px;color:var(--text-dim);}
.motion-filter-select{min-width:0;background:var(--panel3);border:1px solid var(--border2);border-radius:5px;color:var(--text);font-size:10.5px;padding:4px;}
.motion-filter-check{grid-column:1/-1;font-size:10.5px;color:var(--text);cursor:pointer;}
.motion-filter-check input{accent-color:var(--accent);}
.motion-filter-hint{grid-column:1/-1;font-size:9px;line-height:1.35;color:var(--text-dark);}
/* Column presets only affect Motion's list. Animation 2D keeps its complete
   historical control set and DOM untouched. */
body.mode-motion #layer-panel[data-motion-columns="compact"] .motion-col-lock,
body.mode-motion #layer-panel[data-motion-columns="compact"] .motion-col-solo,
body.mode-motion #layer-panel[data-motion-columns="compact"] .motion-col-3d,
body.mode-motion #layer-panel[data-motion-columns="compact"] .motion-col-duplicator,
body.mode-motion #layer-panel[data-motion-columns="compact"] .motion-col-parent,
body.mode-motion #layer-panel[data-motion-columns="animation"] .motion-col-3d,
body.mode-motion #layer-panel[data-motion-columns="animation"] .motion-col-duplicator,
body.mode-motion #layer-panel[data-motion-columns="compositing"] .motion-col-3d,
body.mode-motion #layer-panel[data-motion-columns="compositing"] .motion-col-duplicator{display:none;}
/* Keep the fast numeric values directly beside each timeline property.
   Only the secondary expression/anchor editors stay in the detailed right
   inspector; values are deliberately available in both places. */
body.mode-motion #layer-list .motion-prop-row .motion-expr-btn,
body.mode-motion #layer-list .motion-prop-row .motion-anchor-grid-btn{display:none;}
body.mode-motion #layer-list .pi.motion-val{width:28px;padding-left:2px;padding-right:2px;}
/* Group labels used to consume a full 34px property row plus a 6px gap.
   The same compact rule hits the left header AND its right-grid spacer, so
   the panel/grid alignment contract remains exact. */
body.mode-motion #layer-list .motion-group-row,
body.mode-motion #frame-grid .motion-group-row{height:22px;min-height:22px;margin-top:2px;}
.motion-snap-guide{position:absolute;top:0;bottom:0;width:1px;background:#5cb7ff;box-shadow:0 0 7px rgba(92,183,255,.8);pointer-events:none;z-index:8;}
.motion-snap-guide::after{content:attr(data-label);position:absolute;top:43px;left:4px;padding:2px 4px;border-radius:3px;background:rgba(20,26,35,.92);color:#9fd6ff;font-size:9px;white-space:nowrap;}
/* Both columns reserve the SAME bottom band, so #fg-wrap and #layer-list
   always end at the same y and therefore always show exactly the same rows —
   otherwise the last rows get drawn with no name beside them, and the zoom
   scrollbar sits on top of a row (2026-07-25: "les boutons d'ajout à gauche
   sont plus haut que la scroll bar" then "tu aurais pu mettre la scroll bar
   sous le trait orange"). The band used to be 40px because the layer
   buttons lived down there; they moved into #layer-hdr (2026-07-27), so it
   only has to clear the zoom scrollbar, and both were then halved on top of
   that (2026-07-27: "toute cette zone là tu peux réduire le heigth de 50%")
   — 32px of timeline height handed back to the rows in total.
   THREE places must agree on this number: both paddings below and
   BOTTOM_BAND_PX in timeline-zoom.js, which centres the bar in it. */
#layer-panel{padding-bottom:8px;box-sizing:border-box;}
#fg-col{flex:1;display:flex;flex-direction:column;min-width:0;padding-bottom:8px;box-sizing:border-box;}
#fg-wrap{flex:1;overflow:auto;position:relative;min-height:0;}
/* Design audit 2026-07, round 2 (feedback: "le work area ressemble trop à
   un calque" — the boxed/bordered/purple v1 read as another layer bar, not
   a lightweight timeline indicator; "le ruler au dessus" — the numbered
   ruler should be the dominant top strip, this a thin echo under it, not a
   competing band above it. #frame-hdr now comes FIRST in the DOM
   (index.html) — this strip is `sticky`, offset by #frame-hdr's own
   height (kept in sync below), so the two stay stacked ruler-then-strip
   through any vertical scroll instead of just the ruler staying pinned.
   Round 3 (feedback: "l'onion skin pourrait être en dessous de work area"):
   this strip now holds TWO stacked sub-rows instead of one — work area on
   top, onion skin range below it — see the two blocks below.
   Round 4 (feedback: "double la hauteur du work area"): #wa-bar's own
   height doubled 6px->12px, which pushed the onion sub-row further down
   and this row's own total height up 16px->22px to still fit both without
   crowding (y 1-13 work area, y 15-21 onion, see each block's own top).
   ⚠️ ALIGNMENT: #layer-panel's "Layers" header (index.html, inline
   height:42px) MUST stay equal to #frame-hdr's height + this row's height
   (20+22 here) — that combined height is what #frame-grid's rows align
   against on the OTHER side of the panel split. Change one, change all
   three together or every layer row drifts out of sync with its timeline
   row (confirmed this was already the exact bug introduced in round 2:
   30px header vs a then-26px combined strip). */
/* Round 5 (feedback: "le fond derrière ruler, work area, onion skin
   devrait être noir comme derrière 'Layers' en dessous de Scene") —
   --panel2 (darker) instead of --panel, matching the "Layers" header
   strip (index.html, inline style) exactly, so the two headers either
   side of the panel split read as the same dark strip instead of two
   different tones. */
#bars-row{height:22px;display:flex;position:sticky;top:20px;flex-shrink:0;background:var(--panel2);z-index:2;}
/* Back to --accent (the app's one existing "this is active/selected/
   playhead" blue) instead of the v1 --purple experiment — feedback was
   that a whole separate hue read as its own distinct UI concept (i.e. a
   layer), when work-area is meant to feel like a lighter-weight variant of
   the SAME timeline-position language the playhead already uses, not a
   new one. No border/box-sizing/border-radius box anymore — a flat wash,
   nothing for the eye to read as "a bar sitting on top of the timeline". */
#wa-bar{position:absolute;top:1px;height:12px;background:rgba(63,107,245,.22);cursor:grab;z-index:3;}
/* Handles thinned 7px->3px (feedback: "poignées plus fines") and the
   white hover ring removed (feedback: "pas de liseré blanc autour") —
   opacity/brightness alone now carries the hover feedback, same restrained
   language the ruler's own ticks use. top:0/bottom:0 here fill the PARENT
   #wa-bar's own box exactly (it's the nearest positioned ancestor), so
   they track whatever top/height #wa-bar has above without needing their
   own copy of those values. */
#wa-bar .wa-handle{position:absolute;top:0;bottom:0;width:3px;background:var(--accent);cursor:ew-resize;opacity:.75;}
#wa-bar .wa-handle:hover{opacity:1;}
#wa-bar .wa-handle.left{left:0;}
#wa-bar .wa-handle.right{right:0;}
/* Second echo of the same in/out range, INSIDE the actual scrub/preview
   area (#frame-grid) rather than only in the thin top strip — feedback:
   "un highlight dans la zone de previz". Position/size mirrored from
   #wa-bar by updateWaBar() (ui.js). pointer-events:none: purely a visual
   read, dragging still only happens on the real #wa-bar above. */
#wa-tint{position:absolute;left:0;pointer-events:none;z-index:1;background:rgba(63,107,245,.05);border-left:1px solid rgba(63,107,245,.3);border-right:1px solid rgba(63,107,245,.3);box-sizing:border-box;}
/* Onion skin range markers — moved to the LOWER sub-row of #bars-row (was
   sharing the same y-band as #wa-bar, top:2px, which is also why the two
   used to visually merge into one confusing strip) and shrunk from an
   8×6px rounded pill to a plain 4px sliver, same flat-rectangle language
   as #wa-bar's own handles instead of reading as a separate, chunkier
   widget. Red/blue kept — it's the one place in the timeline that still
   needs to distinguish "in" from "out" by color alone since, unlike work
   area, there's no bracket shape doing that job. top re-derived each round
   #wa-bar's own height changes (round 4: 15px, right under #wa-bar's new
   1-13 span) — see #bars-row's own comment for the current numbers. */
.onion-marker{position:absolute;top:15px;width:4px;height:6px;cursor:ew-resize;z-index:4;}
.onion-marker.om-in{background:rgba(255,80,80,.75);}
.onion-marker.om-out{background:rgba(80,140,255,.75);}
/* Layer in/out point (layer-inout.js, v1 2026-07 — thickened 2026-07 per
   feedback: too subtle to read at a glance; every layer's bar is now a
   bold, full-height colored block). Full-height translucent fill spanning
   the layer's visible frame range so the existing keyframe diamonds/dots
   underneath stay visible through it — always clearly colored (not just on
   a custom range) so a layer's actual duration always reads instantly,
   every row an obviously-colored block regardless of whether it's trimmed.
   Handles are a solid bracket, always visible (not hover-only). */
/* border-radius bumped 3px->6px (2026-08-16, spec's own reference bar is
   8px on a 30px-tall bar — proportionally closer to this than the old
   fairly-square 3px was) so the bar itself reads as a rounded capsule the
   inset white pill sits inside, matching the spec's visual reference. */
.layer-inout-bar{position:absolute;left:0;top:2px;bottom:2px;background:rgba(63,107,245,.32);border:1px solid rgba(63,107,245,.85);border-radius:6px;cursor:grab;z-index:2;box-sizing:border-box;}
.layer-inout-bar.full-range{background:rgba(255,255,255,.07);border-color:rgba(255,255,255,.28);}
/* Overflow caps (2026-08, layer-inout.js updateBar) — the part of a bar
   that sits before frame 0 or past totalFrames-1 (Cavalry-style trim past
   the composition's own range). Hatched, not solid, so it reads as "past
   what actually plays" at a glance; rounded only on its OUTER edge so the
   bar still reads as one continuous capsule. */
.layer-inout-overflow-left,.layer-inout-overflow-right{position:absolute;top:0;bottom:0;
  background:repeating-linear-gradient(45deg,rgba(0,0,0,.4),rgba(0,0,0,.4) 3px,transparent 3px,transparent 6px);
  pointer-events:none;z-index:1;}
.layer-inout-overflow-left{left:0;border-radius:5px 0 0 5px;border-right:1px dashed rgba(255,255,255,.35);}
.layer-inout-overflow-right{right:0;border-radius:0 5px 5px 0;border-left:1px dashed rgba(255,255,255,.35);}
/* 2026-08-16 restyle (nemo-timeline-inout-spec.html, Cyril): a permanent
   white pill INSET inside the bar, not an edge-flush full-height sliver
   colored by the layer's own tint — the bar already carries that color, the
   handle's whole job now is to read as a neutral, always-legible grab
   affordance on top of it, regardless of which layer/color it belongs to.
   --pill/--pill-hot/--pill-dark are this rule family's own tokens (not
   reused elsewhere) so the 3-state ramp (idle/hover-drag/selected) stays
   self-contained and easy to re-tune without hunting other consumers of
   --accent-hover. */
.layer-inout-bar .layer-inout-handle{position:absolute;top:3px;bottom:3px;width:7px;background:var(--pill,#C9D6D2);cursor:ew-resize;border-radius:3px;opacity:1;}
.layer-inout-bar .layer-inout-handle.left{left:3px;}
.layer-inout-bar .layer-inout-handle.right{right:3px;}
/* Widened invisible hit zone (spec: "±5px en X et ±6px en Y, sinon elle est
   inattrapable") — a 7px-wide pill is otherwise a genuinely hard target,
   especially at low timeline zoom. Purely a bigger click area: the visible
   pill's own size/position is unchanged. */
.layer-inout-bar .layer-inout-handle::before{content:'';position:absolute;left:-5px;right:-5px;top:-6px;bottom:-6px;}
/* More discoverable trim handles, Motion mode ONLY (2026-07-29,
   LottieFiles-inspired: "l'affichage du calque avec ses poignées out/in
   Point" — a plain 7px sliver read as part of the bar's own border, not as
   a grabbable control). Animation 2D's frame-grid bars are untouched —
   this never widens the actual click target (still the full row height,
   same element), just a touch wider than the base pill so it reads clearly
   at Motion's shorter 18px bar height.
   2026-08-16 fix (Cyril, live screenshot: "attention visuellement à quoi
   doivent ressembler les poignée in out, regarde bien la documentation") —
   this override still shipped the PRE-restyle tab shape (rounded only on
   the outer corner) plus a dark grip-glyph ::after bar, from before the
   spec's plain symmetric pill existed. Motion mode is the ONLY place these
   handles actually render (Parent-in-Time anchors are Motion-only too), so
   the batch-A restyle's new pill never actually reached the screen — this
   override was clobbering it back to the old look every time.
   2026-08-16 second fix (Cyril, live: "c'est un rond pas une barre... le
   rond de parentage est collé à la barre de poignée") — the first fix above
   widened this to 9px without touching height, which on Motion's 18px bar
   (ROW_H 22, handle inset top/bottom:3 -> 12px tall) reads as a near-square
   BLOB, not the doc's elongated pill (.handle{width:5px;height:18px} on its
   own 30px bar — a ~0.28 width/height ratio). Matching that ratio here
   (12px tall -> ~3-4px wide) both restores the pill silhouette AND stops it
   visually merging with the timelink-anchor dot sitting at the bar's very
   edge (that dot's position never moved; only the handle had grown wide
   enough to reach under it). */
body.mode-motion .layer-inout-bar .layer-inout-handle{width:4px;border-radius:2px;opacity:1;}
/* États (spec): repos -> pill désaturée · survol -> blanc pur + halo,
   ew-resize · drag -> conserve l'état survol tant que le bouton est
   enfoncé, même hors zone (.hot is toggled by onDown/mouseup in
   layer-inout.js — it already drove the state machine, this is the first
   CSS that actually paints it; before this the handle visually reverted to
   idle mid-drag the instant the cursor left its bounds). */
.layer-inout-handle:hover,.layer-inout-handle.hot{background:var(--pill-hot,#fff);box-shadow:0 0 0 3px rgba(255,255,255,.18);}
/* Selected handles need to remain unmistakable against every possible
   layer tint. The dark core alone proved too close to several muted layer
   colours (feedback #56), so the compact pill now gets a crisp white edge
   plus the same blue selection halo used elsewhere. This outlines the
   HANDLE only — it does not resurrect the old full-bar selection rectangle. */
.layer-inout-handle.sel,.layer-inout-handle.sel.hot{background:#11141b;box-shadow:0 0 0 1px rgba(255,255,255,.92),0 0 0 3px rgba(74,158,255,.62);}
.layer-inout-handle.sel:hover{background:#05070b;box-shadow:0 0 0 1px #fff,0 0 0 3px rgba(74,158,255,.8);}
/* Parent in Time — on-timeline connection points (2026-07-30, Van Dijk
   2.1: Shift+[ / Shift+] / Shift+\ "create connection point on In Point /
   Out Point / the Layer"). Restyled 2026-08-16 (nemo-timeline-inout-
   spec.html): moved from sitting ABOVE the bar's top edge to CENTERED on
   the bar's own vertical middle, diameter matched to the handle's own
   width so the two read as one calibrated module instead of two unrelated
   ones fighting for the same corner ("deux modules graphiques différents
   pour des objets voisins" — the spec's own complaint about the old
   top-edge placement). Horizontally still half-in/half-out of the bar edge
   via left:0/50%/100% + a negative margin equal to half its own new
   diameter (in/out) — unchanged mechanism, just re-tuned to the new size.
   2026-08-16 second fix: was 9px to match body.mode-motion's handle width
   at the time — that handle has since shrunk to 4px (see its own comment,
   "c'est un rond pas une barre"), leaving this dot oversized enough to
   physically overlap the handle instead of sitting flush beside it
   ("le rond de parentage est collé à la barre de poignée"). 6px keeps the
   doc's own ~1.4x dot/handle diameter ratio (.link-dot 7px on a .handle
   5px) instead of literally matching the handle's width. These anchors
   only ever render in Motion mode (the only place buildBar's on-bar
   Parent-in-Time UI is used), so there's no base/Motion split to keep in
   sync here the way the handle itself needs one. */
.layer-inout-bar .timelink-anchor{position:absolute;top:50%;width:6px;height:6px;margin-top:-3px;margin-left:-3px;
  border-radius:50%;border:1.5px solid var(--text-dim);background:var(--panel2);cursor:alias;
  opacity:0;pointer-events:none;z-index:5;transition:opacity .12s linear,background .12s linear,border-color .12s linear;}
/* Widened hitbox (spec: "±4 px") — a 9px dot is a small target even before
   accounting for it being half-hidden by design. */
.layer-inout-bar .timelink-anchor::before{content:'';position:absolute;inset:-4px;}
/* Visibility (spec: "un point engagé dans un lien est affiché en
   permanence ; Alt maintenu... ne révèle que les points encore libres") —
   base state above is fully hidden/inert; #frame-grid.timelink-alt (Alt
   held, see setTimeLinkAltReveal in layer-inout.js) reveals EVERY anchor
   including free ones, while .is-child/.is-parent opt back into visibility
   unconditionally regardless of Alt, since an already-engaged point's role
   should never depend on a held key to be legible. */
#frame-grid.timelink-alt .layer-inout-bar .timelink-anchor,
.layer-inout-bar .timelink-anchor.is-child,
.layer-inout-bar .timelink-anchor.is-parent{opacity:1;pointer-events:auto;}
.layer-inout-bar .timelink-anchor:hover{border-color:var(--accent,#5b6cff);box-shadow:0 0 0 2px rgba(91,108,255,.25);}
.layer-inout-bar .timelink-anchor.in{left:0;}
.layer-inout-bar .timelink-anchor.out{left:100%;}
.layer-inout-bar .timelink-anchor.whole{left:50%;}
/* État des ronds (spec): "le rôle se lit à la couleur — enfant -> rond
   plein foncé, parent -> rond plein clair. Un point à la fois enfant et
   parent : fond foncé, contour clair." No connection line between points
   at all — color alone carries the relationship, matching the spec's own
   explicit "pas de trait" rule (this codebase's separate .has-timelink
   whole-bar bottom-border hint, just below, stays as a coarser "this layer
   participates somehow" signal — the dots now carry the precise role). */
.layer-inout-bar .timelink-anchor.is-child{background:#04382E;border-color:#04382E;}
.layer-inout-bar .timelink-anchor.is-parent{background:#fff;border-color:#fff;}
.layer-inout-bar .timelink-anchor.is-child.is-parent{background:#04382E;border-color:#fff;}
.layer-inout-bar.has-timelink{border-bottom:2px solid var(--accent,#5b6cff);}

/* Multi-select (marquee rect -> group-drag several layers' bars together,
   layer-inout.js) */
.layer-inout-bar.sel{box-shadow:0 0 0 1.5px #fff;}
.layer-inout-marquee-rect{position:fixed;border:1px solid var(--accent);background:rgba(63,107,245,.15);pointer-events:none;z-index:50;}
.fc.io-dim{background:rgba(0,0,0,.35);opacity:.4;}
/* Per-keyframe tick marks inside the in/out bar (layer-inout.js
   renderKeyTicks) — one per Animation 2D "full" keyframe, draggable to
   retime that keyframe without leaving Motion mode. */
/* z-index:6, above #playhead's 5 (2026-08-16, Cyril: "si je met une
   keyframe l'indicateur de frame disparait") — F6/insertKeyframe always
   inserts AT state.currentFrame, so a freshly-placed keyframe's tick and
   the playhead sit at the EXACT same x the instant it's created. #playhead
   has a solid 2px accent-blue border-left at z-index:5, previously higher
   than this tick's z-index:3 — it fully painted over the tick, so the very
   moment you placed a keyframe, its marker looked like it had vanished
   (it hadn't; it just moved). Confirmed live: moving the playhead one
   frame away instantly revealed the tick was there all along. */
.layer-inout-bar .layer-inout-key{position:absolute;top:0;bottom:0;width:3px;margin-left:-1.5px;background:#fff;opacity:.85;cursor:ew-resize;z-index:6;border-radius:1px;}
.layer-inout-bar .layer-inout-key:hover{opacity:1;background:var(--accent);width:4px;margin-left:-2px;}
/* Blank-keyframe gaps inside the bar (layer-inout.js renderContentGaps,
   2026-07) — dims a genuinely empty stretch instead of letting it read as
   solid content, pointer-events:none so the bar underneath stays
   draggable through it. Hollow dot at the blank keyframe that closes each
   segment, matching Animation 2D's own full/hollow keyframe-dot
   convention (a filled tick already marks the segment's start, see
   .layer-inout-key above). */
.layer-inout-bar .layer-inout-seg-gap{position:absolute;top:0;bottom:0;background:var(--panel);opacity:.82;pointer-events:none;z-index:1;}
.layer-inout-bar .layer-inout-segdot{position:absolute;top:50%;width:7px;height:7px;margin:-3.5px 0 0 -3.5px;border-radius:50%;background:transparent;border:1.5px solid #fff;pointer-events:none;z-index:4;}
/* Kept at the exact same top/height as .onion-marker above (both moved to
   #bars-row's lower sub-row together, round 3 of the audit, then shifted
   again in round 4 when #wa-bar's own height doubled) so the gradient bar
   and its in/out markers still read as one aligned control. */
#onion-bar{position:absolute;top:15px;height:6px;background:linear-gradient(90deg,rgba(255,80,80,.35),rgba(80,140,255,.35));border-radius:2px;pointer-events:none;z-index:2;}
/* v4: the mockup's frame ruler sits flush in the SAME --panel tone as the
   frame grid below it (just a hairline border-bottom) — it previously used
   --panel2 here, which read as a separate lighter bar boxed above the
   timeline instead of blending straight into it. */
/* Design audit 2026-07, round 3 (feedback: "ruler un peu petite en
   hauteur"): 16px→20px, on top of the round-1 14px→16px bump — gives the
   per-frame ticks below real room to be visible instead of squeezed into
   a couple of leftover px under the numerals.
   ⚠️ ALIGNMENT: #bars-row's `top` (above) and #layer-panel's "Layers"
   header (index.html, inline height) both key off this exact value —
   see the big comment on #bars-row for the full chain.
   Round 5: background --panel2 (darker), matching the "Layers" header —
   see #bars-row's own round-5 note, same reasoning applies here. */
#frame-hdr{display:flex;height:20px;border-bottom:1px solid var(--border);flex-shrink:0;background:var(--panel2);position:sticky;top:0;z-index:2;cursor:pointer;}
/* 8px→9px (round 1): was the smallest text anywhere in the app (Motion's
   own property rows run 10.5px). padding-top (not the old `top:-1px`
   nudge, which fought align-items:center) now reserves clear room below
   the text for the taller round-3 tick marks instead of the two visually
   colliding at this row's old, tighter height. */
.fhc{width:var(--fc);min-width:var(--fc);font-size:9px;color:var(--text-dark);display:flex;align-items:flex-start;justify-content:center;padding-top:3px;box-sizing:border-box;position:relative;}
.fhc:nth-child(5n){color:var(--text-dim);}
/* Real tick marks (round 1 finding: the ruler previously had NO physical
   graduation at all, only a text-color change every 5th cell). Three
   tiers, tallest/brightest wins on a coincidence (CSS specificity alone
   handles that: .sec has 2 classes, :nth-child(5n) has 1 class + a
   pseudo-class, the plain per-frame rule has 1 class — no !important or
   explicit override needed):
     - every frame:  round 3 bumped from 2px/.07 to 4px/.16 (feedback:
       "indicateur de frame pas assez visible") — the round-2 version all
       but disappeared once actually seen live; still clearly the lightest
       of the three tiers, just no longer invisible.
     - every 5th:    6px/.32 — the mid-level landmark.
     - each second:  tallest/brightest (::before below) — the label
       ("1s"/"2s") already gets the same priority treatment. */
.fhc::before{content:'';position:absolute;left:0;bottom:0;width:1px;height:4px;background:rgba(255,255,255,.16);}
.fhc:nth-child(5n)::before{height:6px;background:rgba(255,255,255,.32);}
.fhc.cur{color:var(--accent);font-weight:700;}
.fhc.sec{color:var(--accent);font-weight:700;font-size:8.5px;}
.fhc.sec::before{content:'';position:absolute;left:0;top:0;bottom:-2px;width:1px;background:rgba(255,255,255,.3);}
/* position+z-index gives #frame-grid its OWN stacking context, so any
   z-index set on its descendants (Motion's per-row .layer-inout-bar,
   layer-inout.js — inline `position:relative` with no z-index of its own,
   which does NOT form a stacking context by itself) stays CONTAINED here
   instead of bubbling up to compete directly against #frame-hdr/#bars-row
   (z-index:2 each, sticky, meant to stay pinned on top while scrolling).
   Without this, a scrolled-past layer row painted over the ruler/onion/
   work-area bars — confirmed live: elementFromPoint() over #bars-row hit
   a .layer-inout-bar instead. z-index:1 (below frame-hdr/bars-row's 2) so
   this box itself never outranks them either. */
#frame-grid{display:flex;flex-direction:column;position:relative;z-index:1;}
/* Must stay in lockstep with .lrow's height (28px, v3 redesign) — the layer
   name column (#layer-panel) and the frame grid (#fg-wrap) are separate
   flex columns rendered independently, so any mismatch between .lrow's and
   .frow's height drifts the two out of alignment, worse with every row
   (this was exactly that bug: .lrow went to 28px in the redesign but .frow/
   .fc were left at the old 24px). */
.frow{display:flex;height:34px;border-bottom:1px solid var(--border);flex-shrink:0;}
/* v4: active layer's frame-grid band gets the same blue tint/accent-bar
   treatment as its .lrow counterpart (see above) — the mockup highlights
   the whole timeline row, not just the layer-name column. */
/* Lower alpha than the original mockup value (.16) — at full strength the
   blue wash sat in FRONT of (or muddied, depending on layer color/lightness)
   the per-layer keyframe span tints on top of it, per feedback. The .fc
   children's own ::before span backgrounds already paint over this (later
   in paint order = child backgrounds sit above the parent .frow's own
   background), so this is now closer to a faint wash than a foreground
   tint — the 3px accent bar carries most of the "this row is active" cue. */
.frow.act{background:rgba(63,107,245,.07);box-shadow:inset 3px 0 0 #4E6FF2;}
/* v4: mockup's grid lines are a subtle white-on-dark tick pattern
   (rgba(255,255,255,.03) every frame, rgba(255,255,255,.06) every 5th) —
   the old rgba(60,60,60,.3) gray borders read as a much busier/darker
   grid by comparison. */
.fc{width:var(--fc);min-width:var(--fc);height:34px;border-right:1px solid rgba(255,255,255,.06);cursor:pointer;position:relative;display:flex;align-items:center;justify-content:center;}
.fc:nth-child(5n){border-right-color:rgba(255,255,255,.11);}
.fc:hover{background:rgba(255,255,255,.05);}
.fc.cur{background:transparent;}
/* Animate-style span language: a FULL span (held drawing) reads as one
   continuous light band from its keyframe to the span end (inner cell
   borders suppressed so it looks like one block), an EMPTY span stays
   near-transparent, and the last cell of any span carries a small hollow
   end-rectangle — the three states are distinguishable at a glance.
   v4: tinted with the owning layer's own color (--dot-rgb, set alongside
   --dot-color in renderKeyframeCellsInto) instead of a generic gray, to
   match the mockup's per-channel-colored spans; falls back to the old
   neutral gray triplet for any layer without a color yet. */
/* v5: mockup renders the span tint as a SLIM band inset from the row's
   top/bottom (~16px out of a 36px row there), not a full-height cell fill
   — moved onto a ::before so the visible band reads as a slimmer pill
   instead of a solid block, closer to the mockup's proportions. */
/* v12: kept a faint separator even across a colored span instead of fully
   transparent — the old version suppressed every internal frame divider
   the moment a span existed, so most of a real timeline (anything with
   held content, i.e. almost everything) showed no per-frame grid at all.
   Dark rather than white here since it sits on top of a light colored
   tint, where a white line all but disappears. */
.fc.kf-full,.fc.kf-empty,.fc.span-full,.fc.span-empty{border-right-color:rgba(0,0,0,.14);}
.fc.kf-full::before,.fc.kf-empty::before,.fc.span-full::before,.fc.span-empty::before{content:'';position:absolute;left:0;right:0;top:6px;bottom:6px;pointer-events:none;}
.fc.kf-full::before{background:rgba(var(--dot-rgb,154,154,175),.28);}
.fc.kf-empty::before{background:rgba(255,255,255,.04);}
.fc.span-full::before{background:rgba(var(--dot-rgb,154,154,175),.20);}
.fc.span-empty::before{background:rgba(255,255,255,.03);}
/* Cursor hints the drag affordance across the whole cell — the actual grab
   zone (JS mousedown handler) covers the right ~65% of it, wider than the
   small resting square graphic alone would suggest. */
/* v8: replaced the small square handle entirely — at this cell width (16px)
   a 10x10 square read as near-identical to the round keyframe dot next to
   it (confirmed confusing per feedback) and was a genuinely fiddly target.
   Now a vertical grab-BAR spanning most of the row height, clearly a
   different shape from any dot, and the grab zone is the cell's full width
   (see the JS mousedown handler) instead of a fraction of it — no more
   guessing where exactly within the cell you need to click. */
.fc.span-end{border-right:1px solid var(--border);cursor:ew-resize;}
.fc.span-end::after{content:'';position:absolute;right:2px;width:4px;height:20px;border-radius:2px;background:rgba(var(--dot-rgb,200,200,214),.55);cursor:ew-resize;}
.fc.span-end:hover::after{background:var(--accent);width:5px;}
/* v6/v8: the outpoint drag previously left the OLD marker frozen at its
   original cell while a plain highlight tracked the cursor elsewhere — two
   disconnected visual cues. Now the entire prospective span (source
   keyframe up to the drag position) tints continuously as you drag, like
   watching the held region actually grow/shrink in real time, with the
   grab-bar itself relocating to wherever the cursor currently is — not
   just the single target cell lighting up in isolation. */
.fc.span-drag-band{background:var(--accent-dim);}
.fc.span-drag-preview::after{content:'';position:absolute;right:2px;width:5px;height:22px;border-radius:2px;background:var(--accent);}
/* v9: fully HIDING the original grab-bar during the drag (opacity:0) made
   it look like the marker had vanished rather than moved — feedback: "il
   faudrait laisser la barre bleue d'outpoint et la clé d'après visuellement
   pendant le drag". Dimmed instead of hidden: the original position stays
   as a faint reference for "where it was" while the span-drag-preview
   band/square/dot (still full opacity) shows "where it'll land" — both
   visible at once, distinguishable by opacity alone. */
.fc.span-end.tl-outdrag-source-end::after{opacity:.35;}
/* v10: at the very start of a drag (before the cursor has crossed into a
   new cell), the LIVE preview and the dimmed SOURCE are still the exact
   same DOM cell — CSS doesn't pick one rule over the other for non-
   conflicting properties, so the dim rule's opacity:.35 above ALSO applied
   to the preview's ::after (same pseudo-element), making the live bar
   look faded/"disappeared" right as the drag began — feedback: "la barre
   bleu disparait pendant le drag". Forces the moving preview back to full
   opacity whenever it lands on the same cell as the dimmed source. */
.fc.span-drag-preview.tl-outdrag-source-end::after{opacity:1;}
.fc.span-drag-dot-cell.tl-outdrag-source-key .km{opacity:1;}
/* v7: when the drag will actually relocate a real bordering keyframe (the
   "trim" path, not "insert a new one"), the cell ONE FRAME TO THE RIGHT of
   the bar (span-drag-dot-cell, timeline.js mousemove) gets a live preview
   dot in the SAME style a committed keyframe dot would have — same
   adjacency the real bar+dot pair already have when nothing is dragging.
   (v9 had this dot sharing the BAR's own cell instead — a stray
   `::after{display:none}` selector meant for a different purpose ended up
   matching that shared cell too and hid the bar's own pseudo-element,
   which was the actual cause of "la barre bleu disparait pendant le
   drag". Splitting the bar cell and the dot cell removes the collision
   entirely instead of papering over it.) */
.fc .km.drag-key-preview{opacity:1;}
.fc.tl-outdrag-source-key .km{opacity:.35;}
.fc.tw{background:var(--tween-color);}
/* A tween frame the user hand-corrected reads in green instead of the
   normal tween blue — a silent re-tween would otherwise wipe the fix out
   without warning, so this is the visual cue that something here needs
   the "skip manually-edited frames" option respected. */
.fc.tw-manual{background:rgba(90,247,142,.20);}
.fc .km{width:9px;height:9px;border-radius:50%;position:absolute;z-index:1;}.fc .km:hover{transform:scale(1.4);transition:transform .1s;}
/* Real keyframe markers (fl/hl) are small squares, not circles (2026-07,
   "petit carré draggable") — distinguishes an actually-draggable keyframe
   dot from the plain round tween tick (.td below, never draggable) at a
   glance, and doubles as the visual cue that grabbing it moves the key
   (see timeline.js's frame-grid mousedown handler). */
.fc .km.fl{background:var(--dot-color,var(--key-color));box-shadow:0 0 0 1px rgba(0,0,0,.35);border-radius:2px;cursor:grab;}
.fc .km.hl{border:1.5px solid var(--dot-color,var(--key-color));background:transparent;border-radius:2px;cursor:grab;}
.fc .km.td{background:var(--accent);width:5px;height:5px;}
.fc .km.td.manual{background:var(--green);}
/* WKWebView (Tauri) bug found 2026-07: without a forced compositing layer,
   this element's z-index:5 sometimes doesn't win over the sticky
   #frame-hdr/#bars-row (z-index:2) — #playhead-flag renders behind their
   opaque background and is invisible, EXCEPT right after any window
   resize/relayout (confirmed live: opening devtools, which resizes the
   webview, made the flag reappear correctly). transform:translateZ(0)
   forces #playhead onto its own GPU layer so WebKit paints it above the
   sticky siblings consistently, with no functional change in Chrome/other
   browsers (already correct there). */
#playhead{position:absolute;top:0;width:var(--fc);pointer-events:none;z-index:5;border-left:2px solid var(--accent);background:transparent;transform:translateZ(0);}
/* UI/UX audit (2026-07): a small flag/triangle handle sitting in the
   bars-row (top 16px of #fg-wrap, above the ruler) — the one part of the
   playhead's height that isn't already covered by frame cells, so it
   doesn't compete with clicking a specific frame. pointer-events:auto
   deliberately overrides the parent's :none — this is the ONE grabbable
   part of an otherwise click-through indicator. */
/* Round 3 (2026-07, "est ce que l'on pourrait avoir un rectangle qui
   affiche le numéro d'image à la place du triangle ?"): the shape itself
   IS the badge now — a small rounded rectangle containing the frame
   number as text (set by updatePlayhead(), timeline.js), not a decorative
   ::before circle anymore. width:auto (content-driven, via padding) so it
   grows for 2-3 digit frame numbers without clipping; centered on the
   line via transform:translateX(-50%), which centers on the element's
   OWN rendered width regardless of how many digits it holds — the fixed-
   px centering math from rounds 1-2 only worked for a fixed-size shape.
   left:-1px (not 0) carries forward that same math: #playhead's own
   border-left:2px shifts this child's box origin 2px right of the
   border's own edge, so translateX(-50%) alone would center 2px off —
   -1px moves the origin back to the border's own visual MIDDLE
   (edge+1px, a 2px-wide line), matching rounds 1-2's finding exactly. */
#playhead-flag{position:absolute;top:0;left:-1px;transform:translateX(-50%);min-width:18px;height:14px;padding:0 4px;box-sizing:border-box;display:flex;align-items:center;justify-content:center;font:600 9px/1 var(--font-mono,monospace);color:#fff;background:var(--accent);border-radius:3px;white-space:nowrap;pointer-events:auto;cursor:ew-resize;box-shadow:0 1px 3px rgba(0,0,0,.4);transition:transform .1s,background .1s,color .1s;}
#playhead-flag:hover{transform:translateX(-50%) scale(1.15);background:#fff;color:var(--accent);}
.fc.outside-wa{opacity:.35;}
.fc.sel{background:rgba(74,158,255,.28);box-shadow:inset 0 0 0 1px rgba(74,158,255,.5);}
.fc.sel.cur{background:rgba(74,158,255,.38);}
.tl-drag-ghost{position:absolute;pointer-events:none;z-index:12;opacity:.7;}
.tl-drag-ghost .fc{background:rgba(74,158,255,.35);border:1px solid var(--accent);box-sizing:border-box;}
/* The span a keyframe is being dragged OUT of, for the duration of the
   drag (see fadeDragSourceSpans in timeline.js) — recedes instead of
   staying fully solid while the ghost preview shows the new location. */
.fc.tl-drag-fading{opacity:.32;}

/* STATUSBAR */
#statusbar{height:20px;flex-shrink:0;background:transparent;border-top:none;display:flex;align-items:center;justify-content:space-between;padding:0 6px;font-size:10.5px;color:rgba(236,234,231,.4);font-weight:500;}
#statusbar>span:first-child{display:flex;gap:16px;}
.sc{background:transparent;color:rgba(236,234,231,.6);font-weight:700;padding:0;border-radius:0;font-family:inherit;font-size:10.5px;margin:0 3px 0 0;}
#toast{position:fixed;bottom:40px;left:50%;transform:translateX(-50%) translateY(20px);background:var(--panel3);color:var(--text);padding:6px 16px;border-radius:6px;font-size:11px;opacity:0;pointer-events:none;transition:opacity .25s,transform .25s;z-index:100;border:1px solid var(--border);}
#toast.show{opacity:1;transform:translateX(-50%) translateY(0);}
::-webkit-scrollbar{width:6px;height:6px;}
::-webkit-scrollbar-track{background:var(--bg);}
::-webkit-scrollbar-thumb{background:var(--border2);border-radius:3px;}

/* SYMBOL TABS */
/* v4: nested inside #tl-toolbar now (see index.html) — no longer its own
   44px bar above the transport controls, so it inherits height/background
   from the parent row instead of setting its own. */
#symbol-tabs{display:flex;align-items:center;background:transparent;border-bottom:none;height:100%;flex-shrink:0;overflow-x:auto;padding:0;gap:24px;}
.sym-tab{display:flex;align-items:center;gap:9px;padding:0;font-size:12.5px;font-weight:500;color:rgba(236,234,231,.35);cursor:pointer;border-right:none;white-space:nowrap;}
.sym-tab::before{content:'';width:9px;height:9px;border-radius:50%;background:#4a4852;flex-shrink:0;}
.sym-tab.act{color:var(--text);background:transparent;border-bottom:none;font-weight:600;}
.sym-tab.act::before{background:var(--green);}
.sym-tab .sym-tab-x{font-size:12px;line-height:1;color:var(--text-dim);}
.sym-tab .sym-tab-x:hover{color:var(--text);}
.lico.comp-badge{color:var(--accent);}
.lrow.is-comp .lnm{font-style:italic;}
/* Layer type badge (layer-kind.js). Drawing layers get none — they are the
   default, and a badge on every row would be noise rather than information;
   the badge's job is to make the exceptions stand out. Tinted per kind so
   the type reads before the icon is even resolved: footage warm, generated
   content cool, structural neutral. */
.lkind{width:16px;flex:none;display:flex;align-items:center;justify-content:center;opacity:.85;}
.lkind svg{display:block;}
.lkind-image,.lkind-sequence,.lkind-video{color:#e0a45e;}
.lkind-camera{color:#ffaa28;}
.lkind-effect{color:#7fd1c8;}
.lkind-text{color:#c9a0ff;}
.lkind-component{color:#8fa6ff;}
.lkind-montage{color:#8fa6ff;}
.lkind-null{color:rgba(236,234,231,.4);}
.lrow.lfolder{background:var(--panel2);cursor:default;}
.lrow.lfolder:hover{background:var(--panel2);}
.lrow.in-folder{padding-left:16px;}
.larrow{cursor:pointer;font-size:10px;}
.larrow-spacer{cursor:default;visibility:hidden;}
.frow.ffolder{background:var(--panel2);}
.frow.ffolder-collapsed{opacity:.85;}
.frow.ffolder-collapsed .fc::before{content:'';position:absolute;inset:0;background:var(--accent);opacity:.06;pointer-events:none;}

/* TOOLTIP */
#ui-tip{position:fixed;z-index:400;background:var(--panel3);border:1px solid var(--border2);color:var(--text);
  font-size:10px;padding:4px 9px;border-radius:6px;pointer-events:none;opacity:0;transition:opacity .12s;
  box-shadow:0 4px 16px rgba(0,0,0,.45);white-space:nowrap;max-width:280px;}
#ui-tip.show{opacity:1;}

/* CONTEXT MENU */
.ctx-menu{position:fixed;background:var(--panel2);border:1px solid var(--border2);border-radius:6px;box-shadow:0 8px 28px rgba(0,0,0,.5);z-index:300;padding:4px;min-width:190px;font-size:11px;}
.ctx-item{padding:6px 10px;border-radius:4px;cursor:pointer;color:var(--text);display:flex;align-items:center;justify-content:space-between;gap:12px;white-space:nowrap;}
.ctx-item:hover{background:var(--accent);color:#fff;}
.ctx-item.disabled{color:var(--text-dark);cursor:default;}
.ctx-item.disabled:hover{background:none;color:var(--text-dark);}
.ctx-item .ctx-sc{font-size:9px;color:var(--text-dim);font-family:monospace;}
.ctx-item:hover .ctx-sc{color:rgba(255,255,255,.8);}

/* COLOR PALETTE PANEL */
.palette-tabs{display:flex;flex-wrap:wrap;gap:2px;border-bottom:1px solid var(--border);padding-bottom:4px;margin-bottom:2px;}
.palette-tabs .sym-tab{border-radius:4px;border-right:none;padding:3px 8px;}
.palette-grid{display:grid;grid-template-columns:repeat(8,1fr);gap:4px;padding:2px 0;}
.palette-swatch{width:100%;aspect-ratio:1;border-radius:4px;border:1px solid var(--border2);cursor:pointer;padding:0;position:relative;
  background-image:linear-gradient(45deg,#3a3a48 25%,transparent 25%),linear-gradient(-45deg,#3a3a48 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#3a3a48 75%),linear-gradient(-45deg,transparent 75%,#3a3a48 75%);
  background-size:8px 8px;background-position:0 0,0 4px,4px -4px,-4px 0;background-color:#232330;}
.palette-swatch:hover{border-color:var(--accent);transform:scale(1.08);}
.palette-swatch::after{content:'';position:absolute;inset:0;border-radius:3px;background-color:var(--sw-color);}
.palette-swatch.armed{border-color:#ffb86c;box-shadow:0 0 0 1px #ffb86c;}
/* Rings the swatch(es) matching the color live in the Fill/Stroke picker
   popover (feedback #20) — distinct color from .armed (replace mode) so
   the two never look the same. */
.palette-swatch.sel-match{border-color:var(--accent);box-shadow:0 0 0 2px var(--accent);}
#btn-palette-replace.active{background:var(--accent);color:#fff;border-color:var(--accent);}

/* BRUSH PRESET PICKER */
.bp-swatch-btn{flex:1;display:flex;align-items:center;gap:6px;background:var(--bg);border:1px solid var(--border);border-radius:4px;padding:3px 6px;cursor:pointer;color:var(--text);min-width:0;}
.bp-swatch-btn:hover{border-color:var(--border2);}
.bp-swatch-btn.disabled,.bp-swatch-btn:disabled{opacity:.4;cursor:not-allowed;}
.bp-swatch-btn.disabled:hover,.bp-swatch-btn:disabled:hover{border-color:var(--border);}
.bp-swatch-btn canvas{width:60px;height:16px;flex-shrink:0;border-radius:2px;background:var(--panel3);}
.bp-swatch-btn span{font-size:9px;color:var(--text-dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.bp-picker-pop{width:240px;max-height:400px;overflow-y:auto;padding:8px;display:flex;flex-direction:column;gap:2px;}
.bp-group-label{font-size:9px;font-weight:700;color:var(--text-dim);text-transform:uppercase;letter-spacing:.04em;padding:6px 2px 2px;}
.bp-grid{display:flex;flex-direction:column;gap:2px;}
.bp-item{display:flex;align-items:center;gap:8px;background:transparent;border:1px solid transparent;border-radius:4px;padding:4px 6px;cursor:pointer;color:var(--text);text-align:left;}
.bp-item:hover{background:var(--panel3);}
.bp-item.active{border-color:var(--accent);background:rgba(74,158,255,.12);}
.bp-item canvas{width:110px;height:16px;flex-shrink:0;border-radius:2px;background:var(--panel3);}
.bp-item span{font-size:10px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.bp-item-custom{position:relative;padding-right:20px;}
.bp-item-del{position:absolute;right:4px;top:50%;transform:translateY(-50%);width:14px;height:14px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:11px;line-height:1;color:var(--text-dim);}
.bp-item-del:hover{background:var(--red);color:#fff;}
.bp-edit-btn{margin-top:6px;padding:7px;border-radius:4px;border:1px dashed var(--border2);background:transparent;color:var(--text-dim);font-size:10px;cursor:pointer;}
.bp-edit-btn:hover{color:var(--text);border-color:var(--accent);}
/* Favorite star toggle on each popover row (feedback #81) — sits where
   .bp-item-del sits for a custom preset, so a custom row gets both (star
   further left, delete stays pinned to the edge). Hidden until hover/active
   so the row doesn't look cluttered by default, same convention as most
   icon-only row actions elsewhere in this app. */
.bp-item{position:relative;padding-right:22px;}
.bp-item-custom{padding-right:40px;}
.bp-item-fav{position:absolute;right:4px;top:50%;transform:translateY(-50%);width:16px;height:16px;display:flex;align-items:center;justify-content:center;font-size:12px;line-height:1;color:var(--text-dim);opacity:0;cursor:pointer;}
.bp-item-custom .bp-item-fav{right:20px;}
.bp-item:hover .bp-item-fav,.bp-item-fav.is-fav{opacity:1;}
.bp-item-fav.is-fav{color:#ffc94a;}
.bp-item-fav:hover{color:#ffc94a;transform:translateY(-50%) scale(1.15);}
/* Favorites quick strip under the Brush row in Stroke (feedback #81) */
.bp-fav-row{display:flex;flex-wrap:wrap;gap:4px;padding-top:2px;}
.bp-fav-item{width:26px;height:26px;border-radius:5px;border:1px solid var(--border2);background:var(--panel3);padding:0;cursor:pointer;overflow:hidden;flex:none;}
.bp-fav-item:hover{border-color:var(--accent);}
.bp-fav-item.active{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent);}
.bp-fav-item canvas{width:100%;height:100%;display:block;}
/* Brush floating menu (2026-07, brush-menu-bridge.js) — reuses .bp-grid/
   .bp-item/.bp-group-label above verbatim for the thumbnail lists (same
   visual language, no second style to keep in sync); only new rules are
   the popover's own wider frame, its Vecteur/Bitmap tab strip, and the
   condensed parameter footer. */
/* 2026-07 relayout — feedback: "garde les options en header pas tout en
   bas des brush". The popover itself no longer scrolls as one column;
   tabs + params are a fixed, always-visible header, and ONLY
   .brush-menu-scroll (the preset grids) scrolls independently below it —
   so Taille/Lissage/etc. stay put no matter how long the preset list is. */
.brush-menu-pop{width:300px;height:min(520px,calc(100vh - 16px));padding:8px;display:flex;flex-direction:column;gap:2px;overflow:hidden;}
.brush-menu-tabs{display:flex;gap:2px;margin-bottom:6px;background:var(--panel3);border-radius:5px;padding:2px;flex-shrink:0;}
.brush-menu-tab{flex:1;background:transparent;border:none;border-radius:4px;padding:6px 0;color:var(--text-dim);font-size:10px;font-weight:600;cursor:pointer;text-transform:uppercase;letter-spacing:.03em;}
.brush-menu-tab.active{background:var(--accent);color:#fff;}
.brush-menu-params{border-bottom:1px solid var(--border2);margin-bottom:6px;padding-bottom:6px;display:flex;flex-direction:column;gap:4px;flex-shrink:0;}
.brush-menu-scroll{flex:1;overflow-y:auto;display:flex;flex-direction:column;gap:2px;min-height:80px;}
.brush-menu-pop .bp-item canvas{width:130px;height:22px;}

/* SHADOW BRUSH popover (2026-07, shadow-brush-bridge.js) — small swatch
   picker, same .ctx-menu shell as brush-menu-pop but sized to its content
   instead of that one's fixed 300px catalog width. */
.shadow-brush-pop{width:auto;padding:8px;display:flex;flex-direction:column;gap:4px;}

/* BRUSH EDITOR PANEL */
.bp-editor-pop{width:320px;padding:12px;display:flex;flex-direction:column;gap:6px;}
.bpe-preview-wrap{background:var(--panel3);border-radius:4px;padding:4px;}
#bpe-preview{width:100%;height:60px;display:block;}
.bpe-row{display:flex;align-items:center;gap:8px;}
.bpe-lbl{font-size:9px;color:var(--text-dim);width:100px;flex-shrink:0;}
.bpe-slider{flex:1;accent-color:var(--accent);}
.bpe-val{font-size:9px;color:var(--text-dim);width:32px;text-align:right;flex-shrink:0;}
.bpe-rotmode{flex:1;background:var(--bg);border:1px solid var(--border);color:var(--text);border-radius:4px;padding:4px;font-size:10px;}
.bpe-name-input{flex:1;background:var(--bg);border:1px solid var(--border);color:var(--text);border-radius:4px;padding:5px 7px;font-size:11px;}
.bpe-actions{display:flex;gap:6px;justify-content:flex-end;margin-top:4px;}
.bpe-capture-row #bpe-capture-status{width:auto;text-align:left;flex:1;}

/* COLOR PICKER POPOVER */
.color-picker-pop{min-width:auto;width:196px;padding:8px;display:flex;flex-direction:column;gap:8px;}
.cp-sv{position:relative;width:180px;height:140px;border-radius:4px;overflow:hidden;cursor:crosshair;}
.cp-sv-canvas{display:block;width:180px;height:140px;}
.cp-sv-thumb{position:absolute;width:10px;height:10px;border:2px solid #fff;border-radius:50%;box-shadow:0 0 0 1px rgba(0,0,0,.5);transform:translate(-5px,-5px);pointer-events:none;}
.cp-hue{position:relative;width:180px;height:14px;border-radius:3px;overflow:hidden;cursor:pointer;}
.cp-hue-canvas{display:block;width:180px;height:14px;}
.cp-hue-thumb{position:absolute;top:-1px;width:6px;height:16px;border:2px solid #fff;border-radius:2px;box-shadow:0 0 0 1px rgba(0,0,0,.5);transform:translateX(-3px);pointer-events:none;}
.cp-alpha{position:relative;width:180px;height:14px;border-radius:3px;overflow:hidden;cursor:pointer;}
.cp-alpha-canvas{display:block;width:180px;height:14px;}
.cp-alpha-thumb{position:absolute;top:-1px;width:6px;height:16px;border:2px solid #fff;border-radius:2px;box-shadow:0 0 0 1px rgba(0,0,0,.5);transform:translateX(-3px);pointer-events:none;}
.cp-preview-row{display:flex;gap:8px;align-items:flex-start;}
.cp-preview{width:32px;height:32px;border-radius:5px;border:1px solid var(--border2);flex-shrink:0;
  background-image:linear-gradient(45deg,#3a3a48 25%,transparent 25%),linear-gradient(-45deg,#3a3a48 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#3a3a48 75%),linear-gradient(-45deg,transparent 75%,#3a3a48 75%);
  background-size:8px 8px;background-position:0 0,0 4px,4px -4px,-4px 0;background-color:#232330;}
.cp-fields{flex:1;display:flex;flex-direction:column;gap:5px;}
.cp-fields label{font-size:9px;color:var(--text-dim);display:flex;flex-direction:column;gap:2px;}
.cp-fields input{background:var(--bg);border:1px solid var(--border);color:var(--text);border-radius:4px;padding:3px 5px;font-size:10px;outline:none;width:100%;box-sizing:border-box;}
.cp-rgb-row{display:flex;gap:4px;}
.cp-rgb-row input{width:0;flex:1;text-align:center;}
.cp-swatch-row{display:flex;gap:5px;align-items:center;padding-top:2px;border-top:1px solid var(--border);}
.cp-swatch{width:20px;height:20px;border-radius:4px;border:1px solid var(--border2);cursor:pointer;padding:0;position:relative;overflow:hidden;}
.cp-swatch-none{background:repeating-linear-gradient(45deg,#2a2a38,#2a2a38 3px,#1e1e28 3px,#1e1e28 6px);}
.cp-swatch-none::after{content:'';position:absolute;top:2px;left:2px;right:2px;bottom:2px;border:1.5px solid var(--red);border-radius:2px;transform:rotate(45deg);}
.cp-eyedrop{margin-left:auto;width:22px;height:22px;border-radius:4px;border:1px solid var(--border);background:var(--panel3);color:var(--text-dim);cursor:pointer;display:flex;align-items:center;justify-content:center;}
.cp-eyedrop:hover{color:var(--text);border-color:var(--border2);}
.ctx-sep{height:1px;background:var(--border);margin:4px 2px;}
.lrow.drag-over{border-top:2px solid var(--accent);}
.lrow.dragging{opacity:.4;}

/* START SCREEN — matches the Home.dc.html design (claude.ai/design project
   "Redesign Stroke Motion Interface"): flat #201f25 cards (no border, just a
   background shift on hover), a left-aligned icon badge instead of a big
   centered glyph, Kitsu split out of the grid into its own full-width row
   with a trailing chevron, and a recents list with a colored dot + divider
   per row instead of a leading icon. */
#start-screen{position:fixed;inset:0;z-index:500;background:#0b0a0d;display:flex;align-items:center;justify-content:center;overflow-y:auto;}
#start-screen.hid{display:none;}
#start-inner{width:520px;max-width:92vw;padding:30px 0 50px;}
#start-brand{display:flex;align-items:center;justify-content:center;gap:12px;font-size:26px;font-weight:800;letter-spacing:-.3px;color:#ECEAE7;margin-bottom:36px;}
#start-brand-mark{width:44px;height:44px;display:flex;align-items:center;justify-content:center;flex:none;}
#start-cards{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin-bottom:8px;}
#start-cards:not(.has-resume) #start-resume{display:none;}
.start-card{background:#201f25;border-radius:8px;padding:26px 20px;cursor:pointer;display:flex;flex-direction:column;align-items:center;text-align:center;gap:14px;transition:background .15s;}
.start-card:hover{background:#26242c;}
.start-card-ico{width:34px;height:34px;flex:none;border-radius:8px;background:rgba(255,255,255,.06);display:flex;align-items:center;justify-content:center;color:rgba(236,234,231,.75);}
.start-card-ico-accent{background:rgba(63,107,245,.16);color:#7EA0FA;}
.start-card-title{font-weight:700;font-size:14.5px;color:#ECEAE7;}
.start-card-sub{font-size:11.5px;color:rgba(236,234,231,.4);margin-top:5px;line-height:1.4;}
.start-row{background:#201f25;border-radius:8px;padding:18px 20px;cursor:pointer;display:flex;align-items:center;gap:14px;margin-bottom:28px;transition:background .15s;}
.start-row:hover{background:#26242c;}
.start-row .start-card-ico{color:rgba(236,234,231,.55);}
.start-row-body{flex:1;min-width:0;}
.start-row .start-card-title{font-size:14px;}
.start-row .start-card-sub{margin-top:3px;}
#start-newpanel{background:#201f25;border-radius:8px;padding:16px;margin-bottom:22px;}
#start-recent-hdr,.start-recent-hdr{font-size:10.5px;font-weight:700;letter-spacing:1.4px;color:rgba(236,234,231,.35);margin-bottom:8px;padding:0 2px;text-transform:uppercase;}
#start-recent-list{background:#201f25;border-radius:8px;overflow:hidden;}
#start-recent-list:empty{display:none;}
.start-recent-row{display:flex;align-items:center;gap:12px;padding:12px 16px;cursor:pointer;border-bottom:1px solid rgba(0,0,0,.35);}
.start-recent-row:last-child{border-bottom:none;}
.start-recent-row:hover{background:#26242c;}
.start-recent-row .material-symbols-rounded{display:none;}
.start-recent-dot{width:9px;height:9px;border-radius:50%;background:#5B84F7;flex:none;}
.start-recent-name{font-size:13px;color:#ECEAE7;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.start-recent-meta{font-size:11px;color:rgba(236,234,231,.4);margin-top:2px;}
.start-recent-row.missing{opacity:.45;}
.start-recent-x{margin-left:auto;font-size:14px;color:rgba(236,234,231,.4);padding:2px 6px;border-radius:4px;flex:none;}
.start-recent-x:hover{background:rgba(255,255,255,.08);color:#ECEAE7;}
.start-empty{background:#201f25;border-radius:8px;padding:16px;font-size:12.5px;color:rgba(236,234,231,.35);}

/* MODAL */
.modal-overlay{position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:200;display:flex;align-items:center;justify-content:center;}
/* Kitsu modal (Phase 4) can be opened from the start screen (#start-screen,
   z-index:500) via its "Ouvrir depuis Kitsu…" card — every other
   .modal-overlay only ever opens from inside the already-hidden-start-screen
   editor UI, so this is the one modal that needs to outrank it. */
#kitsu-modal{z-index:600;}
.modal-box{background:var(--panel2);border:1px solid var(--border2);border-radius:12px;width:340px;box-shadow:0 12px 40px rgba(0,0,0,.5);}
.modal-hdr{display:flex;align-items:center;justify-content:space-between;padding:10px 14px;border-bottom:1px solid var(--border);font-size:12px;font-weight:600;}
.modal-x{background:none;border:none;color:var(--text-dim);font-size:16px;cursor:pointer;line-height:1;}
.modal-x:hover{color:var(--text);}
.modal-bdy{padding:12px 14px;display:flex;flex-direction:column;gap:8px;}
/* ONE label column for every dialog. Each one was internally consistent but
   they disagreed with each other — 90px in Export, 70px in Kitsu, 68px
   (the panel default) in Settings — set by per-row inline widths, so opening
   two dialogs in a row shifted the field column under you for no reason a
   reader could see. 90px because that is what the widest label actually
   needs (Export's "Format" row measures 90 in all four languages, Kitsu's
   Spanish "URL del servidor" 85); dialogs have the width to spare, unlike
   the 220px side panel where 68px was the right trade. */
.modal-bdy .pl{width:90px;flex:none;}
.modal-box.wide{width:700px;max-width:92vw;}
/* Réglages accumulates a LOT of sections (langue, sync, feedback local,
   feedback GitHub, raccourcis…) — without this the whole page scrolled
   instead of just the modal body, and the panel routinely grew taller
   than the viewport ("je vois plus rien"). Constrained to the viewport
   height minus room for the header/margins, body scrolls internally. */
#settings-modal .modal-box{max-height:88vh;display:flex;flex-direction:column;}
#settings-modal .modal-bdy{overflow-y:auto;max-height:calc(88vh - 78px);}
.settings-tabs{display:flex;gap:2px;padding:8px 14px 0;border-bottom:1px solid var(--border);flex:none;}
.settings-tab{background:none;border:none;color:var(--text-dim);font-size:11px;font-weight:600;padding:8px 12px;cursor:pointer;border-radius:6px 6px 0 0;transition:background .15s,color .15s;}
.settings-tab:hover{background:var(--panel3);color:var(--text);}
.settings-tab.active{color:var(--accent-hover);background:var(--panel3);box-shadow:inset 0 -2px 0 var(--accent);}
.fb-card{display:flex;flex-direction:column;gap:6px;padding:10px 12px;border-radius:8px;background:var(--panel3);border:1px solid var(--border);font-size:11px;}
.fb-card-head{display:flex;align-items:center;gap:6px;flex-wrap:wrap;color:var(--text-dim);font-size:10px;}
.fb-chip{display:inline-flex;align-items:center;padding:2px 7px;border-radius:10px;font-size:9px;font-weight:600;background:var(--panel);border:1px solid var(--border2);cursor:pointer;user-select:none;white-space:nowrap;}
.fb-chip.active{background:var(--accent);color:#fff;border-color:var(--accent);}
.fb-chip.label-bug{color:#ff8a8a;}
.fb-chip.label-perf{color:#ffd766;}
.fb-chip.label-idée{color:#7fe08a;}
.fb-chip.label-polish{color:#a8c8ff;}
.fb-chip.label-blocking{color:#ff5c5c;}
.fb-chip.label-pending{color:var(--text-dim);}
.fb-chip.label-resolved{color:#6fa8ff;}
.fb-card-title{font-size:12px;font-weight:600;color:var(--text);white-space:pre-wrap;}
.fb-card-actions{display:flex;gap:6px;flex-wrap:wrap;margin-top:2px;}
.fb-card-inline-form{display:flex;flex-direction:column;gap:6px;margin-top:4px;}
.fb-card-inline-form textarea{width:100%;min-height:70px;resize:vertical;background:var(--panel);border:1px solid var(--border2);border-radius:6px;color:var(--text);font-size:11px;padding:6px;box-sizing:border-box;font-family:inherit;}
.fb-card details{margin-top:2px;}
.fb-card summary{cursor:pointer;font-size:9px;color:var(--text-dim);user-select:none;}
.fb-card pre{background:var(--panel);border-radius:6px;padding:6px;font-size:9px;overflow-x:auto;max-height:160px;margin:4px 0 0 0;}

/* ---- Audio strip (audio-bridge.js) ---- */
#audio-strip{position:relative;border-top:1px solid var(--border);background:var(--panel2)}
.audio-row{position:relative;height:30px;border-bottom:1px solid var(--border);overflow:visible}
.audio-wave{position:absolute;top:2px;cursor:grab;border-radius:3px;overflow:hidden;background:rgba(94,106,210,0.12)}
.audio-wave.muted{opacity:.35}
.audio-wave canvas{display:block}
/* name/mute/level now live as a .lrow in #layer-list (audio-bridge.js
   renderAudioLayerRows) — .audio-vol is reused there directly */
.audio-vol{width:52px;height:10px}
.lrow.audio-lrow{cursor:default;}

/* Drag-and-drop import hover feedback (drop-import.js) */
#canvas-area.drop-hover,#timeline-area.drop-hover{outline:2px dashed var(--accent);outline-offset:-2px;}

/* Media Library (media-library.js, v1 2026-07) */
.media-drop{margin:0 8px 6px;padding:10px 8px;border:1px dashed var(--border2);border-radius:6px;font-size:9.5px;color:var(--text-dim);text-align:center;cursor:default;}
.media-drop.drop-hover{border-color:var(--accent);color:var(--text);background:var(--accent-dim);}
/* Rebuilt 2026-07 as a row-based list (project-list-table reference:
   thumbnail+name, a colored type pill, an owner-like avatar+name) instead
   of the original thumbnail grid — see media-library.js render(). */
/* Compact/expand toggle (2026-07-31) — bounded default height + scroll,
   same .expanded-class-flip idiom as .fx-row-chevron/.fx-row.expanded
   above, NOT the continuous #tl-resize drag-handle (a different gesture). */
.media-grid{display:flex;flex-direction:column;gap:4px;padding:0 8px 8px;max-height:184px;overflow-y:auto;transition:max-height .15s ease;}
.media-grid.expanded{max-height:520px;}
.media-panel-hdr{display:flex;align-items:center;gap:6px;}
.media-expand-toggle{flex:none;width:16px;height:16px;display:flex;align-items:center;justify-content:center;color:rgba(236,234,231,.4);cursor:pointer;transition:transform .12s ease;}
.media-expand-toggle:hover{color:var(--text);}
.media-expand-toggle svg{display:block;}
.media-expand-toggle.expanded{transform:rotate(180deg);}
.media-row{position:relative;display:flex;align-items:center;gap:8px;padding:5px 6px;border-radius:6px;background:var(--panel3);cursor:pointer;}
.media-row:hover{box-shadow:0 0 0 1px var(--accent);}
.media-row-thumb{position:relative;width:30px;height:30px;flex:none;border-radius:4px;overflow:hidden;background:var(--panel2);}
.media-row-thumb img{width:100%;height:100%;object-fit:cover;position:absolute;top:0;left:0;}
.media-row-playicon{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,.35);color:#fff;font-size:9px;}
.media-row-main{min-width:0;flex:1;display:flex;flex-direction:column;gap:2px;}
.media-row-name{font-size:10px;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.media-row-meta{display:flex;align-items:center;gap:6px;flex-wrap:wrap;}
.media-row-badge{font-size:8px;line-height:1.6;padding:0 6px;border-radius:8px;font-weight:600;letter-spacing:.02em;}
.media-row-badge.kind-image{background:rgba(180,155,230,.18);color:#c9b6f2;}
.media-row-badge.kind-video{background:rgba(74,158,255,.18);color:#7ea0fa;}
.media-row-badge.kind-audio{background:rgba(120,200,150,.18);color:#8fd6a8;}
/* Embedded/linked distinction (2026-07-31) — a nativeVideo asset only
   persists a filesystem path; this badge is what "can go offline" looks
   like before the user ever hits a broken relink. */
.media-row-badge.kind-linked{background:rgba(230,170,80,.18);color:#e8b869;}
.media-row-size{font-size:8px;color:var(--text-dim);opacity:.75;}
.media-row-thumb-icon{display:flex;align-items:center;justify-content:center;font-size:14px;color:var(--text-dim);}
.media-row-owner{display:flex;align-items:center;gap:4px;font-size:8.5px;color:var(--text-dim);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.media-row-owner-dot{width:6px;height:6px;border-radius:50%;flex:none;}
.media-row-owner.orphan{color:var(--red);font-style:italic;}
.media-row-date{font-size:8px;color:var(--text-dim);opacity:.75;}
/* Decoding placeholder (2026-08, feedback: "afficher l'instance dans média
   instantanément... avec wait et ready") — shown while a media-library entry
   has status:'loading' (media-library.js's addEntry/updateEntry). */
.media-row.loading{cursor:default;}
.media-row-thumb-loading{display:flex;align-items:center;justify-content:center;}
.media-row-spinner{width:14px;height:14px;border-radius:50%;border:2px solid rgba(236,234,231,.2);border-top-color:var(--accent);animation:media-row-spin .8s linear infinite;}
@keyframes media-row-spin{to{transform:rotate(360deg);}}
.media-row-progress{height:3px;border-radius:2px;background:var(--panel2);overflow:hidden;margin-top:1px;}
.media-row-progress-bar{width:40%;height:100%;border-radius:2px;background:var(--accent);animation:media-row-progress-slide 1.1s ease-in-out infinite;}
@keyframes media-row-progress-slide{0%{margin-left:-40%;}100%{margin-left:100%;}}

/* Transform anchor-point picker (redesign 2026-07-09) */
.xform-anchor-grid{width:56px;height:56px;flex:none;position:relative;display:grid;grid-template-columns:repeat(3,1fr);grid-template-rows:repeat(3,1fr);border:1px solid var(--border2);border-radius:4px;margin-top:2px;}
.xa-dot{width:100%;height:100%;border:none;background:transparent;padding:0;margin:0;cursor:pointer;display:flex;align-items:center;justify-content:center;position:relative;}
.xa-dot::after{content:'';width:5px;height:5px;border-radius:50%;background:var(--text-dark);}
.xa-dot:hover::after{background:var(--text-dim);}
.xa-dot.xa-active::after{background:var(--accent);width:7px;height:7px;box-shadow:0 0 0 3px var(--accent-dim);}
.xa-dot.xa-center{color:var(--accent);font-size:16px;font-weight:600;line-height:1;}
.xa-dot.xa-center::after{display:none;}

/* Layer color label dot (redesign 2026-07-09) */
.layer-color-dot{width:16px!important;flex:none;display:flex;align-items:center;justify-content:center;cursor:pointer;}
.layer-color-dot::after{content:'';width:9px;height:9px;border-radius:50%;background:var(--dot-color);border:1px solid rgba(0,0,0,.25);}
.layer-color-dot:hover::after{box-shadow:0 0 0 3px rgba(255,255,255,.08);}
/* Predefined-swatch "nuancier" popover for the layer color dot (v5) —
   quick preset picks from LAYER_COLOR_PALETTE, with a "+" cell falling
   through to the full custom ColorPicker for anyone who wants an
   arbitrary color instead of one of the presets. */
.lcs-pop{position:fixed;z-index:400;display:grid;grid-template-columns:repeat(4,22px);gap:6px;padding:8px;background:var(--panel2);border:1px solid var(--border2);border-radius:8px;box-shadow:0 14px 34px rgba(0,0,0,.5);}
.lcs-swatch{width:22px;height:22px;border-radius:6px;border:1.5px solid rgba(255,255,255,.12);cursor:pointer;padding:0;}
.lcs-swatch:hover{border-color:var(--text);transform:scale(1.08);}
.lcs-swatch.sel{border-color:#fff;box-shadow:0 0 0 2px var(--accent);}
.lcs-swatch.lcs-custom{background:var(--panel3);color:var(--text-dim);font-size:14px;font-weight:700;display:flex;align-items:center;justify-content:center;}
.lcs-swatch.lcs-custom:hover{color:var(--text);}

/* Align/distribute toolbar (redesign 2026-07-09) */
.align-btn{width:26px;height:26px;border-radius:6px;border:none;background:transparent;color:var(--text-dim);cursor:pointer;padding:5px;display:flex;align-items:center;justify-content:center;}
.align-btn svg{width:100%;height:100%;}
.align-btn:hover{background:var(--panel3);color:var(--text);}

/* ---- StoryBoard mode (2026-07) — node space + modules ---- */
#storyboard-space{display:none;position:relative;flex:1;overflow:hidden;background:radial-gradient(circle at 1px 1px,var(--border) 1px,transparent 0) 0 0/24px 24px,var(--bg);cursor:grab;}
#storyboard-space:active{cursor:grabbing;}
#sb-world{position:absolute;left:0;top:0;transform-origin:0 0;}
.sb-module{position:absolute;background:var(--panel2);border:1px solid var(--border);border-radius:10px;box-shadow:0 4px 14px rgba(0,0,0,.35);user-select:none;cursor:default;}
.sb-instance{display:flex;align-items:center;gap:8px;padding:10px;padding-bottom:22px;}
.sb-thumb{width:72px;height:48px;border-radius:6px;flex:none;}
.sb-side{display:flex;flex-direction:column;gap:4px;}
.sb-edit{width:24px;height:24px;border-radius:6px;display:flex;align-items:center;justify-content:center;color:var(--text-dim);cursor:pointer;}
.sb-edit:hover{background:var(--panel3);color:var(--text);}
.sb-name{position:absolute;left:10px;bottom:5px;font-size:9px;color:var(--text-dim);max-width:110px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.sb-montage{min-width:260px;padding:8px;}
.sb-montage.active{border-color:var(--accent);}
.sb-montage-head{display:flex;align-items:center;gap:6px;font-size:10px;color:var(--text-dim);margin-bottom:6px;}
.sb-montage-lane{min-height:56px;border:1px dashed var(--border2);border-radius:6px;display:flex;align-items:center;padding:4px;gap:2px;}
.sb-hint{font-size:9px;color:var(--text-dim);margin:0 auto;}
.sb-montage-head .sb-play{margin-left:auto;cursor:pointer;font-size:11px;color:var(--text-dim);padding:0 4px;}
.sb-montage-head .sb-play:hover{color:var(--accent);}
.sb-montage-lane{position:relative;overflow:visible;}
.sb-chip{position:relative;height:48px;border-radius:5px;flex:none;display:flex;align-items:center;justify-content:center;color:rgba(255,255,255,.85);font-size:9px;font-weight:700;cursor:grab;min-width:14px;overflow:hidden;}
.sb-chip:active{cursor:grabbing;}
.sb-trim{position:absolute;top:0;bottom:0;width:7px;cursor:ew-resize;background:rgba(0,0,0,.25);}
.sb-trim.left{left:0;border-radius:5px 0 0 5px;}
.sb-trim.right{right:0;border-radius:0 5px 5px 0;}
.sb-trim:hover{background:rgba(255,255,255,.35);}
.sb-ph{position:absolute;top:-4px;bottom:-4px;width:2px;background:var(--accent);pointer-events:none;box-shadow:0 0 4px var(--accent);}
.sb-sound{padding:6px;padding-bottom:20px;padding-right:24px;}
.sb-wave{display:block;border-radius:4px;background:rgba(94,106,210,.12);cursor:crosshair;}
.sb-wave-cursor{position:absolute;top:6px;height:44px;width:1.5px;background:#ffaa28;pointer-events:none;}
.sb-sound-play{position:absolute;right:6px;top:6px;font-size:10px;color:var(--text-dim);cursor:pointer;}
.sb-sound-play:hover{color:var(--accent);}
.sb-audio-row{position:relative;height:26px;margin-top:4px;}
.sb-audio-blk{position:absolute;top:0;height:24px;border-radius:4px;background:rgba(94,106,210,.25);border:1px solid rgba(94,106,210,.5);overflow:hidden;cursor:grab;}
.sb-audio-blk:active{cursor:grabbing;}
.sb-montage-lane.drop-hint{border-color:var(--accent);background:rgba(94,106,210,.12);}
/* StoryBoard v2 — anchor block + chain + ruler */
.sb-montageblock{width:64px;height:64px;display:flex;align-items:center;justify-content:center;color:var(--text-dim);cursor:grab;}
.sb-montageblock.active{border-color:var(--accent);color:var(--text);}
.sb-block-play{position:absolute;right:3px;bottom:2px;font-size:9px;color:var(--text-dim);cursor:pointer;}
.sb-block-play:hover{color:var(--accent);}
.sb-module.chained{border-radius:4px;box-shadow:none;border-color:var(--border2);}
.sb-ruler{position:absolute;height:14px;background:repeating-linear-gradient(90deg,var(--border2) 0 1px,transparent 1px 8px),var(--panel2);border:1px solid var(--border);border-radius:4px 4px 0 0;cursor:ew-resize;overflow:visible;}
.sb-ruler .sb-ph{top:0;bottom:-4px;}
.sb-ruler-lbl{position:absolute;right:4px;top:0;font-size:8px;color:var(--text-dim);pointer-events:none;line-height:14px;}

/* ---- Motion graph editor (motion-graph.js) ----
   Absolutely positioned INSIDE #fg-wrap (the scroller) so it inherits
   horizontal scroll and the live FC frame width without participating in the
   panel/grid row-alignment invariant motion.js depends on. */
#motion-graph{position:absolute;left:0;top:42px;z-index:3;display:none;
  background:var(--panel);border-top:1px solid var(--border);}
#motion-graph svg{display:block;}
#motion-graph .mg-key{cursor:ns-resize;}
#motion-graph .mg-ease{cursor:move;}
/* Pinned to the visible scroll window (left is updated on scroll) rather than
   to the graph's own origin, so the legend stays readable at any scroll x. */
#motion-graph .mg-legend{position:absolute;top:4px;font-size:9px;
  background:color-mix(in srgb,var(--panel) 88%,transparent);
  padding:2px 6px;border-radius:3px;pointer-events:none;white-space:nowrap;}
#btn-mgraph.on{color:var(--accent);}

/* AE-style "Parent & Link" cell on each layer row (timeline.js buildParentCell).
   Fixed max width with ellipsis so a long parent name can never push the row
   wider than the user-resizable layer panel. */
.lparent{margin-left:auto;flex:0 0 auto;max-width:84px;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;font-size:9.5px;color:var(--text-dim);padding:2px 6px;border-radius:4px;
  border:1px solid var(--border);background:var(--panel2);cursor:pointer;line-height:1.4;}
.lparent:hover{color:var(--text);border-color:var(--border2);}
.lparent.none{opacity:.55;}
.lrow.act .lparent{border-color:var(--border2);}
/* Pickwhip (AE's parent spiral): drag from this dot onto another layer row.
   Sits INSIDE .lparent so the cell keeps one footprint in the row — the
   click-to-open-menu path stays on the label text, the drag path on the dot,
   so neither gesture can swallow the other. */
.lpick{display:inline-block;width:9px;height:9px;margin-right:4px;vertical-align:-1px;
  border-radius:50%;border:1.5px solid var(--text-dim);cursor:alias;flex:0 0 auto;}
.lpick:hover{border-color:var(--accent,#5b6cff);box-shadow:0 0 0 2px rgba(91,108,255,.25);}
.lrow.pick-target{outline:1px solid var(--accent,#5b6cff);outline-offset:-1px;background:rgba(91,108,255,.12);}
.lpick-line{position:fixed;z-index:9999;pointer-events:none;height:0;border-top:1.5px dashed var(--accent,#5b6cff);
  transform-origin:0 0;}

/* Motion panel's own Parent row (motion.js renderParentRow) — starts from
   the exact same .lparent pill as the layer-list cell ("même ui que dans
   le calque") but unconstrained in width, since the Motion panel row has
   room the layer list doesn't. Once Parent B is set the pill doubles as
   the crossfade fader ("une barre bleu dedans pour fade le parent"): .mp-fill
   is an inner width=blend% bar, click-vs-drag disambiguated by movement
   threshold exactly like the .scrub numeric fields (ui.js) — a plain click
   still opens the same parent menu as the layer-list cell. */
.motion-parent-pill{flex:1;max-width:none;position:relative;overflow:hidden;}
.motion-parent-pill.blendable{cursor:ew-resize;}
.motion-parent-pill .mp-fill{position:absolute;left:0;top:0;bottom:0;width:0;
  background:linear-gradient(90deg,rgba(63,107,245,.5),rgba(63,107,245,.3));
  border-right:1.5px solid var(--accent);pointer-events:none;}
.motion-parent-pill .mp-label{position:relative;z-index:1;}

/* Follow Path row's "Align" toggle (motion.js renderFollowPathRow) — same
   pill-adjacent small-button idiom as other on/off toggles in this panel. */
.mp-align-btn{flex:0 0 auto;margin-left:4px;font-size:9.5px;color:var(--text-dim);
  padding:2px 6px;border-radius:4px;border:1px solid var(--border);background:var(--panel2);
  cursor:pointer;line-height:1.4;}
.mp-align-btn:hover{color:var(--text);border-color:var(--border2);}
.mp-align-btn.on{color:var(--accent,#5b6cff);border-color:var(--accent,#5b6cff);background:rgba(91,108,255,.12);}

/* Effects count on the collapsed section header (effects-panel.js) — the
   header is all that's on screen while the section is collapsed, so it has to
   carry the "this layer has effects" signal by itself. */
.phdr .fx-count{margin-left:auto;background:var(--accent);color:#fff;border-radius:8px;
  min-width:15px;height:15px;line-height:15px;text-align:center;font-size:9px;
  font-weight:700;padding:0 4px;}


/* ---- Nemo script panels & HTML plugins (nemo-panel.js / nemo-plugin.js) ---- */
.npanel{position:fixed;z-index:400;background:var(--panel2);border:1px solid var(--border2);
  border-radius:8px;box-shadow:0 12px 40px rgba(0,0,0,.55);min-width:190px;font-size:11px;color:var(--text);}
.npanel-bar{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:6px 8px;
  border-bottom:1px solid var(--border);cursor:move;font-weight:600;user-select:none;}
.npanel-close{background:none;border:none;color:var(--text-dim);font-size:15px;line-height:1;cursor:pointer;padding:0 2px;}
.npanel-close:hover{color:var(--text);}
.npanel-body{display:flex;flex-direction:column;gap:6px;padding:8px;}
.npanel-row{display:flex;align-items:center;gap:6px;}
.npanel-label{color:var(--text-dim);min-width:64px;}
.npanel-text{color:var(--text-dim);}
.npanel-group{display:flex;flex-direction:column;gap:6px;padding:8px;border:1px solid var(--border);border-radius:6px;}
.npanel-group-title{font-size:9px;color:var(--text-dim);text-transform:uppercase;letter-spacing:.4px;}
.npanel-btn{background:var(--panel);border:1px solid var(--border2);color:var(--text);
  border-radius:5px;padding:5px 10px;cursor:pointer;font-size:11px;}
.npanel-btn:hover{border-color:var(--accent);color:#fff;}
.npanel-input{background:var(--panel);border:1px solid var(--border);color:var(--text);
  border-radius:4px;padding:4px 6px;font-size:11px;flex:1;min-width:50px;}
.npanel-select{background:var(--panel);border:1px solid var(--border);color:var(--text);
  border-radius:4px;padding:4px 6px;font-size:11px;flex:1;}
.npanel-check{display:flex;align-items:center;gap:5px;cursor:pointer;}
.npanel-slider{flex:1;}
.nplugin-frame{display:block;width:100%;border:none;background:var(--panel);border-radius:0 0 8px 8px;}

/* Bouton dégradé sur la ligne Fill (timeline.js initFillGradientButton).
   Une rampe miniature plutôt qu'une icône abstraite : le contrôle montre ce
   qu'il fait, ce qui est tout l'objet de l'avoir déplacé ici. */
.fill-grad-btn{padding:0;width:22px;height:20px;flex:0 0 auto;display:flex;
  align-items:center;justify-content:center;}
.fill-grad-ramp{display:block;width:14px;height:12px;border-radius:2px;
  border:1px solid var(--border2);
  background:linear-gradient(90deg,var(--text) 0%,transparent 100%);}
.fill-grad-btn.on{border-color:var(--accent);}
.fill-grad-btn.on .fill-grad-ramp{border-color:var(--accent);}
.fill-grad-btn.off{opacity:.4;}

/* Stopwatch de paramètre d'effet (effects-panel.js) — même glyphe et même
   position que celui du panneau Motion, pour que ce soit lu comme le même
   geste des deux côtés. */
.fx-stopwatch{cursor:pointer;color:var(--text-dark);flex:0 0 auto;width:16px;
  display:flex;align-items:center;justify-content:center;}
.fx-stopwatch:hover{color:var(--text);}
.fx-stopwatch.on{color:var(--accent);}

/* Navigateur de clés d'un paramètre d'effet (effects-panel.js) — le triple
   précédent / poser-supprimer / suivant qu'AE place à côté d'une propriété
   animée, plus le nombre de clés. */
.fx-keynav{display:flex;align-items:center;gap:2px;margin-left:auto;flex:0 0 auto;}
.fx-keynav-btn{cursor:pointer;color:var(--text-dim);font-size:9px;line-height:1;
  padding:2px 3px;border-radius:3px;user-select:none;}
.fx-keynav-btn:hover{color:var(--text);background:rgba(255,255,255,.06);}
.fx-keynav-btn.off{opacity:.25;cursor:default;}
.fx-keynav-btn.off:hover{color:var(--text-dim);background:none;}
.fx-keynav-count{font-size:8px;color:var(--text-dark);margin-left:2px;min-width:8px;text-align:center;}

/* ---- TIMELINE MARKERS (2026-07-25) ----------------------------------- */
/* Comp markers ride #bars-row (the strip under the ruler), layer markers
   ride their own .frow — both anchored at frame*FC, so they scroll with the
   grid and stay on their frame at any zoom. */
.tl-marker{position:absolute;top:2px;width:0;height:0;z-index:6;cursor:ew-resize;
  border-left:5px solid transparent;border-right:5px solid transparent;
  border-top:9px solid var(--marker-color,#e8b64c);pointer-events:auto;}
.tl-marker:hover{filter:brightness(1.35);}
.tl-marker-layer{top:3px;border-top-width:8px;}
.tl-marker-label{position:absolute;left:7px;top:-9px;font-size:9px;line-height:1;
  color:var(--text);background:rgba(0,0,0,.55);padding:1px 4px;border-radius:3px;
  white-space:nowrap;pointer-events:none;}

/* ---- BPM GUIDES (2026-07-25) ----------------------------------------- */
/* Full-height hairlines inside #frame-grid, behind every row's content
   (z-index 0 against .frow's own stacking) so they read as a grid you align
   TO rather than another layer of chrome on top. */
.bpm-line{position:absolute;top:0;bottom:0;width:1px;background:rgba(255,255,255,.07);
  pointer-events:none;z-index:0;}
.bpm-line.bpm-bar{background:rgba(120,180,255,.22);width:1px;}

/* Work-area duration read-out — centred, non-interactive so the bar keeps
   its whole surface draggable. */
.wa-dur{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  font-size:9px;line-height:1;color:rgba(255,255,255,.72);white-space:nowrap;
  pointer-events:none;text-shadow:0 1px 2px rgba(0,0,0,.6);}

/* Per-keyframe colour (Van Dijk 3.4) — the tint replaces the neutral fill
   but keeps the selected/current states winning above it, so colouring a key
   never costs you the feedback about what is selected. */
.motion-key.tinted{background:var(--key-color,#e6e6e6);}
.motion-key.cur{background:#ffaa28;}
/* Repeated only to outrank per-key custom tint: selection must remain
   unmistakable even when the key carries a user colour. Keep this declaration
   aligned with the base selection rule above. */
.motion-key.sel{z-index:4;background:var(--accent-hover);border-color:#fff;box-shadow:none;}
/* Inline incoming/outgoing influence editors on the primary selected key.
   They are siblings of the key, not children, so Linear's 45° transform
   never rotates the controls. Flat borders only: no selection halo. */
/* Hover-to-reveal (2026-08 fix, feedback: "les box pour changé le lissage
   doit foncé comme pour les autres propriété et doivent apparaître au
   hover si on a key select") — hidden by default, same convention as this
   app's other on-demand controls (.project-tab .pt-close, .layer-inout-bar
   .timelink-anchor). Revealed by hovering the BOX'S OWN rendered area, not
   the key diamond it sits beside (2026-08 follow-up, feedback: "ce n'est
   pas en roll hover de la clé mais si on roll hover sur les box à droite
   ou à gauche elle même") — pointer-events stays 'auto' even while
   invisible so the box can register its own :hover though it renders no
   pixels, rather than gating visibility on the unrelated .motion-fc cell
   underneath. Forced on via .dragging (added by buildKeyEaseBox's own
   mousedown handler) so an active drag never gets cut off mid-gesture
   just because the pointer strayed off this small a target. */
.motion-key-ease-box{position:absolute;top:50%;z-index:8;height:16px;display:flex;align-items:center;
  box-sizing:border-box;border:1px solid #4b4e59;border-radius:2px;background:var(--panel3);color:var(--text-dim);
  transform:translateY(-50%);overflow:hidden;cursor:ew-resize;
  opacity:0;pointer-events:auto;transition:opacity .12s linear;}
.motion-key-ease-box:hover,.motion-key-ease-box.dragging{opacity:1;}
.motion-key-ease-box.in{right:calc(50% + 7px);}
.motion-key-ease-box.out{left:calc(50% + 7px);}
.motion-key-ease-marker{width:11px;display:flex;align-items:center;justify-content:center;font-size:7px;line-height:1;
  color:var(--accent-hover);pointer-events:none;}
.motion-key-ease-input{width:27px;height:14px;box-sizing:border-box;border:0;border-radius:0;outline:0;
  padding:0 2px;background:var(--panel3);color:var(--text);text-align:right;font:600 9px/14px var(--font-mono,monospace);
  cursor:ew-resize;-moz-appearance:textfield;}
.motion-key-ease-input::-webkit-inner-spin-button,.motion-key-ease-input::-webkit-outer-spin-button{-webkit-appearance:none;margin:0;}
.motion-key-ease-input:focus{background:var(--panel2);color:var(--text);}

/* Expression row extras (Van Dijk 7.2 / 7.4) */
.motion-expr-raw{margin-left:10px;font-size:9.5px;color:var(--text-dim);}
.motion-expr-glob{margin-left:auto;font-size:9.5px;padding:2px 7px;border-radius:4px;
  border:1px solid var(--border);background:var(--panel2);color:var(--text-dim);cursor:pointer;}
.motion-expr-glob:hover{color:var(--text);border-color:var(--border2);}

/* ---- EXPRESSION EDITOR (Van Dijk 7.5) + PICKWHIP (7.3) --------------- */
.motion-expr-pane{position:relative;display:flex;width:100%;margin-top:4px;
  border:1px solid var(--border);border-radius:5px;background:#131217;overflow:hidden;}
.motion-expr-gutter{flex:0 0 auto;width:26px;padding:5px 0;overflow:hidden;
  text-align:right;user-select:none;background:rgba(255,255,255,.03);
  border-right:1px solid var(--border);}
.motion-expr-gutter span{display:block;font:10px/1.45 var(--font-mono,monospace);
  color:rgba(236,234,231,.28);padding-right:5px;}
.motion-expr-gutter span.err{color:#ff6b6b;font-weight:700;}
.motion-expr-pane .motion-expr-code{flex:1;min-width:0;height:58px;resize:none;border:0;
  background:transparent;color:var(--text);padding:5px 7px;outline:none;
  font:10px/1.45 var(--font-mono,monospace);white-space:pre;overflow:auto;}
/* Bottom-right grip. Deliberately not `resize:vertical` on the textarea:
   a native resize gives no event, and the frame grid has to re-render on
   every height change to keep its rows aligned (CLAUDE.md §11). */
.motion-expr-grip{position:absolute;right:0;bottom:0;width:14px;height:14px;
  cursor:ns-resize;background:linear-gradient(135deg,transparent 45%,var(--border2) 45%,var(--border2) 55%,transparent 55%);}
.motion-expr-whip{display:inline-block;width:9px;height:9px;margin-left:8px;
  vertical-align:-1px;border-radius:50%;border:1.5px solid var(--text-dim);cursor:alias;}
.motion-expr-whip:hover{border-color:var(--accent,#5b6cff);box-shadow:0 0 0 2px rgba(91,108,255,.25);}
.motion-prop-row.pick-target,.motion-track-row.pick-target{
  outline:1px solid var(--accent,#5b6cff);outline-offset:-1px;background:rgba(91,108,255,.12);}
.fill-gradient-editor{margin:6px 0 1px;padding:6px;border-top:1px solid var(--border);background:color-mix(in srgb,var(--bg) 65%,transparent);border-radius:4px}
