/* ==========================================================================
   melissamreid.ca — site-v3.css

   Loaded only by includes/v3/header.php. Never loaded on :443 — v2 keeps
   assets/css/site.css, which this file does not touch and must not replace.

   COLOUR: five tokens, one hue. No gradients, no shadows. Depth comes from
   fill and rule only.

   TWO LAYOUT SYSTEMS, DELIBERATELY NON-OVERLAPPING:
     .prose > * + *        vertical rhythm on the 17 markdown pages
     .site-main > section  block rhythm on the homepage
   The homepage emits no .prose and the other 17 emit no <section>, so the two
   never meet and their padding cannot cancel.

   THE JS CONTRACT — /assets/js/site.js is shared with v2 and is NOT edited.
   .nav-toggle, #primary-nav.is-open and body.nav-open MUST keep their rules or
   the mobile menu silently breaks.

   HONEYPOT — contact/index.php:208 hides a spam trap with an inline
   position:absolute;left:-10000px. Nothing here may reset position, overflow,
   width or height on unclassed descendants of .contact-form.
   ========================================================================== */

:root {
    --ink:       #063A7C;
    --ink-deep:  #04264F;
    --paper:     #FBFAF7;
    --limestone: #E7E3DB;
    --rule:      #C9C3B8;
}

/* --------------------------------------------------------------------------
   RESET / BASE
   -------------------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
    margin: 0;
    background: var(--paper);
    color: var(--ink-deep);
    font-family: "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
    font-size: clamp(1.0625rem, 1.02rem + 0.2vw, 1.1875rem);
    font-weight: 400;
    line-height: 1.65;
    /* The stones break out with 50vw maths, which counts the scrollbar.
       Without this the page gains a horizontal scrollbar at every width.
       `clip` is correct; `hidden` is the fallback for older engines. */
    overflow-x: hidden;
    overflow-x: clip;
}

img, video, iframe { max-width: 100%; }
/* Images carry width/height attributes so their box is reserved before load.
   height:auto keeps the aspect ratio once CSS narrows them. */
img, video { height: auto; }

a { color: var(--ink); }
a:hover, a:focus-visible { text-decoration-thickness: 2px; }

strong { font-weight: 600; }

