/* threshold-fb.css — form-builder gesture overlays.
 *
 * Port of design canon's fb.css row-split block (design-references/
 * design_handoff_form_builder/fb.css §854–1064) with the codebase's
 * fb-* class prefix substituted for canon's fb-* (the form-builder
 * code uses fb-cell, fb-row, fb-cell-shell, fb-drag-ghost, etc. —
 * this file keeps that conventional). Canon's data-attribute contracts
 * (data-cx-split-target, data-cx-modifier-active, data-cx-source-width)
 * stay verbatim since they already use the cx prefix.
 *
 * Contract per component-separation.md §16 + design-system.md §24:
 *
 *   body[data-cx-modifier-active="alt"]      — Alt held during a drag
 *   [data-cx-split-target="valid"]           — cell will split on drop
 *   [data-cx-split-target="invalid"]         — source too wide for cell
 *   [data-cx-split-target="row-insert"]      — drop is between cells
 *   [data-cx-split-target="row-spawn"]       — row at width-sum 12; spawn
 *                                              a new row above/below
 *   data-cx-source-width="N" (on cells)      — read by the invalid ::after
 *                                              pill so the reject copy names
 *                                              the count (§13 + §14)
 *
 * CSS custom properties driven by the gesture layer alongside those
 * attributes:
 *
 *   --fb-split-pos   — percentage from cell's left edge for the vertical
 *                      split line, computed (source.width / target.width) × 100%
 *   --fb-insert-pos  — percentage from row's left edge for the row-insert
 *                      bar, computed (insertCol / 12) × 100%
 *
 * No new Razor components — canvas/row/cell views push the attributes;
 * the rules in this file render the visual feedback declaratively.
 */

/* ──────────────────────────────────────────────────────────────────────────
 * Modifier indicator — fixed pill at the bottom of the canvas, only visible
 * while body[data-cx-modifier-active] is set. Confirms to the admin that the
 * system saw the modifier; gives them a place to look when they wonder
 * "is hold-Alt actually doing anything?". Low-affordance, never on top of
 * canvas content.
 * ────────────────────────────────────────────────────────────────────────── */
.fb-modifier-indicator {
    position: fixed;
    bottom: 16px;
    left: 50%;
    transform: translateX(-50%);
    display: none;
    align-items: center;
    gap: 8px;
    padding: 6px 12px 6px 8px;
    background: var(--cx-surface);
    border: 1px solid var(--cx-gesture-border);
    border-radius: var(--cx-radius-pill);
    box-shadow: 0 6px 18px rgba(20, 22, 30, 0.10);
    color: var(--cx-gesture);
    font-size: 11.5px;
    font-weight: 500;
    z-index: 80;
    pointer-events: none;
}
body[data-cx-modifier-active="alt"] .fb-modifier-indicator { display: inline-flex; }
.fb-modifier-indicator kbd {
    font-family: var(--th-font-mono);
    font-size: 10px;
    color: var(--cx-gesture);
    background: var(--cx-gesture-soft);
    border: 1px solid var(--cx-gesture-border);
    border-radius: 2px;
    padding: 1px 5px;
    line-height: 1;
}
.fb-modifier-indicator .meta {
    color: var(--cx-ink-muted);
    font-family: var(--th-font-sans);
    font-weight: 400;
}

/* ──────────────────────────────────────────────────────────────────────────
 * Cell-level split target — Target A in canon (drop on existing cell).
 * The cell renders a 2px dashed gesture-purple ring (outline so the cell's
 * geometry doesn't reflow on hover) and a translucent gesture-soft fill.
 * The split position itself is drawn by the .fb-split-indicator child
 * overlay; this rule primes the cell.
 * ────────────────────────────────────────────────────────────────────────── */
[data-cx-split-target="valid"] .fb-cell-shell,
.fb-cell-shell[data-cx-split-target="valid"] {
    outline: 2px dashed var(--cx-gesture-border);
    outline-offset: -1px;
    background: var(--cx-gesture-soft) !important;
    box-shadow: none !important;
}

/* Bypass-shell cells (Group, Spacer) carry their own visual chrome rather
 * than a fb-cell-shell. For the §7.20 cell-split gesture they get the same
 * valid-target highlight applied to their outer chrome — the group's
 * section block, the spacer's body. */
