@layer infine.components {
/* Status dots in product list */
.connect-status-dot {
    display: inline-block;
    width: 12px;
    height: 12px;
    border-radius: 6px;
    flex-shrink: 0;
}

.connect-status-dot--complete    { background-color: var(--infine-green-bright); }
.connect-status-dot--in-progress { background-color: var(--infine-yellow-bright); }

/* Status badge / pill */
.connect-status-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 2px 10px;
    border-radius: 12px;
    font-size: 12px;
    font-weight: 600;
}

.connect-status-pill--complete {
    color: var(--infine-green-dark-strong);
    background-color: var(--infine-green-bg);
}

.connect-status-pill--in-progress {
    color: var(--infine-yellow-strong);
    background-color: var(--infine-yellow-bg);
}

/* Product list (left column on Single view) — sticky so the list stays
   in view as the user scrolls the form; max-height reserves room for the
   fixed autosave bar (44px) plus a small breathing gap above and below. */
.connect-product-list {
    position: sticky;
    top: var(--mantine-spacing-md);
    max-height: calc(100vh - var(--mantine-spacing-md) - 44px - var(--mantine-spacing-md));
    border: 1px solid var(--mantine-color-gray-3);
    border-radius: 6px;
    background: white;
    overflow: hidden;
    display: flex;
    flex-direction: column;
}

/* Full list content. Width is pinned to the expanded column width so that
   while the column animates closed the content clips against the container's
   `overflow: hidden` rather than reflowing (which would squash the search
   field and chips mid-animation). It cross-fades with the rail. */
.connect-product-list__full {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
    width: 280px;
    opacity: 1;
    transition: opacity 200ms ease;
}

@media (max-width: 1280px) {
    .connect-product-list__full { width: 240px; }
}

.connect-product-list.is-collapsed .connect-product-list__full {
    opacity: 0;
    pointer-events: none;
}

.connect-product-list-header {
    padding: var(--mantine-spacing-sm);
    border-bottom: 1px solid var(--mantine-color-gray-2);
    background: var(--infine-blue-bg);
    display: flex;
    flex-direction: column;
    gap: var(--mantine-spacing-xs);
}

/* Title row of the header — product count on the left, collapse control on
   the right. */
.connect-product-list-header__top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--mantine-spacing-xs);
}

/* Collapse control — a filled, borderless caret chip so it reads as clickable
   at rest (a bare icon is easy to miss). It sits on the header's
   `--infine-blue-bg` background, so its resting fill is one step up
   (`--infine-blue-light-fade`) to stay visible against it; the rail's expand
   caret uses the lighter fill because it sits on white. Mirrors the rail
   caret's hover nudge, pointed at the edge it collapses toward. */
.connect-product-list__collapse {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    margin: -2px -2px -2px 0;
    padding: 0;
    border: 0;
    border-radius: 8px;
    background: var(--infine-blue-light-fade);
    color: var(--infine-blue);
    cursor: pointer;
    transition: background-color 160ms ease, transform 160ms ease;
}

.connect-product-list__collapse:hover {
    background: var(--infine-blue-light);
    transform: translateX(-2px);
}

.connect-product-list__collapse:focus-visible {
    outline: 2px solid var(--infine-blue);
    outline-offset: 2px;
}

.connect-product-list-scroll {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
}

/* Collapsed rail — a full-height button overlaying the (hidden) list, so the
   whole strip is one large, obvious target for restoring the list. A
   right-pointing double-caret sits at the top (mirroring where the collapse
   control lived) and a vertical product count is centred down the rail. */
.connect-product-list__rail {
    position: absolute;
    inset: 0;
    z-index: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 12px 0;
    border: 0;
    background: transparent;
    cursor: pointer;
    opacity: 0;
    pointer-events: none;
    font-family: var(--mantine-font-family);
    transition: opacity 240ms ease, background-color 160ms ease;
}

.connect-product-list.is-collapsed .connect-product-list__rail {
    opacity: 1;
    pointer-events: auto;
}