:focus-visible {
    outline: 3px solid var(--ink);
    outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* --------------------------------------------------------------------------
   TYPE SCALE — only h1/h2/h3 exist in the content, so the scale has three
   levels, not six.
   -------------------------------------------------------------------------- */

h1, h2, h3 {
    font-family: Bitter, Georgia, "Times New Roman", serif;
    color: var(--ink);
    line-height: 1.15;
    text-wrap: balance;
    margin: 0;
}

/* h1 SCALE IS SPLIT BY CONTEXT — the semantics are identical, the typography
   is not. The homepage hero h1 is a NAME ("Melissa Reid"); the seven article
   h1s are SENTENCES of up to a dozen words. One scale cannot serve both.
   The two selectors can never match the same element: the homepage emits no
   .prose, and the 17 markdown pages emit no .hero__content. */
h1 { font-size: clamp(1.75rem, 4vw, 2.5rem); font-weight: 700; letter-spacing: -0.01em; }

/* The hero keeps the display scale. Short, so it earns it. */
.hero__content h1 {
    font-size: clamp(2rem, 1.45rem + 2.75vw, 3.25rem);
    letter-spacing: -0.015em;
}

/* Article h1 — wraps to two or three lines comfortably. */
.prose h1 {
    font-size: clamp(1.75rem, 4vw, 2.5rem);
    line-height: 1.15;
    letter-spacing: -0.01em;
}

/* IN-ARTICLE h2/h3 ARE SCOPED DOWN TOO, and this is not cosmetic.
   Gate 2.7 promoted every heading up one level, so what the source writes as a
   `###` subsection now renders as <h2>. At the unscoped display scale that put
   h1 only 1.13x above h2 — the outline validated but did not READ. These two
   rules restore the visible steps. The homepage's section headings are NOT in
   .prose and keep the display scale. */
/* :not(.plank-card__title) is load-bearing. A card title is an <h3> on the
   homepage and an <h2> on the hub, and the hub's sits inside .prose — so
   `.prose h2` (0,1,1) out-specifies `.plank-card__title` (0,1,0) and was
   rendering hub cards at 28px against the homepage's 23px. Excluded here for
   the same reason the list rules are: the card grid is a component that
   happens to live in prose, not prose content. */
.prose h2:not(.plank-card__title) {
    font-size: clamp(1.3125rem, 1.05rem + 1.1vw, 1.75rem);
    letter-spacing: -0.005em;
}

.prose h3:not(.plank-card__title) {
    font-size: clamp(1.125rem, 1.02rem + 0.55vw, 1.3125rem);
    font-weight: 600;
    letter-spacing: 0.005em;
}
h2 { font-size: clamp(1.5rem,  1.24rem + 1.3vw,  2.125rem); font-weight: 700; letter-spacing: -0.01em; }
h3 { font-size: clamp(1.1875rem, 1.11rem + 0.4vw, 1.4375rem); font-weight: 600; }

p, ul, ol, table, figure, blockquote, dl { margin: 0; }

/* --------------------------------------------------------------------------
   LAYOUT PRIMITIVES
   -------------------------------------------------------------------------- */

.container {
    width: 100%;
    max-width: 72rem;
    margin-inline: auto;
    padding-inline: 1.25rem;
}

@media (min-width: 48em) {
    .container { padding-inline: 2rem; }
}

.site-main { display: block; }

.skip-link {
    position: absolute;
    left: -9999px;
    top: 0;
    background: var(--ink-deep);
    color: var(--paper);
    padding: 0.75rem 1.25rem;
    z-index: 100;
    text-decoration: none;
}
.skip-link:focus,
.skip-link:focus-visible {
    left: 0;
    outline: 3px solid var(--paper);
    outline-offset: -6px;
}

/* --------------------------------------------------------------------------
   HEADER + NAV
   The three JS-contract selectors live in this block.
   -------------------------------------------------------------------------- */

.site-header {
    background: var(--paper);
    border-bottom: 1px solid var(--rule);
    position: relative;
    z-index: 20;
}

.site-header__inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding-block: 1rem;
    flex-wrap: wrap;
}

.site-header__brand {
    text-decoration: none;
    color: var(--ink);
    display: block;
    line-height: 1.15;
}

.site-header__brand-name {
    display: block;
    font-family: Bitter, Georgia, serif;
    font-weight: 700;
    font-size: clamp(1.25rem, 1.1rem + 0.7vw, 1.625rem);
    letter-spacing: -0.01em;
}

.site-header__brand-sub {
    display: block;
    font-size: 0.8125rem;
    font-weight: 400;
    color: var(--ink-deep);
    opacity: 0.75;
    margin-top: 0.15rem;
}

/* JS CONTRACT 1 — site.js binds to .nav-toggle. */
.nav-toggle {
    display: inline-flex;
    flex-direction: column;
    justify-content: center;
    gap: 5px;
    width: 2.75rem;
    height: 2.75rem;
    padding: 0.6rem;
    background: transparent;
    border: 1px solid var(--rule);
    cursor: pointer;
}

.nav-toggle__bar {
    display: block;
    height: 2px;
    width: 100%;
    background: var(--ink);
}

.nav-toggle[aria-expanded="true"] { background: var(--limestone); }

/* JS CONTRACT 2 — #primary-nav, collapsed on mobile until .is-open. */
#primary-nav {
    display: none;
    flex-basis: 100%;
}

/* JS CONTRACT 3 — the open state. */
#primary-nav.is-open {
    display: block;
    border-top: 1px solid var(--rule);
    padding-block: 0.5rem 1rem;
}

.primary-nav__list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.primary-nav__item + .primary-nav__item {
    border-top: 1px solid var(--rule);
}

.primary-nav__link {
    display: block;
    padding: 0.85rem 0.25rem;
    color: var(--ink);
    font-weight: 600;
    text-decoration: none;
}

.primary-nav__link:hover,
.primary-nav__link:focus-visible { text-decoration: underline; }

.primary-nav__link.is-current {
    text-decoration: underline;
    text-underline-offset: 0.25em;
    text-decoration-thickness: 2px;
}

/* JS CONTRACT 4 — scroll lock while the mobile menu is open. */
body.nav-open { overflow: hidden; }

