/* ===========================================================================
   Mini Moves Launceston — minimoveslaunceston.com.au
   ===========================================================================

   The design starts from the logo, which is drawn on solid black. So the site
   is dark throughout: near-black page, pure black behind the two logo lockups
   so they sit on their own ground with no visible box, and the trolley orange
   carrying every action and every icon. Blue is the logo's other colour and is
   used sparingly — a rule, a hover, the reviews link — so the orange stays the
   only thing that means "do this".

   Mobile-first: base styles are the narrow viewport and every media query is
   min-width. There is no max-width query in this file and there should never
   be one.

   Bump ASSET_VERSION in includes/site.php after editing this file — assets are
   cached for a year.
   =========================================================================== */

/* ---------------------------------------------------------------------------
   Tokens
   --------------------------------------------------------------------------- */

:root {
    /* Ground. --paper-deep is pure black, reserved for the header and footer
       bands where the logo JPEGs sit; anything else there would show as a
       rectangle around the mark. */
    --paper:       #0b0c0e;
    --paper-alt:   #101216;
    --paper-card:  #15181d;
    --paper-deep:  #000000;

    --ink:         #f3f5f8;
    --ink-soft:    #a7aeb9;
    --ink-dim:     #7c8492;

    --rule:        #24282f;
    --rule-soft:   #1a1d23;

    /* The trolley orange, read off the logo. Every button, link and icon. */
    --accent:      #f0582a;
    --accent-hot:  #ff6b3d;
    --accent-dim:  rgba(240, 88, 42, 0.14);
    --accent-ink:  #0b0c0e;   /* text ON orange — black, not white: white on
                                 this orange is only 3.4:1 and fails AA */

    /* The logo's blue and box gold. Supporting roles only. */
    --blue:        #2e9be0;
    --gold:        #f0a020;

    --ok:          #7fe0a8;
    --ok-bg:       #10241a;
    --error:       #ff9d93;
    --error-bg:    #2a1417;

    /* Type. Both are system stacks — the CSP forbids external origins, so
       there are no webfont links, and these match admin.css deliberately. */
    --font-display: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    --font-body:    system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

    /* Spacing — a 4px-based scale. */
    --s1: 0.25rem;
    --s2: 0.5rem;
    --s3: 1rem;
    --s4: 1.5rem;
    --s5: 2rem;
    --s6: 3rem;
    --s7: 4.5rem;

    --measure: 36rem;
    --gutter:  1.25rem;
    --max:     72rem;

    --radius:    10px;
    --radius-sm: 6px;

    /* Height of the sticky header, so in-page anchors clear it. Must stay at or
       above the tallest the header actually gets: the logo plus its padding. */
    --header-h: 5rem;
}

/* ---------------------------------------------------------------------------
   Reset and base
   --------------------------------------------------------------------------- */

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

html {
    -webkit-text-size-adjust: 100%;
    scroll-behavior: smooth;
    background: var(--paper);
}

body {
    margin: 0;
    background: var(--paper);
    color: var(--ink);
    font-family: var(--font-body);
    font-size: 1rem;
    line-height: 1.65;
    -webkit-font-smoothing: antialiased;
}

img, svg, video { max-width: 100%; height: auto; display: block; }

h1, h2, h3, h4 {
    font-family: var(--font-display);
    line-height: 1.12;
    margin: 0 0 var(--s3);
    font-weight: 800;
    letter-spacing: -0.021em;
}

h1 { font-size: clamp(2rem, 7vw, 3.4rem); }
h2 { font-size: clamp(1.55rem, 4.6vw, 2.3rem); }
h3 { font-size: 1.125rem; letter-spacing: -0.012em; }

p, ul, ol, dl { margin: 0 0 var(--s3); }

a { color: var(--accent); text-underline-offset: 0.18em; }
a:hover { color: var(--accent-hot); }

strong { font-weight: 700; color: var(--ink); }

code {
    font-size: 0.9em;
    background: var(--paper-card);
    border: 1px solid var(--rule);
    border-radius: var(--radius-sm);
    padding: 0.1em 0.35em;
}

