/* Shared components — buttons, form controls, the color grid, #modal, the
   modeless floating panel, the Preferences panel, setBusy(), the boot splash,
   uiPrompt/uiConfirm and the first-run guide coach-marks. */
/* ICONS — base rule every inline <svg class="icon"> in the app relies on for
   its size/stroke; component-scoped rules elsewhere override the size for
   their own context. Restored (Process 4 part 1) after it was lost in the
   legacy Director/Navigator/Hero/Writer CSS deletion (v.4.10.0) — without it
   every icon fell back to the browser's default replaced-element size
   instead of 1em, blowing up layout wherever an icon appears. */
.icon{
	width:1em;height:1em;
	stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;
	fill:none;display:inline-block;vertical-align:middle;
	transition:transform var(--ease), stroke var(--ease);
}
/* BUTTONS */
.btn{
	display:inline-flex;align-items:center;gap:6px;min-height:24px; /* Procress 17 U3 */
	padding:7px 15px;border:none;border-radius:var(--r);
	cursor:pointer;font-size:calc(var(--fs-body) * var(--fsc,1));font-weight:500;
	transition:all var(--ease);font-family:inherit;
}
.btn .icon{width:14px;height:14px;margin-right:2px}
/* A disabled .btn had no styling at all, so it looked exactly like a live one
   — both for the busy state syncBtnBusy sets and for a genuinely unavailable
   action (e.g. Launch on a plugin missing a dependency). Same treatment
   base.css already gives select:disabled. Pointer events stay ON (unlike
   .bnav:disabled in builder.css) so the button's title= tooltip still explains
   WHY it is unavailable. */
.btn:disabled{opacity:.45;cursor:not-allowed}
.btn-p{background:var(--button, var(--accent));color:var(--on-button)}
.btn-p:hover{background:var(--accentH)}
.btn-s{background:var(--raised);color:var(--t1);border:1px solid var(--border)}
.btn-s:hover{background:var(--hover)}
.btn-d{background:transparent;color:var(--danger);border:1px solid var(--danger)}
.btn-d:hover{background:var(--danger);color:var(--on-danger)}
.btn-g{background:transparent;color:var(--t2)}
.btn-g:hover{background:var(--hover);color:var(--t1)}
.btn-i{padding:4px;width:28px;height:28px;justify-content:center;border-radius:var(--rs);font-size:calc(14px * var(--fsc,1))}
.btn-i .icon{margin-right:0;width:15px;height:15px}
/* Icon-only buttons highlight just the icon on hover, not their background —
   wins by source order (equal specificity) over whichever .btn-p/.btn-s/.btn-g
   hover rule it's paired with, without touching those shared rules (labeled
   buttons still use their background-fill hover). .btn-d keeps its red
   warning fill — a destructive-action cue, not decorative hover chrome. */
.btn-i:not(.btn-d):hover{background:transparent}
.btn-i.btn-i-sm{width:24px;height:24px;padding:4px} /* 24px = WCAG 2.5.8 target minimum; the icon stays 11px */
.btn-i.btn-i-sm .icon{width:11px;height:11px}

/* FORMS */
.fg{margin-bottom:14px}
.fg label{display:block;font-size:calc(var(--fs-meta) * var(--fsc,1));color:var(--t3-aa,var(--t2));margin-bottom:5px;font-weight:600;text-transform:uppercase;letter-spacing:.05em}
.fg input,.fg textarea,.fg select{
	width:100%;background:var(--bg);border:1px solid var(--border);
	border-radius:var(--r);color:var(--t1);padding:8px 11px;
	font-size:calc(var(--fs-body) * var(--fsc,1));font-family:inherit;outline:none;
	transition:border-color var(--ease);
}
.fg input:focus,.fg textarea:focus,.fg select:focus{border-color:var(--accent)}
.fg textarea{resize:vertical;min-height:72px}
/* The component contract (APP docs/redesign/COMPONENTS.md): help under a
   field, and the same line turned error. aria-invalid marks the field
   itself, so a screen reader hears what the colour shows. */
.fg .help{display:block;margin-top:5px;font-size:calc(var(--fs-meta) * var(--fsc,1));color:var(--t3-aa,var(--t2))}
.fg .help.err{color:var(--danger)}
.fg [aria-invalid="true"]{border-color:var(--danger)}

/* Keyboard focus. base.css drops the browser outline on inputs and buttons
   (a mouse click drew one), which left keyboard users with nothing but a
   border tint. :focus-visible is only true for keyboard focus, so pointer
   use looks exactly as before. */
.btn:focus-visible,.li:focus-visible,select:focus-visible,
.fg input:focus-visible,.fg textarea:focus-visible,.fg select:focus-visible{outline:2px solid var(--accentH);outline-offset:2px}
.fg select option{background:var(--raised)}
.fg input[type="checkbox"]{width:auto;padding:0}

