/* ============================================================================
   dashboard-sections.css — the collapsible section system (variant B, 2026-08-27)

   WHY THIS FILE EXISTS
   The member dashboard was one 10,381px feed on desktop and 24,392px on a phone.
   Collapsing was already built and applied to exactly the wrong sections: two of
   ten were closed by default and they were the two SMALLEST (56px and 64px), while
   the two largest (the Funding Calendar and the pipeline, together 57% of the page)
   could not collapse at all.

   THE RULE THAT SHAPES EVERY DECLARATION BELOW
   A drawer REPLACES a section's chrome; it never stacks on it. Every section here
   already ships its own card (1px border, 10px radius, 14px/18px padding) and its
   own title, so wrapping one in a second card produced two frames and two headings
   for one section. A first pass did exactly that and read as a step back from
   production. Hence: `.dash-sec__body > *` is stripped of its own frame, the
   section's own title is hidden, and the summary line is drawn ONLY when closed —
   an open section is its own summary, and restating it 40px above the content is
   the same repetition defect this system exists to remove.

   VARIANT B: a CLOSED section is a card you can tap; an OPEN one drops the frame
   entirely. Nesting therefore cannot occur in either state.

   Scoped to the dashboard on purpose. `winner-panel.src.js` is SHARED with the
   ~690 /grants/* pages, so the Who-Actually-Wins hierarchy fix below is applied
   from the dashboard side only and never touches the component itself.
   ========================================================================== */

/* ---- zone label ---------------------------------------------------------- */
.dash-zone { margin: 0 0 26px; }
.dash-zone:last-child { margin-bottom: 0; }
.dash-zone__hd { padding: 0 2px 7px; margin: 0 0 8px; }
.dash-zone__t {
    font: 600 10.5px/1 var(--dash-font-body);
    letter-spacing: .15em;
    text-transform: uppercase;
    /* 10.5px uppercase is the smallest text here, so it needs the most contrast, not the
       least: --dash-ink-faint measured 3.61:1. */
    color: var(--dash-ink-secondary);
}

/* ---- the section drawer -------------------------------------------------- */
details.dash-sec { border: 0; background: transparent; margin: 0 0 8px; }
details.dash-sec:last-child { margin-bottom: 0; }

/* closed: an object you can tap */
details.dash-sec:not([open]) {
    background: var(--dash-paper);
    border: 1px solid var(--dash-cream-dark);
    border-radius: var(--dash-radius);
}
details.dash-sec:not([open]) > summary { padding: 15px 16px; border-radius: var(--dash-radius); }
details.dash-sec:not([open]) > summary:hover { background: #fff; }

/* open: no frame at all, so the section's own content is the only object */
details.dash-sec[open] > summary {
    padding: 15px 2px 13px;
    border-bottom: 1px solid var(--dash-cream-dark);
}

details.dash-sec > summary {
    list-style: none;
    cursor: pointer;
    display: flex;
    align-items: baseline;
    gap: 13px;
}
details.dash-sec > summary::-webkit-details-marker { display: none; }
details.dash-sec > summary:focus-visible {
    outline: 2px solid var(--dash-forest);
    outline-offset: 2px;
}

.dash-sec__t {
    flex: 0 0 auto;
    font: 600 17px/1.35 var(--dash-font-display);
    color: var(--dash-ink);
    letter-spacing: -.005em;
}
.dash-sec__sum {
    flex: 1 1 auto;
    min-width: 0;
    font: 400 13px/1.45 var(--dash-font-body);
    /* ⚠ NOT --dash-ink-faint (#8a8175): measured 3.75:1 on paper at 13px, under the 4.5
       AA floor. The summary is the whole point of a closed row, so it cannot be the
       least legible text on the page. --dash-ink-muted clears it. */
    color: var(--dash-ink-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}
.dash-sec__sum b { color: var(--dash-ink-secondary); font-weight: 600; }
.dash-sec__n {
    flex: 0 0 auto;
    font: 600 12.5px/1 var(--dash-font-body);
    color: var(--dash-forest-deep);
    font-variant-numeric: tabular-nums;
}
.dash-sec__n--warm { color: var(--dash-sienna); }
.dash-sec__date {
    flex: 0 0 auto;
    font: 500 11.5px/1 var(--dash-font-body);
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--dash-ink-muted);
}
/* "changed since you last opened this" — a dot, never a claim about WHAT changed.
   Absent when the section has never been opened: with no baseline there is nothing we
   can honestly assert, and an inferred claim is the trap this repo keeps re-learning. */
.dash-sec__dot {
    flex: 0 0 auto;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--dash-sienna);
    align-self: center;
}
details.dash-sec[open] > summary .dash-sec__dot { display: none; }

