/* ===========================================
   LANDING.CSS - Dark editorial landing page
   Scoped to body.landing-page (index.html only).
   Loaded AFTER main.css so it wins the cascade.
   =========================================== */

.landing-page {
    /* All existing tokens. Page and cards separate by only 1.06:1, so
       cards carry a border rather than the shadow the guide pages use;
       this page is flat by design. --d-ink is the single off-black,
       shared with every other page. */
    --d-bg: var(--bg-page);         /* #f8f8f8, same as every other page */
    --d-surface: var(--bg-surface); /* #ffffff */
    --d-ink: var(--text-primary);   /* #1a1a1a, 15.4:1 on the page */
    --d-ink-soft: var(--text-secondary); /* #3d3a37, 11.3:1 on a card */
    --d-ink-dim: var(--text-muted);      /* #595550, 6.6:1 on the page */

    --d-line: var(--border-light);   /* #e5e5e5 */
    --d-line-strong: var(--border-default); /* #d4d4d4 */

    background: var(--d-bg);
    color: var(--d-ink);
}

.landing-page main {
    max-width: 1400px;
    margin: 0 auto;
    padding: 0 var(--space-2xl);
    width: 100%;
}

/* Skip link: the shared rule parks it at top:-40px while its box is 45px
   tall, so five pixels sit above the fold. Park it fully off-canvas.
   The same bug is still live on the guide pages. */
.landing-page .skip-link {
    top: -100px;
}

.landing-page .skip-link:focus {
    top: 0;
}

/* =========================================
   HEADER
   The page uses the site header from layout.css, the same one every
   other page has. Only two things need correcting: it is sticky at
   top:36px to clear the utility bar the guide pages carry above it,
   and this page has no such bar.
   ========================================= */

/* Rest position identical to the guide pages: the shared margin-top:36px
   stays, so the logo sits at y=60 everywhere and never jumps on
   navigation. But the shared top:36px reserves a slot for the utility
   bar the guide pages have above their header; this page has none, so
   content scrolled visibly through the open slot. Sticking at 0 puts
   the header flush against the viewport once you scroll. */
.landing-page .site-header {
    top: 0;
}

/* Frosted-glass header: content blurs through it while scrolling.
   Solid opaque fallback stays for browsers without backdrop-filter. */
@supports (backdrop-filter: blur(12px)) or (-webkit-backdrop-filter: blur(12px)) {
    .landing-page .site-header {
        background: rgba(248, 248, 248, 0.72);
        -webkit-backdrop-filter: blur(12px) saturate(1.4);
        backdrop-filter: blur(12px) saturate(1.4);
    }
}

/* =========================================
   THE GRID - staircase, 4 columns x 2 rows
   Row 1: [ headline .......... ] [ 01 ] [ 02 ]
   Row 2: [ form ] [ 03 ] [ 04 ] [ 05 ]
   minmax(0, 1fr) so the display headline cannot
   blow the first column past its track.
   ========================================= */

.landing-page .landing-grid {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    /* Cards stretch to their row, so each row's cards are equal; the
       tallest content sets the row and nothing else adds height. */
    gap: var(--space-md);
    padding: var(--space-2xl) 0 var(--space-3xl);
}

/* Only the hero is placed. Every tile after it auto-flows in document
   order, and document order is the visual order, so what you tab through
   is what you see (WCAG 2.4.3). Reordering the page means moving the
   markup, not rewriting a placement table. */
.landing-page .hero-text  { grid-area: 1 / 1 / 2 / 3; }

/* HERO */
.landing-page .hero-text {
    align-self: stretch;
    display: flex;
    flex-direction: column;
    padding: 0 var(--space-xl) var(--space-sm) 0;
}

.landing-page .hero-text h1 {
    font-size: var(--font-4xl);
    font-weight: 700;
    line-height: 0.95;
    letter-spacing: -0.035em;
    text-wrap: balance;
    color: var(--d-ink);
    margin: 0 0 var(--space-lg);
}

.landing-page .hero-text .value-prop {
    font-size: var(--font-xl);
    line-height: 1.5;
    color: var(--d-ink-soft);
    margin: 0;
    max-width: 52ch;
}