@media (min-width: 56em) {
    .nav-toggle { display: none; }
    #primary-nav { display: block; flex-basis: auto; }
    /* .is-open is meaningless on desktop; neutralise the mobile chrome so a
       stale class left by the toggle cannot draw a stray rule. */
    #primary-nav.is-open { border-top: 0; padding-block: 0; }
    .primary-nav__list { display: flex; gap: 1.5rem; align-items: center; }
    .primary-nav__item + .primary-nav__item { border-top: 0; }
    .primary-nav__link { padding: 0.25rem 0; }
    body.nav-open { overflow: visible; }
}

/* --------------------------------------------------------------------------
   PROSE — the 17 markdown pages. Vertical rhythm via --flow-space, overridden
   per element type. This system never touches the homepage.
   -------------------------------------------------------------------------- */

.prose {
    max-width: 66ch;
    margin-inline: auto;
    padding-block: clamp(2rem, 1rem + 4vw, 4rem);
}

.prose > * + * { margin-block-start: var(--flow-space, 1.25em); }

.prose > h2  { --flow-space: 2.75rem; }
.prose > h3  { --flow-space: 2rem; }
.prose > ul,
.prose > ol  { --flow-space: 1.25em; }
.prose > hr  { --flow-space: 3rem; }
.prose > figure,
.prose > table { --flow-space: 2.5rem; }

.prose h1 { margin-bottom: 0.5rem; }

/* The generic markdown list rules must NOT reach the plank card grid. It is a
   <ul> of <li> living inside .prose, so `.prose ul` (0,1,1) and `.prose li + li`
   (0,1,2) both out-specify `.plank-cards` (0,1,0) and were winning:
     - padding-inline-start put a 21.6px strip of --rule down the grid's left edge
     - margin-top: 0.5rem pushed cards 2..6 down 8px inside their grid cells,
       misaligning row 1 and opening an 8px band above every card EXCEPT the
       first (`li + li` cannot match the first child) — the reported defect.
   Excluded here rather than fought with !important. */
.prose ul:not(.plank-cards),
.prose ol { padding-inline-start: 1.35rem; }

.prose li + li { margin-top: 0.5rem; }
.prose .plank-cards li + li { margin-top: 0; }

.prose a { text-underline-offset: 0.18em; }

/* The intentional section break in safety-and-crisis-response.md. */
.prose hr {
    border: 0;
    border-top: 1px solid var(--rule);
    margin-inline: 0;
}

/* --------------------------------------------------------------------------
   THE STONE — seven of them. The signature element.
   Full-bleed --ink-deep panel breaking out of the reading column. Stated, not
   quoted: no quotation marks, no glyph, no left border.
   -------------------------------------------------------------------------- */

blockquote[id^="quote-"],
.rooted__pullquote {
    /* Breakout: pull to the viewport edges from any centred ancestor, then put
       the gutter back as padding. Width-agnostic, no JS, no transform. */
    margin-inline: calc(50% - 50vw);
    padding-inline: calc(50vw - 50%);
    padding-block: clamp(2.25rem, 1.2rem + 4.5vw, 4rem);
    background: var(--ink-deep);
    color: var(--paper);
    font-family: Bitter, Georgia, "Times New Roman", serif;
    font-weight: 700;
    font-size: clamp(1.5rem, 1.05rem + 2.25vw, 2.5rem);
    line-height: 1.25;
    letter-spacing: -0.015em;
    text-wrap: balance;
    quotes: none;
}

blockquote[id^="quote-"] { --flow-space: clamp(2.5rem, 1.5rem + 4vw, 4.5rem); }

/* The markdown wraps stone text in **bold**, so it arrives as <p><strong>.
   Neither element may add weight or spacing of its own. */
blockquote[id^="quote-"] > *,
.rooted__pullquote > * { margin: 0; }
blockquote[id^="quote-"] strong,
.rooted__pullquote strong { font-weight: 700; }
blockquote[id^="quote-"] > * + *,
.rooted__pullquote > * + * { margin-top: 0.75em; }

/* Explicitly no decoration — guards against a UA or future rule adding one. */
blockquote[id^="quote-"]::before, blockquote[id^="quote-"]::after,
.rooted__pullquote::before, .rooted__pullquote::after { content: none; }

