/* ═══════════════════════════════════════
   Portfolio (#524) — holdings table, ledger journal, opening grid.

   Two rules from the design that the CSS enforces rather than trusts:
   1. Gain/loss colour appears on NUMERIC TEXT ONLY. Never a row background,
      never the allocation bar, never an assertion pill. The sign and the
      caret carry the meaning first; colour is the third signal.
   2. Assertions (opening / adjustment) are styled apart from trades by a
      DASHED pill and an em dash where a cash total would be — no colour,
      no extra weight. They didn't spend money, and the absence is the point.

   Design 14a — the Apple pass DCF got and portfolio didn't.
   dcf-valuation-card.css is headed "Apple-like redesign" and upsert-dcf-dialog.css
   "Apple-style Minimal"; this file shipped the older workbench dialect. Every
   literal below is lifted from those two files rather than invented:

     card shell    --ij-surface + 1px border  ->  --ij-bg-gray fill, no border, 20px
     dividers      1px                        ->  0.5px hairlines
     column heads  12px/600 caps              ->  10px/500 caps      (dcf-metric-cap)
     chips/buttons outlined                   ->  capsules on rgba(120,120,128,.12-.18)
     type pills    outlined                   ->  tinted             (dcf-type-badge)
     entry fields  Mud outlined               ->  filled boxes       (ij-dcf-input)
     tabs          underline                  ->  segmented          (ij-dcf-type-toggle)

   Both rules above SURVIVE the reskin: gain/loss stays numeric-text-only (no
   verdict slabs on holdings rows), and assertions keep the dashed pill and the
   em dash — dashed even in the new dialect, because they still didn't spend money.
   This pass changes paint, not decisions: 13a's newest-first, mixed currencies,
   row actions, boundary homes and load-more are all untouched.

   Zero new tokens: the DCF files ignore --ij-radius (4px) with their own 20px
   literal, and this follows their practice rather than widening the token set.
═══════════════════════════════════════ */

/* ── Page header ───────────────────────────────────────────────── */

.ij-pf-header {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--ij-space-6);
    margin-bottom: var(--ij-space-6);
    flex-wrap: wrap;
}

.ij-pf-title {
    font-size: 2rem;
    font-weight: 600;
    letter-spacing: -0.025em;
    line-height: 1.1;
    margin-bottom: var(--ij-space-1);
}

.ij-pf-subtitle {
    font-size: 13px;
    color: var(--ij-text-secondary);
}

/* ── Cards & tables ────────────────────────────────────────────── */

/* 14a: the dcf-card shell. The :not() excludes the ProGate preview, which shares
   this class — 14a defers the gate and the first-run fork to a later pass, so
   they stay on the workbench shell rather than being dragged half-way across.
   The card now carries the inset (20px, dcf-card) and its children drop their own
   horizontal padding, so the hairlines run the full width of the content column
   rather than stopping short of a border that no longer exists. */
.ij-pf-card:not(.ij-progate-preview) {
    background: var(--ij-bg-gray);
    border: none;
    border-radius: 20px;
    padding: 20px;
    overflow: hidden;
    font-variant-numeric: tabular-nums;
}

/* 14b: the gate and the first-run fork get the same pass, so the sample card is
   no longer the exception 14a carved out — it is the dcf-card shell like every
   other card here. The :not() above and this rule collapse back into one
   declaration; kept separate only because the sample's children pad differently. */
.ij-pf-card.ij-progate-preview {
    background: var(--ij-bg-gray);
    border: none;
    border-radius: 20px;
    padding: 20px;
    overflow: hidden;
    font-variant-numeric: tabular-nums;
}

/* The trailing track was 40px while it held a ⋯ menu button. Canvas-19 removed
   that button: on a fine pointer the holding row's actions are lifted out of the
   grid entirely (an absolutely-positioned pill), so all that is left to host here
   is the cash row's pencil — hence 28px. A coarse pointer widens it back, below,
   because there the actions ARE in flow. */
.ij-pf-holdings-grid {
    display: grid;
    grid-template-columns: minmax(200px, 2.3fr) 1fr 0.9fr 1.25fr 1.2fr 28px;
    gap: var(--ij-space-4);
    align-items: center;
    padding: var(--ij-space-3) 0;
}

/* .ij-pf-cash-strip-head shares the look but NOT the phone hide below (17A final
   review): .ij-pf-colhead names six table columns that don't exist on the phone
   card layout, so it disappears under 767px — but the cash strip's "CASH —
   OPTIONAL" is a section label, not a column head, and stays meaningful (and
   present) at every width. */
.ij-pf-colhead,
.ij-pf-cash-strip-head {
    padding: 0 0 var(--ij-space-2);
    font-size: 10px;
    font-weight: 500;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ij-text-secondary);
}

/* Hairlines go on the TOP of every data row rather than the bottom of all but the
   last. Same lines drawn, but this way the rule under the column head and the rules
   between rows are one declaration, the card's bottom edge is clean without a
   :last-child exception, and journal ASSERTION rows — which deliberately carry no
   .ij-pf-row — are separated too. */
.ij-pf-card .ij-pf-holdings-grid:not(.ij-pf-colhead),
.ij-pf-card .ij-pf-journal-grid:not(.ij-pf-colhead),
.ij-pf-card .ij-pf-opening-grid:not(.ij-pf-colhead) {
    border-top: 0.5px solid var(--ij-divider);
}

.ij-pf-num {
    text-align: right;
}

/* Design 12a: one CARD per currency, not one table with separator rows.
   A shared column header IS a promise that its columns are comparable down
   their length — and CAD and USD are never converted, so that promise was a
   lie the copy then had to apologise for three times over (a per-group
   "allocation is % of CAD", a per-group subtotal, and a footnote). Two cards
   make the separation structural; two of those three explanations are deleted.
   Ordered by market value descending — alphabetical would put CAD first by an
   accident of spelling. */
.ij-pf-ccy-card + .ij-pf-ccy-card {
    margin-top: var(--ij-space-4);
}

/* The subtotal lives in the card HEADER rather than in a row: a header is the
   natural place for a figure describing everything beneath it, and it removes a
   row that read like a holding. */
.ij-pf-ccy-head {
    display: flex;
    align-items: center;
    gap: var(--ij-space-3);
    padding: 0 0 14px;
    flex-wrap: wrap;
}

.ij-pf-ccy-code {
    font-size: 17px;
    font-weight: 700;
    letter-spacing: -0.02em;
}

/* Scoped, not global: .ij-pf-group-meta also labels the opening footer's hints,
   which the design keeps at 12px. Only the card header's count and P&L go up. */
.ij-pf-ccy-head .ij-pf-group-meta {
    font-size: 13px;
}

.ij-pf-ccy-head .ij-pf-group-meta.ij-pf-gain,
.ij-pf-ccy-head .ij-pf-group-meta.ij-pf-loss,
.ij-pf-ccy-head .ij-pf-group-meta.ij-pf-flat {
    font-weight: 600;
    display: flex;
    align-items: center;
    white-space: nowrap;
}

.ij-pf-ccy-name {
    font-size: 13px;
    color: var(--ij-text-secondary);
}

/* The currency group header IS the subtotal — so the absence of a grand
   total reads as an answer given up front, not a number still loading. */
.ij-pf-group {
    display: flex;
    align-items: baseline;
    gap: var(--ij-space-3);
    padding: var(--ij-space-3) var(--ij-space-4);
    background: var(--ij-bg-gray);
    border-bottom: 1px solid var(--ij-divider);
    flex-wrap: wrap;
}

.ij-pf-group-code {
    font-size: 13px;
    font-weight: 600;
}

.ij-pf-group-meta {
    font-size: 12px;
    color: var(--ij-text-secondary);
}

.ij-pf-group-spacer {
    flex: 1;
}

.ij-pf-group-mv {
    font-size: 17px;
    font-weight: 700;
    letter-spacing: -0.02em;
}

.ij-pf-identity {
    display: flex;
    align-items: center;
    gap: var(--ij-space-3);
    min-width: 0;
}

/* The identity cell's text column. Without min-width:0 it is a flex item at the
   default `auto`, so it sizes to the NAME's full width — .ij-pf-name's ellipsis
   never engages, and at 375px "Canadian National Railway Company" ran 149px past
   the cell and printed on top of the market value. The cell above it already
   carries min-width:0; this is the second half of the same pair. */
.ij-pf-identity-text {
    min-width: 0;
}

.ij-pf-name {
    font-size: 15px;
    font-weight: 500;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.ij-pf-ticker {
    font-size: 12px;
    color: var(--ij-text-secondary);
    /* The line reads "CNR.TO · CAD" — one fact, one line. Left to wrap it broke
       after the middot at 375px and made that row taller than its siblings, so
       the rows in a single card stopped aligning. Truncating is the right loss
       here: the ticker is a prefix, and a clipped one still identifies the row. */
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.ij-pf-subline {
    font-size: 12px;
    color: var(--ij-text-secondary);
}

.ij-pf-mv {
    font-size: 15px;
    font-weight: 500;
}

/* The holdings row steps down to 13px so the 17px currency subtotal in the card
   header is unambiguously the larger figure — the Apple hierarchy the DCF card
   uses (17px verdict value over 13px metrics). The journal keeps 15px: its rows
   ARE the content there, with no header figure to defer to. */
.ij-pf-holdings-grid .ij-pf-name,
.ij-pf-holdings-grid .ij-pf-mv,
.ij-pf-holdings-grid .ij-pf-pl,
.ij-pf-holdings-grid .ij-pf-num {
    font-size: 13px;
}

.ij-pf-holdings-grid .ij-pf-subline,
.ij-pf-holdings-grid .ij-pf-pl-pct,
.ij-pf-holdings-grid .ij-pf-alloc-label {
    font-size: 12px;
}

/* Allocation: a hairline under market value rather than its own column —
   four numeric columns is the ceiling, and this is the seventh candidate. */
.ij-pf-alloc {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--ij-space-2);
    margin-top: var(--ij-space-1);
}

.ij-pf-alloc-track {
    width: 56px;
    height: 2px;
    background: var(--ij-divider);
    overflow: hidden;
    display: inline-block;
}

.ij-pf-alloc-fill {
    display: block;
    height: 2px;
    background: var(--ij-text-tertiary);
}

.ij-pf-alloc-label {
    font-size: 12px;
    color: var(--ij-text-secondary);
    min-width: 28px;
}

/* 17A review: a single-line card (one holding alone, or cash alone) never shows
   the allocation hairline, so the explanation has to be visible text at the
   bottom of the card, not a tooltip on a hairline that isn't there. Quiet, same
   register as .ij-pf-subline/.ij-pf-no-total. */
.ij-pf-alloc-hint {
    padding: var(--ij-space-2) 0 0;
    font-size: 12px;
    color: var(--ij-text-secondary);
}

/* 17A: the cash row — an assertion wearing a row. Dashed = asserted, no money
   moved (the opening/adjustment mark); the tile is the currency glyph as text.
   Sized to match .wlc-stock-avatar (36px/10px radius) exactly, so the row's
   leading tile lines up with every holding avatar above it rather than
   introducing a second size in the same column. */
.ij-pf-cash-tile {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border: 1.5px dashed var(--ij-divider);
    border-radius: 10px;
    font-size: 12px;
    font-weight: 600;
    color: var(--ij-text-secondary);
    flex: none;
}

.ij-pf-cash-tile--ghost {
    color: transparent;
}

.ij-pf-cash-dash {
    color: var(--ij-text-tertiary);
}

/* THE SHIPPED DEFECT, fixed in #1435. The cash row's identity CELL used to be a
   <button>, and a button is centred by the UA stylesheet — so the cash tile sat
   off-axis from the holding avatars directly above it, in the same column, on
   every card that had both. The whole ROW is the button now (.ij-pf-cash-zone-row)
   and the cell is a plain flex span, which inherits nothing to correct. */
.ij-pf-cash-identity {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    text-align: left;
    min-width: 0;
}

.ij-pf-cash-name-line {
    display: inline-flex;
    align-items: baseline;
    gap: 4px;
    min-width: 0;
}

/* The row's currency, matching the ticker's treatment one zone above it. */
.ij-pf-cash-ccy {
    color: var(--ij-text-secondary);
}

/* The CURRENCY card still renders its cash row as an identity <button> — that
   shape is out of #1435's scope and the second-account rule requires it to stay
   as shipped. It gets the one-line alignment fix and nothing else: without an
   explicit justify-content a flex <button> is centred by the UA stylesheet,
   which is the whole defect. */
.ij-pf-cash-identity-btn {
    background: none;
    border: none;
    padding: 0;
    margin: 0;
    font: inherit;
    text-align: left;
    color: inherit;
    cursor: pointer;
    width: 100%;
    justify-content: flex-start;
}

.ij-pf-cash-edit {
    display: inline-flex;
    align-items: center;
    justify-content: flex-end;
    color: var(--ij-text-tertiary);
    opacity: 0;
    transition: opacity 0.12s ease, color 0.12s ease;
}

.ij-pf-cash-edit .mud-icon-root {
    font-size: 15px;
}

.ij-pf-cash-identity-btn:hover .ij-pf-cash-edit,
.ij-pf-cash-identity-btn:focus-visible .ij-pf-cash-edit {
    opacity: 1;
    color: var(--ij-text-secondary);
}

/* In the ZONE the pencil is visible at rest (#1435). The ramp above starts at
   invisible, so on a card the pointer had not yet crossed there was nothing at
   all to say the balance could be edited — acceptable when the row also carried
   a ⋯, not once the row itself became the only door. Scoped to the zone's row
   so the currency card's ramp is untouched. */
.ij-pf-cash-zone-row .ij-pf-cash-edit {
    opacity: 0.55;
}

.ij-pf-cash-zone-row:hover .ij-pf-cash-edit,
.ij-pf-cash-zone-row:focus-visible .ij-pf-cash-edit {
    opacity: 1;
    color: var(--ij-text-secondary);
}

@media (hover: none) {
    .ij-pf-cash-edit {
        opacity: 1;
    }
}

/* ── The cash zone (#1435) ─────────────────────────────────────────
   One per account card, at its foot. It is not a section — it is the same table,
   re-labelled for rows that are assertions rather than positions. */
.ij-pf-cash-zone {
    margin-top: var(--ij-space-2);
}

/* Sits on the card's grid so the label starts exactly where "Holding" does. */
.ij-pf-cash-zone-head {
    padding-top: var(--ij-space-3);
    border-top: 0.5px solid var(--ij-divider);
}

.ij-pf-cash-zone-label {
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ij-text-tertiary);
}

/* NAMED -zone-row, not -cash-row: .ij-pf-cash-row is already UpdateCashDialog's
   row (portfolio.css:~1300). Reusing it silently pushed this block's hover fill,
   radius and pointer cursor into that dialog, and took the dialog's display:flex
   in return — which is why this row's grid template was present but inert.

   The whole row is the control. Reset the button — and RE-DECLARE display:grid.
   The element already carries .ij-pf-holdings-grid, but a later button rule wins
   the cascade and laid these cells out as flex: the row was the right width in
   the right place while its market value sat ~80px left of the column it was
   supposed to share an edge with. Measured, not guessed — computed display came
   back "flex" with the grid template present but inert. */
.ij-pf-cash-zone-row {
    display: grid;
    /* The fill needs room INSIDE it — at padding 0 its rounded edge sat flush
       against the cash tile on one side and the pencil on the other, so the row
       read as if it had been cropped.

       It cannot simply gain padding: with box-sizing border-box and width 100%,
       horizontal padding shrinks the CONTENT box, which would pull every column
       in and break the alignment with the holding rows above (the cash amount
       shares the Market value column's right edge). So the box grows by exactly
       the padding it gains and is pulled back out by the same amount: content
       stays 100% and on-grid, and the fill extends 10px past it on each side. */
    width: calc(100% + 20px);
    margin: 0 -10px;
    padding: 12px 10px;
    border: 0;
    background: none;
    font: inherit;
    color: inherit;
    text-align: left;
    border-radius: 8px;
    cursor: pointer;
    transition: background 0.12s ease;
}

.ij-pf-cash-zone-row:hover {
    background: rgba(120, 120, 128, 0.08);
}

.ij-pf-cash-zone-row:focus-visible {
    outline: 2px solid var(--ij-primary);
    outline-offset: -2px;
}

/* ONE line for the zone, naming the stalest date the rows above it carry. */
.ij-pf-cash-zone-foot {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 4px;
    padding-top: var(--ij-space-2);
    border-top: 0.5px solid var(--ij-divider);
    font-size: 12px;
    color: var(--ij-text-secondary);
}

.ij-pf-cash-zone-foot .ij-pf-btn-text {
    font-size: 12px;
}

.ij-pf-cash-ghost {
    padding: 12px 0;
}

.ij-pf-cash-ghost-label {
    color: var(--ij-text-secondary);
}

.ij-pf-cash-ghost-ccy {
    font-size: 13px;
}

/* ── Gain / loss ───────────────────────────────────────────────── */

.ij-pf-pl {
    font-size: 15px;
    font-weight: 600;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    white-space: nowrap;
}

.ij-pf-pl-pct {
    font-size: 12px;
}

.ij-pf-gain {
    color: var(--ij-gain);
}

.ij-pf-loss {
    color: var(--ij-loss);
}

/* Flat is an em dash in secondary — no colour, because zero is neither. */
.ij-pf-flat {
    color: var(--ij-text-secondary);
}

/* ── Closing line where a grand total would be ─────────────────── */

/* Outside the cards now, so it aligns to the page column, not to a card inset. */
.ij-pf-no-total {
    display: flex;
    align-items: center;
    gap: var(--ij-space-2);
    padding: 14px 0 0;
    color: var(--ij-text-secondary);
    font-size: 13px;
    line-height: 1.5;
}

/* THE SECOND-PORTFOLIO RULE (25A/Task 14): the container-scope statement — the
   summary strip's caption slot at 2+ accounts, this footnote zone otherwise.
   Primary text colour, not secondary: unlike the currency note above it, this
   is a constraint on what the page shows, not a passing aside. */
.ij-pf-scope-line {
    margin-top: var(--ij-space-2);
    font-size: 12px;
    font-weight: 500;
    color: var(--ij-text-primary);
}

/* Design 13b: Holdings · Transactions. The page is already called Portfolio, so a
   tab cannot repeat it — these two words are what the feature actually is, the
   derived view and the source of truth. */
