/* Builder Page - Assets
 * Asset panel, asset list, categories, expandables, components, and property fields
 */

/* Asset Panel */
.panel-assets {
    min-width: 0;
    width: var(--width-panel-default);
    background: var(--color-background);
    border-right: var(--border-width) var(--border-style) var(--color-border);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    position: relative;
}

/* Collapsed state - panel completely hidden */
.panel-assets.collapsed {
    display: none;
}

/* Responsive adjustments for assets panel are in builder.css using aspect-ratio queries */

.panel-assets-footer {
    padding: var(--space-2);
    padding-left: calc(var(--space-2) + var(--safe-area-left));
    border-top: var(--border-width) var(--border-style) var(--color-border);
    background: var(--color-surface);
    display: flex;
    gap: var(--space-2);
    align-items: center;
    flex-shrink: 0;
    height: var(--height-header);
}

/* Search container with icon */
/* .search-container and .search-icon base live in common/style.css */
.search-icon svg {
    width: 16px;
    height: 16px;
    color: var(--color-text-dark);
}

/* .form-inst-search is defined once in common/style.css (composed with .form-input). */

.panel-assets-content {
    flex: 1;
    overflow-y: auto;
    padding: var(--space-2);
    padding-left: calc(var(--space-2) + var(--safe-area-left));
}

/* Filter Button - icon turns accent when filters are inactive */
#filter-button.has-inactive svg {
    color: var(--color-accent);
}

/* Filter Menu */
.menu-inst-filter {
    position: absolute;
    bottom: 100%;
    right: 0;
    margin-bottom: calc(var(--space-1) + 2.5px); /* raised 2.5px above the button */
    min-width: 160px;
    /* Pops upward (and slides up into place: it carries .menu-up), so square
       the bottom corners (the edge facing the button). */
    border-radius: var(--radius-sm) var(--radius-sm) 0 0;
}

.menu-inst-filter .menu-part-item {
    justify-content: space-between;
}