/* Inner width matches the reading measure so a stone screenshotted at phone
   width reads as a complete artifact rather than an edge-to-edge slab. */
blockquote[id^="quote-"] > *,
.rooted__pullquote > * {
    max-width: 34ch;
    margin-inline: auto;
}

@media (min-width: 48em) {
    blockquote[id^="quote-"] > *,
    .rooted__pullquote > * { max-width: 24ch; }
}

/* The restrained blockquote — every OTHER quotation on the site. */
.prose blockquote:not([id^="quote-"]) {
    border-left: 3px solid var(--rule);
    padding: 0.25rem 0 0.25rem 1.25rem;
    color: var(--ink-deep);
    font-size: 1.0625em;
}
.prose blockquote:not([id^="quote-"]) > * + * { margin-top: 0.75em; }

/* --------------------------------------------------------------------------
   THE TABLE — /platform/affordability-and-growth/ only. A rate schedule, not
   a data grid: hairlines, no zebra, figures right-aligned and tabular.
   -------------------------------------------------------------------------- */

.prose table {
    width: 100%;
    border-collapse: collapse;
    font-variant-numeric: tabular-nums;
    font-size: 0.9375rem;
}

.prose thead th {
    font-weight: 600;
    text-align: left;
    font-size: 0.8125rem;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: var(--ink);
    border-bottom: 2px solid var(--rule);
    padding: 0 0.5rem 0.6rem;
    vertical-align: bottom;
}

/* The empty first header cell stays empty. */
.prose thead th:first-child { width: 55%; }

.prose tbody td {
    border-bottom: 1px solid var(--rule);
    padding: 0.75rem 0.5rem;
    vertical-align: baseline;
}

.prose tbody tr:last-child td { border-bottom: 0; }

/* Figures right-aligned so the digits stack. */
.prose thead th:not(:first-child),
.prose tbody td:not(:first-child) { text-align: right; }

/* The money figures are the point of the object — larger than the row label. */
.prose tbody td strong {
    font-weight: 600;
    font-size: 1.1875rem;
    color: var(--ink);
    white-space: nowrap;
}

.prose thead th:first-child,
.prose tbody td:first-child { padding-left: 0; }
.prose thead th:last-child,
.prose tbody td:last-child { padding-right: 0; }

/* --------------------------------------------------------------------------
   HOMEPAGE — block rhythm. This system never touches .prose.
   -------------------------------------------------------------------------- */

.site-main > section { padding-block: clamp(2.5rem, 1.5rem + 4vw, 5rem); }

/* HERO — the thesis. Portrait first on mobile, height-constrained so badge,
   name and the first paragraph are above the fold. */
.hero { padding-block-start: clamp(1.5rem, 1rem + 2vw, 3rem); }

.hero__inner { display: grid; gap: clamp(1.25rem, 0.5rem + 3vw, 2.75rem); }

.hero__media img {
    width: 100%;
    display: block;
    /* Height-capped on mobile: she is a challenger, so the face does
       recognition work — but not at the cost of pushing the name off-screen. */
    max-height: 34vh;
    object-fit: cover;
    object-position: 50% 22%;
    background: var(--limestone);
}

.hero__badge {
    font-size: 0.8125rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ink);
    margin-bottom: 0.75rem;
}

.hero__content h1 { margin-bottom: 0.5rem; }

.hero__subhead {
    font-family: Bitter, Georgia, serif;
    font-weight: 600;
    font-size: clamp(1.125rem, 1rem + 0.9vw, 1.5rem);
    color: var(--ink);
    line-height: 1.3;
    margin-bottom: 1.25rem;
}

.hero__intro + .hero__intro { margin-top: 1em; }
.hero__cta { margin-top: 1.75rem; }

@media (min-width: 56em) {
    .hero__inner {
        grid-template-columns: minmax(0, 22rem) minmax(0, 1fr);
        align-items: start;
    }
    .hero__media img { max-height: none; object-fit: fill; }
}

/* PROOF STRIP — six quiet lines. Not cards, not icons, not a grid. */
.proof-strip { background: var(--limestone); }

.proof-strip__list { list-style: none; margin: 0; padding: 0; }