/* 14a's one structural swap: the underline tab bar becomes a SEGMENTED CONTROL,
   the Apple dialect's native switcher (ij-dcf-type-toggle). Still two <a> elements
   with real hrefs — the address, not component state, is what selects the tab, so
   deep links and browser back keep working exactly as 13b built them.
   width: fit-content rather than display: inline-flex — an inline-level box would
   pick up line-height leading under it and drift out of the page's vertical rhythm. */
.ij-pf-tabs {
    display: flex;
    align-items: center;
    gap: 2px;
    width: fit-content;
    padding: 2px;
    background: rgba(120, 120, 128, 0.18);
    border-radius: 9px;
    margin-bottom: var(--ij-space-6);
}

.ij-pf-tab {
    padding: 6px 20px;
    border-radius: 7px;
    font-size: 13px;
    font-weight: 500;
    color: var(--ij-text-secondary);
    text-decoration: none;
    transition: background 0.15s ease, color 0.15s ease;
}

.ij-pf-tab--on {
    color: var(--ij-text-primary);
    font-weight: 600;
    background: var(--ij-surface);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.14);
}

/* The pedagogy sentence a tab severs. Quiet on purpose — the tab two centimetres
   away is the door; this names how much history backs the numbers. */
.ij-pf-computed-from {
    margin-top: var(--ij-space-2);
    padding: 0;
    font-size: 13px;
    color: var(--ij-text-secondary);
}

.ij-pf-computed-from a {
    color: var(--ij-primary);
    text-decoration: none;
    font-weight: 600;
}

.ij-pf-computed-from a:hover {
    text-decoration: underline;
}

/* Native (13b): the cross-link keeps ROW weight because it is the only entrance
   at 390 — there is no tab bar to carry it. */
.ij-pf-push-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--ij-space-3);
    width: 100%;
    margin-top: var(--ij-space-4);
    padding: var(--ij-space-4);
    background: var(--ij-surface);
    border: 1px solid var(--ij-divider);
    border-radius: var(--ij-radius);
    font: inherit;
    font-size: 15px;
    color: var(--ij-text-primary);
    text-align: left;
    cursor: pointer;
}

.ij-pf-push-label {
    min-width: 0;
}

.ij-pf-pushed-head {
    display: flex;
    align-items: center;
    gap: var(--ij-space-3);
    padding: var(--ij-space-3) var(--ij-space-4);
    border-bottom: 1px solid var(--ij-divider);
}

.ij-pf-back-btn {
    display: inline-flex;
    align-items: center;
    gap: var(--ij-space-1);
    background: none;
    border: none;
    padding: 0;
    font: inherit;
    font-size: 15px;
    color: var(--ij-primary);
    cursor: pointer;
}

.ij-pf-pushed-title {
    font-size: 15px;
    font-weight: 600;
}

/* ── Journal ───────────────────────────────────────────────────── */

/* Design 13a. The journal used to stop at 25 rows with a footer that named the
   975 it was hiding and offered nothing. Filters find, load-more reaches.
   Three chips, holding first — it is the question users arrive with. */
.ij-pf-jrn-filters {
    display: flex;
    align-items: center;
    gap: var(--ij-space-2);
    padding: 0 0 14px;
    flex-wrap: wrap;
}

/* 14a: capsules on the iOS fill. Still a native <select>, so it keeps its own
   disclosure arrow — the design draws a chevron, and the platform one is that
   chevron, drawn by the control that actually opens the menu. */
.ij-pf-jrn-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--ij-space-1);
    font-size: 13px;
    font-weight: 600;
    color: var(--ij-text-primary);
    background: rgba(120, 120, 128, 0.12);
    border: none;
    border-radius: 20px;
    padding: 6px 10px 6px 14px;
    cursor: pointer;
    white-space: nowrap;
}

/* An active filter is stated in text, not just colour — the chip shows the
   ticker or type it is holding, so the state survives being read aloud. */
.ij-pf-jrn-chip--on {
    color: var(--ij-primary);
    background: color-mix(in srgb, var(--ij-primary) 14%, transparent);
}

.ij-pf-jrn-clear {
    background: none;
    border: none;
    padding: 0;
    font: inherit;
    font-size: 13px;
    font-weight: 600;
    color: var(--ij-primary);
    cursor: pointer;
}

/* The boundary sentence when its own row is not on screen. Same weight as the
   inline rule it stands in for, so neither reads as the louder claim. */
.ij-pf-jrn-boundary-strip {
    display: flex;
    align-items: center;
    gap: var(--ij-space-2);
    padding: 0 0 12px;
    font-size: 12px;
    line-height: 1.5;
    color: var(--ij-text-secondary);
}

.ij-pf-jrn-empty {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--ij-space-2);
    padding: var(--ij-space-8) 0;
}

.ij-pf-jrn-empty-title {
    font-size: 15px;
    font-weight: 500;
}


.ij-pf-section-head {
    display: flex;
    align-items: baseline;
    gap: var(--ij-space-3);
    margin: var(--ij-space-8) 0 var(--ij-space-3);
    flex-wrap: wrap;
}

.ij-pf-section-title {
    font-size: 1.125rem;
    font-weight: 600;
    letter-spacing: -0.015em;
}

.ij-pf-journal-grid {
    display: grid;
    grid-template-columns: 96px 104px minmax(0, 1fr) 1.5fr 1.15fr 40px;
    gap: var(--ij-space-3);
    align-items: center;
    padding: var(--ij-space-3) 0;
}

/* 14a: TINTED, not outlined (dcf-type-badge). Buy rides the neutral iOS fill so
   it recedes — it is the common case and does not need to announce itself. */
.ij-pf-pill {
    justify-self: start;
    display: inline-flex;
    align-items: center;
    gap: var(--ij-space-1);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    padding: 2px 9px;
    border-radius: 20px;
    border: none;
    background: rgba(120, 120, 128, 0.12);
    color: var(--ij-text-secondary);
    white-space: nowrap;
}

.ij-pf-pill-sell {
    background: color-mix(in srgb, var(--ij-loss) 14%, transparent);
    color: var(--ij-loss);
}

/* Dashed = assertion, and it stays dashed THROUGH the reskin — the one pill that
   keeps a border while the others became fills. Deliberately NOT a colour: an
   opening position is not a warning, and on an onboarding portfolio every row
   would carry it. The dashed edge and the em dash under Total are the pair that
   says no money moved; losing either to a fill would flatten the distinction. */
.ij-pf-pill-assertion {
    background: none;
    border: 1px dashed var(--ij-divider);
    color: var(--ij-text-secondary);
}

.ij-pf-boundary {
    display: flex;
    align-items: center;
    gap: var(--ij-space-3);
    padding: 0 0 var(--ij-space-3);
}

.ij-pf-boundary-label {
    flex: none;
    font-size: 12px;
    color: var(--ij-text-tertiary);
}

.ij-pf-boundary-rule {
    flex: 1;
    height: 0.5px;
    background: var(--ij-divider);
}

.ij-pf-row-action {
    justify-self: end;
    color: var(--ij-text-tertiary);
}

.ij-pf-row:hover .ij-pf-row-action {
    color: var(--ij-text-secondary);
}

/* Load-more first, count second: the design reads the action then its address.
   row-reverse rather than reordering the markup — the DOM keeps count-then-button,
   which is the order a screen reader should hear it (state, then the control). */
.ij-pf-journal-footer {
    display: flex;
    flex-direction: row-reverse;
    align-items: center;
    justify-content: flex-end;
    gap: var(--ij-space-4);
    padding: 14px 0 0;
    border-top: 0.5px solid var(--ij-divider);
    font-size: 13px;
    color: var(--ij-text-secondary);
    flex-wrap: wrap;
}

/* "Show 50 more" is a tinted capsule, not a text link — it is the only control in
   the footer and the design gives it the primary tint. Scoped to the footer: the
   same class is a plain text button in the empty state's widening offer and in the
   first-run fork, both of which 14a leaves alone. */
.ij-pf-journal-footer .ij-pf-btn-text {
    display: inline-flex;
    align-items: center;
    background: color-mix(in srgb, var(--ij-primary) 14%, transparent);
    border-radius: 20px;
    padding: 8px 18px;
    font-size: 13px;
}

/* ── Empty state / first-run fork ──────────────────────────────── */

/* First run, for someone who already has access.
   NO container cap — same rule 6a settled on the gate: a cap here shrinks the
   surface and puts the empty space outside it, which is what left a 560px column
   stranded on a 1920px screen. The measure lives on the PROSE (60ch, below);
   cards and the grid fill what they are given.
   NO padding either — the shell (.ij-page-content) owns all inset. Its 32px is
   the shared gutter; adding another 32px here started the first-run content at
   64px while /connect started at 32px, which is the drift this shape exists to
   avoid. */
.ij-pf-empty {
    padding: 0;
}

/* Same shape as /connect, /you and the Pro gate — not a fourth page shape. */
.ij-pf-empty-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 28px;
    align-items: start;
}

.ij-pf-empty-main {
    min-width: 0;
}

.ij-pf-empty-rail {
    min-width: 0;
}

@media (min-width: 960px) {
    .ij-pf-empty-grid {
        grid-template-columns: 1.35fr 1fr;
    }

    .ij-pf-empty-rail {
        position: sticky;
        top: var(--ij-space-6);
        min-width: 340px;
    }
}

/* The empty page's Claude card is the same borrowed surface as the gate's — see
   the .ij-progate-rail rule below, which restyles both. */

.ij-pf-empty-icon {
    display: inline-flex;
    width: 40px;
    height: 40px;
    border-radius: 12px;
    background: color-mix(in srgb, var(--ij-primary) 14%, transparent);
    color: var(--ij-primary);
    align-items: center;
    justify-content: center;
    margin-bottom: var(--ij-space-4);
}

.ij-pf-empty-title {
    font-size: 2rem;
    font-weight: 600;
    letter-spacing: -0.025em;
    line-height: 1.1;
    margin-bottom: var(--ij-space-2);
}

/* The measure the container no longer carries — same 60ch the gate's pitch uses. */
.ij-pf-empty-body {
    font-size: 17px;
    line-height: 1.5;
    color: var(--ij-text-secondary);
    max-width: 60ch;
    margin-bottom: var(--ij-space-6);
    text-wrap: pretty;
}

.ij-pf-fork {
    background: var(--ij-bg-gray);
    border: none;
    border-radius: 20px;
    padding: 20px;
    margin-bottom: var(--ij-space-3);
}

.ij-pf-fork-head {
    display: flex;
    align-items: center;
    gap: var(--ij-space-3);
    margin-bottom: var(--ij-space-2);
}

.ij-pf-fork-icon {
    flex: none;
    width: 32px;
    height: 32px;
    border-radius: 10px;
    background: color-mix(in srgb, var(--ij-primary) 14%, transparent);
    color: var(--ij-primary);
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

/* The muted tile sits ON the fork's gray, so --ij-bg-gray would erase it. */
.ij-pf-fork-icon--muted {
    background: rgba(120, 120, 128, 0.18);
    color: var(--ij-text-secondary);
}

.ij-pf-fork-title {
    flex: 1;
    font-size: 17px;
    font-weight: 600;
}

.ij-pf-fork-tag {
    font-size: 10px;
    font-weight: 500;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ij-text-secondary);
}

.ij-pf-fork-body {
    font-size: 13px;
    line-height: 1.5;
    color: var(--ij-text-secondary);
    margin-bottom: var(--ij-space-4);
}

.ij-pf-quiet-note {
    font-size: 13px;
    line-height: 1.5;
    color: var(--ij-text-secondary);
    margin-top: var(--ij-space-5, 20px);
}

/* The layer line sits in the quiet-note stack on the empty page, not in the
   footnote zone — match that rhythm rather than the footnote's. */
.ij-pf-empty-main .ij-pf-layer-note {
    padding-top: var(--ij-space-5, 20px);
}

/* ── What Pro adds, on the empty page only (27b) ──────── */

/* The same object as .ij-pf-fork, one step larger in padding — not a new card
   dialect. No border, no shadow, no gradient: it is the last block on a page of
   gray blocks, and anything that made it louder would make the two forks above
   it read as the smaller offer. */
.ij-pf-pro-band {
    margin-top: 32px;
    background: var(--ij-bg-gray);
    border-radius: 20px;
    padding: 26px 28px;
}

.ij-pf-pro-band-eyebrow {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 14px;
}

.ij-pf-pro-band-lock {
    flex: none;
    width: 26px;
    height: 26px;
    border-radius: 980px;
    background: var(--ij-primary-tint);
    color: var(--ij-primary);
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.ij-pf-pro-band-eyebrow-text {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--ij-text-secondary);
}

/* Future tense, and the measure keeps it a headline rather than a paragraph. */
.ij-pf-pro-band-title {
    font-size: 1.35rem;
    font-weight: 600;
    letter-spacing: -0.02em;
    line-height: 1.25;
    max-width: 660px;
    margin: 0 0 20px;
    text-wrap: pretty;
}

.ij-pf-pro-band-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 18px 40px;
}

.ij-pf-pro-item {
    display: flex;
    gap: 10px;
    align-items: flex-start;
}

.ij-pf-pro-item-title {
    font-size: 14px;
    font-weight: 600;
    margin-bottom: 3px;
}

.ij-pf-pro-item-body {
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--ij-text-secondary);
    margin: 0;
    text-wrap: pretty;
}

.ij-pf-pro-band-foot {
    margin-top: 22px;
    padding-top: 20px;
    border-top: 0.5px solid var(--ij-divider);
    display: flex;
    gap: 48px;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: flex-start;
}

.ij-pf-pro-band-notify {
    max-width: 430px;
}

.ij-pf-pro-soon {
    display: flex;
    gap: 8px;
    align-items: flex-start;
    margin-bottom: 12px;
}

.ij-pf-pro-soon-title {
    font-size: 13px;
    font-weight: 600;
    margin-bottom: 2px;
}

.ij-pf-pro-soon-body {
    font-size: 12px;
    line-height: 1.5;
    color: var(--ij-text-secondary);
    margin: 0;
}

/* Scoped: the band's CTA is one step quieter than the fork's primary, which has
   to stay the loudest control on this page. The base rule is untouched. */
.ij-pf-pro-band .ij-pf-btn-primary {
    font-size: 14px;
    padding: 9px 20px;
}

/* Secondary, never tertiary — tertiary fails contrast on the gray card. */
.ij-pf-pro-fineprint {
    margin-top: 8px;
    line-height: 1.5;
}

/* Same size step as the fine print it replaces, so the row does not jump when
   the CTA block swaps for the done line. */
.ij-pf-pro-band .ij-progate-notified-label {
    font-size: 13px;
}

.ij-pf-pro-band-promise {
    max-width: 400px;
}

.ij-pf-pro-promise-title {
    font-size: 12px;
    font-weight: 600;
    margin-bottom: 4px;
}

.ij-pf-pro-promise-body {
    font-size: 12px;
    line-height: 1.5;
    color: var(--ij-text-secondary);
    margin: 0 0 8px;
}

/* Glyph sizes are drawn, not inherited from MudIcon's size steps. */
.ij-pf-pro-glyph-lock {
    width: 15px;
    height: 15px;
}

.ij-pf-pro-glyph-check {
    flex: none;
    width: 17px;
    height: 17px;
    margin-top: 2px;
    color: var(--ij-primary);
}

.ij-pf-pro-glyph-clock {
    flex: none;
    width: 16px;
    height: 16px;
    margin-top: 2px;
    color: var(--ij-text-tertiary);
}

.ij-pf-pro-glyph-mail {
    width: 18px;
    height: 18px;
}

/* Two columns of 12.5px prose stop being readable well before the page runs out
   of room, so the collapse happens above the phone breakpoint. */
@media (max-width: 900px) {
    .ij-pf-pro-band-grid {
        grid-template-columns: 1fr;
    }
}

@media (max-width: 600px) {
    .ij-pf-pro-band {
        padding: 20px;
    }

    /* The desktop headline is one long future-tense sentence, and at 390px it
       ran to five lines — a wall of 21.6px type above four items the reader has
       not reached yet. Stepping it down keeps the whole band scannable in one
       glance without shortening the sentence, which carries the offer.
       Tracking relaxes with it: -0.02em is drawn for the larger size and reads
       as cramped once the type is this small. */
    .ij-pf-pro-band-title {
        font-size: 1.15rem;
        line-height: 1.3;
        letter-spacing: -0.015em;
    }

    /* Notify first, promise second: the promise answers a question the pitch
       raises, so it cannot come before it once they are in one column. */
    .ij-pf-pro-band-foot {
        gap: 20px;
    }

    .ij-pf-pro-band-notify,
    .ij-pf-pro-band-promise {
        max-width: none;
        flex: 1 1 100%;
    }

    .ij-pf-pro-band .ij-pf-btn-primary {
        width: 100%;
        justify-content: center;
        min-height: 44px;
    }
}

/* ── The desk's Claude card (canvas 15a) ───────────────────────── */

/* .ij-pf-pro-band's anatomy — eyebrow, title, 2-col item grid, foot — kept
   beside the block it copies so the two shapes evolve together. Three clay
   moves borrowed from the overdue hero: a 1px clay border, a top-down wash and
   a corner glow. Clay is Claude's colour on the desk and nothing else's; it
   says "different kind of thing", never "more urgent" — which is why the card
   sits last on the desk. Move it above the fold and the glow comes off.
   Base rules are the LIGHT theme: on the pale --ij-bg-gray the board's dark
   values read as a pink card, so the wash and glow are re-derived here and the
   dark block below restores the board's numbers. */
.ij-desk-claude {
    position: relative; /* the glow is absolutely positioned */
    overflow: hidden; /* clips the glow to the radius */
    margin-top: 24px;
    border: 1px solid rgba(217, 119, 87, 0.34);
    border-radius: 20px;
    background:
        linear-gradient(
            180deg,
            rgba(217, 119, 87, 0.035),
            rgba(217, 119, 87, 0.01) 42%,
            rgba(217, 119, 87, 0) 78%
        ),
        var(--ij-bg-gray);
    padding: 24px 26px;
}

/* The overdue hero's corner glow, in clay. Offset top-left, behind content. */
.ij-desk-claude::before {
    content: "";
    position: absolute;
    top: -140px;
    left: -80px;
    width: 420px;
    height: 280px;
    border-radius: 50%;
    background: radial-gradient(closest-side, rgba(217, 119, 87, 0.12), transparent);
    pointer-events: none;
}

.ij-desk-claude > * {
    position: relative; /* content above the glow */
}

.ij-desk-claude-eyebrow {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 12px;
}

