/* Public editorial pages share components, with layouts chosen for the work. */
.project-page { color: var(--on-surface); background: var(--surface); }
/* The shell these pages sit in is `.page-shell`, in main.css, which every public
   page now shares. It used to be `.project-shell` and live here, which put the
   site's widest layout in a sheet four fifths of the site does not load. */
.project-breadcrumb { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; padding-block: 16px; font-size: 0.8125rem; color: var(--on-surface-muted); }
.project-breadcrumb a { display: inline-flex; align-items: center; min-height: 44px; color: var(--on-surface-muted); }
.project-hero { display: grid; grid-template-columns: 1fr 1.08fr; gap: 48px; align-items: center; padding-block: 40px 56px; }
.project-hero h1, .project-hub h1, .advice-head h1 { font-size: clamp(2.125rem, 3.8vw, 3.5rem); line-height: 1.12; letter-spacing: -0.035em; margin: 0 0 24px; }
.project-eyebrow { color: var(--text-link); font-size: 0.8125rem; font-weight: 700; letter-spacing: 0.045em; margin: 0 0 14px; }
.project-intro { font-size: 1.0625rem; line-height: 1.8; margin: 0 0 28px; max-width: 64ch; }
.project-hero__image { margin: 0; isolation: isolate; background: var(--surface); }
.project-hero__image img { display: block; width: 100%; height: auto; mix-blend-mode: multiply; }
.project-hero__image figcaption { text-align: center; margin-top: 16px; font-size: 0.8125rem; color: var(--on-surface-muted); }
.project-reassurance { font-size: 0.8125rem; color: var(--on-surface-muted); margin: 12px 0 0; line-height: 1.6; }
.project-page .btn { gap: 10px; white-space: normal; text-align: center; }
.project-page h2 { font-size: clamp(1.5rem, 2.5vw, 2rem); line-height: 1.25; letter-spacing: -0.02em; margin: 0 0 24px; }
.project-page h3 { font-size: 1.0625rem; line-height: 1.4; }
.project-page section, .project-page aside { scroll-margin-top: 100px; }
.project-page section p:not(.project-eyebrow):not(.project-reassurance) { line-height: 1.8; }
.project-jumplinks { display: flex; flex-wrap: wrap; gap: 8px 28px; padding-block: 14px; border-block: 1px solid var(--control-border); }
.project-jumplinks a { display: inline-flex; align-items: center; min-height: 44px; color: var(--on-surface); font-size: 0.875rem; }
.project-editorial { display: grid; grid-template-columns: 0.85fr 1.15fr; gap: 80px; padding-block: 72px; }
.project-scope ul { padding: 0; margin: 0; list-style: none; }
.project-scope li { display: flex; gap: 12px; padding-block: 14px; line-height: 1.7; border-bottom: 1px solid var(--control-border); }
.project-scope li .material-symbols-outlined { color: var(--text-link); margin-top: 2px; flex-shrink: 0; }
.project-advice p:last-child { margin: 0; max-width: 65ch; }
.project-process { background: var(--surface); color: var(--on-surface); border-radius: var(--md-sys-shape-corner-large); padding: 48px; display: grid; grid-template-columns: 1fr 1.1fr; gap: 24px 64px; }
.project-process__intro p:last-child { color: var(--on-surface-muted); margin-bottom: 0; }
.project-steps { margin: 0; padding-left: 24px; }
.project-steps li { padding-left: 12px; margin-bottom: 24px; }
/* --text-link, not --control-accent: the list NUMBER is text, and the accent is
   the amber that fails on cream (1.96:1), while --text-link is what each surface
   block maps to AA gold for prose: dark on cream, bright on the navy process
   panel the homeowner pages put this list in. A raw dark gold here fixed cream
   and dropped that panel to 3.02:1 for a round. */