/* The page is lang="de", so browsers with a German dictionary can
   hyphenate the long compounds. No overflow-wrap here: it breaks words
   at arbitrary letters ("Webentwicklun/g"), which is worse than the
   overflow it prevents. The padding and type sizes below make the
   longest word fit without needing either. */
.landing-page .hero-text h1,
.landing-page .guide-card h2,
.landing-page .guide-card .benefit {
    hyphens: auto;
}

/* =========================================
   TILES
   Title at the top, copy beneath it, link pinned
   to the bottom edge, so the box carries content
   top to bottom instead of hugging one corner.
   ========================================= */

.landing-page .guide-card {
    background: var(--d-surface);
    color: var(--d-ink);
    display: flex;
    flex-direction: column;
    /* No min-height: content decides. 32px vertical padding, 40px
       horizontal; the old 40px all round plus a 236px floor is what
       made every box tall. */
    padding: 32px 40px;
    border: 1px solid var(--d-line-strong);
    border-radius: 0;
    text-decoration: none;
}

/* No hover rules: the shared .guide-card:hover from pages.css applies,
   the same lift and shadow the live index had. */

.landing-page .guide-card:focus-visible {
    outline: 2px solid var(--d-ink);
    outline-offset: 2px;
}

.landing-page .guide-card h2 {
    font-size: var(--font-xl);
    font-weight: 700;
    line-height: 1.05;
    letter-spacing: -0.02em;
    /* Not balanced: a long title fills the first line and the remainder
       drops to the second. */
    text-wrap: wrap;
    color: inherit;
    /* Two lines are reserved whether the title needs them or not, so the
       copy underneath starts at the same height in every tile. */
    min-height: 2.1em;
    margin: 0 0 var(--space-md);
}

.landing-page .guide-card .benefit {
    font-size: var(--font-sm);
    line-height: 1.55;
    color: var(--d-ink-soft);
    margin: 0;
    flex-grow: 0;
}

.landing-page .guide-card .cta {
    font-size: var(--font-sm);
    font-weight: 600;
    color: inherit;
    /* No margin-top:auto here. Pinning the link to the bottom edge dumps
       every pixel of surplus row height into one gap between the copy and
       the link. The link follows the copy on a fixed rhythm instead, and
       leftover height reads as bottom padding. */
    padding-top: var(--space-md);
}

/* DARK TILES
   The middle row carries the three services the business is actually
   built on. They are filled with the site's ink; the guides and the
   partner around them stay white, so the row reads as the centre of the
   page rather than as three more cards.

   Colour only. Every tile in the grid carries .guide-card, which brings
   the structure, the hover lift and the focus ring, so there is one
   definition of a tile and this is a layer on top of it. Title and link
   are color: inherit and follow the fill; only the body copy needs its
   own value. */
.landing-page .tile-dark {
    background: var(--text-primary);
    border-color: var(--text-primary);
    color: var(--d-surface);
}

.landing-page .tile-dark .benefit {
    /* #f3f1ed on #1a1a1a: 14.6:1. */
    color: var(--bg-muted);
}

/* =========================================
   BIO PANEL
   Same material as the tiles at a larger scale.
   The contact form lives here, directly under the
   availability line that motivates it, rather than
   sitting in the guide grid as a peer of the guides.
   ========================================= */

.landing-page .landing-about {
    max-width: none;
    margin: 0 0 var(--space-3xl);
    padding: var(--space-3xl);
    background: var(--d-surface);
    color: var(--d-ink);
    border: 1px solid var(--d-line-strong);
    border-top: 1px solid var(--d-line-strong);
    display: grid;
}

.landing-page .landing-about h2 {
    /* One token above the 14px copy: a card title, not a display
       heading. The guide grid keeps 24px; this supporting row does not
       compete with it. */
    font-size: var(--font-base);
    font-weight: 700;
    line-height: 1.05;
    letter-spacing: -0.03em;
    text-wrap: balance;
    color: var(--d-ink);
    margin: 0;
    max-width: 30ch;
}

/* Paragraph rhythm inside a column: one line-height's worth. */
.landing-page .about-card p + p {
    margin-top: var(--space-md);
}

.landing-page .about-card p {
    /* Same size and rhythm as the card benefits, so the panel reads as
       the same component family: 24px title, 14px copy. */
    font-size: var(--font-sm);
    line-height: 1.55;
    color: var(--d-ink-soft);
    text-align: left;
    margin: 0;
    max-width: 62ch;
}