.ij-desk-claude-glyph {
    flex: none;
    width: 26px;
    height: 26px;
    border-radius: 980px;
    background: rgba(217, 119, 87, 0.2);
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

/* Light-theme clay passes 4.5:1 on the pale ground as-is; the dark block swaps
   in the lightened ramp because #d97757 on the washed dark card does not. */
.ij-desk-claude-eyebrow-text {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--ij-lp-clay);
}

.ij-desk-claude-title {
    font-size: 1.3rem;
    font-weight: 600;
    letter-spacing: -0.02em;
    line-height: 1.25;
    max-width: 640px;
    margin: 0 0 18px;
    text-wrap: pretty;
}

.ij-desk-claude-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 16px 40px;
}

.ij-desk-claude-q {
    font-size: 14px;
    font-weight: 600;
    margin-bottom: 3px;
}

.ij-desk-claude-gloss {
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--mud-palette-text-secondary);
    margin: 0 0 6px;
}

.ij-desk-claude-open {
    font-size: 13px;
    font-weight: 600;
    color: var(--ij-lp-clay);
    text-decoration: none;
}

.ij-desk-claude-open:hover {
    text-decoration: underline;
}

.ij-desk-claude-foot {
    margin-top: 18px;
    padding-top: 16px;
    border-top: 0.5px solid rgba(217, 119, 87, 0.22);
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--mud-palette-text-secondary);
}

/* The board's own numbers — drawn dark-only, restored here. */
.ij-theme-dark .ij-desk-claude {
    background:
        linear-gradient(
            180deg,
            rgba(217, 119, 87, 0.075),
            rgba(217, 119, 87, 0.02) 42%,
            rgba(217, 119, 87, 0) 78%
        ),
        var(--ij-bg-gray);
}

.ij-theme-dark .ij-desk-claude::before {
    background: radial-gradient(closest-side, rgba(217, 119, 87, 0.3), transparent);
}

/* The lightened clay ramp: 11px needs the most help, the 13px links a step less.
   Literal #d97757 fails 4.5:1 on the washed dark card — text never uses it. */
.ij-theme-dark .ij-desk-claude-eyebrow-text {
    color: #e0a184;
}

.ij-theme-dark .ij-desk-claude-open {
    color: #e8916b;
}

/* Follows .ij-pf-pro-band's own collapse, at the desk's phone breakpoint. */
@media (max-width: 899.95px) {
    .ij-desk-claude {
        padding: 20px 18px;
    }

    .ij-desk-claude-grid {
        grid-template-columns: 1fr;
    }

    .ij-desk-claude-title {
        font-size: 1.15rem;
    }
}

/* ── Buttons ───────────────────────────────────────────────────── */

/* Capsule (980px, the literal upsert-dcf-dialog.css already uses on its own pill). */
.ij-pf-btn-primary {
    display: inline-flex;
    align-items: center;
    gap: var(--ij-space-2);
    background: var(--ij-primary);
    color: #fff;
    font-size: 15px;
    font-weight: 600;
    border: none;
    border-radius: 980px;
    padding: 10px 22px;
    cursor: pointer;
    font-family: inherit;
}

.ij-pf-btn-primary:disabled {
    background: var(--ij-divider);
    color: var(--ij-text-tertiary);
    cursor: default;
}

.ij-pf-btn-text {
    background: none;
    border: none;
    font-family: inherit;
    font-size: 15px;
    font-weight: 600;
    color: var(--ij-primary);
    cursor: pointer;
    padding: 0;
}

/* This class had NO disabled state, and nothing needed one until #1435 put
   Archive on it — a control that is disabled most of the time, because only an
   empty account can be archived. Without this a refused Archive rendered in full
   accent blue with a pointer cursor, identical to a live one: it looked
   clickable, did nothing, and read as broken. The caption beside it always said
   why; the button just never agreed. */
.ij-pf-btn-text:disabled {
    color: var(--ij-text-tertiary);
    cursor: default;
}

/* ── Dialog ────────────────────────────────────────────────────── */

.ij-pf-dialog {
    padding: var(--ij-space-1) 0;
}

.ij-pf-dialog-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--ij-space-4);
    padding-top: var(--ij-space-4);
    margin-top: var(--ij-space-4);
    border-top: 1px solid var(--ij-divider);
    font-variant-numeric: tabular-nums;
    flex-wrap: wrap;
}

/* Controlled span, not MudBlazor's Error/ErrorText — the app's field-error pattern. */
.ij-pf-field-error {
    display: block;
    font-size: 12px;
    line-height: 1.4;
    color: var(--ij-loss);
    margin-top: var(--ij-space-1);
}

/* 16A: a disabled company picker reads as the fact this edit is about, not a
   dead control — quiet fill, value in secondary, border and chevron gone.
   Scoped to .mud-autocomplete (the company picker is the only one in this
   dialog) rather than any disabled Mud input, so a future disabled numeric
   field doesn't inherit this look. Also corrected the ancestor: MudBlazor
   never puts .mud-disabled on .mud-input-control itself — it lands on the
   nested .mud-input div (verified against the rendered DOM), which is what
   these rules now target. */
.ij-pf-dialog .mud-autocomplete .mud-input.mud-disabled .mud-input-outlined-border {
    border-color: transparent;
}

.ij-pf-dialog .mud-autocomplete .mud-input.mud-disabled {
    background: rgba(120, 120, 128, 0.12);
    border-radius: var(--mud-default-borderradius);
}

.ij-pf-dialog .mud-autocomplete .mud-input.mud-disabled input {
    color: var(--ij-text-secondary);
    -webkit-text-fill-color: var(--ij-text-secondary);
}

.ij-pf-dialog .mud-autocomplete .mud-input.mud-disabled .mud-input-adornment {
    display: none;
}

/* 16A mobile: FullScreen form — 16px inputs so iOS never auto-zooms; the
   xs=12 grid already stacks the cluster at phone widths. */
.ij-pf-dialog--mobile .mud-input {
    font-size: 16px;
}

/* The nav bar owns the top edge; the body wrapper carries the padding — same
   split as the thesis dialog (thesis.css .ij-thesis-dialog--mobile .mud-dialog-content). */
.ij-pf-dialog-host--mobile .mud-dialog-content {
    padding: 0;
}

.ij-pf-dialog--mobile {
    padding: 0 16px calc(env(safe-area-inset-bottom) + 16px);
}

/* ── Update-cash sheet (17A Task 4) ───────────────────────────────
   Compact sheet: title + inline Cancel/Save share the top row, one row per
   currency below, a footer explainer at the bottom. Never FullScreen, so no
   .ij-pf-dialog-host--mobile / .ij-form-nav here — the 16px-input treatment
   below is the phone-width equivalent, done in CSS alone. */

.ij-pf-cash-row {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--ij-space-4);
    padding: var(--ij-space-3) 0;
    border-bottom: 1px solid var(--ij-divider);
}

.ij-pf-cash-row:last-of-type {
    border-bottom: none;
}

.ij-pf-cash-row-label {
    padding-top: 10px; /* roughly aligns with the outlined field's text baseline */
    min-width: 0;
}

.ij-pf-cash-row-code {
    font-weight: 600;
    margin-right: var(--ij-space-1);
}

.ij-pf-cash-row-name {
    color: var(--ij-text-secondary);
    font-size: 13px;
}

.ij-pf-cash-row-field {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    width: 140px;
    flex-shrink: 0;
}

.ij-pf-cash-row-input input,
.ij-pf-cash-row-input .mud-input-slot {
    text-align: right;
}

.ij-pf-cash-row-caption {
    font-size: 12px;
    color: var(--ij-text-secondary);
    margin-top: var(--ij-space-1);
}

/* The moment a field is dirty, its caption says so in the same tone as the
   rest of the app's "this is about to change" signals. */
.ij-pf-cash-row-caption--dirty {
    color: var(--ij-primary);
}

.ij-pf-cash-explainer {
    margin-top: var(--ij-space-4);
}

/* Phone-width 16px inputs so iOS never auto-zooms — same rule as the
   FullScreen form dialogs (.ij-pf-dialog--mobile .mud-input), reproduced here
   because this sheet stays a centred card at every width rather than
   switching class at open time. */
@media (max-width: 599.98px) {
    .ij-pf-cash-dialog .mud-input {
        font-size: 16px;
    }
}

/* ── Pro gate ──────────────────────────────────────────────────── */

/* ProGate owns its own inset — see design 4a.
   The rule was chosen on failure mode, not taste: if the component pads and a
   host also pads, you get a double gutter (cosmetic, caught in the first
   screenshot). If the host is supposed to pad and forgets, you get text on the
   screen edge — broken, and it ships. That is exactly what happened here.
   Hosts must pass a full-width, zero-horizontal-padding slot.
   Mobile-first: base is the native value, the wide override comes later. */
/* ProGate is a SURFACE, not a block (design 4a, restated as a hard negative in
   6a): NO max-width and NO margin: 0 auto on this container, ever. It renders
   edge-to-edge into whatever slot the host gives it and applies its own inset
   internally — hosts must pass a full-width, zero-horizontal-padding slot.
   Mobile-first: base is the native value, the wide override comes later.

   The measure cap belongs on the PITCH PARAGRAPH alone, at 60ch. A cap on the
   container instead makes the whole page small and pushes the empty space
   OUTSIDE the gate, where it reads as an unfinished page rather than as
   deliberate measure. That is exactly what a max-width here did: 620px of dead
   gutter at 1920, 1260px at 2560. #525 and #711 will re-derive the same cap
   from the same instinct — don't. */
.ij-progate {
    padding: var(--ij-space-6) var(--ij-space-4) 20px;
}

@media (min-width: 768px) {
    .ij-progate {
        padding: var(--ij-space-8);
    }
}

.ij-progate-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 28px;
    align-items: start;
}

.ij-progate-main {
    min-width: 0;
}

/* The railless gate (every native head) has no second column to absorb width, so
   on a Mac window its single column would run to ~1650px: the sample card, the
   notice and the headline all stretched, with only the 60ch pitch behaving.
   Measured after 6a removed the container cap — phones never showed it because
   they are narrower than any cap that was there.
   The cap goes on the CONTENT COLUMN, never the container. That is the whole
   distinction 6a drew: a container cap shrinks the surface and pushes the empty
   space OUTSIDE it, where it reads as an unfinished page; a content cap keeps the
   surface edge-to-edge and puts the space inside, where it reads as measure. */
.ij-progate:not(.ij-progate--workspace) .ij-progate-main {
    max-width: 720px;
}

/* Stacked below 960px, and NOT sticky there: a rail that pins itself after the
   pitch has already scrolled past is just a floating advert. */
.ij-progate-rail {
    display: flex;
    flex-direction: column;
    gap: var(--ij-space-4);
    min-width: 0;
}

/* Scoped to the workspace modifier on purpose: the media query keys on the
   VIEWPORT, so an unscoped rule would give the railless native gate a phantom
   second column inside its 720px cap on any Mac window wider than 960px. */
@media (min-width: 960px) {
    .ij-progate--workspace .ij-progate-grid {
        grid-template-columns: 1.35fr 1fr;
    }

    .ij-progate--workspace .ij-progate-rail {
        position: sticky;
        top: var(--ij-space-6);
        min-width: 340px;
    }
}

/* The rail borrows /connect's shipped surfaces so the Claude block is visibly the
   same object the user meets on /connect.

   Those two pages disagree about shape right now, and the rail is where it shows.
   Before this pass the borrowed card and the rail blocks matched by accident —
   both were surface + 1px border, so overriding only connect's radius was enough.
   Filling the rail blocks broke that: a white outlined card above two filled ones
   reads as two design systems in one column, which is worse than either.

   So the borrowed card takes the dialect here. What makes it "the same object" is
   the header, the mark, the prompt row and the link — all unchanged; a fill is not
   what carries recognition. The inner prompt row deliberately keeps connect's white
   surface: a light inset on a grouped gray background is the iOS pattern, not an
   inconsistency. When /connect gets its own pass these three declarations are what
   to delete. */
.ij-progate-rail .ij-connect-card,
.ij-pf-empty-rail .ij-connect-card {
    background: var(--ij-bg-gray);
    border: none;
    border-radius: 20px;
}

.ij-progate-rail-head {
    display: flex;
    align-items: center;
    gap: var(--ij-space-2);
    margin-bottom: var(--ij-space-2);
}

.ij-progate-rail-title {
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ij-text-secondary);
}

/* The Claude mark. --ij-lp-clay already exists and already has its dark
   override (#c96442 -> #d97757), so the rail adds no token. */
.ij-progate-claude-mark {
    flex: none;
    font-size: 15px;
    line-height: 1;
    color: var(--ij-lp-clay);
}

/* The block header's mark sits in a clay-tinted tile; the one inside the prompt
   row stays a bare glyph, so the two do not compete. */
.ij-progate-claude-badge {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 8px;
    background: color-mix(in srgb, var(--ij-lp-clay) 14%, transparent);
    color: var(--ij-lp-clay);
    font-size: 15px;
    line-height: 1;
}

.ij-progate-claude-title {
    font-size: 15px;
    font-weight: 600;
}

.ij-progate-rail-body {
    font-size: 13px;
    line-height: 1.5;
    color: var(--ij-text-secondary);
    margin-bottom: var(--ij-space-3);
}

.ij-progate-rail-block {
    background: var(--ij-bg-gray);
    border: none;
    border-radius: 20px;
    padding: 20px;
}

/* "Stays free, always" is the only block that is a commitment rather than a
   pitch, so it sits last and quietest — no border, so it reads as a footnote
   the company is signing rather than one more thing being sold. */
/* Still the quietest block, but the quiet is now carried by the ABSENCE of a
   heading rather than by being the only filled one — every rail block is filled
   in this dialect, so the promise needed a different way to stay a footnote. */
.ij-progate-rail-promise {
    background: var(--ij-bg-gray);
    border-radius: 20px;
    padding: 20px;
}

.ij-progate-free-chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ij-space-2);
}

/* Capsules on the iOS fill. They sit ON the promise block's gray, so they use the
   heavier 0.18 step — 0.12 over 0.12 is invisible. */
.ij-progate-free-chip {
    font-size: 12px;
    font-weight: 500;
    color: var(--ij-text-primary);
    background: rgba(120, 120, 128, 0.18);
    border: none;
    border-radius: 20px;
    padding: 4px 12px;
}

.ij-progate-connected {
    display: flex;
    align-items: center;
    gap: var(--ij-space-2);
    font-size: 13px;
    margin-bottom: var(--ij-space-2);
}

/* Native only: Claude stripped to description. No query, no link, no verb —
   see design 5a. A CTA here would send someone off to configure a connector for
   a feature they cannot use, which is exactly the "buy it on the web"
   implication guideline 3.1.1 forbids. */
.ij-progate-claude-note {
    display: flex;
    align-items: flex-start;
    gap: var(--ij-space-2);
    font-size: 12px;
    line-height: 1.5;
    color: var(--ij-text-secondary);
    margin-bottom: var(--ij-space-4);
}

.ij-progate-badge {
    display: inline-flex;
    align-items: center;
    gap: var(--ij-space-1);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: var(--ij-primary);
    background: color-mix(in srgb, var(--ij-primary) 14%, transparent);
    border-radius: 20px;
    padding: 3px 10px;
    margin-bottom: var(--ij-space-3);
}

/* No cap (6a): the headline never exceeds the left column at any width, and a
   440px cap forced two lines everywhere — including at 1920, where the column
   is ~980px and it comfortably fits on one. Line count is deliberately NOT
   monotonic: 1 line at 1920, 2 at 1280 and 1024, back to 1 at the 900 collapse,
   because the collapsed single column is wider than the 1024 board's
   two-column left. Budget for two lines; the narrow case is the tall one. */
.ij-progate-title {
    font-size: 1.5rem;
    font-weight: 600;
    letter-spacing: -0.02em;
    line-height: 1.15;
    margin-bottom: var(--ij-space-2);
}

.ij-progate-body {
    font-size: 17px;
    line-height: 1.5;
    color: var(--ij-text-secondary);
    max-width: 60ch;
    margin-bottom: var(--ij-space-6);
    text-wrap: pretty;
}

.ij-progate-preview {
    margin-bottom: var(--ij-space-4);
}

/* The head's own gray fill was how it separated from a white card. On a gray card
   it separates by rhythm instead — bottom padding above the first row's hairline,
   exactly like the currency card header. */
.ij-progate-sample-head {
    display: flex;
    align-items: center;
    gap: var(--ij-space-2);
    padding: 0 0 14px;
}

/* Tinted, like every other pill in this file since 14a. Neutral fill rather than
   a colour: "SAMPLE" is a label, not a status. */
.ij-progate-sample-badge {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: var(--ij-text-secondary);
    background: rgba(120, 120, 128, 0.12);
    border: none;
    border-radius: 20px;
    padding: 2px 9px;
}

/* Narrow = the 5a treatment: avatar, name over "TICKER · shares", and market
   value over the P&L pair. Grid rather than flex so the trailing figures
   actually align to the right edge — the previous flex version leaned on two
   class names (ij-pf-grow-narrow / ij-pf-trail-narrow) that exist in no
   stylesheet, so the rows packed left with a gap after them. */
.ij-progate-sample-row {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas:
        "avatar co mv"
        "avatar sh pl";
    column-gap: var(--ij-space-3);
    align-items: center;
    padding: var(--ij-space-3) 0;
    border-top: 0.5px solid var(--ij-divider);
}

.ij-progate-sample-avatar {
    grid-area: avatar;
}

.ij-progate-sample-co {
    grid-area: co;
    min-width: 0;
}

.ij-progate-sample-sh {
    grid-area: sh;
    min-width: 0;
}

.ij-progate-sample-mv {
    grid-area: mv;
    text-align: right;
}

.ij-progate-sample-pl {
    grid-area: pl;
    text-align: right;
    font-weight: 600;
    white-space: nowrap;
}

/* The ticker rides with the shares on one line when stacked; it moves under the
   company name once there are real columns. Two spans, one hidden per
   breakpoint — cheaper than reflowing the cell it lives in. */
.ij-progate-sample-tk-wide {
    display: none;
}

/* What the extra width earns (6a): above ~1280 the sample becomes a proper
   four-column grid — company, shares, market value, unrealized — which is what
   the real holdings table does at this width, so the sample keeps resembling
   the thing it is a sample of. Scoped to the workspace: the railless native
   gate has no second column and must keep the stacked treatment. */
