/* ═══════════════════════════════════════
   MORNING DESK (#1488 M2)
   Linked from StockGrade/Components/App.razor AND, since #1706, from
   StockGrade.Maui/wwwroot/index.html: the device Home renders MorningDesk with
   DeskVariant.Mobile over /api/v1/desk (#1705). The ≤599.95px rules below are
   what a phone gets.
═══════════════════════════════════════ */

/* #1488 M2b Task 2c fix: this used to be `max-width: 1092px; margin: 0 auto` —
   a centred narrow column lifted straight from the design canvas artboard's
   1180px frame width. An artboard width is the frame a design was drawn in,
   not a max-width constraint on the real page. Every other data-dense page in
   this app is the full-gutter workspace shape (#794): no cap, no centring,
   starts at the left gutter — see .home-content (home-view.css:6-8, the page
   this replaced) and .ij-page-content (app-layout.css:1150-1152), both
   `padding: 32px 32px …` with no max-width. This rule now matches that
   horizontal measure instead of the invented 44px. The lead card's stat rail
   gets its own cap below (.ij-desk-lead-rail) so it doesn't stretch
   full-width on wide viewports — the page itself never does. */
.ij-desk {
    padding: 32px 32px 80px;
}

.ij-desk-skeleton {
    height: 220px;
    border-radius: 18px;
    background: var(--mud-palette-surface);
    border: 1px solid var(--ij-divider);
}

.ij-desk-greeting {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 24px;
}

.ij-desk-greeting-title {
    font-size: 1.5rem;
    font-weight: 600;
    color: var(--mud-palette-text-primary);
    /* Final-review fix 5 — same rule home-view.css's .home-greeting-title
       carries, for the same reason: DeskGreeting.razor's DisplayName falls
       back to the full username/email when no first/last name is set (a
       Sign-in-with-Apple user with no name lands on an unbreakable
       "...@privaterelay.appleid.com"), and that string has no natural break
       point for the browser to wrap on without this. */
    overflow-wrap: anywhere;
    min-width: 0;
}

.ij-desk-greeting-meta {
    display: flex;
    align-items: baseline;
    gap: 8px;
    text-align: right;
    color: var(--mud-palette-text-secondary);
    font-size: 0.875rem;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* Acceptance-pass fix (#1488 M2 Task 7): the date ends in a bare day-of-month digit
   ("September 2") immediately followed by the item count ("3 items") — with only
   the flex gap between them, tabular numerals on both sides read as one number ("2  3"
   looks like "23"). Same mid-dot convention already used for this kind of adjacent-fact
   line elsewhere (portfolio.css:2212-2214, "TICKER · shares"). */
.ij-desk-greeting-count::before {
    content: "· ";
}

/* #1488 M2b Task 5, canvas #7a: "Tuesday, September 2 · 5 items · ranked by cost
   of ignoring" — the desk's premise (rank order = consequence, not just a count)
   spelled out, not left implicit. Same mid-dot convention as the count above,
   never a mid-dot baked into the resx string itself (matches every other
   adjacent-fact line in this app). */
.ij-desk-greeting-tagline::before {
    content: "· ";
}

.ij-desk-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    padding: 56px 32px;
    border-radius: 18px;
    border: 1px solid var(--ij-divider);
    background: var(--mud-palette-surface);
    text-align: center;
}

.ij-desk-empty-icon {
    color: var(--mud-palette-success);
}

.ij-desk-empty-title {
    font-size: 1.125rem;
    font-weight: 600;
    color: var(--mud-palette-text-primary);
}

.ij-desk-empty-sub {
    max-width: 40ch;
    color: var(--mud-palette-text-secondary);
}

/* ── Unavailable (#1705) ─────────────────────────────────────────────────
   The device desk when /api/v1/desk could not be reached. Same card shape as
   the empty state so the page does not jump between the two; the icon is
   neutral (secondary text), never the empty state's success green — nothing
   here is a good outcome. */
.ij-desk-unavailable {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    padding: 56px 32px;
    border-radius: 18px;
    border: 1px solid var(--ij-divider);
    background: var(--mud-palette-surface);
    text-align: center;
}

.ij-desk-unavailable-icon {
    color: var(--mud-palette-text-secondary);
}

.ij-desk-unavailable-title {
    font-size: 1.125rem;
    font-weight: 600;
    color: var(--mud-palette-text-primary);
}

.ij-desk-unavailable-sub {
    max-width: 40ch;
    color: var(--mud-palette-text-secondary);
}

/* #1707: the block's own retry — same pill grammar as the desk's secondary CTA,
   as a <button> because it performs an action rather than navigating. */
.ij-desk-unavailable-retry {
    margin-top: 4px;
    padding: 8px 18px;
    border-radius: 999px;
    border: 1px solid var(--ij-divider);
    background: var(--mud-palette-surface);
    color: var(--ij-primary);
    font: inherit;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
}

.ij-desk-unavailable-retry:hover,
.ij-desk-unavailable-retry:focus-visible {
    border-color: var(--ij-primary);
}

/* ── Coming up (#1503 M3b, Canvas-20 #1e) ──────────────────────────────
   The empty desk's one forward-looking block: the next few announced results
   dates and thesis-review dates. An 88px date column in tertiary, one row per
   date with a hairline between, a right-aligned "Calendar" link in the header.
   Rows are plain text, not cards — the desk only states what is known. */
.ij-desk-coming {
    margin-top: 28px;
}

.ij-desk-coming-head {
    display: flex;
    align-items: baseline;
    gap: 12px;
}

.ij-desk-coming-title {
    flex: 1;
    font-size: 16px;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--mud-palette-text-primary);
}

.ij-desk-coming-link {
    font-size: 13px;
    font-weight: 600;
    color: var(--ij-primary);
    text-decoration: none;
}

.ij-desk-coming-link:hover {
    text-decoration: underline;
}

.ij-desk-coming-rows {
    margin-top: 10px;
    display: flex;
    flex-direction: column;
}

.ij-desk-coming-row {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 13px 4px;
    border-bottom: 1px solid var(--ij-divider);
    font-size: 13.5px;
    color: var(--mud-palette-text-primary);
    text-decoration: none;
}

.ij-desk-coming-row:last-child {
    border-bottom: 0;
}

.ij-desk-coming-row:hover .ij-desk-coming-what {
    text-decoration: underline;
}

.ij-desk-coming-when {
    flex: none;
    width: 88px;
    color: var(--ij-text-secondary);
    font-variant-numeric: tabular-nums;
}

.ij-desk-coming-what {
    flex: 1;
    min-width: 0;
}

.ij-desk-coming-detail {
    color: var(--mud-palette-text-secondary);
}

@media (max-width: 600px) {
    .ij-desk-coming-when {
        width: 72px;
    }
}

/* ── Lead card (#1488 M2 Task 4) ─────────────────────────────────────── */

.ij-desk-lead {
    /* #1488 M4 Task 1: positions the stretched .ij-desk-lead-link overlay below
       (see DeskLeadCard.razor's own comment for why the card is a <div> with an
       absolutely-positioned <a> overlay rather than being the <a> itself). */
    position: relative;
    display: grid;
    /* #1488 M2b Task 2c fix: the second track was a bare 0.75fr, which grew
       unbounded once .ij-desk stopped capping the whole page's width. At
       1920px that made the rail ~610px wide — the hero number and its small
       sparkline stranded in a track built for much more content than either
       actually has. `minmax(0, 340px)` caps the RAIL's own track (roughly
       what its 0.75fr share worked out to under the design canvas's 1092px
       frame, now derived honestly as a component cap instead of a page one)
       while 1.25fr keeps absorbing whatever width the desk has — verified
       at 1920/1440/375 (see task-2c-report.md); at ≤960px this collapses to
       a single column below and the cap is moot.
    */
    grid-template-columns: 1.25fr minmax(0, 340px);
    gap: 36px;
    padding: 32px 36px;
    border-radius: 18px;
    border: 1px solid var(--ij-divider);
    /* #1488 M2b Task 1 fix: this was the `background` SHORTHAND, which resets
       background-image to `none` as part of the same declaration. That is harmless
       here in THIS rule's own source position (the .ij-desk-tint-* rules below
       redeclare background-image and come later in the file, so they still win the
       cascade for .ij-desk-lead) — but the identical shorthand on .ij-desk-converging
       further down this file sits AFTER the tint rules, so there it silently
       re-clobbered them back to `none` (computed background-image was verified `none`
       live). Using the longhand here makes BOTH cards' tint order-independent rather
       than one working by accident of file order. */
    background-color: var(--mud-palette-surface);
    text-decoration: none;
    color: inherit;
}

.ij-desk-tint-review {
    background-image: radial-gradient(
        120% 160% at 85% -20%,
        rgba(41, 151, 255, 0.16),
        transparent 55%
    );
}

.ij-desk-tint-zone {
    background-image: radial-gradient(
        120% 160% at 85% -20%,
        rgba(61, 203, 108, 0.14),
        transparent 55%
    );
}

.ij-desk-tint-stale {
    background-image: radial-gradient(
        120% 160% at 85% -20%,
        rgba(255, 181, 69, 0.14),
        transparent 55%
    );
}

/* #1503 M3b: the fourth row (EarningsAhead) in the event indigo — --ij-event-tint is
   the same rgba the calendar's pills use, so the desk and /calendar agree on the hue. */
