/* Watchlist page (views/watchlist.js, task T17) — master/detail layout.
 *
 * Everything the shared sheets already paint stays there: .panel, .btn,
 * .badge, .pill, .tabs/.tab, .check, .switch, .empty-note, .form-error,
 * .form-ok, .num, .muted, .small, .pos/.neg, table.data. This file only adds
 * the page's own layout and row anatomy. Every colour and every length that
 * matches a token comes from tokens.css custom properties — no colour literal
 * of any form lives here (transparent, currentColor and inherit are allowed).
 * The 400 px master column is the approved design width; no token carries it.
 */

/* ---- page grid: 400 px master + detail ---------------------------------- */

.watchlist-page {
  display: grid;
  grid-template-columns: 400px minmax(0, 1fr);
  gap: var(--space-5);
  align-items: start;
}

@media (max-width: 980px) {
  .watchlist-page {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* ---- master list --------------------------------------------------------- */

.wl2-master {
  position: sticky;
  top: var(--space-3);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

@media (max-width: 980px) {
  .wl2-master {
    position: static;
  }
}

.wl2-master .view-head {
  margin-bottom: var(--space-1);
}

.wl2-count {
  min-height: var(--fs-label);
}

.wl2-add-form {
  display: flex;
  gap: var(--space-2);
  align-items: center;
}

.wl2-add-input {
  flex: 1;
  min-width: 0;
  background: var(--panel-2);
  border: 1px solid var(--panel-border);
  border-radius: var(--radius-sm);
  color: var(--ink);
  font: inherit;
  font-size: var(--fs-small);
  padding: var(--space-1) var(--space-2);
  text-transform: uppercase;
}

.wl2-add-input:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 0;
}

.wl2-add-error .form-error,
.wl2-action-error .form-error {
  min-height: 0;
}

.wl2-rows {
  display: flex;
  flex-direction: column;
  border-top: 1px solid var(--panel-border);
}

.wl2-rows[hidden] {
  display: none;
}

.wl2-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-1);
  border-bottom: 1px solid var(--panel-border);
  border-radius: var(--radius-sm);
}

.wl2-row:hover {
  background: var(--panel-hover);
}

/* The row is the listbox option and the keyboard stop (roving tabindex). */
.wl2-row:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: -2px;
}

.wl2-row.selected {
  background: var(--accent-tint);
  box-shadow: inset 2px 0 0 var(--accent);
}

.wl2-row.disabled .wl2-sym,
.wl2-row.disabled .wl2-quote {
  opacity: 0.45;
}

/* T120: one listbox item = the option plus its chart trigger. The wrapper is
   presentational (role="none") — the option keeps its own border, hover paint
   and keyboard stop — and only lays the two side by side. */
.wl2-item {
  display: flex;
  align-items: stretch;
  gap: var(--space-1);
}

.wl2-item .wl2-row {
  flex: 1 1 auto;
  min-width: 0;
}

.wl2-item .chart-btn {
  align-self: center;
}

.wl2-row-tools {
  display: flex;
  gap: 2px;
  flex: none;
}

.wl2-row-link {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  color: inherit;
  text-decoration: none;
  padding: 2px var(--space-1);
  border-radius: var(--radius-sm);
}

.wl2-row-link:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 0;
}

.wl2-row-link:hover {
  text-decoration: none;
}

.wl2-id {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-width: 0;
}