.landing-page .landing-about a {
    color: var(--d-ink);
    font-weight: 500;
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 4px;
}

/* Availability runs inline in the copy, carried by weight alone.
   font-size is reset explicitly: the shared .intake-note rule sets 14px,
   written for when this was its own paragraph. Inline inside a 17px
   paragraph that shrank the sentence mid-line. */
.landing-page .intake-note {
    color: var(--d-ink);
    font-weight: 700;
    font-size: inherit;
}

/* --- form -------------------------------------------------------------
   One definition, one place. Airy: plain labels over full-width fields,
   a clear gap between groups, no chips, no tails.
   ---------------------------------------------------------------------- */
/* Inline labels: plain text left, field beside it, both columns sized
   by the widest label. The textarea row top-aligns its label. */
.landing-page .about-form .contact-form {
    margin-top: 0;
    width: 100%;
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    column-gap: var(--space-md);
    row-gap: 12px;
    align-items: center;
}

.landing-page .contact-form label {
    grid-column: 1;
    color: var(--d-ink);
    font-size: var(--font-sm);
    font-weight: 500;
    line-height: 1.35;
    padding: 0;
    margin: 0;
}

.landing-page .contact-form label[for="contact-message"] {
    align-self: start;
    padding-top: 10px;
}

.landing-page .contact-form input,
.landing-page .contact-form textarea {
    grid-column: 2;
    display: block;
    width: 100%;
    color: var(--d-ink);
    font-size: var(--font-sm);
    padding: 10px var(--space-md);
    margin: 0;
    border-radius: 0;
}

/* Button sits in the field column, exactly as wide as the inputs. */
.landing-page .contact-form button {
    grid-column: 2;
}

.landing-page .contact-form .form-error,
.landing-page .contact-form .form-success {
    grid-column: 1 / -1;
}

.landing-page .contact-form textarea {
    min-height: 48px;
    resize: vertical;
}

.landing-page .contact-form input::placeholder,
.landing-page .contact-form textarea::placeholder {
    color: #6b6866;   /* 5.0:1 on the field */
}

.landing-page .contact-form input:focus,
.landing-page .contact-form textarea:focus {
    outline: 2px solid var(--d-ink);
    outline-offset: 2px;
    border-color: var(--d-ink);
}

.landing-page .contact-form button {
    background: var(--d-ink);
    color: var(--d-surface);
    border: 1px solid var(--d-ink);
    font-size: var(--font-sm);
    font-weight: 600;
    padding: 10px var(--space-md);
    border-radius: 0;
}

.landing-page .contact-form button:hover {
    background: transparent;
    color: var(--d-ink);
}

.landing-page .contact-form button:focus-visible {
    outline: 2px solid var(--d-ink);
    outline-offset: 3px;
}

.landing-page .form-note {
    font-size: var(--font-sm);
    line-height: 1.6;
    color: var(--d-ink-soft);
    margin: var(--space-sm) 0 0;
}

.landing-page .form-error {
    background: transparent;
    border: 1px solid var(--d-ink);
    padding: var(--space-md);
    margin-bottom: var(--space-md);
    font-size: var(--font-sm);
    border-radius: 0;
}

.landing-page .form-error p,
.landing-page .form-success p,
.landing-page .form-success strong {
    color: var(--d-ink);
}

.landing-page .form-success {
    background: transparent;
    border: 1px solid #767472;
    border-radius: 0;
    text-align: left;
}

.landing-page .form-success .form-note {
    color: var(--d-ink-soft);
}

/* =========================================
   FOOTER
   ========================================= */

.landing-page .landing-footer {
    background: transparent;
    color: var(--d-ink-soft);
    border-top: 1px solid var(--d-line-strong);
    max-width: 1400px;
    margin: 0 auto;
    padding: var(--space-lg) var(--space-2xl);
    font-size: var(--font-sm);
}

.landing-page .landing-footer p {
    font-size: var(--font-sm);
    color: var(--d-ink-soft);
}

.landing-page .landing-footer a,
.landing-page .landing-footer .legal-links a {
    font-size: var(--font-sm);
    color: var(--d-ink);
    text-decoration: none;
    border-bottom: 1px solid transparent;
}