@media (min-width: 1280px) {
    /* Proportional tracks, not auto: auto sizes each figure to its content and
       shoves the three of them against the right edge with a hole in the middle.
       The avatar keeps its own leading column here (the design nests it inside
       the company cell) — same four content groups, same result. */
    .ij-progate--workspace .ij-progate-sample-row {
        grid-template-columns: auto minmax(0, 2.4fr) 1fr 1.2fr 1.2fr;
        grid-template-areas: "avatar co sh mv pl";
        column-gap: var(--ij-space-4);
    }

    .ij-progate--workspace .ij-progate-sample-sh,
    .ij-progate--workspace .ij-progate-sample-mv {
        text-align: right;
        white-space: nowrap;
    }

    .ij-progate--workspace .ij-progate-sample-tk-wide {
        display: block;
    }

    .ij-progate--workspace .ij-progate-sample-tk-inline {
        display: none;
    }
}

.ij-progate-sample-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--ij-space-4);
    padding: 14px 0 0;
    border-top: 0.5px solid var(--ij-divider);
    font-size: 12px;
    color: var(--ij-text-secondary);
    flex-wrap: wrap;
}

.ij-progate-cta-row {
    display: flex;
    align-items: flex-start;
    gap: var(--ij-space-8);
    flex-wrap: wrap;
}

/* The gate's primary action is a MudButton, not .ij-pf-btn-primary, so it needs
   the capsule spelled out here or it would be the one square button left on a
   page of capsules. Scoped to the gate: this must not leak to MudButtons the rest
   of the app draws. */
.ij-progate .mud-button-filled {
    border-radius: 980px;
    padding: 8px 22px;
}

/* 5a moved this out of the CTA row and into the rail, so it is a titled list
   rather than a chip strip — each line now has room to say what it does. */
.ij-progate-bundle {
    display: flex;
    flex-direction: column;
    gap: var(--ij-space-3);
}

.ij-progate-bundle-item {
    display: flex;
    align-items: flex-start;
    gap: var(--ij-space-2);
}

.ij-progate-bundle-item .mud-icon-root {
    flex: none;
    color: var(--ij-gain);
}

.ij-progate-bundle-title {
    font-size: 13px;
    font-weight: 600;
}

.ij-progate-bundle-desc {
    font-size: 12px;
    line-height: 1.45;
    color: var(--ij-text-secondary);
}

/* Announced (7a): the sentence pair that replaces the CTA. Sits exactly where the
   button was — the reader has already scrolled past a working sample, so nothing
   above this line is hedged and it cannot be read as "feature unfinished". */
/* 14px, not 20px: this is a status block inside the main column, and the DCF card
   uses 14px for exactly that (dcf-verdict) against its own 20px shell. Keeping the
   two radii distinct is what stops a page of nested 20px boxes. */
.ij-progate-soon {
    padding: 16px;
    background: var(--ij-bg-gray);
    border-radius: 14px;
    margin-bottom: var(--ij-space-4);
}

.ij-progate-soon .mud-icon-root {
    flex-shrink: 0;
    color: var(--ij-text-secondary);
}

.ij-progate-soon-title {
    font-size: 15px;
    font-weight: 600;
    margin-bottom: var(--ij-space-1);
}

.ij-progate-soon-body {
    font-size: 13px;
    line-height: 1.5;
    color: var(--ij-text-secondary);
    max-width: 60ch;
}

/* Confirmed in place — no toast, no dialog: the block replaces itself, so the
   answer appears where the question was asked. Undo sits beside it because
   consent you cannot withdraw in the same breath isn't really one tap. */
.ij-progate-notified {
    display: flex;
    align-items: center;
    gap: var(--ij-space-3);
    flex-wrap: wrap;
}

.ij-progate-notified-label {
    display: inline-flex;
    align-items: center;
    gap: var(--ij-space-2);
    font-size: 15px;
    font-weight: 600;
    color: var(--ij-gain);
}

.ij-progate-notified-label .mud-icon-root {
    color: var(--ij-gain);
}

/* Undo borrows the connect link's colour and weight but is a <button>, so it needs
   the element's own chrome stripped. */
.ij-progate-undo {
    background: none;
    border: none;
    padding: 0;
    font: inherit;
    cursor: pointer;
}

.ij-progate-native-notice {
    padding: 14px 16px;
    background: var(--ij-bg-gray);
    border-radius: 14px;
    margin-bottom: var(--ij-space-4);
    font-size: 13px;
    line-height: 1.5;
}

.ij-progate-meanwhile {
    background: var(--ij-bg-gray);
    border: none;
    border-radius: 20px;
    padding: 20px;
    margin-bottom: var(--ij-space-2);
}

/* ── Opening-position grid ─────────────────────────────────────── */

.ij-pf-opening-grid {
    display: grid;
    grid-template-columns: minmax(200px, 2.4fr) 1fr 1.3fr 1.3fr 40px;
    gap: var(--ij-space-3);
    align-items: center;
    padding: var(--ij-space-2) 0;
}

/* The empty row no longer needs a background of its own: on the gray card it was
   invisible. It is distinguished the way the design distinguishes it — by its
   fields sitting at the LIGHTER fill, which reads as "not yet holding anything"
   rather than as a highlighted row. */
.ij-pf-opening-new {
    background: none;
}

.ij-pf-opening-hint {
    padding: 10px 0 14px;
    font-size: 12px;
    color: var(--ij-text-tertiary);
}

.ij-pf-opening-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--ij-space-6);
    padding: var(--ij-space-4) 0 0;
    border-top: 0.5px solid var(--ij-divider);
    flex-wrap: wrap;
}

.ij-pf-opening-asof {
    flex: none;
    max-width: 240px;
}

/* ── 14a: Mud fields as iOS filled boxes ───────────────────────────
   Same override technique upsert-dcf-dialog.css uses on its own Mud inputs
   (.ij-dcf-input), applied here through a descendant selector because these
   fields carry no per-field class and 14a changes no markup.

   The outlined <fieldset> border is what makes the row read as a spreadsheet;
   it goes, and the .mud-input itself becomes the box. Values are right-aligned
   in primary — the DCF dialog's rule that a typed number looks typed. */

.ij-pf-opening-grid .mud-input-control {
    margin: 0 !important;
}

.ij-pf-opening-grid .mud-input.mud-input-outlined {
    background: rgba(120, 120, 128, 0.24);
    border: 1px solid rgba(120, 120, 128, 0.4);
    border-radius: 8px;
    padding: 0 10px;
    transition: border-color 0.15s ease, background 0.15s ease;
}

.ij-pf-opening-grid .mud-input.mud-input-outlined:focus-within {
    border-color: var(--ij-primary);
    background: rgba(120, 120, 128, 0.3);
}

/* The fieldset draws the outline AND the label notch — both belong to the shape
   being replaced. */
.ij-pf-opening-grid .mud-input-outlined-border {
    display: none !important;
}

.ij-pf-opening-grid .mud-input-outlined input,
.ij-pf-opening-grid .mud-input-outlined .mud-input-slot {
    font-size: 14px;
    color: var(--ij-primary);
    padding: 6px 0 !important;
    height: auto !important;
    min-height: unset !important;
    overflow: hidden;
    text-overflow: ellipsis;
}

.ij-pf-opening-grid .ij-pf-num input,
.ij-pf-opening-grid .ij-pf-num .mud-input-slot {
    text-align: right;
}

/* MudBlazor ships `.mud-input>input.mud-input-root::placeholder{color:currentColor}`
   at (0,2,2). A plainer `input::placeholder` loses to it, and currentColor is the
   PRIMARY blue this block just gave typed values — so an empty row rendered its
   placeholder in the same colour as a real entry, which is exactly backwards.
   Matching Mud's own selector shape is what makes the override stick. */
.ij-pf-opening-grid .mud-input > input.mud-input-root::placeholder,
.ij-pf-opening-grid .mud-input > div.mud-input-slot.mud-input-root::placeholder {
    color: var(--ij-text-tertiary);
    opacity: 1;
}

/* An untouched row sits at the lighter fill — the design's "Pick a company" state. */
.ij-pf-opening-new .mud-input.mud-input-outlined {
    background: rgba(120, 120, 128, 0.12);
    border-color: rgba(120, 120, 128, 0.25);
}

/* Invalid = the DCF dialog's error ring, not a red outline the box no longer has. */
.ij-pf-opening-grid .mud-input-error .mud-input.mud-input-outlined,
.ij-pf-opening-grid .mud-input.mud-input-outlined.mud-input-error {
    border-color: var(--ij-loss);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--ij-loss) 14%, transparent);
}

.ij-pf-opening-grid .ij-pf-field-error {
    text-align: right;
    font-size: 11px;
}

/* The as-of date is the gray capsule from the DCF date row. Its Mud label floats
   above the box once a date is set (there is always one — it defaults to today),
   so the field stays labelled without the outlined notch that carried the label. */
.ij-pf-opening-asof .mud-input.mud-input-outlined {
    background: rgba(120, 120, 128, 0.16);
    border: none;
    border-radius: 8px;
    padding: 0 12px;
}

.ij-pf-opening-asof .mud-input-outlined-border {
    display: none !important;
}

.ij-pf-opening-asof .mud-input-outlined input {
    font-size: 13.5px;
    padding: 7px 0 !important;
    height: auto !important;
    min-height: unset !important;
}

/* ── Reconcile diff ────────────────────────────────────────────── */

.ij-pf-diff {
    border: 1px solid var(--ij-divider);
    border-radius: var(--ij-radius);
    overflow: hidden;
    margin-bottom: var(--ij-space-4);
    font-variant-numeric: tabular-nums;
}

.ij-pf-diff-grid {
    display: grid;
    grid-template-columns: 0.9fr 1.1fr 24px 1.1fr 1fr;
    gap: var(--ij-space-3);
    align-items: center;
    padding: var(--ij-space-2) var(--ij-space-3);
    border-bottom: 1px solid var(--ij-divider);
    font-size: 13px;
}

.ij-pf-diff-head {
    background: var(--ij-bg-gray);
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ij-text-secondary);
}

.ij-pf-diff-next {
    font-weight: 600;
}

/* A consequence, not a warning: nothing is deleted, so there is no alarm colour. */
.ij-pf-consequence {
    display: flex;
    gap: var(--ij-space-2);
    padding: var(--ij-space-3);
    background: var(--ij-bg-gray);
    border-radius: var(--ij-radius);
    margin-bottom: var(--ij-space-4);
    font-size: 13px;
    line-height: 1.5;
}

/* ── Watching / Owning segment (#524 M4, device only) ──────────── */

/* Web does NOT get this: it has the 88px rail, and a segment plus a rail item
   pointing at the same route is one entry point too many. */

.ij-pf-segment {
    display: flex;
    gap: var(--ij-space-1);
    padding: var(--ij-space-1);
    margin: var(--ij-space-3) var(--ij-space-4);
    background: var(--ij-field);
    border-radius: var(--ij-radius);
}

.ij-pf-segment-item {
    flex: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--ij-space-1);
    text-align: center;
    font-family: inherit;
    font-size: 15px;
    font-weight: 500;
    color: var(--ij-text-secondary);
    background: none;
    border: 1px solid transparent;
    border-radius: var(--ij-radius);
    padding: var(--ij-space-2) 0;
    cursor: pointer;
}

.ij-pf-segment-active {
    font-weight: 600;
    color: var(--ij-text-primary);
    background: var(--ij-surface);
    border-color: var(--ij-divider);
}

.ij-pf-owning-meta {
    padding: 0 var(--ij-space-4) var(--ij-space-3);
    font-size: 12px;
    color: var(--ij-text-secondary);
}

.ij-pf-owning-loading,
.ij-pf-owning-empty {
    padding: var(--ij-space-4);
}

.ij-pf-owning-empty {
    text-align: center;
    padding: var(--ij-space-8) var(--ij-space-4);
}

/* Shown once, ever — see the Preferences key in Watchlists.razor. */
.ij-pf-whats-new {
    display: flex;
    align-items: center;
    gap: var(--ij-space-2);
    margin: var(--ij-space-3) var(--ij-space-4) 0;
    padding: var(--ij-space-2) var(--ij-space-3);
    background: var(--ij-primary-tint);
    color: var(--ij-primary);
    border-radius: var(--ij-radius);
}

.ij-pf-whats-new-text {
    flex: 1;
    font-size: 13px;
    line-height: 1.4;
    color: var(--ij-text-primary);
}


/* ── Narrow overrides ──────────────────────────────────────────── */
/* Last in the file on purpose: these are overrides, and everything above
   declares at the same specificity. When this block sat higher up, the base
   .ij-progate padding silently won on a 390pt phone. */

@media (max-width: 767px) {
    /* 20px of card inset on each side costs a tenth of a 390pt viewport. The
       radius stays — it is the shape, not the padding, that carries the dialect. */
    .ij-pf-card:not(.ij-progate-preview) {
        padding: 16px;
    }

    /* The trailing track is reserved only where something actually rests in it —
       under a COARSE pointer, below. On a narrow desktop window the pointer is
       still fine, the actions are still the hover pill, and a reserved column
       there is 36px of empty gutter taken from a 375px viewport. */
    .ij-pf-holdings-grid {
        /* The identity track needs a FLOOR, not just a share. At minmax(0, 1fr)
           it resolves to whatever the value column leaves, and the value column
           is `auto` — max-content. Measured on a 375px phone: the P&L cell took
           the whole row and .ij-pf-identity-text came back exactly 0px wide, so
           the company name rendered at zero width while its market value kept
           full size. A floor makes the numbers give way instead. */
        grid-template-columns: minmax(116px, 1fr) auto;
        grid-template-areas:
            "identity mv"
            "shares   pl";
        gap: var(--ij-space-1) var(--ij-space-3);
        align-items: start;
    }

    .ij-pf-c-identity { grid-area: identity; }
    .ij-pf-c-shares   { grid-area: shares; text-align: left; }
    .ij-pf-c-mv       { grid-area: mv; }
    .ij-pf-c-pl       { grid-area: pl; }
    .ij-pf-c-last     { display: none; }

    /* Shares and average cost become one sub-line under the company. */
    .ij-pf-c-shares > div { display: inline; }

    .ij-pf-c-shares > div + div::before {
        content: " · ";
    }

    .ij-pf-journal-grid {
        grid-template-columns: auto minmax(0, 1fr) auto 32px;
        grid-template-areas:
            "type ticker total menu"
            "date qty    total menu";
        gap: var(--ij-space-1) var(--ij-space-3);
        align-items: start;
    }

    .ij-pf-c-type   { grid-area: type; align-self: center; }
    .ij-pf-c-ticker { grid-area: ticker; }
    .ij-pf-c-date   { grid-area: date; white-space: nowrap; }
    .ij-pf-c-qty    { grid-area: qty; text-align: left; }
    .ij-pf-c-total  { grid-area: total; align-self: center; }

    /* Column heads name six columns that no longer exist on this layout. */
    .ij-pf-colhead {
        display: none;
    }

    .ij-pf-title {
        font-size: 1.5rem;
        letter-spacing: -0.02em;
    }

    .ij-pf-alloc-label {
        display: none;
    }

    /* A boundary label that clips mid-word stops being a sentence. */
    .ij-pf-boundary {
        flex-wrap: wrap;
    }

    .ij-pf-boundary-label {
        flex: 1 1 100%;
    }

    .ij-pf-boundary-rule {
        display: none;
    }

    .ij-pf-opening-grid {
        grid-template-columns: minmax(0, 1fr) 32px;
        gap: var(--ij-space-2);
    }


    .ij-pf-opening-footer {
        gap: var(--ij-space-3);
    }
}

/* ── Owning segment chrome (#524 M4, device only) ──────────────── */

.ij-pf-owning-bar {
    display: flex;
    align-items: center;
    gap: var(--ij-space-3);
    padding: 0 var(--ij-space-4) var(--ij-space-3);
}

.ij-pf-owning-bar .ij-pf-owning-meta {
    flex: 1;
    padding: 0;
}

.ij-pf-owning-journal-head {
    padding: var(--ij-space-6) var(--ij-space-4) var(--ij-space-3);
}

/* ── The value layer (#1082 / 18A) ─────────────────────────────── */
/* Pro appends ONE column after Unrealized; the free template above is untouched,
   so nothing a free user reads ever shifts by a pixel. 12a's four-numeric-column
   ceiling bends here knowingly — this column is the page's point for a Pro user. */

.ij-pf-holdings-grid--mos {
    grid-template-columns: minmax(180px, 2fr) 0.85fr 0.8fr 1.15fr 1.1fr 1.15fr 28px;
}

/* The value cell: a 13px stat over its verdict word — the DCF card's verdict
   vocabulary at row scale. The word travels with the number everywhere, so
   colour is never the only signal. */
.ij-pf-c-mos .ij-pf-mos-num {
    font-size: 13px;
    font-weight: 600;
}

.ij-pf-c-mos .ij-pf-mos-word {
    font-size: 12px;
    font-weight: 500;
    margin-top: 1px;
}

/* The card's existing success/warning/error trio — no new tokens. P&L keeps
   ij-gain/ij-loss: two greens answering two different questions (how the trade
   is doing vs what the thing is worth) is deliberate, and the verdict word is
   what disambiguates them. */
.ij-pf-mos--under { color: var(--mud-palette-success); }
.ij-pf-mos--fair  { color: var(--mud-palette-warning); }
.ij-pf-mos--over  { color: var(--mud-palette-error); }

/* Un-valued: the honesty dash, tertiary like the cash row's — the column asks a
   question this row can't answer yet. Never a button. */
.ij-pf-mos--none {
    color: var(--ij-text-tertiary);
}

.ij-pf-mos--none .ij-pf-mos-num {
    font-weight: 400;
}

/* The priced-for line rides the card header's underside, right-aligned beneath
   the subtotal it qualifies — a rate, not a total, so it never competes with
   Pf_NoCombinedTotal. The negative margin eats part of the header's fixed 14px
   so the pair reads as one block, like the mock's 2px+12px split. */
.ij-pf-priced-for {
    display: flex;
    justify-content: flex-end;
    margin-top: -8px;
    padding-bottom: var(--ij-space-3);
    font-size: 12px;
    color: var(--ij-text-secondary);
}

.ij-pf-priced-for b {
    color: var(--ij-text-primary);
    font-weight: 600;
    margin: 0 3px;
}

/* Thesis: one glyph-weight quiet after the ticker, linking to the argument.
   Drift ("{n} trades since") reuses the cash row's staleness grammar. */
.ij-pf-ticker {
    display: flex;
    align-items: center;
    gap: 5px;
    min-width: 0;
}

.ij-pf-thesis {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    color: var(--ij-text-tertiary);
    white-space: nowrap;
}

