/*
|–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
| webeditor — editor chrome
|–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
| This stylesheet is the TOOL: the mast, the File menu, the New-Page modal, the
| thumbnail palette and the canvas frame. Every class here is namespaced `ed-`
| (plus nanobase's own `btn-*` for actions) and every value reads from the
| nanobase design tokens in theme.css.
|
| IMPORTANT BOUNDARY: nothing in here ever lands on the page the user is
| authoring. The authored page lives inside `[data-page-root]` and is styled
| EXCLUSIVELY by utility classes compiled at runtime by styler.js. The `ed-`
| layer is the editor around the page, never the page itself.
*/

/* ── App frame ─────────────────────────────────────────────────────────── */

/* Editor-only: no document scrollbar (overrides reset.css's html overflow-y:
   scroll, which stays for exported pages). The canvas does the scrolling. */
html, body { height: 100%; overflow: hidden; }

body.ed-app {
    display: flex;
    flex-direction: column;
    height: 100vh;
    overflow: hidden;
    font-family: var(--fnt-std);
    font-size: var(--siz-0);
    letter-spacing: .01125ch;
    color: var(--color-fg);
    background: var(--color-bg);
    line-height: var(--line-height-tight);
}

textarea {
    border: none;
    resize: none !important;
}

/* ── Mast ──────────────────────────────────────────────────────────────── */

.ed-palette {
    user-select: none;
    -webkit-user-select: none;
}

.ed-mast {
    display: flex;
    align-items: center;
    flex-shrink: 0;
    width: 100%;
    height: var(--mst-hgt);
    padding: 0 1.5rem 0 1rem;
    border-bottom: solid 2px var(--blk-0);
    background-color: var(--blk-1);
    box-shadow: var(--shd-1);
    z-index: 4;
}

.ed-mast__inner {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 1.5rem;
    width: 100%;
}

/* Logo placeholder — a stand-in mark plus the wordmark, left-aligned. */
.ed-logo {
    display: inline-flex;
    align-items: center;
    gap: .65rem;
    padding: 0 .5rem;
    font-family: var(--fnt-hdg);
    font-size: var(--siz-1);
    font-weight: 550;
    color: var(--wht-1);
    text-decoration: none;
    -webkit-user-select: none;
    user-select: none;
}

.ed-logo__mark {
    display: grid;
    place-items: center;
    width: 34px;
    height: 34px;
    border-radius: var(--rad-2);
    background: linear-gradient(150deg, var(--blu-1), var(--pur-1));
    color: var(--wht-0);
    box-shadow: var(--shd-1);
}

.ed-logo__mark svg { width: 20px; height: 20px; }

.ed-logo__name { letter-spacing: -.02ch; }
.ed-logo__name b { font-weight: 550; color: var(--wht-0); }
.ed-logo__name span { font-weight: 400; color: var(--wht-2); }

/* ── Menu bar + File dropdown ──────────────────────────────────────────── */

.ed-menubar {
    display: flex;
    align-items: center;
    gap: .25rem;
}

.ed-menu { position: relative; }

.ed-menu__button {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    min-height: 36px;
    padding: .75rem 1rem;
    border-radius: var(--rad-1);
    background-color: transparent;
    font-family: var(--fnt-std);
    font-size: var(--siz-0);
    font-weight: 550;
    color: var(--wht-1);
    cursor: pointer;
    transition: var(--trn);
}

.ed-menu__button:hover,
.ed-menu.is-open .ed-menu__button {
    background-color: var(--blk-2);
}

.ed-menu__button svg { width: 14px; height: 14px; opacity: .7; }

.ed-menu__panel {
    position: absolute;
    top: calc(100% + .4rem);
    left: 0;
    display: none;
    flex-direction: column;
    min-width: 13rem;
    padding: .4rem;
    background-color: var(--blk-0);
    outline: solid 2px var(--wht-3);
    border-radius: var(--rad-1);
    box-shadow: var(--shd-1);
    z-index: 100;
}

.ed-menu.is-open .ed-menu__panel {
    display: flex;
    -animation: ed-fade-down .075s var(--log);
}

.ed-menu__item {
    display: flex;
    align-items: center;
    gap: .75rem;
    width: 100%;
    min-height: 40px;
    padding: 0 .75rem;
    border-radius: var(--rad-1);
    background: transparent;
    font-family: var(--fnt-std);
    font-size: var(--siz-0);
    font-weight: 550;
    color: var(--wht-1);
    text-align: left;
    white-space: nowrap;
    cursor: pointer;
    transition: var(--trn);
}

.ed-menu__item:hover { background-color: var(--blk-1); }

.ed-menu__item svg { width: 18px; height: 18px; opacity: .8; flex-shrink: 0; }

.ed-menu__item-shortcut {
    margin-left: auto;
    padding-left: 1.5rem;
    font-family: var(--fnt-fix);
    font-size: var(--siz-min);
    color: var(--wht-3);
}

/* ── Mast right: autosave status + validity pill ───────────────────────── */

.ed-mast__right {
    display: flex;
    align-items: center;
    gap: .25rem;
    margin-left: auto;
}

/* Mast icon buttons (undo / redo). */
.ed-icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: var(--rad-1);
    background-color: transparent;
    color: var(--wht-1);
    cursor: pointer;
    transition: var(--trn);
}
.ed-icon-btn:hover:not(:disabled) { background-color: var(--blk-2); }
.ed-icon-btn:disabled { opacity: .35; cursor: default; }
.ed-icon-btn svg { width: 17px; height: 17px; }

.ed-save-status {
    font-size: var(--siz-min);
    color: var(--wht-3);
    transition: var(--trn);
}

.ed-save-status[data-state="idle"]    { color: var(--wht-3); }
.ed-save-status[data-state="saving"]  { color: var(--wht-3); }
.ed-save-status[data-state="saved"]   { color: var(--wht-2); }   /* cached locally, sync pending */
.ed-save-status[data-state="syncing"] { color: var(--wht-3); }
.ed-save-status[data-state="synced"]  { color: var(--grn-1); }   /* durable on the server */
.ed-save-status[data-state="offline"] { color: var(--ylw-1); }
.ed-save-status[data-state="error"]   { color: var(--red-1); }

/* ── Options tab: status pills + inline validity list ──────────────────── */
/* The save-status + validity now live at the top of the Options (inspector)
   tab as two equal-width pills. The options panel zeroes the default body
   padding; the pills, validity list and inspector body each pad themselves. */
.ed-palette__body[data-panel="options"] { padding: 0; }

.ed-insp-pills {
    display: flex;
    gap: .5rem;
    padding: 1rem;   /* equal all around */
}

.ed-pill {
    flex: 1;
    min-width: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .4rem;
    min-height: 30px;
    padding: 0 .7rem;
    border-radius: 999px;
    background-color: var(--blk-1);
    font-size: var(--siz-min);
    font-weight: 550;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.ed-validity-pill { color: var(--wht-1); cursor: pointer; transition: var(--trn); }
.ed-validity-pill:hover { background-color: var(--blk-0); }
.ed-validity-pill .ed-validity__dot { flex-shrink: 0; }
.ed-validity-pill[data-state="valid"]   .ed-validity__dot { background-color: var(--grn-1); }
.ed-validity-pill[data-state="warning"] .ed-validity__dot { background-color: var(--ylw-1); }
.ed-validity-pill[data-state="error"]   .ed-validity__dot { background-color: var(--red-1); }

/* Pinned palette footer: the two status pills, shared across every tab. */
.ed-palette__footer {
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    border-top: solid 1px var(--blk-0);
    background-color: var(--blk-2);
}

/* Inline issues list — expands upward from the footer pill (kept out of the
   scroll region so it isn't clipped). */
.ed-validity-panel {
    margin: .6rem 1rem 0;
    max-height: 40vh;
    border-radius: var(--rad-2);
    background-color: var(--blk-1);
    overflow-y: auto;
}
.ed-validity-panel[hidden] { display: none; }

.ed-validity { position: relative; }

.ed-validity__btn {
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    min-height: 32px;
    padding: 0 .8rem;
    border-radius: var(--btn-hgt);
    background-color: var(--blk-2);
    color: var(--wht-1);
    font-family: var(--fnt-std);
    font-size: var(--siz-min);
    font-weight: 550;
    cursor: pointer;
    transition: var(--trn);
}

.ed-validity__btn:hover { background-color: var(--blk-0); }

.ed-validity__dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background-color: var(--wht-3);
}