.project-steps li::marker { color: var(--text-link); font-weight: 700; }
.project-steps h3 { margin: 0 0 8px; }
.project-steps p { color: var(--on-surface-muted); margin: 0; font-size: 0.9375rem; }
.project-process > .btn { justify-self: start; }
.project-planning-grid { display: grid; grid-template-columns: 1.15fr 0.85fr; gap: 80px; align-items: start; padding-block: 72px; }
.project-preparation { background: var(--surface-card); border: 1px solid var(--control-border); border-radius: var(--md-sys-shape-corner-large); padding: 32px; }
.project-preparation__icon { color: var(--text-link); font-size: 32px; flex-shrink: 0; }
.project-preparation h2 { display: flex; align-items: center; gap: 12px; font-size: 1.375rem; }
.project-preparation ul { padding-left: 20px; }
.project-preparation li { padding-left: 4px; margin-bottom: 12px; line-height: 1.7; }
.project-preparation > p { font-size: 0.875rem; color: var(--on-surface-muted); margin-bottom: 0; }
.project-faq { display: grid; grid-template-columns: 0.8fr 1.2fr; gap: 64px; padding-bottom: 72px; }
.project-faq details { border-bottom: 1px solid var(--control-border); }
.project-faq summary { padding: 20px 4px; cursor: pointer; font-weight: 700; line-height: 1.6; min-height: 44px; }
.project-faq details p { margin: 0; padding: 0 4px 24px; color: var(--on-surface-muted); }
.project-next { border-block: 1px solid var(--control-border); padding-block: 40px; display: flex; align-items: center; justify-content: space-between; gap: 32px; }
.project-next h2 { margin-bottom: 12px; }
.project-next p { margin-bottom: 0; max-width: 60ch; }
.project-next > :last-child { flex-shrink: 0; }
.project-related { padding-block: 64px 80px; }
.project-related > p { margin-top: -8px; margin-bottom: 28px; }
/* `:not(.project-card)` because the card carries its own ring in components.css:
   this rule's 4px is right for an inline link and squares a corner-large card,
   and the card renders on a page that does NOT load this sheet, so the component
   has to own the ring or the same tile focuses two different ways. */
/* The survival kit's /advice link is EXCLUDED: it renders on the homepage too,
   where this sheet is not loaded, so it carries its own amber ring in main.css.
   Without the exclusion this (0,3,1) rule beats that (0,2,1) rule on every
   project page and the two shells draw two different rings, which is the
   shared-partial drift the exclusion on .account__cta already guards against.
   tests/test_advice_pages.py pins the exclusion, not just the hook. */
.project-page a:not(.project-card):not(.homeowner-tips__more *):focus-visible, .project-page summary:focus-visible { box-shadow: var(--focus-ring); outline: 2px solid transparent; outline-offset: 2px; border-radius: 4px; }
.project-hub__header { padding-block: 40px 48px; max-width: 800px; }
.project-category { padding-block: 48px 8px; }
.project-hub .project-next { margin-block: 64px 80px; }
/* Repair pages lead with diagnosis; specialist pages foreground the brief. */
.project-page--repair .project-hero__image { order: -1; }
.project-page--repair .project-editorial { grid-template-columns: 1.15fr 0.85fr; }
.project-page--specialist .project-hero { gap: 0; align-items: stretch; }
.project-page--specialist .project-hero__copy { background: var(--surface); color: var(--on-surface); padding: 40px; border-radius: var(--md-sys-shape-corner-large); }
.project-page--specialist .project-hero__image { align-self: center; padding-left: 24px; }

/* ── The sections every homeowner page shares (#484) ───────────────────────
   Why Pinnacle exists, the project area, Graham's survival kit and a
   homeowner's own words. Each reads the surface-aware vars, so the same
   declaration is right on the cream page and inside the navy bands below.
   ------------------------------------------------------------------------- */
.project-why { display: grid; grid-template-columns: 0.8fr 1.2fr; gap: 64px; padding-block: 72px; border-top: 1px solid var(--control-border); }
.project-why__body > p { max-width: 68ch; margin: 0 0 16px; }
.project-why__body > .btn { margin-top: 12px; }
/* Set apart from the three steps above it: same navy panel, its own rule and
   breathing room, so it reads as what registering GIVES you rather than as a
   fourth step. It SPANS the panel's two columns because it is a paragraph
   where its neighbours are a list of short steps: left in the steps' column
   it sets well under the 68ch measure the rest of the page keeps. No figure
   here on purpose, since the column is a fraction of a shell that changes
   with the viewport, so any number would be true at one width only. */