.ij-pf-thesis:hover {
    color: var(--ij-text-secondary);
}

.ij-pf-thesis svg {
    width: 13px;
    height: 13px;
    flex: none;
}

.ij-pf-thesis-drift {
    font-size: 11px;
}

/* ProLayerNote — the one-line, in-page sibling of ProGate: icon + sentence +
   at most one link, in the footnote zone's own voice. No banner surface. The
   migration variant adds an inline text action at the right edge. */
.ij-pf-layer-note {
    display: flex;
    align-items: flex-start;
    gap: var(--ij-space-2);
    padding: 14px 0 0;
    color: var(--ij-text-secondary);
    font-size: 13px;
    line-height: 1.5;
}

.ij-pf-layer-note > .mud-icon-root {
    flex: none;
    font-size: 20px;
    margin-top: 1px;
}

.ij-pf-layer-note-text {
    flex: 1;
    min-width: 0;
}

.ij-pf-layer-note-text a {
    color: var(--ij-primary);
    font-weight: 600;
}

.ij-pf-layer-note-dismiss {
    flex: none;
}

@media (max-width: 767px) {
    /* At phone width the column stops being a column: it becomes the row's
       third line, number and verdict word joined on one line. Shares' area
       grows a row so the left edge stays one block. */
    .ij-pf-holdings-grid--mos {
        grid-template-columns: minmax(116px, 1fr) auto;
        grid-template-areas:
            "identity mv"
            "shares   pl"
            "shares   mos";
    }

    .ij-pf-holdings-grid--mos .ij-pf-c-mos {
        grid-area: mos;
        text-align: right;
    }

    .ij-pf-holdings-grid--mos .ij-pf-mos-num,
    .ij-pf-holdings-grid--mos .ij-pf-mos-word {
        display: inline;
        font-size: 12px;
        font-weight: 500;
    }

    .ij-pf-holdings-grid--mos .ij-pf-mos-word::before {
        content: " · ";
    }

    /* The priced-for line keeps its coverage clause; left-aligned under the
       header once right-alignment has nothing to align with. */
    .ij-pf-priced-for {
        justify-content: flex-start;
        margin-top: -6px;
    }
}

/* ── Accounts (20A) ─────────────────────────────────────────────────────────
   The card becomes the account at 2+ accounts. Badges are the existing capsule
   fill, section heads reuse the card-header type ramp, the summary strip is
   plain text on the page background — zero new tokens. */

.ij-pf-header-actions {
    display: flex;
    align-items: center;
    gap: var(--ij-space-3);
}

/* The page summary strip — per-currency totals across accounts, the one legal
   cross-account sum: figures side by side, never merged. */
.ij-pf-sum-strip {
    display: flex;
    align-items: stretch;
    gap: var(--ij-space-6);
    flex-wrap: wrap;
    margin-bottom: var(--ij-space-5);
}

.ij-pf-sum-block {
    min-width: 0;
}

.ij-pf-sum-label {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--mud-palette-text-secondary);
    margin-bottom: 4px;
}

.ij-pf-sum-total {
    font-size: 22px;
    font-weight: 700;
    letter-spacing: -0.02em;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
}

.ij-pf-sum-pl {
    font-size: 13px;
    font-weight: 600;
    display: flex;
    align-items: center;
    margin-top: 2px;
    font-variant-numeric: tabular-nums;
}

.ij-pf-sum-priced {
    font-size: 12px;
    color: var(--mud-palette-text-secondary);
    margin-top: 3px;
}

.ij-pf-sum-priced b {
    color: var(--mud-palette-text-primary);
    font-weight: 600;
}

.ij-pf-sum-divider {
    width: 1px;
    background: var(--mud-palette-divider);
}

.ij-pf-sum-divider:last-child {
    display: none;
}

/* Account-card header: the name where the code was, the code demoted to a
   capsule badge. The name takes the ellipsis; the value keeps its width. */
.ij-pf-acct-head {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 0 0 12px;
}

@media (max-width: 599.98px) {
    /* Phone only: the siblings drop to a second line instead of squeezing the
       name to its 96px floor. At desktop widths a second line would be a
       regression, not a rescue. */
    .ij-pf-acct-head {
        flex-wrap: wrap;
    }
}

.ij-pf-acct-name {
    font-size: 17px;
    font-weight: 700;
    letter-spacing: -0.02em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    /* The collapse floor, on the element it protects rather than on its wrapper
       (#1435) — see .ij-pf-acct-name-line, which used to carry a 96px one and now
       sizes to content so a short name sits 10px from its badge instead of 52px.
       This was `min-width: 0`, which paired with that wrapper floor; with the
       floor moved here, 0 would let the name vanish under pressure exactly as it
       did before the wrapper rule existed. 6ch keeps a few characters and the
       ellipsis. ONE declaration: a second one further down this block is what
       silently ate the first attempt at this fix. */
    min-width: 6ch;
}

.ij-pf-acct-badge {
    flex: none;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.03em;
    padding: 2px 9px;
    border-radius: 20px;
    /* 0.24, the fill the #1435 handoff specifies. It was 0.12, and the tax chip
       below it 0.08 — faint enough that on a near-black card the pill had no
       visible shape at all, only text. That passed unnoticed while the card ALSO
       stated its currency in 13px bold section headers down the table; flattening
       removed those, so this pill is now the only place the card says which
       currency it is in, and it has to look like something. */
    background: rgba(120, 120, 128, 0.24);
    color: var(--mud-palette-text-secondary);
    white-space: nowrap;
}

/* The tax chip rides the currency badge's shape so a row never grows a second
   visual language — only the tint differs, and it stays inside the neutral
   secondary-text ramp because this is a label, not a verdict. */
/* Inherits the currency badge's fill now: at 0.08 this one was fainter still,
   and two pills side by side that differ only in how nearly invisible they are
   is not a distinction anybody can use. They are told apart by their WORDS. */
.ij-pf-acct-tax-badge {
    color: var(--mud-palette-text-secondary);
}

.ij-pf-acct-tax {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-top: 10px;
}