.ed-validity[data-state="none"]    .ed-validity__dot { background-color: var(--wht-3); }
.ed-validity[data-state="valid"]   .ed-validity__dot { background-color: var(--grn-1); }
.ed-validity[data-state="warning"] .ed-validity__dot { background-color: var(--ylw-1); }
.ed-validity[data-state="error"]   .ed-validity__dot { background-color: var(--red-1); }

.ed-validity__panel {
    position: absolute;
    top: calc(100% + .5rem);
    right: 0;
    display: none;
    flex-direction: column;
    width: 360px;
    max-height: 60vh;
    padding: .4rem;
    background-color: var(--blk-0);
    outline: solid 2px var(--wht-3);
    border-radius: var(--rad-2);
    box-shadow: var(--shd-1);
    overflow-y: auto;
    z-index: 100;
}

.ed-validity.is-open .ed-validity__panel {
    display: flex;
    -animation: ed-fade-down .075s var(--log);
}

.ed-validity__ok {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .85rem;
    font-size: var(--siz-min);
    color: var(--grn-1);
}

.ed-validity__note {
    padding: .85rem;
    font-size: var(--siz-min);
    color: var(--wht-3);
}

.ed-issue {
    display: flex;
    gap: .6rem;
    width: 100%;
    padding: .6rem;
    border-radius: var(--rad-1);
    background: transparent;
    text-align: left;
    cursor: pointer;
    transition: var(--trn);
}

.ed-issue:hover { background-color: var(--blk-1); }

.ed-issue__dot {
    width: 8px;
    height: 8px;
    margin-top: .35rem;
    flex-shrink: 0;
    border-radius: 50%;
}

.ed-issue--error   .ed-issue__dot { background-color: var(--red-1); }
.ed-issue--warning .ed-issue__dot { background-color: var(--ylw-1); }

.ed-issue__body { display: flex; flex-direction: column; gap: .15rem; min-width: 0; }

.ed-issue__msg { font-size: var(--siz-min); color: var(--wht-1); line-height: 1.4; }

.ed-issue__where {
    font-family: var(--fnt-fix);
    font-size: 11px;
    color: var(--wht-3);
}

/* ── Workspace: palette | canvas ───────────────────────────────────────── */

.ed-workspace {
    display: flex;
    flex: 1;
    min-height: 0;
}

/* Left: thumbnail palette */
.ed-palette {
    display: flex;
    flex-direction: column;
    flex-shrink: 0;
    width: 328px;
    border-right: solid 2px var(--blk-0);
    background-color: var(--blk-2);
    overflow: hidden;                /* the middle scrolls; tabs + footer stay pinned */
}

/* The scrolling middle of the palette, between the fixed tabs and footer. */
.ed-palette__scroll {
    flex: 1;
    min-height: 0;
    overflow-y: scroll;                          /* always reserve + show the bar */
    scrollbar-width: thin;                       /* Firefox */
    scrollbar-color: var(--blk-0) var(--blk-2);  /* thumb / track — track matches the palette */
}

/* Always-on scrollbar (WebKit/Blink); the track matches the palette background. */
.ed-palette__scroll::-webkit-scrollbar { width: 12px; }
.ed-palette__scroll::-webkit-scrollbar-track { background: var(--blk-2); }
.ed-palette__scroll::-webkit-scrollbar-thumb {
    background: var(--blk-0);
    border: 3px solid var(--blk-2);   /* inset border (matches track) reads as a pill */
    border-radius: 12px;
}
.ed-palette__scroll::-webkit-scrollbar-thumb:hover { background: var(--wht-3); }

.ed-palette__tabs {
    flex-shrink: 0;
    display: flex;
    gap: .1rem;
    padding: .6rem .4rem 0;
    background-color: var(--blk-2);
    border-bottom: solid 1px var(--blk-0);
}

.ed-tab {
    flex: 1;                        /* five equal icon tabs */
    display: flex;
    align-items: center;
    justify-content: center;
    padding: .55rem .25rem;
    border-radius: var(--rad-1) var(--rad-1) 0 0;
    border-bottom: solid 2px transparent;
    background-color: transparent;
    cursor: pointer;
    transition: var(--trn);
}

/* Icon-only tabs: the glyph dims when inactive, brightens on hover / active (on
   top of the per-kind active underline below). The label lives in title/aria-label. */
.ed-tab svg { width: 17px; height: 17px; color: var(--wht-2); transition: var(--trn); }
.ed-tab:hover svg,
.ed-tab.is-active svg { color: var(--wht-0); }

.ed-tab:not(.is-active):hover { border-bottom-color: var(--wht-3); }

.ed-tab.is-active { border-bottom-color: var(--blu-1); }

/* The ACTIVE-tab underline matches each kind's on-canvas highlight ring
   (Section=yellow, Container=green, Artefact=purple — see the [data-ed-selected]
   rules). Assets keeps purple; Options keeps the default blue underline. */
.ed-tab[data-tab="sections"].is-active   { border-bottom-color: var(--ylw-1); }
.ed-tab[data-tab="containers"].is-active { border-bottom-color: var(--grn-1); }
.ed-tab[data-tab="artefacts"].is-active  { border-bottom-color: var(--pur-1); }
.ed-tab[data-tab="assets"].is-active     { border-bottom-color: var(--pur-1); }

.ed-palette__body { padding: 1rem 1rem 2rem; }
.ed-palette__body[hidden] { display: none; }

/* Shown before a page exists. */
.ed-palette__empty {
    padding: 2rem 1.25rem;
    font-size: var(--siz-min);
    line-height: 1.55;
    color: var(--wht-3);
}

.ed-palette__group { margin-bottom: 1.5rem; }

.ed-palette__group-title { margin-bottom: .65rem; }   /* font: .ed-heading-ctx */

.ed-palette__grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: .5rem;
}

/* A draggable element thumbnail. */
.ed-thumb {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: .5rem;
    padding: .65rem;
    border-radius: var(--rad-2);
    background-color: var(--blk-1);
    outline: solid 1.5px transparent;
    cursor: grab;
    transition: var(--trn);
}

.ed-thumb:hover {
    /*outline-color: var(--blu-1);*/
    transform: translateY(-1px);
}

.ed-thumb:active { cursor: grabbing; }

.ed-thumb.is-dragging { opacity: .4; }

/* Thumbnails that span both columns (full-width sections read better wide). */
.ed-thumb--wide { grid-column: 1 / -1; }

/* Saved-element thumbnails (Assets tab) reuse the .ed-thumb look — same as the
   Sections / Artefacts palette — with a footer row: the name (badge) centred
   under the icon and a delete button to its RIGHT. The left spacer column
   (matching the delete's width) keeps the name visually centred. */