.project-process__portal { grid-column: 1 / -1; border-top: 1px solid var(--control-border); padding-top: 24px; }
.project-process__portal h3 { margin: 0 0 8px; }
.project-process__portal p { margin: 0; max-width: 68ch; color: var(--on-surface-muted); }
/* The kit's own CSS (main.css) reads the RAW navy tokens rather than the
   surface-aware pair, so it is white-on-cream anywhere but a navy band. This
   is that band; homeowner_kit.py's docstring carries the full reasoning and
   a test holds it. Padding and radius mirror .project-process, its sibling
   navy panel, so the page reads as two bands and not two different cards. */
.project-kit { background: var(--surface); color: var(--on-surface); border-radius: var(--md-sys-shape-corner-large); padding: 48px; margin-block: 8px 72px; }
/* The kit's group title on this family's pages, stated for BOTH heading levels.
   It is an <h3> in a project page's band and an <h2> on the kit's own page
   (/advice/survival-kit, #521), and the two element rules above would size them
   differently: `.project-page h2` as a section heading. Two classes outrank
   both, and the values are the ones the project-page bands already rendered
   through `.project-page h3`, so those pages are unchanged. The homepage does
   not load this sheet and keeps main.css's own rule.
   tests/test_survival_kit_page.py holds the ranking and the values. */
.project-page .tip-group__title { font-size: 1.0625rem; line-height: 1.4; letter-spacing: normal; margin: 0; }
.project-proof { display: grid; grid-template-columns: 1.15fr 0.85fr; gap: 64px; align-items: start; padding-bottom: 72px; }
.project-proof__press { max-width: 60ch; margin-bottom: 0; }
/* One column, not the trade pages' three: the homeowner pool is one card
   today, and a lone card in a third of the width reads as a gap where two
   more should be. A second entry stacks under it, which is what a grid is
   for and needs no edit here. */
.project-proof__cards { display: grid; gap: 24px; }
@media (max-width: 800px) {
    .project-hero, .project-editorial, .project-page--repair .project-editorial,
    .project-process, .project-planning-grid, .project-faq,
    .project-why, .project-proof { grid-template-columns: 1fr; gap: 32px; }
    .project-hero { padding-block: 24px 32px; }
    .project-page--repair .project-hero__image { order: initial; }
    .project-page--specialist .project-hero { gap: 24px; }
    .project-page--specialist .project-hero__copy { padding: 28px; }
    .project-page--specialist .project-hero__image { padding-left: 0; }
    .project-editorial, .project-planning-grid { padding-block: 40px; }
    .project-process, .project-kit { padding: 28px; }
    .project-why, .project-proof { padding-block: 40px; }
    .project-kit { margin-block: 0 40px; }
    .project-steps { margin-bottom: -16px; }
    .project-faq { padding-bottom: 40px; }
    .project-next { flex-direction: column; align-items: start; }
}
@media (max-width: 480px) {
    .project-jumplinks { gap: 4px 20px; }
    .project-hero__copy .btn, .project-next .btn { width: 100%; }
    .project-next > :last-child { width: 100%; }
}

/* ── Trade page sections ───────────────────────────────────────────────────
   NOT the project pages' two-column editorial containers. Those are tuned for
   the homeowner pages' long copy; a trade page carries three bullets, two
   paragraphs and three FAQs, so the same containers left half-empty rows and
   an inconsistent left edge (the padded panel indented its heading 48px while
   every other heading sat at the shell edge). Stacked, one left edge, one
   rhythm. Owner review, 20 September 2026.
   ------------------------------------------------------------------------- */
.trade-section {
    /* The prose looked like it stopped half way across the page, and the cause
       was the RULE, not the text: each section's hairline border ran the shell's
       full 1200px while the paragraph wrapped at a readable 73 characters, so
       the text read as short rather than as measured (owner, 20 September 2026).

       So the SECTION carries the reading width, and its rule stops with its
       text. Two alternatives were built and measured first. Stretching the prose
       to the shell gave 127 characters per line against a readable band of 45 to
       75, i.e. it closed the gap by spending the thing the gap was worth closing
       for. Narrowing the whole shell to 720px fixed the prose (76 characters, no
       gap) and cramped the hero, whose h1 then wrapped to four short lines beside
       its illustration. Keeping the shell wide for the hero and the related grid,
       and bounding only the text sections, is the one that costs nothing.

       Declared here rather than in a second `.trade-section` rule further down:
       the component was split across two blocks with an override tail, which the
       house rule bans, and which leaves anyone reading the first block (or any
       guard that reads one top-level rule) seeing half the component. */
    max-width: 720px;
    padding-block: 56px;
    border-top: 1px solid var(--control-border);
}
.trade-section:first-of-type { border-top: 0; }
.trade-section > h2 { margin: 0 0 8px; }
/* The body sets no measure of its own: the SECTION above carries it, and a
   second, smaller cap here is what reintroduced the gap this section was
   restructured to close. Stated rather than declared, because `max-width: none`
   is the initial value and nothing caps this element, so the declaration was a
   no-op that read like it was undoing something. The one exception is the
   --wide variant below, which lifts the SECTION's cap for its grid and so has
   to put the measure back on its lede paragraph. */