.proof-strip__item {
    font-weight: 600;
    padding-block: 1rem;
    border-bottom: 1px solid var(--rule);
}
.proof-strip__item:first-child { padding-top: 0; }
.proof-strip__item:last-child { border-bottom: 0; padding-bottom: 0; }

@media (min-width: 48em) {
    .proof-strip__item { padding-block: 1.15rem; font-size: 1.0625rem; }
}

/* PLANK CARDS — 2-up desktop, 1-up mobile, equal weight, no icons. */
.planks-section__heading { margin-bottom: clamp(1.5rem, 1rem + 2vw, 2.5rem); }

/* The separator bands ARE the container's --rule background showing through a
   1px grid gap. A full 1px border closes the same rule around all four outer
   edges, so the grid reads as one object rather than a stack with open sides. */
.plank-cards {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 1px;
    background: var(--rule);
    border: 1px solid var(--rule);
}

.plank-card {
    position: relative;
    background: var(--paper);
    padding: clamp(1.25rem, 0.9rem + 1.4vw, 2rem);
    /* The whole card is the target, so the whole card gets the cursor. */
    cursor: pointer;
    display: flex;
    flex-direction: column;
    transition: background-color 120ms ease-out;
}

/* Leading-edge rule. An absolutely positioned pseudo-element rather than a real
   border, so thickening it on hover cannot shift the card's content. */
.plank-card::before {
    content: "";
    position: absolute;
    inset-block: 0;
    inset-inline-start: 0;
    width: 3px;
    background: var(--rule);
    transition: width 120ms ease-out, background-color 120ms ease-out;
}

/* ONE coordinated state, shared by pointer hover and keyboard focus: the fill
   shifts to limestone, the leading rule thickens to ink, the title underlines
   and the arrow nudges. */
.plank-card:hover,
.plank-card:has(.plank-card__link:focus-visible) { background: var(--limestone); }

.plank-card:hover::before,
.plank-card:has(.plank-card__link:focus-visible)::before {
    width: 6px;
    background: var(--ink);
}

.plank-card:hover .plank-card__link,
.plank-card:has(.plank-card__link:focus-visible) .plank-card__link {
    text-decoration: underline;
    text-underline-offset: 0.18em;
}

.plank-card:hover .plank-card__arrow,
.plank-card:has(.plank-card__link:focus-visible) .plank-card__arrow {
    transform: translateX(0.3em);
}

/* Size pinned on the class, not inherited from the element: the card title is
   an <h3> on the homepage and an <h2> on the hub (different depth in each
   page's outline), and both must look identical. */
.plank-card__title {
    margin-bottom: 0.6rem;
    font-size: clamp(1.1875rem, 1.11rem + 0.4vw, 1.4375rem);
    font-weight: 600;
    letter-spacing: 0;
}

/* The whole card is the click target — one anchor, stretched. No nested
   interactive elements, so this stays keyboard-correct. */
.plank-card__link {
    font: inherit;
    color: var(--ink);
    text-decoration: none;
}
.plank-card__link::after {
    content: "";
    position: absolute;
    inset: 0;
}
.plank-card__link:hover,
.plank-card__link:focus-visible { text-decoration: underline; }
.plank-card:has(.plank-card__link:focus-visible) { outline: 3px solid var(--ink); outline-offset: -3px; }
.plank-card__link:focus-visible { outline: none; }

.plank-card__text { margin: 0; }

/* Sits on the card's bottom edge regardless of how much card_text there is, so
   the six cards line their doors up with each other. */
.plank-card__more {
    display: block;
    margin-top: auto;
    padding-top: 1rem;
    color: var(--ink);
    font-weight: 600;
    font-size: 0.9375rem;
    letter-spacing: 0.01em;
}

.plank-card__arrow {
    display: inline-block;
    transition: transform 120ms ease-out;
    will-change: transform;
}

@media (prefers-reduced-motion: reduce) {
    /* Keep the fill and the rule — drop only the movement. */
    .plank-card__arrow { transition: none; }
    .plank-card:hover .plank-card__arrow,
    .plank-card:has(.plank-card__link:focus-visible) .plank-card__arrow { transform: none; }
}

@media (min-width: 44em) {
    .plank-cards { grid-template-columns: 1fr 1fr; }
}