.ed-thumb__foot {
    display: grid;
    grid-template-columns: 18px 1fr 18px;
    align-items: center;
    gap: .15rem;
}
.ed-thumb__foot .ed-thumb__label {
    grid-column: 2;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.ed-thumb__del {
    grid-column: 3;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    padding: 0;
    border: none;
    border-radius: var(--rad-1);
    background-color: transparent;
    color: var(--wht-3);
    font-size: 12px;
    line-height: 1;
    cursor: pointer;
    transition: var(--trn);
}
.ed-thumb__del:hover { background-color: var(--red-2); color: var(--wht-0); }

/* Icons modal — search box + scrollable Lucide preview grid. The search field
   matches the editor's standard text inputs (.ed-insp-input). */
.ed-icons__search {
    width: 100%;
    height: 32px;
    padding: 0 .5rem;
    border: none;
    border-radius: var(--rad-1);
    background-color: var(--blk-1);
    outline: solid 1px var(--blk-0);
    color: var(--wht-1);
    font-size: var(--siz-min);
}
.ed-icons__search:focus { outline-color: var(--blu-1); }
.ed-icons__count { margin-bottom: .6rem; font-size: var(--siz-min); color: var(--wht-3); }
.ed-icons__grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(54px, 1fr));
    gap: .4rem;
    max-height: 50vh;
    overflow-y: auto;
    padding-right: .25rem;
}
.ed-icons__item {
    display: flex;
    align-items: center;
    justify-content: center;
    aspect-ratio: 1;
    border-radius: var(--rad-1);
    background-color: var(--blk-1);
    outline: solid 1px transparent;
    color: var(--wht-1);
    cursor: pointer;
    transition: var(--trn);
}
.ed-icons__item:hover { outline-color: var(--blu-1); color: var(--wht-0); background-color: var(--blk-0); }
.ed-icons__item svg { width: 24px; height: 24px; }
.ed-icons__empty { grid-column: 1 / -1; padding: 1.5rem; text-align: center; color: var(--wht-3); font-size: var(--siz-min); }

/* Recently-used icons strip (above the search results). */
.ed-icons__recent { margin-bottom: .85rem; }
.ed-icons__recent-label { margin-bottom: .4rem; font-size: var(--siz-min); color: var(--wht-3); }
.ed-icons__recent-row { display: flex; flex-wrap: wrap; gap: .4rem; }
.ed-icons__recent-row .ed-icons__item { flex: 0 0 auto; width: 52px; }

.ed-thumb__preview {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 54px;
    padding: .4rem;
    border-radius: var(--rad-1);
    background-color: var(--blk-3);
    color: var(--wht-2);
    overflow: hidden;
}

.ed-thumb__preview svg { width: 32px; height: 32px; color: var(--wht-2); }

.ed-thumb__label {
    font-size: var(--siz-min);
    font-weight: 550;
    color: var(--wht-1);
    text-align: center;
}

/* Assets tab — saved, reusable elements (a draggable list of named cards). */
.ed-assets__list { display: flex; flex-direction: column; gap: .5rem; }

.ed-asset {
    display: flex;
    align-items: center;
    gap: .6rem;
    padding: .55rem .6rem;
    border-radius: var(--rad-2);
    background-color: var(--blk-1);
    outline: solid 1.5px transparent;
    cursor: grab;
    transition: var(--trn);
}

.ed-asset:hover { outline-color: var(--blu-1); }
.ed-asset.is-selected { outline-color: var(--blu-1); background-color: hsla(210, 100%, 42%, .12); }
.ed-asset:active { cursor: grabbing; }
.ed-asset.is-dragging { opacity: .4; }

.ed-asset__glyph {
    display: grid;
    place-items: center;
    width: 34px;
    height: 34px;
    flex-shrink: 0;
    border-radius: var(--rad-1);
    background-color: var(--blk-3);
    color: var(--wht-2);
}

.ed-asset__glyph svg { width: 18px; height: 18px; }

.ed-asset__meta { display: flex; flex-direction: column; gap: .1rem; min-width: 0; flex: 1; }

.ed-asset__name {
    font-size: var(--siz-min);
    font-weight: 550;
    color: var(--wht-1);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ed-asset__tag {
    font-family: var(--fnt-fix);
    font-size: 11px;
    color: var(--wht-3);
}

.ed-asset__del {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    flex-shrink: 0;
    border-radius: var(--rad-1);
    background-color: transparent;
    color: var(--wht-3);
    opacity: 0;
    cursor: pointer;
    transition: var(--trn);
}

.ed-asset:hover .ed-asset__del { opacity: 1; }
.ed-asset__del:hover { background-color: var(--red-2); color: var(--wht-0); }

/* Assets tab — four sections (Elements, Foreground/Background images, Icons). */
.ed-assets__section { margin-bottom: 1.25rem; }
.ed-assets__head { display: flex; align-items: center; justify-content: space-between; margin-bottom: .5rem; }
.ed-assets__title { font-size: var(--siz-min); font-weight: 550; color: var(--wht-1); }
.ed-assets__add {
    display: inline-flex; align-items: center; justify-content: center;
    width: 24px; height: 24px; border-radius: var(--rad-1);
    background-color: var(--blk-1); outline: solid 1px var(--blk-0);
    color: var(--wht-2); cursor: pointer; transition: var(--trn);
}
.ed-assets__add:hover { color: var(--wht-0); outline-color: var(--blu-1); }
.ed-assets__add svg { width: 14px; height: 14px; }

/* Full-width "save selection as element" button atop the Assets tab (primary,
   matching .btn-1). Replaced the small + add-icon when the tab became Elements-only. */
.ed-assets__add-full {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: .4rem;
    width: 100%;
    min-height: 36px;
    margin-bottom: 1rem;
    padding: 0 1rem;
    border: none;
    border-radius: var(--rad-1);
    background-color: var(--blu-1);
    color: var(--wht-0);
    font-family: var(--fnt-std);
    font-size: var(--siz-0);
    font-weight: 550;
    cursor: pointer;
    transition: var(--trn);
}
.ed-assets__add-full svg { width: 16px; height: 16px; }
.ed-assets__add-full:not(:disabled):hover { background-color: var(--blu-0); }
.ed-assets__add-full:disabled { opacity: .5; cursor: not-allowed; }
.ed-assets__grid { display: flex; flex-wrap: wrap; gap: .5rem; }
.ed-assets__empty { grid-column: 1 / -1; width: 100%; padding: .35rem 0; font-size: var(--siz-min); color: var(--wht-3); }
.ed-assets__grid .ed-asset:not(.ed-asset--img):not(.ed-asset--icon) { width: 100%; }   /* element cards take a full row */
.ed-asset--img, .ed-asset--icon {
    position: relative; width: 56px; height: 56px; padding: 0;
    overflow: hidden; display: grid; place-items: center;
}
.ed-asset__thumb { width: 100%; height: 100%; object-fit: cover; display: block; }
.ed-asset--icon .ed-asset__icon { display: grid; place-items: center; color: var(--wht-1); }
.ed-asset--icon .ed-asset__icon svg { width: 26px; height: 26px; }
.ed-asset--img .ed-asset__name { display: none; }   /* name shown via the hover title */
.ed-asset--img .ed-asset__del, .ed-asset--icon .ed-asset__del {
    position: absolute; top: 2px; right: 2px; width: 18px; height: 18px;
    background-color: hsla(0, 0%, 0%, .55); opacity: 0;
}

/* Right: canvas */
.ed-canvas {
    flex: 1;
    min-width: 0;
    padding: 1.5rem;
    background-color: var(--blk-4);
    background-image:
        radial-gradient(circle at 1px 1px, hsla(0,0%,100%,.04) 1px, transparent 0);
    background-size: 22px 22px;
    overflow-x: hidden;
    overflow-y: scroll;                          /* always reserve + show the bar */
    scrollbar-width: thin;                       /* Firefox */
    scrollbar-color: var(--blk-0) var(--blk-2);  /* thumb / track */
}

/* Always-on dark scrollbar for the canvas window (WebKit/Blink). The track sits
   a couple shades lighter than the canvas so the bar is visible even when the
   page fits without scrolling. */
.ed-canvas::-webkit-scrollbar { width: 12px; }
.ed-canvas::-webkit-scrollbar-track { background: var(--blk-2); }
.ed-canvas::-webkit-scrollbar-thumb {
    background: var(--blk-0);
    border: 3px solid var(--blk-2);   /* inset border reads the thumb as a pill */
    border-radius: 12px;
}
.ed-canvas::-webkit-scrollbar-thumb:hover { background: var(--wht-3); }

/* Empty state before a page is created. */
.ed-canvas__empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1rem;
    height: 100%;
    min-height: 60vh;
    text-align: center;
    color: var(--wht-3);
}