::selection { background: var(--accent); color: var(--accent-ink); }

/* Visible focus, always. Never remove this without replacing it. */
:focus-visible {
    outline: 2px solid var(--accent-hot);
    outline-offset: 3px;
    border-radius: 2px;
}

/* Respect a reduced-motion preference across the whole site. */
@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;
    }
}

/* ---------------------------------------------------------------------------
   Layout helpers
   --------------------------------------------------------------------------- */

.measure { max-width: var(--measure); }

.band { padding-block: var(--s6); }
.band--lift { background: var(--paper-alt); border-block: 1px solid var(--rule-soft); }

.band__inner,
.site-header__inner,
.site-footer__inner,
.page-head__inner,
.prose {
    max-width: var(--max);
    margin-inline: auto;
    padding-inline: var(--gutter);
}

.prose {
    max-width: calc(var(--measure) + var(--gutter) * 2);
    padding-block: var(--s5) var(--s6);
}
.prose h2 { font-size: 1.35rem; margin-top: var(--s6); }
.prose h2:first-of-type { margin-top: var(--s5); }
.prose li { margin-bottom: var(--s2); }
.prose p, .prose li { color: var(--ink-soft); }

.eyebrow {
    font-family: var(--font-display);
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--accent);
    margin-bottom: var(--s2);
}

/* Anchor targets have to clear the sticky header, or a jump to #services
   leaves the heading hidden underneath it. */
[id] { scroll-margin-top: calc(var(--header-h) + var(--s3)); }

/* ---------------------------------------------------------------------------
   Icons — one rule paints every one of them.
   --------------------------------------------------------------------------- */

.icon {
    width: 1.5rem;
    height: 1.5rem;
    flex: none;
    color: var(--accent);
    display: block;
}
.icon--lg { width: 2rem; height: 2rem; }
.icon--sm { width: 1.125rem; height: 1.125rem; }

/* ---------------------------------------------------------------------------
   Buttons
   --------------------------------------------------------------------------- */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--s2);
    min-height: 48px;
    padding: var(--s2) var(--s5);
    border: 2px solid var(--accent);
    border-radius: var(--radius-sm);
    background: var(--accent);
    color: var(--accent-ink);
    font-family: var(--font-display);
    font-size: 1rem;
    font-weight: 700;
    line-height: 1.2;
    text-decoration: none;
    cursor: pointer;
    transition: background-color 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}
.btn:hover {
    background: var(--accent-hot);
    border-color: var(--accent-hot);
    color: var(--accent-ink);
    transform: translateY(-1px);
}
.btn .icon { color: currentColor; }

.btn--ghost {
    background: transparent;
    border-color: var(--rule);
    color: var(--ink);
}
.btn--ghost:hover {
    background: transparent;
    border-color: var(--ink-soft);
    color: var(--ink);
}

.btn--lg {
    min-height: 56px;
    padding-inline: var(--s5);
    font-size: 1.0625rem;
}

/* A row of calls to action that stacks on a phone, where a full-width tap
   target is easier to hit than two half-width ones. */
.cta-row { display: grid; gap: var(--s2); margin: 0; }

@media (min-width: 30em) {
    .cta-row { display: flex; flex-wrap: wrap; gap: var(--s3); }
}

/* ---------------------------------------------------------------------------
   Skip link — visible only once focused.
   --------------------------------------------------------------------------- */

.skip-link {
    position: absolute;
    left: -9999px;
    top: 0;
    z-index: 200;
    background: var(--accent);
    color: var(--accent-ink);
    font-weight: 700;
    padding: var(--s2) var(--s3);
    text-decoration: none;
}
.skip-link:focus { left: 0; }

/* ---------------------------------------------------------------------------
   Header and navigation

   Mobile first: the nav is a stacked drawer revealed by the toggle. nav.js sets
   aria-expanded on the button and toggles .is-open on the nav. With JavaScript
   off the nav is simply always visible — correct, and why the closed state is
   scoped to .js below.

   The band is pure black because the logo JPEG is; anything lighter would draw
   a rectangle around the mark.
   --------------------------------------------------------------------------- */