.connect-product-list__rail:hover {
    background: var(--infine-blue-bg);
}

.connect-product-list__rail:focus-visible {
    outline: 2px solid var(--infine-blue);
    outline-offset: -2px;
    border-radius: 6px;
}

/* Rail expand caret — same filled caret-chip look and hover treatment as the
   collapse control (rest `--infine-blue-light-fade` → hover `--infine-blue-light`)
   so the button reads identically in both directions. Only the trigger differs:
   here the whole rail drives the hover (rule below), there it's the button. */
.connect-product-list__rail-caret {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 38px;
    height: 38px;
    border-radius: 9px;
    background: var(--infine-blue-light-fade);
    color: var(--infine-blue);
    transition: background-color 160ms ease, transform 160ms ease;
}

.connect-product-list__rail:hover .connect-product-list__rail-caret {
    background: var(--infine-blue-light);
    transform: translateX(2px);
}

/* Vertical product-count label, centred in the space below the caret via
   flex auto-margins (works regardless of the label's own writing-mode). */
.connect-product-list__rail-label {
    flex: 0 0 auto;
    margin: auto 0;
    writing-mode: vertical-rl;
    transform: rotate(180deg);
    text-transform: uppercase;
    letter-spacing: 0.12em;
    font-size: 11px;
    font-weight: 600;
    color: var(--mantine-color-gray-6);
    white-space: nowrap;
    transition: color 160ms ease;
}

.connect-product-list__rail:hover .connect-product-list__rail-label {
    color: var(--infine-blue);
}

.connect-product-row {
    display: flex;
    flex-direction: row;
    align-items: stretch;
    gap: var(--mantine-spacing-xs);
    padding: 10px var(--mantine-spacing-sm);
    border-bottom: 1px solid var(--mantine-color-gray-1);
    cursor: pointer;
    transition: background-color 0.1s ease;
}

.connect-product-row:hover {
    background-color: var(--infine-blue-bg);
}

.connect-product-row--active {
    background-color: var(--infine-blue-light-fade);
}

/* Vertical completeness chip pinned against the row's left edge. Sized to
   the height of the title row only (not the full row) — reads as a
   typographic accent next to the name rather than a row-spanning bar.
   Track is a thin gray rail; the fill grows from the bottom (thermometer-
   style) carrying the row's status colour. */
.connect-product-row__chip {
    flex: 0 0 auto;
    width: 4px;
    height: 18px;
    align-self: flex-start;
    background: var(--mantine-color-gray-2);
    border-radius: 2px;
    position: relative;
    overflow: hidden;
}

.connect-product-row__chip-fill {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    border-radius: 2px;
    transition: height 240ms cubic-bezier(0.22, 1, 0.36, 1),
                background-color 240ms ease;
}

.connect-product-row__content {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

/* Title row — product name on the left, error badge (when present) on the
   right. Space-between keeps the badge anchored without an explicit margin. */
.connect-product-row__title {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--mantine-spacing-xs);
}

/* Trailing aside on the title row — holds the optional status/recency pill and
   the error badge together, right-aligned, so name stays anchored left. */
.connect-product-row__title-aside {
    display: flex;
    align-items: center;
    gap: 6px;
    flex: 0 0 auto;
}

/* The "N left" / "x days ago" tag next to the name in the Overview attention
   lists is now a Mantine Badge (radius "sm", variant "light") — see
   ui/product_row.cljs. No bespoke CSS needed here. */

.connect-product-row .name {
    font-size: var(--mantine-font-size-sm);
    font-weight: 600;
    color: var(--infine-blue);
    line-height: 18px;
}

/* Meta row — pct + GTIN. Visible at rest in a quiet gray so the row reads
   as a complete two-line entry; darkens slightly on hover for legibility
   when the user is looking. The vertical chip carries the status colour
   at rest, so this row is pure reference data. */
.connect-product-row__meta {
    display: flex;
    align-items: center;
    gap: var(--mantine-spacing-xs);
    color: var(--mantine-color-gray-5);
    transition: color 0.18s ease;
}