/* COLOR GRID */
.cgrid{display:flex;flex-wrap:wrap;gap:7px;margin-top:4px}
#cpicker-grid{max-height:112px;overflow-y:auto;padding-right:2px}
.cswatch{
	width:26px;height:26px;border-radius:50%;cursor:pointer;
	border:3px solid transparent;transition:all var(--ease);
}
.cswatch:hover{transform:scale(1.15)}
.cswatch.sel{border-color:var(--on-media);box-shadow:0 0 0 1px rgba(255,255,255,.3)}

.symswatch{
	width:30px;height:30px;padding:0;border-radius:var(--rs);cursor:pointer;
	display:inline-flex;align-items:center;justify-content:center;font-size:calc(15px * var(--fsc,1));line-height:1;
	border:1px solid var(--border);background:var(--raised);color:var(--t1);
	transition:transform var(--ease),background var(--ease),border-color var(--ease),box-shadow var(--ease);
}
.symswatch:hover{transform:translateY(-1px);background:var(--hover);border-color:var(--t3)}
.symswatch.sel{background:var(--accent);color:var(--on-accent);border-color:var(--accent);box-shadow:0 0 0 1px rgba(99,102,241,.25)}

/* Char-elements picker (modal-in-modal) — clickable "insert boxes" that
   toggle selected state, replacing a native checkbox list so multi-select
   reads visually instead of relying on tiny checkbox hit-targets. */
.elem-pick-grid{display:flex;flex-direction:column;gap:4px;margin-bottom:8px}
.elem-pick{
	display:flex;align-items:center;gap:8px;padding:7px 10px;cursor:pointer;
	background:var(--bg);border:1px solid var(--border);border-radius:var(--rs);
	color:var(--t2);transition:background var(--ease),border-color var(--ease),color var(--ease);
}
.elem-pick:hover{border-color:var(--t3)}
.elem-pick.sel{background:color-mix(in srgb, var(--accent) 15%, var(--bg));border-color:var(--accent);color:var(--t1)}

/* MODAL */
#modal-overlay{
	position:fixed;inset:0;background:rgba(0,0,0,.65);
	display:flex;align-items:center;justify-content:center;
	z-index:var(--z-dropdown);backdrop-filter:blur(4px);
}
#modal-overlay.hidden{display:none}
#modal{
	background:var(--surface);border:1px solid var(--border);
	border-radius:var(--rl);width:var(--modal-md);max-width:95vw;
	max-height:88vh;display:flex;flex-direction:column;
	box-shadow:var(--shadow-modal);
}
#modal-head{
	display:flex;align-items:center;padding:15px 18px;
	border-bottom:1px solid var(--border);
}
#modal-title{flex:1;font-size:calc(14px * var(--fsc,1));font-weight:700}
#modal-close{color:var(--t3-aa,var(--t2))}
#modal-close:hover{color:var(--t1)}
#modal-body{padding:18px;overflow-y:auto;flex:1}
/* three sizes, from the tokens (Procress 22) */
#modal[data-size="sm"]{width:var(--modal-sm)}
#modal[data-size="md"]{width:var(--modal-md)}
#modal[data-size="lg"]{width:min(var(--modal-lg),95vw);height:min(760px,88vh)}
/* the foot: buttons, primary rightmost; a destructive one on the far left */
#modal-foot{padding:12px 18px;border-top:1px solid var(--border)}
#modal-foot[hidden]{display:none}
#modal-foot > .mfoot{margin:0;padding:0;border:0;align-items:center}
.mfoot{display:flex;gap:8px;justify-content:flex-end;margin-top:18px;padding-top:14px;border-top:1px solid var(--border)}
.mfoot > .btn-d:first-child:not(:last-child){margin-right:auto}

/* FLOATING (MODELESS) PANEL — like #modal but no backdrop, so the app below
   stays interactive (Plan part3 setting#2). */
.floating-panel{
	--ls-floor:var(--surface);
	position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);
	max-width:95vw;max-height:90vh;
	background:var(--surface);border:1px solid var(--border);border-radius:var(--rl);
	box-shadow:0 24px 60px rgba(0,0,0,.5);z-index:calc(var(--z-dropdown) + 50);display:flex;flex-direction:column;overflow:hidden;
}
.fp-head{
	display:flex;align-items:center;justify-content:space-between;padding:15px 18px;
	border-bottom:1px solid var(--border);font-size:calc(14px * var(--fsc,1));font-weight:700;flex-shrink:0;
}
.fp-close{
	background:none;border:none;color:var(--t3-aa,var(--t2));cursor:pointer;
	font-size:calc(15px * var(--fsc,1));padding:3px 6px;border-radius:var(--rs);line-height:1;
}
.fp-close:hover{color:var(--t1)}
.fp-close .icon{width:15px;height:15px;display:block}
.fp-body{padding:18px;overflow-y:auto;flex:1;min-height:0}