.dash-sec__cv {
    flex: 0 0 auto;
    width: 16px; height: 16px;
    color: var(--dash-ink-faint);
    transition: transform .2s ease;
    align-self: center;
}
details.dash-sec[open] > summary .dash-sec__cv { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) {
    .dash-sec__cv { transition: none; }
}

/* ★ an OPEN section does not restate itself in its own header */
details.dash-sec[open] > summary .dash-sec__sum,
details.dash-sec[open] > summary .dash-sec__n { display: none; }

/* the section's primary action rides the header instead of floating in a band */
.dash-sec__act { flex: 0 0 auto; align-self: center; }
details.dash-sec:not([open]) > summary .dash-sec__act { display: none; }
.dash-sec__act .dash-sec__btn {
    font: 600 13px/1 var(--dash-font-body);
    color: var(--dash-forest-deep);
    background: transparent;
    border: 1px solid var(--dash-cream-dark);
    border-radius: 8px;
    padding: 8px 13px;
    cursor: pointer;
}
.dash-sec__act .dash-sec__btn:hover { background: var(--dash-forest-light); }

/* ---- ONE frame: the section stops drawing its own card inside a drawer ---- */
.dash-sec__body { padding: 13px 0 18px; }
.dash-sec__body > section,
.dash-sec__body > div,
.dash-sec__body > details {
    background: transparent !important;
    border: 0 !important;
    border-radius: 0 !important;
    box-shadow: none !important;
    padding: 0 !important;
    margin-left: 0 !important;
    margin-right: 0 !important;
}

/* the drawer header now owns the title, so the section stops printing its own */
.dash-sec__body .dash-today__head,
.dash-sec__body .dash-pipeline-head,
.dash-sec__body .gcal-head,
.dash-sec__body .dash-ww__lead { display: none; }

/* ---- repetition: the same fact stops being printed more than once --------
   Measured on the live page 2026-08-27: Who Actually Wins rendered ONE 36px
   headline, ONE eyebrow and ONE licence line three times each, while the only
   thing that differed (the programme name) was the smallest element on the row
   and sat OUTSIDE the card. Scoped to .dash-ww__row--panel so the shared
   winner-panel component is untouched on /grants/*.                        */
.dash-ww__row--panel .gc-wp__h,
.dash-ww__row--panel .gc-wp__attr,
.dash-ww__row--panel .gc-wp__eyebrow { display: none; }

.dash-ww__row--panel .dash-ww__progline {
    font: 600 20px/1.3 var(--dash-font-display);
    color: var(--dash-ink);
    letter-spacing: -.01em;
    text-transform: none;      /* it was a mono uppercase label */
    margin: 0 0 2px;
}
.dash-ww__ogl {
    font: 400 11.5px/1.5 var(--dash-font-body);
    color: var(--dash-ink-faint);
    margin: 10px 0 0;
}

/* the SAVED chip repeated its own group's label on all 22 rows */
.dash-pipeline-stage--saved .dash-gstate--saved { display: none; }

/* each calendar event printed its date up to three times */
.dash-sec__body .gcal-ev__when { display: none; }

/* a filter that can select nothing is not an option */
.dash-gfilters .dash-gchip.is-zero { display: none; }

/* ---- control polish: search and sort stop being two different systems ---- */
.dash-sec__body .dash-gfilters select {
    font: 500 13px/1 var(--dash-font-body);
    color: var(--dash-ink);
    background: var(--dash-paper);
    border: 1px solid var(--dash-cream-dark);
    border-radius: 8px;
    padding: 8px 11px;
    box-shadow: none;
    appearance: none;
    padding-right: 26px;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%231a4731' stroke-width='2.4' stroke-linecap='round'><polyline points='6 9 12 15 18 9'/></svg>");
    background-repeat: no-repeat;
    background-position: right 8px center;
    background-size: 12px;
}
/* the wrapper owns the box, so its old bare underline stops trailing past the field */
.dash-sec__body .dash-search {
    border: 1px solid var(--dash-cream-dark);
    border-radius: 8px;
    background: var(--dash-paper);
    padding: 2px 10px;
    display: flex;
    align-items: center;
    gap: 7px;
}
.dash-sec__body .dash-search input {
    border: 0 !important;
    background: transparent !important;
    box-shadow: none !important;
    padding: 8px 0 !important;
    /* ⚠ The outline is removed from the INPUT because the wrapper now draws the box —
       but removing it without a replacement left a core control with no visible focus
       at all for a keyboard user. The ring moves to the wrapper, it does not vanish. */
    outline: none;
    font: 500 13px/1 var(--dash-font-body);
    color: var(--dash-ink);
}
.dash-sec__body .dash-search:focus-within {
    outline: 2px solid var(--dash-forest);
    outline-offset: 1px;
    border-color: var(--dash-forest);
}