/* HOUSING BLOCK / WHO I AM / ROOTED / CLOSING — shared measure and rhythm. */
.housing-block__heading,
.who-i-am__heading,
.rooted__heading,
.closing__heading { margin-bottom: 1.25rem; }

.housing-block .container > p,
.who-i-am .container > p,
.rooted .container > p { max-width: 66ch; }

.housing-block .container > p + p,
.who-i-am .container > p + p,
.rooted .container > p + p,
.closing .container > p + p { margin-top: 1em; }

.housing-block { background: var(--limestone); }

.housing-block__ctas,
.closing__ctas {
    list-style: none;
    margin: 1.75rem 0 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 1rem 1.5rem;
}

.housing-block__cta { max-width: 30rem; }

.housing-block__cta-note {
    display: block;
    font-size: 0.9375rem;
    line-height: 1.45;
    margin-top: 0.5rem;
    color: var(--ink-deep);
    opacity: 0.8;
}

.who-i-am__cta,
.rooted__cta { margin-top: 1.75rem; }

.rooted__heading { margin-bottom: 1.75rem; }
.rooted__pullquote + p { margin-top: clamp(2rem, 1.2rem + 3vw, 3.5rem); }

.closing { background: var(--limestone); }

/* --------------------------------------------------------------------------
   BUTTONS
   -------------------------------------------------------------------------- */

.btn {
    display: inline-block;
    font-weight: 600;
    font-size: 1rem;
    line-height: 1.3;
    padding: 0.8rem 1.4rem;
    border: 2px solid var(--ink);
    color: var(--ink);
    background: transparent;
    text-decoration: none;
}

.btn:hover, .btn:focus-visible { background: var(--limestone); }

.btn--primary {
    background: var(--ink);
    color: var(--paper);
}
.btn--primary:hover, .btn--primary:focus-visible {
    background: var(--ink-deep);
    border-color: var(--ink-deep);
    color: var(--paper);
}

/* Not emitted by any v3 page today; kept because v2 uses it and a content
   edit could reintroduce it. */
.btn--secondary {
    background: transparent;
    color: var(--ink);
    border-color: var(--rule);
}
.btn--secondary:hover, .btn--secondary:focus-visible {
    border-color: var(--ink);
    background: var(--limestone);
}

/* --------------------------------------------------------------------------
   CARRY-OVER — pages with no v3 controller. Unstyled here means raw there.
   -------------------------------------------------------------------------- */

/* /story/ and /lineage/ — photos injected into the rendered HTML by the v2
   controllers. --right sits inside a <p> and floats; --closing is a direct
   child of .prose. Neither may exceed the measure. */
.story-photo { display: block; max-width: 100%; height: auto; background: var(--limestone); }

.story-photo--right {
    float: right;
    width: 11rem;
    margin: 0.35rem 0 1rem 1.5rem;
    shape-margin: 1rem;
}

.story-photo--closing {
    width: 100%;
    max-width: 22rem;
    margin-inline: auto;
    margin-block-start: 2.5rem;
}

@media (max-width: 30em) {
    .story-photo--right { width: 8.5rem; margin-left: 1rem; }
}

/* /journey/ */
.journey-photo {
    margin-block: 2rem;
}
.journey-photo img { display: block; width: 100%; height: auto; background: var(--limestone); }

@media (min-width: 44em) {
    .journey-photo { width: 15rem; }
    .journey-photo--left  { float: left;  margin: 0.35rem 1.75rem 1.25rem 0; }
    .journey-photo--right { float: right; margin: 0.35rem 0 1.25rem 1.75rem; }
}

.journey-media { margin-block: 2.5rem; }
.journey-media video { display: block; width: 100%; background: var(--ink-deep); }
.journey-media figcaption {
    font-size: 0.9375rem;
    line-height: 1.5;
    color: var(--ink-deep);
    opacity: 0.85;
    margin-top: 0.65rem;
}

/* The Facebook embed. aspect-ratio + max-width per the brief. The known
   narrow-viewport crop inside Facebook's own iframe is out of scope here. */
.journey-media__fb-wrap {
    position: relative;
    width: 100%;
    max-width: 26.25rem;
    aspect-ratio: 9 / 16;
    background: var(--limestone);
}
.journey-media__fb-wrap iframe {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: 0;
}