.landing-page .landing-footer a:hover,
.landing-page .landing-footer .legal-links a:hover {
    border-bottom-color: var(--d-ink);
}

.landing-page .landing-footer .legal-links {
    gap: var(--space-lg);
}

/* =========================================
   RESPONSIVE
   ========================================= */

@media (max-width: 1000px) {
    /* Staircase collapses to a plain 2-up: headline and form full width,
       then the five tiles flow in order. */
    .landing-page .landing-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
    .landing-page .hero-text {
        grid-area: auto;
        grid-column: 1 / -1;
    }
    .landing-page .hero-text {
        padding-right: 0;
    }


}

@media (max-width: 640px) {
    .landing-page main {
        padding: 0 var(--space-lg);
    }
    /* minmax(0,...) so a track can go below its min-content width, plus
       hyphenation on the long German compounds. Without both,
       "Barrierefreiheitsstärkungsgesetz" and 40px of card padding set a
       floor of 310px inside a 272px content box, and the page scrolled
       sideways at 320px: WCAG 1.4.10 Reflow. */
    .landing-page .landing-grid {
        grid-template-columns: minmax(0, 1fr);
        padding-bottom: var(--space-2xl);
    }
    .landing-page .hero-text h1 {
        font-size: var(--font-2xl);
    }
    .landing-page .hero-text .value-prop {
        font-size: var(--font-base);
    }
    /* 16px padding leaves 240px of text width at 320, and the longest
       word on the page, Barrierefreiheitsstaerkungsgesetz, needs 234. */
    .landing-page .guide-card {
        padding: var(--space-md);
    }
    .landing-page .landing-footer {
        flex-direction: column;
        align-items: flex-start;
        gap: var(--space-md);
        text-align: left;
        padding: var(--space-lg);
    }
}

@media (prefers-reduced-motion: reduce) {
    .landing-page .guide-card,
    .landing-page .contact-form button {
        transition: none;
    }
}


/* ===========================================
   THREE-COLUMN GRID
   Merged from the former landing-3col.css; appended last so its
   overrides keep exactly the cascade order the two files had.
   =========================================== */

.landing-3col .landing-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
}

/* The hero spans the first two columns; the seven tiles auto-flow after
   it in document order:

       [ hero .................... ] [ BFSG-Check ]
       [ Website ] [ SEO ] [ Reichweite ]            <- the dark row
       [ Barrierefreiheit ] [ Werbung ] [ Wartung ]
*/
.landing-3col .hero-text { grid-area: 1 / 1 / 2 / 3; }

/* HERO COPY
   Previously capped at 700px inside an 832px cell: a correct 66-character
   measure whose right edge aligned with nothing.

   Instead of narrowing the text to fit the measure, scale the text so the
   measure fits the cell. The hero spans two grid columns, 864px. Dropping
   the cell's right padding and raising the type to 25px puts 66 characters
   across the full 864px, so the paragraph now ends exactly where column
   two ends, on the gap before the tiles. */
/* HERO VERTICAL RHYTHM
   Two rules agree on the same number, which is why it is this one:

   - one line of the copy it separates: 25px x 1.5 = 37.5px
   - the 40px padding the cards already use inside themselves

   So 40px above the copy, and 40px below it to the next row: 24px of
   cell padding plus the grid's own 16px gap. The hero now breathes like
   a card does, instead of 24px above and 8px below. */
/* 32px above the copy and 16px + the grid's 16px gap below it: the
   same 32px vertical rhythm the cards now run inside themselves. */
.landing-3col .hero-text {
    padding-right: 0;
    padding-bottom: 16px;
}

.landing-3col .hero-text h1 {
    margin-bottom: 32px;
}

/* Size lives in landing.css (--font-xl, 17px under 640). text-wrap:
   pretty improves the rag where supported; the non-breaking spaces in
   the markup do the load-bearing work. */
.landing-3col .hero-text .value-prop {
    max-width: none;
    text-wrap: pretty;
}

/* BIO PANEL: THREE COLUMNS
   Heading, copy, form, one per column.

   Padding drops from 64px to 40px, matching the cards, to buy the
   middle column back the width it needs; at 64px the copy fell to 39
   characters per line. */