.site-header {
    position: sticky;
    top: 0;
    z-index: 100;
    background: var(--paper-deep);
    border-bottom: 1px solid var(--rule);
}

.site-header__inner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--s3);
    padding-block: var(--s2);
    min-height: var(--header-h);
}

.site-header__brand {
    display: inline-flex;
    align-items: center;
    text-decoration: none;
    border-radius: var(--radius-sm);
}
/* Taller than a monogram would need. This lockup carries the word "Launceston"
   under the wordmark, and below about 3rem that line stops being readable —
   which would waste the one part of the logo doing SEO work in the header. */
.site-header__brand img {
    height: 3.25rem;
    width: auto;
    max-width: none;
}

.site-header__wordmark {
    font-family: var(--font-display);
    font-size: 1.2rem;
    font-weight: 800;
    color: var(--ink);
}

.nav-toggle {
    display: inline-flex;
    align-items: center;
    gap: var(--s2);
    min-height: 44px;
    padding: var(--s2) var(--s3);
    background: transparent;
    border: 1px solid var(--rule);
    border-radius: var(--radius-sm);
    color: var(--ink);
    font-family: var(--font-display);
    font-size: 0.9375rem;
    font-weight: 600;
    cursor: pointer;
}
.nav-toggle:hover { border-color: var(--accent); color: var(--accent); }

.nav-toggle__bars {
    width: 1.125rem;
    height: 2px;
    background: currentColor;
    box-shadow: 0 -6px 0 currentColor, 0 6px 0 currentColor;
}

.site-nav { flex-basis: 100%; }

.site-nav__list {
    list-style: none;
    margin: 0;
    padding: 0;
    border-top: 1px solid var(--rule-soft);
}

.site-nav__list a {
    display: flex;
    align-items: center;
    min-height: 48px;
    padding: var(--s2) 0;
    color: var(--ink);
    font-family: var(--font-display);
    font-weight: 600;
    text-decoration: none;
    border-bottom: 1px solid var(--rule-soft);
}
.site-nav__list a:hover { color: var(--accent); }
.site-nav__list a[aria-current="page"] { color: var(--accent); }

/* The phone number is the primary call to action, so in the nav it is a button
   rather than a link — on a phone it is the fastest path to a quote. */
.site-nav__aside { margin: var(--s3) 0 var(--s2); }
.site-nav__aside a {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--s2);
    min-height: 48px;
    padding: var(--s2) var(--s4);
    border-radius: var(--radius-sm);
    background: var(--accent);
    color: var(--accent-ink);
    font-family: var(--font-display);
    font-weight: 700;
    text-decoration: none;
}
.site-nav__aside a:hover { background: var(--accent-hot); color: var(--accent-ink); }

/* Collapsed state applies only when nav.js has run — it adds .js to <html> and
   toggles .is-open on the nav. Without JavaScript neither appears, the rules
   below never match, and the nav stays a plain visible list. That is the
   fallback, not a bug.

   THE 62rem BREAKPOINT BELOW MUST MATCH the matchMedia query in
   assets/js/nav.js. If you move one, move the other. */
.js .site-nav { display: none; }
.js .site-nav.is-open { display: block; }

@media (min-width: 62rem) {
    .nav-toggle { display: none; }

    .site-header__brand img { height: 3.5rem; }

    .site-nav,
    .js .site-nav,
    .js .site-nav.is-open {
        display: flex;
        align-items: center;
        gap: var(--s4);
        flex-basis: auto;
    }

    .site-nav__list { display: flex; gap: var(--s4); border-top: 0; }
    .site-nav__list a {
        padding: 0;
        min-height: 0;
        border-bottom: 0;
        font-size: 0.9375rem;
    }

    .site-nav__aside { margin: 0; }
    .site-nav__aside a { min-height: 44px; padding-inline: var(--s4); }
}

/* ---------------------------------------------------------------------------
   Hero

   A silent, looping film behind a scrim. The loop is the markup's own, so the
   hero moves with JavaScript off; assets/js/hero.js only stands the film down
   for a visitor who asked for less motion, and the rule below hides it for the
   same reason so nothing is left half-playing.
   --------------------------------------------------------------------------- */