/* ⚠⚠ THE [hidden] ATTRIBUTE IS OVERRIDDEN BY ANY RULE THAT SETS display.
   `.dash-pipeline-row { display: grid }` beat it, so the 16 capped rows kept rendering
   at 174px each: 3,083px of "hidden" list still on the page, live in production. The cap
   was doing almost nothing on screen while every attribute-based check reported success.
   This is a documented class in this repo and it caught us anyway. */
.dash-pipeline-row[hidden],
.dash-pipeline-row[data-sec-capped] { display: none !important; }

/* ---- "show the rest" control for a long saved list ---------------------- */
.dash-sec__more {
    display: block;
    width: 100%;
    margin: 11px 0 0;
    padding: 13px;
    min-height: 44px;              /* measured 38px on a phone, under the touch floor */
    border: 1px solid var(--dash-cream-dark);
    background: transparent;
    border-radius: 9px;
    font: 600 13.5px/1 var(--dash-font-body);
    color: var(--dash-forest-deep);
    cursor: pointer;
}
.dash-sec__more:hover { background: var(--dash-forest-light); }

/* ---- rail: the same three groups, in the same order --------------------- */
.dash-rail__grp {
    margin: 18px 0 5px;
    font: 600 10px/1 var(--dash-font-body);
    letter-spacing: .15em;
    text-transform: uppercase;
    color: var(--dash-ink-faint);
    padding: 0 4px;
}
.dash-rail__grp:first-child { margin-top: 0; }

/* ---- phone --------------------------------------------------------------- */
@media (max-width: 620px) {
    details.dash-sec > summary { flex-wrap: wrap; row-gap: 3px; }
    .dash-sec__t { flex: 1 1 auto; }
    /* Wrap rather than truncate mid-word, but BOUND it: a 75-char summary took a
       52px row to 115px, and a quiet index of tall rows is just the long feed again.
       Two lines keeps the outlier legible without letting it set the page height. */
    .dash-sec__sum {
        flex: 1 1 100%;
        white-space: normal;
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
        overflow: hidden;
    }
    .dash-sec__date { display: none; }
    /* a 44px floor on the tap target, per the UI stress-test discipline */
    details.dash-sec:not([open]) > summary { padding: 16px; min-height: 44px; }
}

/* ============================================================================
   FIXES from Khalid's production review, 2026-08-27 evening
   ========================================================================== */

/* ---- 1. a CONVERTED drawer kept its own card padding -------------------
   The <details>-native sections (Our Picks, Who Actually Wins, Match Criteria,
   Quiz Results, Competitor Intel) ARE the drawer, so `.dash-sec__body > *` never
   reached them: they kept .dash-who-wins / .dash-quiz-profile padding of 14-18px
   and rendered INDENTED and taller than the sections above them. Measured on
   production: title x=459 vs x=426/441, and 10-14px of dead vertical space.
   `details.dash-sec` is (0,0,1,1) so it wins over the component classes without
   !important. The drawer draws the box; the section inside draws nothing. */
details.dash-sec {
    padding: 0;
    margin-left: 0;
    margin-right: 0;
}
details.dash-sec[open] { background: transparent; border-color: transparent; }

/* ---- 2. Matched Contracts was designed as a DARK module ----------------
   `.dash-contracts` ships `linear-gradient(135deg,#1a3d2e,#0f2a1f)` with #fff /
   #c9b98a / #bfe0cd / #f2dca8 text. The drawer strips the background so one frame
   remains, which left every one of those pale colours on cream: the section title,
   the row titles and the set-aside chips were effectively invisible.
   Re-themed to the light language rather than restoring the dark ground, because a
   single dark slab inside a light collapsible feed is the composition problem the
   zones exist to remove. */
.dash-sec__body .dash-contracts { color: var(--dash-ink); }

/* the drawer header already says "Matched Contracts" — one title, not two */
.dash-sec__body .dash-contracts__kick,
.dash-sec__body .dash-contracts__title-h { display: none; }
.dash-sec__body .dash-contracts__head { margin-bottom: 4px; justify-content: flex-end; }