.ij-pf-acct-tax-row {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

/* The name and its pencil. 26A made the name itself click-to-edit; it is plain
   text now and the button beside it is the control. Revealed on hover, on keyboard
   focus, and always on coarse pointers — this component also renders on the device
   head, where there is no hover at all. */
.ij-pf-acct-name-line {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    /* A FLOOR, not min-width: 0 — the same fix the manage-accounts sheet's name
       row carries, for the same reason. Everything to the right of the name in
       .ij-pf-acct-head is flex: none (currency badge, tax badge, holding count,
       the ⋯), so on a narrow card the only shrinkable item is the name — and at
       min-width: 0 it shrank to nothing, taking even its ellipsis with it. The
       card then showed two badges and a count with no account on them.

       THE FLOOR MOVED TO .ij-pf-acct-name (#1435). A fixed 96px here was
       calibrated when this line also held the 32px pencil: a SHORT name padded
       the line out to the floor and the slack sat harmlessly under the pencil.
       With the pencil moved after the badges that slack became visible — 42px
       between "Margin" and its currency badge, where longer names sat at 11px.

       min(96px, max-content) looks like the fix and is NOT: Chromium rejects it
       for min-width, so the declaration is dropped, this resolves to auto, and
       an auto minimum on a flex item whose child has overflow:hidden is ZERO —
       the collapse above, back again, silently. Measured: the line fell to 20px
       under pressure. Flooring the NAME instead keeps the line content-sized
       (no slack for a short name) while giving the automatic minimum something
       real to compute from. */
    min-width: auto;
}

.ij-pf-acct-name-edit {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    flex: none;
    border: 0;
    background: transparent;
    color: var(--ij-text-tertiary);
    cursor: pointer;
    opacity: 0;
    transition: opacity 0.12s ease, color 0.12s ease;
}

/* The account card's pencil moved OUT of the name line (#1435) — it edits the
   badges beside it now, so it sits after them and reveals on the whole HEADER's
   hover, not the name's. The solo currency card's pencil is still inside a name
   line, which is why both selectors stay. */
.ij-pf-acct-name-line:hover .ij-pf-acct-name-edit,
.ij-pf-acct-head:hover .ij-pf-acct-edit-btn,
.ij-pf-ccy-head:hover .ij-pf-acct-edit-btn,
.ij-pf-acct-name-edit:focus-visible {
    opacity: 1;
}

.ij-pf-acct-name-edit:hover {
    color: var(--ij-text-secondary);
}

@media (hover: none) {
    .ij-pf-acct-name-edit {
        opacity: 1;
    }
}

.ij-pf-acct-name-input {
    font: inherit;
    font-size: 17px;
    font-weight: 700;
    letter-spacing: -0.02em;
    border: 2px solid var(--mud-palette-primary);
    border-radius: 9px;
    padding: 1px 8px;
    background: var(--mud-palette-surface);
    color: var(--mud-palette-text-primary);
    min-width: 0;
    max-width: 100%;
}

.ij-pf-acct-name-input:focus {
    outline: none;
}

/* The per-currency section head (.ij-pf-acct-sec-*) is GONE with #1435 — the
   account card is one flat table now, so there are no sections to head and no
   subtotals to put in them. The currency each row belongs to moved onto the row
   itself; see .ij-pf-ticker-ccy. */

/* The row's own currency, in a multi-currency account. Quiet, and after the
   ticker rather than before it: the ticker is what the reader is scanning for,
   and the currency only disambiguates once they have found it. */
.ij-pf-ticker-ccy {
    color: var(--ij-text-secondary);
}

/* The just-created account card asserts nothing: quiet sentence + ghost row. */
.ij-pf-acct-empty-body {
    font-size: 13px;
    color: var(--mud-palette-text-secondary);
    padding-bottom: 4px;
}

.ij-pf-acct-empty-cash {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 0 2px;
    border-top: 0.5px solid var(--mud-palette-divider);
    margin-top: 10px;
}

/* The journal's account line — an address, not an event: quiet under the date. */
.ij-pf-jrn-acct {
    font-size: 12px;
    color: var(--mud-palette-text-disabled);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* The trade dialog's account picker caption + field error reuse. */
.ij-pf-acct-caption {
    font-size: 12px;
    color: var(--mud-palette-text-secondary);
    margin-top: 4px;
}

.ij-pf-acct-option {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    width: 100%;
}

/* ── The accounts sheet (compact sheet, 17a's law) ── */

.ij-pf-acct-sheet-row {
    position: relative;
    padding: 10px 0;
    border-top: 0.5px solid var(--mud-palette-divider);
}

.ij-pf-acct-sheet-row--dragging {
    opacity: 0.4;
}

/* Task 13: the drag handle / name / badge / value / inline actions line — split
   out from .ij-pf-acct-sheet-row so the archive caption below (rule + why,
   always together, no MudMenu popup to hide it in) can sit on its own line
   under the same row. */
.ij-pf-acct-sheet-line {
    display: flex;
    align-items: center;
    gap: 10px;
}

.ij-pf-acct-drag {
    flex: none;
    color: var(--mud-palette-text-disabled);
    cursor: grab;
}

.ij-pf-acct-sheet-name {
    font-size: 15px;
    font-weight: 500;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
    flex: 1;
}

.ij-pf-acct-sheet-value {
    flex: none;
    font-size: 12px;
    color: var(--mud-palette-text-secondary);
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

/* Fix round 1 (2026-08-28): at phone width the row's rigid siblings — the
   currency badge, the tax chip, the value, and Rename/Archive — never shrink
   (flex: none), so a second badge starved the name to 0px instead of
   truncating. The name is the row's identity and must never lose the fight
   for space: give it a floor no combination of siblings can erase, and let
   the row wrap so whichever siblings don't fit drop to a second line instead
   of forcing horizontal overflow. Nothing is hidden — everything still
   renders, just not always on one line.

   Fix round 2: the floor is UNCONDITIONAL, not viewport-keyed. The constraint
   is the CONTAINER's width, not the window's — the sheet is MaxWidth.Small
   (~600px), so its content is ~552px wide at EVERY viewport above 600px, and
   a viewport-keyed floor switched itself off exactly where the row is still
   narrow (the 601–760px band). 96px is harmless at any width: the name is the
   row's only flex:1 element, so the floor binds only when the siblings would
   otherwise have crushed it. Wrapping stays phone-only — at desktop widths a
   second line would be a regression, not a rescue. */
.ij-pf-acct-sheet-name {
    min-width: 96px;
}

@media (max-width: 599.98px) {
    .ij-pf-acct-sheet-line {
        flex-wrap: wrap;
    }
}

.ij-pf-acct-editor {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 4px 0;
}

.ij-pf-acct-ccy-row {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
}

.ij-pf-acct-ccy-label {
    font-size: 13px;
    color: var(--mud-palette-text-secondary);
}

.ij-pf-acct-create {
    border-top: 0.5px solid var(--mud-palette-divider);
    padding-top: 14px;
    margin-top: 2px;
}

.ij-pf-acct-create-label {
    font-size: 10px;
    font-weight: 500;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--mud-palette-text-secondary);
    margin-bottom: 10px;
}

/* Task 13: archive's consequence caption, now a line of its own under the row
   (the MudMenu popup it used to live inside is gone) — the rule and the why,
   always shown together, on both the empty and non-empty account. */
.ij-pf-acct-archive-caption {
    font-size: 11px;
    line-height: 1.4;
    color: var(--mud-palette-text-disabled);
    white-space: normal;
    margin-top: 4px;
}

.ij-pf-acct-reorder-hint {
    font-size: 12px;
    color: var(--mud-palette-text-disabled);
    margin-top: 14px;
}

@media (max-width: 599.98px) {
    /* The strip stacks its currency blocks side by side at phone width; the
       name truncates, the value never does. */
    .ij-pf-sum-strip {
        gap: var(--ij-space-5);
    }

    .ij-pf-sum-total {
        font-size: 17px;
    }

    .ij-pf-sum-divider {
        display: none;
    }
}

/* ── The account at the door (21A) ──────────────────────────────────────────
   /portfolio/opening gains the account block, the self-answering currency
   segment, and the save-and-add-another pass. Zero new tokens. */

.ij-pf-opening-account {
    background: var(--ij-field, var(--mud-palette-background-grey));
    border-bottom: 1px solid var(--mud-palette-divider);
    margin: -20px -20px 16px;
    padding: 18px 20px;
}

.ij-pf-opening-account-head {
    font-size: 13px;
    font-weight: 600;
    margin-bottom: 12px;
}

.ij-pf-opening-account-fields {
    display: flex;
    gap: 20px;
    align-items: flex-start;
    flex-wrap: wrap;
}

.ij-pf-opening-account-name {
    flex: 1;
    min-width: 220px;
    max-width: 340px;
}

.ij-pf-opening-field-label {
    font-size: 11px;
    color: var(--mud-palette-text-secondary);
    margin-bottom: 4px;
}

/* "Required", riding the label rather than shouting from a second line — the
   field is prefilled, so this is a statement about what emptying it costs. */
.ij-pf-field-required {
    margin-left: 6px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-size: 10px;
    color: var(--ij-text-secondary, var(--mud-palette-text-secondary));
    opacity: 0.75;
}

/* The currency segment — a READOUT set by the first position. Not IjSegmented:
   it needs an unset state and a refused-in-place state that control doesn't have. */
.ij-pf-ccy-seg {
    display: inline-flex;
    background: var(--ij-field, var(--mud-palette-background-grey));
    border: 1px solid var(--mud-palette-divider);
    border-radius: 9px;
    padding: 2px;
    gap: 2px;
}

.ij-pf-ccy-seg-btn {
    font: inherit;
    font-size: 13px;
    padding: 6px 16px;
    border: none;
    border-radius: 7px;
    background: transparent;
    color: var(--mud-palette-text-secondary);
    cursor: pointer;
}

.ij-pf-ccy-seg-btn--on {
    font-weight: 600;
    background: var(--mud-palette-surface);
    color: var(--mud-palette-text-primary);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
}

/* Blocked ≠ disabled: still clickable, and the click states the reason in the
   caption — a currency control must never be a delete button. */
.ij-pf-ccy-seg-btn--blocked {
    color: var(--mud-palette-action-disabled);
    text-decoration: line-through;
}

.ij-pf-opening-seg-caption {
    font-size: 11px;
    color: var(--mud-palette-text-secondary);
    margin-top: 5px;
}

.ij-pf-opening-seg-caption--widened {
    color: var(--mud-palette-primary);
    font-weight: 500;
}

/* 22A — the stack. A COLLAPSED block is the same line it will render as on
   /portfolio, so the shape the user agrees to is the shape they'll live with.
   Collapsing persists nothing. */
.ij-pf-opening-collapsed {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    background: var(--mud-palette-surface);
    border: 1px solid var(--mud-palette-divider);
    border-radius: var(--ij-radius);
    padding: 14px 20px;
    /* 23A: no margin of its own — the seam belongs to the container's gap. */
}

/* The whole line is the reopen affordance — a collapsed block is a preview, not
   a commitment, so it must be one click back. */
.ij-pf-opening-collapsed-main {
    font: inherit;
    display: flex;
    align-items: center;
    /* Explicit: a <button> centres its content by default, which would float
       the name into the middle of a full-width row. */
    justify-content: flex-start;
    gap: 10px;
    min-width: 0;
    flex: 1;
    padding: 0;
    border: none;
    background: none;
    color: inherit;
    text-align: left;
    cursor: pointer;
}

.ij-pf-opening-caret {
    color: var(--mud-palette-text-disabled);
    font-size: 12px;
    flex: none;
}

.ij-pf-opening-caret-btn {
    font: inherit;
    font-size: 12px;
    padding: 0;
    border: none;
    background: none;
    color: var(--mud-palette-text-secondary);
    cursor: pointer;
    flex: none;
}

/* The open block's header: ordinal + name, so two open blocks are never
   ambiguous. */
.ij-pf-opening-block-head {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: -20px -20px 0;
    padding: 12px 20px;
    border-bottom: 1px solid var(--mud-palette-divider);
}

.ij-pf-opening-ordinal {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    padding: 3px 8px;
    border-radius: 6px;
    background: var(--ij-field, var(--mud-palette-background-grey));
    color: var(--mud-palette-text-secondary);
    flex: none;
}

.ij-pf-opening-block-name {
    font-size: 14px;
    font-weight: 500;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
}

.ij-pf-opening-untitled {
    font-size: 14px;
    color: var(--mud-palette-text-disabled);
}

/* The card footer stopped being a save bar: this account's subtotal + Collapse.
   23A: 16px below the subtotal row so Collapse isn't sitting on the card edge. */
.ij-pf-opening-block-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    flex-wrap: wrap;
    border-top: 1px solid var(--mud-palette-divider);
    margin: 12px -20px -20px;
    padding: 12px 20px var(--ij-space-4);
}

/* Permanent furniture, never behind a save — the row sits where the next block
   will appear, so the affordance and the result share an address. */
.ij-pf-opening-add {
    font: inherit;
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    /* 23A: the stack's gap separates it from the block above — see .ij-pf-opening-stack. */
    padding: 15px 20px;
    border: 1px dashed var(--mud-palette-divider);
    border-radius: var(--ij-radius);
    background: none;
    color: var(--mud-palette-text-disabled);
    text-align: left;
    cursor: default;
}

.ij-pf-opening-add--on {
    border-color: var(--mud-palette-primary);
    background: var(--ij-primary-tint, transparent);
    color: var(--mud-palette-primary);
    cursor: pointer;
}

.ij-pf-opening-add-label {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 14px;
    font-weight: 600;
}

.ij-pf-opening-add-plus {
    font-size: 16px;
    line-height: 1;
}

/* One primary for the whole stack, pinned so it is reachable at four accounts. */
.ij-pf-opening-savebar {
    position: sticky;
    bottom: 0;
    z-index: 2;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 24px;
    flex-wrap: wrap;
    margin-top: var(--ij-space-8);
    padding: 16px 0;
    border-top: 1px solid var(--mud-palette-divider);
    background: var(--mud-palette-background);
}

.ij-pf-opening-savebar-totals {
    font-size: 14px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.ij-pf-opening-saved-name {
    font-size: 15px;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.ij-pf-opening-saved-actions {
    display: flex;
    align-items: center;
    gap: 16px;
    flex: none;
}

.ij-pf-opening-saved-value {
    font-size: 15px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* Accounts already in the ledger, listed above the stack when the page is
   reached again (22A). Deliberately the SAME collapsed line as a folded block —
   it is the shape the account being typed will take. Which makes the two
   groups indistinguishable at a glance, so each one is LABELLED
   (.ij-pf-opening-existing-head / .ij-pf-opening-stack-head) rather than
   separated by a tint: a folded block read as "already saved" is a user who
   navigates away believing their positions are in the ledger. */
.ij-pf-opening-existing-main {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
    flex: 1;
}

.ij-pf-opening-existing-head,
.ij-pf-opening-stack-head {
    padding: var(--ij-space-2) 0;
    font-size: 10px;
    font-weight: 500;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ij-text-secondary);
}

/* Only ever rendered beneath the saved list, so it needs the air that separates
   the two groups. */
.ij-pf-opening-stack-head {
    padding-top: var(--ij-space-4);
}

/* ── 23A: the stack needs air, and the seam has to read as a seam ───────────
   In the build the two blocks touched, so the eye read one long card with a
   stray ACCOUNT 2 label inside it: two rounded corners meeting produce a pinch,
   not a gap, and Collapse ended up sitting on what looked like Account 2's top
   edge. The fix is spacing, and it is owned by the CONTAINER — per-block margins
   are what allowed the seam to collapse in the first place, and a single gap
   means adding a block never changes the rhythm. */
.ij-pf-opening-saved-list,
.ij-pf-opening-stack {
    display: flex;
    flex-direction: column;
}

/* The already-saved accounts are context, not stack: they keep the tighter
   rhythm a read-only list wants. */
.ij-pf-opening-saved-list {
    gap: 10px;
}

/* One value for every seam in the stack: block↔block, and block↔add-another. */
.ij-pf-opening-stack {
    gap: var(--ij-space-6);
}

/* The only non-spacing change in 23A, and it earns itself by making "where does
   account 2 start" answerable at a glance. Marks the block being typed, so it
   moves rather than accumulating. Selector doubled up to out-specify
   `.ij-pf-card:not(.ij-progate-preview){border:none}` above. */
.ij-pf-card.ij-pf-opening-block--active {
    border-top: 6px solid var(--mud-palette-primary);
}

/* The average-cost error reserves its line whether or not it speaks, so the grid
   never shifts when it arrives (23A). visibility, not opacity: it must also stay
   out of the accessibility tree while silent. */
.ij-pf-field-error--reserved {
    visibility: hidden;
}

/* That reserved line makes the average-cost CELL taller than its siblings, and a
   centred grid then pushes its field up off the line Company and Shares sit on.
   So a position row top-aligns and the two cells that carry no field are dropped
   onto the field's text instead — the shape 23A's own mock uses. Scoped to
   position rows: the cash strip shares .ij-pf-opening-grid/.ij-pf-row and has no
   error line to reserve, so centring is still right there. */
.ij-pf-opening-position-row {
    align-items: start;
}

/* Half the 40px field minus half the line's own height. */
.ij-pf-opening-position-row .ij-pf-mv {
    padding-top: 10px;
}

/* The remove button is 30px against the field's 40. */
.ij-pf-opening-position-row .ij-pf-row-action {
    padding-top: 5px;
}

/* .ij-pf-opening-actions / .ij-pf-btn-secondary retired with 21A's two-button
   card footer — 22A has exactly one primary, on the page. */

/* The portfolio's own name (21A): at rest a title, hover a dashed hairline,
   editing an outlined field in the same type. */
.ij-pf-title-input {
    font: inherit;
    font-size: 2rem;
    font-weight: 600;
    letter-spacing: -0.025em;
    line-height: 1.1;
    border: 2px solid var(--mud-palette-primary);
    border-radius: 9px;
    padding: 2px 10px;
    background: var(--mud-palette-surface);
    color: var(--mud-palette-text-primary);
    min-width: 0;
    max-width: 100%;
}

.ij-pf-title-input:focus {
    outline: none;
}

@media (max-width: 599.98px) {
    /* The segment goes full width at 390 — « Les deux » sets the minimum. */
    .ij-pf-ccy-seg {
        display: flex;
        width: 100%;
    }

    .ij-pf-ccy-seg-btn {
        flex: 1;
        padding: 10px 0;
    }

    .ij-pf-opening-account-name {
        max-width: none;
    }

    /* At 390 the save bar stacks its totals above the full-width primary, still
       pinned to the bottom of the viewport. */
    .ij-pf-opening-savebar {
        flex-direction: column;
        align-items: stretch;
        gap: 10px;
        margin-top: 20px;
    }

    /* 23A's rhythm, tightened for the phone. */
    .ij-pf-opening-stack {
        gap: var(--ij-space-4);
    }

    .ij-pf-opening-savebar .ij-pf-btn-primary {
        width: 100%;
        text-align: center;
    }

    .ij-pf-opening-add {
        justify-content: center;
    }
}

/* The restored-draft line (22A open question 1): one quiet row above the stack,
   never a modal — the user is being told what happened, not asked. */
.ij-pf-opening-draft {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    margin-bottom: 12px;
    padding: 10px 16px;
    border: 1px solid var(--mud-palette-divider);
    border-radius: var(--ij-radius);
    background: var(--ij-field, var(--mud-palette-background-grey));
    font-size: 13px;
    color: var(--mud-palette-text-secondary);
}

/* ═══════════════════════════════════════
   The title row and the switch (25A #Task 11).

   The open portfolio's name IS the h1; the other portfolios' names sit
   beside it as quiet siblings — no dropdown, no tab bar, no new button.
   Everything in this block is gated on ShowPortfolioChrome (the
   second-portfolio rule): at one portfolio none of it renders at all. */

.ij-pf-title-row {
    display: flex;
    align-items: baseline;
    gap: 24px;
    flex-wrap: wrap;
    margin-bottom: 4px;
}



.ij-pf-rule {
    border-top: 0.5px solid var(--ij-divider);
    margin: 20px 0;
}


.ij-pf-body--in {
    animation: ij-pf-rise-in 120ms ease-out;
}


@keyframes ij-pf-rise-in {
    from {
        opacity: 0;
        transform: translateY(6px);
    }
    to {
        opacity: 1;
        transform: none;
    }
}

/* A cut, not a skip. The old justification for 0.01ms over `none` was that
   `animation: none` never fires animationend, which drove the switch navigation —
   that listener went with the switcher (#1413/#1629). Kept as a duration anyway:
   it reads identically to a reader and leaves the element animatable. */
@media (prefers-reduced-motion: reduce) {
    .ij-pf-body--in {
        animation-duration: 0.01ms;
    }
}

@media (max-width: 600px) {
    .ij-pf-title-row {
        gap: 12px;
    }
}

/* ═══════════════════════════════════════
   The portfolios sheet (25A Task 12) — a sibling of the accounts sheet
   (.ij-pf-acct-sheet-*), same compact-sheet shell, but its own row/action
   classes: this sheet's numbers (17px title, 14px name, 13px inline
   actions) come from 25a-strings.json's design spec verbatim rather than
   reusing .ij-pf-section-title (18px, the page's h2 size). */

.ij-pf-sheet-title {
    font-size: 17px;
    font-weight: 600;
}

.ij-pf-sheet-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 11px 0;
    border-top: 0.5px solid var(--ij-divider);
}

.ij-pf-sheet-identity {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    flex: 1;
}

.ij-pf-sheet-name {
    font-size: 14px;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.ij-pf-sheet-meta {
    font-size: 12px;
    color: var(--ij-text-secondary);
}

.ij-pf-sheet-value {
    flex: none;
    font-size: 12px;
    color: var(--ij-text-secondary);
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

.ij-pf-sheet-actions {
    flex: none;
    display: flex;
    align-items: center;
    gap: 12px;
}

.ij-pf-sheet-action {
    font-size: 13px;
    font-weight: 600;
    color: var(--ij-primary);
    background: none;
    border: none;
    padding: 0;
    cursor: pointer;
}

/* Task 13: a business-rule-disabled inline action (accounts sheet Archive, on a
   non-empty account) needs the same visible affordance MudMenuItem's Disabled
   gave it for free — plain buttons don't dim themselves. */
.ij-pf-sheet-action:disabled {
    color: var(--ij-text-secondary);
    cursor: default;
}

.ij-pf-sheet-action--danger {
    color: var(--ij-loss);
}

.ij-pf-sheet-action--cancel {
    color: var(--ij-text-secondary);
}

/* Rename-in-place: the row's label becomes a text field, no second dialog. */
.ij-pf-sheet-editor {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: flex-start;
    gap: 10px;
}

.ij-pf-sheet-editor-field {
    flex: 1;
    min-width: 0;
}

.ij-pf-sheet-editor-field .ij-pf-sheet-name-field {
    width: 100%;
}

/* Aligns Cancel/Save with the field's text, not the taller row when the
   duplicate-name error is showing underneath it. */
.ij-pf-sheet-editor .ij-pf-sheet-action {
    margin-top: 8px;
}

/* Archive confirms IN the row — one sentence, two inline verbs, no second dialog. */
.ij-pf-sheet-confirm {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex: 1;
    min-width: 0;
}

.ij-pf-sheet-confirm-text {
    font-size: 13px;
    color: var(--ij-text-secondary);
    min-width: 0;
}

.ij-pf-sheet-confirm-actions {
    flex: none;
    display: flex;
    align-items: center;
    gap: 12px;
}

.ij-pf-sheet-archived {
    margin-top: 6px;
}

.ij-pf-sheet-archived-toggle {
    display: flex;
    align-items: center;
    gap: 4px;
    font-size: 12px;
    font-weight: 500;
    color: var(--ij-text-secondary);
    background: none;
    border: none;
    padding: 10px 0;
    cursor: pointer;
    width: 100%;
}

.ij-pf-sheet-row--archived .ij-pf-sheet-name {
    color: var(--ij-text-secondary);
}

.ij-pf-sheet-create {
    border-top: 0.5px solid var(--ij-divider);
    padding-top: 16px;
    margin-top: 4px;
}

.ij-pf-sheet-create-label {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--ij-text-secondary);
    margin-bottom: 10px;
}

.ij-pf-sheet-name-field .mud-input.mud-disabled {
    background: var(--ij-field);
    border-radius: 10px;
}

.ij-pf-sheet-name-field .mud-input.mud-disabled .mud-input-outlined-border {
    border-color: transparent;
}

.ij-pf-sheet-hint {
    font-size: 12px;
    color: var(--ij-text-secondary);
    margin-top: 8px;
}

.ij-pf-sheet-limit {
    font-size: 12px;
    color: var(--ij-text-secondary);
    margin-top: 8px;
}

.ij-pf-sheet-limit--reached {
    max-width: 290px;
}

.ij-pf-sheet-primary {
    display: inline-block;
    margin-top: 14px;
    font-size: 14px;
    font-weight: 600;
    color: #fff;
    background: var(--ij-primary);
    border: none;
    border-radius: 980px;
    padding: 9px 18px;
    cursor: pointer;
}

.ij-pf-sheet-primary:disabled {
    cursor: default;
}

.ij-pf-sheet-primary--ceiling {
    background: var(--ij-text-tertiary);
}

@media (max-width: 600px) {
    .ij-pf-sheet-row {
        min-height: 44px;
    }
}


/* ── /portfolios — the book index (#1426) ─────────────────────────────────────
   Rows used to carry the name and a chevron, which made the page that NAVIGATES
   say less than the dialog that RENAMES. Each book is now a card: a monogram in
   a tinted band, then counts, last entry, and this book's own value per currency.

   The colour is IDENTITY, never category — keyed by SortOrder so it is fixed for
   a book's life, present only on the monogram and the band, never on a figure or
   a state, and with no legend anywhere. Nothing in the product may be read FROM
   it, and archived books drop it entirely. If a later feature ever needs colour
   to carry meaning, this rotation is what has to give way.

   The page takes the FULL width of the workspace. It was capped at a 1080px
   measure to begin with, borrowed from the reading pages — but that left a third
   of a wide screen empty beside the books. The width now buys something: a second
   column of questions to ask Claude about the very books beside it. */
.ij-pf-books {
    width: 100%;
}

.ij-pf-books-head {
    margin: var(--ij-space-6) 0 22px;
}

.ij-pf-books-usage {
    margin: 6px 0 0;
    font-size: 15px;
    line-height: 1.5;
    color: var(--ij-text-secondary);
}

/* Two columns, /connect's shape and its 900px collapse: the books on the left,
   the Claude rail on the right. `align-items: start` keeps the rail at the top of
   its column rather than stretching it to the height of a long book list. */
.ij-pf-books-layout {
    display: grid;
    grid-template-columns: 1.35fr 1fr;
    gap: 2.5rem;
    align-items: start;
}

/* Without this a long book name refuses to ellipsise: a grid item's default
   min-width is auto, so the card's content sets the column's floor and the whole
   layout widens instead of the text truncating. */
.ij-pf-books-main {
    min-width: 0;
}

/* One card per line. It was a multi-column grid while it owned the full page
   width; beside the rail it reads as a list, which is also what a book IS here —
   a row you pick, not a tile you browse. */
.ij-pf-books-list {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.ij-pf-books-skeleton {
    border-radius: 20px;
}

.ij-pf-books-failure {
    background: var(--ij-bg-gray);
    border-radius: 20px;
    padding: 34px 20px;
}

.ij-pf-book {
    position: relative;
    display: flex;
    flex-direction: column;
    background: var(--ij-bg-gray);
    border-radius: 20px;
    overflow: hidden;
}

/* The rotation. Declared on the CARD rather than :root so each alias resolves
   against the tokens in scope where it is used — a var() alias parked on :root
   freezes the light value and carries it into dark, which is why --ij-field has
   to be re-declared inside .ij-theme-dark (see tokens.css). --ij-lp-clay is the
   one entry here with a dark override, and it follows the theme for free. */
.ij-pf-book--t1 {
    --ij-pf-band: var(--ij-primary-tint);
    --ij-pf-fill: var(--ij-primary);
    --ij-pf-ink: #fff;
}

.ij-pf-book--t2 {
    --ij-pf-band: rgba(45, 212, 191, 0.14);
    --ij-pf-fill: var(--ij-lp-teal);
    --ij-pf-ink: #000;
}

.ij-pf-book--t3 {
    --ij-pf-band: rgba(201, 100, 66, 0.14);
    --ij-pf-fill: var(--ij-lp-clay);
    --ij-pf-ink: #fff;
}

.ij-pf-book--t4 {
    --ij-pf-band: rgba(168, 85, 247, 0.14);
    --ij-pf-fill: var(--ij-lp-purple);
    --ij-pf-ink: #fff;
}

.ij-pf-book--t5 {
    --ij-pf-band: rgba(236, 72, 153, 0.14);
    --ij-pf-fill: var(--ij-lp-pink);
    --ij-pf-ink: #fff;
}

.ij-pf-book-band {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 18px 20px;
    background: var(--ij-pf-band);
}

.ij-pf-book-mono {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 44px;
    height: 44px;
    border-radius: 12px;
    background: var(--ij-pf-fill);
    color: var(--ij-pf-ink);
    font-size: 17px;
    font-weight: 700;
    letter-spacing: -0.02em;
}

.ij-pf-book-id {
    display: flex;
    align-items: center;
    gap: 9px;
    flex: 1;
    min-width: 0;
}

.ij-pf-book-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 19px;
    font-weight: 700;
    letter-spacing: -0.02em;
    color: var(--ij-text-primary);
}

/* An ADDRESS, not a status: it says where the bare /portfolio and every Claude
   write land. Deliberately quiet — a rank badge is exactly what it is not. */
.ij-pf-book-default {
    flex: none;
    padding: 1px 6px;
    border: 1px solid var(--ij-divider);
    border-radius: 5px;
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ij-text-secondary);
}

.ij-pf-book-chev {
    flex: none;
    color: var(--ij-text-secondary);
    transition: opacity 0.12s ease;
}

.ij-pf-book-body {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 24px;
    flex: 1;
    padding: 18px 20px 20px;
}

.ij-pf-book-meta {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
}

.ij-pf-book-meta-line {
    font-size: 13px;
    color: var(--ij-text-secondary);
}

.ij-pf-book-values {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 5px;
    flex: none;
    /* One line per currency, largest first, NEVER a sum — with no FX rate a
       combined figure would be invented. Same rule Pf_NoCombinedTotal states on
       the detail page. */
    font-variant-numeric: tabular-nums;
}

/* Every currency line is a peer (Canvas-21 #1a): same size, same ink. A smaller
   second line reads as "headline + its conversion", which these figures are not
   — they are separate pools. The ISO code is the label, not the type scale. */
.ij-pf-book-value-row {
    display: flex;
    align-items: baseline;
    gap: 8px;
}

.ij-pf-book-value-code {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.07em;
    color: var(--ij-text-tertiary);
}

.ij-pf-book-value {
    font-size: 20px;
    font-weight: 600;
    letter-spacing: -0.02em;
    color: var(--ij-text-primary);
}

/* A book with no positions has nothing to value, so the stack is replaced by the
   way to finish it. This is the dead end the page used to have: an unfinished
   book could only be resumed by opening it and finding the fork again. */
.ij-pf-book-enter {
    position: relative;
    z-index: 2;
    display: inline-flex;
    align-items: center;
    flex: none;
    box-sizing: border-box;
    padding: 7px 15px;
    border: 1.5px dashed var(--ij-divider);
    border-radius: 980px;
    font-size: 14px;
    font-weight: 600;
    color: var(--ij-primary);
    text-decoration: none;
}

/* The stretched link: one anchor covering the card, LAST in DOM so it paints
   over the static content and takes every click. Never an anchor wrapping the
   card — the Enter-positions pill inside points somewhere else, and a nested
   anchor is invalid. The action buttons and that pill are lifted above it. */
.ij-pf-book-open {
    position: absolute;
    inset: 0;
    z-index: 1;
    border-radius: 20px;
}

.ij-pf-book-open:focus-visible {
    outline: 2px solid var(--ij-primary);
    outline-offset: 2px;
}

/* Rename / Archive, sitting exactly where the chevron was. Revealed on hover AND
   on keyboard focus — a hover-only control does not exist for the keyboard — and
   unconditionally on coarse pointers, the rule .ij-pf-title-edit already follows.
   Tab order is card → Rename → Archive → next card, which is DOM order. */
.ij-pf-book-actions {
    position: absolute;
    top: 18px;
    right: 20px;
    z-index: 2;
    display: flex;
    align-items: center;
    gap: 12px;
    height: 44px;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.12s ease;
}

.ij-pf-book:hover .ij-pf-book-actions,
.ij-pf-book:focus-within .ij-pf-book-actions {
    opacity: 1;
    pointer-events: auto;
}

.ij-pf-book:hover .ij-pf-book-chev,
.ij-pf-book:focus-within .ij-pf-book-chev {
    opacity: 0;
}

.ij-pf-book-action {
    padding: 0;
    border: 0;
    background: transparent;
    font-family: inherit;
    font-size: 13px;
    font-weight: 600;
    color: var(--ij-primary);
    cursor: pointer;
}

.ij-pf-book-action--quiet {
    color: var(--ij-text-secondary);
}

.ij-pf-book-action--danger {
    color: var(--ij-loss);
}

.ij-pf-book-action:disabled {
    opacity: 0.5;
    cursor: default;
}

/* Hidden above 760px: on a phone there is no hover to reveal the actions with,
   so they get a real 44px control instead of an invisible one. */
.ij-pf-book-more {
    display: none;
}

/* Rename and the archive confirm take over the BODY, never the band — the book
   you are editing has to stay named while you edit it. */
.ij-pf-book-body--rename,
.ij-pf-book-body--confirm {
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
}

.ij-pf-book-confirm-text {
    font-size: 13px;
    line-height: 1.5;
    color: var(--ij-text-secondary);
}

.ij-pf-book-confirm-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 16px;
}

.ij-pf-book-rename-field {
    display: flex;
    flex-direction: column;
}

/* The add card: a ghost where the book will be, in the last cell. Only under the
   ceiling — same rule as the header pill. */
.ij-pf-book-add {
    display: flex;
    align-items: center;
    /* Explicit, because a <button> is centred by the UA stylesheet even as a flex
       container — without this the ghost tile floats in the middle of the card
       instead of sitting where every other card's monogram sits. */
    justify-content: flex-start;
    gap: 14px;
    padding: 18px 20px;
    border: 1.5px dashed var(--ij-divider);
    border-radius: 20px;
    background: transparent;
    font-family: inherit;
    text-align: left;
    cursor: pointer;
}

.ij-pf-book-add-tile {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 44px;
    height: 44px;
    border-radius: 12px;
    background: rgba(120, 120, 128, 0.18);
    color: var(--ij-text-secondary);
}

.ij-pf-book-add-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.ij-pf-book-add-title {
    font-size: 15px;
    font-weight: 600;
    color: var(--ij-primary);
}

.ij-pf-book-add-sub {
    font-size: 13px;
    color: var(--ij-text-secondary);
}

/* ── The Claude rail ─────────────────────────────────────────────────────────
   Same job as /connect's starter prompts, scoped to the books beside it. Two of
   the five are WRITES on purpose: "Claude can read your portfolio" is the smaller
   half of what is true, and a rail that only ever asked questions would teach the
   smaller half. */
.ij-pf-books-rail {
    min-width: 0;
}

.ij-pf-rail-card {
    display: flex;
    flex-direction: column;
    padding: 22px;
    border: 1px solid var(--ij-divider);
    border-radius: 20px;
    background: transparent;
}

.ij-pf-rail-head {
    display: flex;
    align-items: center;
    gap: 8px;
    color: var(--ij-text-primary);
}

.ij-pf-rail-title {
    font-size: 18px;
    font-weight: 600;
    letter-spacing: -0.015em;
}

.ij-pf-rail-intro {
    /* 1px here + the first row's own 13px padding = the same 14px gap the row
       used to get by dropping its padding. Every row now has identical padding,
       so every hover fill is the same height. */
    margin: 8px 0 1px;
    font-size: 14px;
    line-height: 1.5;
    color: var(--ij-text-secondary);
}

.ij-pf-rail-row {
    position: relative;
    display: grid;
    /* icon | prompt | glyph. The prompt column is the only flexible one, so a long
       sentence wraps instead of pushing the glyph off the card. */
    grid-template-columns: 32px minmax(0, 1fr) 20px;
    align-items: start;
    gap: 12px;
    padding: 13px 8px;
    margin: 0 -8px;
    border-radius: 12px;
    color: inherit;
    text-decoration: none;
}

/* The rule between rows. A pseudo-element, NOT a border-top: the row is rounded
   for its hover fill, and a border follows those corners — which drew a line that
   bowed up at both ends and made five prompts read as five stacked capsules.
   Inset by the row's own horizontal padding so it lines up with the text. */
.ij-pf-rail-row + .ij-pf-rail-row::before {
    content: "";
    position: absolute;
    top: 0;
    left: 8px;
    right: 8px;
    height: 1px;
    background: var(--ij-divider);
}

.ij-pf-rail-row:hover {
    background: var(--ij-bg-gray);
}

/* A filled row needs no rule above it, and neither does the row after it. */
.ij-pf-rail-row:hover::before,
.ij-pf-rail-row:hover + .ij-pf-rail-row::before {
    opacity: 0;
}

.ij-pf-rail-row:focus-visible {
    outline: 2px solid var(--ij-primary);
    outline-offset: 1px;
}

.ij-pf-rail-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border-radius: 9px;
    background: var(--ij-pf-rail-tint);
    color: var(--ij-pf-rail-ink);
}