.hero {
    position: relative;
    isolation: isolate;
    display: flex;
    align-items: flex-end;
    min-height: 34rem;
    /* Restrained on a phone on purpose: the top padding has to stay small
       enough that the "Ring for a free quote" button is still above the fold on
       a 667px screen. It opens up from 48em, where there is room. */
    padding-block: var(--s6) var(--s5);
    background: var(--paper-deep);
    overflow: hidden;
}

.hero__media {
    position: absolute;
    inset: 0;
    z-index: -2;
    background: #08090b;
}

.hero__film {
    width: 100%;
    height: 100%;
    max-width: none;
    object-fit: cover;
    opacity: 0.62;
}

/* Two scrims, not one: a vertical wash so the text end of the frame is dark
   enough for AA contrast, and a slight wash from the left so the copy holds up
   over a bright patch of road. */
.hero__scrim {
    position: absolute;
    inset: 0;
    z-index: -1;
    background:
        linear-gradient(to top, rgba(6, 7, 9, 0.96) 0%, rgba(6, 7, 9, 0.72) 38%, rgba(6, 7, 9, 0.35) 70%, rgba(6, 7, 9, 0.55) 100%),
        linear-gradient(to right, rgba(6, 7, 9, 0.72) 0%, rgba(6, 7, 9, 0.2) 60%, rgba(6, 7, 9, 0) 100%);
}

.hero__inner {
    position: relative;
    width: 100%;
    max-width: var(--max);
    margin-inline: auto;
    padding-inline: var(--gutter);
}

.hero__title { margin-bottom: var(--s3); max-width: 16ch; }
.hero__title em {
    font-style: normal;
    color: var(--accent);
}

.hero__lede {
    max-width: 42ch;
    margin-bottom: var(--s4);
    font-size: 1.0625rem;
    color: var(--ink-soft);
}

.hero__actions { margin-bottom: var(--s4); }

.hero__note {
    margin: 0;
    font-size: 0.875rem;
    color: var(--ink-dim);
}

/* The three things that separate this business from a big removalist, stated
   before a visitor has scrolled at all. */
.hero__trust {
    list-style: none;
    margin: var(--s5) 0 0;
    padding: var(--s4) 0 0;
    border-top: 1px solid rgba(255, 255, 255, 0.12);
    display: grid;
    gap: var(--s2);
}
.hero__trust li {
    display: flex;
    align-items: center;
    gap: var(--s2);
    margin: 0;
    font-family: var(--font-display);
    font-size: 0.9375rem;
    font-weight: 600;
    color: var(--ink);
}

@media (min-width: 48em) {
    .hero { min-height: 42rem; padding-block: var(--s7) var(--s6); }
    .hero__lede { font-size: 1.1875rem; }
    .hero__trust { grid-template-columns: repeat(3, 1fr); gap: var(--s4); }
}

@media (min-width: 62em) {
    .hero { min-height: 46rem; }
}

/* A visitor who has asked for less motion gets the still, dark ground and no
   film at all. hero.js pauses it as well so it is not fetched and decoded. */
@media (prefers-reduced-motion: reduce) {
    .hero__film { display: none; }
    .hero__media {
        background:
            radial-gradient(80% 60% at 70% 10%, rgba(240, 88, 42, 0.16), transparent 70%),
            #08090b;
    }
}

/* ---------------------------------------------------------------------------
   Section headings
   --------------------------------------------------------------------------- */

.section-head { max-width: 46rem; margin-bottom: var(--s5); }
.section-head h2 { margin-bottom: var(--s3); }
.section-head p {
    margin: 0;
    color: var(--ink-soft);
    font-size: 1.0625rem;
    max-width: 52ch;
}

/* ---------------------------------------------------------------------------
   Services grid
   --------------------------------------------------------------------------- */

.services {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: var(--s3);
}

.service {
    padding: var(--s4);
    margin: 0;
    background: var(--paper-card);
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    transition: border-color 0.15s ease, transform 0.15s ease;
}
.service:hover { border-color: var(--accent); transform: translateY(-2px); }