.trade-section__body > p { margin: 0 0 16px; }
.trade-section__body > p:last-child { margin-bottom: 0; }
.trade-section .project-steps { margin: 16px 0 0; }
.trade-section details { border-bottom: 1px solid var(--control-border); padding-block: 16px; }
.trade-section details:first-of-type { border-top: 1px solid var(--control-border); }
/* The questions are a disclosure, and nothing said so: the default marker is
   suppressed by the flex summary, so a bold line gave no hint an answer was
   behind it. A rotating chevron is the platform's convention (Material
   Symbols, never a text glyph), and it is aria-hidden because the native
   <details> already announces its own expanded state. */
.trade-section summary {
    cursor: pointer;
    font-weight: 700;
    min-height: 44px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    list-style: none;
}
.trade-section summary::-webkit-details-marker { display: none; }
.trade-section summary .material-symbols-outlined {
    flex-shrink: 0;
    color: var(--text-link);
    transition: transform var(--md-sys-motion-duration-short3) var(--md-sys-motion-easing-standard);
}
.trade-section details[open] summary .material-symbols-outlined { transform: rotate(180deg); }
/* Capped tighter than the section: an answer is a short read inside a wider
   block, and this is the only measure inside .trade-section. */
.trade-section details > p { margin: 8px 0 0; max-width: 68ch; }
.trade-section .btn { margin-top: 24px; }

/* Two sections are grids of short items rather than prose, and a grid of
   features or member cards inside a 720px measure is a column of crumbs. The
   SECTION takes the shell's width; its lede paragraph keeps the 720px measure
   below, because lifting the section's cap lifted the paragraph's with it. */
.trade-section--wide { max-width: none; }
.trade-section--wide .trade-section__body > p { max-width: 720px; }
.trade-features { list-style: none; margin: 24px 0 0; padding: 0; display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px 32px; }
.trade-features li { display: flex; gap: 14px; align-items: flex-start; }
.trade-features .material-symbols-outlined { color: var(--text-link); font-size: 28px; flex-shrink: 0; margin-top: 2px; }
.trade-features h3 { margin: 0 0 6px; }
.trade-features p { margin: 0; font-size: 0.9375rem; color: var(--on-surface-muted); }
/* Its own grid, not .testimonial-grid: that one is a hand-composed bento
   whose 4-column tier places children by nth-child into named areas, and
   with a different count of cards it strands one. Authored columns rather
   than auto-fit, which put all but one card on a row and the last alone on
   the next between 801 and 1015px. Three is a CAP on a row, not the size of
   the store: a fourth video wraps onto a second row, which is what a grid is
   for, and adding one needs no edit here. */
.trade-members { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; margin-top: 8px; }
/* One column under 800px, where the shell is up to 640px wide: a square
   poster at the full column is 640px tall, three of them a screen and a half
   of media, so the media is capped and the card's text takes the width. */
/* The testimonial card family's cream corrections live in main.css under
   .surface-cream, keyed on the SURFACE rather than on this section, so a
   player reused on any other cream page is right without anyone remembering. */

@media (max-width: 800px) {
    .trade-section { padding-block: 40px; }
    .trade-features, .trade-members { grid-template-columns: 1fr; }
    .trade-members .testimonial-card__media { max-width: 280px; }
}

@media (prefers-reduced-motion: reduce) {
    .trade-section summary .material-symbols-outlined { transition: none; }
}

/* ── Advice pages (#522) ──────────────────────────────────────────────────
   Long-form editorial, sharing this sheet rather than minting a parallel set
   of classes: `.project-page`, `.page-shell`, `.project-breadcrumb`,
   `.project-jumplinks`, `.project-intro`, `.project-eyebrow` and
   `.project-next` are all reused verbatim, and so is the `section p`
   line-height above. What is genuinely new is only what follows.

   THE THREE LINK BANDS ARE ONE CLASS, not three. The survival-kit band, the
   project band and the read-next band are the same component (a heading, a
   sentence, a list of links) differing only in what fills them, and three
   near-identical classes is the drift CLAUDE.md's one-component rule is
   about. */
