/* Behavior Modal - Grid Editor for Causes and Effects */
/* Note: Layout values must match BuilderModalBehavior.js constants:
   TILE_WIDTH=150, ARROW_WIDTH=24 (tile/label heights are content-driven) */

/* Content wrapper */
.behavior-modal-content {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
    overflow: hidden;
}

/* Scrollable wrapper */
.behavior-canvas-wrapper {
    flex: 1;
    min-height: 0;
    overflow: auto;
    background: var(--color-background);
    border: var(--border-width) var(--border-style) var(--color-border);
    border-radius: var(--radius-sm);
}

/* Zoomable canvas - using CSS Grid */
.behavior-grid-canvas {
    display: grid;
    row-gap: var(--space-2);
    column-gap: 0;
    padding: var(--space-2);
    align-items: start;
    align-content: start;
    transform-origin: top left;
}

/* Arrow separator between columns */
.behavior-arrow {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    align-self: stretch;
    width: 24px;
    gap: var(--space-1);
    color: var(--color-text-dark);
}

.behavior-arrow svg {
    width: 16px;
    height: 16px;
}

.behavior-arrow-marker {
    display: flex;
    align-items: center;
    justify-content: center;
}

/* An edge that can take a modifier swaps its chevron for a plus on hover. */
.behavior-arrow-plus {
    display: none;
}

.behavior-arrow-insertable .behavior-arrow-marker {
    cursor: pointer;
}

.behavior-arrow-insertable:hover .behavior-arrow-chevron {
    display: none;
}

.behavior-arrow-insertable:hover .behavior-arrow-plus {
    display: flex;
    color: var(--color-accent);
}

/* Which output of a branching modifier (Sequence, Random Branch) this arrow
   carries. One letter, so it fits the arrow column as it is. */
.behavior-arrow-label {
    font-size: var(--font-size-xs);
    color: var(--color-text-dark);
}

/* A branch that is one outcome against its opposite -- a Picker's pick against
   its cancel -- marks its arrows with a tick and a cross instead of letters,
   in the colours those two answers wear everywhere else. Dim grey is right for
   a modifier's A/B/C, where the tiles below say which is which; here the mark
   is the only thing telling two arrows apart, so it carries the weight. */
.behavior-arrow-label-success {
    color: var(--color-success);
}

.behavior-arrow-label-failure {
    color: var(--color-error);
}

/* An edge that does not wait: wiring authored before completion ports, on an
   Effect that takes time. It fires the moment that Effect is invoked rather
   than when it finishes, so a chain that runs all at once never reads as a
   sequence. */
.behavior-arrow-immediate::before {
    content: '';
    position: absolute;
    inset-inline: 0;
    top: 50%;
    border-top: var(--border-width) dashed var(--color-border);
}

/* Arrow pointing at a "+ Add" tile: tile sits at the top of its grid row
   (align-self: start, content-sized). Anchor the chevron to the top with
   matching --space-2 padding so its icon center lines up with the tile's
   text center. */
.behavior-arrow-to-add {
    align-self: start;
    padding: var(--space-2) 0;
}

/* Column header label (top row); height auto-fits content */
.behavior-column-label {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
}

.behavior-column-label span {
    font-size: var(--font-size-sm);
    color: var(--color-text-dark);
    text-transform: uppercase;
    letter-spacing: 0.1em;
}

.behavior-column-label .column-label-icon {
    display: flex;
    color: var(--color-text-dark);
}

/* Base tile styles. Single-row tiles are content-sized; row-spanning tiles
   stretch to fill their span (parent tile's vertical extent = sum of its
   leaf descendants' row heights). */
.behavior-tile {
    --close-size: 18px;
    position: relative;
    min-width: 150px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    border-radius: var(--radius-sm);
    cursor: pointer;
    /* Background fades on hover; opacity fades when the filter dim toggles. */
    transition: background 0.15s ease, opacity 0.15s ease;
    background: var(--color-surface);
    color: var(--color-text);
    border: var(--border-width) solid var(--color-border);
}