.service__icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 3rem;
    height: 3rem;
    margin-bottom: var(--s3);
    border-radius: var(--radius-sm);
    background: var(--accent-dim);
}

.service__title {
    margin-bottom: var(--s2);
    font-size: 1.0625rem;
    font-weight: 700;
    color: var(--ink);
}

.service__text {
    margin: 0;
    font-size: 0.9375rem;
    color: var(--ink-soft);
}

@media (min-width: 34em) { .services { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 56em) { .services { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 76em) { .services { grid-template-columns: repeat(4, 1fr); } }

/* ---------------------------------------------------------------------------
   Reasons — the "why us" list
   --------------------------------------------------------------------------- */

.reasons {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: var(--s5);
}

.reason { margin: 0; }
.reason .icon { margin-bottom: var(--s3); }
.reason h3 { margin-bottom: var(--s2); }
.reason p { margin: 0; color: var(--ink-soft); }

@media (min-width: 40em) { .reasons { grid-template-columns: repeat(2, 1fr); gap: var(--s5) var(--s6); } }
@media (min-width: 68em) { .reasons { grid-template-columns: repeat(4, 1fr); } }

/* ---------------------------------------------------------------------------
   Steps — how a job actually goes
   --------------------------------------------------------------------------- */

.steps {
    list-style: none;
    margin: 0;
    padding: 0;
    counter-reset: step;
    display: grid;
    gap: var(--s4);
}

.step {
    position: relative;
    margin: 0;
    padding: var(--s4);
    background: var(--paper);
    border: 1px solid var(--rule);
    border-radius: var(--radius);
}
.step::before {
    counter-increment: step;
    content: counter(step);
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    margin-bottom: var(--s3);
    border-radius: 50%;
    background: var(--accent);
    color: var(--accent-ink);
    font-family: var(--font-display);
    font-weight: 800;
}
.step h3 { margin-bottom: var(--s2); }
.step p { margin: 0; color: var(--ink-soft); font-size: 0.9375rem; }

@media (min-width: 44em) { .steps { grid-template-columns: repeat(3, 1fr); } }

/* ---------------------------------------------------------------------------
   Areas served
   --------------------------------------------------------------------------- */

/* Photo beside the places. Stacked on a phone with the photo first — a face and
   a signwritten truck do more for a stranger deciding whether to ring than a
   list of town names does. Side by side from 60em, where both fit. */
.areas { display: grid; gap: var(--s5); }

@media (min-width: 60em) {
    .areas {
        grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr);
        gap: var(--s6);
        align-items: start;
    }
}

.owner { margin: 0; }

.owner img {
    width: 100%;
    height: auto;
    border-radius: var(--radius);
    border: 1px solid var(--rule);
}

/* An orange rule rather than an icon: the caption is a name, and an icon beside
   it would be the third decorative orange thing in this band. */
.owner__caption {
    margin-top: var(--s3);
    padding-left: var(--s3);
    border-left: 2px solid var(--accent);
}

.owner__name {
    display: block;
    font-family: var(--font-display);
    font-size: 1.0625rem;
    font-weight: 700;
    color: var(--ink);
}

.owner__role {
    display: block;
    font-size: 0.875rem;
    color: var(--ink-soft);
}

.areas__list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: var(--s2);
}
.areas__list li {
    margin: 0;
    padding: 0.35rem 0.75rem;
    border: 1px solid var(--rule);
    border-radius: 999px;
    background: var(--paper-card);
    font-size: 0.875rem;
    color: var(--ink-soft);
}

.areas__note {
    margin: var(--s4) 0 0;
    padding-left: var(--s3);
    border-left: 3px solid var(--blue);
    color: var(--ink-soft);
}

/* ---------------------------------------------------------------------------
   Reviews

   Deliberately NO star rating and no pulled quotes. We have not read the
   reviews and cannot verify a score, and a row of five gold stars is a claim
   whether or not it is labelled as one. The link goes to the real page and
   lets people read the real thing.
   --------------------------------------------------------------------------- */

.reviews {
    display: grid;
    gap: var(--s4);
    align-items: center;
}
.reviews .section-head { margin-bottom: 0; }

