A top-level element already got a selection border via its .canvasElement wrapper, but a child posed inside a container/répéteur/ groupe de champs has no such separate frame, so selecting it from the tree gave no visual feedback on the canvas at all. applySelectionHighlight() now targets the element's own tag directly via data-element-id (present on every rendered element, nested or not) and outlines it, re-run after every canvas refresh path (initial load, full pjax navigation, partial panel refresh, and the autosave-only canvas refresh). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
351 lines
19 KiB
CSS
351 lines
19 KiB
CSS
:root{
|
|
--bg:#12151c; --panel:#191d27; --panel2:#1f2430; --border:#2b3140;
|
|
--text:#e8eaf0; --text-dim:#8b93a7; --accent:#5b8cff; --danger:#e2685f;
|
|
}
|
|
*{ box-sizing:border-box; }
|
|
body{ margin:0; font-family:system-ui,-apple-system,"Segoe UI",sans-serif; background:var(--bg); color:var(--text); }
|
|
h1{ font-size:20px; margin:0 0 6px; }
|
|
h2{ font-size:13px; text-transform:uppercase; letter-spacing:.05em; color:var(--text-dim); margin:24px 0 8px; }
|
|
h3{ font-size:13px; color:var(--accent); margin:14px 0 6px; }
|
|
label{ display:block; font-size:12px; color:var(--text-dim); margin:8px 0 4px; }
|
|
input[type=text], input[type=number], input[type=date], textarea, select{
|
|
width:100%; background:var(--panel2); border:1px solid var(--border); border-radius:6px;
|
|
color:var(--text); padding:8px 10px; font-size:13px; font-family:inherit;
|
|
}
|
|
input[type=checkbox]{ width:auto; margin-top:6px; }
|
|
|
|
.topbar{ display:flex; align-items:center; gap:10px; padding:12px 20px; background:var(--panel); border-bottom:1px solid var(--border); }
|
|
.brand{ color:var(--text); font-weight:700; text-decoration:none; }
|
|
.crumb{ color:var(--text-dim); text-decoration:none; font-size:13px; }
|
|
.crumb-sep{ color:var(--text-dim); }
|
|
.content{ max-width:760px; margin:0 auto; padding:28px 20px; }
|
|
|
|
.card{ border:1px solid var(--border); border-radius:10px; padding:16px; background:var(--panel); margin:12px 0; }
|
|
.inline-form .fieldRow{ display:flex; gap:8px; align-items:flex-end; }
|
|
.inline-form .fieldRow input{ flex:1; }
|
|
.fieldRow{ display:flex; gap:10px; }
|
|
.fieldRow > div{ flex:1; }
|
|
.formField{ margin-bottom:6px; }
|
|
|
|
button{ background:var(--panel2); border:1px solid var(--border); color:var(--text); border-radius:6px; padding:9px 14px; cursor:pointer; font-size:13px; }
|
|
button.primary{ background:var(--accent); border-color:var(--accent); color:#fff; font-weight:600; }
|
|
button.smallBtn{ padding:5px 10px; font-size:11.5px; }
|
|
button.danger{ color:var(--danger); border-color:rgba(226,104,95,.4); }
|
|
.addBtn{ display:inline-block; margin:10px 0; padding:9px 14px; border-radius:6px; border:1px dashed var(--border); color:var(--accent); text-decoration:none; font-size:13px; }
|
|
.actionsRow{ margin-top:16px; }
|
|
|
|
.list{ display:flex; flex-direction:column; gap:6px; }
|
|
.listRow{ display:block; padding:10px 12px; border:1px solid var(--border); border-radius:8px; background:var(--panel); text-decoration:none; color:var(--text); }
|
|
.listRow:hover{ background:var(--panel2); }
|
|
.listRowFlex{ display:flex; align-items:center; justify-content:space-between; gap:10px; }
|
|
.listRowFlex .rowLink{ flex:1; text-decoration:none; color:var(--text); }
|
|
.listRowFlex form{ margin:0; }
|
|
.rowTitle{ font-size:14px; }
|
|
.rowSub{ font-size:11px; color:var(--text-dim); margin-top:2px; }
|
|
.rowActions{ display:flex; gap:6px; align-items:center; }
|
|
|
|
.hint{ font-size:11.5px; color:var(--text-dim); line-height:1.5; }
|
|
.autosaveStatus{ display:inline-flex; align-items:center; gap:6px; transition:color .2s ease; }
|
|
.autosaveStatus.saving{ color:var(--text-dim); }
|
|
.autosaveStatus.saved{ color:#7bd88f; }
|
|
.warningBanner{ border:1px solid var(--danger); background:rgba(226,104,95,.1); color:var(--text);
|
|
border-radius:8px; padding:10px 14px; font-size:12.5px; margin:12px 0; }
|
|
.dangerZone{ border:1px solid rgba(226,104,95,.4); border-radius:10px; padding:14px; margin-top:20px; }
|
|
.dangerZone h3{ color:var(--danger); }
|
|
.fieldsExistingRow{ display:flex; align-items:center; justify-content:space-between;
|
|
padding:8px 10px; border:1px solid var(--border); border-radius:6px; margin-bottom:6px; font-size:12.5px; }
|
|
.fieldsExistingRow form{ margin:0; }
|
|
|
|
.fieldRowCard{ margin-bottom:10px; }
|
|
.relationTarget{ margin-top:6px; }
|
|
|
|
.dataTable{ width:100%; border-collapse:collapse; font-size:12.5px; }
|
|
.dataTable th, .dataTable td{ border:1px solid var(--border); padding:6px 8px; text-align:left; }
|
|
.dataTable th{ background:var(--panel2); color:var(--text-dim); }
|
|
|
|
.content-wide{ max-width:1080px; }
|
|
.twoCol{ display:flex; gap:24px; align-items:flex-start; margin-top:10px; }
|
|
.twoCol .colLeft{ flex:0 0 340px; }
|
|
.twoCol .colRight{ flex:1; min-width:0; }
|
|
.fieldEditCard{ display:flex; flex-direction:column; gap:10px; }
|
|
.fieldEditCard input[disabled]{ color:var(--text-dim); opacity:.8; }
|
|
.fieldEditActions{ margin-top:6px; }
|
|
@media (max-width: 820px){
|
|
.twoCol{ flex-direction:column; }
|
|
.twoCol .colLeft{ flex:none; width:100%; }
|
|
}
|
|
|
|
/* ---------- Éditeur d'écrans (façon Elementor/Bricks) ---------- */
|
|
/* La page de l'éditeur d'écran ne doit jamais défiler elle-même : elle
|
|
occupe exactement la hauteur de la fenêtre (topbar + zone de travail), et
|
|
ce sont les zones internes (panneaux, écran, panneau de logique) qui
|
|
défilent chacune de leur côté si besoin. */
|
|
body.builderBody{ display:flex; flex-direction:column; height:100vh; margin:0; overflow:hidden; }
|
|
body.builderBody > .topbar{ flex:0 0 auto; }
|
|
body.builderBody > main.content{ flex:1 1 auto; min-height:0; overflow:hidden; display:flex; flex-direction:column; }
|
|
|
|
.content-builder{
|
|
/* .content (ci-dessus) pose "margin:0 auto" pour centrer une page normale
|
|
— mais sur cette page, le body est un flex-container en colonne
|
|
(body.builderBody), et une marge horizontale "auto" y désactive le
|
|
stretch d'un flex-item : sa largeur est alors recalculée en
|
|
"shrink-to-fit" à partir de son contenu, un calcul qui traverse toute
|
|
la chaîne flex/%/aspect-ratio jusqu'au canvas et redonne un résultat
|
|
légèrement différent à chaque changement de contenu du panneau (élément
|
|
sélectionné, grille affichée...) — d'où le canvas qui grandit/rétrécit
|
|
sans raison apparente à chaque interaction. "width:100%" donne une
|
|
taille définie à la place : la marge "auto" ne fait alors que centrer
|
|
l'espace restant une fois "max-width" atteint, comme voulu à l'origine. */
|
|
width:100%;
|
|
max-width:1600px;
|
|
}
|
|
.content-builder > .fieldRow:first-child{ flex:0 0 auto; }
|
|
|
|
/* 3 colonnes : ajout d'éléments (gauche) / écran en grand (centre) / propriétés (droite) —
|
|
toutes les trois occupent exactement la même hauteur (celle qui reste
|
|
disponible), avec leur propre défilement interne si leur contenu dépasse. */
|
|
.builder3{ display:flex; gap:20px; align-items:stretch; margin-top:14px; flex:1 1 auto; min-height:0; }
|
|
.builderPanel{ flex:0 0 260px; min-width:0; height:100%; overflow-y:auto; }
|
|
.builderPanelRight{ flex:0 0 320px; min-width:0; height:100%; overflow-y:auto; }
|
|
.builderCanvasArea{ flex:1 1 auto; min-width:0; height:100%; overflow-y:auto; display:flex; flex-direction:column; }
|
|
|
|
.widgetGrid{ display:grid; grid-template-columns:1fr 1fr; gap:8px; }
|
|
.widgetBtnForm{ margin:0; }
|
|
.widgetBtn{
|
|
width:100%; display:flex; flex-direction:column; align-items:center; gap:4px;
|
|
padding:12px 6px; border:1px solid var(--border); border-radius:10px; background:var(--panel);
|
|
color:var(--text); cursor:pointer;
|
|
}
|
|
.widgetBtn:hover{ border-color:var(--accent); background:var(--panel2); }
|
|
.widgetIcon{ font-size:22px; }
|
|
.widgetLabel{ font-size:11px; text-align:center; line-height:1.2; color:var(--text-dim); }
|
|
|
|
.canvasToolbar{ display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin-bottom:10px; }
|
|
.aspectBtn.active{ background:var(--accent); border-color:var(--accent); color:#fff; }
|
|
|
|
.canvasFrame{
|
|
width:100%; padding:10px; border:1px solid var(--border); border-radius:16px; background:var(--panel);
|
|
}
|
|
.canvas{
|
|
position:relative; width:100%; max-width:100%; margin:0 auto; background:#0b0d12; border-radius:8px;
|
|
overflow:hidden; border:1px solid var(--border);
|
|
}
|
|
.canvasElement{
|
|
/* Pas d'overflow:hidden ici : une échelle (transform:scale) ou une
|
|
animation posée sur cet élément (voir la Timeline d'animation) vit sur
|
|
CE cadre (voir filters/element_style_filter.py) — le rogner clippait
|
|
l'effet à la taille d'origine de la boîte au lieu de le laisser
|
|
grossir/bouger avec elle. La zone de l'écran elle-même (.canvas,
|
|
ci-dessus) reste rognée, donc rien ne peut déborder de l'écran final. */
|
|
box-sizing:border-box; cursor:move; user-select:none;
|
|
border:1px dashed transparent;
|
|
}
|
|
.canvasElement:hover{ border-color:rgba(91,140,255,.5); }
|
|
.canvasElement.selected{ border:2px solid var(--accent); }
|
|
.canvasElementInner{ width:100%; height:100%; pointer-events:none; }
|
|
|
|
/* Surbrillance de l'élément sélectionné dans l'arborescence, posée en JS sur
|
|
sa propre balise (voir applySelectionHighlight) — seul moyen de la voir
|
|
sur le canevas quand cet élément est imbriqué dans un conteneur/répéteur/
|
|
groupe de champs, qui n'a pas de cadre ".canvasElement" séparé comme un
|
|
élément posé directement sur l'écran. */
|
|
.elementHighlighted{ outline:2px solid var(--accent); outline-offset:-1px; }
|
|
.resizeHandle{
|
|
position:absolute; right:0; bottom:0; width:14px; height:14px; cursor:nwse-resize;
|
|
background:var(--accent); border-radius:3px 0 6px 0; opacity:.85;
|
|
}
|
|
|
|
.listRow.selected{ border-color:var(--accent); background:var(--panel2); }
|
|
|
|
.childList{ display:flex; flex-direction:column; gap:6px; margin:2px 0 10px 18px; padding-left:10px; border-left:2px dashed var(--border); }
|
|
.childRow{ padding:7px 10px; font-size:12px; }
|
|
.childRow .rowTitle{ font-size:12px; }
|
|
|
|
/* Arborescence compacte des éléments de l'écran (panneau gauche) — une
|
|
ligne par élément, indentation par imbrication réelle (profondeur
|
|
illimitée) plutôt qu'un seul niveau d'enfants comme l'ancienne .childList,
|
|
pour rester lisible même avec beaucoup d'éléments. */
|
|
.elementTree{ display:flex; flex-direction:column; gap:1px; max-height:55vh; overflow-y:auto; margin-bottom:14px; }
|
|
.treeNode{ display:flex; flex-direction:column; }
|
|
.treeRow{ display:flex; align-items:center; gap:2px; }
|
|
.treeToggle{
|
|
flex:0 0 auto; width:16px; height:16px; padding:0; border:none; background:none; cursor:pointer;
|
|
color:var(--text-dim); font-size:10px; display:flex; align-items:center; justify-content:center;
|
|
transition:transform .12s ease;
|
|
}
|
|
.treeToggle:hover{ color:var(--text); }
|
|
.treeToggleSpacer{ flex:0 0 auto; width:16px; height:16px; }
|
|
.treeNode.collapsed > .treeRow > .treeToggle{ transform:rotate(-90deg); }
|
|
.treeNode.collapsed > .treeChildren{ display:none; }
|
|
.treeRowLink{
|
|
flex:1; display:flex; align-items:center; gap:6px; padding:4px 6px; border-radius:5px;
|
|
text-decoration:none; color:var(--text); font-size:12.5px; line-height:1.5;
|
|
white-space:nowrap; overflow:hidden; min-width:0;
|
|
}
|
|
.treeRowLink:hover{ background:var(--panel2); }
|
|
.treeRowLink.selected{ background:var(--accent); color:#0b0e14; font-weight:600; }
|
|
.treeIcon{ flex:0 0 auto; font-size:12px; }
|
|
.treeLabel{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
|
.treeChildren{ display:flex; flex-direction:column; margin-left:10px; padding-left:8px; border-left:1px dashed var(--border); }
|
|
|
|
.contextMenu{
|
|
position:fixed; z-index:500; background:var(--panel); border:1px solid var(--border);
|
|
border-radius:8px; box-shadow:0 8px 24px rgba(0,0,0,.4); padding:4px; min-width:160px;
|
|
}
|
|
.contextMenu button{
|
|
display:block; width:100%; text-align:left; background:none; border:none; color:var(--text);
|
|
padding:7px 10px; border-radius:5px; font-size:13px; cursor:pointer;
|
|
}
|
|
.contextMenu button:hover{ background:var(--panel2); }
|
|
|
|
.propGroup{ border:1px solid var(--border); border-radius:8px; margin-bottom:8px; background:var(--panel); }
|
|
.propGroup > summary{
|
|
list-style:none; cursor:pointer; padding:9px 12px; font-size:13px; color:var(--accent);
|
|
font-weight:600; user-select:none; display:flex; align-items:center; justify-content:space-between;
|
|
}
|
|
.propGroup > summary::-webkit-details-marker{ display:none; }
|
|
.propGroup > summary::after{ content:"▸"; color:var(--text-dim); font-size:11px; transition:transform .15s; }
|
|
.propGroup[open] > summary::after{ transform:rotate(90deg); }
|
|
.propGroup > summary:hover{ background:var(--panel2); }
|
|
.propGroupBody{ padding:2px 12px 12px; }
|
|
.propGroupBody h3{ margin-top:0; }
|
|
|
|
/* Le groupe "Ajouter DANS ce conteneur" doit être visuellement impossible à
|
|
confondre avec "Ajouter un élément sur l'écran" (panneau de gauche) —
|
|
même icônes de widgets, même mise en page, mais une cible totalement
|
|
différente (à l'intérieur du conteneur sélectionné, pas sur l'écran). */
|
|
.containerContentGroup{ border-color:#3d6b3d; background:#152015; }
|
|
.containerContentGroup > summary{ color:#8fd98f; }
|
|
|
|
.posGrid{ display:grid; grid-template-columns:1fr 1fr; gap:8px 12px; margin-bottom:14px; }
|
|
.posGrid label{ font-size:11px; color:var(--text-dim); display:flex; flex-direction:column; gap:4px; }
|
|
.posGrid input{ background:var(--panel2); border:1px solid var(--border); border-radius:6px; color:var(--text); padding:6px 8px; }
|
|
.posGrid input:disabled{ opacity:0.4; cursor:not-allowed; }
|
|
.sizeField{ display:flex; gap:4px; }
|
|
.sizeField input{ flex:1; min-width:0; }
|
|
.sizeField select{ width:auto; flex:0 0 auto; padding:6px 4px; }
|
|
|
|
.controlRow{ margin-bottom:12px; }
|
|
.controlRow > label{ display:block; font-size:12px; color:var(--text-dim); margin-bottom:4px; }
|
|
.sliderRow{ display:flex; align-items:center; gap:10px; }
|
|
.sliderRow input[type=range]{ flex:1; }
|
|
.sliderValue{ font-size:12px; color:var(--text-dim); min-width:44px; text-align:right; }
|
|
.alignGroup{ display:flex; gap:6px; }
|
|
.alignOption{ flex:1; text-align:center; padding:8px 0; border:1px solid var(--border); border-radius:6px; cursor:pointer; }
|
|
.alignOption input{ display:none; }
|
|
.alignOption.active{ border-color:var(--accent); background:rgba(91,140,255,.15); }
|
|
input[type=color]{ width:52px; height:34px; padding:2px; }
|
|
|
|
.propsPanel .sectionDivider, .builderPanelRight .sectionDivider{ border:none; border-top:1px solid var(--border); margin:14px 0; }
|
|
.actionAddForm{ margin-top:10px; }
|
|
|
|
.uploadRow{ margin-top:6px; }
|
|
.uploadInput{ font-size:11px; color:var(--text-dim); }
|
|
.uploadStatus{ display:block; margin-top:4px; }
|
|
code{ background:var(--panel2); border:1px solid var(--border); border-radius:4px; padding:1px 6px; font-size:11.5px; }
|
|
|
|
@media (max-width: 1300px){
|
|
/* Sous cette largeur, les 3 colonnes s'empilent : le principe "tout tient
|
|
dans la fenêtre, chaque zone défile pour elle-même" n'a plus de sens
|
|
(il n'y a plus qu'une seule colonne) — on revient à une page classique
|
|
qui défile normalement. */
|
|
body.builderBody{ height:auto; overflow:visible; }
|
|
body.builderBody > main.content{ overflow:visible; }
|
|
.builder3{ flex-direction:column; flex:none; }
|
|
.builderPanel, .builderPanelRight, .builderCanvasArea{ flex:none; width:100%; height:auto; max-height:none; overflow:visible; }
|
|
}
|
|
|
|
/* ---------- Logique de la scène : éditeur de flow à nœuds ---------- */
|
|
/* Panneau du bas, dans le même flux flexbox que .builder3 (pas une
|
|
surcouche/overlay) : replié, il ne prend que la hauteur de son en-tête et
|
|
.builder3 récupère tout le reste de l'espace ; ouvert, sa hauteur est
|
|
fixée en pixels (réglable à la souris via la poignée juste au-dessus) et
|
|
.builder3 rétrécit d'autant automatiquement — jamais l'un par-dessus
|
|
l'autre. */
|
|
.flowPanel{
|
|
flex:0 0 auto; border:1px solid var(--border); border-radius:10px; background:var(--panel);
|
|
margin-top:8px; display:flex; flex-direction:column; overflow:hidden;
|
|
}
|
|
.flowPanelHeader{
|
|
flex:0 0 auto; padding:10px 16px; font-weight:700; cursor:pointer; user-select:none;
|
|
display:flex; align-items:center; gap:6px;
|
|
}
|
|
.flowPanelHeader:hover{ background:var(--panel2); }
|
|
.flowToggleIcon{ color:var(--text-dim); font-size:11px; transition:transform .15s; display:inline-block; }
|
|
.flowPanel.open .flowToggleIcon{ transform:rotate(90deg); }
|
|
.flowPanelBody{ flex:1 1 auto; min-height:0; padding:0 16px 16px; display:none; flex-direction:column; }
|
|
.flowPanel.open .flowPanelBody{ display:flex; }
|
|
.flowToolbar{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin-bottom:10px; flex:0 0 auto; }
|
|
|
|
.flowResizeHandle{
|
|
flex:0 0 auto; height:10px; margin-top:6px; cursor:row-resize; position:relative; display:none;
|
|
}
|
|
.flowResizeHandle.visible{ display:block; }
|
|
.flowResizeHandle::before{
|
|
content:""; position:absolute; left:50%; top:3px; width:60px; height:4px;
|
|
background:var(--border); border-radius:2px; transform:translateX(-50%);
|
|
}
|
|
.flowResizeHandle:hover::before{ background:var(--accent); }
|
|
|
|
.nodeForm{ border:1px solid var(--border); border-radius:8px; padding:12px; margin-bottom:12px; background:var(--panel2); max-width:420px; flex:0 0 auto; }
|
|
.nodeForm label{ margin-top:8px; }
|
|
|
|
.flowCanvasWrap{ position:relative; width:100%; flex:1 1 auto; min-height:120px; overflow:auto; border:1px dashed var(--border); border-radius:8px; background:#0d0f15; }
|
|
.flowCanvas{ position:relative; width:2200px; height:1400px; }
|
|
.flowEdgesSvg{ position:absolute; top:0; left:0; width:2200px; height:1400px; pointer-events:none; z-index:0; }
|
|
.flowEdgeLine{ stroke:var(--accent); stroke-width:2; pointer-events:stroke; cursor:pointer; }
|
|
.flowEdgeLine.flowEdgeTrue{ stroke:#4caf7d; }
|
|
.flowEdgeLine.flowEdgeFalse{ stroke:var(--danger); }
|
|
|
|
.flowNode{
|
|
position:absolute; width:220px; min-height:52px; border-radius:8px; border:1px solid var(--border);
|
|
background:var(--panel2); padding:10px 12px; font-size:12.5px; cursor:grab; z-index:1; user-select:none;
|
|
}
|
|
.flowNode-trigger{ border-color:#5b8cff; }
|
|
.flowNode-condition{ border-color:#e0b23c; }
|
|
.flowNode-action{ border-color:#4caf7d; }
|
|
.flowNodeBody{ padding-right:16px; line-height:1.4; word-break:break-word; }
|
|
.flowNodeDelete{
|
|
position:absolute; top:4px; right:4px; width:18px; height:18px; padding:0; line-height:1;
|
|
font-size:11px; border-radius:4px; background:transparent; border:none; color:var(--text-dim);
|
|
}
|
|
.flowNodeDelete:hover{ color:var(--danger); }
|
|
.flowPort{
|
|
position:absolute; width:14px; height:14px; border-radius:50%; background:var(--panel);
|
|
border:2px solid var(--accent); top:50%; transform:translateY(-50%); cursor:crosshair; z-index:2;
|
|
}
|
|
.flowPortIn{ left:-8px; }
|
|
.flowPortOut{ right:-8px; }
|
|
.flowPortTrue{ right:-8px; top:35%; border-color:#4caf7d; }
|
|
.flowPortFalse{ right:-8px; top:65%; border-color:var(--danger); }
|
|
|
|
/* ---------- Timeline d'animation : panneau sous "Logique de la scène" ---------- */
|
|
.animTimelineWrap{
|
|
position:relative; width:100%; flex:1 1 auto; min-height:120px; overflow:auto;
|
|
border:1px dashed var(--border); border-radius:8px; background:#0d0f15;
|
|
}
|
|
.animRuler{ display:flex; height:22px; border-bottom:1px solid var(--border); position:sticky; top:0; background:#0d0f15; z-index:3; }
|
|
.animRulerSpacer{ position:sticky; left:0; width:140px; flex:0 0 140px; background:var(--panel); z-index:2; border-right:1px solid var(--border); }
|
|
.animRulerTicksWrap{ position:relative; flex:0 0 auto; }
|
|
.animRulerTick{
|
|
position:absolute; top:0; bottom:0; font-size:10px; color:var(--text-dim);
|
|
border-left:1px solid var(--border); padding-left:3px;
|
|
}
|
|
.animTracks{ position:relative; }
|
|
.animTrack{ position:relative; height:38px; border-bottom:1px solid var(--border); display:flex; align-items:stretch; }
|
|
.animTrackLabel{
|
|
position:sticky; left:0; width:140px; flex:0 0 140px; background:var(--panel); z-index:2;
|
|
padding:0 8px; font-size:12px; display:flex; align-items:center; border-right:1px solid var(--border);
|
|
overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
|
|
}
|
|
.animTrackLane{ position:relative; flex:0 0 auto; }
|
|
.animClip{
|
|
position:absolute; top:5px; height:28px; border-radius:6px; background:var(--accent); color:#fff;
|
|
font-size:11px; padding:5px 8px; cursor:grab; overflow:hidden; white-space:nowrap; user-select:none;
|
|
box-sizing:border-box;
|
|
}
|
|
.animClip.selected{ outline:2px solid #fff; }
|
|
.animClipResizeHandle{ position:absolute; right:0; top:0; width:8px; height:100%; cursor:ew-resize; }
|
|
.animKeyframeRow{ align-items:flex-start; }
|
|
.animKeyframeRow textarea{ font-family:monospace; font-size:11px; }
|