/* Decorative in exactly the way the card tints are: fixed per row, never read
   FROM. Declared on the ROW, not on :root — an alias parked on :root freezes the
   light value and carries it into dark (see tokens.css on --ij-field). */
.ij-pf-rail-row--c1 {
    --ij-pf-rail-tint: var(--ij-primary-tint);
    --ij-pf-rail-ink: var(--ij-primary);
}

.ij-pf-rail-row--c2 {
    --ij-pf-rail-tint: rgba(45, 212, 191, 0.16);
    --ij-pf-rail-ink: var(--ij-lp-teal);
}

.ij-pf-rail-row--c3 {
    --ij-pf-rail-tint: rgba(201, 100, 66, 0.16);
    --ij-pf-rail-ink: var(--ij-lp-clay);
}

.ij-pf-rail-row--c4 {
    --ij-pf-rail-tint: rgba(168, 85, 247, 0.16);
    --ij-pf-rail-ink: var(--ij-lp-purple);
}

.ij-pf-rail-row--c5 {
    --ij-pf-rail-tint: rgba(236, 72, 153, 0.16);
    --ij-pf-rail-ink: var(--ij-lp-pink);
}

.ij-pf-rail-text {
    margin-top: 4px;
    font-size: 15px;
    line-height: 1.5;
    color: var(--ij-text-primary);
}

/* Always present, never loud: the row needs a resting mark that says it goes
   somewhere. It brightens to the accent on hover rather than appearing from
   nothing, so the affordance is discoverable without the pointer. */
.ij-pf-rail-open {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    margin-top: 6px;
    color: var(--ij-text-tertiary);
    transition: color 0.12s ease;
}

.ij-pf-rail-row:hover .ij-pf-rail-open,
.ij-pf-rail-row:focus-visible .ij-pf-rail-open {
    color: var(--ij-primary);
}

.ij-pf-rail-connect {
    display: inline-flex;
    align-items: center;
    align-self: flex-start;
    gap: 2px;
    margin-top: 16px;
    padding-top: 14px;
    font-size: 14px;
    font-weight: 600;
    color: var(--ij-primary);
    text-decoration: none;
}

.ij-pf-books-foot {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin-top: 24px;
    padding-top: 14px;
    border-top: 1px solid var(--ij-divider);
}

.ij-pf-books-archived-toggle {
    display: inline-flex;
    align-items: center;
    align-self: flex-start;
    gap: 6px;
    padding: 0;
    border: 0;
    background: transparent;
    font-family: inherit;
    font-size: 13.5px;
    font-weight: 600;
    color: var(--ij-text-secondary);
    cursor: pointer;
}

.ij-pf-books-archived {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

/* Flat, bordered, and colourless. That absence is what makes the group read as
   inactive without a badge — archived books never count against the ceiling, and
   they keep their figures because restoring one brings the book back as it was. */
.ij-pf-book-archived {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 16px;
    border: 1px solid var(--ij-divider);
    border-radius: 16px;
}

.ij-pf-book-mono--archived {
    width: 38px;
    height: 38px;
    border-radius: 11px;
    background: rgba(120, 120, 128, 0.18);
    color: var(--ij-text-secondary);
    font-size: 14px;
}

.ij-pf-book-archived-id {
    display: flex;
    flex-direction: column;
    gap: 2px;
    flex: 1;
    min-width: 0;
}

.ij-pf-book-archived-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 16px;
    font-weight: 600;
    letter-spacing: -0.015em;
    color: var(--ij-text-secondary);
}

.ij-pf-book-archived-meta {
    font-size: 12.5px;
    color: var(--ij-text-secondary);
}

.ij-pf-books-note {
    margin: 0;
    max-width: 640px;
    font-size: 13px;
    line-height: 1.5;
    color: var(--ij-text-secondary);
}

/* Coarse pointer, any width: nothing reveals on hover, so the actions are simply
   there. Below 760px they move out of the band and behind the ⋮ instead, because
   a phone card has no room to hold a name and two links on the same line. */
@media (pointer: coarse) {
    .ij-pf-book-actions {
        opacity: 1;
        pointer-events: auto;
    }

    .ij-pf-book-chev {
        opacity: 0;
    }
}

/* One column below 900px — /connect's breakpoint, so the two pages fold at the
   same width. The rail follows the books rather than sitting beside them. */
@media (max-width: 900px) {
    .ij-pf-books-layout {
        grid-template-columns: 1fr;
        gap: 2rem;
    }
}

@media (max-width: 760px) {
    .ij-pf-book {
        border-radius: 18px;
    }

    .ij-pf-book-band {
        gap: 12px;
        padding: 14px 16px;
    }

    .ij-pf-book-mono {
        width: 40px;
        height: 40px;
        border-radius: 11px;
        font-size: 15px;
    }

    /* The Default label drops under the name rather than beside it — at 17px the
       name already owns the line. */
    .ij-pf-book-id {
        flex-direction: column;
        align-items: flex-start;
        gap: 3px;
    }

    .ij-pf-book-name {
        font-size: 17px;
        max-width: 100%;
    }

    .ij-pf-book-default {
        padding: 0;
        border: 0;
    }

    .ij-pf-book-body {
        gap: 12px;
        padding: 14px 16px 16px;
    }

    /* Only the empty book. Its "Enter positions" pill is wide enough to squeeze the
       meta into "1 account · no / positions" at 375px — a sentence broken in half.
       Stacking gives the meta the full width and drops the pill beneath it, right
       where the value stack sits on every other card. Scoped to this one body so a
       card WITH a figure keeps its side-by-side layout, which still fits. */
    .ij-pf-book-body--empty {
        flex-direction: column;
        align-items: stretch;
    }

    .ij-pf-book-body--empty .ij-pf-book-enter {
        align-self: flex-end;
    }

    .ij-pf-book-meta-line {
        font-size: 12.5px;
    }

    .ij-pf-book-value {
        font-size: 17px;
    }

    .ij-pf-book-value-code {
        font-size: 10px;
    }

    .ij-pf-book-values {
        gap: 3px;
    }

    .ij-pf-book-more {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        position: relative;
        z-index: 2;
        flex: none;
        width: 44px;
        height: 44px;
        margin: -10px -10px -10px 0;
        border: 0;
        border-radius: 980px;
        background: transparent;
        color: var(--ij-text-secondary);
        cursor: pointer;
    }

    .ij-pf-book-chev {
        display: none;
    }

    /* Out of the band and onto their own row, revealed by the ⋮ rather than by a
       hover that a touch screen cannot produce. */
    .ij-pf-book-actions {
        position: static;
        height: auto;
        justify-content: flex-end;
        gap: 20px;
        padding: 0 16px 14px;
        opacity: 0;
        pointer-events: none;
        display: none;
    }

    .ij-pf-book--actions-open .ij-pf-book-actions {
        display: flex;
        opacity: 1;
        pointer-events: auto;
    }

    .ij-pf-book-add {
        border-radius: 18px;
        padding: 14px 16px;
    }

    .ij-pf-book-add-tile {
        width: 40px;
        height: 40px;
        border-radius: 11px;
    }

    /* The board's phone card carries the action alone; the "N more books" line is
       desktop breathing room, not information the phone is missing. */
    .ij-pf-book-add-sub {
        display: none;
    }
}


/* The ghost-tile row: a ghost tile where the thing will be, then the action —
   the same shape as the holdings card's "Enter cash" row. Geometry is duplicated
   from .ij-pf-cash-tile rather than shared, because that class names CASH and
   this is not cash; converging them is a deliberate cleanup, not a side effect
   of this change. Now used only by the EMPTY-book fork — /portfolios itself moved
   to the card grid above (#1426). */
.ij-pf-list-add {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 0 0;
    margin-bottom: var(--ij-space-4);
}

.ij-pf-ghost-tile {
    display: inline-flex;
    width: 36px;
    height: 36px;
    border: 1.5px dashed var(--ij-divider);
    border-radius: 10px;
    flex: none;
}

/* Title + its edit affordance. The button is quiet at rest and revealed on hover,
   but ALSO on keyboard focus and unconditionally on coarse pointers — a hover-only
   control does not exist for touch or the keyboard. */
.ij-pf-title-line {
    display: flex;
    align-items: center;
    gap: 8px;
}

.ij-pf-title-edit {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* 44px hit target even though the glyph is small. */
    width: 44px;
    height: 44px;
    flex: none;
    border: 0;
    background: transparent;
    color: var(--ij-text-tertiary);
    cursor: pointer;
    opacity: 0;
    transition: opacity 0.12s ease, color 0.12s ease;
}

.ij-pf-title-line:hover .ij-pf-title-edit,
.ij-pf-title-edit:focus-visible {
    opacity: 1;
}

.ij-pf-title-edit:hover {
    color: var(--ij-text-secondary);
}

@media (hover: none) {
    /* No hover to reveal it with — touch gets it permanently. */
    .ij-pf-title-edit {
        opacity: 1;
    }
}

.ij-pf-rename-actions {
    display: flex;
    align-items: center;
    margin-top: var(--ij-space-3);
}

/* The way back from a book to the list. Only rendered at 2+ books, so it never
   appears for a one-portfolio user. */
.ij-pf-back {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    margin: 0 0 8px -8px;
    padding: 6px 8px;
    /* 44px floor: this is a phone-reachable control, not just a desktop link. */
    min-height: 44px;
    box-sizing: border-box;
    color: var(--mud-palette-primary);
    font-size: 15px;
    text-decoration: none;
}


/* Cancel and Save as ONE child of the savebar. The bar is space-between, so as
   separate children they were pushed to opposite ends and Cancel ended up beside
   the totals instead of beside the button it belongs to. */
.ij-pf-opening-actions {
    display: flex;
    align-items: center;
    gap: var(--ij-space-3);
}


/* ── Edit account dialog (#1435) ───────────────────────────────────
   Name, currency and tax in one compact sheet. It replaced a rename-only dialog
   opened from a pencil beside the name, which offered to edit one of the three
   facts the header states. */
.ij-pf-acct-edit {
    display: flex;
    flex-direction: column;
    gap: var(--ij-space-4);
}

.ij-pf-acct-edit-title {
    font-size: 17px;
    font-weight: 600;
    letter-spacing: -0.015em;
}

.ij-pf-acct-edit-field {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.ij-pf-acct-edit-label {
    font-size: 12px;
    font-weight: 600;
    color: var(--ij-text-secondary);
}

.ij-pf-acct-edit-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--ij-space-2);
}

/* The account editor's archive confirm (#1435) — inline two-step, so the
   question and its answer sit where the button was. */
.ij-pf-acct-archive-confirm {
    font-size: 13px;
    line-height: 1.5;
    color: var(--ij-text-secondary);
}

.ij-pf-acct-archive-actions {
    display: flex;
    align-items: center;
    gap: var(--ij-space-4);
    margin-top: 8px;
}

/* The destructive half of the pair reads as such — and only while it IS the
   destructive act, never on the button that merely opens the question. */
.ij-pf-acct-archive-btn--danger {
    color: var(--ij-loss);
}

/* Canvas-17 1a — the per-card "Add". A GHOST: outlined in the primary, never
   filled with it. The page keeps exactly one primary (the header's Add
   transaction); filling this would put N identical primaries on one page and
   demote the real one. Spec: 13.5px/600, 45% primary border, pill. */
.ij-pf-acct-add {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex: none;
    font: inherit;
    font-size: 13.5px;
    font-weight: 600;
    line-height: 1;
    color: var(--ij-primary);
    background: transparent;
    border: 1px solid color-mix(in srgb, var(--ij-primary) 45%, transparent);
    border-radius: 980px;
    padding: 6px 14px;
    cursor: pointer;
}

.ij-pf-acct-add:hover {
    background: color-mix(in srgb, var(--ij-primary) 8%, transparent);
}