.wl2-sym {
  font-weight: var(--fw-semibold);
  font-size: var(--fs-small);
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.wl2-quote {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  flex: none;
}

.wl2-price {
  font-size: var(--fs-label);
  color: var(--ink-2);
}

/* Sparkline: geometry lives in the view's inline SVG; colour is currentColor
 * from the direction tokens, so both themes and the 12/24 setting need no
 * extra rules. */
.wl2-spark {
  flex: none;
  display: block;
}

.wl2-spark.up {
  color: var(--pos);
}

.wl2-spark.down {
  color: var(--neg);
}

.wl2-spark.flat {
  color: var(--muted);
}

.wl2-loading {
  padding: var(--space-2) 0;
}

/* ---- detail pane --------------------------------------------------------- */

.wl2-detail {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  min-width: 0;
}

.wl2-detail-head {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.wl2-detail-line {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
}

.wl2-detail-symbol {
  font-size: var(--fs-section);
  font-weight: var(--fw-semibold);
  color: var(--ink);
  margin: 0;
  letter-spacing: 0.01em;
}

.wl2-detail-price {
  font-size: var(--fs-figure);
  font-weight: var(--fw-semibold);
  color: var(--ink);
  letter-spacing: -0.01em;
}

.wl2-detail-change {
  display: inline-flex;
  align-items: baseline;
  gap: var(--space-1);
  color: var(--muted);
  font-size: var(--fs-small);
}

.wl2-detail-controls {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
}

.wl2-detail-controls .check {
  margin-left: auto;
}

.wl2-detail-controls .muted {
  min-height: var(--fs-label);
}

/* Page-level Interval picker — sits first in the controls row, left of the
 * session-range picker. The Day-so-far segment is the local-only view mode;
 * its presence here keeps the chart and the table together. */
.wl2-page-interval {
  display: flex;
  align-items: center;
}

.wl2-detail-meta:empty {
  display: none;
}

.wl2-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--space-3);
}

.wl2-hour {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  flex-wrap: wrap;
}

.wl2-hour-date {
  white-space: nowrap;
}

/* Day-so-far mode hides the hourly filter bar (it filters by hour state and
 * minimum per-hour RVOL — neither of which exists in the cumulative series)
 * and lets the cumulative table take its place. */
.watchlist-page[data-mode="day-so-far"] .wl2-filters {
  display: none;
}

/* ---- hourly table: filter bar -------------------------------------------- */

.wl2-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--space-2) var(--space-5);
}

.wl2-filter {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  min-width: 0;
}

.wl2-filter-label {
  display: block;
}

.wl2-table-box[hidden] {
  display: none;
}

/* ---- phones: list-first panes, stacked controls, list-mode rows (§3.2) ---- */
/* New rules only — the two `@media (max-width: 980px)` blocks above are
 * pinned at their line numbers by responsive-architecture.test.mjs
 * (LEGACY_DESKTOP_MEDIA), so nothing may be inserted before them. The
 * list-mode row classes below are never rendered at ≥768 (DataTable keeps
 * its <table>), so they need no media query of their own. */

/* The back button and the "⋯" row-actions trigger are phone-only; the plain
 * Remove button takes their place at 768 and above. display:none keeps them
 * out of the desktop structural snapshot entirely. The menu's wrapper goes
 * with it so the empty span can never generate a box either. */
.wl2-back,
.wl2-detail-menu-wrap {
  display: none;
}

/* §3.2 compact body DataTable renders below 768:
 *   10:00–11:00  [30m]            RVOL 2.63x
 *   +0.25%   Close 110.91   Vol 66.8K
 */
.wl2-mrow {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  min-width: 0;
}

.wl2-mrow-line {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
  min-width: 0;
}

.wl2-mrow-line .wl2-hour {
  flex: 1 1 auto;
  min-width: 0;
}

.wl2-mrow-rvol {
  margin-left: auto;
  display: inline-flex;
  align-items: baseline;
  gap: var(--space-1);
  flex: none;
}

.wl2-mrow-meta {
  color: var(--ink-2);
  font-size: var(--fs-small);
}

.wl2-mrow-cell {
  display: inline-flex;
  align-items: baseline;
  gap: var(--space-1);
}

.wl2-mrow-label {
  color: var(--muted);
}