/* SETTING WINDOW (Plan part1 #Setting) — two-level sidebar-nav layout hosted
   inside .floating-panel, replacing the old flat PREFERENCES PANEL below
   (whose .prefs-* content classes it still reuses for the Theme/Text&Size
   pages moved in from there). */
.setting-shell{display:flex;height:100%;gap:16px}
.setting-sidebar{width:190px;flex-shrink:0;display:flex;flex-direction:column;gap:2px;overflow-y:auto}
.setting-content{flex:1;min-width:0;overflow-y:auto}
/* v5 Part 6 §10.3: the rule between the two halves of a merged Setting page. */
.setting-merge-sep{border-top:1px solid var(--border);margin:22px 0 16px}

/* Slider+number row (Plan part2 #1) — 5:1 width ratio, both inputs kept in
   sync live via inline oninput on the JS side; this only lays them out. */
.size-slider-row{display:grid;grid-template-columns:5fr 1fr;gap:8px;align-items:center}

/* Module-name read-only compare list (Plan part2 #3) — reuses welcome.css's
   .welcome-name-* box/row classes for the two-column layout; scoped here to
   relax them (nothing here is clickable, unlike the wizard's picker) and to
   define its own row-height var since --wz-name-row lives under
   .welcome-wizard only. Height clamps between 4 and 5 visible rows, scaling
   with viewport height in between since the Setting window itself is a
   fixed-size floating panel. */
.setting-name-cols{--wz-name-row:26px;margin-top:8px}
.setting-name-cols .welcome-name-box{cursor:default}
.setting-name-cols .welcome-name-box:hover{border-color:var(--border)}
.setting-name-cols .welcome-name-list{max-height:clamp(calc(var(--wz-name-row) * 4), 26vh, calc(var(--wz-name-row) * 5))}

/* PREFERENCES PANEL — sidebar-nav layout hosted inside .floating-panel */
.prefs-shell{display:flex;height:100%;gap:16px}
.prefs-sidebar{width:160px;flex-shrink:0;display:flex;flex-direction:column;gap:2px}
.prefs-content{flex:1;min-width:0;overflow-y:auto}
/* a .togglerow that is a real switch (role=switch, Tab + Enter/Space) */
.togglerow.setting-switch{min-height:var(--ctl-sm);color:var(--t1);cursor:pointer}
.togglerow.setting-switch:focus-visible{outline:var(--focus-ring) solid var(--accentH,var(--accent));outline-offset:2px}
.prefs-theme-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:12px;margin-top:4px}
.prefs-theme-cell{
	position:relative;border:1px solid var(--border);border-radius:var(--r);padding:8px;cursor:pointer;
	background:var(--bg);transition:border-color var(--ease);
}
.prefs-theme-cell:hover{border-color:var(--accentH)}
.prefs-theme-cell.active{border-color:var(--accent)}
/* Procress 10 part 2 — a catalog package not yet downloaded: greyed out like
   a disabled button (.btn:disabled above), no hover/select affordance since
   the cell itself carries no onclick; the Download button inside it stays
   at full opacity so it still reads as the one actionable thing in the row. */
.prefs-theme-cell.locked{opacity:.55;cursor:default}
/* With a catalog preview the colours ARE the point — keep them at full
   strength and mark "not downloaded" with a dashed border + corner button. */