.landing-3col .landing-about {
    /* 16px between columns of prose was far too tight: text in adjacent
       cards is separated by 96px (40 padding + 16 gap + 40 padding), so
       16px inside the panel read as cramped against the grid above.
       Gaps now match the panel's own 40px padding.

       The form column is narrower than the two text columns, which buys
       the prose back the width the wider gaps cost: 46 characters per
       line rather than 43. */
    /* Not one wrapper panel: three cards on exactly the tracks and gap
       the card rows above use, so the row reads as one more grid row. */
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-md);
    padding: 0;
    background: transparent;
    border: none;
}

.landing-3col .about-card h2 {
    margin: 0 0 var(--space-md);
}

/* Two blocks rather than display:contents, so a column can hold more
   than one paragraph without needing its own grid placement. */

.landing-3col .about-body > p {
    max-width: none;
}

/* FORM LABELS
   Full-width bars stacked directly on their fields, same fill as the
   callouts they replace. No tail: sitting flush on top of the field,
   there is nothing left to point at. */
/* At full width the tiles are wide enough that titles no longer need a
   reserved second line to keep their copy flush. */
.landing-3col .guide-card h2 {
    min-height: 0;
}

@media (max-width: 1000px) {
    /* Same collapse as the four-column version: headline full width,
       then the tiles in order, with the paid service closing the row. */
    .landing-3col .landing-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
    .landing-3col .hero-text {
        grid-area: auto;
        grid-column: 1 / -1;
    }
    /* Three dark tiles do not divide by two, so on a two-column grid one
       of them would always sit beside a white one and the middle row
       would stop reading as one band. The tile before the dark run
       (BFSG-Check) and the last of the run (Reichweite) take the full
       width, which leaves every row a single colour:

           [ BFSG-Check ..................... ]
           [ Website ] [ SEO ]
           [ Reichweite ...................... ]
           [ Barrierefreiheit ] [ Werbung ]
           [ Wartung ]
    */
    .landing-3col .landing-grid > a:nth-of-type(1),
    .landing-3col .landing-grid > a:nth-of-type(4) {
        grid-column: 1 / -1;
    }
}