.advice-head { padding-block: 32px 8px; }
/* The h1 takes the SHARED scale (added to the selector above) rather than a
   scale of its own: one family, one h1. Only the measure is local. */
.advice-head h1 { max-width: 24ch; }
/* The dates are content, not furniture: a guide about money and the law that
   does not say when it was reviewed is asking a worried reader to trust
   undated advice. Muted, but never hidden, and never smaller than the
   footnote size the rest of the sheet uses for secondary text. */
.advice-dates { display: flex; flex-wrap: wrap; gap: 4px 24px; margin: 0 0 8px; font-size: 0.8125rem; color: var(--on-surface-muted); }
.advice-dates__author { color: var(--on-surface); font-weight: 600; }
.advice-section { padding-block: 8px 24px; }
/* The margin is SET here, not inherited: main.css resets `p` to zero margin,
   so a long-form section without this renders every paragraph flush against
   the next and the whole guide reads as one block of text. It was invisible
   while the catalogue held placeholder copy, because each section had a single
   paragraph and there was nothing for a gap to sit between. */
.advice-section p, .advice-subsection p { max-width: 68ch; margin: 0 0 20px; }
.advice-section > p:last-child, .advice-subsection > p:last-child { margin-bottom: 0; }
.advice-subsection { margin-top: 28px; padding-left: 20px; border-left: 2px solid var(--control-border); }
.advice-subsection h3 { margin: 0 0 12px; }
.advice-band { padding-block: 32px; border-top: 1px solid var(--control-border); }
.advice-band > p { max-width: 65ch; }
.advice-links { list-style: none; padding: 0; margin: 0; display: flex; flex-wrap: wrap; gap: 4px 28px; }
.advice-links a { display: inline-flex; align-items: center; min-height: 44px; color: var(--text-link); }
/* The checks control after the projects list. The band is block flow, so the
   .btn base's margin-top:auto resolves to 0 and would sit it against the list. */
.advice-band > .btn { margin-top: 16px; }
.advice-index { list-style: none; padding: 0; margin: 0; display: grid; gap: 28px; }
.advice-index__item { padding-bottom: 24px; border-bottom: 1px solid var(--control-border); }
.advice-index__title { font-size: 1.25rem; margin: 0 0 10px; }
/* The colour is NOT inherited and NOT defaulted: no stylesheet this site
   loads declares a global `a { color }`, so an anchor that sets none renders
   in the browser's #0000EE. Every other anchor in this sheet sets one, and
   these are the hub's primary links. */
.advice-index__title a { color: var(--text-link); }
.advice-index__summary { max-width: 68ch; margin: 0 0 10px; }
.advice-index__meta { margin: 0; font-size: 0.8125rem; color: var(--on-surface-muted); }

@media (max-width: 600px) {
    .advice-subsection { padding-left: 14px; }
    /* A row gap is kept: these are 44px targets and they WRAP at this width,
       so zero would abut two tap targets exactly where a mis-tap is likeliest.
       Only the column gap narrows. */
    .advice-links { gap: 4px 20px; }
}

/* Section blocks: bullets, and outbound citations.
   `.advice-sources` is deliberately distinct from `.advice-links`, which is the
   three in-page bands' component: these leave the site, so they carry the
   external-link icon and open in a new tab, and the icon is sized by a
   DESCENDANT selector because the Material Symbols stylesheet sets 24px and
   `line-height: 1` directly on the class, which out-specifies anything
   inherited from the host. */
.advice-points { margin: 0 0 20px; padding-left: 22px; max-width: 66ch; }
.advice-points li { padding-left: 4px; margin-bottom: 10px; line-height: 1.8; }
.advice-sources { list-style: none; margin: 4px 0 20px; padding: 0; max-width: 66ch; }
.advice-sources li { margin-bottom: 4px; }
.advice-sources a { display: inline-flex; align-items: center; gap: 6px; min-height: 44px; color: var(--text-link); }
.advice-sources .material-symbols-outlined { font-size: 16px; }