.prefs-theme-cell.locked.has-preview{opacity:1;border-style:dashed;position:relative}
.prefs-theme-cell.locked.has-preview .prefs-theme-name{color:var(--t2)}
.prefs-theme-cell.locked.has-preview .prefs-theme-dl{position:absolute;top:10px;right:10px}
.prefs-theme-cell.locked:hover{border-color:var(--border)}
.prefs-theme-cell.locked .btn{opacity:1}
.prefs-theme-cell-lockglyph{align-items:center;justify-content:center;color:var(--t3-aa,var(--t2))}
.prefs-theme-name{margin-top:6px;font-size:calc(var(--fs-meta) * var(--fsc,1));font-weight:600;color:var(--t1);
	overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.prefs-theme-tools{display:none;position:absolute;top:6px;right:6px;gap:4px;background:var(--surface);
	border-radius:var(--rs);padding:2px 4px}
.prefs-theme-cell:hover .prefs-theme-tools{display:flex}
.prefs-theme-tools span{cursor:pointer;color:var(--t3-aa,var(--t2));padding:0 2px;font-size:calc(var(--fs-meta) * var(--fsc,1))}
.prefs-theme-tools span:hover{color:var(--accentH)}
.prefs-theme-check{position:absolute;top:6px;left:6px;color:var(--accent-text,var(--accent));font-weight:700;
	background:var(--surface);border-radius:50%;width:16px;height:16px;display:flex;align-items:center;justify-content:center;
	font-size:calc(var(--fs-meta) * var(--fsc,1))}
.prefs-theme-add{
	display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--sp-1);min-height:112px;
	border:1px dashed var(--border);color:var(--t3-aa,var(--t2));font-size:calc(var(--fs-meta) * var(--fsc,1));
}
.prefs-theme-add .icon{width:22px;height:22px}
.prefs-theme-add-group{font-size:var(--fs-xs);font-weight:700;letter-spacing:.05em;text-transform:uppercase}
.prefs-theme-add-label{color:var(--t1);font-weight:600}
.prefs-theme-add:hover{border-color:var(--accentH)}
.prefs-theme-add:focus-visible{outline:var(--focus-ring) solid var(--accentH,var(--accent));outline-offset:2px}
.setting-wide-btns .btn{width:100%;margin-bottom:6px}
.prefs-lang-shell{display:flex;gap:16px;margin-top:4px}
.lang-list{width:240px;flex-shrink:0;max-height:320px;overflow-y:auto}
.prefs-lang-preview{
	flex:1;background:var(--bg);border:1px solid var(--border);border-radius:var(--r);
	padding:14px;display:flex;flex-direction:column;gap:8px;font-size:calc(var(--fs-body) * var(--fsc,1));color:var(--t1);
}
.prefs-advanced{margin-top:10px;padding-top:10px;border-top:1px solid var(--border)}

#confirm-overlay{position:fixed;inset:0;background:rgba(0,0,0,.55);display:flex;align-items:center;justify-content:center;z-index:var(--z-modal);backdrop-filter:blur(4px)}
#confirm-box{background:var(--surface);border:1px solid var(--border);border-radius:var(--rl);width:360px;max-width:92vw;padding:20px;box-shadow:var(--shadow-modal)}
.confirm-msg{font-size:calc(var(--fs-body) * var(--fsc,1));color:var(--t1);line-height:1.5;white-space:pre-wrap}
.confirm-actions{display:flex;gap:8px;justify-content:flex-end;margin-top:18px}
/* setBusy() — the app's only loading affordance (see core.js). Theme tokens
   only; sits above panel content but below every dialog layer. */
.busy-veil{
	position:absolute;inset:0;z-index:calc(var(--z-dropdown) - 10);
	display:flex;align-items:center;justify-content:center;gap:10px;
	background:color-mix(in srgb, var(--bg) 72%, transparent);
	backdrop-filter:blur(1px);font-size:calc(var(--fs-body) * var(--fsc,1));color:var(--t2);
}
.busy-spin{
	width:16px;height:16px;flex-shrink:0;border-radius:50%;
	border:2px solid var(--border);border-top-color:var(--accent);
	animation:busy-spin .7s linear infinite;
}
.busy-text{color:var(--t2)}
@keyframes busy-spin{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){.busy-spin{animation-duration:2.4s}}

/* Procress 27 part 5 — core/reorder.js: the picked-up item follows the
   pointer on one axis; the others slide out of its way. */
.reorder-slide{transition:transform .15s ease}
.reorder-drag{position:relative;z-index:var(--z-sticky);background:var(--surface);box-shadow:var(--shadow-pop);opacity:.96}
tr.reorder-drag td{background:var(--surface)}
html.reorder-active,html.reorder-active *{cursor:grabbing!important;user-select:none!important}
@media (prefers-reduced-motion:reduce){.reorder-slide{transition:none}}

/* Process 7 part 1 — shared toggle-open/close animation, driven by
   core/ui.js's animateToggleOpen()/animateToggleCloseThenCommit() on any
   element a toggle shows/hides (Hub accordion .acc-body, Nest tree
   .nest-children). --anim-dur is
   written once by applyUiSettings() from the Workspace "animation speed"
   setting (core/settings.js), so every consumer here picks up a live
   change without touching this file. A CSS `animation` (not `transition`)
   is required specifically because every one of these elements is
   destroyed and recreated by a full innerHTML re-render on each toggle —
   there is no "before" state for a transition to interpolate from, but an
   `animation` plays from its own `from` keyframe regardless of when the
   class landed on the node. */
.anim-toggle-in{animation:animToggleIn var(--anim-dur,.15s) ease}
.anim-toggle-out{animation:animToggleOut var(--anim-dur,.15s) ease}
@keyframes animToggleIn{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}
@keyframes animToggleOut{from{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(-4px)}}

/* Boot splash — the full-window loader shown from first paint until init()
   finishes (markup + controller live inline at the top of index.html so they
   exist before any app JS parses). z-index clears every dialog layer, the
   highest of which is #guide-overlay at 1200; it is removed from the DOM once
   faded, so nothing here ever competes with the app for a click. */