[data-cx-split-target="valid"] > .fb-group,
[data-cx-split-target="valid"] > .fb-drop-target--bypass > .fb-group,
[data-cx-split-target="valid"] > .fb-drop-target--bypass {
    outline: 2px dashed var(--cx-gesture-border);
    outline-offset: -1px;
}

/* Invalid target — source-width > target-width. Red dashed ring + reject
 * pill. The cell's content stays legible (no dim) because the admin needs
 * to read the existing field's width to decide what to do. */
[data-cx-split-target="invalid"] .fb-cell-shell,
.fb-cell-shell[data-cx-split-target="invalid"] {
    outline: 2px dashed var(--cx-error-border);
    outline-offset: -1px;
    background: var(--cx-error-soft) !important;
    box-shadow: none !important;
    cursor: not-allowed;
}
/* Reject pill — a real span inside the cell-shell rather than a ::after
 * pseudo-element. The previous pseudo-element approach used attr() to read
 * data-cx-source-width, but CSS attr() resolves on the element bearing
 * the pseudo (the cell-shell), not on the cell-wrapper ancestor that
 * carries the attribute — so the source-width was silently dropped from
 * the copy. A real DOM element renders the dynamic value reliably and
 * is testable via data-testid. */
.fb-cell-shell__reject-pill,
.fb-cell__reject-pill {
    position: absolute;
    bottom: 6px;
    right: 8px;
    font-size: 10.5px;
    font-family: var(--th-font-mono);
    color: var(--cx-error);
    background: var(--cx-surface);
    border: 1px solid var(--cx-error-border);
    border-radius: var(--cx-radius-xs);
    padding: 2px 6px;
    pointer-events: none;
    max-width: calc(100% - 16px);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    z-index: 7;
}

/* ──────────────────────────────────────────────────────────────────────────
 * Split indicator — vertical dashed gesture-purple line inside the target
 * cell at (source.width / target.width × 100%) from the cell's left edge.
 * Position is data-driven; the cell sets --fb-split-pos and this rule
 * reads it. Pill labels on either side ("N/12 · new", "M/12 · empty")
 * read attr() values set on the indicator element by the canvas view.
 * ────────────────────────────────────────────────────────────────────────── */
.fb-split-indicator {
    position: absolute;
    top: -2px;
    bottom: -2px;
    left: var(--fb-split-pos, 50%);
    width: 0;
    border-left: 2px dashed var(--cx-gesture);
    pointer-events: none;
    z-index: 6;
}
.fb-split-indicator::before,
.fb-split-indicator::after {
    position: absolute;
    font-family: var(--th-font-mono);
    font-size: 9.5px;
    font-weight: 600;
    color: var(--cx-gesture);
    background: var(--cx-surface);
    border: 1px solid var(--cx-gesture-border);
    border-radius: var(--cx-radius-xs);
    padding: 1px 4px;
    line-height: 1;
    top: -8px;
    white-space: nowrap;
}
.fb-split-indicator::before {
    content: attr(data-source-width) "/12 · new";
    right: calc(100% + 4px);
}
/* Remainder side: just "M/12" — no "· empty" descriptor because the
 * remainder may carry the original cell's content (shrink-and-insert
 * semantic preserves the target's content + ID under the new shorter
 * width). The "new" descriptor on the left already disambiguates which
 * side is the inserted cell. */
.fb-split-indicator::after {
    content: attr(data-remainder-width) "/12";
    left: calc(100% + 4px);
    color: var(--cx-ink-muted);
    border-color: var(--cx-border-dashed);
    background: var(--cx-surface-sunken);
}

/* ──────────────────────────────────────────────────────────────────────────
 * Row-level insert affordance — Target B in canon (drop between cells in a
 * row that still has remaining width). A 3px gesture-purple vertical bar in
 * the inter-cell gap with a gesture-soft halo and an "Insert N/12 here"
 * mono pill above. Absolutely positioned inside the row body.
 * ────────────────────────────────────────────────────────────────────────── */