.journey-article-card {
    border-block: 1px solid var(--rule);
    padding-block: 1.5rem;
    margin-block: 2.5rem;
}
.journey-article-card__date {
    font-size: 0.8125rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ink);
    margin-bottom: 0.5rem;
}
.journey-article-card__title {
    font-family: Bitter, Georgia, serif;
    font-weight: 700;
    font-size: clamp(1.25rem, 1.1rem + 0.8vw, 1.625rem);
    line-height: 1.2;
    margin-bottom: 0.6rem;
}
.journey-article-card__title a { font: inherit; color: var(--ink); text-decoration: none; }
.journey-article-card__title a:hover,
.journey-article-card__title a:focus-visible { text-decoration: underline; }
.journey-article-card__pull { margin-bottom: 0.75rem; }
.journey-article-card__more { font-weight: 600; margin: 0; }

/* Clear the floated journey photos so a card never wraps around one. */
.journey-article-card,
.journey-media { clear: both; }

.journey-back {
    font-weight: 600;
    margin-bottom: 1.5rem;
}

/* /contact/ */
.contact-layout { display: grid; gap: 2rem; }
.contact-layout__photo img { width: 100%; height: auto; display: block; background: var(--limestone); }

@media (min-width: 52em) {
    .contact-layout { grid-template-columns: minmax(0, 1fr) minmax(0, 18rem); align-items: start; }
    .contact-layout__photo { order: 2; }
    .contact-layout__form  { order: 1; }
}

.contact-form { margin-top: 1.5rem; }

.form-field { margin-bottom: 1.25rem; }
.form-field label {
    display: block;
    font-weight: 600;
    margin-bottom: 0.35rem;
}
.form-field input,
.form-field select,
.form-field textarea {
    width: 100%;
    font: inherit;
    color: inherit;
    padding: 0.65rem 0.75rem;
    border: 1px solid var(--rule);
    background: var(--paper);
}
.form-field textarea { min-height: 10rem; resize: vertical; }
.form-field input:focus-visible,
.form-field select:focus-visible,
.form-field textarea:focus-visible { border-color: var(--ink); }

.form-field__hint {
    display: block;
    font-size: 0.875rem;
    line-height: 1.45;
    color: var(--ink-deep);
    opacity: 0.8;
    margin-top: 0.35rem;
    font-weight: 400;
}

.form-privacy {
    font-size: 0.875rem;
    line-height: 1.5;
    color: var(--ink-deep);
    opacity: 0.85;
    margin-top: 1rem;
}

/* --------------------------------------------------------------------------
   STATE-ONLY — none of these appear in a GET. All must be styled or the
   failure is invisible.
   -------------------------------------------------------------------------- */

/* Melissa will test the contact form. An unstyled panel reads as broken. */
.form-success {
    border: 2px solid var(--ink);
    background: var(--limestone);
    padding: clamp(1.25rem, 1rem + 1.5vw, 2rem);
    margin-block: 1.5rem;
}
.form-success h2 { margin-bottom: 0.5rem; }
.form-success p { margin: 0; }

.form-error {
    border-left: 4px solid var(--ink);
    background: var(--limestone);
    padding: 0.85rem 1rem;
    margin-bottom: 1.25rem;
    font-weight: 600;
}

/* Interim bracketed copy must never be mistaken for finished copy — that is
   the entire point of the convention in includes/markdown.php. */
.placeholder-slot {
    color: var(--ink);
    background: var(--limestone);
    border-left: 4px solid var(--rule);
    padding: 0.6rem 0.9rem;
    font-style: italic;
    opacity: 0.9;
}

/* Fail-loud must look loud. */
.v3-missing {
    background: var(--ink-deep);
    color: var(--paper);
    border: 2px solid var(--ink);
    padding: 0.85rem 1rem;
    margin: 0 0 1.5rem;
    font-weight: 600;
    font-size: 0.9375rem;
    line-height: 1.5;
}
.v3-todo {
    background: var(--ink-deep);
    color: var(--paper);
    padding: 0.1em 0.4em;
    font-weight: 600;
    white-space: nowrap;
}