#splash{
	position:fixed;inset:0;z-index:calc(var(--z-tooltip) + 100);
	display:flex;flex-direction:column;align-items:center;justify-content:center;
	gap:var(--sp-7);background:var(--bg);
	transition:opacity .26s ease;
}
#splash.splash-hide{opacity:0;pointer-events:none}
/* .brand-img carries the content:url() logo (nav-hub.css), so the
   splash only needs to override its 30px size. */
#splash .splash-logo{height:88px;width:88px}
#splash-track{
	width:220px;height:4px;border-radius:var(--rs);
	background:var(--raised);overflow:hidden;
}
#splash-fill{
	height:100%;width:0;border-radius:var(--rs);
	background:var(--button, var(--accent));
	transition:width .3s ease;
}
#splash-pct{font-size:var(--fs-xs);color:var(--t3-aa,var(--t2));font-variant-numeric:tabular-nums}
@media (prefers-reduced-motion:reduce){#splash,#splash-fill{transition:none}}

/* uiPrompt() — the text-entry sibling of uiConfirm. Reuses the whole confirm
   chrome; only needs a wider box and top spacing for its .fg field. */
#confirm-box.wide{width:460px}
#confirm-box .fg{margin:12px 0 0}
#confirm-box .fg textarea{min-height:110px;font-family:var(--mono,ui-monospace,monospace);font-size:calc(12px * var(--fsc,1))}

/* First-run coach-marks guide (src/renderer/guide.js) — theme-token colors only */
#guide-overlay{position:fixed;inset:0;z-index:var(--z-tooltip);pointer-events:none}
.guide-catch{position:absolute;inset:0;pointer-events:auto}
.guide-spotlight{position:fixed;border-radius:var(--r);pointer-events:none;
	box-shadow:0 0 0 9999px rgba(0,0,0,.6),0 0 0 2px var(--accent);
	transition:left .18s ease,top .18s ease,width .18s ease,height .18s ease}
.guide-pop{position:fixed;width:280px;max-width:92vw;pointer-events:auto;
	background:var(--surface);border:1px solid var(--border);border-radius:var(--rl);
	padding:14px 16px;box-shadow:var(--shadow-modal);
	transition:left .18s ease,top .18s ease}
.guide-pop-title{font-size:calc(14px * var(--fsc,1));font-weight:700;color:var(--t1);margin-bottom:6px}
.guide-pop-text{font-size:calc(var(--fs-body) * var(--fsc,1));color:var(--t2);line-height:1.5}
.guide-pop-foot{display:flex;gap:6px;align-items:center;margin-top:14px}
.guide-step{font-size:calc(var(--fs-meta) * var(--fsc,1));color:var(--t3-aa,var(--t2))}

/* Modal: separate description (hint callout) from data (labeled sections) */
.modal-hint{
	display:flex;gap:8px;align-items:flex-start;
	background:var(--raised);border:1px solid var(--border);
	border-left:3px solid var(--accent);border-radius:var(--rs);
	padding:8px 11px;margin:0 0 14px;
	color:var(--t2);font-size:calc(var(--fs-body) * var(--fsc,1));line-height:1.45;
}
.modal-hint[hidden]{display:none}
.modal-hint .icon{width:14px;height:14px;flex-shrink:0;margin-top:1px;color:var(--accent-text,var(--accent))}
/* Data rows inside a modal aren't row-clickable — only their action button is */
.modal-data .li{cursor:default;background:var(--bg);border:1px solid var(--border);margin-bottom:4px}
.modal-data .li:hover{background:var(--bg);color:var(--t2)}


/* toast() (core/ui.js). V5.md §7.5 bug #1: #toast had no rule in any
   stylesheet — it rendered as an unstyled block in the body flow, so every
   "tell the user why" message in the app was effectively invisible. Bottom
   right, above modals (100/150) and the confirm dialog (1000) so the result
   of a confirmed action shows, below the 2000 full-window layer. */
#toast{position:fixed;right:18px;bottom:18px;z-index:var(--z-toast);max-width:min(420px,calc(100vw - 36px));
	padding:10px 16px;border-radius:var(--r);border:1px solid var(--border);border-left:4px solid var(--accent);
	background:var(--raised);color:var(--t1);font-size:calc(var(--fs-body) * var(--fsc,1));box-shadow:var(--shadow-float);
	transform:translateY(24px);opacity:0;pointer-events:none;transition:transform .2s ease,opacity .2s ease}
#toast:empty{display:none}
#toast.show{transform:translateY(0);opacity:1}
#toast.ok{border-left-color:var(--success)}
#toast.err{border-left-color:var(--danger)}
/* toastAction (§11.4): the only toast that takes a click. */
#toast.has-action{pointer-events:auto;display:flex;align-items:center;gap:12px}
#toast .toast-act{flex-shrink:0}
#toast.warn{border-left-color:var(--warn)}
/* v5 Part 7 §11.4: the Trash panel (hub/trash.js). */
#modal .trash-list .ls-list{max-height:min(420px,60vh);overflow-y:auto}