.fb-row-insert-bar {
    position: absolute;
    top: -4px;
    bottom: -4px;
    width: 3px;
    background: var(--cx-gesture);
    border-radius: 2px;
    left: var(--fb-insert-pos, 50%);
    transform: translateX(-50%);
    pointer-events: none;
    z-index: 6;
    box-shadow: 0 0 0 4px var(--cx-gesture-soft);
}
.fb-row-insert-bar::after {
    content: "Insert " attr(data-source-width) "/12 here";
    position: absolute;
    top: -22px;
    left: 50%;
    transform: translateX(-50%);
    font-family: var(--th-font-mono);
    font-size: 9.5px;
    font-weight: 600;
    color: var(--cx-gesture);
    background: var(--cx-surface);
    border: 1px solid var(--cx-gesture-border);
    border-radius: var(--cx-radius-xs);
    padding: 1px 5px;
    line-height: 1;
    white-space: nowrap;
}

/* ──────────────────────────────────────────────────────────────────────────
 * Row spawn band — Target B at widthSum = 12. Canon spawns a new row above
 * or below depending on which half of the row body the pointer was in;
 * implementation renders TWO bands (one above, one below) as separate
 * hover surfaces — the pointer's position over a band determines the side.
 * Visualised as a 28px gesture-soft band sitting flush above or below the
 * row body, with a dashed gesture-border outline and an inline label.
 *
 * Note: pointer-events stays on (the band IS the DropTarget surface, not
 * a decorative overlay). Canon's `pointer-events: none` would block the
 * hover detection — adapted here to fit the live drop-target wiring.
 * ────────────────────────────────────────────────────────────────────────── */
.fb-row-spawn-band {
    position: absolute;
    left: -22px;
    right: -22px;
    height: 28px;
    background: var(--cx-gesture-soft);
    border: 1.5px dashed var(--cx-gesture-border);
    border-radius: var(--cx-radius-sm);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--cx-gesture);
    font-size: 11px;
    font-weight: 500;
    font-family: var(--th-font-sans);
    z-index: 6;
}
.fb-row-spawn-band.is-above { top: -34px; }
.fb-row-spawn-band.is-below { bottom: -34px; }
.fb-row-spawn-band .glyph {
    margin-right: 6px;
    color: var(--cx-gesture);
    font-family: var(--th-font-mono);
}
/* Lift the band's visual when it's the active hover target so the admin
 * knows which side will commit on release. */
.fb-row-spawn-band[data-drop-active="true"] {
    background: var(--cx-gesture);
    color: var(--cx-surface);
    border-style: solid;
}
.fb-row-spawn-band[data-drop-active="true"] .glyph {
    color: var(--cx-surface);
}

/* ──────────────────────────────────────────────────────────────────────────
 * Row-insert band — action-blue twin of the spawn band for the un-modified
 * (no Alt) row-insert affordances (SectionTop / InterRow / SectionBottom).
 * Replaces the prior 6px flow-positioned bar that pushed content around
 * when the drag started and was hard to hit. Same absolute-positioned
 * overlap pattern as the spawn band — extends into the row's gutter
 * region so the hit zone covers the full visual width. Action-soft fill +
 * action-border dashed outline; hover transitions to solid action color.
 * ────────────────────────────────────────────────────────────────────────── */
.fb-row-insert-band {
    position: absolute;
    left: -22px;
    right: -22px;
    height: 28px;
    background: var(--cx-action-soft);
    border: 1.5px dashed var(--cx-action-border);
    border-radius: var(--cx-radius-sm);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--cx-action);
    font-size: 11px;
    font-weight: 500;
    font-family: var(--th-font-sans);
    z-index: 6;
}
.fb-row-insert-band.is-above { top: -34px; }
.fb-row-insert-band.is-below { bottom: -34px; }

/* In-flow variant for group-inner-row bands. Section-level bands stick out
 * into the row gutter via absolute positioning + negative offsets; group-
 * inner bands live INSIDE the group body and flow in normal layout instead.
 * Visual treatment (bg, border, copy, hover, cap mode) is inherited from
 * the base .fb-row-insert-band rules. */