.menu-inst-filter .menu-part-item .filter-icon {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

/* Inactive filter icon and text is muted */
.menu-inst-filter .menu-part-item .filter-icon {
    color: var(--color-text-dark);
}

.menu-inst-filter .menu-part-item .filter-icon svg {
    width: 14px;
    height: 14px;
    color: var(--color-text-dark);
}

.menu-inst-filter .menu-part-item.active .filter-icon,
.menu-inst-filter .menu-part-item.active .filter-icon svg {
    color: var(--color-text);
}

.menu-inst-filter .menu-part-item .filter-eye {
    display: flex;
    align-items: center;
}

.menu-inst-filter .menu-part-item .filter-eye svg {
    width: 14px;
    height: 14px;
}

/* Asset List */
.asset-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

/* Icon styling for asset types and component types */
.asset-type-icon,
.component-type-icon,
.section-part-type-icon {
    font-size: var(--font-size-sm); /* Slightly larger than default 10px */
    height: 16px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    color: var(--color-text-dark);
}

/* .asset-header inherits all layout from .expandable-part-header - DO NOT override height.
   Watermark thumbnail (when applicable) is added via BuilderUtilsWatermark.attach. */

.asset-name {
    flex: 1;
    font-size: var(--font-size-sm);
    color: var(--color-text);
    outline: none;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.asset-name[contenteditable="true"] {
    background: var(--color-background);
    padding: var(--space-1);
    border: var(--border-width) var(--border-style) var(--color-accent);
    border-radius: var(--radius-sm);
}

/* Actions container - shared by assets and components */
.asset-actions,
.component-actions {
    display: flex;
    gap: var(--space-1);
    opacity: 1;
    transition: opacity 0.15s ease;
}

/* The icon-button skeleton (transparent/borderless/centered) is shared in
   common/style.css; only the size + color deltas live here. */

/* Base action button styles - shared by asset and component buttons.
   With its padding the button is exactly as tall as the row it sits in (the
   header's 40px). Any taller and the row, which clips, cuts the top and
   bottom off the focus ring drawn inside the button. */
.button-bare-inst-asset-action,
.button-bare-inst-component-action {
    width: 24px;
    height: var(--space-4);
    padding: var(--space-2);
    margin: calc(-1 * var(--space-2));
    box-sizing: content-box;
    color: var(--color-text-dark);
}

.button-bare-inst-asset-action:hover,
.button-bare-inst-component-action:hover {
    color: var(--color-text);
}

/* Expand/collapse button. As tall as its row, like the action buttons. */
.button-bare-inst-expand {
    width: 24px;
    height: var(--space-4);
    padding: var(--space-2);
    margin: calc(-1 * var(--space-2));
    box-sizing: content-box;
    color: var(--color-text-dark);
    flex-shrink: 0;
}

.button-bare-inst-expand:hover {
    color: var(--color-text);
}

/* Chevron rotation when expanded (override for button wrapper) */
.expandable.expanded > .expandable-part-header > .button-bare-inst-expand > .expandable-part-icon {
    transform: rotate(90deg);
}

/* Ellipsis menu container */
.menu-inst-ellipsis-container {
    position: relative;
    display: inline-block;
}

/* Ellipsis menu positioning (uses .menu base styles from style.css).
   The menu hangs off the right end of its row and reads as one more section
   of it: the nudges land it on the row's outer right edge with its top
   border laid over the row's bottom border, so the one line between them is
   the same separator the menu draws between its own sections
   (.menu-part-divider), and the corners at that join are square. */
.menu-inst-ellipsis {
    position: fixed;
    margin-top: -2px; /* raise 2px from the JS-computed position */
    margin-left: 1px; /* nudge 1px right */
    border-radius: 0 0 var(--radius-sm) var(--radius-sm);
    /* Cut the drop shadow off at the join: a section of the row would not
       cast one back onto it. The other three sides keep theirs. */
    clip-path: inset(0 -20px -20px -20px);
}

/* Opened above its button (no room below): the same join, mirrored. */
.menu-inst-ellipsis.menu-up {
    margin-top: 2px; /* lower 2px from the JS-computed position */
    border-radius: var(--radius-sm) var(--radius-sm) 0 0;
    clip-path: inset(-20px -20px 0 -20px);
}

/* The row squares the corner its open menu meets (BuilderPanelAssets
   .toggleEllipsisMenu sets these). An expanded row's bottom corner is far
   below its header, so only a collapsed one gives it up. */
.expandable.has-menu-below:not(.expanded) {
    border-bottom-right-radius: 0;
}

.expandable.has-menu-above {
    border-top-right-radius: 0;
}

/* Individual Assets - specific styling only (uses .expandable base classes in HTML) */
/* .asset inherits background: transparent from .expandable base class */

/* .asset-expand-icon inherits all from .expandable-part-icon - no specific styling needed */

/* asset-content uses base .expandable-part-content rules */

/* Base classes for all "Add" buttons */
.item-add-button {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2);
    border: var(--border-width) dashed var(--color-border);
    border-radius: var(--radius-sm);
    background: transparent;
    justify-content: center;
    cursor: pointer;
    transition: background-color 0.15s ease;
    height: 40px;
}

.item-add-button:hover {
    background: var(--color-surface);
}

.item-add-text {
    font-size: var(--font-size-sm);
    color: var(--color-text-dark);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Component Fields - unified field wrapper for all component properties */
.component-field {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2);
    border-bottom: var(--border-width) var(--border-style) var(--color-border);
}

.component-field:last-child {
    border-bottom: none;
}

.property-label {
    font-size: var(--font-size-sm);
    color: var(--color-text);
    flex-shrink: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ====================
   UNIFIED EXPANDABLE PATTERN
   Base classes for all collapsible/expandable sections

   BACKGROUND COLOR RULE:
   - Headers (.expandable-part-header): var(--color-surface) - lighter
   - Content (.expandable-part-content): var(--color-background) - darker
   - Wrappers (.expandable): transparent - no background
   ==================== */

/* Utility class for text truncation */
.text-truncate {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Expandable Section Overrides for Assets Panel
   Base styles in common/style.css, panel-specific overrides here. */

.expandable {
    width: 100%;
    min-width: 0;
    overflow: hidden;
}

/* Note: .expandable-indented class exists but has no specific styles.
   Indentation is handled by parent padding instead of child margin. */

/* Content with opacity fade */
.expandable-part-content {
    transition: grid-template-rows 0.25s ease, opacity 0.25s ease;
    width: 100%;
    min-width: 0;
    opacity: 0;
}

.expandable.expanded > .expandable-part-content {
    opacity: 1;
}

/* Enhanced content-inner for assets panel */
.expandable-part-content-inner {
    width: 100%;
    min-width: 0;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding: 0 var(--space-2);
    transition: padding 0.25s ease;
}

.expandable.expanded > .expandable-part-content > .expandable-part-content-inner {
    padding: var(--space-2);
}

/* Note: Each specific content class (.asset-content, .preview-content, etc.)
   has its own expanded rule with the appropriate display value (block or flex).
   The generic rule above handles the animation properties. */

/* Collapsible section lists - expanded state */
.expandable-indented.expanded > .preview-content,
.expandable-indented.expanded > .advanced-content,
.expandable-indented.expanded > .causes-content,
.expandable-indented.expanded > .effects-content,
.expandable.expanded > .preview-content,
.expandable.expanded > .advanced-content,
.expandable.expanded > .causes-content,
.expandable.expanded > .effects-content {
    grid-template-rows: 1fr;
    border-top: var(--border-width) var(--border-style) var(--color-border);
}

/* Causes/Effects: trigger items pad themselves, so the inner has no padding.
   Advanced is intentionally NOT in this rule — its inner contains a
   .component-fields block whose edge-to-edge negative margin needs the
   default .expandable-part-content-inner padding to consume. */
.causes-content > .expandable-part-content-inner,
.effects-content > .expandable-part-content-inner {
    padding: 0;
    transition: none;
}

/* Override expanded state padding (must be more specific than generic rule) */
.expandable.expanded > .causes-content > .expandable-part-content-inner,
.expandable.expanded > .effects-content > .expandable-part-content-inner,
.expandable-indented.expanded > .causes-content > .expandable-part-content-inner,
.expandable-indented.expanded > .effects-content > .expandable-part-content-inner {
    padding: 0;
}

/* Causes/Effects lists contain trigger-item elements (see CAUSES/EFFECTS section below) */

/* Template siblings run on the copies, not the template itself. Reads as the
   first row of the param list: out to the panel edges the way
   .component-fields is, then padded and divided like a .component-field, so
   its text starts where every param label does. The negative bottom margin
   swallows the content column's row gap, because param rows meet each other
   flush and this one has to meet the first of them the same way. */
.behavior-template-hint {
    margin: 0 calc(-1 * var(--space-2)) calc(-1 * var(--space-2));
    padding: var(--space-2);
    border-bottom: var(--border-width) var(--border-style) var(--color-border);
    font-size: var(--font-size-sm);
    font-style: italic;
    color: var(--color-text-dark);
}

/* The fields' own pull-up would drag the first param row over the hint's
   divider; the hint is the top of the column now. */
.behavior-template-hint + .asset-fields,
.behavior-template-hint + .component-fields {
    margin-top: 0;
}

/* Inline fields - displayed at top of content without collapsible wrapper
   .asset-fields: asset config at top of asset content
   .component-fields: behavior params at top of component content */
.asset-fields,
.component-fields {
    display: flex;
    flex-direction: column;
    /* Extend to edges by countering parent padding */
    margin: calc(-1 * var(--space-2)) calc(-1 * var(--space-2)) 0;
    border-bottom: var(--border-width) var(--border-style) var(--color-border);
}

.asset-fields .component-field,
.component-fields .component-field {
    padding: var(--space-2);
}

/* Remove border from last visible field.
   :last-child alone is not enough: params hidden by a hiddenWhen predicate
   stay in the DOM as display:none, so the last child can be an invisible
   row while the last *seen* row keeps its divider and doubles up against
   the container's bottom border. The panel marks the last visible field
   with .is-last-visible; :last-child stays for the containers built
   without that pass. */
.asset-fields .component-field:last-child,
.component-fields .component-field:last-child,
.asset-fields .component-field.is-last-visible,
.component-fields .component-field.is-last-visible {
    border-bottom: none;
}

/* When .asset-fields / .component-fields is the only/last child of its
   expandable content, nothing follows it — consume the parent's bottom
   padding and drop the now-orphaned divider so it doesn't look like a
   half-finished section. */
.asset-fields:last-child,
.component-fields:last-child {
    margin-bottom: calc(-1 * var(--space-2));
    border-bottom: none;
}

/* Horizontal line before preview/advanced/causes/effects sections */
.preview,
.advanced,
.causes,
.effects {
    border-top: var(--border-width) var(--border-style) var(--color-border);
}

/* Visual behavior thumbnail fills its section */
.behavior-preview-image {
    display: block;
    width: 100%;
}

/* Positioning context for the asset attribution "(i)" button overlay
   (both image and audio previews). */
.preview-content > .expandable-part-content-inner {
    position: relative;
}

/* Image previews go edge-to-edge: strip the inner padding so the thumbnail
   isn't inset by --space-2. Audio previews keep the default inset. */
.preview-content > .expandable-part-content-inner:has(> .behavior-preview-image) {
    padding: 0;
    transition: none;
}

.expandable.expanded > .preview-content > .expandable-part-content-inner:has(> .behavior-preview-image),
.expandable-indented.expanded > .preview-content > .expandable-part-content-inner:has(> .behavior-preview-image) {
    padding: 0;
}

/* Component content - padding and gap for child sections */
.component-content > .expandable-part-content-inner {
    gap: var(--space-2);
    padding: 0 var(--space-2);
}

.expandable.expanded > .component-content > .expandable-part-content-inner {
    padding: var(--space-2);
}


/* Individual Components - specific styling only (uses .expandable base classes in HTML) */
/* .component inherits background: transparent from .expandable base class */

.component-name {
    flex: 1;
    font-size: var(--font-size-sm);
    color: var(--color-text);
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Parameter Control Container */
.param-control-container {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
}

/* Compact panel fields: the parameter inputs and the inline rename field. */
.form-inst-param,
.form-inst-param-select,
.form-inst-param-area,
.form-inst-vector,
.param-checkbox-group-summary,
.form-inst-rename {
    flex: 1;
    min-width: 0;
    padding: var(--space-1);
    /* background-color, not the shorthand: the shorthand would wipe the caret
       image the shared select rule paints on .form-inst-param-select. */
    background-color: var(--color-background);
    border: var(--border-width) var(--border-style) var(--color-border);
    border-radius: var(--radius-sm);
    color: var(--color-text);
    font-size: var(--font-size-sm);
    outline: none;
    transition: border-color 0.15s ease;
}

.form-inst-param:focus,
.form-inst-param-select:focus,
.form-inst-param-area:focus,
.form-inst-vector:focus,
.param-checkbox-group-summary:focus,
.form-inst-rename:focus {
    border-color: var(--color-accent);
}

/* Error state for inputs with invalid values */
.form-inst-param.error,
.form-inst-param-area.error {
    border-color: var(--color-error);
}

/* Specific input overrides */
.form-inst-param-select {
    cursor: pointer;
    /* The compact `padding` this field shares with the text params (above)
       beats the shared select rule in common/style.css and would run a long
       value under its caret. Keep the caret's own room. */
    padding-right: var(--select-caret-room);
}

.form-inst-param-area {
    resize: vertical;
    min-height: 40px;
}

/* Code-editor variant -- opt-in via `code: true` on the param. Used for
   GraphQL, JSON, and other code-like content where character alignment
   helps readability. Wrap is also disabled at the element level via the
   textarea's `wrap` attribute. The 0.75em correction compensates for
   monospace fonts (Monaco/Menlo) rendering optically larger than the
   inspector's proportional font at the same nominal size. */
.form-inst-param-area-code {
    font-family: var(--font-family-mono);
    font-size: 0.75em;
}

/* margin-right: auto pushes the bind toggle to the right edge so it
   lines up with other param types, where the input fills the wrapper
   via flex: 1. */
.param-checkbox {
    flex: unset;
    margin-right: auto;
}

.param-color {
    cursor: pointer;
}

.param-checkbox-group {
    flex: 1;
    min-width: 0;
}

.param-checkbox-group-summary {
    cursor: pointer;
    list-style: none;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Bindable param wrapper: hosts the literal input (number or checkbox), bound-source chip, and bind toggle */
.param-bind-wrapper {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: var(--space-1);
}

.param-bind-wrapper .form-inst-param {
    flex: 1;
    min-width: 0;
}

.param-bind-wrapper .param-binding-chip {
    flex: 1;
    min-width: 0;
}

.button-bare-inst-param-bind {
    flex: unset;
    flex-shrink: 0;
    width: 18px;
    height: 18px;
    padding: 0;
    color: var(--color-link);
}

.button-bare-inst-param-bind svg {
    width: 14px;
    height: 14px;
}

.button-bare-inst-param-bind:hover {
    color: var(--color-link-light);
}

.param-checkbox-group-summary::-webkit-details-marker {
    display: none;
}

.param-checkbox-group-summary:hover {
    border-color: var(--color-accent);
}

.param-checkbox-group-options {
    padding: var(--space-2);
    background: var(--color-surface);
    border: var(--border-width) var(--border-style) var(--color-border);
    border-radius: var(--radius-sm);
    border-top: none;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.param-checkbox-group-item {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    cursor: pointer;
    font-size: var(--font-size-sm);
    color: var(--color-text);
}

/* Vector Input Container */
.form-inst-vector-group {
    display: flex;
    gap: var(--space-1);
    flex: 1;
    min-width: 0;
    overflow: hidden;
}

.form-inst-vector {
    min-width: 40px;
    overflow: hidden;
}

.form-inst-vector::placeholder {
    color: var(--color-text-dark);
}

/* Selection highlight for assets, components, and folders (synced with 3D view) */
.asset.selected,
.component.selected,
.folder-wrapper.selected {
    border-color: var(--color-accent);
}

/* Parent asset gets muted accent when a component inside it is selected.
   Structural on purpose: a selected component carries the primary accent
   while its host asset (which may not have .selected itself) shows the
   muted one. */
.asset:has(.component.selected) {
    border-color: var(--color-accent-dark);
}

/* Asset error state (e.g., orphaned Asset2D not parented to any canvas) */
.asset.asset-error {
    border-color: var(--color-error);
}

/* Asset Selector Control (for behavior params) */
.param-asset-selector {
    display: flex;
    flex-direction: column;
    flex: 1;
}

/* Make asset selector span full width on its own line */
.component-field:has(.param-asset-selector) {
    flex-wrap: wrap;
}

.component-field:has(.param-asset-selector) .param-control-container {
    flex-basis: 100%;
}

/* String List Control */
.param-string-list {
    display: flex;
    flex-direction: column;
    flex: 1;
}

/* String list fields: wrap to label above when space is tight */
.component-field:has(.param-string-list) {
    flex-wrap: wrap;
}

.component-field:has(.param-string-list) .param-control-container {
    flex-basis: 100%;
}

/* Vector fields: wrap to label above inputs when space is tight */
.component-field:has(.form-inst-vector-group) {
    flex-wrap: wrap;
}

.component-field:has(.form-inst-vector-group) .form-inst-vector-group {
    flex: 1;
    min-width: 150px;
}

/* Dropdown and checkbox group fields: wrap to label above when space is tight */
.component-field:has(.form-inst-param-select),
.component-field:has(.param-checkbox-group) {
    flex-wrap: wrap;
}

.component-field:has(.form-inst-param-select) .param-control-container,
.component-field:has(.param-checkbox-group) .param-control-container {
    flex: 1;
    min-width: 150px;
}

/* Code-mode textareas: drop the textarea onto its own row beneath the
   label so it gets the full inspector width (mirrors the asset-selector
   pattern). Only the code variant needs this -- short, single-line
   multiline params (e.g., descriptions) still read fine inline. */
.component-field:has(.form-inst-param-area-code) {
    flex-wrap: wrap;
}

.component-field:has(.form-inst-param-area-code) .param-control-container {
    flex-basis: 100%;
}

/* Disabled component fields */
.component-field.disabled {
    opacity: 0.5;
}

.component-field.disabled .property-label {
    color: var(--color-text-dark);
}

.component-field.disabled input:disabled {
    cursor: not-allowed;
    background: var(--color-surface);
}

/* ====================
   FOLDER STYLES
   Folders use same classes as assets (.asset-name, .asset-actions, etc.)
   with additional folder-specific classes below
   ==================== */

/* Folder icon - same styling as asset type icons */
.folder-icon {
    font-size: var(--font-size-sm);
    height: 16px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    color: var(--color-text-dark);
}

/* Drag and drop states */
.expandable-part-header.drag-over {
    outline: var(--border-width) solid var(--color-accent);
    outline-offset: calc(-1 * var(--border-width));
}

.asset.dragging,
.folder-wrapper.dragging {
    opacity: 0.1;
}

/* Disable hover effects during drag and FLIP animations */
.asset-list.dragging-active *,
.asset-list.flip-animating * {
    pointer-events: none;
}

.asset-list.dragging-active .asset,
.asset-list.dragging-active .folder-wrapper,
.asset-list.dragging-active .expandable-part-header {
    pointer-events: auto;
}

/* Drop position indicator: one accent line centred in the list gap, half
   the gap plus half the line's own height out from the row. That second
   term is what lands "below the row above" and "above the row below" on
   the same pixels, so one gap only ever shows one insert. */
.asset,
.folder-wrapper {
    position: relative;
}

.asset.drop-before,
.asset.drop-after,
.folder-wrapper.drop-before,
.folder-wrapper.drop-after {
    overflow: visible;
}

.asset.drop-before::before,
.folder-wrapper.drop-before::before {
    content: '';
    position: absolute;
    top: calc(-0.5 * var(--space-2) - 1px);
    left: 0;
    right: 0;
    height: 2px;
    background: var(--color-accent);
    pointer-events: none;
    z-index: 10;
}

.asset.drop-after::after,
.folder-wrapper.drop-after::after {
    content: '';
    position: absolute;
    bottom: calc(-0.5 * var(--space-2) - 1px);
    left: 0;
    right: 0;
    height: 2px;
    background: var(--color-accent);
    pointer-events: none;
    z-index: 10;
}

/* A list with nothing in it says so. The container names its own line
   (data-empty) and :empty shows it, so the incremental inserts and removes
   (BuilderPanelAssetsRefresh) need no bookkeeping: the asset list is only
   ever empty on a search miss (the add buttons fill it otherwise), and a
   folder body only when the folder is truly empty (one whose contents are
   all filtered out is hidden itself, folderHasMatchingAsset). Same look as
   the pickers' .select-empty. */
.empty-line:empty::before {
    content: attr(data-empty);
    display: block;
    padding: var(--space-3);
    text-align: center;
    color: var(--color-text-dark);
}

/* Add buttons container */
.add-buttons-container {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

.add-buttons-container > * {
    flex: 1 1 0;
    min-width: 100px;
}

/* ====================
   CAUSES/EFFECTS SECTIONS
   Trigger items and connections within behavior components
   ==================== */

/* .advanced-header/.causes-header/.effects-header always used with .expandable-part-header - DO NOT override height */
.advanced-header,
.causes-header,
.effects-header {
    font-size: var(--font-size-sm);
}

/* .section-part-expand-icon inherits all from .expandable-part-icon - no specific styling needed */

.trigger-item {
    padding: 0 var(--space-2) var(--space-2) var(--space-2);
    border-bottom: var(--border-width) var(--border-style) var(--color-border);
}

.trigger-item:first-child {
    padding-top: var(--space-2);
}

.trigger-item:last-child {
    border-bottom: none;
}

/* Trigger header is NOT an expandable header - just a label for cause/effect triggers */
.trigger-header {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: var(--space-2);
}

.trigger-name {
    font-size: var(--font-size-sm);
    color: var(--color-text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.connections-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

/* Space between a populated list and the add button below.
   Lives on the button (not on the list as margin-bottom) so a hidden
   add button (e.g. single-ref slot at capacity) doesn't leave a gap. */
.connections-list:not(:empty) + .add-connection-button {
    margin-top: var(--space-2);
}

.connection-item {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-1);
    background: var(--color-surface);
    border: var(--border-width) var(--border-style) var(--color-border);
    border-radius: var(--radius-sm);
    font-size: var(--font-size-sm);
}

.connection-label {
    flex: 1;
    color: var(--color-text);
    font-family: var(--font-family-mono);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.connection-label.connection-missing {
    color: var(--color-error);
}

.connection-row {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.connection-row .connection-item {
    flex: 1;
}

.connection-letter {
    color: var(--color-text-dark);
    font-family: var(--font-family-mono);
    font-size: var(--font-size-sm);
    min-width: 2em;
    text-align: right;
}

/* Unified connection remove button */
.button-bare-inst-connection-remove {
    width: 18px;
    height: 18px;
    padding: 0;
    color: var(--color-text-dark);
    flex-shrink: 0;
}

.button-bare-inst-connection-remove svg {
    width: 14px;
    height: 14px;
}

.button-bare-inst-connection-remove:hover {
    color: var(--color-error);
}

.add-connection-button {
    width: 100%;
    padding: var(--space-1) var(--space-2);
    background: transparent;
    border: var(--border-width) dashed var(--color-border);
    border-radius: var(--radius-sm);
    color: var(--color-text-dark);
    font-size: var(--font-size-sm);
    cursor: pointer;
    transition: all 0.15s ease;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.add-connection-button:hover {
    background: var(--color-surface);
    border-style: solid;
    color: var(--color-text);
}

/* Factory field labels: icon + text lead-in above a component's input
   (BuilderPanelAssetsFactoryField). */
.asset-section-label {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  color: var(--color-text);
}

.asset-section-icon {
  display: inline-flex;
  align-items: center;
  color: var(--color-text-dark);
}