@media (min-width: 48em) {
    .reviews { grid-template-columns: 1fr auto; gap: var(--s6); }
}

/* ---------------------------------------------------------------------------
   FAQs

   The visible half of the FAQPage node index.php passes to schema.php. Both are
   built from one array — if these ever stop matching, the structured data is
   the thing that is wrong.
   --------------------------------------------------------------------------- */

.faqs {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: var(--s5);
}

/* The accent is a border rather than a generated character. A ::before glyph
   would be announced by most screen readers, prefixing every question with a
   stray "question mark" — decoration is the one thing that must not speak. */
.faq {
    margin: 0;
    max-width: 52ch;
    padding-left: var(--s3);
    border-left: 2px solid var(--accent);
}
.faq h3 { margin-bottom: var(--s2); font-size: 1.0625rem; }
.faq p { margin: 0; color: var(--ink-soft); }

@media (min-width: 48em) { .faqs { grid-template-columns: repeat(2, 1fr); gap: var(--s5) var(--s6); } }

/* ---------------------------------------------------------------------------
   Call-to-action band — the loudest thing on the page, on purpose.
   --------------------------------------------------------------------------- */

.cta-band {
    background: var(--accent);
    color: var(--accent-ink);
    padding-block: var(--s6);
}
.cta-band h2 { color: var(--accent-ink); margin-bottom: var(--s2); }
.cta-band p { color: rgba(11, 12, 14, 0.82); max-width: 46ch; }
.cta-band .eyebrow { color: rgba(11, 12, 14, 0.68); }

.cta-band__phone {
    display: inline-flex;
    align-items: center;
    gap: var(--s3);
    margin: var(--s4) 0 0;
    padding: var(--s3) var(--s5);
    min-height: 56px;
    border-radius: var(--radius-sm);
    background: var(--paper-deep);
    color: #ffffff;
    font-family: var(--font-display);
    font-size: clamp(1.375rem, 5vw, 1.875rem);
    font-weight: 800;
    letter-spacing: -0.02em;
    text-decoration: none;
}
.cta-band__phone:hover { background: #15181d; color: #ffffff; }
.cta-band__phone .icon { color: var(--accent); width: 1.75rem; height: 1.75rem; }

/* ---------------------------------------------------------------------------
   Contact
   --------------------------------------------------------------------------- */

.contact-grid { display: grid; gap: var(--s6); }

@media (min-width: 60em) {
    .contact-grid { grid-template-columns: 1fr 1.15fr; gap: var(--s7); }
}

.contact-list { list-style: none; margin: var(--s4) 0 0; padding: 0; }
.contact-list li {
    display: flex;
    align-items: flex-start;
    gap: var(--s3);
    margin: 0 0 var(--s4);
}
.contact-list .eyebrow { margin-bottom: 0.15rem; color: var(--ink-dim); }
.contact-list a {
    font-family: var(--font-display);
    font-size: 1.0625rem;
    font-weight: 700;
    text-decoration: none;
    overflow-wrap: anywhere;
}
.contact-list a:hover { text-decoration: underline; }
.contact-list p { margin: 0; color: var(--ink-soft); font-size: 0.9375rem; }

/* ---------------------------------------------------------------------------
   Detail list — used by the privacy page and anywhere facts are paired.
   --------------------------------------------------------------------------- */

.detail-list { display: grid; grid-template-columns: 1fr; gap: 0; }
.detail-list dt {
    font-family: var(--font-display);
    font-weight: 700;
    color: var(--ink);
    margin-top: var(--s3);
}
.detail-list dd { margin: 0; color: var(--ink-soft); }

/* ---------------------------------------------------------------------------
   Page head — used by /privacy and /404, not by the home page.
   --------------------------------------------------------------------------- */

.page-head {
    padding-block: var(--s6) var(--s4);
    border-bottom: 1px solid var(--rule-soft);
    background: var(--paper-alt);
}
.page-head__lede {
    max-width: var(--measure);
    color: var(--ink-soft);
    margin-bottom: 0;
    font-size: 1.0625rem;
}

/* ---------------------------------------------------------------------------
   Quicklinks — the 404 page's way back.
   --------------------------------------------------------------------------- */

.quicklinks {
    list-style: none;
    margin: var(--s5) auto;
    padding-inline: var(--gutter);
    max-width: var(--max);
    display: grid;
    gap: var(--s2);
}

.quicklinks__link {
    display: flex;
    align-items: center;
    min-height: 48px;
    padding: var(--s3);
    background: var(--paper-card);
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    color: var(--ink);
    font-family: var(--font-display);
    font-weight: 600;
    text-decoration: none;
}
.quicklinks__link:hover { border-color: var(--accent); color: var(--accent); }

@media (min-width: 40em) {
    .quicklinks { grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); }
}