/* ── Genre bundles + guide picker (v5 Part 7, V5.md §11.7–§11.8) ── */
.bundle-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:12px}
.bundle-head{display:flex;align-items:center;gap:8px}
.bundle-head .kicon .icon{width:18px;height:18px}
.bundle-mods{display:flex;flex-wrap:wrap;gap:4px}
.bundle-mod{display:inline-flex;align-items:center;gap:3px;padding:1px 7px;border-radius:999px;background:var(--raised);font-size:calc(var(--fs-meta) * var(--fsc,1));color:var(--t2)}
.bundle-mod .icon{width:11px;height:11px}
.bundle-acts{display:flex;gap:6px;justify-content:flex-end;margin-top:auto}
.bundle-adj-row{display:grid;grid-template-columns:auto 1fr;gap:6px;align-items:center;margin-bottom:6px}
.bundle-adj-mod{display:inline-flex;align-items:center;gap:4px}
.bundle-adj-fields{grid-column:2;font-size:calc(12px * var(--fsc,1))}
.bundle-adj-fields input{display:block;width:100%;margin-top:4px}
/* Artisan gallery — cards beside what the selected bundle builds
   (Procress 14, mockup 08-artisan.html). Opened in the xl modal. */
.art{display:grid;grid-template-columns:minmax(0,1fr) minmax(300px,380px);gap:16px;height:100%;min-height:0}
.art-left{min-width:0;display:flex;flex-direction:column;min-height:0}
.art-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));gap:10px;overflow:auto;padding:2px}
.art-card{display:flex;flex-direction:column;text-align:left;padding:0;border:1px solid var(--border);border-radius:var(--r);background:var(--surface);overflow:hidden;cursor:pointer;color:var(--t1);font:inherit}
.art-card:hover{border-color:var(--t3)}
.art-card.on{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent)}
.art-card.art-note{cursor:default;border-style:dashed;background:transparent}
.art-cover{display:flex;align-items:center;height:56px;padding:0 12px;color:var(--on-media);background-size:cover}
.art-cover .icon{width:22px;height:22px}
.art-cbody{display:flex;flex-direction:column;gap:3px;padding:9px 12px 11px;min-width:0}
.art-cbody b{font-size:calc(var(--fs-body) * var(--fsc,1))}
.art-cbody>span{font-size:calc(var(--fs-meta) * var(--fsc,1));color:var(--t3-aa,var(--t2));line-height:1.35}
.art-chips{display:flex;gap:4px;margin-top:4px}
.art-chips i{width:10px;height:10px;border-radius:var(--rs)}
.art-detail{min-height:0;overflow:auto;border:1px solid var(--border);border-radius:var(--r);background:var(--surface)}
.art-dh{padding:14px 16px;color:var(--on-media);background-size:cover}
.art-dh h3{display:flex;align-items:center;gap:8px;font-size:calc(16px * var(--fsc,1))}
.art-dh h3 .icon{width:20px;height:20px}
.art-dh p{font-size:calc(12px * var(--fsc,1));margin-top:4px;opacity:.95}
.art-dh .art-counts{font-weight:600}
.art-db{padding:12px 16px 14px}
.art-db h4{font-size:calc(var(--fs-meta) * var(--fsc,1));text-transform:uppercase;letter-spacing:.05em;color:var(--t3-aa,var(--t2));margin:12px 0 6px}
.art-db h4:first-child{margin-top:0}
.art-tree{font-size:calc(var(--fs-body) * var(--fsc,1))}
.art-row{display:flex;align-items:center;gap:6px;padding:3px 0 3px calc(var(--d,0) * 16px)}
.art-row .icon{width:14px;height:14px;color:var(--t3-aa,var(--t2))}
.art-row .k{width:9px;height:9px;border-radius:var(--rs);flex:none}
.art-kind{margin-left:auto;font-size:calc(var(--fs-meta) * var(--fsc,1));color:var(--t3-aa,var(--t2))}
.art-smp{font-size:calc(var(--fs-meta) * var(--fsc,1));padding:0 6px;border-radius:999px;background:color-mix(in srgb,var(--success) 18%,transparent);color:var(--t1)}
.art-links{width:100%;height:auto;background:var(--bg);border:1px solid var(--border);border-radius:var(--rs)}
.art-links line{stroke:var(--t3);stroke-width:1.5}
.art-links line.b{stroke:var(--accent);stroke-dasharray:4 3}
.art-node rect{fill:var(--raised);stroke:var(--border)}
.art-node rect.k{stroke:none}
.art-node text{fill:var(--t1);font-size:10.5px;text-anchor:middle}
.art-legend{display:flex;gap:14px;font-size:calc(var(--fs-meta) * var(--fsc,1));color:var(--t3-aa,var(--t2));margin-top:6px}
.art-legend i{display:inline-block;width:18px;height:0;border-top:2px solid var(--t3);vertical-align:middle;margin-right:5px}
.art-legend i.b{border-top:2px dashed var(--accent)}
.art-check{display:flex;gap:8px;align-items:center;font-size:calc(var(--fs-body) * var(--fsc,1));margin-bottom:6px}
.art-db .bundle-acts{margin-top:14px}
@media (max-width:820px){.art{grid-template-columns:1fr;height:auto}.art-detail{overflow:visible}}