.fb-row-insert-band--inner {
    position: static;
    left: auto;
    right: auto;
    margin: 4px 0;
}
.fb-row-insert-band--inner.is-above,
.fb-row-insert-band--inner.is-below {
    top: auto;
    bottom: auto;
}
.fb-row-insert-band .glyph {
    margin-right: 6px;
    color: var(--cx-action);
    font-family: var(--th-font-mono);
}
.fb-row-insert-band[data-drop-active="true"] {
    background: var(--cx-action);
    color: var(--cx-surface);
    border-style: solid;
}
.fb-row-insert-band[data-drop-active="true"] .glyph {
    color: var(--cx-surface);
}

/* ──────────────────────────────────────────────────────────────────────────
 * .fb-icon-btn — icon-only utility button atom.
 *
 * Ported from design canon fb.css §667–399. Two densities:
 *   base (22×22) — gutter / card-inline / row-affordance density.
 *                  Hover DEPRESSES (--cx-surface-sunken) — affordance reads
 *                  as pressed into the host surface.
 *   .is-lg (28×28) — panel-header / standalone density. Hover LIFTS
 *                    (--cx-surface-raised) — affordance reads as floating
 *                    above the host. Lift-vs-depress physical metaphor
 *                    (design-system §26).
 *
 * Variants compose: .is-lg + .is-bordered + .is-danger all stack.
 *
 * :disabled / [aria-disabled="true"] applies at the BASE selector so every
 * variant inherits — disabled reads disabled, not danger, not lifted. Hover
 * background is suppressed so a stray pointer doesn't preview an unavailable
 * action.
 *
 * Consumed by _shared/IconButton.razor (header-context use; passes .is-lg).
 * Future consumers (cell delete, row kebab, drawer-row actions) consume
 * the base 22px atom directly when they land.
 * ────────────────────────────────────────────────────────────────────────── */
.fb-icon-btn {
    width: 22px;
    height: 22px;
    color: var(--th-ink-3);
    border: none;
    background: transparent;
    border-radius: 3px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
}
.fb-icon-btn:hover { background: var(--cx-surface-sunken); color: var(--th-ink); }
.fb-icon-btn:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--cx-action-soft-strong);
}
.fb-icon-btn:disabled,
.fb-icon-btn[aria-disabled="true"] {
    color: var(--cx-ink-muted);
    cursor: not-allowed;
}
.fb-icon-btn:disabled:hover,
.fb-icon-btn[aria-disabled="true"]:hover {
    background: transparent;
    color: var(--cx-ink-muted);
}
.fb-icon-btn.is-bordered {
    border: 1px solid var(--cx-border);
    background: var(--cx-surface);
}
.fb-icon-btn.is-danger { color: var(--cx-error); }
.fb-icon-btn.is-danger:hover { background: var(--cx-error-soft); color: var(--cx-error); }

/* .is-lg — 28×28 header/standalone density variant. Per canon v6.2, hover
 * deliberately flips to LIFT (--cx-surface-raised) instead of base's
 * depress; the variant owns the metaphor switch. */
.fb-icon-btn.is-lg {
    width: 28px;
    height: 28px;
}
.fb-icon-btn.is-lg:hover {
    background: var(--cx-surface-raised);
    color: var(--th-ink);
}

/* ──────────────────────────────────────────────────────────────────────────
 * .fb-input — text / number / textarea atom.
 *
 * Ported from design canon fb.css §472–528. Base + variants:
 *   base — flat surface (--cx-surface), reads as "part of the form fabric"
 *          when the input sits against a paper-toned host.
 *   .is-mono — mono font family + slightly smaller (12.5px), for key /
 *              expression / code inputs.
 *   .is-textarea — min-height 60px + resize: vertical.
 *   .is-raised — raised surface (--cx-surface-raised) for inputs that
 *                sit on a SUNKEN substrate (the properties panel uses
 *                --cx-surface-sunken; without .is-raised, base inputs
 *                disappear into the panel).
 *   .is-sm — density variant for popover-context inputs (4px 7px / 12.5px
 *            vs base 6px 9px / 13px). Mirrors the .cc-segmented.is-small /
 *            .cc-btn.is-sm / .cc-pill.is-sm density convention. Composes
 *            with .is-mono (small mono token inputs are real) and .is-raised
 *            (popover inputs may sit on a raised surface). One axis per
 *            suffix (design-system §26 rule 2): .is-sm names density only.
 *   :disabled / [aria-disabled="true"] — disabled treatment overrides the
 *                base/.is-raised surface; disabled reads disabled, not raised.
 *
 * Variants compose: .is-sm + .is-raised + .is-mono + .is-textarea all stack.
 *
 * Consumers: properties-panel bodies (Section/Group/Field/InfoButton/
 * Markdown + Validation bodies + Major/InfoButton type blocks) use
 * .fb-input.is-raised because the panel substrate is sunken. Popover-
 * internal inputs (rule-popover compose, choice-list-picker search +
 * create-name, choice-fork-form, choice-presentation) use .fb-input.is-sm
 * for the denser popover density.
 * ────────────────────────────────────────────────────────────────────────── */