@media (max-width: 767.98px) {
  /* §3.2: phones see the list XOR the detail. Desktop ignores the attribute
   * and keeps both panes side by side. */
  .watchlist-page[data-pane="list"] > .wl2-detail {
    display: none;
  }

  .watchlist-page[data-pane="detail"] > .wl2-master {
    display: none;
  }

  /* §3.2 gate fix 3: the phone header is "‹ Watchlist" plus the symbol title,
   * then the Overview | Holdings tabs, then the rest. `.wl2-overview` and
   * `.wl2-detail-head` are grouping wrappers only — `display: contents` lets
   * their children reorder against the tab row without moving any node in the
   * DOM (the desktop box tree is untouched: this block is phone-only). The
   * wrappers' own `order` is inert (a contents element generates no box);
   * equal `order` values keep document order, so 3 for "everything after the
   * title" already yields tabs → header rest → overview body → holdings.
   * The `.wl2-detail >` prefix is load-order insurance: views/holdings.css —
   * linked after this file — styles `.wl2-overview { display: flex }` for the
   * Holdings tab, and a bare `.wl2-overview` selector would lose to it. */
  .wl2-detail {
    flex-flow: row wrap;
    align-items: center;
  }

  .wl2-detail > .wl2-overview,
  .wl2-overview > .wl2-detail-head {
    display: contents;
  }

  .wl2-back {
    display: inline-flex;
    align-items: center;
    order: 1;
    flex: 0 0 auto;
    min-height: var(--hit-min);
  }

  .wl2-detail-line {
    order: 2;
    flex: 1 1 auto;
    min-width: 0;
  }

  .wl2-detail-tabs,
  .wl2-detail-head > *:not(.wl2-detail-line),
  .wl2-overview > *:not(.wl2-detail-head),
  .wl2-holdings-host {
    order: 3;
    flex: 1 0 100%;
  }

  /* The embedded Holdings subtree's min-content is wider than the phone
   * column at 320 (the holdings table's own min-content measures 326 px), and
   * a flex item's automatic minimum size grows the page to it — scrollWidth
   * 334 at 320. The host takes the column exactly and lets the embedded view
   * contain its own wide pieces (its `.table-wrap` scrolls the table). */
  .wl2-holdings-host {
    flex: 1 1 100%;
    min-width: 0;
  }

  /* §3.2 gate fix 5: "⋯" is one control of the header's controls row, not a
   * full-width row of its own. The two pickers stay full-width strips (P6
   * fill); Compare and the "⋯" trigger share the third line. */
  .wl2-detail-menu-wrap {
    display: inline-flex;
    width: auto;
    margin-left: auto;
  }

  .wl2-detail-menu {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: auto;
    min-width: var(--hit-min);
    min-height: var(--hit-min);
  }

  /* Remove moves into the "⋯" BottomSheet (§3.2). */
  .wl2-detail-controls .wl2-remove {
    display: none;
  }

  /* Interval picker above the range picker, both in fill mode (P6 fills
   * `.tabs` below 768): 5 cells of about 57 px at 320, then Today | 5 days |
   * 10 days beneath. A wrapping row (not a column) so the Compare toggle and
   * the "⋯" trigger can share one line (§3.2 gate fix 5) — each picker takes
   * a whole line with `flex-basis: 100%`. */
  .wl2-detail-controls {
    flex-flow: row wrap;
    align-items: center;
    gap: var(--space-2);
  }

  .wl2-detail-controls .check {
    margin-left: 0;
    min-height: var(--hit-min);
    align-items: center;
  }

  .wl2-page-interval,
  .wl2-range {
    flex: 1 0 100%;
    width: 100%;
  }

  /* The hourly filters stack so each segmented control has the full width —
   * they must fit at 320 (§3.2). */
  .wl2-filters {
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-3);
  }

  /* StatCards: §2.11's phone grid (the desktop 150 px track is above). */
  .wl2-stats {
    grid-template-columns: repeat(auto-fit, minmax(min(136px, 100%), 1fr));
  }

  /* §3.2 gate fix 7: page-header.css stacks `.view-head-actions` onto its own
   * full-width row below 768, which on this page is the "Edit" row with a dead
   * gap under it. Keep the action on the title row, as at ≥768. */
  .wl2-master .view-head-actions {
    flex-basis: auto;
    margin-left: auto;
    flex-direction: row;
    align-items: center;
  }

  /* Once the cluster stops stretching, Edit is a 42 px text button — under
   * the 44 px floor of §2.9/§4.5 (the shared `.btn` phone rule sets the
   * height only). */
  .wl2-master .view-head-actions .btn {
    min-width: var(--hit-min);
    min-height: var(--hit-min);
  }

  /* §2.9 pattern 1 (invisible hit extension): Edit, the "⋯" trigger and the
   * row controls are compact --radius boxes, and the 44 px probe samples
   * centre ± 21 px — 1 px inside each corner, where the rounded corner clips
   * hit-testing and the click falls through to the wrapper. The square ::after
   * carries the button's own hit region over the corners; nothing visible
   * changes. (The switch's hit box is a square label — no corner to clip.) */
  .wl2-master .view-head-actions .btn,
  .wl2-detail-menu,
  .wl2-row-tools .btn,
  .wl2-row > .btn.danger {
    position: relative;
  }

  .wl2-master .view-head-actions .btn::after,
  .wl2-detail-menu::after,
  .wl2-row-tools .btn::after,
  .wl2-row > .btn.danger::after {
    content: "";
    position: absolute;
    inset: 0;
    width: max(100%, var(--hit-min));
    height: max(100%, var(--hit-min));
    pointer-events: auto;
  }

  /* §2.9/§3.2: the Edit-mode row controls (↑, ↓, the enable switch, ✕) each
   * carry a ≥44×44 hit area, ≥44 px apart centre to centre. They wrap onto
   * their own line under the row link (`order` — the DOM keeps tools-first,
   * so ≥768 and the desktop snapshot are untouched) so the identity line
   * keeps its width at 320. */
  .wl2-row {
    min-height: var(--hit-min);
    gap: var(--space-2);
    flex-wrap: wrap;
  }

  .wl2-row-tools {
    order: 1;
    flex: 0 0 auto;
    gap: var(--space-2);
  }

  .wl2-row-link {
    order: 0;
    flex: 1 1 100%;
  }

  .wl2-row > .switch {
    order: 2;
  }

  .wl2-row > .btn.danger {
    order: 3;
  }

  /* 44 px hit boxes, 52 px apart centre to centre (44 + --space-2). The
   * switch's track keeps its shared 30 × 16 skin: only the label grows to
   * --hit-min, and the track is centred back to its own size (the knob is
   * positioned inside the track and follows it). */
  .wl2-row-tools .btn,
  .wl2-row > .btn.danger {
    min-width: var(--hit-min);
    min-height: var(--hit-min);
  }

  .wl2-row > .switch {
    width: var(--hit-min);
    height: var(--hit-min);
  }

  .wl2-row > .switch .track {
    inset: auto;
    top: 50%;
    left: 50%;
    width: 30px;              /* styles.css `.switch`'s own width */
    height: var(--fs-section);
    transform: translate(-50%, -50%);
  }

  /* §3.2's row content is symbol, price, sparkline, pill — the ticker is the
   * row's identity and never gives up space; the sparkline and the quote
   * shrink first (they carry no identity and both clip cleanly). */
  .wl2-row-link .wl2-id {
    flex: 0 0 auto;
    max-width: 100%;
  }

  .wl2-row-link .wl2-spark,
  .wl2-row-link .wl2-quote {
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
  }

  /* The empty warnings / membership notes generate boxes and flex gaps —
   * about 48 px of dead space under the tabs. `.wl2-detail-meta` already
   * collapses this way at every width; phones need it for the two notes
   * (desktop keeps its boxes: the snapshot must not move). */
  .wl2-note:empty {
    display: none;
  }
}

/* ---- the "⋯" sheet's Remove action (§3.2 gate fix 6) -------------------- */

/* components/sheet.js gives a `kind: "danger"` action the `btn danger
 * sheet-action` skin, but styles.css defines only `.btn.danger:hover` — at
 * rest the confirm sheet's Remove looked like its Cancel. This is the missing
 * base skin (the `.banner` danger treatment: wash, border, `--neg` ink),
 * scoped to this page's own sheet: the dialog mounts on document.body (not
 * under `.wl2`), so watchlist.js marks its handle `.wl2-sheet` and only that
 * instance is painted. The desktop Remove (`btn subtle danger wl2-remove`,
 * meant to stay a quiet text button) and every other sheet stay untouched.
 * The shared `.btn.danger:hover` still wins on hover — it carries one more
 * class than this selector. */
.wl2-sheet .sheet-action[data-kind="danger"] {
  color: var(--neg);
  border-color: var(--danger-border);
  background: var(--danger-bg);
}

@media (max-width: 767.98px) {
  /* The full-width flex item must shrink below its sort select's intrinsic
     width when mobile form text is 16px (notably at 320px). */
  .wl2-table {
    min-width: 0;
  }
}