.dash-sec__body .dash-contracts__tune {
    display: inline-flex; align-items: center; min-height: 44px;   /* measured 34px on a phone */
    color: var(--dash-forest-deep);
    border-color: var(--dash-cream-dark);
    background: var(--dash-paper);
}
.dash-sec__body .dash-contracts__tune:hover,
.dash-sec__body .dash-contracts__tune:focus-visible {
    background: var(--dash-forest-light);
    border-color: var(--dash-forest);
    color: var(--dash-forest-deep);
}

.dash-sec__body .dash-contracts__row {
    background: var(--dash-paper);
    border: 1px solid var(--dash-cream-dark);
    border-left: 3px solid var(--dash-cream-dark);
    color: var(--dash-ink);
}
.dash-sec__body .dash-contracts__row:hover,
.dash-sec__body .dash-contracts__row:focus-visible { background: #fff; }
.dash-sec__body .dash-contracts__row.u7 { border-left-color: var(--dash-sienna); }
.dash-sec__body .dash-contracts__row.u3 { border-left-color: var(--dash-rose); }

.dash-sec__body .dash-contracts__title { color: var(--dash-ink); }
.dash-sec__body .dash-contracts__entity { color: var(--dash-ink-muted); }

.dash-sec__body .dash-contracts__type {
    color: var(--dash-forest-deep);
    background: var(--dash-forest-light);
    border-color: var(--dash-cream-dark);
}
.dash-sec__body .dash-contracts__setaside {
    color: #6b4c0b;                       /* gold, dark enough to read on its tint */
    background: var(--dash-gold-light);
    border-color: rgba(184, 134, 11, .35);
}
.dash-sec__body .dash-contracts__due {
    background: var(--dash-cream-dark);
    /* --dash-ink-secondary measured 4.22:1 here at 10.5px, just under AA */
    color: var(--dash-ink);
}
/* the u3 chip is white on #c0603a in the original module: 4.22:1, marginally under AA.
   Its rule is (0,0,3,0) so it outranks the base override; matched and darkened here. */
.dash-sec__body .dash-contracts__row.u3 .dash-contracts__due {
    background: #9e4622;
    color: #fff;
}
.dash-sec__body .dash-contracts__row.u7 .dash-contracts__due {
    background: var(--dash-sienna-light);
    color: #8a4a1f;
}
.dash-sec__body .dash-contracts__why { color: var(--dash-ink-muted); }
.dash-sec__body .dash-contracts__foot a { color: var(--dash-forest-deep); }
.dash-sec__body .dash-contracts__foot a:hover,
.dash-sec__body .dash-contracts__foot a:focus-visible { color: var(--dash-forest-deep); }
.dash-sec__body .dash-contracts__group-label { color: var(--dash-ink-muted); }
.dash-sec__body .dash-contracts__group-label--matched { border-top-color: var(--dash-cream-dark); }
.dash-sec__body .dash-contracts__closed { color: var(--dash-ink-muted); opacity: 1; }
.dash-sec__body .dash-contracts__saved,
.dash-sec__body .dash-contracts__more { color: var(--dash-ink-secondary); }

/* ---- 3. the rail recommendation is dismissible -------------------------- */
.dash-rail__recwrap { position: relative; display: block; }
.dash-rail__recx {
    position: absolute;
    top: 4px; right: 4px;
    /* the rail is desktop-only (dashboard.css hides it under the mobile breakpoint), so
       the 44px touch floor does not apply — but 24px is a mean target for a mouse too. */
    width: 30px; height: 30px;
    display: flex; align-items: center; justify-content: center;
    border: 0; background: transparent; cursor: pointer;
    font: 400 17px/1 var(--dash-font-body);
    color: var(--dash-ink-faint);
    border-radius: 6px;
}
.dash-rail__recx:hover { background: rgba(26,23,20,.06); color: var(--dash-ink); }
.dash-rail__recx:focus-visible { outline: 2px solid var(--dash-forest); outline-offset: 1px; }

/* ---- 4. rail groups fold (default open, deliberately NOT persisted) ----- */
.dash-rail__hbtn {
    display: flex; align-items: center; gap: 5px;
    width: 100%; padding: 0; border: 0; background: transparent;
    font: inherit; color: inherit; letter-spacing: inherit; text-transform: inherit;
    cursor: pointer; text-align: left;
}
.dash-rail__hbtn:hover { color: var(--dash-ink-secondary); }
.dash-rail__hbtn:focus-visible { outline: 2px solid var(--dash-forest); outline-offset: 2px; border-radius: 4px; }
.dash-rail__hcv { width: 12px; height: 12px; opacity: .55; transition: transform .18s ease; }
nav.is-folded .dash-rail__hcv { transform: rotate(-90deg); }
nav.is-folded .dash-rail__item,
nav.is-folded .dash-rail__recwrap { display: none; }
@media (prefers-reduced-motion: reduce) { .dash-rail__hcv { transition: none; } }

/* ---- 5 + 6. WIDE SCREENS ONLY: descriptions fold into a hover tooltip ----
   Khalid, 2026-08-27: on a large monitor the rail runs past the fold and it is easy
   to miss that more buttons exist below. Seven description lines are ~130px of that.
   Hover does not exist on touch, so this is gated on (hover: hover) AND a wide
   viewport — on a phone the descriptions stay as visible text. The text also stays in
   the DOM in BOTH cases, so a screen reader still reads it; a ::after tooltip alone
   would have removed it from the accessibility tree. */
@media (hover: hover) and (pointer: fine) and (min-width: 1100px) {
    .dash-rail__item .d {
        position: absolute;
        width: 1px; height: 1px;
        padding: 0; margin: -1px;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }
    .dash-rail__item { position: relative; }
    .dash-rail__item[data-tip]::after {
        content: attr(data-tip);
        position: absolute;
        left: calc(100% + 10px);
        top: 50%;
        transform: translateY(-50%);
        z-index: 60;
        max-width: 230px;
        width: max-content;
        padding: 8px 11px;
        border-radius: 8px;
        background: #26231f;
        color: #f4f1ea;
        font: 400 12.5px/1.45 var(--dash-font-body);
        letter-spacing: 0;
        text-transform: none;
        box-shadow: 0 6px 20px rgba(26,23,20,.22);
        opacity: 0;
        pointer-events: none;
        transition: opacity .13s ease;
    }
    .dash-rail__item[data-tip]:hover::after,
    .dash-rail__item[data-tip]:focus-visible::after { opacity: 1; }
    @media (prefers-reduced-motion: reduce) {
        .dash-rail__item[data-tip]::after { transition: none; }
    }
}

/* ---- 5b. there is more below: say so ------------------------------------
   ⚠ A cue that ships at an alpha nobody can see is not a cue. This is a solid-to-
   transparent fade over the cream ground plus a real bottom border, and the harness
   asserts the fade's own opacity rather than its existence. */
/* ⚠ DO NOT set position here. `.dash-rail__in` is `position: fixed` and dashboard.css
   says so emphatically ("NOT sticky — see the warning above"); adding `position: relative`
   overrode it, dropped the rail out of fixed positioning and dumped it into the content
   column — and only ever on the tall monitors this cue exists for. Fixed already
   establishes a containing block for the pseudo-element. */
.dash-rail__in.has-overflow::after {
    content: '';
    position: absolute;
    left: 0; right: 8px; bottom: 0;
    height: 34px;
    pointer-events: none;
    background: linear-gradient(to bottom, rgba(250,248,244,0), rgba(250,248,244,.97) 78%);
}

/* ---- PHASE A.4: the recommendation, in the work zone --------------------
   Moved out of the rail because it carries the best sentence on the page. It keeps the
   rail's markup and handlers, so only the presentation changes here. */
.dash-rail__recwrap--inline { display: block; margin: 0 0 12px; }
.dash-rail__recwrap--inline .dash-rail__rec {
    display: block;
    width: 100%;
    text-align: left;
    background: var(--dash-paper);
    border: 1px solid var(--dash-cream-dark);
    border-left: 3px solid var(--dash-sienna);
    border-radius: var(--dash-radius);
    padding: 16px 18px;
    text-decoration: none;
    cursor: pointer;
}
.dash-rail__recwrap--inline .dash-rail__rec:hover { background: #fff; }
.dash-rail__recwrap--inline .dash-rail__rec .k {
    display: block;
    font: 700 10.5px/1 var(--dash-font-body);
    letter-spacing: .14em; text-transform: uppercase;
    color: var(--dash-sienna);
    margin-bottom: 6px;
}
.dash-rail__recwrap--inline .dash-rail__rec .t {
    display: block;
    font: 600 19px/1.3 var(--dash-font-display);
    color: var(--dash-ink);
    margin-bottom: 4px;
}
.dash-rail__recwrap--inline .dash-rail__rec .b {
    display: block;
    font: 400 14px/1.5 var(--dash-font-body);
    color: var(--dash-ink-secondary);
    max-width: 62ch;
}
.dash-rail__recwrap--inline .dash-rail__rec .c {
    display: inline-block;
    margin-top: 10px;
    font: 600 13.5px/1 var(--dash-font-body);
    color: var(--dash-forest-deep);
}
.dash-rail__recwrap--inline .dash-sec__t { display: none; }