/* Setting window search (Procress 13 part 4, G5 — core/setting-search.js) */
.setting-search{margin:0 0 10px}
.setting-hit-group{margin-bottom:14px}
.setting-hit-row{display:flex;width:100%;justify-content:flex-start;text-align:left;padding:7px 10px;color:var(--t1)}
.setting-hit-row:hover{background:var(--hover)}
.setting-hit{outline:2px solid var(--accent);outline-offset:3px;border-radius:var(--rs);transition:outline-color .6s}
/* Procress 17 P1: core/ui.js lazyRows sentinel — invisible, spans a whole grid row.
   Procress 19 F10: also the spacers of a recycled list, so never the scroll
   anchor (the rows are) and, as a table row, no cell padding of its own. */
.lazy-more{height:1px;grid-column:1/-1;overflow-anchor:none}
.lazy-more>td{padding:0;border:0}
/* Procress 17 P2: "N more ›" after a module's first 50 elements in the Nest */
.nest-item-more .name{color:var(--t3-aa,var(--t2));font-style:italic}
/* Procress 16 B6: the Nest's "Unsorted (N)" virtual folder (was the Import Dock) */
.nest-unsorted .cnt{margin-left:auto;color:var(--t3-aa,var(--t2));font-size:calc(var(--fs-meta) * var(--fsc,1))}
/* Procress 21: its files, as a shared list (core/list.js), one step in */
.nest-unsorted-list{padding-left:var(--sp-5)}
.wyvern-unsorted{margin-top:16px}
/* Procress 17 P4: a borrowed view not drawn yet keeps roughly its space */
.pb-defer{min-height:120px}
/* Procress 18 part 1 — Home phase A (builder.js builderEmptyPaneHtml) */
.home-start{max-width:640px;margin:56px auto 24px;padding:0 16px;display:flex;flex-direction:column;gap:20px}
.home-start h2{font-size:calc(22px * var(--fsc,1));font-weight:650;margin:0}
.home-actions{display:flex;gap:8px;flex-wrap:wrap}
.home-sec h3{font-size:calc(var(--fs-body) * var(--fsc,1));font-weight:600;color:var(--t2);margin:0 0 6px;text-transform:none}
.home-organise{align-self:flex-start}
/* Procress 18 part 1: identity row = icon · name · kind · save state · primary · ⋯ */
.page-title .navbar-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.page-title .navbar-row .navbar-h{min-width:0}
.page-title .ph-save{margin-left:auto;color:var(--t3-aa,var(--t2));font-size:calc(12px * var(--fsc,1))}
.page-title .navbar-acts{display:flex;align-items:center;gap:6px}
/* Procress 18 part 1: an empty module's next step — the button and the line that explains it, side by side */
.kind-empty .kind-empty-act{display:flex;align-items:center;justify-content:center;gap:12px;flex-wrap:wrap;max-width:560px;margin:8px auto 0}
.kind-empty .kind-empty-act p{margin:0;text-align:left;max-width:360px}
/* Procress 16 part 2: the folder page — the right half of the Nest's two-column mode */
.folder-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(var(--tile,112px),1fr));gap:10px;margin-top:12px}
.folder-tile{display:flex;flex-direction:column;align-items:center;gap:6px;padding:10px 6px;border-radius:var(--r);cursor:pointer;text-align:center;min-width:0}
.folder-tile:hover{background:var(--hover)}
.folder-tile-icon{width:calc(var(--tile,112px) * .45);height:calc(var(--tile,112px) * .45);display:flex;align-items:center;justify-content:center;font-size:calc(var(--tile,112px) * .3)}
.folder-tile-icon .icon,.folder-tile-icon img{width:100%;height:100%;object-fit:cover;border-radius:var(--r)}
.folder-tile-name{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:calc(var(--fs-body) * var(--fsc,1))}
.folder-tile-kind{font-size:calc(var(--fs-meta) * var(--fsc,1));color:var(--t3-aa,var(--t2))}
.folder-tile:focus-visible,.folder-details tr:focus-visible{outline:var(--focus-ring) solid var(--accentH,var(--accent));outline-offset:-2px}
/* Procress 29 part 2: File Explorer views — small icons (a row of icon + name),
   a list, details (a sortable table). Large = the tile grid above. */