@media (max-width: 1000px) {
    /* Panel stacks. The column assignments have to be reset with it:
       leaving grid-column 2 and 3 against a single-column grid creates
       implicit tracks, which squeezed the form to 41px at 390. */
    .landing-3col .landing-about {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (max-width: 640px) {
    .landing-3col .landing-grid {
        grid-template-columns: minmax(0, 1fr);
    }
    .landing-3col .landing-about {
        grid-template-columns: minmax(0, 1fr);
    }
}


/* ===========================================
   ENTRANCE (index only)
   One signature moment: the headline builds word by word out of an
   overflow mask. Everything else gets a single quiet rise-in with a
   short stagger. All plain CSS, absent under reduced motion.
   animation-fill-mode: backwards hides elements only until their
   delay, then hands transform back to the hover rules.
   =========================================== */

@media (prefers-reduced-motion: no-preference) {
    @keyframes word-rise {
        from { transform: translateY(115%); }
        to { transform: translateY(0); }
    }

    @keyframes soft-rise {
        from {
            opacity: 0;
            transform: translateY(18px);
        }
        to {
            opacity: 1;
            transform: translateY(0);
        }
    }

    /* The padding/negative-margin pair widens the clip box so
       descenders survive the overflow mask. */
    .landing-3col .hero-text h1 .hw {
        display: inline-block;
        overflow: hidden;
        vertical-align: bottom;
        padding-bottom: 0.14em;
        margin-bottom: -0.14em;
    }

    .landing-3col .hero-text h1 .hw > span {
        display: inline-block;
        animation: word-rise 0.7s cubic-bezier(0.19, 1, 0.22, 1) backwards;
        animation-delay: calc(var(--w) * 0.09s);
    }

    .landing-3col .hero-text .value-prop {
        animation: soft-rise 0.6s cubic-bezier(0.19, 1, 0.22, 1) 0.3s backwards;
    }

    .landing-3col .guide-card,
    .landing-3col .about-card {
        animation: soft-rise 0.5s ease-out backwards;
    }

    /* Stagger follows the reading order of the grid. Keyed to position
       rather than to a tile's name, so reordering the markup reorders
       the entrance with it. */
    .landing-3col .landing-grid > a:nth-of-type(1) { animation-delay: 0.25s; }
    .landing-3col .landing-grid > a:nth-of-type(2) { animation-delay: 0.31s; }
    .landing-3col .landing-grid > a:nth-of-type(3) { animation-delay: 0.37s; }
    .landing-3col .landing-grid > a:nth-of-type(4) { animation-delay: 0.43s; }
    .landing-3col .landing-grid > a:nth-of-type(5) { animation-delay: 0.49s; }
    .landing-3col .landing-grid > a:nth-of-type(6) { animation-delay: 0.55s; }
    .landing-3col .landing-grid > a:nth-of-type(7) { animation-delay: 0.61s; }
    .landing-3col .about-card:nth-child(1) { animation-delay: 0.67s; }
    .landing-3col .about-card:nth-child(2) { animation-delay: 0.73s; }
    .landing-3col .about-card:nth-child(3) { animation-delay: 0.79s; }
}


/* ===========================================
   FOOTER ZONE (index only)
   The three about-cards become an open three-column zone that reads
   as the page's footer: kicker + card-style title per column, prose,
   underline-only form fields, the submit styled like the card links,
   then the hairline bottom bar. Same tokens, same type as the tiles
   above; appended last so it wins the cascade over the panel rules.
   =========================================== */

/* --- zone --------------------------------------------------------- */
.landing-3col .landing-about {
    /* The two prose columns are held to 40ch anyway; the card takes the
       extra width. */
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1.3fr);
    column-gap: var(--space-3xl);
    row-gap: var(--space-2xl);
    margin: var(--space-3xl) 0 var(--space-3xl);
    padding: 0;
}

.landing-3col .about-card {
    background: transparent;
    border: 0;
    padding: 0;
}

/* --- eyebrow ------------------------------------------------------ */
/* Same voice as the card copy: 14px, medium, muted. No uppercase, no
   tracking; the site does not use either for labels. */
.landing-3col .about-card .eyebrow,
.landing-3col .about-card h2.eyebrow {
    font-size: var(--font-sm);
    font-weight: 500;
    line-height: 1.35;
    letter-spacing: normal;
    text-transform: none;
    color: var(--d-ink-dim);
    margin: 0 0 var(--space-sm);
    max-width: none;
}

/* --- column headline ---------------------------------------------- */
/* Identical to the guide-card title above: 24px, 700, tight. */
.landing-3col .about-card h2:not(.eyebrow) {
    font-size: var(--font-xl);
    font-weight: 700;
    line-height: 1.05;
    letter-spacing: -0.02em;
    color: var(--d-ink);
    margin: 0 0 var(--space-md);
    max-width: 20ch;
}

/* The availability line is now the column headline, no longer an
   inline bold; neutralise the shared .intake-note rule. */
.landing-3col h2.intake-note {
    font-weight: 700;
    font-size: var(--font-xl);
}

.landing-3col .about-card p:not(.eyebrow) {
    font-size: var(--font-sm);
    line-height: 1.55;
    color: var(--d-ink-soft);
    max-width: 40ch;
}

/* --- form card ------------------------------------------------------
   The third column is a white card: title, two boxed fields, one
   full-width filled button. It is the only card material in the zone,
   which is what marks it as the thing to act on.

   Accessibility, checked against WCAG 2.2 AA:
   - Labels stay in the markup for assistive tech and are hidden
     visually; the placeholder is the visible cue.
   - No field border (Anastasia's call). 1.4.11 allows that when the
     control is identifiable by other means: the placeholder is 7:1 on
     the field fill, typed text 15:1, and the focus ring below.
   - Placeholder: --d-ink-dim (#575049) on the --bg-muted fill, 7.0:1
     (1.4.3). The lighter #767472 used before was under 4.5:1 and failed.
   - Fields are 16px so iOS does not zoom on focus; e-mail field,
     message field and button are all exactly 44px tall (2.5.8). The
     message field opens to three lines on focus and grows with the
     text (js/main.js), back to its content height on blur.
   - Focus: 2px ink ring with 2px offset (2.4.7, 2.4.13).
   ---------------------------------------------------------------------- */
.landing-3col .about-form {
    background: var(--d-surface);
    padding: var(--space-xl);
    box-shadow: var(--shadow-md);
    align-self: start;
}

.landing-3col .about-form h2 {
    margin-bottom: var(--space-md);
}

.landing-3col .about-form .contact-form {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    row-gap: var(--space-sm);
    align-items: stretch;
    margin-top: 0;
}

.landing-3col .contact-form label,
.landing-3col .contact-form input,
.landing-3col .contact-form textarea,
.landing-3col .contact-form button {
    grid-column: 1;
}

/* Visually hidden, still announced. */
.landing-3col .contact-form label {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.landing-3col .contact-form input,
.landing-3col .contact-form textarea {
    box-sizing: border-box;
    width: 100%;
    height: 44px;
    min-height: 44px;
    margin: 0;
    padding: 10px 14px;
    background: var(--bg-muted);
    border: 0;
    border-radius: 0;
    color: var(--d-ink);
    font-family: inherit;
    font-size: 16px;
    line-height: 1.4;
}

.landing-3col .contact-form input::placeholder,
.landing-3col .contact-form textarea::placeholder {
    color: var(--d-ink-dim);
    opacity: 1;
}

.landing-3col .contact-form textarea {
    /* One line at rest, the same height as the e-mail field and the
       button. On focus it opens to three lines and then grows with the
       message (js/main.js). Without JS it keeps its drag handle. */
    height: auto;
    resize: vertical;
}

.landing-3col .contact-form textarea:focus {
    min-height: 96px;
}

.landing-3col .contact-form textarea.is-autogrow {
    resize: none;
    overflow: hidden;
}

.landing-3col .contact-form input:focus-visible,
.landing-3col .contact-form textarea:focus-visible {
    outline: 2px solid var(--d-ink);
    outline-offset: 2px;
}

@media (prefers-reduced-motion: no-preference) {
    .landing-3col .contact-form textarea {
        transition: min-height 0.15s ease-out, height 0.15s ease-out;
    }
}

.landing-3col .contact-form button {
    justify-self: stretch;
    width: 100%;
    min-height: 44px;
    margin-top: var(--space-sm);
    background: var(--d-ink);
    color: var(--d-surface);
    border: 1px solid var(--d-ink);
    padding: 12px var(--space-lg);
    /* Buttons do not inherit the page font; the live site's button was
       falling back to Arial for this reason. */
    font-family: inherit;
    font-size: var(--font-sm);
    font-weight: 600;
    line-height: 1.3;
    cursor: pointer;
}

.landing-3col .contact-form button:hover {
    background: var(--d-surface);
    color: var(--d-ink);
}

.landing-3col .contact-form button:focus-visible {
    outline: 2px solid var(--d-ink);
    outline-offset: 3px;
}

.landing-3col .contact-form button:disabled {
    opacity: 0.55;
    cursor: default;
}

.landing-3col .contact-form .form-error,
.landing-3col .contact-form .form-success {
    padding: var(--space-md);
    border: 0;
    border-radius: 0;
    text-align: left;
}

.landing-3col .contact-form .form-error {
    border-left: 3px solid var(--color-danger);
}

/* --- bottom bar ---------------------------------------------------- */
.landing-page .landing-footer {
    padding: var(--space-lg) var(--space-2xl) var(--space-2xl);
    border-top-color: var(--d-line-strong);
    color: var(--d-ink-dim);
}

.landing-page .landing-footer p {
    color: var(--d-ink-dim);
}

/* --- responsive ---------------------------------------------------- */
@media (max-width: 1000px) {
    .landing-3col .landing-about {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        column-gap: var(--space-2xl);
        margin-top: var(--space-3xl);
    }
    .landing-3col .about-form {
        grid-column: 1 / -1;
        max-width: 560px;
    }
}

@media (max-width: 640px) {
    .landing-3col .landing-about {
        grid-template-columns: minmax(0, 1fr);
        row-gap: var(--space-2xl);
        margin-top: var(--space-2xl);
    }
    .landing-3col .about-body {
        padding: 0;
    }
    .landing-3col .about-form {
        padding: var(--space-lg);
    }
    .landing-3col .about-card p:not(.eyebrow),
    .landing-3col .about-card h2:not(.eyebrow) {
        max-width: none;
    }
    .landing-page .landing-footer {
        padding: var(--space-lg) var(--space-lg) var(--space-2xl);
    }
}