.ed-canvas__empty svg { width: 56px; height: 56px; opacity: .5; }

/* .ed-canvas__empty h2 font: .ed-heading-lg */

.ed-canvas__empty p { font-size: var(--siz-0); max-width: 32ch; }

/* The page surface ("paper") — the editor frame around the authored page.
   It carries NO layout opinions of its own beyond being a centred sheet; the
   page's real layout lives on [data-page-root] as utility classes. */
.ed-page {
    display: flex;
    flex-direction: column;          /* titlebar (fixed) + content viewport (fills the rest) */
    /* The WINDOW CHROME — titlebar, outline, corners, shadow — is NEVER scaled by a
       viewport: only its child .ed-vp (the content) zooms. So the titlebar height and
       the 2px outline stay pixel-constant on every resolution. The window's WIDTH does
       follow the active viewport (= device width × fit-scale) so it still represents
       the device; --ed-page-w is that rendered width (set by applyViewportSizing), and
       100% in edit mode. --ed-page-h keeps the window at 100% of the canvas height. */
    width: var(--ed-page-w, 100%);
    max-width: var(--ed-page-frame, 1280px);
    transition: width .2s ease;
    min-height: var(--ed-page-h, calc(100vh - var(--mst-hgt) - 3rem));
    margin: 0 auto;
    background-color: var(--color-bg);
    outline: solid 2px var(--blk-0);   /* constant — the frame itself is not zoomed */
    border-radius: var(--rad-2) var(--rad-2) 0 0;
    box-shadow: var(--shd-2);
    overflow: hidden;
    /* Keep clear room inside the overflow:hidden clip so a selected element's 1.5px
       outline never reaches the sheet edge. 1.5px (= the outline width) put the ring
       EXACTLY at the clip, so the sub-pixel shift from a viewport zoom round-trip
       (Mobile/Tablet/Desktop → Edit) sheared the right side off. 4px keeps it clear. */
    padding: 4px;
}

/* The content viewport — the ONLY part a viewport scales. It is laid out at the
   EXACT device width (= the breakpoint width, since it has no padding) and zoom-
   scaled to fit; it's the `ed-vp` query container, so authored tokens with a
   responsive context (m+, l, …) compile to @container queries against THIS box and
   the page reflows as if the browser window were resized — all while the chrome
   above stays constant. inline-size only — height still grows with content. */
.ed-vp {
    flex: 1 0 auto;
    display: flex;
    flex-direction: column;
    width: var(--ed-vp-w, 100%);
    zoom: var(--ed-vp-zoom, 1);
    container: ed-vp / inline-size;
}

/* The body (page-root) always fills the sheet height on the canvas — so it stays
   a full-height drop target and its selection ring spans the whole page — and
   still grows past it for taller content. A min-height (sheet height − the 40px
   titlebar) is used rather than flex-grow, which doesn't distribute a flex
   container's min-height extra. (Editor only: not part of a Download export.) */
.ed-vp > [data-page-root] {
    flex: 1 0 auto;
    min-height: calc(100vh - var(--mst-hgt) - 5rem - 40px);
}

/* Safari-style window chrome atop the page sheet (editor-only — never exported).
   A 1fr/auto/1fr grid keeps the address bar centred while the lights sit left. It
   lives in .ed-page (outside the zoomed .ed-vp), so its 40px height and 1px border
   are CONSTANT on every viewport — only the content below is scaled. */
.ed-titlebar {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    flex-shrink: 0;
    height: 40px;
    padding: 0 1rem;
    background: linear-gradient(var(--blk-1), var(--blk-2));
    border-bottom: solid 1px var(--blk-0);
    -webkit-user-select: none;
    user-select: none;
}

