/* ==========================================================================
   Watchlist rail - content + interaction layer (loaded right after
   style.css). style.css keeps the SHELL mechanics its regression tests
   pin: fixed position, collapse transform, resize handles, tab strip,
   toggle offset, the 1280px content push. This file layers what the rail
   says and how it behaves on top of that.
   ========================================================================== */

/* ---- collapsed tab: says what it is ----------------------------------
   A bare 28px chevron was all that was left of a collapsed watchlist -
   easy to forget it exists at all. Collapsed, the tab now reads
   WATCHLIST down the screen edge with the follow count under it; open,
   it goes back to a plain chevron (the header already says the rest). */
.watchlist-rail-toggle-label,
.watchlist-rail-toggle-count {
    display: none;
}
.watchlist-rail.is-collapsed .watchlist-rail-toggle {
    flex-direction: column;
    gap: 0.45rem;
    height: auto;
    padding: 0.6rem 0 0.7rem;
}
.watchlist-rail.is-collapsed .watchlist-rail-toggle-label {
    display: block;
    writing-mode: vertical-rl;
    font-size: 9px;
    font-weight: 800;
    letter-spacing: 0.24em;
    text-transform: uppercase;
    color: var(--color-slate-400, #94a3b8);
    transition: color 0.15s ease;
}
.watchlist-rail.is-collapsed .watchlist-rail-toggle:hover .watchlist-rail-toggle-label,
.watchlist-rail.is-collapsed .watchlist-rail-toggle:focus-visible .watchlist-rail-toggle-label {
    color: var(--color-accent);
}
.watchlist-rail.is-collapsed .watchlist-rail-toggle-count:not([hidden]) {
    display: grid;
    place-items: center;
    min-width: 1.15rem;
    height: 1.15rem;
    padding: 0 0.25rem;
    border-radius: 9999px;
    font: 800 9px/1 "JetBrains Mono", ui-monospace, monospace;
    color: var(--color-base);
    background: var(--color-accent);
}

/* ---- drawer mode (below 1280px) ----------------------------------------
   The open rail is a modal drawer there (watchlist_rail.js inerts the
   page and moves focus in), so it has to sit above everything it covers:
   the horizon dock (z 25) and the tour's "?" button (z 45) both used to
   draw on top of it. The scrim dims the page and closes on tap. */
.watchlist-rail-content {
    overscroll-behavior: contain; /* a swipe at the list's end can't scroll the page behind */
}
.watchlist-rail-scrim {
    position: fixed;
    inset: 0;
    z-index: 47;
    background: rgba(4, 6, 10, 0.6);
    -webkit-backdrop-filter: blur(2px);
    backdrop-filter: blur(2px);
}
@media (max-width: 1279.98px) {
    .watchlist-rail {
        z-index: 48;
    }
    .watchlist-rail.is-drawer {
        box-shadow: -20px 0 48px rgba(0, 0, 0, 0.55);
    }
}
@media (prefers-reduced-motion: no-preference) {
    .watchlist-rail-scrim:not([hidden]) {
        animation: rail-scrim-in 0.25s ease both;
    }
}
@keyframes rail-scrim-in {
    from { opacity: 0; }
}

/* ---- the tour's "?" button steps aside for the open panel ---------------
   It's fixed bottom-right above the rail (module_intro.css), so on wide
   screens it sat on top of the quick look. Same --rail-width the page
   push uses, so it tracks a drag-resize too. */
@media (min-width: 1280px) {
    .module-intro-replay {
        transition: right 0.25s ease;
    }
    body.watchlist-rail-open .module-intro-replay {
        right: calc(var(--rail-width, 260px) + 1.1rem);
    }
    body.watchlist-rail-resizing .module-intro-replay {
        transition: none;
    }
}

@media print {
    .watchlist-rail-scrim {
        display: none;
    }
}

/* ---- the rail's horizon accent ---------------------------------------------
   base.html keeps data-horizon current (server-rendered, then the horizon
   switcher), so every accent below re-themes along with the page. */
.watchlist-rail { --rail-hz: var(--color-horizon-swing); }
.watchlist-rail[data-horizon="day"] { --rail-hz: var(--color-horizon-day); }
.watchlist-rail[data-horizon="invest"] { --rail-hz: var(--color-horizon-invest); }

/* "Manage" sits beside the add-ticker box - the two list-management
   actions together - which also leaves the header (title + horizon) on
   one line at every rail width. */
#watchlist-rail-add-form {
    display: flex;
    align-items: center;
    gap: 0.4rem;
}
#watchlist-rail-add-input {
    flex: 1 1 0; /* basis 0, not its w-full 100%: the form wraps (for the status line), the box must not */
    min-width: 0;
}
.watchlist-rail-manage {
    flex: none;
    display: inline-grid;
    place-items: center;
    width: 1.9rem;
    height: 1.9rem;
    border: 1px solid var(--color-border);
    border-radius: 0.375rem;
    color: var(--color-slate-500, #64748b);
    transition: color 0.15s ease, background-color 0.15s ease, border-color 0.15s ease;
}
.watchlist-rail-manage:hover,
.watchlist-rail-manage:focus-visible {
    color: var(--color-accent);
    border-color: color-mix(in srgb, var(--color-accent) 40%, transparent);
    background: color-mix(in srgb, var(--color-accent) 10%, transparent);
}

/* ---- rows: nothing collides at the default 260px ----------------------------
   One button per row on a two-line grid - BullYeah's read on the left
   (symbol + score + its move | the Alignment label), the market's day on
   the right (price | change) - with the follow star (and, on Favorites,
   the drag handle) beside it. The sparkline is a faint landscape behind
   the row (rail_sparkline.py) that fades out under the symbol. */
.rail-row {
    position: relative;
    isolation: isolate;
    display: flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.55rem 0.75rem 0.55rem 0.55rem;
    border-bottom: 1px solid var(--color-border);
    transition: background-color 0.15s ease, box-shadow 0.15s ease;
}
.rail-row:hover {
    background: rgba(255, 255, 255, 0.025);
}
.rail-row.is-selected {
    background: color-mix(in srgb, var(--rail-hz) 9%, transparent);
    box-shadow: inset 2px 0 0 var(--rail-hz);
}
.rail-row-spark {
    --spark: var(--color-bull);
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    z-index: -1;
    pointer-events: none;
    -webkit-mask-image: linear-gradient(90deg, transparent 8%, #000 55%);
    mask-image: linear-gradient(90deg, transparent 8%, #000 55%);
}
.rail-row.is-down .rail-row-spark { --spark: var(--color-bear); }
.rail-row-spark-area { fill: var(--spark); opacity: 0.07; }
.rail-row-spark-line {
    fill: none;
    stroke: var(--spark);
    stroke-width: 1.25px;
    opacity: 0.3;
    vector-effect: non-scaling-stroke;
}
.rail-row .drag-handle,
.rail-row-star {
    flex: none;
}
.rail-row .drag-handle {
    color: var(--color-slate-600, #475569);
    cursor: grab;
}
/* A mouse finds the grip on hover; at rest, six grips in a column were just
   texture - and the width they held is the Alignment label's. Touch (no
   hover) keeps them as they were, with style.css's roomy touch padding.
   Here the grip sheds its sideways padding (keeping its height to grab)
   and the row its left gutter, but stays in the flow: an absolutely
   positioned grip made Chromium hit-test the list ABOVE other rows once
   the quick look resized it - clicks on them went nowhere. */
@media (hover: hover) and (pointer: fine) {
    .rail-row:has(.drag-handle) {
        padding-left: 0.15rem;
    }
    .rail-row .drag-handle {
        padding-inline: 0.05rem;
        opacity: 0;
        transition: opacity 0.15s ease;
    }
    .rail-row .drag-handle svg {
        width: 10px;
        height: 10px;
    }
    .rail-row:hover .drag-handle,
    .rail-row:focus-within .drag-handle {
        opacity: 1;
    }
}
/* Touch keeps the roomy grip - its spacing from the star is what clears
   WCAG 2.2's 24px target-spacing bar - but the grip's own left padding is
   gutter enough: the row's would only push the label into an ellipsis. */
@media (hover: none), (pointer: coarse) {
    .rail-row:has(.drag-handle) {
        padding-left: 0.15rem;
    }
}
.rail-row-btn {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    row-gap: 0.35rem;
    padding: 0.1rem 0;
    text-align: left;
    color: inherit;
    background: none;
    border: 0;
    border-radius: 0.375rem;
    cursor: pointer;
    /* A map-label halo: the landscape behind the row never cuts a digit. */
    text-shadow: 0 0 3px var(--color-panel), 0 0 7px var(--color-panel);
}
.rail-row-btn:focus-visible {
    outline: 2px solid var(--color-accent);
    outline-offset: 2px;
}
/* Two lines - symbol and score over the price, the label over the day's
   change - each sizing its own right-hand figure. A grid column shared
   with the price gave the label only what the (wider) price left: in the
   live site's Inter, "Great Company, Bad Entry" lost its last letters. */
.rail-row-line {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-width: 0;
}
.rail-row-id {
    flex: 1 1 0;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    column-gap: 0.3rem; /* the move sits beside its score; in Inter it fits whole at 240px */
    min-width: 0;
    /* One line, exactly the score badge's height (its text-xs line 1rem +
       py-1's 0.25rem + the underline's 0.45rem): the delta, when it doesn't
       fit, wraps out of sight WHOLE - never a clipped "up 2" of "up 27.4". */
    height: 1.7rem;
    overflow: hidden;
}
/* Symbol + score never part: the pair shrinks as one (the symbol's
   ellipsis takes it), so the score can't wrap away - only the delta can.
   Order of sacrifice on a cramped crypto row: the delta, then the
   symbol's tail; never the score. */
.rail-row-core {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    flex: 0 1 auto;
    min-width: 0;
}
.rail-row-symbol {
    /* 4ch of a monospace: AMD's score lines up under AAPL's, so scores read
       down the list as a column. Longer symbols extend; a cramped crypto
       row can still ellipsize down to this. */
    min-width: 4ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font: 700 0.875rem/1.2 "JetBrains Mono", ui-monospace, monospace;
    letter-spacing: 0.01em;
    color: #e2e8f0;
}
.rail-row-price,
.rail-row-change {
    flex: none;
    margin-left: auto;
    white-space: nowrap;
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}
.rail-row-price { font-size: 0.8125rem; line-height: 1.2; color: #e2e8f0; }
.rail-row-change { font-size: 10px; line-height: 1; }
/* The score's move since its last record (rm.rail_delta): quiet ink, only
   the arrow in the direction's colour. */
.rail-delta {
    flex: none;
    font: 600 10px/1 "JetBrains Mono", ui-monospace, monospace;
    font-variant-numeric: tabular-nums;
    color: var(--color-slate-400, #94a3b8);
    white-space: nowrap;
}
.rail-delta i { font-style: normal; margin-right: 1px; }
.rail-delta.is-up i { color: var(--color-bull); }
.rail-delta.is-down i { color: var(--color-bear); }
.rail-row-story {
    flex: 1 1 0;
    display: flex;
    align-items: center;
    gap: 0.35rem;
    min-width: 0;
}
.rail-row-story > * { flex: none; }
/* The shared alignment badge is inline-flex, where an ellipsis can't show;
   inline-block lets a long label end in "..." instead of being clipped.
   A touch less side padding than the shared pill: in Inter, "Great Company,
   Bad Entry" fits at the default width with room to spare; a wider
   fallback font (DejaVu, before Inter arrives) ends it in "...". */
.rail-row-story .rail-row-alignment {
    display: inline-block;
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    padding-inline: 0.375rem;
}

/* The score badge's horizon underline (rm.rail_score): Day, Swing, Invest. */
.rail-score {
    position: relative;
    flex: none;
    padding-bottom: 0.45rem;
}
.rail-score-horizons {
    position: absolute;
    left: 0.45rem;
    right: 0.45rem;
    bottom: 0.2rem;
    height: 3px;
    display: flex;
    align-items: flex-end;
    gap: 2px;
}
.rail-score-seg {
    flex: 1;
    height: 2px;
    border-radius: 1px;
    background: var(--color-slate-600, #475569);
    opacity: 0.55;
}
.rail-score-seg.is-bull { background: var(--color-bull); }
.rail-score-seg.is-neutral { background: var(--color-neutral-score); }
.rail-score-seg.is-bear { background: var(--color-bear); }
.rail-score-seg.is-active { height: 3px; opacity: 1; }

/* ---- quick look: closed until a row is chosen ------------------------------
   The list gets the whole rail until then; the panel (and its resize
   edge) only takes room while it has something to show. */
.watchlist-rail-detail {
    transition: flex-basis 0.28s cubic-bezier(0.2, 0.8, 0.2, 1);
}
.watchlist-rail:not(.has-look) .watchlist-rail-detail {
    flex-basis: 0;
    min-height: 0;
    overflow: hidden;
    visibility: hidden;
    transition: flex-basis 0.22s ease, visibility 0s linear 0.22s;
}
.watchlist-rail:not(.has-look) .watchlist-rail-detail-resize-handle {
    display: none;
}
.watchlist-rail.has-look .watchlist-rail-detail-resize-handle {
    border-top-color: color-mix(in srgb, var(--rail-hz) 55%, var(--color-border));
}
.watchlist-rail-detail:focus {
    outline: none;
}
.watchlist-rail-detail:focus-visible {
    box-shadow: inset 0 2px 0 var(--color-accent);
}
.rail-look {
    display: grid;
    grid-template-columns: minmax(0, 1fr); /* never wider than the panel, whatever a child's nowrap content says */
    gap: 0.7rem;
    padding: 0.75rem 0.9rem 1rem;
}
.rail-look-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 0.5rem;
}
.rail-look-title {
    display: flex;
    flex-direction: column;
    min-width: 0;
    margin: 0;
}
.rail-look-symbol {
    font: 800 1.05rem/1.15 "JetBrains Mono", ui-monospace, monospace;
    letter-spacing: 0.02em;
    color: #f1f5f9;
}
.rail-look-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 11px;
    color: var(--color-slate-500, #64748b);
}
.rail-look-close {
    flex: none;
    display: grid;
    place-items: center;
    width: 1.75rem;
    height: 1.75rem;
    border-radius: 0.5rem;
    color: var(--color-slate-500, #64748b);
    transition: color 0.15s ease, background-color 0.15s ease;
}
.rail-look-close:hover,
.rail-look-close:focus-visible {
    color: #e2e8f0;
    background: rgba(255, 255, 255, 0.06);
}
.rail-look-actions {
    display: flex;
    align-items: center;
    gap: 0.4rem;
}
.rail-look-analyze {
    flex: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.35rem;
    padding: 0.45rem 0.75rem;
    border-radius: 0.6rem;
    font-size: 12px;
    font-weight: 700;
    color: var(--color-base);
    background: var(--color-accent);
    transition: filter 0.15s ease;
}
.rail-look-analyze:hover { filter: brightness(1.08); }
.rail-look-analyze:focus-visible {
    outline: 2px solid #f8fafc;
    outline-offset: 2px;
}
.rail-look-actions .rail-row-alert-btn {
    width: 2rem;
    height: 2rem;
    border: 1px solid var(--color-border);
    border-radius: 0.6rem;
}
.rail-look-quote {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    margin: 0;
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-variant-numeric: tabular-nums;
}
.rail-look-price { font-size: 1.25rem; font-weight: 700; }
.rail-look-change { font-size: 11px; }
/* The Analyze page's three horizon cards in miniature: label in the
   horizon's own colour, score in its zone colour, active one lit. */
.rail-look-horizons {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0.4rem;
    margin: 0;
    padding: 0;
    list-style: none;
}
.rail-look-tile {
    --hz: var(--color-horizon-swing);
    display: grid;
    justify-items: center;
    gap: 0.2rem;
    padding: 0.45rem 0.25rem 0.5rem;
    border-radius: 0.6rem;
    border: 1px solid color-mix(in srgb, var(--hz) 32%, transparent);
    background: color-mix(in srgb, var(--hz) 5%, var(--color-base));
}
.rail-look-tile.is-day { --hz: var(--color-horizon-day); }
.rail-look-tile.is-invest { --hz: var(--color-horizon-invest); }
.rail-look-tile.is-active {
    border-color: var(--hz);
    background: color-mix(in srgb, var(--hz) 12%, var(--color-base));
    box-shadow: 0 0 14px -4px color-mix(in srgb, var(--hz) 65%, transparent);
}
.rail-look-tile-label {
    font-size: 9px;
    font-weight: 800;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--hz);
}
.rail-look-tile-score {
    font: 800 1.15rem/1 "JetBrains Mono", ui-monospace, monospace;
    font-variant-numeric: tabular-nums;
}
.rail-look-story {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem;
    margin: 0;
}
.rail-look-since {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    font-size: 10px;
    color: var(--color-slate-500, #64748b);
}
.rail-look-desc {
    margin: 0;
    font-size: 11px;
    line-height: 1.45;
    color: var(--color-slate-400, #94a3b8);
}
.rail-look-stats {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.3rem 0.75rem;
    margin: 0;
    padding: 0.6rem 0.7rem;
    border-radius: 0.6rem;
    border: 1px solid var(--color-border);
    background: var(--color-panel);
    color: #e2e8f0; /* inherited, so .text-bull/.text-bear on a value still win */
}
.rail-look-stats > div {
    display: flex;
    justify-content: space-between;
    gap: 0.4rem;
    min-width: 0;
}
.rail-look-stat-wide { grid-column: 1 / -1; }
.rail-look-stats dt {
    font-size: 10px;
    color: var(--color-slate-500, #64748b);
}
.rail-look-stats dd {
    margin: 0;
    white-space: nowrap;
    font: 600 11px/1.3 "JetBrains Mono", ui-monospace, monospace;
    font-variant-numeric: tabular-nums;
}
.rail-look .rail-detail-chart {
    max-width: 100%; /* Chart.js sizes it to the panel; never the canvas default 300px */
}

@media (prefers-reduced-motion: reduce) {
    .watchlist-rail-detail,
    .watchlist-rail:not(.has-look) .watchlist-rail-detail {
        transition: none;
    }
}

/* ---- quick-add says what happened (watchlist_rail_rows.js) ------------------ */
#watchlist-rail-add-form {
    flex-wrap: wrap;
}
.watchlist-rail-add-status {
    flex: 1 0 100%;
    margin: 0;
    font-size: 11px;
    line-height: 1.35;
    color: var(--color-slate-400, #94a3b8);
}
.watchlist-rail-add-status[data-tone="ok"] { color: var(--color-bull); }
.watchlist-rail-add-status[data-tone="error"] { color: var(--color-bear); }
#watchlist-rail-add-input[aria-busy="true"] {
    opacity: 0.7;
    cursor: progress;
}

/* The row of the symbol open in Analyze right now. */
.rail-row-viewing {
    display: none;
    flex: none;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--color-accent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-accent) 22%, transparent);
}
.rail-row.is-viewing .rail-row-viewing {
    display: inline-block;
}