.ij-desk-tint-event {
    background-image: radial-gradient(
        120% 160% at 85% -20%,
        var(--ij-event-tint),
        transparent 55%
    );
}

.ij-tnum {
    font-variant-numeric: tabular-nums;
}

.ij-desk-lead:hover {
    border-color: rgba(120, 120, 128, 0.5);
}

/* Fix round 1, Finding 3, still true after Task 4b: a row with no real figure
   collapses to one column rather than a bordered rail with nothing behind it — not
   every row type resolves a figure (e.g. a stock with no surviving valuation). */
.ij-desk-lead--no-rail {
    grid-template-columns: 1fr;
}

.ij-desk-lead-main {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 12px;
    min-width: 0;
}

/* #1488 M2b Task 1, canvas #6a: icon + label, colour-coded by row type — 11px/700,
   not the previous flat 12px/600 grey run with no icon. Colour comes from a
   modifier class below, never a default here, so a row can't render uncoloured. */
.ij-desk-lead-eyebrow {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.ij-desk-eyebrow-icon {
    width: 14px;
    height: 14px;
    flex-shrink: 0;
}

/* Same three hues the tint gradients and the figure gain/loss colours already use
   (verified against tokens.css, NOT the nonexistent --ij-amber/indigo tokens this
   task's brief named — --mud-palette-warning is the app's actual amber, already
   used by .ij-desk-step-eyebrow--stale below). */
.ij-desk-lead-eyebrow--review {
    color: var(--ij-primary);
}

.ij-desk-lead-eyebrow--zone {
    color: var(--ij-gain);
}

.ij-desk-lead-eyebrow--stale {
    color: var(--mud-palette-warning);
}

.ij-desk-lead-eyebrow--event {
    color: var(--ij-event);
}

/* Canvas #6a: the pull quote is the user's OWN thesis, 14.5px italic with a 2px
   left border in the row's own tint colour. Reuses .ij-desk-tint-* as a SECOND
   class (see DeskLeadCard.razor) purely to key its border colour below by row
   type without a third parallel switch — but .ij-desk-tint-* ALSO declares
   background-image (it targets whatever element carries the class, not just
   .ij-desk-lead), so it must be cancelled back to none here or this small box
   would paint its own copy of the card-sized radial gradient. */
.ij-desk-lead-quote {
    margin-top: 2px;
    padding: 10px 16px;
    border-left: 2px solid var(--ij-divider);
    background-image: none;
    font-size: 14.5px;
    font-style: italic;
    line-height: 1.55;
    color: var(--mud-palette-text-secondary);
}

.ij-desk-lead-quote.ij-desk-tint-review {
    border-left-color: rgba(41, 151, 255, 0.5);
}

.ij-desk-lead-quote.ij-desk-tint-zone {
    border-left-color: rgba(61, 203, 108, 0.5);
}

.ij-desk-lead-quote.ij-desk-tint-stale {
    border-left-color: rgba(255, 181, 69, 0.5);
}

.ij-desk-lead-quote.ij-desk-tint-event {
    border-left-color: var(--ij-event);
}

.ij-desk-lead-headline {
    font-size: 34px;
    font-weight: 600;
    line-height: 1.3;
    color: var(--mud-palette-text-primary);
}

/* #1503 M3b: the EarningsAhead lead's one-line evidence (period · timing · thesis) —
   same voice as the step card's evidence line, one size up for the lead. */
.ij-desk-lead-evidence {
    font-size: 15px;
    line-height: 1.5;
    color: var(--mud-palette-text-secondary);
}

.ij-desk-lead-cta {
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--mud-palette-primary);
}

/* ── Hover actions (#1488 M4 Task 1, canvas #2a) ─────────────────────────
   Snooze / "Not useful" — the stretched-link overlay that makes the whole card
   ONE link (see DeskLeadCard.razor's own comment) and the actions pills that
   float above it. Shared here (rather than per-card) because DeskLeadCard,
   DeskStepCard and DeskConvergingLead's panels all use the exact same overlay
   +  pill shapes. */
.ij-desk-lead-link,
.ij-desk-step-link {
    position: absolute;
    inset: 0;
    z-index: 0;
}

.ij-desk-actions {
    position: relative;
    z-index: 1;
    display: flex;
    align-self: flex-start;
    gap: 8px;
}

/* Cards position their own actions row where it reads best for that shape —
   the lead/step cards float it top-right over the card; a converging panel
   (narrower, no absolute overlay to sit above) keeps it in normal flow, right-
   aligned, under the panel's own content — see .ij-desk-panel .ij-desk-actions
   below. */
.ij-desk-lead > .ij-desk-actions,
.ij-desk-step > .ij-desk-actions {
    position: absolute;
    top: 16px;
    right: 16px;
}

/* Canvas #2a's own pill: icon + label, 12.5px/600, a plain divider-bordered
   pill — never filled, so it never competes with the card's one primary CTA.
   Hidden by default and revealed on hover/focus below; the ≤599.95px override
   further down this file (there is no hover on touch) makes both ALWAYS
   visible at that width — this is the base (desktop) state only.
   #1488 M4 Task 3 fix (F1): this used to carry
   `background-color: var(--mud-palette-surface)` — invisible on a plain
   step card (card bg and pill bg are the same colour there), but on the two
   TINTED shapes (the lead card's radial gradient, the converging panel's
   rgba(120,120,128,0.09) wash) it stamped two flat opaque lozenges through
   the tint — the one visual cue the design uses to make the lead card read
   as a lead card. The canvas (`[id="2a"]`) sets no background on these spans
   at all; verified legible with none against all three surfaces (plain step
   card, tinted lead, converging panel) in both themes — the divider border
   plus secondary-text colour carry the pill's shape on their own, same as
   the canvas. */
.ij-desk-snooze,
.ij-desk-not-useful {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--mud-palette-text-secondary);
    padding: 7px 12px;
    border-radius: 999px;
    border: 1px solid var(--ij-divider);
    cursor: pointer;
    opacity: 0;
    pointer-events: none;
    transition:
        opacity 120ms ease,
        border-color 120ms ease,
        color 120ms ease;
}

.ij-desk-snooze .mud-icon-root,
.ij-desk-not-useful .mud-icon-root {
    width: 14px;
    height: 14px;
}

.ij-desk-snooze:hover,
.ij-desk-not-useful:hover {
    border-color: rgba(120, 120, 128, 0.5);
    color: var(--mud-palette-text-primary);
}

/* Revealed on hover OR keyboard focus (":focus-within" — a Tab landing on
   either pill must not require a mouse hover to become visible first). */
.ij-desk-lead:hover .ij-desk-snooze,
.ij-desk-lead:hover .ij-desk-not-useful,
.ij-desk-lead:focus-within .ij-desk-snooze,
.ij-desk-lead:focus-within .ij-desk-not-useful,
.ij-desk-step:hover .ij-desk-snooze,
.ij-desk-step:hover .ij-desk-not-useful,
.ij-desk-step:focus-within .ij-desk-snooze,
.ij-desk-step:focus-within .ij-desk-not-useful,
.ij-desk-panel:hover .ij-desk-snooze,
.ij-desk-panel:hover .ij-desk-not-useful,
.ij-desk-panel:focus-within .ij-desk-snooze,
.ij-desk-panel:focus-within .ij-desk-not-useful {
    opacity: 1;
    pointer-events: auto;
}

.ij-desk-lead-rail {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: flex-start;
    gap: 12px;
    padding-left: 24px;
    border-left: 1px solid var(--ij-divider);
}

/* Spec §5.2/§5.4: 44px/700/-0.035em, gain-or-loss colour (same hero-number pattern
   as .ij-propage-headline's -0.035em, pro-billing.css:582). Task 4b (#1488 M2): each
   row picks --ij-gain or --ij-loss via a modifier class per its own direction
   (DeskLeadCard.FigureDirectionClass) — no default colour here, so a figure can
   never render without an explicit direction. */
.ij-desk-lead-figure {
    font-size: 44px;
    font-weight: 700;
    letter-spacing: -0.035em;
    line-height: 1.1;
}

.ij-desk-lead-figure--gain {
    color: var(--ij-gain);
}

.ij-desk-lead-figure--loss {
    color: var(--ij-loss);
}

/* Final-review fix 6: the "at firing" qualifier beside PriceInZone's margin-of-safety
   figure (DeskFigureFormatter.IsAtFiring) — shared by the lead rail, the step card,
   and the converging panel, so it always reads the same size/weight wherever the
   figure it qualifies appears. */
.ij-desk-figure-qualifier {
    font-size: 11px;
    font-weight: 500;
    color: var(--mud-palette-text-secondary);
}

/* #1488 M2b Task 2, canvas #6a: the rail's own label ("Price since you wrote it" /
   "Price since your valuation"), sitting above the hero % — the SAME grey secondary
   text convention used everywhere else on the desk (never Color.Secondary/purple). */
.ij-desk-rail-label {
    font-size: 12px;
    color: var(--mud-palette-text-secondary);
}

.ij-desk-sparkline {
    width: 100%;
    height: 52px;
    display: block;
}