.ij-pf-acct-add:focus-visible {
    outline: 2px solid var(--ij-primary);
    outline-offset: 2px;
}

/* Canvas-18 2a — the "Open in Claude" strip in the Add-transaction dialog.
   Deliberately the DCF editor's ✦ gradient-pill recipe (ij-dcf-ai-btn), because
   this is the same affordance: "let Claude do this part". Values mirror that
   file rather than importing it — the two dialogs load different stylesheets,
   and a cross-file dependency would couple them for eight declarations. */
.ij-pf-claude-strip {
    display: flex;
    align-items: center;
    gap: 10px;
    border-radius: 12px;
    padding: 9px 10px 9px 14px;
    margin-bottom: 16px;
    /* Canvas-19 rides along: clay, not the blue ij-dcf-ai-btn gradient. Every
       Claude surface in this app is clay (ij-progate-claude-badge, the account
       card's Ask-Claude pill), and a second colour for the same idea reads as a
       second idea. */
    background: color-mix(in srgb, var(--ij-lp-clay) 10%, transparent);
}

/* Holds the ClaudeMark now — the official spark in its own brand colour, never
   recoloured, so this rule sizes it and sets nothing else. */
.ij-pf-claude-spark {
    flex: none;
    display: inline-flex;
}

.ij-pf-claude-hint {
    flex: 1;
    min-width: 0;
    font-size: 13.5px;
    line-height: 1.4;
    color: var(--mud-palette-text-secondary);
}

.ij-pf-claude-btn {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 14px;
    border-radius: 20px;
    background: color-mix(in srgb, var(--ij-lp-clay) 14%, transparent);
    color: var(--ij-lp-clay);
    font-size: 13px;
    font-weight: 500;
    text-decoration: none;
    white-space: nowrap;
    transition: opacity 0.15s ease, transform 0.1s ease;
}

.ij-pf-claude-btn:hover {
    background: color-mix(in srgb, var(--ij-lp-clay) 24%, transparent);
    text-decoration: none;
}

/* The hint is the first thing to give way — the pill must stay whole and the
   strip must never widen the dialog. */
@media (max-width: 520px) {
    .ij-pf-claude-hint {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
}

/* ── Canvas-18 1a: the Add-transaction dialog in the system's form-dialog
   language. Values MIRROR upsert-dcf-dialog.css's recipes rather than importing
   its classes: the two dialogs load different stylesheets, and borrowing
   ij-dcf-* names into a portfolio surface would couple two features that only
   happen to look alike. Same numbers, own names. ── */
.ij-txn-section-label {
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.7px;
    color: var(--mud-palette-text-secondary);
    margin: 14px 0 5px;
    padding: 0;
}

.ij-txn-group {
    background: rgba(120, 120, 128, 0.12);
    border-radius: 12px;
    overflow: hidden;
}

.ij-txn-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    min-height: 44px;
    padding: 4px 14px;
    border-bottom: 0.5px solid var(--mud-palette-divider);
}

.ij-txn-row:last-child {
    border-bottom: none;
}

.ij-txn-label {
    font-size: 14px;
    color: var(--mud-palette-text-primary);
    flex: 1;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* The 168px value box. MudBlazor puts Class on .mud-input-control, which its own
   CSS lets flex-grow inside a row — pin it with flex-basis, not just width. */
.ij-txn-input {
    width: 168px;
    max-width: 168px;
    flex: 0 0 168px;
    display: flex;
    align-items: center;
    background: rgba(120, 120, 128, 0.24);
    border: 1px solid rgba(120, 120, 128, 0.4);
    border-radius: 8px;
    padding: 4px 10px;
    transition: border-color 0.15s ease, background 0.15s ease;
}

.ij-txn-input:focus-within {
    border-color: var(--mud-palette-primary);
}

/* The value-side control of a row that is NOT a numeric box — company search,
   account picker. It sits right, keeps the row's height, and drops MudBlazor's
   outline so the row itself is the visual container. */
.ij-txn-value {
    flex: 0 1 auto;
    min-width: 0;
    max-width: 62%;
}

.ij-txn-value .mud-input-control,
.ij-txn-input .mud-input-control {
    margin: 0;
}

/* A footnote under a group — the account caption and field errors move out of
   the fields and sit here, per the handoff. */
.ij-txn-note {
    font-size: 12px;
    line-height: 1.45;
    color: var(--mud-palette-text-secondary);
    margin: 6px 2px 0;
}

.ij-txn-note--error {
    color: var(--ij-loss);
}

.ij-txn-foot {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 18px;
    padding-top: 14px;
    margin-top: 16px;
    border-top: 0.5px solid var(--mud-palette-divider);
}

/* The summary sits left of the actions and gives way first. */
.ij-txn-foot-summary {
    flex: 1;
    min-width: 0;
    font-size: 12px;
    color: var(--mud-palette-text-secondary);
}

.ij-txn-save {
    border-radius: 980px;
    padding: 8px 24px;
    text-transform: none;
}

.ij-txn-save:disabled {
    opacity: 0.35;
}

/* MudBlazor's Text variant still draws its underline and left-aligns its value.
   Inside a field row the ROW is the container, so the underline is a second
   border competing with the row divider — and a number in a boxed field reads
   right-aligned, the way the DCF editor and every statement print it. */
.ij-txn-row .mud-input-underline::before,
.ij-txn-row .mud-input-underline::after {
    display: none;
}

.ij-txn-row .mud-input.mud-input-text {
    margin-top: 0;
}

.ij-txn-input input {
    text-align: right;
}

/* The currency sits left of the number, so the adornment keeps its own space. */
.ij-txn-input .mud-input-adornment-start {
    margin-right: 4px;
    color: var(--mud-palette-text-secondary);
}

/* Company / account / date read right, like the values they are. */
.ij-txn-value input,
.ij-txn-row .mud-picker input {
    text-align: right;
}

/* The value side of a non-numeric row (company, account, date) now FILLS the
   row and right-aligns inside it, so its text ends at the same x as the numeric
   boxes' right edge. Before this each control was content-sized, so Company
   stopped at its clear ×, Account at its chevron and the date at its calendar —
   three different right edges down one column, which is what read as "not
   aligned" even though every input was individually text-align:right. */
.ij-txn-value {
    flex: 1 1 auto;
    max-width: none;
    min-width: 0;
}

/* Adornments are chrome, not value: they sit after the text and must not push
   it further left than the next row's. */
.ij-txn-value .mud-input-adornment-end,
.ij-txn-row .mud-picker .mud-input-adornment-end {
    margin-left: 2px;
}

/* ══ Canvas-19: the account card's rows become CARDS ═══════════════════════
   The ⋯ menu held four items that were really two destinations and two actions:
   View stock and Value holding… both navigated to the same stock page, so the
   ROW is that link now, and only History and Reconcile needed a home. Dividers
   go with the menu — a row that is a door reads better as its own surface than
   as a line in a table. */

/* Row cards draw their OWN edge, replacing the card-wide hairline between rows.
   Both declarations must sit at the hairline rule's specificity
   (.ij-pf-card .ij-pf-holdings-grid:not(.ij-pf-colhead), = 0,3,0) or it keeps
   winning: a plain .ij-pf-cash-card border lost to it and the dashed card
   rendered with border-top: none — measured, computed borderTopStyle came back
   "none" while the other three sides were dashed. The journal and opening grids
   are still tables and keep their hairline. */
.ij-pf-card .ij-pf-holdings-grid.ij-pf-row-card {
    border: 1px solid var(--ij-divider);
}

.ij-pf-card .ij-pf-holdings-grid.ij-pf-cash-card {
    border: 1.5px dashed var(--ij-divider);
}

.ij-pf-row-card {
    position: relative;
    margin-top: 10px;
    padding: 14px 16px;
    border-radius: 12px;
    /* One step up from the card it sits on — the same mix the Claude chat
       surface uses, so an elevated row reads the same everywhere in the app. */
    background: color-mix(in srgb, var(--ij-text-primary) 4%, var(--ij-surface));
}

/* The row's focal number. It is the one figure a person scans a card for, and
   the only one that gains weight — bolding two would rank neither. */
.ij-pf-row-card .ij-pf-mv {
    font-weight: 600;
}

/* Column heads align with the row cards' PADDING, not the card's edge, or every
   label sits 16px left of the column it names. */
.ij-pf-colhead.ij-pf-holdings-grid,
.ij-pf-cash-zone-head {
    padding-left: 16px;
    padding-right: 16px;
}

/* The row is a link (role="link" + Enter), so it takes focus and must show it. */
.ij-pf-row-card:focus-visible {
    outline: 2px solid var(--ij-primary);
    outline-offset: -2px;
}

/* Only this glyph says the row opens something. Hidden at rest: on every line of
   a table it would read as data rather than as chrome. */
.ij-pf-row-go {
    width: 12px !important;
    height: 12px !important;
    font-size: 12px !important;
    margin-left: 4px;
    color: var(--ij-text-tertiary);
    opacity: 0;
    transition: opacity 0.12s ease-out;
}

/* ── The row's two actions ──────────────────────────────────────────────────
   ONE markup, two placements. Fine pointers get a floating pill that appears on
   hover; coarse pointers get a persistent stacked pair in the grid's trailing
   column — the same media-query split the rename pencil already ships, and the
   only honest one: there is no hover to reveal anything with on a touch screen. */
.ij-pf-row-actions {
    display: flex;
    gap: 2px;
}

.ij-pf-row-act {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 5px 9px;
    border: 0;
    border-radius: 6px;
    background: none;
    color: var(--ij-text-secondary);
    font: inherit;
    font-size: 12px;
    font-weight: 500;
    line-height: 1;
    cursor: pointer;
    transition: background 0.12s ease-out;
}

.ij-pf-row-act:hover {
    background: rgba(120, 120, 128, 0.2);
    color: var(--ij-text-primary);
}

.ij-pf-row-act:focus-visible {
    outline: 2px solid var(--ij-primary);
    outline-offset: -2px;
}

.ij-pf-row-act .mud-icon-root {
    width: 14px;
    height: 14px;
    font-size: 14px;
}

@media (hover: hover) {
    .ij-pf-row-card {
        cursor: pointer;
        transition:
            border-color 0.12s ease-out,
            box-shadow 0.12s ease-out,
            transform 0.12s ease-out;
    }

    /* Same specificity ladder as the border above, or the hairline rule's colour
       survives the hover. */
    .ij-pf-card .ij-pf-holdings-grid.ij-pf-row-card:hover {
        border-color: var(--ij-text-tertiary);
    }

    .ij-pf-row-card:hover {
        box-shadow: 0 10px 28px rgba(0, 0, 0, 0.35);
        transform: translateY(-1px);
    }

    .ij-pf-row-card:hover .ij-pf-row-go,
    .ij-pf-row-card:focus-visible .ij-pf-row-go {
        opacity: 1;
    }

    /* Docked ABOVE the row's top edge, straddling the 10px gap, so it can never
       cover the row's own numbers — which is the failure that makes a hover
       toolbar worse than the menu it replaced. */
    .ij-pf-row-actions {
        position: absolute;
        top: -32px;
        right: 12px;
        z-index: 2;
        gap: 2px;
        padding: 3px;
        border: 1px solid var(--ij-divider);
        border-radius: 9px;
        background: var(--ij-surface);
        box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
        opacity: 0;
        pointer-events: none;
        transition: opacity 0.12s ease-out;
    }

    /* focus-within, not only hover: the pill's own buttons are reachable by Tab
       once the row has focus, and a control you can focus but cannot see is a
       control that does not exist. */
    .ij-pf-row-card:hover .ij-pf-row-actions,
    .ij-pf-row-card:focus-within .ij-pf-row-actions {
        opacity: 1;
        pointer-events: auto;
    }
}

@media (hover: none) {
    /* No hover to reveal them with, so they rest in the grid's trailing column,
       stacked, icon-only. The row's two line boxes give the pair its ≥44px of
       effective target height. */
    .ij-pf-row-actions {
        flex-direction: column;
        gap: 4px;
        align-self: center;
    }

    .ij-pf-row-act {
        justify-content: center;
        width: 36px;
        height: 36px;
        padding: 0;
        border-radius: 8px;
        background: rgba(120, 120, 128, 0.12);
        color: var(--ij-text-tertiary);
    }

    .ij-pf-row-act .mud-icon-root {
        width: 17px;
        height: 17px;
        font-size: 17px;
    }

    /* The label is the pill's affordance; at 36px square the icon is the whole
       control and a tooltip/aria-label carries the name. */
    .ij-pf-row-act-label {
        display: none;
    }

    .ij-pf-row-go {
        display: none;
    }
}

@media (prefers-reduced-motion: reduce) {
    .ij-pf-row-card:hover {
        transform: none;
    }
}

/* ── The cash row-card ──────────────────────────────────────────────────────
   Dashed, because an asserted balance is a different KIND of thing from a
   position: nobody bought it, and the app never computed it. It absorbed the
   card-level "Cash as of …" footnote, which stated ONE date for a card that can
   assert a different one per currency.

   Overrides the negative-margin trick .ij-pf-cash-zone-row used to keep its fill
   on-grid: as a card it has real padding, and every row card on the card shrinks
   by the same 32px, so the columns still line up. */
.ij-pf-cash-card {
    /* A <button> is shrink-to-fit, so width must be stated: without it the cash
       card ended ~275px short of the holding cards' right edge, and the amount
       left the Market-value column it is supposed to share an edge with. */
    width: 100%;
    margin: 10px 0 0;
    padding: 12px 16px;
    border-radius: 12px;
    background: none;
}

.ij-pf-cash-card:hover {
    background: rgba(120, 120, 128, 0.06);
}

/* The name line gained a third part (name · currency · as-of), which at 375px
   is longer than the identity column. Wrapping is what keeps it inside its own
   cell — without it the date ran underneath the balance. */
.ij-pf-cash-card .ij-pf-cash-name-line {
    flex-wrap: wrap;
    row-gap: 0;
}

/* The date the row asserts, in the subline register the ticker already uses. */
.ij-pf-cash-asof {
    font-size: 12px;
    color: var(--ij-text-secondary);
    white-space: nowrap;
}

/* ── "Ask Claude" (Canvas-19 4a) ────────────────────────────────────────────
   Clay, never the blue ij-dcf-ai-btn gradient: Claude surfaces in this app are
   clay (ij-progate-claude-badge is the precedent), and the mark is the shared
   ClaudeMark — Anthropic's spark in its own brand colour, never a generic
   sparkle and never recoloured per theme. */
.ij-pf-acct-claude {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 14px;
    border-radius: 20px;
    background: color-mix(in srgb, var(--ij-lp-clay) 14%, transparent);
    color: var(--ij-lp-clay);
    font-size: 13px;
    font-weight: 500;
    text-decoration: none;
    white-space: nowrap;
    transition: background 0.12s ease-out;
}

.ij-pf-acct-claude:hover {
    background: color-mix(in srgb, var(--ij-lp-clay) 24%, transparent);
    text-decoration: none;
}

.ij-pf-acct-claude:focus-visible {
    outline: 2px solid var(--ij-primary);
    outline-offset: 2px;
}

.ij-pf-acct-claude-open {
    width: 12px !important;
    height: 12px !important;
    font-size: 12px !important;
}

/* The header wraps on a phone; the pill drops under the badges rather than
   squeezing the account's name. */
@media (max-width: 767px) {
    .ij-pf-acct-head {
        flex-wrap: wrap;
    }
}

/* The phone card, on a real phone: the trailing track comes back, because on a
   coarse pointer the History/Reconcile pair rests IN it rather than appearing on
   a hover that will never happen. Split out of the width-only block above so a
   narrow desktop window — fine pointer, hover pill — is not charged 36px of
   gutter it has nothing to put in. */
@media (max-width: 767px) and (hover: none) {
    .ij-pf-holdings-grid {
        /* Same floor as the fine-pointer phone grid above, minus the 36px the
           resting action pair costs. */
        grid-template-columns: minmax(116px, 1fr) auto 36px;
        grid-template-areas:
            "identity mv menu"
            "shares   pl menu";
    }

    .ij-pf-holdings-grid--mos {
        grid-template-columns: minmax(116px, 1fr) auto 36px;
        grid-template-areas:
            "identity mv  menu"
            "shares   pl  menu"
            "shares   mos menu";
    }

    .ij-pf-c-menu {
        grid-area: menu;
        align-self: center;
    }
}

/* Above the phone reshape but still on a touch screen (a tablet), the pair rests
   in the table's own trailing track — which the fine-pointer rules narrowed to
   28px for the cash pencil alone. */
@media (min-width: 768px) and (hover: none) {
    .ij-pf-holdings-grid {
        grid-template-columns: minmax(200px, 2.3fr) 1fr 0.9fr 1.25fr 1.2fr 36px;
    }

    .ij-pf-holdings-grid--mos {
        grid-template-columns: minmax(180px, 2fr) 0.85fr 0.8fr 1.15fr 1.1fr 1.15fr 36px;
    }
}

/* A bordered card costs horizontal room, and on a 375px phone the card's 16px
   of padding plus the 36px action column left the company name ~75px — the
   identity text collapsed to nothing while the market value kept its width.
   Measured before/after; the flat rows this replaced had ~113px there.

   So the phone card spends less on padding and gutter than the desktop one. The
   16px inset is a desktop affordance; at 375px it is the name. */
@media (max-width: 767px) {
    .ij-pf-row-card,
    .ij-pf-cash-card {
        padding-left: 10px;
        padding-right: 10px;
        column-gap: var(--ij-space-2);
    }
}

/* The cash pencil, on a fine-pointer phone. The phone grid has no trailing track
   there (nothing rests in it), so the pencil — an in-flow cell — was auto-placed
   into an IMPLICIT row and rendered on a line of its own under the as-of date.
   Taking it out of flow puts it back on the row it belongs to; the card buys the
   space with right padding so it never sits on top of the balance.

   The holding rows need no equivalent: their action pair is already absolute
   under (hover: hover), so it never asks the grid for a cell. */
@media (max-width: 767px) and (hover: hover) {
    .ij-pf-cash-card {
        position: relative;
        padding-right: 34px;
    }

    .ij-pf-cash-card .ij-pf-cash-edit {
        position: absolute;
        right: 8px;
        top: 50%;
        transform: translateY(-50%);
    }

    /* The ghost row's trailing cell is empty and would open the same implicit
       row for nothing. */
    .ij-pf-cash-ghost .ij-pf-c-menu {
        display: none;
    }
}