.fb-input {
    width: 100%;
    background: var(--cx-surface);
    border: 1px solid var(--cx-border);
    border-radius: 3px;
    padding: 6px 9px;
    font-size: 13px;
    color: var(--cx-ink);
    font-family: var(--th-f-sans);
    outline: none;
    transition: border-color 100ms, box-shadow 100ms;
}
.fb-input:hover { border-color: var(--cx-border-strong); }
.fb-input:focus {
    border-color: var(--cx-action);
    box-shadow: 0 0 0 3px var(--cx-action-soft-strong);
}
.fb-input.is-mono {
    font-family: var(--th-f-mono);
    font-size: 12.5px;
}
.fb-input.is-textarea {
    min-height: 60px;
    resize: vertical;
}
.fb-input.is-sm {
    padding: 4px 7px;
    font-size: 12.5px;
}
.fb-input:disabled,
.fb-input[aria-disabled="true"] {
    background: var(--cx-surface-disabled);
    color: var(--cx-ink-muted);
    border-color: var(--cx-border);
    cursor: not-allowed;
}
.fb-input:disabled:hover,
.fb-input[aria-disabled="true"]:hover {
    border-color: var(--cx-border);
}
.fb-input.is-raised {
    background: var(--cx-surface-raised);
}

/* ──────────────────────────────────────────────────────────────────────────
 * C5 · fb-stepper — labeled numeric stepper for preference numbers (rows,
 * precision). Bare <input type="number"> stays for constraint numbers
 * (min/max/length bounds); the affordance distinguishes "tune by nudging"
 * from "type a value." Canon: design-references/design_handoff_form_builder/
 * fb.css:593-642 (block lifted verbatim modulo --th-ink-2 → --cx-ink-muted,
 * --th-ink → --cx-ink-strong, --cx-* surface/border passthrough). Canon
 * leaves the disabled state unstyled; the impl extends with a small
 * not-allowed/.55-opacity treatment matching .fb-switch and .fb-icon-btn.
 * ────────────────────────────────────────────────────────────────────────── */
.fb-stepper {
    display: flex;
    align-items: stretch;
    border: 1px solid var(--cx-border);
    border-radius: 3px;
    background: var(--cx-surface);
    overflow: hidden;
}
.fb-stepper > .label {
    padding: 5px 8px;
    font-size: 12px;
    color: var(--cx-ink-muted);
    border-right: 1px solid var(--cx-border-faint);
    display: inline-flex;
    align-items: center;
    flex: none;
    font-family: var(--th-f-sans);
}
.fb-stepper > input {
    border: none;
    outline: none;
    flex: 1;
    background: transparent;
    padding: 0 6px;
    font-family: var(--th-f-mono);
    font-size: 12.5px;
    color: var(--cx-ink-strong);
    min-width: 0;
}
.fb-stepper > .steps {
    display: flex;
    flex-direction: column;
    border-left: 1px solid var(--cx-border-faint);
}
.fb-stepper > .steps > button {
    width: 20px;
    height: 13px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--cx-ink-muted);
    background: transparent;
    border: none;
    cursor: pointer;
}
.fb-stepper > .steps > button:hover {
    background: var(--cx-surface-sunken);
    color: var(--cx-ink-strong);
}
.fb-stepper > .steps > button + button { border-top: 1px solid var(--cx-border-faint); }
.fb-stepper.is-disabled,
.fb-stepper[aria-disabled="true"] {
    background: var(--cx-surface-disabled);
    cursor: not-allowed;
}
.fb-stepper.is-disabled > input,
.fb-stepper[aria-disabled="true"] > input {
    color: var(--cx-ink-muted);
    cursor: not-allowed;
}
.fb-stepper.is-disabled > .steps > button,
.fb-stepper.is-disabled > .steps > button:hover,
.fb-stepper[aria-disabled="true"] > .steps > button,
.fb-stepper[aria-disabled="true"] > .steps > button:hover {
    color: var(--cx-ink-muted);
    cursor: not-allowed;
    background: transparent;
}