.ij-desk-sparkline-line {
    fill: none;
    stroke: var(--mud-palette-primary);
    stroke-width: 2px;
    vector-effect: non-scaling-stroke;
    /* #1488 M4 Task 2: the "final frame"/no-motion state is fully drawn — see
       the Arrival Motion section below for the entrance keyframe that animates
       dashoffset FROM 700 down to this same 0 on an unplayed container. */
    stroke-dasharray: 700;
    stroke-dashoffset: 0;
}

.ij-desk-sparkline-fill {
    fill: var(--mud-palette-primary);
    fill-opacity: 0.08;
    stroke: none;
}

/* #1488 M2b Task 3: the sparkline used to draw in --mud-palette-primary (blue)
   REGARDLESS of direction — controller-spotted on screen, a green "+18.0%" hero
   figure above a blue line. These modifier classes (DeskSparkline.Direction, a
   plain pass-through of the SAME DeskFigureFormatter.Direction every hero figure
   already uses) make the line match the number it sits under, same as canvas
   #6a's own green line under a green "+18%". */
.ij-desk-sparkline--gain .ij-desk-sparkline-line {
    stroke: var(--ij-gain);
}

.ij-desk-sparkline--gain .ij-desk-sparkline-fill {
    fill: var(--ij-gain);
}

.ij-desk-sparkline--loss .ij-desk-sparkline-line {
    stroke: var(--ij-loss);
}

.ij-desk-sparkline--loss .ij-desk-sparkline-fill {
    fill: var(--ij-loss);
}

/* #1488 M2b Task 2, canvas #6a: the two small stats beneath the sparkline ("vs
   your FV" / "Thesis age") — a FLEX row sized to however many stats actually
   resolved (1 or 2), never a fixed 3-column grid with an empty slot where the
   canvas's dropped "P/E then → now" would have sat (#1488 M2b ruling: two honest
   stats, never three fabricated). */
.ij-desk-rail-stats {
    display: flex;
    gap: 28px;
}

.ij-desk-rail-stat {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.ij-desk-rail-stat-label {
    font-size: 12px;
    color: var(--mud-palette-text-secondary);
}

/* 16px/700 per spec — deliberately its OWN class, not a reuse of
   .ij-desk-lead-figure (44px), which the hero above already owns. */
.ij-desk-rail-stat-value {
    font-size: 16px;
    font-weight: 700;
    color: var(--mud-palette-text-primary);
}

.ij-desk-rail-stat-value--gain {
    color: var(--ij-gain);
}

.ij-desk-rail-stat-value--loss {
    color: var(--ij-loss);
}

/* Spec §5.4: lead headline 34px → 26px, hero number 44px → 32px at ≤599.95px
   (the home-view.css breakpoint). */
@media (max-width: 599.95px) {
    .ij-desk-lead-headline {
        font-size: 26px;
    }

    .ij-desk-lead-figure {
        font-size: 32px;
    }
}

/* ── Step cards (#1488 M2 Task 5) — ranks 2–4 ────────────────────────── */

.ij-desk-steps {
    display: grid;
    gap: 16px;
    margin-top: 20px;
}

/* Count-driven modifier, not a fixed 3-column grid — a 2-item layout (rank count
   2–3, i.e. 3 total items) must not leave a visibly empty third column. 2 total
   items (1 lead + 1 step) renders `.ij-desk-steps--1` — intentionally without a
   matching rule here: the grid's single-column default already renders that case
   correctly, and adding `grid-template-columns: 1fr` for it would be a no-op. See
   DeskTiersTests.Two_items_render_a_single_step_card_with_the_singular_grid_modifier. */
.ij-desk-steps--2 {
    grid-template-columns: 1fr 1fr;
}

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

.ij-desk-step {
    /* #1488 M4 Task 1: same stretched-link anchor as .ij-desk-lead above. */
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 10px;
    min-width: 0;
    padding: 22px;
    border-radius: 16px;
    border: 1px solid var(--ij-divider);
    background: var(--mud-palette-surface);
    text-decoration: none;
    color: inherit;
}

.ij-desk-step:hover {
    border-color: rgba(120, 120, 128, 0.5);
}

/* #1488 M2b Task 5, canvas #7a: was icon-only (no gap needed) — now icon + label,
   same 11px/700/uppercase/0.06em shape as .ij-desk-lead-eyebrow (reused, not a
   parallel size/weight defined here). */
.ij-desk-step-eyebrow {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

/* Same hue mapping as the lead card's tint gradients (Task 4): info-blue for a
   review, success-green for a buy zone, warning-amber for a stale valuation — but
   here it tints a small icon glyph, not a background wash. */
.ij-desk-step-eyebrow--review {
    color: var(--mud-palette-info);
}

.ij-desk-step-eyebrow--zone {
    color: var(--mud-palette-success);
}

.ij-desk-step-eyebrow--stale {
    color: var(--mud-palette-warning);
}

.ij-desk-step-eyebrow--event {
    color: var(--ij-event);
}

.ij-desk-step-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    min-width: 0;
}

/* #1488 M2b Task 3, canvas #6a: "Novo Nordisk NVO" — company name + a coloured
   ticker chip, replacing the old bare ".ij-desk-step-ticker" run (ticker only,
   no company name at all). Grouped in its own flex row so ".ij-desk-step-row"'s
   justify-content:space-between still has exactly two children (identity group,
   figure group) — unchanged from before this task. */
.ij-desk-step-identity {
    display: flex;
    align-items: baseline;
    gap: 8px;
    min-width: 0;
    overflow: hidden;
}

.ij-desk-step-name {
    overflow: hidden;
    font-size: 18px;
    font-weight: 700;
    color: var(--mud-palette-text-primary);
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ij-desk-step-ticker-chip {
    flex-shrink: 0;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.02em;
    padding: 3px 9px;
    border-radius: 999px;
}

/* Same three hues as .ij-desk-step-eyebrow--review/--zone/--stale (info/success/
   warning) — the chip and its row's eyebrow icon always agree. */
.ij-desk-step-ticker-chip--review {
    color: var(--mud-palette-info);
    background: rgba(41, 151, 255, 0.14);
}

.ij-desk-step-ticker-chip--zone {
    color: var(--mud-palette-success);
    background: rgba(61, 203, 108, 0.14);
}

.ij-desk-step-ticker-chip--stale {
    color: var(--mud-palette-warning);
    background: rgba(255, 181, 69, 0.14);
}

.ij-desk-step-ticker-chip--event {
    color: var(--ij-event);
    background: var(--ij-event-tint);
}

/* Task 4b's convention, not a row-type switch: direction is derived from the
   FIGURE (DeskStepCard.FigureDirectionClass), reusing the same --ij-gain/--ij-loss
   tokens as .ij-desk-lead-figure. */
/* Wraps the figure + its optional "at firing" qualifier (fix 6) so the pair stacks
   on the RIGHT edge of .ij-desk-step-row while the ticker on the left keeps its own
   baseline alignment — .ij-desk-step-figure itself is unchanged for the common case
   (no qualifier), this wrapper is what stacks the two lines when one is present. */
.ij-desk-step-figure-wrap {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    flex-shrink: 0;
}

.ij-desk-step-figure {
    flex-shrink: 0;
    font-size: 24px;
    font-weight: 700;
    text-align: right;
}

/* #1503 M3b, canvas #1e: the EarningsAhead hero slot holds the period label ("Q2
   2026") — 22px/700 secondary, neither gain nor loss. */
.ij-desk-step-figure--label {
    font-size: 22px;
    letter-spacing: -0.03em;
    color: var(--mud-palette-text-secondary);
}

.ij-desk-step-figure--gain {
    color: var(--ij-gain);
}

.ij-desk-step-figure--loss {
    color: var(--ij-loss);
}

/* #1488 M2b Task 3: evidence lines now carry real numbers + an optional quote
   ("$61.20 vs your $78 — you wrote 'buy zone under $66.'"), routinely longer
   than the old one-clause sentence this single-line nowrap+ellipsis rule was
   sized for. Canvas #6a's own evidence line wraps (line-height:1.5, no
   white-space:nowrap) — matched here rather than truncating real numbers off
   the end of the line. */
.ij-desk-step-evidence {
    font-size: 0.8125rem; /* 13px */
    line-height: 1.5;
    color: var(--mud-palette-text-secondary);
}

/* ── Overflow ledge (#1488 M2 Task 5) — rank 5+ ──────────────────────── */

.ij-desk-ledge {
    margin-top: 16px;
    padding: 12px 22px;
    border: 1px dashed var(--ij-divider);
    border-radius: 14px;
}

.ij-desk-ledge-summary-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
}

.ij-desk-ledge-summary {
    color: var(--mud-palette-text-secondary);
    font-size: 0.875rem;
}

/* A plain button, styled as a link — clicking it toggles state in place, it never
   navigates, so it must never be an <a>. */
.ij-desk-ledge-show {
    padding: 0;
    border: none;
    background: none;
    color: var(--mud-palette-primary);
    font: inherit;
    font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
}

.ij-desk-ledge-rows {
    display: flex;
    flex-direction: column;
    margin-top: 10px;
}

.ij-desk-ledge-row {
    display: flex;
    align-items: baseline;
    gap: 10px;
    padding: 8px 0;
    border-top: 1px solid var(--ij-divider);
    text-decoration: none;
    color: inherit;
}

.ij-desk-ledge-row:first-child {
    border-top: none;
}

.ij-desk-ledge-row-ticker {
    flex-shrink: 0;
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--mud-palette-text-primary);
}