/* Tile delete button - matches button-bare-inst-connection-remove style */
.behavior-tile-delete {
    position: absolute;
    top: var(--space-1);
    right: var(--space-1);
    width: var(--close-size);
    height: var(--close-size);
    padding: 0;
    background: transparent;
    border: none;
    color: var(--color-text-dark);
    cursor: pointer;
    transition: color 0.15s ease;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}

.behavior-tile-delete svg {
    width: 14px;
    height: 14px;
}

.behavior-tile-delete:hover {
    color: var(--color-error);
}

/* Tile entrance animation */
@keyframes tile-enter {
    from {
        opacity: 0;
        transform: scale(0.9);
    }
    to {
        opacity: 1;
        transform: scale(1);
    }
}

.behavior-tile.tile-new {
    animation: tile-enter 0.25s ease forwards;
}

.behavior-tile:hover {
    background: var(--color-surface-light);
}

/* Read-only tiles (valueFlow consumers and inline cause/effect chains
   reached through valueFlow) — no replace-on-click, no delete button. */
.behavior-tile-readonly {
    cursor: default;
}

.behavior-tile-readonly:hover {
    background: var(--color-surface);
}

/* Add tile (dashed) */
.behavior-tile-add {
    background: transparent;
    color: var(--color-text-dark);
    border-style: dashed;
    justify-content: center;
    padding: var(--space-2);
    font-size: var(--font-size-sm);
}

.behavior-tile-add:hover {
    background: var(--color-surface);
}

.behavior-tile .tile-label {
    text-align: center;
}

.tile-breadcrumb {
    flex-shrink: 0;
    width: 100%;
    padding: var(--space-2);
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    overflow: hidden;
}

.tile-breadcrumb-row {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-width: 0;
}

.tile-breadcrumb-icon {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    /* Color inherits from the tile so kind-variant tinting cascades
       to the SVG icon (via currentColor). Same mix as the text. */
}

.tile-breadcrumb-icon svg {
    width: 16px;
    height: 16px;
}