.ed-titlebar__lights { display: flex; gap: .5rem; }
.ed-titlebar__lights span { width: 12px; height: 12px; border-radius: 50%; }
.ed-titlebar__lights span:nth-child(1) { background: #ff5f57; }
.ed-titlebar__lights span:nth-child(2) { background: #febc2e; }
.ed-titlebar__lights span:nth-child(3) { background: #28c840; }

.ed-titlebar__address {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    min-width: 200px;
    max-width: 360px;
    height: 24px;
    padding: 0 .75rem;
    border-radius: var(--rad-1);
    background-color: var(--blk-3);
    color: var(--wht-3);
    font-size: var(--siz-min);
    white-space: nowrap;
    overflow: hidden;
}
.ed-titlebar__address svg { width: 13px; height: 13px; opacity: .7; flex-shrink: 0; }
.ed-titlebar__address span { overflow: hidden; text-overflow: ellipsis; }

/* Viewport device buttons (right of the titlebar) — resize the page sheet to a
   mobile / tablet / desktop width. Glyphs + active style mirror the inspector's
   S/M/L scope tabs so the two viewport controls read as one language. */
.ed-titlebar__views {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    gap: .15rem;
}
.ed-titlebar__view {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 22px;
    padding: 0;
    border: 0;
    border-radius: var(--rad-1);
    background-color: transparent;
    color: var(--wht-3);
    cursor: pointer;
    transition: var(--trn);
}
.ed-titlebar__view svg { width: 15px; height: 15px; }
.ed-titlebar__view:hover { color: var(--wht-0); background-color: var(--blk-3); }
.ed-titlebar__view.is-active { background-color: var(--blu-1); color: var(--wht-0); }

/* Empty authored page — just a centred hint, no dashed card. The page sheet is
   the only frame; the hint vanishes the moment a section is dropped in. */
[data-page-root]:empty {
    display: flex;
    align-items: center;
    justify-content: center;
    /* no min-height — the body fills the sheet via .ed-page > [data-page-root] */
}

/*[data-page-root]:empty::before {
    content: "Drag a section from the palette to begin";
    font-size: var(--siz-0);
    color: var(--wht-3);
}*/

/* Drop cues (editor-only, set during dragover). A section drop lights the whole
   page sheet; an artefact drop outlines the section/container it will enter; an
   artefact with no valid section under the pointer shows the "no-drop" cursor.
   The artefact cue is a data-attribute (never a class) so it can't leak into the
   authored class list or wake the autosave / styler observers. */
.ed-page.is-drop-target {
    outline-color: var(--blu-1);
    box-shadow: 0 0 0 4px hsla(210, 100%, 42%, .12), var(--shd-2);
}

.ed-page.is-drop-invalid { cursor: not-allowed; }

[data-page-root] [data-ed-drop="target"] {
    outline: dashed 2px var(--blu-1) !important;
    outline-offset: -2px !important;
    background-color: hsla(210, 100%, 42%, .06);
}

/* ⌘-drag to move: while ⌘ (Command) is held every authored element shows the move
   cursor; the element being dragged is dimmed. (draggable + data-ed-moving are
   editor-only, stripped from saves/exports.) */
.ed-move-mode [data-page-root] * { cursor: move; }
[data-page-root] [data-ed-moving] { opacity: .4; }

/* ───────────────── HTML source inspector (the Code tab) ─────────────────
   A live, read-only pretty-print of the authored markup (built by source.js). Each
   .ed-src-node maps to one canvas element; hover / selection / parent state on the
   canvas tints that node's OWN tag lines (the `>` child combinator keeps nested
   elements distinct) in the element's kind colour — same language as the rings. */
.ed-src {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: var(--siz-min);
    line-height: 1.6;
    color: var(--wht-1);
    padding: .5rem 0;
    -webkit-user-select: text;
    user-select: text;
}
.ed-src-empty { padding: 1rem .75rem; color: var(--wht-3); font-style: italic; }
.ed-src-line {
    /* Soft-wrap at the inspector width — long class lists wrap (continuation aligns
       at the line's indent via padding-left), and `overflow-wrap: anywhere` breaks
       even a single long token, so there's never a horizontal scrollbar. `pre-wrap`
       still preserves the spacing between attributes. */
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    padding-right: .75rem;
    border-left: 2px solid transparent;   /* the selected-state accent bar slots in here */
    cursor: pointer;                       /* a tag line is clickable — it selects its canvas element */
}
.ed-src-tag  { color: var(--wht-0); }
.ed-src-attr { color: var(--wht-2); }
.ed-src-val  { color: var(--wht-1); }
.ed-src-punc { color: var(--wht-3); }
.ed-src-text { color: var(--wht-2); font-style: italic; }

/* Per-kind highlight colour, mirroring the canvas rings (section yellow, container
   green, artefact purple). */
.ed-src-node[data-kind="section"]   { --ed-src-k: var(--ylw-1); }
.ed-src-node[data-kind="container"] { --ed-src-k: var(--grn-1); }
.ed-src-node[data-kind="artefact"]  { --ed-src-k: var(--pur-1); }
.ed-src-node[data-kind="body"]      { --ed-src-k: var(--wht-2); }

/* ── View tree — top of the Code tab. One row per highlighted (ancestor/hover) and
   selected canvas element, indented by nesting depth, with a 3px left bar in the
   element's kind colour. Highlighted rows are dimmed (muted); the selected row is full. */
.ed-tree {
    display: flex;
    flex-direction: column;
    gap: .25rem;                 /* breathing room between rows */
    padding: .5rem 0;
}
.ed-tree[hidden] { display: none; }
.ed-tree-row {
    box-sizing: border-box;
    /* The indent is a margin-left (set per-row inline), so it sits BEFORE the border —
       the 3px kind-colour bar steps right with each nesting level. */
    border-left: 3px solid var(--wht-3);
    padding: .2rem .5rem;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: var(--siz-min);
    line-height: 1.5;
    color: var(--wht-0);
    opacity: .32;                /* default rows are heavily muted — label AND kind bar dim */
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    cursor: pointer;             /* click a row to select its canvas element */
}
.ed-tree-row:hover { opacity: 1; background-color: var(--blk-1); }
.ed-tree-row[data-kind="section"]   { border-left-color: var(--ylw-1); --k: var(--ylw-1); }
.ed-tree-row[data-kind="container"] { border-left-color: var(--grn-1); --k: var(--grn-1); }
.ed-tree-row[data-kind="artefact"]  { border-left-color: var(--pur-1); --k: var(--pur-1); }
.ed-tree-row[data-kind="body"]      { border-left-color: var(--wht-2); --k: var(--wht-2); }
/* The selection chain + hovered element are LIT (full opacity + a barely-there kind
   tint). The SELECTED element is clearly distinct: a strong kind fill + bold label.
   Everything else stays muted. */
.ed-tree-row[data-state="highlighted"] { opacity: 1; background-color: color-mix(in srgb, var(--k) 7%, transparent); }
.ed-tree-row[data-state="selected"]    { opacity: 1; font-weight: 700; background-color: color-mix(in srgb, var(--k) 40%, transparent); }
.ed-tree-tag { color: inherit; }

/* Column guidelines — faint, 1px, DASHED vertical lines down the FULL height of the
   Code tab at every tree tab stop (a 16px column, matching the rows' per-level margin
   in source.js), so the nesting columns read even in the empty space below the rows.
   The 16px left padding on .ed-palette__body lands the first stop (depth 0) on the
   line at x=16. (If the row indent step changes in source.js, match it here.)
   The columns are a 1px-per-16px gradient; the dash is a vertical mask that breaks
   each line into 3px dashes. Painted on a behind-content layer (isolation + z-index:-1)
   so it never sits over the tree rows, and so the mask doesn't clip the content. */
.ed-palette__body[data-panel="code"] {
    position: relative;
    isolation: isolate;
    min-height: 100%;
}
.ed-palette__body[data-panel="code"]::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background-image: repeating-linear-gradient(to right,
        color-mix(in srgb, var(--wht-3) 20%, transparent) 0 1px,
        transparent 1px 16px);
    -webkit-mask-image: repeating-linear-gradient(to bottom, #000 0 3px, transparent 3px 6px);
            mask-image: repeating-linear-gradient(to bottom, #000 0 3px, transparent 3px 6px);
}

/* Tint only the element's OWN tag lines: parent (ancestor) faint, hover muted,
   selected full + an accent bar. color-mix keeps the kind hue at low alpha. */
.ed-src-node.is-parent   > .ed-src-line { background: color-mix(in srgb, var(--ed-src-k) 10%, transparent); }
.ed-src-node.is-hover    > .ed-src-line { background: color-mix(in srgb, var(--ed-src-k) 17%, transparent); }
.ed-src-node.is-selected > .ed-src-line {
    background: color-mix(in srgb, var(--ed-src-k) 27%, transparent);
    border-left-color: var(--ed-src-k);
}

/* An empty section / container keeps a min-height in the editor so it stays
   selectable and droppable. No placeholder icon — the element's own hover/selected
   rings are the only affordance. Editor-only (not exported): the authored element
   still carries nothing but its utility classes. */
[data-page-root] [data-el="emptySection"]:empty,
[data-page-root] [data-el="container"]:empty {
    min-height: 72px;
}

/* Image artefact — an editor-only picture-icon placeholder (centred via the
   element's flx-row(cc)) until a background-image is set, then it hides so the
   image shows through. Never exported. */
[data-page-root] [data-el="image"]::before {
    content: "";
    width: 56px;
    height: 56px;
    background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23808d9c' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='18' height='18' x='3' y='3' rx='2' ry='2'/%3E%3Ccircle cx='9' cy='9' r='2'/%3E%3Cpath d='m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21'/%3E%3C/svg%3E") center / contain no-repeat;
    opacity: .7;
    pointer-events: none;
}
[data-page-root] [data-el="image"][style*="background-image"]::before,
[data-page-root] [data-el="image"][data-bg]::before { display: none; }

/* ── Modal (New Page) ──────────────────────────────────────────────────── */

.ed-modal {
    position: fixed;
    inset: 0;
    z-index: 20;
    display: none;
    align-items: center;
    justify-content: center;
    padding: 1.5rem;
}

.ed-modal.is-open { display: flex; }

.ed-modal__overlay {
    position: absolute;
    inset: 0;
    background-color: hsla(0, 0%, 0%, .7);
    animation: ed-fade-in .15s var(--log);
}

.ed-modal__card {
    position: relative;
    z-index: 1;
    display: flex;
    flex-direction: column;
    gap: 2.25rem;
    width: 100%;
    max-width: 560px;
    max-height: calc(100vh - 3rem);
    padding: 2rem;
    background-color: var(--blk-2);
    outline: solid 2px var(--blk-0);
    border-radius: var(--rad-4);
    box-shadow: var(--shd-2);
    overflow-y: auto;
    -animation: ed-fade-down .075s var(--log);
}

/* When the card overflows and shows a scrollbar, square the right corners so the
   scrollbar sits flush against a straight edge (toggled in editor.js). */
.ed-modal__card.is-scrolling {
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
}

.ed-modal__head { display: flex; flex-direction: column; gap: .35rem; }

/* .ed-modal__title font: .ed-heading-lg */

.ed-modal__sub { font-size: var(--siz-0); color: var(--wht-2); }

.ed-modal__close {
    position: absolute;
    top: 1rem;
    right: 1rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border-radius: var(--rad-1);
    background-color: transparent;
    color: var(--wht-1);
    cursor: pointer;
    transition: var(--trn);
}

.ed-modal__close:hover { background-color: var(--blk-1); }

.ed-modal__field {
    display: flex;
    flex-direction: column;
    gap: .75rem;
}

/* .ed-modal__section-label font: .ed-heading-ctx */

/* Dimension option list — selectable cards (radio group). */
.ed-options { display: flex; flex-direction: column; gap: .75rem; }

.ed-option {
    display: flex;
    align-items: center;
    gap: 1rem;
    /*border-radius: var(--rad-3);*/
    /*background-color: var(--blk-1);*/
    /*outline: solid 2px var(--blk-0);*/
    cursor: pointer;
    transition: var(--trn);
}

.ed-option:hover { outline-color: var(--wht-1); }

.ed-option.is-selected {
    outline-color: var(--blu-1);
}

.ed-option input { position: absolute; opacity: 0; pointer-events: none; }

.ed-option__radio {
    display: grid;
    place-items: center;
    width: 22px;
    height: 22px;
    flex-shrink: 0;
    border-radius: 50%;
    outline: solid 2px var(--wht-3);
}

.ed-option__radio::after {
    content: "";
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background-color: var(--blu-1);
    transform: scale(0);
    transition: var(--trn);
}

.ed-option.is-selected .ed-option__radio { outline-color: var(--blu-1); }
.ed-option.is-selected .ed-option__radio::after { transform: scale(1); }

.ed-option__body { display: flex; flex-direction: column; gap: .2rem; }

.ed-option__name {
    font-size: var(--siz-0);
    font-weight: 550;
    color: var(--wht-0);
}

.ed-option__meta { font-size: var(--siz-min); color: var(--wht-2); }

.ed-option__spec {
    margin-left: auto;
    font-family: var(--fnt-fix);
    font-size: var(--siz-min);
    color: var(--wht-3);
    text-align: right;
    white-space: nowrap;
}

.ed-modal__actions {
    display: flex;
    justify-content: flex-end;
    gap: .75rem;
    padding-top: .5rem;
}

/* ── Buttons (modal actions) ───────────────────────────────────────────── */
/* Standardised to the editor's own button look — rad-1 corners + a compact
   height — rather than nanobase's full-height pill (var(--btn-hgt) radius). */

.btn-1, .btn-2 {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .5rem;
    min-height: 36px;
    padding: 0 1rem;
    border: none;
    border-radius: var(--rad-1);
    font-family: var(--fnt-std);
    font-size: var(--siz-0);
    font-weight: 550;
    text-decoration: none;
    cursor: pointer;
    transition: var(--trn);
}

.btn-1 { background-color: var(--blu-1); color: var(--wht-0); }
.btn-1:not(:disabled):hover { background-color: var(--blu-0); }
.btn-2 { background-color: var(--blk-1); color: var(--wht-1); }
.btn-2:not(:disabled):hover { background-color: var(--blk-0); }

.btn-1:disabled, .btn-2:disabled { opacity: .5; cursor: not-allowed; }

/* data-confirm: a button armed for a confirming second click — solid red.
   `button.is-confirming` (0,1,1) outranks the .btn-* / :hover rules above. */
button.is-confirming,
button.is-confirming:hover { background-color: var(--red-1); color: var(--wht-0); }

/* ── Inspector (right: property toolbar) ───────────────────────────────── */

.ed-inspector {
    display: flex;
    flex-direction: column;
    flex-shrink: 0;
    width: 250px;
    border-left: solid 2px var(--blk-0);
    background-color: var(--blk-2);
    overflow-y: auto;
}

.ed-inspector__empty {
    padding: 2rem 1.25rem;
    font-size: var(--siz-min);
    line-height: 1.55;
    color: var(--wht-3);
}

.ed-inspector__head {
    position: sticky;
    top: 0;
    display: flex;
    flex-direction: column;       /* title row, then the actions on their own line */
    align-items: stretch;
    gap: .6rem;
    padding: .85rem 1rem;
    background-color: var(--blk-2);
    border-bottom: solid 1px var(--blk-0);
    z-index: 1;
}

.ed-inspector__title { display: flex; align-items: center; gap: .5rem; min-width: 0; }

.ed-tag {
    font-family: var(--fnt-fix);
    font-size: var(--siz-min);
    color: var(--wht-2);
}

.ed-inspector__name {
    padding: .1rem .5rem;
    border-radius: var(--rad-1);
    background-color: var(--blu-1);
    color: var(--wht-0);
    font-size: var(--siz-min);
    font-weight: 550;
}

/* The "asset" badge marks symbol-edit mode; purple to set it apart from the
   blue element-name badge. The note explains the propagation. */
.ed-inspector__name--asset { background-color: var(--pur-1); }

.ed-insp-assetnote {
    margin: 0 1rem;
    padding: .5rem .65rem;
    border-radius: var(--rad-1);
    background-color: hsla(255, 100%, 70%, .12);
    color: var(--wht-2);
    font-size: var(--siz-min);
    line-height: 1.45;
}

.ed-insp-actions { display: flex; gap: .25rem; }

.ed-insp-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 1;                /* stretch the full-width actions row equally */
    height: 28px;
    border-radius: var(--rad-1);
    background-color: var(--blk-1);
    color: var(--wht-1);
    font-size: var(--siz-0);
    line-height: 1;
    cursor: pointer;
    transition: var(--trn);
}

.ed-insp-btn:not(:disabled):hover { background-color: var(--blk-0); }
.ed-insp-btn--danger:not(:disabled):hover { background-color: var(--red-2); color: var(--wht-0); }
.ed-insp-btn:disabled { opacity: .35; cursor: not-allowed; }
.ed-insp-btn svg { width: 15px; height: 15px; }
.ed-insp-btn--accent { background-color: var(--blu-1); color: var(--wht-0); }
.ed-insp-btn--accent:not(:disabled):hover { background-color: var(--blu-0); }

.ed-inspector__body { padding: .5rem 1rem 2rem; }

/* Viewport scope sub-tabs (S / M / L) — a segmented control inside the inspector. */
.ed-scope-tabs {
    display: flex;
    gap: .2rem;
    margin: .5rem 0 1rem;
    padding: .25rem;
    border-radius: var(--rad-2);
    background-color: var(--blk-1);
}
.ed-scope-tab {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: .35rem;
    border-radius: var(--rad-1);
    background-color: transparent;
    color: var(--wht-2);
    font-family: var(--fnt-hdg);
    font-size: var(--siz-min);
    font-weight: 550;
    cursor: pointer;
    transition: var(--trn);
}
.ed-scope-tab svg { width: 15px; height: 15px; }
.ed-scope-tab:hover { color: var(--wht-0); }
.ed-scope-tab.is-active { background-color: var(--blu-1); color: var(--wht-0); }

.ed-insp-section { padding: 1rem 0; border-bottom: solid 1px var(--blk-1); }
.ed-insp-section:last-child { border-bottom: none; }

.ed-insp-section__title { margin-bottom: .65rem; }   /* font: .ed-heading-ctx */

.ed-insp-row {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
    margin-bottom: .5rem;
}

.ed-insp-row > span {
    font-size: var(--siz-min);
    color: var(--wht-2);
    white-space: nowrap;
}

.ed-insp-row select {
    flex: 1;
    min-width: 0;
    max-width: 60%;
    height: 32px;
    padding: 0 1.75rem 0 .5rem;       /* room for the custom chevron on the right */
    border-radius: var(--rad-1);
    background-color: var(--blk-1);
    outline: solid 1px var(--blk-0);
    color: var(--wht-1);
    font-size: var(--siz-min);
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;                 /* drop the native OS dropdown arrow */
}

.ed-insp-row select:focus { outline-color: var(--blu-1); }

/* Custom dropdown chevron = chevron-down.svg, used as a mask + theme-coloured so
   it renders identically across browsers (a currentColor SVG won't inherit the
   element's colour as a background-image). Scoped to rows that actually hold a
   dropdown, so the Link/Image/Keep-together rows (inputs + buttons) get no chevron. */
.ed-insp-row:has(.dropdown-input)::after {
    content: "";
    position: absolute;
    right: .6rem;
    top: 50%;
    width: 14px;
    height: 14px;
    transform: translateY(-50%);
    background-color: var(--wht-2);
    -webkit-mask: url(../icons/chevron-down.svg) center / contain no-repeat;
    mask: url(../icons/chevron-down.svg) center / contain no-repeat;
    pointer-events: none;
}

/* A control that doesn't apply to the selected element — greyed and inert. */
.ed-insp-row.is-disabled { opacity: .4; }
.ed-insp-row.is-disabled select { cursor: not-allowed; }

/* ── Custom dropdown (vanilla component, themed for the editor) ─────────────
   Replaces the native <select>. While open, its option list is portaled to <body>
   with fixed positioning (by dropdown.js) so it isn't clipped by the palette's
   overflow:scroll — hence .dropdown-list is styled globally, not under a row. */
.dropdown-wrapper { position: relative; width: 100%; }

.dropdown-input {
    width: 100%;
    height: 32px;
    padding: 0 1.75rem 0 .5rem;
    border: none;
    border-radius: var(--rad-1);
    background-color: var(--blk-1);
    outline: solid 1px var(--blk-0);
    color: var(--wht-1);
    font-family: var(--fnt-std);
    font-size: var(--siz-min);
    cursor: pointer;
    text-overflow: ellipsis;
}
.dropdown-input:focus { outline-color: var(--blu-1); }

.dropdown-list {
    display: none;
    flex-direction: column;
    max-height: 220px;
    padding: .35rem;
    overflow-y: auto;
    background-color: var(--blk-0);
    outline: solid 1px var(--blk-2);
    border-radius: var(--rad-1);
    box-shadow: var(--shd-2);
    z-index: 1000;
}
.dropdown-option {
    display: flex;
    align-items: center;
    min-height: 30px;
    padding: 0 .6rem;
    border-radius: var(--rad-1);
    font-size: var(--siz-min);
    color: var(--wht-1);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    cursor: pointer;
    user-select: none;
}
.dropdown-option:hover { background-color: var(--blk-2); }
.dropdown-option.highlighted { background-color: var(--blu-1); color: var(--wht-0); }

/* In an inspector row the dropdown takes the old select's place + sizing; the row's
   ::after chevron is kept, so suppress the input's own background-image chevron. */
.ed-insp-row .dropdown-wrapper { flex: 1; min-width: 0; max-width: 60%; }
.ed-insp-row .dropdown-input { background-image: none; }
.ed-insp-row.is-disabled .dropdown-input { cursor: not-allowed; }

.ed-insp-raw {
    width: 100%;
    padding: .6rem .65rem;
    border-radius: var(--rad-1);
    background-color: var(--blk-3);
    outline: solid 1px var(--blk-0);
    color: var(--wht-1);
    font-family: var(--fnt-fix);
    font-size: var(--siz-min);
    line-height: 1.5;
    resize: vertical;
}

.ed-insp-raw:focus { outline-color: var(--blu-1); }

/* ── Inspector: Link inputs, Background-image control, action buttons ─────── */

/* Text inputs (Link URL / Title). */
.ed-insp-input {
    flex: 1;
    min-width: 0;
    max-width: 60%;
    height: 32px;
    padding: 0 .5rem;
    border: none;
    border-radius: var(--rad-1);
    background-color: var(--blk-1);
    outline: solid 1px var(--blk-0);
    color: var(--wht-1);
    font-size: var(--siz-min);
}
.ed-insp-input:focus { outline-color: var(--blu-1); }
.ed-insp-input:disabled { cursor: not-allowed; opacity: .55; }
.ed-insp-input.is-invalid { outline-color: var(--red-1); }
/* Inside the input+clear flex wrapper (Href), the field fills the row. */
.ed-insp-imgctl .ed-insp-input { max-width: none; }

/* Background-image control (Canvas › Image): a name/Choose button + a clear (✕). */
.ed-insp-imgctl {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: .35rem;
    flex: 1;
    min-width: 0;
    max-width: 60%;
}
.ed-insp-imgbtn {
    flex: 1;
    min-width: 0;
    height: 32px;
    padding: 0 .6rem;
    border: none;
    border-radius: var(--rad-1);
    background-color: var(--blk-1);
    outline: solid 1px var(--blk-0);
    color: var(--wht-1);
    font-size: var(--siz-min);
    cursor: pointer;
    text-align: left;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.ed-insp-imgbtn:hover { outline-color: var(--blu-1); }
.ed-insp-imgclear {
    flex: none;
    width: 32px;
    height: 32px;
    border: none;
    border-radius: var(--rad-1);
    background-color: var(--blk-1);
    outline: solid 1px var(--blk-0);
    color: var(--wht-2);
    cursor: pointer;
}
.ed-insp-imgclear:hover { outline-color: var(--red-1); color: var(--wht-0); }

/* Link section's status hint. */
.ed-insp-hint {
    margin-top: .5rem;
    font-size: var(--siz-min);
    color: var(--wht-3);
    line-height: 1.4;
}

/* Selection + hover rings — editor-only, keyed on data attributes (never a class
   on the authored element). `outline` doesn't affect layout. The [data-page-root]
   ancestor gives specificity (0,2,0) that beats any single-class out(...) utility
   (0,1,0) WITHOUT !important — which matters because !important would block the
   fade-in animation below. Stripped on export. */
@keyframes ed-ring-in {
    from { outline-color: transparent; }   /* fades up to each rule's own colour */
}

/* Parent affordance — when an element is selected, its PARENT gets a dashed ring in
   the parent's OWN kind colour (keyed on data-ed-parent; purple base here, recoloured
   per kind below) plus the padding hatch, so the container context AND its padding read
   at a glance. Placed BEFORE the hover/selection rules so actually hovering or selecting
   the parent still wins (equal specificity, later in source). Lowest z-index so it never
   lifts above sibling content. Editor-only. */
[data-page-root][data-ed-parent],
[data-page-root] [data-ed-parent] {
    position: relative;
    z-index: 1;
    outline: 1.5px dashed var(--pur-1);
    outline-offset: 0;
    animation: ed-ring-in .075s ease-in-out;
}

/* Hover affordance — a light dashed ring on the editable element under the
   pointer (keyed on data-ed-hover), fading in over 1s. */
[data-page-root][data-ed-hover],
[data-page-root] [data-ed-hover] {
    position: relative;
    z-index: 2;
    outline: 1.5px dashed var(--pur-1);
    outline-offset: 0;
    animation: ed-ring-in .075s ease-in-out;
}

/* While hovered, hatch the element's PADDING region with muted -45° lines (like a
   design tool's padding overlay). The pseudo fills the padding box; `padding:
   inherit` makes its content box match the element's, and the mask (whole box XOR
   content box) leaves only the padding ring — so the hatch shows solely where
   there's padding, and nothing at all when the element has none. Shown for the HOVERED
   element, the SELECTED element, and the highlighted PARENT alike — so whatever you're
   working on, plus its container, reveals its padding. (The body/page-root only ever
   shows this hatch, never an outline ring — see below.) Editor-only (a ::after, never
   in the authored DOM) and pointer-transparent. */
[data-page-root][data-ed-hover]::after,
[data-page-root] [data-ed-hover]::after,
[data-page-root][data-ed-selected]::after,
[data-page-root] [data-ed-selected]::after,
[data-page-root][data-ed-parent]::after,
[data-page-root] [data-ed-parent]::after {
    content: "";
    position: absolute;
    inset: 0;
    padding: inherit;
    box-sizing: border-box;
    pointer-events: none;
    z-index: 1;
    background: repeating-linear-gradient(-45deg, var(--wht-3) 0 1px, transparent 1px 7px);
    opacity: .5;
    -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
    mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    mask-composite: exclude;
}

/* Selection ring — solid, fading in over 1s. Placed AFTER the hover rule so a
   selected element that's also under the pointer keeps the solid ring (equal
   specificity, later in source wins) instead of the dashed one. */
[data-page-root] [data-ed-selected],
[data-page-root][data-ed-selected] {
    position: relative;              /* establish a stacking context so the ring... */
    z-index: 3;                      /* ...draws above adjacent canvas content */
    outline: 1.5px solid var(--pur-1);
    outline-offset: 0;
    animation: ed-ring-in .075s ease-in-out;
}

/* Every ring hugs the element (outline-offset: 0) so it fits the 1.5px clip-safe
   padding .ed-page reserves (see above). The BODY (page-root) draws NO outline ring in
   any state — a full-sheet ring is just noise — so its highlight is the padding hatch
   alone; sections/containers recolour their own rings below. */
[data-page-root][data-ed-selected] { outline-color: transparent; }
[data-page-root][data-ed-hover]    { outline-color: transparent; }
[data-page-root][data-ed-parent]   { outline-color: transparent; }

/* Ring colour by element KIND, so the three highlight types stay distinct:
   Artefact = purple (the base colour set above), Section = blue, Container = green.
   Specificity stacks the precedence naturally — container (0,3,0) > section (0,2,1)
   > artefact base (0,2,0). The fade keyframe pins only `from: transparent` and
   animates up to whichever colour wins here. */

/* Sections — every Sections-palette element builds a <section>. */
[data-page-root] section[data-ed-selected],
[data-page-root] section[data-ed-hover],
[data-page-root] section[data-ed-parent] { outline-color: var(--ylw-1); }

/* Containers — green. */
[data-page-root] [data-el="container"][data-ed-selected],
[data-page-root] [data-el="container"][data-ed-hover],
[data-page-root] [data-el="container"][data-ed-parent] { outline-color: var(--grn-1); }

/* Inline text editing — a leaf made contenteditable on double-click shows a text
   caret (the selection ring already frames it). */
[data-page-root] [contenteditable] { cursor: text; }

/* Icon artefacts paint their glyph on a ::before so the element BOX stays unmasked and
   shows the same selection/hover outline as any other artefact — a mask on the element
   itself would clip the ring (and the padding hatch). The per-icon mask url is injected
   by Icons.applyMasks onto [data-icon]::before; here we set up the box (transparent
   itself) and the glyph layer (currentColor = the Icon › Stroke colour). Editor-only:
   the Download still masks the element directly, so the published page is unaffected. */
[data-page-root] [data-el="icon"] {
    position: relative;
    background-color: transparent !important;
}
[data-page-root] [data-el="icon"]::before {
    content: "";
    position: absolute;
    inset: 0;
    background-color: currentColor;
}

/* Image picker modal — a big upload drop-zone + a scrollable strip of the images
   already present in the page (scanned from background-image inline styles; the
   editor keeps no separate media store). The card is wider than the others. */
.ed-modal__card--wide { max-width: 600px; }

.ed-imgpick__drop {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: .6rem;
    min-height: 180px;
    padding: 1.5rem;
    border-radius: var(--rad-2);
    border: dashed 2px var(--wht-3);
    background-color: var(--blk-1);
    color: var(--wht-2);
    font-size: var(--siz-min);
    font-weight: 550;
    text-align: center;
    cursor: pointer;
    transition: var(--trn);
}
.ed-imgpick__drop:hover,
.ed-imgpick__drop.is-over { border-color: var(--blu-1); color: var(--wht-0); background-color: var(--blk-0); }
.ed-imgpick__drop svg { width: 34px; height: 34px; opacity: .8; }

/* On drop / choose, the dropped image previews here (covers the box, hides the
   prompt) before it's stored. */
.ed-imgpick__drop.has-preview {
    border-style: solid;
    background-size: cover;
    background-position: center;
}
.ed-imgpick__drop.has-preview svg,
.ed-imgpick__drop.has-preview span { display: none; }

/* Every available photo (project images/ folder) as a small thumbnail to reuse. */
.ed-imgpick__thumbs {
    display: flex;
    flex-wrap: wrap;
    gap: .4rem;
    margin-top: 1rem;
    max-height: 200px;
    overflow-y: auto;
    /* overflow-y:auto also clips overflow-x, which cut the selection outline off the
       edge thumbs — 4px of padding gives the 2px ring room to show inside the clip. */
    padding: 4px;
}
.ed-imgpick__thumb-wrap {
    position: relative;     /* anchors the delete ✕ */
    flex: 0 0 auto;
    width: 56px;
    height: 56px;
}
.ed-imgpick__thumb {
    display: block;
    width: 100%;
    height: 100%;
    padding: 0;
    border: none;
    border-radius: var(--rad-1);
    overflow: hidden;
    outline: solid 2px transparent;
    cursor: pointer;
    transition: var(--trn);
}
.ed-imgpick__thumb:hover,
.ed-imgpick__thumb.is-active { outline-color: var(--blu-1); }
.ed-imgpick__thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Per-thumb delete — a ✕ in the top-right corner, revealed on hover. */
.ed-imgpick__del {
    position: absolute;
    top: 3px;
    right: 3px;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    padding: 0;
    border: none;
    border-radius: 50%;
    background-color: rgba(0, 0, 0, .6);
    color: #fff;
    cursor: pointer;
    opacity: 0;
    pointer-events: none;
    transition: var(--trn);
}
.ed-imgpick__thumb-wrap:hover .ed-imgpick__del,
.ed-imgpick__del:focus-visible { opacity: 1; pointer-events: auto; }
.ed-imgpick__del:hover { background-color: var(--red-1); }
.ed-imgpick__del svg { width: 10px; height: 10px; }
.ed-imgpick__empty {
    width: 100%;
    margin-top: 1rem;
    font-size: var(--siz-min);
    color: var(--wht-3);
}

/* Palette editor modal — a 2-col grid of swatches, each a native colour input
   styled as a rounded chip beside its name. (The modal frame reuses .ed-modal.) */
.ed-palette-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: .5rem;
}
.ed-swatch {
    display: flex;
    align-items: center;
    gap: .6rem;
    padding: .4rem .55rem;
    border-radius: var(--rad-1);
    background-color: var(--blk-1);
    cursor: pointer;
    transition: var(--trn);
}
.ed-swatch:hover { background-color: var(--blk-0); }
.ed-swatch input[type="color"] {
    width: 30px;
    height: 30px;
    flex-shrink: 0;
    padding: 0;
    border: none;
    background: none;
    border-radius: var(--rad-1);
    cursor: pointer;
}
.ed-swatch input[type="color"]::-webkit-color-swatch-wrapper { padding: 0; }
.ed-swatch input[type="color"]::-webkit-color-swatch { border: solid 1px var(--blk-0); border-radius: var(--rad-1); }
.ed-swatch input[type="color"]::-moz-color-swatch { border: solid 1px var(--blk-0); border-radius: var(--rad-1); }
.ed-swatch__name {
    font-size: var(--siz-min);
    font-weight: 550;
    color: var(--wht-1);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ── Editor heading scale ──────────────────────────────────────────────── */
/* The chrome uses EXACTLY two heading styles. Both are white and sentence
   case (no uppercase, no tracking); they differ only in size. Applied via
   these reusable classes and by grouping the chrome's existing heading
   selectors below, so there is a single source of truth for each. */

.ed-heading-lg,
.ed-modal__title,
.ed-canvas__empty h2 {
    font-family: var(--fnt-hdg);
    font-size: 1.5rem;
    font-weight: 550;
    line-height: var(--line-height-tight);
    letter-spacing: normal;
    text-transform: none;
    color: var(--wht-0);
}

.ed-heading-ctx,
.ed-palette__group-title,
.ed-insp-section__title,
.ed-modal__section-label,
.ed-tab {
    font-family: var(--fnt-hdg);
    font-size: var(--siz-min);
    font-weight: 550;
    line-height: var(--line-height-tight);
    letter-spacing: normal;
    text-transform: none;
    color: var(--wht-0);
}

/* ── Animations ────────────────────────────────────────────────────────── */

@keyframes ed-fade-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}

@keyframes ed-fade-down {
    from { opacity: 0; transform: translateY(-.5rem); }
    to   { opacity: 1; transform: translateY(0); }
}