.folder-page{min-width:0}
.folder-small{grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:2px}
.folder-small .folder-tile{flex-direction:row;padding:5px 8px;gap:8px;text-align:left}
.folder-small .folder-tile-icon{width:20px;height:20px;font-size:16px;flex-shrink:0}
.folder-list,.folder-details-wrap{margin-top:12px}
.folder-list-icon{width:16px;height:16px;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0}
.folder-list-icon .icon,.folder-list-icon img{width:16px;height:16px;object-fit:cover;border-radius:var(--rs)}
.folder-details-wrap{overflow-x:auto}
.folder-details{width:100%;border-collapse:collapse;font-size:calc(var(--fs-body) * var(--fsc,1))}
.folder-details th{text-align:left;font-weight:600;color:var(--t3-aa,var(--t2));border-bottom:1px solid var(--border);padding:2px 6px}
.folder-details th .btn{color:inherit;font:inherit;padding:0 4px}
.folder-details td{padding:6px;border-bottom:1px solid var(--border);color:var(--t2);white-space:nowrap}
.folder-details td.folder-d-name{color:var(--t1);white-space:normal;width:50%}
.folder-d-cell{display:flex;align-items:center;gap:8px}
.folder-details tbody tr{cursor:pointer}
.folder-details tbody tr:hover{background:var(--hover)}
.folder-size{display:flex;align-items:center;gap:6px}
.folder-size input{width:96px}
/* Procress 18 part 2: the Properties panel (page/props-panel.js) in #side-panel */
.sp-props{padding:8px 12px;display:flex;flex-direction:column;gap:14px;overflow:auto}
.props-sec h4{font-size:calc(12px * var(--fsc,1));color:var(--t2);margin:0 0 6px;font-weight:600}
.props-row{display:grid;grid-template-columns:92px 1fr;gap:8px;align-items:center;padding:3px 0;font-size:calc(var(--fs-body) * var(--fsc,1))}
.props-k{color:var(--t3-aa,var(--t2));font-size:calc(12px * var(--fsc,1))}
.props-v{min-width:0;overflow:hidden;text-overflow:ellipsis;display:flex;align-items:center;gap:6px}
.props-unresolved .ls-title{color:var(--danger)}
.props-acts{flex-direction:row;display:flex;gap:6px;flex-wrap:wrap}

/* Procress 18 part 5: no state is told by colour alone. A toast says what
   kind it is with a mark; the selected row and the active tab carry a bar;
   the chosen segment is bold as well as filled. */
#toast.ok::before,#toast.err::before,#toast.warn::before,#toast.info::before{display:inline-block;width:1.2em;margin-right:6px;font-weight:700;text-align:center}
#toast.ok::before{content:'✓';color:var(--success)}
#toast.err::before{content:'✕';color:var(--danger)}
#toast.warn::before{content:'!';color:var(--warn)}
#toast.info::before{content:'i';color:var(--info)}
#toast.info{border-left-color:var(--info)}
.li.sel,.li.active{box-shadow:inset 3px 0 0 var(--accent)}
.project-tab.active{box-shadow:inset 0 2px 0 var(--accent)}
/* Procress 16 part 5: Home phase B */
.home-portal{display:contents}
.home-featured{cursor:pointer;border:1px solid var(--border);border-radius:var(--r);padding:var(--sp-3);max-width:520px}
.home-featured:hover{border-color:var(--accent)}
.home-stats{color:var(--t2);margin:0 0 var(--sp-2)}
.left-changed{margin-top:var(--sp-4)}
.hx-row2{display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-3)}
#hx-css{width:100%;font-family:ui-monospace,Consolas,monospace}
/* Procress 16 part 7: the new Nexus's template gallery */
.home-tpls{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:var(--sp-3);margin-bottom:var(--sp-2)}
.btn.home-tpl{flex-direction:column;align-items:flex-start;gap:var(--sp-1);padding:var(--sp-3);border:1px solid var(--border);background:var(--surface);color:var(--t1);text-align:left;font-weight:400;white-space:normal}
.btn.home-tpl:hover{border-color:var(--accent)}
.home-tpl-pic{display:flex;flex-wrap:wrap;gap:4px;padding:var(--sp-2);border-radius:var(--rs);background:var(--raised);width:100%;min-height:40px}
.home-tpl-pic i{display:inline-flex}.home-tpl-pic .icon{width:18px;height:18px}
.btn.home-tpl .kli-desc{color:var(--t2);font-size:calc(var(--fs-meta) * var(--fsc,1))}

/* Procress 22: an icon inline with text (a lock after a name) */
.inline-ico{display:inline-flex;vertical-align:-2px}
.inline-ico .icon{width:var(--icon-sm);height:var(--icon-sm)}