/* --------------------------------------------------------------------------
   FOOTER
   -------------------------------------------------------------------------- */

.site-footer {
    background: var(--ink-deep);
    color: var(--paper);
    padding-block: clamp(2.5rem, 1.5rem + 3vw, 4rem);
    margin-block-start: 0;
}

.site-footer a { color: var(--paper); text-underline-offset: 0.18em; }

.site-footer__list {
    list-style: none;
    margin: 0 0 2rem;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem 1.75rem;
    font-weight: 600;
}

/* The contact line. footer.php concatenates the item spans with NO whitespace
   between them, so an inline layout has no soft-wrap opportunity and the whole
   line becomes one unbreakable run — 539px wide at any viewport. Flex supplies
   the break opportunities that the markup does not.
   Each item keeps nowrap so its leading separator can never be orphaned onto
   the start of a wrapped line; below 30em the items stack and the separators
   (decorative, aria-hidden) are dropped entirely. */
.site-footer__contact {
    margin: 0 0 1rem;
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
}
.site-footer__contact-item { white-space: nowrap; }
.site-footer__sep { padding-inline: 0.6rem; opacity: 0.6; }

@media (max-width: 30em) {
    .site-footer__contact { flex-direction: column; align-items: flex-start; gap: 0.5rem; }
    .site-footer__sep { display: none; }
}

.site-footer__tagline,
.tagline {
    font-family: Bitter, Georgia, serif;
    font-weight: 600;
    font-size: clamp(1.0625rem, 1rem + 0.5vw, 1.25rem);
    margin: 0 0 1rem;
}

.site-footer__copy {
    margin: 0;
    font-size: 0.875rem;
    opacity: 0.8;
}

/* --------------------------------------------------------------------------
   PLATFORM HUB
   The card grid is a direct child of .prose, so without this it inherits the
   66ch reading measure and the 2-up layout comes out cramped. Widen the grid
   only — the hub's prose keeps the measure.
   -------------------------------------------------------------------------- */

.platform-hub > .plank-cards {
    --flow-space: clamp(2.5rem, 1.5rem + 3vw, 4rem);
    width: min(56rem, calc(100vw - 2.5rem));
    margin-inline: auto;
}

@media (min-width: 48em) {
    .platform-hub > .plank-cards { width: min(56rem, calc(100vw - 4rem)); }
}

/* Translate the grid's own edge back so it stays centred on the page rather
   than on the narrower prose column. */
.platform-hub > .plank-cards {
    margin-inline: calc((100% - min(56rem, calc(100vw - 2.5rem))) / 2);
}

@media (min-width: 48em) {
    .platform-hub > .plank-cards {
        margin-inline: calc((100% - min(56rem, calc(100vw - 4rem))) / 2);
    }
}

/* --------------------------------------------------------------------------
   JOURNEY MEDIA MODIFIERS
   The base .journey-media carries the shared rhythm; these two set the width
   each medium actually wants.
   -------------------------------------------------------------------------- */

.journey-media--video { max-width: 34rem; }
.journey-media--video video { border: 1px solid var(--rule); }

.journey-media--fbvideo { max-width: 26.25rem; }

/* --------------------------------------------------------------------------
   FOOTER STRUCTURE
   -------------------------------------------------------------------------- */

.site-footer__nav { margin-bottom: 0; }

.site-footer__meta {
    max-width: 60ch;
    border-top: 1px solid rgba(251, 250, 247, 0.25);
    padding-top: 1.5rem;
}

/* .site-footer__inner is also .container, so it already carries the page
   gutter and max-width. Nothing further is needed here. */

/* --------------------------------------------------------------------------
   BODY PAGE HOOKS — .page-<slug>, one per URL, emitted by every controller.
   DELIBERATELY UNSTYLED. They are scoping hooks for future page-specific
   overrides, not visual classes; every one of the fourteen is fully styled by
   the component rules above. Listed here so the coverage audit can see they
   were considered rather than missed:
     .page-home .page-platform .page-housing
     .page-affordability-and-growth .page-infrastructure-and-accountability
     .page-safety-and-crisis-response .page-food-and-resilience .page-heritage
     .page-story .page-lineage .page-journey .page-voting
     .page-get-involved .page-contact
   -------------------------------------------------------------------------- */