.tile-breadcrumb-text {
    flex: 1;
    min-width: 0;
    font-size: var(--font-size-sm);
    /* Color inherits from the tile so kind-variant tinting (mixed at
       25% against --color-text) cascades through. Tile sets `color`
       in #addOrUpdateTile. */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Asset / Behavior breadcrumb rows are clickable to filter the editor
   down to chains touching that asset/behavior. */
.tile-breadcrumb-row.row-focusable {
    cursor: pointer;
    transition: background 0.15s ease;
}

.tile-breadcrumb-row.row-focusable:hover {
    background: var(--color-surface-light);
}

/* Filter: when any of (locked focus, hover preview, search) is active, the
   canvas gets .has-filter and matching tiles get .tile-match. Everything
   else under the canvas dims so the chains touching the focused
   asset/behavior — or matching the search — stand out. Transition lives
   on the children directly so the fade-back also animates when
   .has-filter is removed. Background is listed too so this rule doesn't
   clobber the tile's own background-hover transition (equal specificity
   to .behavior-tile, this rule wins on source order — listing both
   properties keeps the tile-hover fade intact). */
.behavior-grid-canvas > * {
    transition: opacity 0.15s ease, background 0.15s ease;
}

.behavior-grid-canvas.has-filter > *:not(.tile-match):not(.behavior-folder) {
    opacity: 0.25;
}

/* ---------------------------------------------------------------------
   Folders and drag-to-rearrange (Cause column only)
   --------------------------------------------------------------------- */

/* Folder heading: spans every column so it reads as a divider across the
   whole canvas rather than a tile in the Cause column. Layout, padding
   and the 40px height come from .expandable-part-header, the same class
   every list row in the builder is built on -- see #renderFolderRow. Only
   what makes it a heading rather than a list row is set here. */
.behavior-folder {
    /* The name label and the input that replaces it share this width, so
       swapping one for the other never moves the heading around. */
    --folder-name-width: 200px;
    position: relative;
    border: var(--border-width) var(--border-style) var(--color-border);
    border-radius: var(--radius-sm);
    color: var(--color-text-dark);
    cursor: grab;
}

.behavior-folder-toggle,
.behavior-folder-delete {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    background: transparent;
    border: none;
    color: var(--color-text-dark);
    cursor: pointer;
    flex-shrink: 0;
    transition: color 0.15s ease;
}

.behavior-folder-toggle svg,
.behavior-folder-delete svg,
.behavior-folder-icon svg {
    width: 16px;
    height: 16px;
}

.behavior-folder-toggle:hover {
    color: var(--color-text);
}

.behavior-folder-delete {
    /* Pushed to the far edge so the heading's actions bracket its name. */
    margin-left: auto;
}

.behavior-folder-delete:hover {
    color: var(--color-error);
}

.behavior-folder-icon {
    display: flex;
    align-items: center;
    flex-shrink: 0;
}

/* The label wears the input's whole box -- same width, same padding, and
   a transparent border standing in for the input's -- so clicking to
   rename swaps the two without the heading changing size. Same idea as
   the asset panel, where .asset-name and .form-inst-rename are both
   flex: 1; here it is a fixed width rather than the full heading, which
   runs the width of the canvas. */
.behavior-folder-name,
.behavior-folder .form-inst-rename {
    flex: 0 1 var(--folder-name-width);
    min-width: 0;
    padding: var(--space-1);
    font-size: var(--font-size-sm);
}

.behavior-folder-name {
    border: var(--border-width) var(--border-style) transparent;
    color: var(--color-text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    cursor: pointer;
}

/* The row being dragged fades so the drop line reads against it. */
.behavior-tile.dragging,
.behavior-folder.dragging {
    opacity: 0.4;
}

/* Drop indicator: one line centred in the row gap, the same geometry the
   asset panel uses. Centring it there is what makes a gap read as a
   single place to land -- drawn at the rows' own edges instead, the one
   gap between two rows shows a different line depending on which of the
   two the cursor happens to be over.

   .behavior-tile carries the watermark host's overflow: hidden, which
   would clip a line drawn outside the box, so the class lifts it for as
   long as the drag is over that row. */
.behavior-tile.drop-before,
.behavior-tile.drop-after,
.behavior-folder.drop-before,
.behavior-folder.drop-after {
    overflow: visible;
}

.behavior-tile.drop-before::after,
.behavior-tile.drop-after::after,
.behavior-folder.drop-before::after,
.behavior-folder.drop-after::after {
    content: '';
    position: absolute;
    inset-inline: 0;
    height: 2px;
    background: var(--color-accent);
    pointer-events: none;
    z-index: 10;
}

/* Half the row gap, plus half the line's own height. That second term is
   what makes the two states land on the same pixels: "below the row
   above" and "above the row below" both centre the line on the boundary
   between them, so one gap only ever shows one insert. */
.behavior-tile.drop-before::after,
.behavior-folder.drop-before::after {
    top: calc(-0.5 * var(--space-2) - 1px);
}

.behavior-tile.drop-after::after,
.behavior-folder.drop-after::after {
    bottom: calc(-0.5 * var(--space-2) - 1px);
}

/* Dropping a chain INTO a folder lights the whole heading, since the
   landing place is the folder rather than a position between rows. */
.behavior-folder.drop-into {
    background: var(--color-surface-light);
    border-color: var(--color-accent);
}

/* A chain inside a folder shifts right as one block -- cause tile, arrows
   and every effect tile -- so the indent is what says where the folder's
   contents end and the loose chains below it begin. Margin rather than
   transform, which the FLIP pass owns. The negative right margin hands back
   exactly what the left one takes, so each element keeps its column's full
   width and nothing inside the chain moves relative to anything else. */
.behavior-grid-canvas > .behavior-chain-indented {
    margin-left: var(--space-4);
    margin-right: calc(-1 * var(--space-4));
}

/* Control bar spacing */
.modal-behavior .search-row {
    margin-bottom: var(--space-2);
}

/* Hide empty button container */
.modal-behavior .modal-part-buttons {
    display: none;
}