/* ---------------------------------------------------------------------------
   Forms

   Inputs are 16px minimum so iOS does not zoom the page on focus. Touch
   targets are 44px minimum. Both are requirements, not preferences.
   --------------------------------------------------------------------------- */

/* HONEYPOT — LOAD-BEARING. DO NOT DELETE THIS RULE.
 *
 * spam_trap_fields() in includes/security.php emits a decoy field wrapped in
 * .hp. Bots fill it in; people never see it. If this rule goes missing the
 * field becomes visible, and a visitor who dutifully completes every field is
 * treated as a bot — spam_trap_reason() returns 'honeypot', the page reports
 * success to them, and the enquiry is discarded without ever being sent. The
 * failure is silent on both sides, which is what makes it dangerous.
 *
 * Off-screen rather than display:none, which some bots detect and skip. Must
 * be a class, never an inline style — the CSP forbids those. */
.hp {
    position: absolute;
    left: -9999px;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

.form-card {
    padding: var(--s4);
    background: var(--paper-card);
    border: 1px solid var(--rule);
    border-radius: var(--radius);
}

@media (min-width: 40em) { .form-card { padding: var(--s5); } }

label {
    display: block;
    margin-bottom: var(--s1);
    font-family: var(--font-display);
    font-size: 0.9375rem;
    font-weight: 600;
    color: var(--ink);
}
label .hint { font-weight: 400; }
label [aria-hidden="true"] { color: var(--accent); }

input[type="text"],
input[type="email"],
input[type="tel"],
input[type="password"],
textarea {
    width: 100%;
    min-height: 48px;
    padding: var(--s2) var(--s3);
    margin-bottom: var(--s3);
    border: 1px solid var(--rule);
    border-radius: var(--radius-sm);
    background: var(--paper);
    color: var(--ink);
    font: inherit;
    font-size: 1rem;
}
input::placeholder, textarea::placeholder { color: var(--ink-dim); }
input:focus, textarea:focus { border-color: var(--accent); }

textarea { min-height: 9rem; resize: vertical; }

.hint, .privacy { font-size: 0.875rem; color: var(--ink-dim); }
.privacy { margin: var(--s3) 0 0; }

.notice {
    padding: var(--s3);
    margin-bottom: var(--s4);
    border-left: 3px solid;
    border-radius: var(--radius-sm);
}
.notice--ok    { border-color: var(--ok);    background: var(--ok-bg);    color: var(--ok); }
.notice--error { border-color: var(--error); background: var(--error-bg); color: var(--error); }
.notice ul { margin: 0; padding-left: var(--s4); }
.notice p:last-child { margin-bottom: 0; }

/* ---------------------------------------------------------------------------
   Footer

   Pure black, like the header, so the secondary lockup sits on its own ground.
   --------------------------------------------------------------------------- */

.site-footer {
    background: var(--paper-deep);
    border-top: 1px solid var(--rule);
    padding-block: var(--s6) var(--s4);
    margin-top: 0;
}

.site-footer__inner { display: grid; gap: var(--s5); }

.site-footer__brand { margin: 0 0 var(--s2); }
.site-footer__brand img {
    width: 15rem;
    max-width: 100%;
    height: auto;
}
.site-footer__tagline {
    margin: var(--s3) 0 0;
    max-width: 34ch;
    color: var(--ink-soft);
    font-size: 0.9375rem;
}

.site-footer__block h2 { font-size: 0.75rem; }
.site-footer__block address { font-style: normal; color: var(--ink-soft); }
.site-footer__block p { color: var(--ink-soft); }
.site-footer__block a { text-decoration: none; }
.site-footer__block a:hover { text-decoration: underline; }

.site-footer__list { list-style: none; margin: 0; padding: 0; }
.site-footer__list a,
.site-footer__social a { display: inline-flex; align-items: center; gap: var(--s2); padding-block: var(--s1); }
.site-footer__social a + a { margin-left: var(--s3); }

.site-footer__legal {
    max-width: var(--max);
    margin: var(--s5) auto 0;
    padding: var(--s4) var(--gutter) 0;
    border-top: 1px solid var(--rule-soft);
    font-size: 0.8125rem;
    color: var(--ink-dim);
}
.site-footer__legal a { color: var(--ink-soft); text-decoration: none; }
.site-footer__legal a:hover { color: var(--accent); text-decoration: underline; }

/* The closing three, in descending loudness: what the business owes the public,
   who built it, and the staff door. All three share the legal line's gutters so
   their left edges align down the page.

   Ranked deliberately — see the note in the platform's footer.php. If a future
   edit leaves them the same size and colour, the staff link reads as a public
   feature, which is exactly what this structure exists to prevent. */

/* ONE RHYTHM FOR ALL THREE: var(--s3) of visible space between each line.
   Read the note on .site-footer__staff before changing any of these margins —
   the third one is not the same number as the other two, and that is the point,
   not an oversight. */

/* Studio credit — a signature, not another notice. */
.site-footer__credit {
    max-width: var(--max);
    margin: var(--s3) auto 0;
    padding-inline: var(--gutter);
    font-size: 0.8125rem;
    color: var(--ink-dim);
}
.site-footer__credit a { color: var(--ink-soft); text-decoration: none; }
.site-footer__credit a:hover { color: var(--accent); text-decoration: underline; }

/* Staff login — the quietest thing on the page. Alone on its own line, at the
   smallest size and dimmest ink on the site.

   Left-aligned, sharing the gutter with the two lines above it, so all three
   run down one edge. The ranking is done entirely by size and colour: that is
   the part that has to hold, and it survives a redesign in a way that pushing
   the link to the far edge does not.

   It is still a full 44px touch target: discreet is not the same as hard to
   tap, and the people using it are doing their job on a phone. The focus ring
   is untouched, so it is perfectly reachable by keyboard.

   ── WHY ITS MARGIN IS --s1 AND NOT --s3 LIKE THE LINE ABOVE ──────────────────

   The 44px target is taller than the 12px text inside it, and the link centres
   that text, so roughly 12px of the target already reads as blank space above
   the word: (44 - 12 x 1.65 line-height) / 2 = 12.1px.

   Give this line the same --s3 (16px) margin as the credit above it and the gap
   measures 16px but LOOKS like 28px, which is the imbalance this replaced. So
   the margin is --s1 (4px), and 4 + 12.1 lands at the same optical 16px as the
   other two gaps.

   The target is built from min-height and centring rather than padding-block on
   purpose. Padding would work too, but only with a negative margin to claw the
   space back — and that would float this link's invisible hit area up over the
   "Innovators Creative" link above it, quietly stealing its clicks. */
.site-footer__staff {
    max-width: var(--max);
    margin: var(--s1) auto 0;
    padding-inline: var(--gutter);
    font-size: 0.75rem;
}
.site-footer__staff a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    color: var(--ink-dim);
    text-decoration: none;
}
.site-footer__staff a:hover { color: var(--ink-soft); text-decoration: underline; }

@media (min-width: 44em) {
    .site-footer__inner { grid-template-columns: repeat(2, 1fr); gap: var(--s5) var(--s6); }
    .site-footer__brand { grid-column: 1 / -1; }
}

@media (min-width: 68em) {
    .site-footer__inner { grid-template-columns: 1.4fr 1fr 1fr 1fr; align-items: start; }
    .site-footer__brand { grid-column: auto; grid-row: span 1; }
}