/* ────────────────────────────────────────────────────────────────────────────
 * fb depth-cap visualization — data-cx-cap on production drop zones.
 *
 * ADR-0017 / form-domain §4 invariant 6: a GroupContent cannot contain
 * another GroupContent. Spec §5.5 enforces at the gesture layer; design-
 * system §29 owns the visible-rejection treatment.
 *
 * Three modes (one trigger each, set by the gesture layer):
 *   striped   — passive default on every suppressed inner zone during Group drag.
 *   forbidden — single zone under the pointer (escalation). Re-enables
 *               pointer-events so it can detect hover + refuse the drop while
 *               showing not-allowed.
 *   dimmed    — sibling zones recede while one zone is forbidden.
 *
 * Selector shape is element-direct: data-cx-cap rides on each affected
 * .fb-drop-target (per canon Sub-decision A — no descendant chains). Bare
 * [data-cx-cap] is the fallback so the treatment lands on any non-drop-target
 * wrapper that surfaces the attribute.
 * ────────────────────────────────────────────────────────────────────────── */
[data-cx-cap] {
    border-radius: var(--cx-radius-sm);
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 34px;
    transition: background-color 100ms, border-color 100ms;
}
[data-cx-cap="striped"] {
    background: transparent;
    background-image: repeating-linear-gradient(
        45deg,
        color-mix(in oklab, var(--cx-error) 6%, transparent) 0 6px,
        transparent 6px 12px);
    border: 1px dashed var(--cx-error-border);
    color: var(--cx-drop-disabled-ink);
}
[data-cx-cap="dimmed"] {
    background-image: none;
    background: var(--cx-surface-sunken);
    border: 1px dashed var(--cx-border-dashed);
    color: var(--cx-ink-subtle);
    opacity: 0.8;
}
[data-cx-cap="dimmed"] svg { color: var(--cx-ink-subtle); }
[data-cx-cap="forbidden"] {
    cursor: not-allowed;
    background-image: none;
    background: var(--cx-surface-disabled);
    border: 1px solid var(--cx-border);
    color: var(--cx-ink-muted);
}
[data-cx-cap="forbidden"] svg { color: var(--cx-drop-disabled-ink); }
[data-cx-cap="forbidden"]::before {
    content: "⊘";
    margin-right: 6px;
    font-size: 14px;
    color: var(--cx-drop-disabled-ink);
}
/* DropTarget's data-drop-suppressed="true" zeros pointer-events; striped +
 * dimmed are passive and stay inert, but forbidden must catch hover to
 * render the not-allowed cursor and refuse the drop. */
.fb-drop-target[data-cx-cap="striped"],
.fb-drop-target[data-cx-cap="dimmed"] { pointer-events: none; }
.fb-drop-target[data-cx-cap="forbidden"] { pointer-events: auto; }

/* ──────────────────────────────────────────────────────────────────────────
 * Section kebab — the shared four-item section menu (Duplicate / Move up /
 * Move down / Delete) per spec §5.9 + recon §1.4. Ported from canon
 * fb.css's .fb-section-kebab block (chrome.jsx SectionKebab / SectionKebabMenu)
 * with the --th-* placeholders mapped to the form-builder's --cx-* layer.
 *
 * Lives in the global sheet (not scoped) for two reasons:
 *   - the tab-strip hover-reveal keys off the .fb-section-tab wrapper (in
 *     SectionTab) but reveals the trigger (in SectionKebab) — a cross-component
 *     relationship scoped CSS can't express;
 *   - the menu panel is portal-rendered into the PopoverLayer at app root via
 *     RulesEditorPopover, so its chrome can't be component-scoped. Root-scoped
 *     --cx-* tokens resolve there fine.
 *
 * Two placements: .is-sm (section-tab strip, fades in on tab hover) and
 * .is-bordered (Versions drawer section row, always-visible chip).
 * ────────────────────────────────────────────────────────────────────────── */