.ij-desk-ledge-row-company {
    overflow: hidden;
    font-size: 0.8125rem;
    color: var(--mud-palette-text-secondary);
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ── Converging lead (#1488 M2 Task 6) — two-or-more triggers, one company ──── */

/* Deliberately NOT an <a> like .ij-desk-lead: this card carries two distinct
   actions (review vs. valuation), so the whole card cannot be one link. Same
   surface/border/radius as .ij-desk-lead and reuses its tint gradients — this is
   still the desk's rank-1 position, just a different internal layout. */
.ij-desk-converging {
    display: flex;
    flex-direction: column;
    gap: 20px;
    padding: 32px 36px;
    border-radius: 18px;
    border: 1px solid var(--ij-divider);
    /* #1488 M2b Task 1 fix: THIS was the actual live bug — the `background`
       shorthand here sat AFTER .ij-desk-tint-review/-zone/-stale in the file (they
       are declared up near .ij-desk-lead, long before this rule), so at equal
       specificity this later declaration's implicit `background-image: none` won
       the cascade and silently overwrote the tint every time. Verified live via
       Playwright/getComputedStyle before this fix: `.ij-desk-converging
       .ij-desk-tint-review` computed `background-image: none`; after switching to
       the longhand it computes the real radial-gradient (see
       DeskTintCascadeTests). See .ij-desk-lead's own comment above for why THAT
       card's identical shorthand happened not to exhibit the bug. */
    background-color: var(--mud-palette-surface);
}

/* #1488 M2b Task 1, canvas #7b: icon + label per trigger, each in its own row-type
   colour, joined by a plain grey "+" — was one flat grey 12px/600 run with no
   icon and no per-label colour. */
.ij-desk-eyebrow {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.ij-desk-eyebrow-item {
    display: inline-flex;
    align-items: center;
    gap: 7px;
}

.ij-desk-eyebrow-item--review {
    color: var(--ij-primary);
}

.ij-desk-eyebrow-item--zone {
    color: var(--ij-gain);
}

.ij-desk-eyebrow-item--stale {
    color: var(--mud-palette-warning);
}

.ij-desk-eyebrow-item--event {
    color: var(--ij-event);
}

.ij-desk-eyebrow-plus {
    color: var(--mud-palette-text-secondary);
    font-weight: 600;
    text-transform: none;
    letter-spacing: normal;
}

/* Fix round 1, Finding 2: a third trigger on the same company is real
   (DeskRanker's merge has no cap) — this surfaces the count it would otherwise
   silently drop, echoing DeskLedge's own overflow convention without needing to
   be expandable itself. Normal case (no third trigger, well under 599.95px) is
   just a lowercase-tracking span next to the eyebrow, so it never fights the
   eyebrow's own uppercase/letter-spacing treatment for attention. */
.ij-desk-converging-overflow {
    margin-left: 8px;
    text-transform: none;
    letter-spacing: normal;
    color: var(--mud-palette-text-secondary);
    opacity: 0.8;
}

.ij-desk-converging-headline {
    font-size: 34px;
    font-weight: 600;
    line-height: 1.3;
    color: var(--mud-palette-text-primary);
}

/* Two-up stat grid, one panel per trigger — spec's own "two-up panel grid", radius
   12px on the flat rgba(120,120,128,0.09) wash (never a bordered card: that reads
   as a THIRD card shape on a page that already has the lead surface and the step
   card surface). */
/* #1488 M2b Task 5 fix (REGRESSION from Task 2c): Task 2c's own reasoning — treat
   this like the lead rail's 340px cap — does not hold for this grid, and the
   460px cap it introduced was itself the bug the user caught side-by-side against
   canvas #7b. The lead rail is a SIDEBAR beside body copy (1.25fr main / capped
   rail track): capping it stops a stat block that only ever holds a label +
   hero + sparkline from stretching to ~600px of empty space. .ij-desk-panels is
   not a sidebar — canvas #7b's two panels ARE the card's body, side by side, and
   are meant to track the card's own width exactly like a two-column table. A
   fixed 460px+460px+12px gap (932px) left a large dead strip on the right of any
   card wider than that — visible immediately at 1920px, where the converging
   card spans the full page gutter but its panels stopped at roughly two-thirds
   across. `1fr 1fr` lets both panels grow with the card, same as the two-up step
   card grid below (.ij-desk-steps--2) already does with no cap of its own. */
.ij-desk-panels {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
}

.ij-desk-panel {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
    padding: 16px 18px;
    border-radius: 12px;
    background: rgba(120, 120, 128, 0.09);
}

/* #1488 M4 Task 1: a panel is not absolutely-overlaid (DeskConvergingLead is not
   one whole-card link — see its own doc), so its actions row sits in normal
   flow, right-aligned under the panel's own content. */
.ij-desk-panel > .ij-desk-actions {
    align-self: flex-end;
    margin-top: 4px;
}

/* #1488 M2b Task 3, canvas #7b: "THE PRICE"/"THE THESIS" render UPPERCASE via
   text-transform (the markup/resx text stays sentence case, "The price" —
   text-transform is what does the capitalising, same convention the eyebrow
   above already uses). Sized 11px/700/0.05em tracking to match the canvas
   exactly — was 12px/600/no-transform, a real fidelity gap the side-by-side
   caught (not just a colour/weight mismatch: sentence-case text read as a
   different, quieter design entirely). Colour stays
   --mud-palette-text-secondary, NOT --ij-text-tertiary (canvas's own token)
   — tertiary fails AA contrast in this app, see the
   reference_ij_text_tertiary_fails_aa memory; secondary is the established
   substitute every other label on this card already uses
   (.ij-desk-rail-label, .ij-desk-panel-subline). */
.ij-desk-panel-label {
    overflow: hidden;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--mud-palette-text-secondary);
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Same figure scale as the step cards' hero number — smaller than the single-lead
   44px, because two of these sit side by side. Direction colour is the SAME shared
   rule as .ij-desk-lead-figure/.ij-desk-step-figure (DeskFigureFormatter) — see
   DeskConvergingLead.FigureDirectionClass. */
.ij-desk-panel-figure {
    font-size: 26px;
    font-weight: 700;
    letter-spacing: -0.02em;
    line-height: 1.1;
    color: var(--mud-palette-text-primary);
}

.ij-desk-panel-figure--gain {
    color: var(--ij-gain);
}

.ij-desk-panel-figure--loss {
    color: var(--ij-loss);
}

/* #1488 M2b Task 3, canvas #7b: "22% under **your $78**" — inline secondary-text
   context trailing the panel's own hero figure, never its own line. */
.ij-desk-panel-figure-context {
    margin-left: 6px;
    font-size: 14px;
    font-weight: 600;
    color: var(--mud-palette-text-secondary);
}

/* Canvas #7b: each panel's own explanatory line under the figure — a real
   thesis quote ("You wrote: ...") for the price panel, the fiscal-year
   sentence for a stale panel, or the existing Reason(row) text otherwise. */
.ij-desk-panel-subline {
    margin-top: 2px;
    font-size: 0.78125rem; /* 12.5px */
    line-height: 1.5;
    color: var(--mud-palette-text-secondary);
}

/* The CTA row sequences the work rather than offering two equal choices: a filled
   primary pill ("do this first") beside a plain secondary link ("or skip to this
   instead") — never two buttons of the same weight. */
.ij-desk-converging-actions {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 20px;
}

.ij-desk-cta-primary {
    display: inline-flex;
    align-items: center;
    padding: 10px 20px;
    border-radius: 999px;
    background: var(--mud-palette-primary);
    color: #fff;
    font-size: 0.875rem;
    font-weight: 600;
    text-decoration: none;
}

.ij-desk-cta-primary:hover {
    opacity: 0.92;
}

.ij-desk-cta-secondary {
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--mud-palette-text-secondary);
    text-decoration: none;
}

.ij-desk-cta-secondary:hover {
    color: var(--mud-palette-text-primary);
}

@media (max-width: 599.95px) {
    .ij-desk-converging-headline {
        font-size: 26px;
    }

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

/* ── Quiet strip (#1488 M2b Task 4) — canvas #6a/#8a ─────────────────── */

.ij-desk-quiet {
    margin-top: 26px;
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

.ij-desk-quiet-label {
    margin-right: 6px;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--mud-palette-text-secondary);
}

.ij-desk-quiet-pill {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    padding: 8px 14px;
    border-radius: 999px;
    border: 1px solid var(--ij-divider);
    font-size: 12.5px;
    color: var(--mud-palette-text-secondary);
    text-decoration: none;
}

.ij-desk-quiet-pill:hover {
    border-color: rgba(120, 120, 128, 0.5);
}

.ij-desk-quiet-pill-ticker {
    color: var(--mud-palette-text-primary);
    font-weight: 600;
}

.ij-desk-quiet-pill-figure {
    font-variant-numeric: tabular-nums;
}

.ij-desk-quiet-pill-figure--gain {
    color: var(--ij-gain);
}

.ij-desk-quiet-pill-figure--loss {
    color: var(--ij-loss);
}

/* A dashed pill styled as a button (it opens the search dialog, never a link) —
   same shape/size as the pills beside it so it reads as the last chip in the
   strip, not a separate control. */
.ij-desk-quiet-add {
    padding: 8px 14px;
    border: 1px dashed var(--ij-divider);
    border-radius: 999px;
    background: none;
    color: var(--mud-palette-primary);
    font-size: 12.5px;
    font-weight: 500;
    cursor: pointer;
}

.ij-desk-quiet-add:hover {
    border-color: rgba(120, 120, 128, 0.7);
}

/* ── Resume strip (#1488 M2 turn 9 Task 2) — canvas [id="9a"] (final) ──────
   "Pick up where you left off", rebuilt from M2b's chips into 9a's work-snapshot
   CARDS. Every value below is the artboard's own: 14px radius, 1px divider border,
   16px 18px 14px 20px padding, a 3px left spine, 10.5px/700 eyebrow, 15px/700
   company, 11.5px/600 ticker, 12px state line, 11px/600 verb link.

   No progress-bar rule exists here on purpose — see DeskResumeStrip.razor: neither
   DCF inputs nor thesis sections yield a truthful fraction, so every card takes 9a's
   own verb-link fallback. The bar would have nothing honest to fill. */

.ij-desk-resume {
    margin-top: 26px;
}

.ij-desk-resume-head {
    display: flex;
    align-items: baseline;
    gap: 12px;
}

.ij-desk-resume-label {
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--mud-palette-text-secondary);
}

/* Right-aligned per 9a. --mud-palette-text-secondary rather than the artboard's
   --ij-text-tertiary for the same reason .ij-desk-quiet-label and
   .ij-desk-resume-label above already deviate: tertiary is #a1a1a6 on white, ~2.5:1,
   which fails AA outright for a 12px control. It is a clickable affordance, so it
   also brightens to the primary text colour on hover. */
.ij-desk-resume-clear {
    margin-left: auto;
    padding: 0;
    border: none;
    background: none;
    font: inherit;
    font-size: 12px;
    font-weight: 600;
    color: var(--mud-palette-text-secondary);
    cursor: pointer;
}

.ij-desk-resume-clear:hover {
    color: var(--mud-palette-text-primary);
}

/* 9a: repeat(4, 1fr), gap 12px — and 1fr, not the capped minmax() M2b's five chips
   needed. These cards carry four rows of content (eyebrow, identity, state line,
   verb), so a wide viewport stretching them to ~330px fills them rather than
   emptying them; the artboard's own tracks are already 264px at its 1092px measure. */
.ij-desk-resume-grid {
    margin-top: 12px;
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 12px;
}

.ij-desk-resume-card {
    position: relative;
    display: block;
    min-width: 0;
    overflow: hidden;
    padding: 16px 18px 14px 20px;
    border-radius: 14px;
    border: 1px solid var(--ij-divider);
    background: var(--mud-palette-surface);
    text-decoration: none;
    color: inherit;
}

.ij-desk-resume-card:hover {
    border-color: rgba(120, 120, 128, 0.5);
}

.ij-desk-resume-spine {
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 3px;
}

/* The surface colour-coding — 9a's whole "scans by shape before you read a word"
   claim. --ij-lp-purple IS defined, on bare :root in tokens.css (#a855f7) and
   deliberately not overridden under .ij-theme-dark, so it paints identically in
   both themes; it is a global token despite the landing-page-derived name. */
.ij-desk-resume-card--valuation .ij-desk-resume-spine {
    background: var(--ij-primary);
}

.ij-desk-resume-card--thesis .ij-desk-resume-spine {
    background: var(--ij-lp-purple);
}

.ij-desk-resume-card--researching .ij-desk-resume-spine {
    background: var(--ij-text-tertiary);
}

.ij-desk-resume-eyebrow {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.ij-desk-resume-card--valuation .ij-desk-resume-eyebrow {
    color: var(--ij-primary);
}

/* The spine above keeps the design's #a855f7 (a 3px decorative fill has no
   contrast requirement); the 10.5px eyebrow TEXT does not — #a855f7 is 3.96:1 on
   the light surface, under AA's 4.5:1 for small text. --ij-lp-purple-text is the
   same hue at 5.38:1 in light and reverts to #a855f7 in dark, where the base
   purple already measures 4.91:1. Surface colour-coding is preserved. */
.ij-desk-resume-card--thesis .ij-desk-resume-eyebrow {
    color: var(--ij-lp-purple-text);
}

/* 9a itself splits these two: the researching card's SPINE is --ij-text-tertiary but
   its eyebrow TEXT is a step brighter, because 10.5px uppercase at tertiary is
   unreadable. Kept exactly as the artboard has it. */
.ij-desk-resume-card--researching .ij-desk-resume-eyebrow {
    color: var(--mud-palette-text-secondary);
}

.ij-desk-resume-eyebrow-icon {
    flex-shrink: 0;
    width: 12px;
    height: 12px;
    font-size: 12px;
}

.ij-desk-resume-time {
    margin-left: auto;
    padding-left: 6px;
    font-weight: 600;
    text-transform: none;
    letter-spacing: 0;
    white-space: nowrap;
    color: var(--mud-palette-text-secondary);
}

.ij-desk-resume-identity {
    margin-top: 9px;
    display: flex;
    align-items: baseline;
    gap: 8px;
    min-width: 0;
}

.ij-desk-resume-name {
    overflow: hidden;
    font-size: 15px;
    font-weight: 700;
    letter-spacing: -0.015em;
    color: var(--mud-palette-text-primary);
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ij-desk-resume-ticker {
    flex-shrink: 0;
    font-size: 11.5px;
    font-weight: 600;
    color: var(--mud-palette-text-secondary);
}

.ij-desk-resume-state {
    margin-top: 4px;
    font-size: 12px;
    line-height: 1.45;
    color: var(--mud-palette-text-secondary);
}

.ij-desk-resume-verb {
    margin-top: 10px;
    font-size: 11px;
    font-weight: 600;
    color: var(--ij-primary);
}

/* ── Streak footer (#1488 M2b Task 4) — canvas #6b/#2b footer shape ─────── */

.ij-desk-streak {
    margin-top: 26px;
    padding-top: 16px;
    border-top: 1px solid var(--ij-divider);
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    color: var(--mud-palette-text-secondary);
}

.ij-desk-streak-icon {
    width: 15px;
    height: 15px;
    flex-shrink: 0;
}

@media (max-width: 960px) {
    .ij-desk-resume-grid {
        grid-template-columns: repeat(2, 1fr);
    }
}

/* One column below the app's narrow breakpoint. Two 9a cards side by side at 375px
   would leave ~170px of track for a 15px company name plus a 12px sentence — the
   name would ellipsis away on almost every real company. */
@media (max-width: 599.95px) {
    .ij-desk-resume-grid {
        grid-template-columns: 1fr;
    }
}

/* ── Responsive (#1488 M2 Task 7) ─────────────────────────────────────
   The handoff is 1092px-desktop-only — no mobile frame exists. These two
   breakpoints match the ones already used in home-view.css (599.95 / 960 /
   1400); the per-component 599.95px rules above (lead headline/figure,
   step grid, converging headline/panels) were written alongside each
   component in Tasks 4-6 and are left in place rather than merged here. */

@media (max-width: 960px) {
    .ij-desk {
        padding: 24px 20px 64px;
    }

    /* The stat rail moves below the copy; its 1px left divider becomes a
       top border (DeskLeadCard.razor's rail is `.ij-desk-lead-rail`, not
       the bare `.ij-desk-rail` the brief's own snippet named). */
    .ij-desk-lead {
        grid-template-columns: 1fr;
        gap: 20px;
    }

    .ij-desk-lead-rail {
        border-left: none;
        border-top: 1px solid var(--ij-divider);
        padding-top: 16px;
        padding-left: 0;
    }

    /* Supersedes the narrower 599.95px-only rule these two modifiers used
       to carry (removed as dead weight): 1-up now starts at 960px, same as
       the lead card and per spec §5.4. */
    .ij-desk-steps,
    .ij-desk-steps--2,
    .ij-desk-steps--3 {
        grid-template-columns: 1fr;
    }
}

@media (max-width: 599.95px) {
    .ij-desk-lead {
        padding: 20px 18px;
    }

    /* Acceptance-pass fix (#1488 M2 Task 7) — real, not a contrived edge
       case: DeskGreeting.razor's DisplayName falls back to the full
       username/email when no first/last name is set (its own doc comment
       says so), and at that length the title wraps to two lines while the
       right-aligned, white-space:nowrap meta line stays pinned to
       justify-content:space-between's far edge — verified pushing it
       224px past the 375px viewport (documentElement.scrollWidth 598 vs
       clientWidth 375), a genuine horizontal-overflow FAIL, not a
       screenshot artifact. Stacked and left-aligned below the title at
       this width fixes it; unlike the fixed AI panel/bottom-nav offenders
       ruled out during this same pass, this one is inside .ij-desk. */
    .ij-desk-greeting {
        flex-direction: column;
        align-items: flex-start;
        gap: 4px;
    }

    /* #1488 M2b Task 5: the meta line grew a third segment ("ranked by cost of
       ignoring" — canvas's own tagline, see .ij-desk-greeting-tagline below).
       .ij-desk-greeting-meta's base rule is a single-line flex row with
       white-space:nowrap (by design at desktop widths, where all three segments
       fit); at 375px that combination no longer fits and both the row's own
       nowrap and its INHERITED white-space would keep every span glued to one
       overflowing line. Wrapping is allowed here, not width-truncated: this is a
       real sentence, not a number that must stay legible on one line the way the
       date+count pairing does. */
    .ij-desk-greeting-meta {
        text-align: left;
        flex-wrap: wrap;
        white-space: normal;
        row-gap: 2px;
    }

    /* There is no hover on touch: the hover-only actions are always visible.
       #1488 M4 Task 1 now renders .ij-desk-snooze/.ij-desk-not-useful (this rule
       was previously dead scaffolding, written ahead of that markup) — the base
       rule (further up this file) also sets `pointer-events: none` alongside
       `opacity: 0` so a hidden desktop pill can't be tabbed to; both must be
       overridden together here, or a touch user would see the pill but be
       unable to tap it. */
    .ij-desk-snooze,
    .ij-desk-not-useful {
        opacity: 1;
        pointer-events: auto;
    }

    /* Acceptance-pass fix (#1488 M4 Task 1): the lead/step actions row is
       absolutely positioned top-right on desktop, over blank card padding
       above the eyebrow — harmless while hidden, but at this width the pills
       are ALWAYS visible (no hover to reveal them), and the same top-right
       corner is where the eyebrow's own text ("FIRST ON THE DESK · REVIEW DUE
       TODAY") runs, verified overlapping in a live 375px capture. Taking the
       actions row out of absolute positioning here returns it to normal flow
       — for .ij-desk-lead (already a single grid column below 960px, see the
       ≤960px block above) it becomes its own row before the eyebrow; for
       .ij-desk-step (a column flexbox) the same DOM-order reasoning applies.
       Converging panels are unaffected — .ij-desk-panel > .ij-desk-actions was
       never absolutely positioned (see its own rule), so it already sits
       correctly below the panel's own content at every width. */
    .ij-desk-lead > .ij-desk-actions,
    .ij-desk-step > .ij-desk-actions {
        position: static;
        justify-content: flex-end;
        margin-bottom: 8px;
    }
}

/* #1708: the two rules above keyed "no hover on touch" off WIDTH, and the two
   part company on an Android tablet — at 800dp the pills stayed hidden and no
   hover existed to reveal them, so a touch user could not dismiss a row at all
   (verified on the emulator at 1600×2560 @ 320dpi). The always-visible state
   belongs to the pointer capability, so it is repeated here under the query
   that names it — the same one portfolio.css uses for the account card's touch
   actions — while the width rule stays for narrow pointer viewports. Both halves
   of the base rule are overridden (opacity AND pointer-events), and the actions
   row leaves its absolute top-right corner for the same eyebrow-overlap reason
   the phone rule gives. DeskTouchPillsCssContractTests pins all three. */
@media (hover: none) {
    .ij-desk-snooze,
    .ij-desk-not-useful {
        opacity: 1;
        pointer-events: auto;
    }

    .ij-desk-lead > .ij-desk-actions,
    .ij-desk-step > .ij-desk-actions {
        position: static;
        justify-content: flex-end;
        margin-bottom: 8px;
    }
}

/* ── Arrival motion (#1488 M4 Task 2, spec §5.5, canvas #6c) ─────────────
   Pure CSS keyframes — Blazor exposes no animation events (the M4 plan's own
   note), so nothing here is driven from C#, with one narrow, approved
   exception (a MOUNT signal, never an animation trigger — see
   desk-motion.js's own top-of-file doc). That companion module
   (wwwroot/js/desk-motion.js, registered in App.razor next to the app's
   other plain script-tag modules) does exactly one thing, once per real
   page view: decide whether THIS BROWSER SESSION has already played the
   motion, and if this is a genuine first play, OPT the container IN by
   adding `data-desk-animate` to it.

   #1488 M4 Task 3 fix (F3) — THE GATE IS INVERTED from the shape M4 Task 2
   originally shipped. That version defaulted to animating and had JS opt
   OUT (`data-desk-played`, `:not([data-desk-played])`) — which meant every
   moment before the flag landed was, by construction, a moment of invisible
   (0%-keyframe) content. A full page reload swaps the ENTIRE `.ij-desk`
   element for a fresh one when the interactive circuit takes over from the
   prerendered markup (see desk-motion.js's own doc on that swap), and a
   verification pass caught a real ~7-9ms window — confirmed with a painted
   CDP screencast frame, not an inference — where the fresh container had
   NOT yet been re-stamped and so rendered its animated elements invisible
   while the non-animated quiet/resume strips drew normally.

   Below, the DEFAULT (no `data-desk-animate` attribute) is the final frame
   — every selector requires `[data-desk-animate]` to match at all, so an
   unstamped container (which is what EVERY container is, prerendered or
   interactive, until the mount signal explicitly opts it in) simply never
   matches any entrance rule and renders its plain declared styles, which
   already equal each keyframe's `to` state. A blank frame during the
   prerender -> interactive swap is now impossible, not merely unlikely: the
   freshly-swapped container starts with NO attribute, which was already the
   "show everything" state even before this fix — there is no window,
   however short, where it could read as "hide everything." The no-JS path
   (module fails to load entirely) renders correctly for the same reason,
   for free.

   `@media (prefers-reduced-motion: reduce)` mirrors every selector verbatim
   (same specificity, later in the file) to force `animation: none` (plus an
   explicit `opacity: 1` for the hero figure — see its own rule's doc for why
   that one needs restoring separately) regardless of the attribute — belt
   and suspenders against a hypothetical bug in desk-motion.js's own
   `prefersReducedMotion()` check, not because the JS is expected to get it
   wrong.

   ── `--ij-desk-anim-elapsed`: the RESUME OFFSET ─────────────────────────────
   Every delay below is written `calc(<designed delay> - var(
   --ij-desk-anim-elapsed, 0ms))`, and NO rule carries a delay in its
   `animation` shorthand (the shorthand resets `animation-delay`, so a delay
   left in both places would be decided by declaration order — a trap, not a
   style choice). DeskArrivalMotionResumeTests pins both halves.

   Why: the prerender -> interactive swap replaces the whole `.ij-desk`
   element (see desk-motion.js's own doc). Both containers get stamped, so
   before this offset existed the entrance ran on the prerendered container
   and then AGAIN, from zero, on its replacement. desk-motion.js's header
   called that "a sub-perceptual ~20ms discontinuity" — true only on
   localhost, where the circuit connects in ~50ms. The real gap is however
   long the circuit takes, which is network-bound: measured 1588ms at 60ms
   RTT and 2166ms at 150ms RTT, i.e. long enough for the first desk to finish
   its whole ~1200ms entrance and sit settled before being wiped and replayed.
   That is the "the home page loads twice" report.

   desk-motion.js sets this property (in ms) on every container AFTER the
   first of a page view, to how long ago that first play started. The
   subtraction then means:

     * offset 0 (absent — the first container, or no JS at all): every rule
       computes to its designed delay and the motion plays exactly as before;
     * offset smaller than a rule's delay + duration: negative computed delay,
       so that rule resumes MID-FLIGHT where its predecessor left off;
     * offset past a rule's delay + duration: the computed delay is negative
       beyond the animation's own length, and `both`/`forwards` fill puts the
       element straight on its final frame with no motion at all.

   So the replacement never rewinds, at any latency, and the no-JS path still
   renders correctly for free (the `0ms` fallback IS the designed delay). */

@keyframes ij-desk-fade-rise {
    from {
        opacity: 0;
        transform: translateY(12px);
    }
    to {
        opacity: 1;
        transform: none;
    }
}

/* stroke-dasharray below is a fixed 700 — comfortably longer than the
   longest real polyline: DeskRailBuilder downsamples to ~13 points inside a
   100x52 viewBox (DeskSparkline's own ViewBoxWidth/Height), whose worst-case
   zigzag total is ~632 units. A fixed constant (rather than a per-instance
   computed length) needs no per-row JS/inline-style plumbing and is exactly
   the standard "draw a path with CSS alone" technique — see MDN's
   stroke-dashoffset article for the same trick under an unknown path length. */
@keyframes ij-desk-sparkline-draw {
    from {
        stroke-dashoffset: 700;
    }
    to {
        stroke-dashoffset: 0;
    }
}

/* #1488 M4 Task 3 fix (F2): the hero %'s own reveal — see
   .ij-desk-lead-figure's rule below for why this exists as a separate,
   near-instant keyframe rather than reusing ij-desk-fade-rise. */
@keyframes ij-desk-hero-reveal {
    to {
        opacity: 1;
    }
}

/* 0-300ms: greeting title + meta. Plays on every branch that renders
   DeskGreeting, including the empty state (spec: "the greeting motion should
   still play; there is nothing to stagger" — no lead/step selectors below
   need to exist for this rule to do its job). */
.ij-desk[data-desk-animate] .ij-desk-greeting-title,
.ij-desk[data-desk-animate] .ij-desk-greeting-meta {
    animation: ij-desk-fade-rise 300ms cubic-bezier(0.16, 1, 0.3, 1) both;
    animation-delay: calc(0ms - var(--ij-desk-anim-elapsed, 0ms));
}

/* 300-900ms: the lead position enters — DeskLeadCard's single-trigger
   `.ij-desk-lead` or DeskConvergingLead's merged `.ij-desk-converging`.
   MorningDesk.razor renders exactly one of the two, never both. */
.ij-desk[data-desk-animate] .ij-desk-lead,
.ij-desk[data-desk-animate] .ij-desk-converging {
    animation: ij-desk-fade-rise 350ms cubic-bezier(0.16, 1, 0.3, 1) both;
    animation-delay: calc(300ms - var(--ij-desk-anim-elapsed, 0ms));
}

/* Step-down cards at an 80ms stagger after the lead. At most 3 siblings ever
   render under `.ij-desk-steps` (ranks 2-4 — DeskTiersTests pins the
   --2/--3 grid-count contract), so three nth-child rules cover every real
   layout; a 1-card layout (`.ij-desk-steps--1`, no dedicated grid rule of its
   own — see that class's comment above) still matches :nth-child(1) here. */
.ij-desk[data-desk-animate] .ij-desk-steps > .ij-desk-step:nth-child(1) {
    animation: ij-desk-fade-rise 350ms cubic-bezier(0.16, 1, 0.3, 1) both;
    animation-delay: calc(380ms - var(--ij-desk-anim-elapsed, 0ms));
}

.ij-desk[data-desk-animate] .ij-desk-steps > .ij-desk-step:nth-child(2) {
    animation: ij-desk-fade-rise 350ms cubic-bezier(0.16, 1, 0.3, 1) both;
    animation-delay: calc(460ms - var(--ij-desk-anim-elapsed, 0ms));
}

.ij-desk[data-desk-animate] .ij-desk-steps > .ij-desk-step:nth-child(3) {
    animation: ij-desk-fade-rise 350ms cubic-bezier(0.16, 1, 0.3, 1) both;
    animation-delay: calc(540ms - var(--ij-desk-anim-elapsed, 0ms));
}

/* 600-1200ms: the sparkline draws (the honest stroke-dashoffset technique —
   not a clip-path/opacity fake) and the SVG's fill wash fades in alongside
   the line it sits under, rather than popping in the instant the line starts
   drawing. */
.ij-desk[data-desk-animate] .ij-desk-sparkline {
    animation: ij-desk-fade-rise 400ms cubic-bezier(0.16, 1, 0.3, 1) both;
    animation-delay: calc(600ms - var(--ij-desk-anim-elapsed, 0ms));
}

.ij-desk[data-desk-animate] .ij-desk-sparkline-line {
    animation: ij-desk-sparkline-draw 600ms cubic-bezier(0.16, 1, 0.3, 1) both;
    animation-delay: calc(600ms - var(--ij-desk-anim-elapsed, 0ms));
}

/* #1488 M4 Task 3 fix (F2): the hero %'s own count-up is JS
   (desk-motion.js), never CSS — DeskFigureFormatter is this app's one place
   a DeskFigure becomes text (the M4 plan's own constraint), so nothing here
   re-derives or re-parses that string's meaning; the JS module only
   re-plays digits the server already formatted. This rule's job is narrower
   than that: it owns the figure's VISIBILITY, independently of its
   ancestor `.ij-desk-lead`'s own fade-rise above.

   A verification pass caught a real bug from the ORIGINAL version, which
   had no rule of its own here at all: the ancestor `.ij-desk-lead` reaches
   full opacity by ~650ms (300ms delay + 350ms duration), which is AFTER the
   hero figure's count-up is scheduled to start (600ms) but BEFORE its first
   write actually lands (the first `requestAnimationFrame` tick after that
   delay) — so for a real, measured ~25ms window the user saw the
   server-rendered FINAL value at full opacity, watched it reset to zero,
   then climb back — a worse experience than no animation at all. Hiding the
   figure until its OWN 600ms mark (independent of the ancestor already
   being visible) closes that: whatever the ancestor is doing, this element
   is not on screen until desk-motion.js's own reveal, and that module
   additionally resets the DOM text to zero SYNCHRONOUSLY — not on the first
   rAF tick — the instant it decides to animate this container, so there is
   no instant, however brief, at which becoming visible could show the old
   text (closes the same race one layer down: a CSS animation-delay clock
   and a JS setTimeout are two independently-scheduled timers that are not
   guaranteed to fire in the same tick).

   `1ms` duration, not `ij-desk-fade-rise`'s 300-400ms: this is a reveal, not
   an entrance — the number's own "arrival" IS the count-up climbing, so the
   element itself should simply become visible as close to instantaneously
   as an `animation` (rather than a discontinuous style swap with no
   transition semantics at all) can express, right as the JS write lands. */
.ij-desk[data-desk-animate] .ij-desk-lead-figure {
    opacity: 0;
    animation: ij-desk-hero-reveal 1ms linear forwards;
    animation-delay: calc(600ms - var(--ij-desk-anim-elapsed, 0ms));
}

@media (prefers-reduced-motion: reduce) {
    .ij-desk[data-desk-animate] .ij-desk-greeting-title,
    .ij-desk[data-desk-animate] .ij-desk-greeting-meta,
    .ij-desk[data-desk-animate] .ij-desk-lead,
    .ij-desk[data-desk-animate] .ij-desk-converging,
    .ij-desk[data-desk-animate] .ij-desk-steps > .ij-desk-step:nth-child(1),
    .ij-desk[data-desk-animate] .ij-desk-steps > .ij-desk-step:nth-child(2),
    .ij-desk[data-desk-animate] .ij-desk-steps > .ij-desk-step:nth-child(3),
    .ij-desk[data-desk-animate] .ij-desk-sparkline,
    .ij-desk[data-desk-animate] .ij-desk-sparkline-line {
        animation: none;
    }

    /* The hero figure rule (above) is the one selector in this file that sets
       a STATIC `opacity: 0` alongside its animation, not just a keyframe —
       every other selector here relies entirely on the animation to move
       away from an implicit default opacity: 1, so `animation: none` alone
       correctly restores them. This one needs its opacity restored
       explicitly too, or a reduced-motion visitor would see the hero number
       PERMANENTLY invisible instead of the required correct static figure. */
    .ij-desk[data-desk-animate] .ij-desk-lead-figure {
        animation: none;
        opacity: 1;
    }
}

/* ── "Your list" (canvas 11a) — the desk's one user-authored block ──────────
   Values are the handoff's, with two standing house deviations: every "tertiary"
   small text uses --mud-palette-text-secondary (the artboard's tertiary fails AA
   at these sizes — same deviation .ij-desk-resume-label documents), and the due
   chip's amber is --mud-palette-warning (--ij-amber does not exist in tokens.css,
   verified against origin/main during the earnings-loop handoff review). */

.ij-desk-list {
    margin-top: 26px;
}

.ij-desk-list-head {
    display: flex;
    align-items: baseline;
    gap: 12px;
    margin-bottom: 10px;
}

.ij-desk-list-head-text {
    display: flex;
    align-items: baseline;
    gap: 12px;
}

.ij-desk-list-label {
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--mud-palette-text-secondary);
}

.ij-desk-list-count {
    font-size: 12px;
    color: var(--mud-palette-text-secondary);
    font-variant-numeric: tabular-nums;
}

.ij-desk-list-customize {
    margin-left: auto;
    padding: 0;
    border: none;
    background: none;
    font: inherit;
    font-size: 12px;
    font-weight: 600;
    color: var(--ij-primary);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 5px;
}

.ij-desk-list-customize-icon {
    width: 13px;
    height: 13px;
}

.ij-desk-list-card {
    border-radius: 16px;
    background-color: var(--mud-palette-surface);
    border: 1px solid var(--ij-divider);
    overflow: hidden;
}

.ij-desk-list-row {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 14px 22px;
    cursor: pointer;
    position: relative;
}

.ij-desk-list-row + .ij-desk-list-row {
    border-top: 1px solid var(--ij-divider);
}

.ij-desk-list-row:hover {
    background-color: rgba(120, 120, 128, 0.08);
}

.ij-desk-list-row--drop {
    box-shadow: inset 0 2px 0 var(--ij-primary);
}

.ij-desk-list-check {
    flex: none;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    border: 1.5px solid rgba(120, 120, 128, 0.7);
    background: none;
    padding: 0;
    cursor: pointer;
}

.ij-desk-list-check--done {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: none;
    background-color: var(--ij-gain);
}

.ij-desk-list-check-glyph {
    width: 11px;
    height: 11px;
    color: #000;
}

.ij-desk-list-check--add {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1.5px dashed rgba(120, 120, 128, 0.5);
    color: var(--mud-palette-text-secondary);
    font-size: 13px;
    line-height: 1;
    cursor: default;
}

.ij-desk-list-text {
    flex: 1;
    min-width: 0;
    font-size: 14.5px;
    color: var(--mud-palette-text-primary);
}

.ij-desk-list-ticker {
    flex: none;
    font-size: 11.5px;
    font-weight: 600;
    color: var(--ij-primary);
}

.ij-desk-list-due {
    flex: none;
    font-size: 11.5px;
    font-weight: 600;
    padding: 3px 9px;
    border-radius: 999px;
    color: var(--mud-palette-text-secondary);
    border: 1px solid var(--ij-divider);
    font-variant-numeric: tabular-nums;
}

/* Due today or overdue — the one warm accent this card is allowed. */
.ij-desk-list-due--warm {
    color: var(--mud-palette-warning);
    border: none;
    padding: 4px 10px;
    background-color: rgba(255, 181, 69, 0.14);
}

/* Same hidden-until-hover pill grammar as the desk cards' Snooze / "Not useful"
   (.ij-desk-snooze above) at this row's smaller scale, with the same
   ":focus-within" keyboard reveal and the same ≤599.95px always-visible
   override at the bottom of this section (no hover on touch). */
.ij-desk-list-actions {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.ij-desk-list-pill {
    font-size: 12px;
    font-weight: 600;
    color: var(--mud-palette-text-secondary);
    padding: 5px 10px;
    border-radius: 999px;
    border: 1px solid var(--ij-divider);
    background: none;
    cursor: pointer;
    opacity: 0;
    pointer-events: none;
    transition:
        opacity 120ms ease,
        border-color 120ms ease,
        color 120ms ease;
}

.ij-desk-list-pill:hover {
    border-color: rgba(120, 120, 128, 0.5);
    color: var(--mud-palette-text-primary);
}

.ij-desk-list-row:hover .ij-desk-list-pill,
.ij-desk-list-row:focus-within .ij-desk-list-pill,
.ij-desk-list-row:hover .ij-desk-list-grip,
.ij-desk-list-row:focus-within .ij-desk-list-grip {
    opacity: 1;
    pointer-events: auto;
}

.ij-desk-list-grip {
    display: inline-flex;
    align-items: center;
    color: var(--mud-palette-text-secondary);
    cursor: grab;
    opacity: 0;
    pointer-events: none;
}

.ij-desk-list-grip-icon {
    width: 16px;
    height: 16px;
}

.ij-desk-list-row--done {
    padding: 12px 22px;
    opacity: 0.55;
}

.ij-desk-list-text--done {
    font-size: 14px;
    color: var(--mud-palette-text-secondary);
    text-decoration: line-through;
}

.ij-desk-list-done-at {
    flex: none;
    font-size: 11.5px;
    color: var(--mud-palette-text-secondary);
    font-variant-numeric: tabular-nums;
}

.ij-desk-list-add {
    background-color: var(--ij-field);
    cursor: default;
}

.ij-desk-list-add:hover {
    background-color: var(--ij-field);
}

.ij-desk-list-add-anchor {
    position: relative;
    flex: 1;
    min-width: 0;
    display: flex;
}

.ij-desk-list-add-input {
    flex: 1;
    min-width: 0;
    border: none;
    background: none;
    font: inherit;
    font-size: 14.5px;
    color: var(--mud-palette-text-primary);
    outline: none;
    padding: 0;
}

.ij-desk-list-add-input::placeholder {
    color: var(--mud-palette-text-secondary);
    opacity: 1;
}

.ij-desk-list-add-hint {
    flex: none;
    font-size: 11.5px;
    color: var(--mud-palette-text-secondary);
}

.ij-desk-list-add-hint b {
    font-weight: 700;
}

.ij-desk-list-pending {
    cursor: pointer;
}

.ij-desk-list-due-menu {
    position: absolute;
    top: calc(100% + 8px);
    left: 0;
    z-index: 10;
    display: flex;
    flex-direction: column;
    min-width: 160px;
    padding: 6px;
    border-radius: 12px;
    background-color: var(--mud-palette-surface);
    border: 1px solid var(--ij-divider);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
}

.ij-desk-list-due-option {
    border: none;
    background: none;
    font: inherit;
    font-size: 13px;
    color: var(--mud-palette-text-primary);
    text-align: left;
    padding: 8px 10px;
    border-radius: 8px;
    cursor: pointer;
}

.ij-desk-list-due-option:hover {
    background-color: rgba(120, 120, 128, 0.08);
}

.ij-desk-list-due-date-input {
    font: inherit;
    font-size: 13px;
    color: var(--mud-palette-text-primary);
    background-color: var(--ij-field);
    border: 1px solid var(--ij-divider);
    border-radius: 8px;
    padding: 8px 10px;
}

.ij-desk-list-edit-input {
    flex: 1;
    min-width: 0;
    border: none;
    border-bottom: 1px solid var(--ij-primary);
    background: none;
    font: inherit;
    font-size: 14.5px;
    color: var(--mud-palette-text-primary);
    outline: none;
    padding: 0 0 2px;
}

/* Rule 4: the empty state is one 13px line + the add input — never an empty card,
   and the "card" wrapper here only rounds the add row itself. */
.ij-desk-list--empty .ij-desk-list-empty-line {
    display: block;
    font-size: 13px;
    color: var(--mud-palette-text-secondary);
    margin-bottom: 10px;
}

/* The stock page's mirror label (canvas 11d rule 7) — same grammar as the desk
   card's own header label. */
.ij-desk-list-mirror-label {
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--mud-palette-text-secondary);
    margin-bottom: 10px;
}

/* No hover on touch: the row pills are always visible at phone widths — the same
   override the desk cards' Snooze/"Not useful" pills take. */
@media (max-width: 599.95px) {
    .ij-desk-list-pill,
    .ij-desk-list-grip {
        opacity: 1;
        pointer-events: auto;
    }

    .ij-desk-list-row,
    .ij-desk-list-row--done {
        padding: 12px 16px;
        flex-wrap: wrap;
    }

    .ij-desk-list-add-hint {
        display: none;
    }
}

/* ── Canvas-16 fidelity pass (validated 2026-09-06 against artboard 11a) ─────
   Two deviations the first ship carried, caught by diffing the live card
   against the canvas:

   1. The hidden hover pills RESERVED their width (opacity: 0 keeps layout), so
      the ticker and due chip sat ~180px inboard of the row's right edge — the
      canvas draws them flush right, with the pills only existing on hover. The
      actions now overlay the row's right edge on hover-capable screens, and the
      chips fade out while they are shown so nothing collides; ≤599.95px keeps
      the always-visible pills IN FLOW (rows wrap there, and an overlay would
      permanently cover the chips). */
.ij-desk-list-actions {
    position: absolute;
    right: 14px;
    top: 50%;
    transform: translateY(-50%);
}

.ij-desk-list-row:hover .ij-desk-list-ticker,
.ij-desk-list-row:focus-within .ij-desk-list-ticker,
.ij-desk-list-row:hover .ij-desk-list-due,
.ij-desk-list-row:focus-within .ij-desk-list-due {
    opacity: 0;
    transition: opacity 120ms ease;
}

/* The add row's pending chips are inside .ij-desk-list-add (also a row) and
   must never fade — they are the state being composed, and the add row has no
   hover actions to make room for. */
.ij-desk-list-add:hover .ij-desk-list-ticker,
.ij-desk-list-add:hover .ij-desk-list-due,
.ij-desk-list-add:focus-within .ij-desk-list-ticker,
.ij-desk-list-add:focus-within .ij-desk-list-due {
    opacity: 1;
}

/* 2. Rule 4 ("never an empty card") applies to the CHROME, not just the rows:
      the empty state used to wrap its lone add row in the full bordered card
      with the --ij-field bar, which reads as exactly the empty card the rule
      forbids. Empty now renders the one line plus a BARE add row. */
.ij-desk-list--empty .ij-desk-list-card {
    border: none;
    border-radius: 0;
    background: none;
    overflow: visible;
}

.ij-desk-list--empty .ij-desk-list-add {
    background: none;
    padding: 6px 0;
}

@media (max-width: 599.95px) {
    .ij-desk-list-actions {
        position: static;
        transform: none;
    }

    .ij-desk-list-row:hover .ij-desk-list-ticker,
    .ij-desk-list-row:focus-within .ij-desk-list-ticker,
    .ij-desk-list-row:hover .ij-desk-list-due,
    .ij-desk-list-row:focus-within .ij-desk-list-due {
        opacity: 1;
    }
}

/* The empty state's one line carries the Customize link at its right edge —
   rule 5's single settings affordance, kept reachable while the list is empty
   (the settings would otherwise be locked behind a first item). */
.ij-desk-list-empty-row {
    display: flex;
    align-items: baseline;
    gap: 12px;
    margin-bottom: 10px;
}

.ij-desk-list--empty .ij-desk-list-empty-line {
    margin-bottom: 0;
}

/* Phone rows: give the task text its OWN line.
   At ≤599.95px the Edit/Delete pills are always visible and in flow (there is
   no hover on touch), and with a ticker and a due chip beside them the text —
   `flex: 1; min-width: 0` — was shrinking to one or two WORDS per line rather
   than wrapping the row. Caught at 390px while verifying canvas 12a; the row
   already sets `flex-wrap: wrap` at this width, so a full-width basis is all
   it needed to break properly: text on top, ticker/chip/actions beneath. */
@media (max-width: 599.95px) {
    .ij-desk-list-text {
        flex-basis: 100%;
    }
}

/* ── Desk list v2 (canvas 15a) ──────────────────────────────────────────────
   The list is full width again — canvas 13's two-column rail is withdrawn; the
   Claude prompts now live in the clay-lit .ij-desk-claude card below the list
   (portfolio.css, beside the .ij-pf-pro-band block it copies). */

/* Customize is a link OUT now, not an action: secondary text, chevron, no pill. */
.ij-desk-list-customize {
    color: var(--mud-palette-text-secondary);
    text-decoration: none;
}

.ij-desk-list-customize:hover {
    color: var(--mud-palette-text-primary);
}