.connect-product-row:hover .connect-product-row__meta {
    color: var(--mantine-color-gray-7);
}

/* GTIN rides on the right edge of the meta row — quiet, technical, a
   secondary identifier next to the leading percentage. */
.connect-product-row .gtin {
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 11px;
    color: inherit;
    flex: 0 0 auto;
    margin-left: auto;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.connect-product-row__pct {
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 11px;
    font-weight: normal;
    line-height: 1;
    color: inherit;
    flex-shrink: 0;
    min-width: 30px;
    text-align: left;
    font-variant-numeric: tabular-nums;
}

/* Rail fade when the user's attention is anywhere but the rail. Triggers:
   1. Mouse hover anywhere in the single-view grid that isn't the rail itself.
      Matches the whole grid box (including the gap between form and
      marginalia columns), so the rail doesn't briefly wake when the cursor
      crosses the gutter on the way from one column to the other.
   2. Recent keyboard activity in the form — `data-form-keyboard-active`
      attribute set + decay-cleared by an effect in the SingleView. Covers
      keyboard-only workflows so the rail still steps back during typing.
   3. Any Mantine popover dropdown (Select / MultiSelect / DatePicker / etc.)
      is open anywhere on the page — those render into a portal at body level,
      so the user mousing into the dropdown panel takes the cursor off the
      form-column and would otherwise wake the rail mid-pick. Closed dropdowns
      stay in the DOM with `display: none` inline, so the `:not([style*=…])`
      filter narrows the match to the one currently open.
   Rail hover always wins (the user explicitly reached for the rail).

   The faded state also goes grayscale: the chip colours, error badges, and
   filter chips lose their hue so no colour information competes with the
   form. The rail restores to full colour the moment the user hovers it.

   Both directions are slow and calm — fading *out* (the form takes the
   user's attention) over 1.18s with a plain ease, coming *back* over 1.2s
   with an ease-out curve. They're near-symmetric in duration but differ in
   feel: the gentle ease-out on the return resolves a touch more decisively
   without ever snapping. The two are kept as separate rules so each
   direction's timing/curve can be tuned independently. CSS encodes this by
   timing: a transition lives on the state being
   transitioned *to*. The base rule below is the un-faded state (the target
   when the triggers release) → it carries the return timing; the
   faded-state rule is the target when a trigger engages → it carries the
   fade-out timing. `--list-faded-*` are vars so the collapsed rail can opt out
   entirely (set to 1/none under `.is-collapsed` below — the rail is the only
   way back to switching products, so it must never recede; it keeps its own
   hover effect instead). */
.connect-product-list {
    --list-faded-opacity: 0.3;
    --list-faded-filter: grayscale(1);
    transition: opacity 1.2s cubic-bezier(0.22, 1, 0.36, 1),
                filter 1.2s cubic-bezier(0.22, 1, 0.36, 1);
}

.connect-product-list.is-collapsed {
    --list-faded-opacity: 1;
    --list-faded-filter: none;
}

.connect-single-grid:hover .connect-product-list:not(:hover),
.connect-single-grid[data-form-keyboard-active="true"] .connect-product-list:not(:hover),
body:has(.mantine-Popover-dropdown:not([style*="display: none"])) .connect-single-grid .connect-product-list:not(:hover) {
    opacity: var(--list-faded-opacity);
    filter: var(--list-faded-filter);
    transition: opacity 1.18s ease, filter 1.18s ease;
}

/* Honour reduced-motion: collapse/expand and the rail fade should resolve
   without the long, eye-catching tweens. */
@media (prefers-reduced-motion: reduce) {
    .connect-single-grid,
    .connect-product-list,
    .connect-product-list__full,
    .connect-product-list__rail,
    .connect-single-grid:hover .connect-product-list:not(:hover),
    .connect-single-grid[data-form-keyboard-active="true"] .connect-product-list:not(:hover),
    body:has(.mantine-Popover-dropdown:not([style*="display: none"])) .connect-single-grid .connect-product-list:not(:hover) {
        transition-duration: 0.01ms;
    }
}

}