.fb-section-kebab {
    flex: 0 0 auto;
    width: 22px;
    margin: 8px 4px 8px -4px;
    padding: 0;
    color: var(--cx-ink-subtle);
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--cx-radius-xs);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: opacity 100ms, background 100ms, color 100ms;
}
.fb-section-kebab.is-sm { margin: 8px 2px 8px -2px; height: auto; }
.fb-section-kebab.is-bordered {
    width: 24px;
    height: 24px;
    margin: 0;
    border-color: var(--cx-border);
    background: var(--cx-surface);
    color: var(--cx-ink-muted);
}
.fb-section-kebab.is-bordered:hover,
.fb-section-kebab.is-bordered.is-open {
    background: var(--cx-surface-sunken);
    color: var(--cx-ink);
}

/* Tab-strip: the kebab fades in on tab-shell hover. The drawer-row variant
   (.is-bordered, not inside .fb-section-tab) is left always-visible. */
.fb-section-tab .fb-section-kebab { opacity: 0; }
.fb-section-tab:hover .fb-section-kebab,
.fb-section-tab .fb-section-kebab.is-open,
.fb-section-tab .fb-section-kebab:focus-visible { opacity: 1; }

.fb-section-kebab:hover,
.fb-section-kebab.is-open {
    color: var(--cx-ink-strong);
    background: var(--cx-surface-sunken);
}
.fb-section-kebab:focus-visible {
    opacity: 1;
    outline: none;
    box-shadow: 0 0 0 2px var(--cx-action-soft-strong);
}

/* Floating menu panel (portal). Positioning + the click-away scrim are owned by
   RulesEditorPopover; this is the panel chrome only. */
.fb-section-kebab-menu {
    min-width: 220px;
    padding: 4px;
    background: var(--cx-surface);
    border: 1px solid var(--cx-border);
    border-radius: var(--cx-radius-md);
    box-shadow: var(--cx-shadow-popover);
    font-family: var(--cx-font);
    display: flex;
    flex-direction: column;
    gap: 1px;
}
.fb-section-kebab-item {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 8px 6px 7px;
    border: none;
    background: transparent;
    border-radius: var(--cx-radius-sm);
    cursor: pointer;
    text-align: left;
    color: var(--cx-ink-strong);
    font-size: 12.5px;
}
.fb-section-kebab-item:hover { background: var(--cx-action-soft); }
.fb-section-kebab-item.is-disabled,
.fb-section-kebab-item:disabled {
    color: var(--cx-ink-faint);
    cursor: not-allowed;
}
.fb-section-kebab-item.is-disabled:hover,
.fb-section-kebab-item:disabled:hover { background: transparent; }
.fb-section-kebab-item.is-danger { color: var(--cx-error); }
.fb-section-kebab-item.is-danger:hover { background: var(--cx-error-soft); }
.fb-section-kebab-ico {
    width: 16px;
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: currentColor;
    opacity: 0.75;
}
.fb-section-kebab-label {
    flex: 1;
    font-weight: 500;
    white-space: nowrap;
}
.fb-section-kebab-hint {
    font-family: var(--cx-font-mono);
    font-size: 10px;
    color: var(--cx-ink-faint);
    letter-spacing: 0.01em;
    white-space: nowrap;
}
.fb-section-kebab-kbd {
    font-family: var(--cx-font-mono);
    font-size: 10px;
    color: var(--cx-ink-muted);
    background: var(--cx-surface-sunken);
    border: 1px solid var(--cx-border);
    border-radius: 2px;
    padding: 0 4px;
    white-space: nowrap;
}
.fb-section-kebab-divider {
    height: 1px;
    background: var(--cx-border-faint);
    margin: 3px 4px;
}
