/* ─── RESET ──────────────────────────────────────────────── */
    *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
    img { display: block; max-width: 100%; }
    a { color: inherit; text-decoration: none; }
    a:focus-visible, button:focus-visible, [tabindex="0"]:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

    /* ─── TOKENS ─────────────────────────────────────────────── */
    :root {
      --bg:       #ECEAE4;
      --ink:      #1A1916;
      --muted:    #6B675F; /* darkened from #7A766F for WCAG AA contrast on the cream bg */
      --accent:   #3D4A35;
      --white:    #FFFFFF;
      --f-head:   'Lora', Georgia, serif;
      --f-body:   'DM Sans', sans-serif;
      --sp-xs:    16px;
      --sp-sm:    24px;
      --sp-md:    48px;
      --sp-lg:    80px;
      --sp-xl:    120px;
      --gutter:   24px;
      --max:      960px;
      --side-w:   20px;
      /* Small deliberate gap between the rail and full-bleed photos'
         true edge — previously photos ran truly edge-to-edge (0px gap),
         so the rail sat flush on top of them with no breathing room at
         all. Mobile only; desktop's 88px gutter already has plenty of
         natural space. */
      --photo-edge-gap: 0px;
      /* Mobile gutter was 72px — on a 390px phone that plus .wrap's own
         padding left only ~206px (53%) for text, forcing headlines into
         ten cramped lines. Narrowed so text runs wider; the side labels
         now float over the edge of the text zone instead of owning a
         dedicated column, and rail-visibility.js fades them when text
         is actually underneath (see body.rails-over-text). */
    }
    @media (max-width: 639px)  { :root { --photo-edge-gap: 0px; } }
    @media (min-width: 640px)  { :root { --side-w: 80px; } }
    @media (min-width: 1024px) { :root { --side-w: 88px; } }

    html {
      scroll-behavior: smooth;
      /* Opt out of automatic mobile text inflation. Without this, iOS
         Safari (and some Android browsers) boost font sizes when the
         phone rotates to landscape — unevenly, favoring large text
         blocks with short lines, i.e. exactly the nav drawer's links —
         and the inflated sizes stick or misapply when rotating back to
         portrait. This is the documented, standard fix for that bug. */
      -webkit-text-size-adjust: 100%;
      text-size-adjust: 100%;
    }
    /* Guard against transient horizontal overflow (e.g. the ph-img scale(1.02)
       entrance inside any container that forgets overflow:hidden). Vertical
       scrolling is unaffected. */
    html, body { overflow-x: clip; }

    body {
      background: var(--bg);
      color: var(--ink);
      font-family: var(--f-body);
      font-weight: 300;
      font-size: 16px;
      line-height: 1.75;
      -webkit-font-smoothing: antialiased;
      padding-left: var(--side-w);
      padding-right: var(--side-w);
    }
    body.menu-open { overflow: hidden; }

    .wrap {
      width: 100%;
      padding-left: 42px;
      padding-right: 42px;
    }
    @media (min-width: 640px) { .wrap { padding-left: 32px; padding-right: 32px; } }
    @media (min-width: 1024px) {
      .wrap {
        max-width: var(--max);
        margin-left: auto;
        margin-right: auto;
        padding-left: 0;
        padding-right: 0;
      }
    }

    /* ─── TYPOGRAPHY HELPERS ─────────────────────────────────── */
    .heading {
      font-family: var(--f-head);
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: 0.04em;
      line-height: 1.15;
    }
    /* Section heading on subpages — one size for one job. Craft, Owners, and
       Architects previously carried this inline at clamp(22px,3vw,36px) while
       Story's sections used 26/42 from a class; consolidated at Story's scale
       so every subpage section heading matches. */
    .section-heading { font-size: clamp(26px, 3.5vw, 42px); max-width: 640px; }

    .eyebrow {
      font-family: var(--f-body);
      font-size: 11px;
      font-weight: 400;
      text-transform: uppercase;
      letter-spacing: 0.14em;
      color: var(--muted);
    }

    .text-link {
      font-family: var(--f-body);
      font-size: 13px;
      font-weight: 500;
      text-transform: uppercase;
      letter-spacing: 0.1em;
      color: var(--ink);
      transition: color 0.2s;
      cursor: pointer;
    }
    /* Literal hex, not var(--ink): browsers silently refuse to resolve
       CSS custom properties inside :visited rules (a privacy guard against
       using timing/rendering to sniff browsing history), so a var() here
       would just never apply — confirmed live, caught 2026-09-24. */
    .text-link:visited { color: #1A1916; }
    .text-link:hover { color: var(--accent); }

    .btn-solid {
      display: inline-block;
      font-family: var(--f-body);
      font-size: 12px;
      font-weight: 500;
      text-transform: uppercase;
      letter-spacing: 0.14em;
      padding: 14px 32px;
      background: var(--ink);
      color: var(--white);
      border: 1px solid var(--ink);
      cursor: pointer;
      transition: background 0.2s, color 0.2s;
    }
    .btn-solid:hover { background: var(--accent); border-color: var(--accent); }
    .btn-solid { align-self: flex-start; }
    .btn-solid:active { transform: translateY(1px); }

    /* ─── FADE-IN ─────────────────────────────────────────────── */
    .js .fade-in {
      opacity: 0;
      transform: translateY(14px);
      transition: opacity 1.2s cubic-bezier(0.22, 1, 0.36, 1),
                  transform 1.2s cubic-bezier(0.22, 1, 0.36, 1);
    }
    .fade-in.visible { opacity: 1; transform: translateY(0); }

    /* ─── SIDE LABELS ─────────────────────────────────────────── */
    .side-label {
      position: fixed;
      top: 50%;
      z-index: 200;
      font-family: var(--f-body);
      font-size: 13px;
      font-weight: 500;
      text-transform: uppercase;
      letter-spacing: 0.16em;
      color: var(--white);
      writing-mode: vertical-rl;
      text-decoration: none;
      opacity: 0.85;
      transition: color 0.4s ease, opacity 0.2s ease;
      width: var(--side-w);
      text-align: center;
      padding: 0 8px;
      cursor: pointer;
    }
    .side-label:hover { opacity: 1; }
    /* Toggled by assets/rail-visibility.js. Two independent signals on
       mobile now, mirroring the reference behavior:
         body.rails-hidden    -> a photo is under the label: go WHITE and
                                 stay visible (previously hid entirely).
         body.rails-over-text -> text is under the label: fade out so the
                                 wider mobile text and the label never
                                 visibly collide.
       Photo wins over text if both are true, since white-on-photo is
       legible and a fade there would just look like a glitch. */
    @media (max-width: 639px) {
      /* No fade over text on mobile. The 20px gutter plus .wrap's 20px
         padding gives the label a 5px clearance from the text column, so
         there's nothing to hide from — the rails stay fully visible over
         copy, which is the whole point of having them. (rail-visibility.js
         still sets body.rails-over-text; it's just not styled, kept in
         case a subtle dim is ever wanted later.) */
      body.rails-hidden .side-label { opacity: 0.85; pointer-events: auto; color: var(--white); }
      body.rails-hidden .side-label.is-dark { color: var(--white); }
    }
    .side-label--left  { left: 15px;  transform: translateY(-50%) rotate(180deg); }
    .side-label--right { right: 15px; transform: translateY(-50%); }
    @media (min-width: 640px)  { .side-label--left { left: 20px; } .side-label--right { right: 20px; } }
    @media (min-width: 1024px) { .side-label--left { left: 24px; } .side-label--right { right: 24px; } }
    .side-label.is-dark { color: var(--ink); }
    /* Desktop/tablet: the same "a photo is centered in the viewport"
       signal that hides the rails on mobile (rail-visibility.js,
       body.rails-hidden) instead just switches the label back to white
       here, since project heroes and full-bleed photos already break
       out to the true screen edge on every size — the label was sitting
       on top of them in dark ink the whole time. Higher specificity
       than the plain .side-label.is-dark rule above, so it wins without
       needing !important; reverts automatically once the photo scrolls
       past and .is-dark's normal dark ink takes back over. */
    @media (min-width: 640px) {
      body.rails-hidden .side-label.is-dark { color: var(--white); }
    }
    /* ─── MENU BUTTON ─────────────────────────────────────────── */
    .menu-btn {
      position: fixed; top: 28px; right: 28px; z-index: 500;
      width: 44px; height: 44px;
      display: flex; flex-direction: column; justify-content: center; align-items: center; gap: 6px;
      cursor: pointer; background: none; border: none; padding: 8px;
    }
    .menu-btn__bar {
      display: block; width: 24px; height: 1.5px; background: var(--ink);
      transition: transform 0.4s cubic-bezier(0.76,0,0.24,1), opacity 0.3s ease, background 0.4s ease;
      transform-origin: center;
    }
    .menu-btn.over-hero .menu-btn__bar { background: var(--white); box-shadow: 0 0 4px rgba(0,0,0,0.55); }
    .menu-btn.is-open .menu-btn__bar:nth-child(1) { transform: translateY(7.5px) rotate(45deg); }
    .menu-btn.is-open .menu-btn__bar:nth-child(2) { opacity: 0; transform: scaleX(0); }
    .menu-btn.is-open .menu-btn__bar:nth-child(3) { transform: translateY(-7.5px) rotate(-45deg); }

    /* ─── NAV DRAWER ──────────────────────────────────────────── */
    .nav-drawer {
      position: fixed; inset: 0; z-index: 400;
      display: grid; grid-template-columns: 1fr 1fr; pointer-events: none;
      visibility: hidden; transition: visibility 0s linear 0.55s;
    }
    @media (max-width: 639px) { .nav-drawer { grid-template-columns: 0 1fr; } }
    .nav-drawer__backdrop { background: rgba(26,25,22,0.45); opacity: 0; transition: opacity 0.5s ease; cursor: pointer; }
    .nav-drawer__panel {
      background: var(--bg);
      display: flex; flex-direction: column; justify-content: space-between;
      padding: 48px 52px 48px 48px;
      transform: translateX(100%);
      transition: transform 0.55s cubic-bezier(0.76,0,0.24,1);
      overflow-y: auto;
    }
    .nav-drawer.is-open { pointer-events: all; visibility: visible; transition-delay: 0s; }
    .nav-drawer.is-open .nav-drawer__backdrop { opacity: 1; }
    .nav-drawer.is-open .nav-drawer__panel { transform: translateX(0); }
    .nav-drawer__top { display: flex; flex-direction: column; gap: 0; margin-top: 32px; }
    .nav-link {
      display: flex; align-items: baseline; gap: 16px;
      padding: 22px 0; border-bottom: 1px solid rgba(26,25,22,0.1);
      text-decoration: none; overflow: hidden; cursor: pointer;
    }
    .nav-link:first-child { border-top: 1px solid rgba(26,25,22,0.1); }
    .nav-link__num {
      font-family: var(--f-body); font-size: 10px; font-weight: 400;
      letter-spacing: 0.1em; color: var(--muted); min-width: 20px; transition: color 0.25s;
    }
    .nav-link__label {
      font-family: var(--f-head); font-size: clamp(22px, 3.5vw, 32px);
      font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
      color: var(--ink); line-height: 1;
      transform: translateY(110%); transition: transform 0.55s cubic-bezier(0.76,0,0.24,1);
    }
    .nav-link:nth-child(1) .nav-link__label { transition-delay: 0.08s; }
    .nav-link:nth-child(2) .nav-link__label { transition-delay: 0.14s; }
    .nav-link:nth-child(3) .nav-link__label { transition-delay: 0.20s; }
    .nav-link:nth-child(4) .nav-link__label { transition-delay: 0.26s; }
    .nav-link:nth-child(5) .nav-link__label { transition-delay: 0.32s; }
    .nav-drawer.is-open .nav-link__label { transform: translateY(0); }
    .nav-link:hover .nav-link__label { color: var(--accent); }
    .nav-link[aria-current="page"] .nav-link__num,
    .nav-link[aria-current="page"] .nav-link__label { color: var(--accent); }
    .nav-link:hover .nav-link__num   { color: var(--accent); }
    .nav-drawer__footer { display: flex; flex-direction: column; gap: 6px; }
    .nav-drawer__wordmark { font-family: var(--f-head); font-size: 11px; text-transform: uppercase; letter-spacing: 0.16em; color: var(--ink); margin-bottom: 4px; }
    .nav-drawer__sub { font-size: 11px; color: var(--muted); letter-spacing: 0.06em; }

    /* ─── PAGE ENTRANCE ───────────────────────────────────────── */
    /* The old .is-entering/pageEnter fade-and-rise (site.js used to add
       the class on every page load) is gone as of 2026-09-25. It was a
       second, uncoordinated transition stacked on top of the native
       View Transition added later (@view-transition below) — the browser
       already crossfades old page to new, then this one restarted the
       new page from opacity:0 a moment after, which is exactly the
       "flashes once or twice" Kayle saw clicking through on a phone.
       View Transitions now own the whole-page transition alone. */
    .page { display: block; }



    /* ─── TYPOGRAPHIC REFINEMENTS ─────────────────────────────── */
    /* Hanging punctuation on pull quotes and testimonials */
    .testimonial__quote { hanging-punctuation: first; }
    .hang-quote { margin-left: -0.45em; }

    /* Optical margin on large headings */
    .home-cta__heading,
    .brand-statement__text { text-wrap: balance; }

    /* ─── IMAGE PLACEHOLDER ───────────────────────────────────── */
    .img-placeholder {
      margin-left: calc(-1 * var(--side-w) + var(--photo-edge-gap)); margin-right: calc(-1 * var(--side-w) + var(--photo-edge-gap));
      width: calc(100% + 2 * (var(--side-w) - var(--photo-edge-gap))); aspect-ratio: 16/7;
      background: #D5D2CB; display: flex; align-items: center; justify-content: center;
    }
    @media (max-width: 639px) { .img-placeholder { aspect-ratio: 4/3; } }
    .img-placeholder__label { font-size: 10px; text-transform: uppercase; letter-spacing: 0.18em; color: rgba(26,25,22,0.3); text-align: center; padding: 0 16px; }
    /* Shorter treatment for breaks that sit INSIDE a numbered sequence
       (process.html's steps) rather than opening a page. The full
       16:7 / 4:3 height was long enough that the reader lost track of
       which step they were on by the time it ended — confirmed by two
       people independently. This reads as a beat, not a scene change,
       while still keeping real photography breaking up the list. */
    .img-placeholder--divider { aspect-ratio: 3/1; }
    @media (max-width: 639px) { .img-placeholder--divider { aspect-ratio: 2/1; } }

    /* ─── CTA SECTION ─────────────────────────────────────────── */
    .cta-section { padding: var(--sp-lg) 0 var(--sp-xl); }
    .cta-section__inner { border-top: 1px solid rgba(26,25,22,0.15); padding-top: var(--sp-lg); margin-top: calc(-1 * var(--sp-lg)); }
    .cta-section__inner { max-width: 700px; display: flex; flex-direction: column; gap: 24px; }
    .cta-section__heading { font-size: clamp(24px, 3vw, 38px); line-height: 1.05; }
    .cta-section__body { font-size: 15px; line-height: 1.8; color: var(--muted); max-width: 480px; }

    @media (min-width: 1024px) {
      #page-contact .fade-in > div:first-child { max-width: none; }
      #page-contact .fade-in { grid-template-columns: 1fr 1fr !important; align-items: start; }
    }

    /* ─── CONTACT FORM ───────────────────────────────────────────── */
    .contact-form { display: flex; flex-direction: column; gap: 28px; max-width: 560px; }
    .form-field { display: flex; flex-direction: column; gap: 8px; }
    .form-label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.16em; color: var(--muted); }
    .form-input, .form-textarea {
      background: transparent;
      border: none;
      border-bottom: 1px solid rgba(26,25,22,0.3);
      padding: 10px 0;
      font-family: var(--f-body);
      font-size: 15px;
      font-weight: 300;
      color: var(--ink);
      outline: none;
      width: 100%;
      transition: border-color 0.2s;
      border-radius: 0;
      -webkit-appearance: none;
    }
    .form-input:focus, .form-textarea:focus { border-bottom-color: var(--ink); }

    /* ─── CUSTOM DROPDOWN ────────────────────────────────────────── */
    .custom-select { position: relative; width: 100%; }
    .custom-select__trigger {
      display: flex; align-items: center; justify-content: space-between;
      padding: 10px 0; border-bottom: 1px solid rgba(26,25,22,0.3);
      font-family: var(--f-body); font-size: 15px; font-weight: 300;
      color: rgba(26,25,22,0.62); cursor: pointer; transition: border-color 0.2s;
      user-select: none;
    }
    .custom-select__trigger.has-value { color: var(--ink); }
    .custom-select__trigger.is-open { border-bottom-color: var(--ink); }
    .custom-select__arrow { width: 10px; height: 6px; flex-shrink: 0; transition: transform 0.2s; }
    .custom-select__trigger.is-open .custom-select__arrow { transform: rotate(180deg); }
    .custom-select__options {
      position: absolute; top: calc(100% + 2px); left: 0; right: 0; z-index: 100;
      background: var(--bg); border: 1px solid rgba(26,25,22,0.15);
      box-shadow: 0 8px 24px rgba(0,0,0,0.08); display: none;
    }
    .custom-select__options.is-open { display: block; }
    .custom-select__options.opens-up { top: auto; bottom: calc(100% + 2px); box-shadow: 0 -8px 24px rgba(0,0,0,0.08); }
    .custom-select__option {
      padding: 12px 16px; font-family: var(--f-body); font-size: 14px; font-weight: 300;
      color: var(--ink); cursor: pointer; transition: background 0.15s;
    }
    .custom-select__option:hover { background: #2e2d2a; color: var(--white); }
    .custom-select__option.is-selected { color: var(--muted); }
    .form-textarea { resize: none; min-height: 100px; line-height: 1.75; }
    .form-textarea::placeholder, .form-input::placeholder { color: rgba(26,25,22,0.62); }
    .form-submit { margin-top: 8px; }
    .form-success { display: none; padding: 20px 0; font-size: 15px; color: var(--accent); }
    .form-success.visible { display: block; }
    .form-error { display: none; font-size: 12px; color: #8A3B2E; }
    .form-error.visible { display: block; }
    .form-input.has-error { border-bottom-color: #8A3B2E; }
    .custom-select__trigger.has-error { border-bottom-color: #8A3B2E; }

    /* ─── FOOTER ──────────────────────────────────────────────── */
    .footer { padding: 48px 0; }
    .footer__grid { display: grid; grid-template-columns: 1fr; gap: 24px; margin-bottom: 24px; border-top: 1px solid rgba(26,25,22,0.15); padding-top: 48px; margin-top: -48px; }
    /* Three equal columns need real room: at 640px the side rails already
       take --side-w (80px) off each edge plus .wrap's own 32px, leaving
       under 550px for three columns and their gaps — the lockup shrinks
       to fit its column and "For Architects & Builders" wraps across
       several lines. Stacked (one column) stays correct all the way to
       1024px, where --side-w settles at 88px and the site generally
       starts treating the layout as desktop-wide; three columns only
       switch on there, where each one has ~360px+ to work with. */
    @media (min-width: 1024px) { .footer__grid { grid-template-columns: 1fr 1fr 1fr; gap: 40px; } }
    .footer__brand-name { font-family: var(--f-head); font-size: 13px; text-transform: uppercase; letter-spacing: 0.1em; margin-bottom: 6px; }
    .footer__tagline { font-size: 12px; color: var(--muted); }
    .footer__col-label { font-size: 11px; font-weight: 500; text-transform: uppercase; letter-spacing: 0.12em; color: var(--muted); margin-bottom: 12px; }
    .footer__nav { display: flex; flex-direction: column; gap: 8px; list-style: none; }
    .footer__nav a { font-size: 14px; color: var(--ink); transition: color 0.2s; cursor: pointer; }
    .footer__nav a:visited { color: #1A1916; } /* literal hex — var() is blocked inside :visited */
    .footer__nav a:hover { color: var(--accent); }
    .footer__contact { font-size: 14px; line-height: 1.9; }
    .footer__contact a { transition: color 0.2s; }
    .footer__contact a:visited { color: inherit; }
    .footer__contact a:hover { color: var(--accent); }
    .footer__bottom {
      border-top: 1px solid rgba(26,25,22,0.1); padding-top: 20px;
      display: flex; flex-direction: column; gap: 6px; font-size: 11px; color: var(--muted);
    }
    @media (min-width: 640px) { .footer__bottom { flex-direction: row; justify-content: space-between; align-items: center; } }

    /* ════════════════════════════════════════════════════════════
       HOME PAGE
    ════════════════════════════════════════════════════════════ */
    .hero {
      position: relative;
      margin-left: calc(-1 * var(--side-w) + var(--photo-edge-gap)); margin-right: calc(-1 * var(--side-w) + var(--photo-edge-gap));
      width: calc(100% + 2 * (var(--side-w) - var(--photo-edge-gap)));
      height: 100vh;
      height: 100dvh;
      min-height: 560px; overflow: hidden;
    }
    .hero__img {
      position: absolute; top: 0; left: 0; right: 0;
      /* sized to the LARGEST viewport state: when the mobile browser bar
         collapses, the taller hero reveals more of this pre-sized layer
         instead of rescaling it — eliminates the scroll "zoom" on phones */
      height: 100vh;
      height: 100lvh;
      min-height: 560px;
      background: url('img/hero-2400.webp') center 30% / cover no-repeat, linear-gradient(160deg, #4a5040 0%, #2a2e25 50%, #1a1916 100%);
      /* one-time cinematic settle on load */
      animation: heroSettle 3s cubic-bezier(0.22, 1, 0.36, 1) both;
    }
    @keyframes heroSettle {
      from { transform: scale(1.05); }
      to   { transform: scale(1); }
    }
    /* Scrim for text legibility. The .hero__overlay div was in the markup but
       had no rule, so the hero had no darkening at all — white text was
       relying on text-shadow alone over a bright image. Weighted to the top
       and bottom bands where the wordmark and tagline sit, and left lighter
       through the middle so the photograph still reads. */
    .hero__overlay {
      position: absolute; inset: 0; pointer-events: none;
      background:
        linear-gradient(to bottom,
          /* Kayle 2026-10-21: the kitchen looked flat under an even fade. Dark only where the words sit
             (logo at the top, tagline and links at the bottom); the room in the middle stays clear. */
          rgba(20,19,17,0.62) 0%,
          rgba(20,19,17,0.22) 18%,
          rgba(20,19,17,0) 34%,
          rgba(20,19,17,0) 60%,
          rgba(20,19,17,0.40) 82%,
          rgba(20,19,17,0.70) 100%);
    }
    /* Phones crop the hero to a tall strip, which lands the text over the
       brightest part of the frame — needs a heavier scrim than desktop. */
    @media (max-width: 639px) {
      .hero__img { background-image: url('img/hero-1400.webp'), linear-gradient(160deg, #4a5040 0%, #2a2e25 50%, #1a1916 100%); }
      .hero__overlay {
        background:
          linear-gradient(to bottom,
            rgba(20,19,17,0.66) 0%,
            rgba(20,19,17,0.26) 20%,
            rgba(20,19,17,0.06) 40%,
            rgba(20,19,17,0.08) 58%,
            rgba(20,19,17,0.46) 78%,
            rgba(20,19,17,0.78) 100%);
      }
    }
    .hero__wordmark {
      position: absolute; top: 32px; left: 50%; transform: translateX(-50%);
      display: flex; flex-direction: column; align-items: center; gap: 10px;
    }
    .hero__brandmark {
      width: clamp(44px, 4.5vw, 54px);
      opacity: 0.95;
      filter: drop-shadow(0 1px 3px rgba(0,0,0,0.5));
    }
    .hero__wordmark-text {
      font-family: var(--f-head); font-size: clamp(12px,1.8vw,16px); font-weight: 700;
      text-transform: uppercase; letter-spacing: 0.22em; color: var(--white); white-space: nowrap;
      text-shadow: 0 1px 3px rgba(0,0,0,0.55), 0 0 18px rgba(0,0,0,0.35);
    }
    .hero__bottom {
      position: absolute; bottom: 0; left: 0; right: 0;
      padding: 0 var(--gutter) 36px;
      display: flex; flex-direction: column; align-items: center; gap: 18px; text-align: center;
    }
    @media (min-width: 640px) { .hero__bottom { padding: 0 60px 48px; } }
    .hero__tagline { margin: 0; font-family: var(--f-body); font-size: 11px; font-weight: 400; text-transform: uppercase; letter-spacing: 0.14em; color: rgba(255,255,255,0.88); text-shadow: 0 1px 3px rgba(0,0,0,0.6), 0 0 16px rgba(0,0,0,0.4); }
    .hero__ctas { display: flex; gap: 32px; flex-wrap: wrap; justify-content: center; }
    .hero__cta { font-family: var(--f-body); font-size: 12px; font-weight: 400; text-transform: uppercase; letter-spacing: 0.12em; color: var(--white); text-decoration: underline; text-underline-offset: 4px; cursor: pointer; text-shadow: 0 1px 3px rgba(0,0,0,0.6), 0 0 16px rgba(0,0,0,0.4); }
    .hero__cta:hover { color: rgba(255,255,255,0.7); }
    /* Photographer credit (his license asks for it wherever the photo runs).
       Bottom-right corner, inside .hero__bottom's bottom padding (36px phone,
       48px desktop), so it sits below the tagline and links and never meets
       them, even when the links wrap to two lines on a phone. The side labels
       are fixed at mid-height, well clear of this corner. Same white and
       text-shadow as the hero text, just smaller and dimmer. */
    .hero__credit { position: absolute; right: var(--gutter); bottom: 8px; margin: 0; font-family: var(--f-body); font-size: 11px; font-weight: 400; letter-spacing: 0.02em; color: rgba(255,255,255,0.72); text-shadow: 0 1px 3px rgba(0,0,0,0.6), 0 0 16px rgba(0,0,0,0.4); pointer-events: none; }
    @media (min-width: 640px) { .hero__credit { right: 28px; bottom: 18px; } }
    /* Phones: run the credit up the right edge, smaller and dimmer, clear of the hero links (Kayle 2026-10-07: "less in your face"). */
    @media (max-width: 639px) { .hero__credit { right: 6px; bottom: 14px; writing-mode: vertical-rl; transform: rotate(180deg); font-size: 10px; letter-spacing: 0.04em; color: rgba(255,255,255,0.6); } }

    .brand-statement { padding: var(--sp-xl) 0; }
    .brand-statement__inner { display: flex; justify-content: center; max-width: 720px; margin: 0 auto; }
    .brand-statement__text { font-family: var(--f-body); font-size: clamp(20px,2.4vw,30px); font-weight: 300; line-height: 1.6; text-align: center; color: var(--ink); }

    .why { padding: var(--sp-lg) 0; }
    .why__inner { display: grid; grid-template-columns: 1fr; gap: var(--sp-md); max-width: 900px; border-top: 1px solid rgba(26,25,22,0.15); padding-top: var(--sp-lg); margin-top: calc(-1 * var(--sp-lg)); }
    .why__inner { display: grid; grid-template-columns: 1fr; gap: var(--sp-md); max-width: 900px; }
    @media (min-width: 640px) { .why__inner { grid-template-columns: 1fr 1fr; gap: 60px; } }
    /* The heading is much shorter than the copy+pillars column beside it.
       Grid's default stretch gives this column the full row height; center
       the heading within it rather than pinning it to the top, which read
       as an orphaned line floating over empty space. */
    .why__left { display: flex; flex-direction: column; justify-content: center; }
    .why__heading { font-size: clamp(22px, 3vw, 32px); }
    .why__body { font-size: 15px; line-height: 1.8; margin-bottom: 20px; }
    .why__link { display: block; margin-bottom: var(--sp-md); }
    .pillars { border-top: 1px solid rgba(26,25,22,0.15); }
    .pillar { display: grid; grid-template-columns: 36px 1fr; gap: 16px; align-items: start; padding: 20px 0; border-bottom: 1px solid rgba(26,25,22,0.15); }
    .pillar__num { font-family: var(--f-body); font-size: 11px; font-weight: 400; color: var(--muted); letter-spacing: 0.08em; padding-top: 3px; }
    .pillar__title { font-family: var(--f-head); font-size: 12px; text-transform: uppercase; letter-spacing: 0.08em; line-height: 1.5; }

    .full-bleed {
      margin-left: calc(-1 * var(--side-w) + var(--photo-edge-gap)); margin-right: calc(-1 * var(--side-w) + var(--photo-edge-gap));
      width: calc(100% + 2 * (var(--side-w) - var(--photo-edge-gap))); aspect-ratio: 4/3; overflow: hidden; background: #2a2e25;
    }
    @media (min-width: 1024px) { .full-bleed { aspect-ratio: 16/7; } }
    .full-bleed img { width: 100%; height: 100%; object-fit: cover; }

    .projects { padding: var(--sp-lg) 0; }
    .section-header { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: var(--sp-md); }
    .section-header .heading { font-size: clamp(18px,2.5vw,26px); }
    .section-header .text-link { white-space: nowrap; margin-left: 16px; flex: none; }
    .project-grid { display: grid; grid-template-columns: 1fr; gap: 3px; }
    @media (min-width: 640px) { .project-grid { grid-template-columns: 1fr 1fr; } }
    .project-card { position: relative; aspect-ratio: 3/4; overflow: hidden; display: block; }
    .project-card[data-page] { cursor: pointer; }
    .project-card__img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.9s cubic-bezier(0.25, 0.46, 0.45, 0.94); background: #3a3d35; }
    .project-card[data-page]:hover .project-card__img { transform: scale(1.04); }
    .project-card__overlay { position: absolute; inset: 0; background: linear-gradient(to top, rgba(0,0,0,0.6) 0%, transparent 50%); }
    .project-card__info { position: absolute; bottom: 0; left: 0; right: 0; padding: 24px; color: var(--white); }
    /* Full opacity + shadow, matching .work-card__meta's proven treatment
       elsewhere on the site — the gradient scrim alone wasn't reliable.
       Checked against the two live cards: the meta line was already
       nearly illegible against Cedar Lakes' stonework and Keuka's
       retaining wall at the previous 65% opacity with no shadow. Name
       stays very slightly more prominent than meta (full white vs. 88%)
       to preserve the hierarchy the original opacity gap was going for,
       but both now clear an actual legibility floor instead of depending
       on luck with future photography. */
    .project-card__name { font-family: var(--f-head); font-size: 12px; font-weight: 400; text-transform: uppercase; letter-spacing: 0.12em; line-height: 1.2; margin-bottom: 4px; color: var(--white); text-shadow: 0 1px 3px rgba(0,0,0,0.35); }
    .project-card__meta { font-family: var(--f-body); font-size: 11px; font-weight: 400; text-transform: uppercase; letter-spacing: 0.12em; color: rgba(255,255,255,0.88); text-shadow: 0 1px 3px rgba(0,0,0,0.35); }
    /* Phones: the overlay was carrying three lines (name, town, type) on
       a small card — just the name reads better. Location and type are
       one tap away on the project page itself. */
    @media (max-width: 639px) {
      .project-card__meta { display: none; }
    }

    /* ─── FOLLOW GRID (Instagram teaser) ──────────────────────────
       Square tiles read as "Instagram" on sight without borrowing any
       of Instagram's own chrome (no like counts, no blue links, no
       embed script) — on-brand by construction. Photos are ones
       already shot and processed for the site; this doesn't sync live,
       so swap in fresher shots here by hand every so often. */
    .follow-section { padding: var(--sp-lg) 0; }
    .follow-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 3px; }
    @media (min-width: 640px) { .follow-grid { grid-template-columns: repeat(6, 1fr); } }
    .follow-grid__item { position: relative; aspect-ratio: 1/1; overflow: hidden; display: block; }
    .follow-grid__item img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.9s cubic-bezier(0.25, 0.46, 0.45, 0.94); background: #3a3d35; }
    .follow-grid__item:hover img { transform: scale(1.04); }
    /* The handle is long enough that forcing it onto one flex row with
       the heading pushes it past the viewport edge on a phone (the
       heading already wraps to two lines at this width on its own).
       Stack instead of fighting the text length. */
    @media (max-width: 639px) {
      .follow-section .section-header { flex-direction: column; align-items: flex-start; gap: 8px; }
      .follow-section .section-header .text-link { margin-left: 0; }
    }

    /* Gap matches .project-figures (28px / 32px), not the 2-3px hairline
       used by pure-image grids like .project-grid and .work-project-grid.
       This section pairs each photo with a caption and a link — the wider
       gap is the site's own existing convention for that content type, and
       it doubles as the visual signal that this isn't more project
       photography: Selected Projects above stays tight at 3px, this
       doesn't, so the two sections read as different things at a glance
       instead of one four-photo set where two panels go nowhere. */
    .split-grid { display: grid; grid-template-columns: 1fr; gap: 3px; }
    @media (min-width: 640px) { .split-grid { grid-template-columns: 1fr 1fr; } }
    .split-grid__img { aspect-ratio: 4/5; overflow: hidden; background: #45483e; }
    .split-grid__img img { width: 100%; height: 100%; object-fit: cover; }

    .about { padding: var(--sp-lg) 0; }
    .about__inner { display: grid; grid-template-columns: 1fr; gap: var(--sp-md); max-width: 900px; }
    @media (min-width: 640px) { .about__inner { grid-template-columns: 1fr 1fr; gap: 60px; align-items: start; } }
    .about__img { aspect-ratio: 3/4; overflow: hidden; background: #3e4138; }
    .about__img img { width: 100%; height: 100%; object-fit: cover; }
    .about__content { display: flex; flex-direction: column; gap: 20px; }
    .about__heading { font-size: clamp(20px,2.8vw,30px); }
    .about__body { font-size: 15px; line-height: 1.8; }

    .home-cta { padding: 0 0 var(--sp-xl); }
    .home-cta .wrap { border-top: 1px solid rgba(26,25,22,0.15); padding-top: var(--sp-lg); }

    /* ── Joinery Corner Details ────────────────────────────── */

    /* SVG corners injected via JS — see initCornerDetails() */
    /* Diagonal pair only — top-left and bottom-right. site.js's
       addHousedCorners() only ever creates these two; .tr/.bl variants
       existed here but were never generated by any code path. */
    .joinery-corner { position: absolute; pointer-events: none; }
    .joinery-corner.tl { top: 0; left: 0; }
    .joinery-corner.br { bottom: 0; right: 0; transform: scale(-1); }
    .home-cta__inner { max-width: 700px; display: flex; flex-direction: column; gap: 24px; }
    .home-cta__heading { font-size: clamp(32px,5.5vw,68px); line-height: 1.05; }
    .home-cta__body { font-size: 15px; line-height: 1.8; color: var(--muted); max-width: 480px; }

    /* ════════════════════════════════════════════════════════════
       INNER PAGE HEADER
    ════════════════════════════════════════════════════════════ */
    .page-header { padding: 96px 0 var(--sp-lg); }
    .page-header .wrap > .fade-in { border-bottom: 1px solid rgba(26,25,22,0.15); padding-bottom: var(--sp-lg); margin-bottom: calc(-1 * var(--sp-lg)); }
    .page-header:has(+ .img-placeholder) .wrap > .fade-in { border-bottom: 0; }
    .page-header__label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.16em; color: var(--muted); margin-bottom: 20px; }
    .page-header__h1 { font-family: var(--f-head); font-size: clamp(30px,8vw,72px); text-transform: uppercase; letter-spacing: 0.03em; line-height: 1.0; max-width: 680px; margin-bottom: 40px; }
    .page-header__text { font-size: clamp(17px,2.4vw,22px); font-weight: 300; line-height: 1.65; max-width: 640px; }

    /* ════════════════════════════════════════════════════════════
       HOW WE WORK PAGE
    ════════════════════════════════════════════════════════════ */
    .pillars-section { padding: var(--sp-lg) 0 0; }
    .pillars-section .wrap { border-bottom: 1px solid rgba(26,25,22,0.15); padding-bottom: var(--sp-lg); }
    .howwework-intro { font-size: clamp(18px, 2.4vw, 24px); font-weight: 300; line-height: 1.7; max-width: 780px; color: var(--ink); }
    .pillars-grid { display: grid; grid-template-columns: 1fr; }
    @media (min-width: 640px) { .pillars-grid { grid-template-columns: 1fr 1fr 1fr; } }
    .pillar-card { padding: 36px 0; border-bottom: 1px solid rgba(26,25,22,0.12); }
    .pillar-card:last-child { border-bottom: none; }
    @media (min-width: 640px) {
      .pillar-card { padding: 40px 40px 40px 0; border-bottom: none; border-right: 1px solid rgba(26,25,22,0.12); }
      .pillar-card:nth-child(2) { padding-left: 40px; }
      .pillar-card:last-child { border-right: none; padding-left: 40px; padding-right: 0; }
    }
    .pillar-card__num { display: block; font-size: 11px; color: var(--muted); letter-spacing: 0.1em; margin-bottom: 20px; }
    .pillar-card__title { font-family: var(--f-head); font-size: clamp(14px,1.6vw,17px); text-transform: uppercase; letter-spacing: 0.06em; line-height: 1.4; margin-bottom: 14px; }
    .pillar-card__body { font-size: 14px; line-height: 1.8; }

    .process-intro { padding: var(--sp-lg) 0 var(--sp-md); }
    .process-intro__label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.16em; color: var(--muted); margin-bottom: 16px; }
    .process-intro__heading { font-family: var(--f-head); font-size: clamp(26px,3.5vw,42px); text-transform: uppercase; letter-spacing: 0.04em; line-height: 1.1; }

    .process-steps { padding-bottom: var(--sp-xl); }
    .process-steps.no-top { padding-top: 0; }
    .process-steps.no-top:last-of-type { padding-bottom: 0; }
    .step { display: grid; grid-template-columns: 1fr; border-top: 1px solid rgba(26,25,22,0.15); }
    @media (min-width: 640px)  { .step { grid-template-columns: 200px 1fr; } }
    @media (min-width: 1024px) { .step { grid-template-columns: 240px 1fr; } }
    .step__left { padding: 36px 0 16px; cursor: pointer; display: flex; flex-direction: column; position: relative; }
    @media (min-width: 640px) { .step:not(.step--faq) .step__left { padding: 44px 48px 44px 0; border-right: 1px solid rgba(26,25,22,0.15); cursor: default; } }
    .step__num { display: block; font-size: 11px; color: var(--muted); letter-spacing: 0.1em; margin-bottom: 10px; }
    .step__title { font-family: var(--f-head); font-size: clamp(13px,1.4vw,15px); text-transform: uppercase; letter-spacing: 0.08em; line-height: 1.4; }
    .step__subtitle { font-size: 12px; font-style: italic; color: var(--muted); margin-top: 8px; line-height: 1.5; font-weight: 300; }

    /* accordion toggle icon — mobile only */
    .step__toggle { display: flex; align-items: center; justify-content: center; position: absolute; right: 0; top: 36px; width: 20px; height: 20px; }
    .step__toggle::before, .step__toggle::after { content: ''; position: absolute; background: var(--ink); transition: transform 0.35s ease, opacity 0.35s ease; }
    .step__toggle::before { width: 12px; height: 1.5px; }
    .step__toggle::after  { width: 1.5px; height: 12px; }
    .step.is-open .step__toggle::after { transform: rotate(90deg); opacity: 0; }
    @media (min-width: 640px) { .step:not(.step--faq) .step__toggle { display: none; } }

    /* accordion body — mobile collapses, desktop always visible */
    .step__right { padding: 0; overflow: hidden; max-height: 0; transition: max-height 0.5s cubic-bezier(0.4,0,0.2,1), padding 0.35s ease; position: relative; }
    .step__right::after { display: none; content: ''; position: absolute; bottom: 0; left: 0; right: 0; height: 40px; background: linear-gradient(to bottom, transparent, var(--bg)); pointer-events: none; transition: opacity 0.35s ease; }
    .step.is-open .step__right { max-height: 3000px; padding: 0 0 36px; }
    .step.is-open .step__right::after { opacity: 0; }
    @media (min-width: 640px) { .step:not(.step--faq) .step__right { max-height: none !important; padding: 44px 0 44px 48px !important; overflow: visible; } .step:not(.step--faq) .step__right::after { display: none; } }
    .step__body { font-size: 15px; line-height: 1.85; }
    .step__body p + p { margin-top: 18px; }

    /* FAQ variant — single column, collapsible at every breakpoint */
    .step.step--faq { grid-template-columns: 1fr; }
    .step--faq .step__left { border-right: none; }
    .step--faq.is-open .step__right { padding-top: 4px; }
    .step--faq .step__toggle { top: 30px; }
    .step--faq .step__title, .step--faq .step__subtitle { padding-right: 44px; }
    @media (max-width: 639px) { .step__left[data-accordion] .step__title, .step__left[data-accordion] .step__subtitle { padding-right: 44px; } }

    /* ════════════════════════════════════════════════════════════
       OUR WORK PAGE
    ════════════════════════════════════════════════════════════ */
    .work-header { padding: 96px 0 40px; display: flex; flex-direction: column; align-items: center; gap: 12px; text-align: center; }
    .work-header__label { font-family: var(--f-head); font-size: clamp(36px, 6vw, 72px); font-weight: 700; text-transform: uppercase; letter-spacing: 0.16em; color: var(--ink); white-space: nowrap; border-bottom: 1px solid rgba(26,25,22,0.15); padding-bottom: 40px; margin-bottom: -40px; }
    /* Below ~480px the 36px floor + heavy tracking is wider than the
       viewport and wraps "Our Work" to two lines. Scale size and
       tracking down together so it stays on one line without shrinking
       the heading on tablet/desktop, where it already fits fine. */
    @media (max-width: 479px) {
      .work-header__label { font-size: 8.2vw; letter-spacing: 0.10em; }
    }
    .work-header__text { font-size: 13px; color: var(--muted); font-style: italic; }

    .work-projects { padding: var(--sp-lg) 0; }
    /* Two-up from 640px. (Tried one-per-row at every width on 2026-09-25
       at Kayle's ask; he reverted it the same day — if it comes up again,
       the card image `sizes` in work.html must change with it, or
       full-width cards get served half-width renditions.) */
    .work-project-grid { display: grid; grid-template-columns: 1fr; gap: 56px; border-bottom: 1px solid rgba(26,25,22,0.15); padding-bottom: var(--sp-lg); margin-bottom: calc(-1 * var(--sp-lg)); }
    @media (min-width: 640px) { .work-project-grid { grid-template-columns: 1fr 1fr; column-gap: 3px; row-gap: 48px; } }
    .work-card { display: block; position: relative; }
    .work-card[data-page] { cursor: pointer; }

    /* ─── PROJECT PAGE ───────────────────────────────────────────── */
    .project-hero { width: 100%; height: 70vh; min-height: 480px; background: #2a2e25; position: relative; overflow: hidden; display: flex; align-items: center; justify-content: center; }
    .project-hero__img { width: 100%; height: 100%; object-fit: cover; }
    .project-hero__label { font-size: 10px; text-transform: uppercase; letter-spacing: 0.18em; color: rgba(255,255,255,0.2); }
    .project-meta-bar { border-bottom: 1px solid rgba(26,25,22,0.15); padding: 32px 0; }

    /* Mobile: a clean stacked list — each item full width, separated by a
       hairline rule instead of being squeezed into cramped 2-up columns. */
    .project-meta-bar__inner { display: flex; flex-direction: column; gap: 18px; }
    .project-meta-item { padding-bottom: 16px; border-bottom: 1px solid rgba(26,25,22,0.08); }
    .project-meta-bar__inner > .project-meta-item:last-child { border-bottom: none; padding-bottom: 0; }

    /* Tablet: two per row, still stacked label-over-value, dividers dropped. */
    @media (min-width: 640px) {
      .project-meta-bar__inner { display: grid; grid-template-columns: repeat(2, 1fr); gap: 24px 32px; }
      .project-meta-item { border-bottom: none; padding-bottom: 0; }
    }

    /* Desktop: spread edge-to-edge in a single row so every value fits on
       one line — no wrap, generous gaps do the spacing instead of a fixed
       column grid (which left empty columns whenever a page has fewer
       than 6 meta items). */
    @media (min-width: 1024px) {
      .project-meta-bar__inner { display: flex; flex-direction: row; flex-wrap: nowrap; justify-content: space-between; gap: 40px; }
      .project-meta-item { white-space: nowrap; }
    }

    .project-meta-item__label { font-size: 10px; text-transform: uppercase; letter-spacing: 0.14em; color: var(--muted); margin-bottom: 6px; }
    .project-meta-item__value { font-family: var(--f-head); font-size: 13px; letter-spacing: 0.04em; color: var(--ink); line-height: 1.4; }
    .project-stats { padding: var(--sp-md) 0; border-bottom: 1px solid rgba(26,25,22,0.15); }
    .project-stats__grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 2px; background: rgba(26,25,22,0.1); }
    @media (min-width: 640px) { .project-stats__grid { grid-template-columns: repeat(3, 1fr); } }
    @media (min-width: 1024px) { .project-stats__grid { grid-template-columns: repeat(6, 1fr); } }
    .project-stat { background: var(--bg); padding: 28px 24px; }
    .project-stat__num { font-family: var(--f-head); font-size: clamp(28px, 4vw, 44px); letter-spacing: -0.01em; color: var(--ink); line-height: 1; margin-bottom: 8px; }
    .project-stat__label { font-size: 10px; text-transform: uppercase; letter-spacing: 0.14em; color: var(--muted); line-height: 1.5; }
    .project-narrative { padding: var(--sp-lg) 0; border-bottom: 1px solid rgba(26,25,22,0.15); }
    .project-narrative__inner { display: grid; grid-template-columns: 1fr; gap: var(--sp-md); }
    @media (min-width: 768px) { .project-narrative__inner { grid-template-columns: 1fr 2fr; gap: var(--sp-lg); } }
    .project-narrative__label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.16em; color: var(--muted); margin-bottom: 12px; }
    .project-narrative__heading { font-family: var(--f-head); font-size: clamp(20px, 2.5vw, 28px); color: var(--ink); line-height: 1.3; }
    .project-narrative__body { font-size: 15px; line-height: 1.85; font-weight: 300; }
    .project-narrative__body p + p { margin-top: 18px; }
    /* Contained gallery: photos keep true aspect but sit in a centered
       column (wider than the 960px text wrap, well short of the viewport).
       The hero stays full-bleed — one cinematic moment, then composed
       photography. Widen or narrow with the max-width below. */
    .project-gallery { padding: var(--sp-lg) 24px; max-width: 1248px; margin: 0 auto; }
    /* Slots are sized by image aspect, not viewport height, so landscape
       photography shows essentially uncropped on desktop. Knobs:
       - fulls: 3/2 matches the camera; max-height 95vh keeps very tall
         monitors from turning one photo into two screens (imperceptible
         crop when it engages).
       - pairs: 3/2 each — two uncropped landscape halves.
       - portraits: 4/5 — a gentle crop of native 2:3 verticals that keeps
         the pair from towering. Use 3/4 here for even less crop. */
    .project-gallery__full { width: 100%; height: auto; aspect-ratio: 3 / 2; max-height: 95vh; min-height: 400px; background: rgba(26,25,22,0.08); display: flex; align-items: center; justify-content: center; margin-bottom: 2px; }
    .project-gallery__pair { display: grid; grid-template-columns: 1fr 1fr; gap: 2px; margin-bottom: 2px; }
    .project-gallery__pair-img { height: auto; aspect-ratio: 3 / 2; background: rgba(26,25,22,0.08); display: flex; align-items: center; justify-content: center; }
    .project-gallery__portrait { display: grid; grid-template-columns: 1fr 1fr; gap: 2px; margin-bottom: 2px; }
    .project-gallery__portrait-img { height: auto; aspect-ratio: 4 / 5; background: rgba(26,25,22,0.08); display: flex; align-items: center; justify-content: center; }
    .project-gallery__portrait-img.tall { height: auto; aspect-ratio: 4 / 5; }

    /* Video pairs with a still, same as any portrait pair — a short
       muted/looping clip (4:5, matching .project-gallery__portrait-img)
       graded to the same warm, desaturated palette as the photography
       so motion doesn't read as a foreign media widget. No controls. */
    .project-gallery__portrait-img video { width: 100%; height: 100%; object-fit: cover; display: block; }
    /* Same treatment for video in the other two gallery slot types — added
       when a video first appeared in a FULL slot (Kacin Barn's model
       reveal). Previously only the portrait slot had this rule, since
       video had only ever been used there before. */
    .project-gallery__full video,
    .project-gallery__pair-img video { width: 100%; height: 100%; object-fit: cover; display: block; }
    .gallery-label { font-size: 10px; text-transform: uppercase; letter-spacing: 0.16em; color: rgba(26,25,22,0.3); text-align: center; padding: 0 20px; }
    .project-nav { padding: var(--sp-md) 0; border-top: 1px solid rgba(26,25,22,0.15); display: flex; justify-content: space-between; align-items: center; }

    /* Project page images: the heights above are viewport- or pixel-based, which
       works on wide screens but inverts on phones. Two fixes here.

       1. FULL BLEED. body carries `padding: 0 var(--side-w)`, and unlike .hero
          and .full-bleed, .project-hero never broke out of it — so on a 393px
          phone the hero was only 249px wide. These now span edge to edge.
       2. ASPECT RATIOS below 1024px, so landscape photographs stay landscape
          instead of being cropped to a vertical sliver. */
    /* Only the hero breaks out of the side rail now — the gallery is a
       contained, centered column (see .project-gallery above). */
    .project-hero {
      margin-left: calc(-1 * var(--side-w) + var(--photo-edge-gap));
      margin-right: calc(-1 * var(--side-w) + var(--photo-edge-gap));
      width: calc(100% + 2 * (var(--side-w) - var(--photo-edge-gap)));
    }
    @media (max-width: 1023px) {
      .project-hero        { height: auto; min-height: 0; aspect-ratio: 3/2; }
      .project-gallery__full { height: auto; min-height: 0; aspect-ratio: 3/2; }
      .project-gallery__pair-img { height: auto; aspect-ratio: 3/2; }
      .project-gallery__portrait-img,
      .project-gallery__portrait-img.tall { height: auto; aspect-ratio: 4/5; }
    }
    @media (max-width: 639px) {
      /* Square hero: a statement block at ~46% of viewport height that still
         keeps 67% of a 3:2 frame's width. Taller than this and the building
         loses its setting. */
      .project-hero { aspect-ratio: 1/1; }

      /* Same inset as the photo pairs (.split-grid) on mobile — no
         full-bleed breakout. Was previously broken out edge-to-edge
         to the true screen edge; reverted so gallery photos carry
         the same small margin off the edge that .split-grid does. */
      .project-gallery {
        max-width: none;
        padding-left: 0;
        padding-right: 0;
      }

      /* Landscape slots (a full-width single, or a pair meant to read as
         two landscape photos side by side) keep their true 3:2 shape and
         stack one per row. Squeezing two 3:2 photos into half a phone's
         width at a forced 4:5 crop was hiding most of each picture —
         object-fit:cover had to cut both sides off to fill a box far
         narrower than the photo actually is. */
      .project-gallery__full,
      .project-gallery__pair-img {
        aspect-ratio: 3/2;
      }
      .project-gallery__pair { grid-template-columns: 1fr; gap: 2px; }

      /* Portrait pairs also stack one per row, full width, below 640px —
         Kayle's call: two vertical photos at half a phone's width (under
         190px each) were technically uncropped but too small to actually
         see. One at a time, full width, at their true 4:5 shape. */
      .project-gallery__portrait-img,
      .project-gallery__portrait-img.tall {
        aspect-ratio: 4/5;
      }
      .project-gallery__portrait { grid-template-columns: 1fr; gap: 2px; }
    }
    .project-nav__link { font-size: 12px; text-transform: uppercase; letter-spacing: 0.12em; color: var(--muted); cursor: pointer; transition: color 0.2s; }
    .project-nav__link:visited { color: #6B675F; } /* literal hex — var() is blocked inside :visited */
    .project-nav__link:hover { color: var(--ink); }
    /* Landscape at every width — the old 3:4 mobile crop turned each card
       into a tall narrow strip; architecture photography reads far better
       wide than tall, and a run of 8 cards stayed shorter as a result. */
    .work-card__img { aspect-ratio: 4/3; background: #D5D2CB; display: flex; align-items: center; justify-content: center; overflow: hidden; position: relative; }
    /* A light shared tone at rest, released to the photo's real color on
       hover — ties Keuka's dusk light, Parkland's Florida daylight, and
       Morris's warm interior into one set at a glance, without a heavy
       filter flattening any of them. The scale-up on release matches the
       homepage project-card hover already used elsewhere on the site. */
    .work-card__img img {
      filter: saturate(0.86) sepia(0.05) contrast(1.02);
      transition: filter 0.6s ease, transform 0.9s cubic-bezier(0.25, 0.46, 0.45, 0.94);
    }
    .work-card:hover .work-card__img img {
      filter: none;
      transform: scale(1.035);
    }
    /* Morris's great-room shot is portrait (985x1231) going into a
       landscape 4:3 card — a dead-center crop split the difference
       between the roof peak and the seating, losing a bit of both.
       Biasing up keeps both chandeliers and the arched window, the
       shot's real subject, and trades away foreground rug/sofa instead. */
    .work-card--morris .work-card__img img { object-position: 50% 22%; }
    .work-card__img-label { font-size: 10px; text-transform: uppercase; letter-spacing: 0.18em; color: rgba(26,25,22,0.3); text-align: center; padding: 0 16px; }
    /* A scrim under the label, not just a color swap — var(--muted) was
       tuned for the cream page background and nearly vanished sitting
       directly on top of a photo. White alone would still fail against
       a light sky or pale wood; the gradient guarantees contrast no
       matter what's behind it. */
    .work-card__img::after {
      content: ""; position: absolute; inset: auto 0 0 0; height: 55%;
      background: linear-gradient(to top, rgba(15,14,12,0.55), rgba(15,14,12,0) 100%);
      pointer-events: none;
    }
    .work-card__meta { position: absolute; bottom: 14px; left: 16px; font-size: 11px; color: var(--white); letter-spacing: 0.12em; text-transform: uppercase; text-shadow: 0 1px 3px rgba(0,0,0,0.35); z-index: 1; }
    /* Status flag (e.g. "In Progress") — top-right corner, opposite the
       category label at bottom-left. No scrim up there to lean on like
       .work-card__meta has, so this carries its own background rather
       than relying on text-shadow alone. */
    .work-card__flag { position: absolute; top: 14px; right: 14px; font-size: 10px; color: var(--white); letter-spacing: 0.1em; text-transform: uppercase; background: rgba(26,25,22,0.6); padding: 5px 10px; border-radius: 2px; z-index: 1; }
    .work-card__info { padding: 14px 0 0; }
    .work-card__name { font-family: var(--f-head); font-size: 12px; font-weight: 400; text-transform: uppercase; letter-spacing: 0.12em; line-height: 1.3; color: var(--muted); }

    .testimonials { padding: var(--sp-lg) 0; }
    .testimonials .wrap > *:last-child { border-bottom: 1px solid rgba(26,25,22,0.15); padding-bottom: var(--sp-lg); margin-bottom: calc(-1 * var(--sp-lg)); }
    .testimonials__label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.16em; color: var(--muted); margin-bottom: 16px; }
    .testimonials__heading { font-family: var(--f-head); font-size: clamp(26px,3.5vw,42px); text-transform: uppercase; letter-spacing: 0.04em; line-height: 1.1; margin-bottom: 48px; }
    .testimonial { padding: 40px 0; border-top: 1px solid rgba(26,25,22,0.15); display: grid; grid-template-columns: 1fr; gap: 20px; }
    @media (min-width: 640px) { .testimonial { grid-template-columns: 1fr 200px; gap: 60px; align-items: start; } }
    .testimonial__quote { font-family: var(--f-head); font-size: clamp(16px,2vw,20px); font-style: italic; font-weight: 700; line-height: 1.55; }
    .testimonial__source { text-align: left; }
    @media (min-width: 640px) { .testimonial__source { text-align: right; } }
    .testimonial__name { font-family: var(--f-head); font-size: 13px; text-transform: uppercase; letter-spacing: 0.08em; line-height: 1.4; margin-bottom: 4px; }
    .testimonial__org { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.1em; }

    .types { padding: var(--sp-lg) 0; }
    .types .wrap > *:last-child { border-bottom: 1px solid rgba(26,25,22,0.15); padding-bottom: var(--sp-lg); margin-bottom: calc(-1 * var(--sp-lg)); }
    .types__label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.16em; color: var(--muted); margin-bottom: 16px; }
    .types__heading { font-family: var(--f-head); font-size: clamp(26px,3.5vw,42px); text-transform: uppercase; letter-spacing: 0.04em; line-height: 1.1; margin-bottom: 48px; }
    .types__grid { display: grid; grid-template-columns: 1fr; }
    @media (min-width: 1024px) { .types__grid { grid-template-columns: 1fr 1fr; } }
    .type-row { padding: 28px 0; border-top: 1px solid rgba(26,25,22,0.15); display: grid; grid-template-columns: 1fr; gap: 12px; }
    @media (min-width: 640px) { .type-row { grid-template-columns: 48px 1fr; gap: 24px; padding: 28px 0; } }
    @media (min-width: 1024px) {
      .type-row { grid-template-columns: 160px 1fr; gap: 32px; }
      .type-row:nth-child(odd) { padding-right: 40px; }
      .type-row:nth-child(even) { padding-left: 40px; border-left: 1px solid rgba(26,25,22,0.15); }
    }
    .type-row__num { font-size: 11px; color: var(--muted); letter-spacing: 0.1em; padding-top: 3px; }
    .type-row__title { font-family: var(--f-head); font-size: 14px; text-transform: uppercase; letter-spacing: 0.06em; line-height: 1.4; margin-bottom: 8px; }
    .type-row__desc { font-size: 13px; line-height: 1.75; }

    /* ════════════════════════════════════════════════════════════
       WHO WE ARE PAGE
    ════════════════════════════════════════════════════════════ */
    .origin { padding: var(--sp-lg) 0; }
    .origin__inner { display: grid; grid-template-columns: 1fr; gap: 48px; border-bottom: 1px solid rgba(26,25,22,0.15); padding-bottom: var(--sp-lg); margin-bottom: calc(-1 * var(--sp-lg)); }
    @media (min-width: 640px) { .origin__inner { grid-template-columns: 160px 1fr; gap: 60px; } }
    .origin__year { font-family: var(--f-head); font-size: clamp(48px,6vw,72px); font-weight: 700; line-height: 1; opacity: 0.15; }
    .origin__body { font-size: 15px; line-height: 1.85; }
    .origin__body p + p { margin-top: 18px; }

    .beliefs { padding: var(--sp-lg) 0; }
    .beliefs .wrap > *:last-child { border-bottom: 1px solid rgba(26,25,22,0.15); padding-bottom: var(--sp-lg); margin-bottom: calc(-1 * var(--sp-lg)); }
    .beliefs__label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.16em; color: var(--muted); margin-bottom: 16px; }
    .beliefs__heading { font-family: var(--f-head); font-size: clamp(26px,3.5vw,42px); text-transform: uppercase; letter-spacing: 0.04em; line-height: 1.1; margin-bottom: 16px; }
    .beliefs__intro { font-size: 15px; line-height: 1.85; max-width: 640px; color: var(--muted); }
    .belief { display: grid; grid-template-columns: 1fr; border-top: 1px solid rgba(26,25,22,0.15); margin-top: 48px; }
    @media (min-width: 640px)  { .belief { grid-template-columns: 200px 1fr; } }
    @media (min-width: 1024px) { .belief { grid-template-columns: 240px 1fr; } }
    .belief__left { padding: 36px 0 16px; }
    @media (min-width: 640px) { .belief__left { padding: 44px 48px 44px 0; border-right: 1px solid rgba(26,25,22,0.15); } }
    .belief__num { display: block; font-size: 11px; color: var(--muted); letter-spacing: 0.1em; margin-bottom: 10px; }
    .belief__title { font-family: var(--f-head); font-size: clamp(13px,1.4vw,15px); text-transform: uppercase; letter-spacing: 0.08em; line-height: 1.4; }
    .belief__right { padding: 20px 0 44px; }
    @media (min-width: 640px) { .belief__right { padding: 44px 0 44px 48px; } }
    .belief__body { font-size: 15px; line-height: 1.85; }

    .team { padding: var(--sp-lg) 0; }
    .team .wrap > *:last-child { border-bottom: 1px solid rgba(26,25,22,0.15); padding-bottom: var(--sp-lg); margin-bottom: calc(-1 * var(--sp-lg)); }
    .team__label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.16em; color: var(--muted); margin-bottom: 16px; }
    .team__heading { font-family: var(--f-head); font-size: clamp(26px,3.5vw,42px); text-transform: uppercase; letter-spacing: 0.04em; line-height: 1.1; margin-bottom: 48px; }
    .team__grid { display: grid; grid-template-columns: 1fr; gap: 48px; }
    @media (min-width: 640px) { .team__grid { grid-template-columns: 1fr 1fr; gap: 40px; } }
    @media (min-width: 1024px) { .team__grid { grid-template-columns: 1fr 1fr 1fr; gap: 48px; } }
    .team-card__photo { aspect-ratio: 3/4; background: #D5D2CB; display: flex; align-items: center; justify-content: center; }
    .team-card__photo-label { font-size: 10px; text-transform: uppercase; letter-spacing: 0.18em; color: rgba(26,25,22,0.3); text-align: center; padding: 0 16px; }
    .team-card__info { padding: 20px 0 0; }
    .team-card__name { font-family: var(--f-head); font-size: 15px; text-transform: uppercase; letter-spacing: 0.06em; line-height: 1.3; margin-bottom: 4px; }
    .team-card__role { font-size: 14px; color: var(--muted); letter-spacing: 0; line-height: 1.7; }

    .partners { padding: var(--sp-lg) 0; }
    .partners .wrap > *:last-child { border-bottom: 1px solid rgba(26,25,22,0.15); padding-bottom: var(--sp-lg); margin-bottom: calc(-1 * var(--sp-lg)); }
    .partners__label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.16em; color: var(--muted); margin-bottom: 16px; }
    .partners__heading { font-family: var(--f-head); font-size: clamp(26px,3.5vw,42px); text-transform: uppercase; letter-spacing: 0.04em; line-height: 1.1; margin-bottom: 16px; }
    .partners__intro { font-size: 15px; line-height: 1.85; max-width: 640px; color: var(--muted); margin-bottom: 48px; }
    .partners__grid { display: grid; grid-template-columns: 1fr; }
    @media (min-width: 1024px) { .partners__grid { grid-template-columns: 1fr 1fr; } }
    .partner-row { padding: 28px 0; border-top: 1px solid rgba(26,25,22,0.15); display: grid; grid-template-columns: 1fr; gap: 8px; }
    @media (min-width: 640px) {
      .partner-row { grid-template-columns: 160px 1fr; gap: 32px; }
    }
    @media (min-width: 1024px) {
      .partner-row:nth-child(odd) { padding-right: 40px; }
      .partner-row:nth-child(even) { padding-left: 40px; border-left: 1px solid rgba(26,25,22,0.15); }
    }
    .partner-row__category { font-size: 11px; text-transform: uppercase; letter-spacing: 0.12em; color: var(--muted); padding-top: 3px; }
    .partner-row__name { font-family: var(--f-head); font-size: 14px; text-transform: uppercase; letter-spacing: 0.06em; line-height: 1.4; margin-bottom: 6px; }
    .partner-row__desc { font-size: 13px; line-height: 1.75; }

/* ─── SKIP LINK ─────────────────────────────────────────────── */
.skip-link {
  position: fixed; top: 12px; left: 12px; z-index: 600;
  background: var(--ink); color: var(--white);
  font-family: var(--f-body); font-size: 12px; font-weight: 500;
  text-transform: uppercase; letter-spacing: 0.1em;
  padding: 12px 20px; transform: translateY(-200%);
  transition: transform 0.2s ease;
}
.skip-link:focus { transform: translateY(0); }

/* ─── IMAGE HELPER (used when replacing photo placeholders) ─── */
.ph-img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ─── FORM SUBMIT STATE ─────────────────────────────────────── */
.btn-solid:disabled { opacity: 0.55; cursor: default; }
.btn-solid:disabled:hover { background: var(--ink); border-color: var(--ink); }

/* ─── REDUCED MOTION ────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001s !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001s !important;
  }
  .fade-in { opacity: 1 !important; transform: none !important; }
}

/* ─── JOURNAL (additive — delete this whole block to undo) ──── */
.journal-list { border-top: 0; }
.journal-item:last-child { border-bottom: 0; }
.journal-item {
  display: grid; grid-template-columns: 150px 1fr; gap: 12px 40px;
  padding: 40px 0; border-bottom: 1px solid rgba(26,25,22,0.15);
}
@media (max-width: 639px) { .journal-item { grid-template-columns: 1fr; gap: 8px; } }
.journal-item__date { font-size: 11px; text-transform: uppercase; letter-spacing: 0.14em; color: var(--muted); padding-top: 7px; }
.journal-item__title { font-family: var(--f-head); font-size: clamp(22px, 3vw, 32px); font-weight: 700; line-height: 1.25; }
.journal-item__title a:visited { color: inherit; }
.journal-item__title a:hover { color: var(--accent); }
.journal-item__excerpt { margin-top: 12px; font-size: 15px; font-weight: 300; line-height: 1.7; color: var(--muted); max-width: 62ch; }
.journal-item__read { display: inline-block; margin-top: 16px; }

.article { max-width: 740px; }
.article__meta { font-size: 11px; text-transform: uppercase; letter-spacing: 0.14em; color: var(--muted); margin-bottom: 20px; }
.article__meta a:visited { color: inherit; }
.article__meta a:hover { color: var(--accent); }
.article__body { margin-top: 8px; }
.article__body p { font-size: 16px; font-weight: 300; line-height: 1.8; }
.article__body p + p { margin-top: 22px; }
.article__body h2 { font-family: var(--f-head); font-size: clamp(20px, 2.5vw, 26px); font-weight: 700; line-height: 1.3; margin: 52px 0 18px; }
.article__body ul { margin: 22px 0 22px 22px; }
.article__body li { font-size: 16px; font-weight: 300; line-height: 1.8; margin-bottom: 10px; }
.article__body a { text-decoration: underline; text-underline-offset: 3px; }
.article__body a:visited { color: inherit; }
.article__body a:hover { color: var(--accent); }
.article__footer { margin-top: 72px; padding-top: 44px; border-top: 1px solid rgba(26,25,22,0.15); display: flex; flex-wrap: wrap; align-items: center; gap: 24px; }
.article__footer-text { font-size: 15px; font-weight: 300; color: var(--muted); }

/* ─── NAV DRAWER — mobile spacing fix ───────────────────────── */
/* Guarantee a gap between the links and the wordmark footer even
   when the panel content is taller than the viewport. */
.nav-drawer__footer { margin-top: 48px; flex-shrink: 0; }
@media (max-width: 639px) {
  .nav-drawer__panel { padding: 40px 28px 36px; }
  .nav-drawer__top { margin-top: 16px; }
  .nav-link { padding: 16px 0; }
  .nav-drawer__top > div[style*="margin-top:24px"] { margin-top: 18px !important; padding-top: 18px !important; }
  .nav-drawer__footer { margin-top: 32px; }
}
@media (max-height: 640px) {
  .nav-link { padding: 12px 0; }
  .nav-drawer__panel { padding-top: 32px; padding-bottom: 28px; }
}

/* ─── SIGNATURE DETAILS ─────────────────────────────────────── */

/* 3. Pencil-line underline — draws left to right on hover */
.text-link, .footer__nav a, .journal-item__title a, .utility-link {
  background-image: linear-gradient(currentColor, currentColor);
  background-size: 0% 1px;
  background-repeat: no-repeat;
  background-position: left calc(100% - 1px);
  transition: background-size 0.35s ease, color 0.2s ease;
}
.text-link:hover, .footer__nav a:hover, .journal-item__title a:hover, .utility-link:hover,
.text-link:focus-visible, .footer__nav a:focus-visible, .utility-link:focus-visible {
  background-size: 100% 1px;
}

/* Photos breathe in — a beat behind their section, long and gentle.
   No hidden states beyond the section fade that already exists. */
.js .fade-in img.ph-img {
  opacity: 0;
  transform: scale(1.02);
  will-change: opacity, transform;
  transition: opacity 1.6s cubic-bezier(0.22, 1, 0.36, 1) 0.15s,
              transform 1.6s cubic-bezier(0.22, 1, 0.36, 1) 0.15s;
}
/* the fade begins only when the section is on screen AND the image is
   fully decoded — so it always fades real pixels, never an empty box */
.fade-in.visible img.ph-img.img-ready { opacity: 1; transform: scale(1); }
@media (prefers-reduced-motion: reduce) {
  .fade-in img.ph-img { opacity: 1 !important; transform: none !important; }
}

/* 4. Selection in the house green */
::selection { background: var(--accent); color: var(--white); }
::-moz-selection { background: var(--accent); color: var(--white); }

/* 5. Colophon */
.footer__colophon { letter-spacing: 0.12em; }

@media (prefers-reduced-motion: reduce) {
  .text-link, .footer__nav a, .journal-item__title a { transition: none !important; }
}

/* ═══════════════════════════════════════════════════════════════════
   PROJECT PAGES — PHOTO-DENSITY TIERS
   Paste this block at the end of assets/styles.css.

   Additive only — nothing here overrides an existing rule, and the
   existing project pages render identically with or without it.

   Three new components, all used by the Medium and Lean templates:
     .project-sequence / .project-phase   phase notes (shop, raise, in place)
     .project-figure                      contained image + caption + credit
     .project-figures                     two figures side by side

   Everything else those templates use — .page-header, .project-meta-bar,
   .project-stats, .project-narrative, .project-gallery, .testimonial —
   is already in this stylesheet.
   ═══════════════════════════════════════════════════════════════════ */

/* ─── Phase notes ────────────────────────────────────────────────
   A phase is a movement in the story: shop, raise, in place. The
   label carries real sequence information, so it's numbered on the
   Medium template and named on the Lean one, where the order is
   drawing → frame rather than a timeline. */

.project-sequence {
  padding: var(--sp-lg) 0 0;
}

.project-phase {
  padding: 0 0 28px;
}

.project-phase + .project-figure,
.project-phase + .project-figures {
  padding-bottom: var(--sp-lg);
}

.project-phase__label {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--muted);
  margin-bottom: 14px;
}

.project-phase__title {
  font-size: clamp(20px, 2.6vw, 30px);
  margin-bottom: 16px;
  max-width: 22ch;
}

.project-phase__text {
  font-size: 15px;
  line-height: 1.8;
  font-weight: 300;
  max-width: 62ch;
}

/* ─── Figure: contained image with a caption ─────────────────────
   Distinct from .project-gallery__full, which crops full-bleed. A
   caption is the point: it lets a shop or raise photo carry the
   narrative weight a finished shot would otherwise carry. */

.project-figure {
  margin: 0;
  padding: 0 0 var(--sp-md);
}

.project-figure__frame {
  position: relative;
  width: 100%;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: rgba(26, 25, 22, 0.06);
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 16px;
}

.project-figure__frame img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.project-figure--portrait .project-figure__frame { aspect-ratio: 4 / 5; }
.project-figure--wide     .project-figure__frame { aspect-ratio: 16 / 9; }

/* Drawings and renderings must not be cropped — they're contained on
   white, the way a drawing sits on a sheet. */
.project-figure--drawing .project-figure__frame {
  aspect-ratio: 3 / 2;
  background: var(--white);
  border: 1px solid rgba(26, 25, 22, 0.12);
  padding: 28px;
}

.project-figure--drawing .project-figure__frame img {
  position: relative;
  object-fit: contain;
}

.project-figure__caption {
  margin-top: 14px;
  font-size: 13px;
  line-height: 1.7;
  font-weight: 300;
  color: var(--muted);
  max-width: 58ch;
}

/* Credit line for architect- or photographer-supplied images. */
.project-figure__credit {
  display: block;
  margin-top: 6px;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--muted);
  opacity: 0.8;
}

/* ─── Two figures side by side ───────────────────────────────────
   Stacks on phones. Figures of different aspect ratios align at the
   top, which reads as deliberate rather than as a layout accident. */

.project-figures {
  display: grid;
  grid-template-columns: 1fr;
  gap: 28px;
  align-items: start;
  padding-bottom: var(--sp-md);
}

.project-figures .project-figure {
  padding-bottom: 0;
}

@media (min-width: 720px) {
  .project-figures { grid-template-columns: 1fr 1fr; gap: 32px; }
}

/* ═══════════════════════════════════════════════════════════════════
   FRAME STUDIES — paste at the end of assets/styles.css,
   AFTER the project-tiers block (it uses .project-figure--drawing).

   One addition: spec rows inside a study reuse the meta-bar item
   styles but sit inside the page flow, tightened up, with a rule
   above and below so each study reads as a self-contained sheet.
   ═══════════════════════════════════════════════════════════════════ */

.study {
  border-bottom: 1px solid rgba(26, 25, 22, 0.15);
  padding-bottom: var(--sp-lg);
}

.study__specs {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 20px 32px;
  padding: 24px 0 32px;
  border-top: 1px solid rgba(26, 25, 22, 0.15);
  margin-top: 4px;
}

@media (min-width: 720px) {
  .study__specs { grid-template-columns: repeat(4, 1fr); }
}


/* ═══ 2026-09-14 audit fixes (see FIXES-2026-09-14.md) ═══ */

/* Section rules sit at content width, like every other divider. Replaces the inline border styles. */
.section-ruled { padding: var(--sp-lg) 0 0; }
.section-ruled > .wrap { border-bottom: 1px solid rgba(26,25,22,0.15); padding-bottom: var(--sp-lg); }
.section-ruled-top { padding-top: 0; }
.section-ruled-top > .wrap { border-top: 1px solid rgba(26,25,22,0.15); padding-top: var(--sp-lg); }

/* The small italic links in the drawer and footer. */
.utility-link { font-size: 13px; color: var(--muted); font-style: italic; cursor: pointer; }
.utility-link:visited { color: #6B675F; } /* literal hex — var() is blocked inside :visited */
.utility-link[aria-current="page"] { color: var(--accent); }

/* Tap targets: 44px of hit area on small links without changing how they look. */
.hero__cta, .text-link, .footer__nav a, .footer__contact a, .utility-link, .project-pager__all, .project-nav__link, .article__meta a, .article__footer-text a, .nav-drawer__sub a, .fact-link { position: relative; }
.hero__cta::before, .text-link::before, .footer__nav a::before, .footer__contact a::before, .utility-link::before, .project-pager__all::before, .project-nav__link::before, .article__meta a::before, .article__footer-text a::before, .nav-drawer__sub a::before, .fact-link::before { content: ''; position: absolute; left: 0; right: 0; top: -14px; bottom: -14px; }
.side-label::before { content: ''; position: absolute; top: -10px; bottom: -10px; left: -12px; right: -12px; }
/* Footer links are only 18px of line-height, so the shared -12px extension
   above (18 + 12 + 12 = 42px) lands 2px short of the 44px minimum — the
   one place that fix undershoots. Footer-only override with a touch more. */
.footer__nav a::before, .footer__contact a::before { top: -14px; bottom: -14px; }

/* Phones zoom into fields under 16px. */
@media (max-width: 767px) { .form-input, .form-textarea, .custom-select__trigger { font-size: 16px; } }

/* Corner marks stay visible over pale skies. */
.joinery-corner svg { filter: drop-shadow(0 0 1.5px rgba(0,0,0,0.45)); }

/* Headings balance their lines; phone headlines never carry a forced break. */
.heading { text-wrap: balance; }
@media (max-width: 639px) { .page-header__h1 br { display: none; } }

/* Story: the team block gets a heading like its neighbours. */
.team__heading { margin-bottom: 12px; }

/* 404: half the air. */
#page-404 .page-header { padding-bottom: var(--sp-md); }
#page-404 .page-header .wrap > .fade-in { padding-bottom: var(--sp-md); margin-bottom: calc(-1 * var(--sp-md)); }
#page-404 .cta-section { padding-top: var(--sp-md); }

/* Footer colophon wraps as a unit on phones. */
.footer__colophon { white-space: normal; }
/* 404: one rule, not two (the CTA block's own rule is redundant under the header rule). */
#page-404 .cta-section__inner { border-top: 0; margin-top: 0; padding-top: 0; }

/* Section rules: exactly content width at every size (the wrap's own padding is 42 / 32 / 0). */
:root { --wrap-pad: 42px; }
@media (min-width: 640px) { :root { --wrap-pad: 32px; } }
@media (min-width: 1024px) { :root { --wrap-pad: 0px; } }
.section-ruled > .wrap, .section-ruled-top > .wrap, .pillars-section .wrap, .home-cta .wrap { position: relative; border: 0 !important; }
.section-ruled > .wrap::after, .pillars-section .wrap::after { content: ''; position: absolute; left: var(--wrap-pad); right: var(--wrap-pad); bottom: 0; height: 1px; background: rgba(26,25,22,0.15); }
.section-ruled-top > .wrap::before, .home-cta .wrap::before { content: ''; position: absolute; left: var(--wrap-pad); right: var(--wrap-pad); top: 0; height: 1px; background: rgba(26,25,22,0.15); }
/* Phone headlines: tighter tracking, and a long word can never leave the column. */
@media (max-width: 639px) { .page-header__h1 { letter-spacing: 0.01em; overflow-wrap: anywhere; } }
/* White rails over a photo carry a soft shadow so they read on pale skies and mist. */
body.rails-hidden .side-label, .side-label:not(.is-dark) { text-shadow: 0 1px 3px rgba(0,0,0,0.45); }

/* Soft page transitions — REMOVED 2026-09-25. The cross-document
   `@view-transition { navigation: auto }` crossfade that lived here was
   pulled after reading Kayle's iPhone screen recording frame by frame:
   iOS Safari painted the new page first, THEN started the transition —
   replaying the old page's last frame on top and crossfading it away.
   Measured as a brightness spike on every navigation (worst leaving the
   open nav drawer: a full-screen light frame flashing over the Home
   hero), and it got MORE visible as the site's own entrance fades were
   removed, since those had been starting each new page at opacity 0
   and accidentally hiding the early paint. Navigation is plain and
   instant now; the drawer slides closed before the page changes
   (site.js). Don't bring this back on the strength of a desktop
   browser — only a real-phone recording can show the bug. */

/* Line breaks: no lone last words (2026-10-03). Paragraphs avoid a one-word last line; short labels and names balance their lines. */
p, li, dd, blockquote { text-wrap: pretty; }
.pillar__title, .partner-row__name, .testimonial__name, .step__title, .step__subtitle, .fact-v { text-wrap: balance; }
@media (max-width: 639px) { .brand-statement__text { text-wrap: pretty; } }

/* Batch 3 layout (2026-10-03) */
/* Comfortable line length for step and FAQ text; figures keep the full column */
.step__body > p { max-width: 64ch; }
.step--faq .step__body { max-width: 720px; }
/* Figures inside a step: two up only when the column can hold two 280px figures; links line up at the bottom */
.step__body .project-figures { grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr)); align-items: stretch; }
.step__body .project-figure { display: flex; flex-direction: column; }
.step__body .project-figure__caption { flex: 1; display: flex; flex-direction: column; }
.step__body .project-figure__caption > span { margin-top: auto !important; padding-top: 14px; }
/* Home: proof list under Selected Projects, lined up with the project cards */
.proof-list { list-style: none; margin-top: var(--sp-sm); border-top: 1px solid rgba(26,25,22,0.15); }
.proof-list li { border-bottom: 1px solid rgba(26,25,22,0.15); }
.proof-list a { display: block; padding: 14px 0; font-size: 15px; line-height: 1.6; color: inherit; text-decoration: none; }
.proof-list strong { font-weight: 500; }
.proof-list__name, .proof-list__fact { display: block; }
.proof-list__name { margin-bottom: 2px; }
@media (min-width: 640px) { .proof-list a { display: grid; grid-template-columns: 1fr 1fr; column-gap: 3px; padding: 16px 0; } .proof-list__name { margin-bottom: 0; } .proof-list__fact { padding-left: 24px; } }
/* Home pillars: a narrower number column so titles don't stack */
.pillar { grid-template-columns: 24px 1fr; gap: 12px; }
/* Hover for the new row links, same accent and timing as .text-link */
.pillar__title, .proof-list a, .owner-row .step__title { transition: color 0.2s; }
.pillar:hover .pillar__title, .pillar:focus-visible .pillar__title, .proof-list a:hover, .proof-list a:focus-visible, .owner-row:hover .step__title, .owner-row:focus-visible .step__title { color: var(--accent); }
/* Home Our Story block on tablets: the photo fills the column beside the longer text */
@media (min-width: 640px) and (max-width: 1023px) { .about__inner { align-items: stretch; } .about__img { aspect-ratio: auto; } }
@media (max-width: 639px) {
  /* Home brand statement reads as a paragraph on phones */
  .brand-statement { padding: var(--sp-lg) 0; }
  .brand-statement__text { text-align: left; font-size: 19px; }
  /* Closing paragraphs with a long email address */
  .cta-section__body { text-wrap: balance; }
}

/* Planning a project: the six-stop path from first call to raising day (2026-10-08). Each stop links to its step on the Process page. */
.journey { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: 1fr; }
.journey__stop { position: relative; padding: 0 0 26px 34px; }
.journey__stop::before { content: ''; position: absolute; left: 0; top: 5px; width: 11px; height: 11px; border-radius: 50%; border: 1px solid var(--ink); background: var(--bg); box-sizing: border-box; }
.journey__stop:not(:last-child)::after { content: ''; position: absolute; left: 5px; top: 16px; bottom: -5px; width: 1px; background: rgba(26,25,22,0.25); }
.journey__stop:last-child::before { background: var(--ink); }
.journey__stop a { display: block; min-height: 44px; color: inherit; text-decoration: none; line-height: 1.4; }
.journey__num { display: block; font-size: 11px; color: var(--muted); letter-spacing: 0.1em; margin-bottom: 6px; }
.journey__title { display: block; font-family: var(--f-head); font-size: clamp(13px,1.4vw,15px); text-transform: uppercase; letter-spacing: 0.08em; line-height: 1.4; }
.journey__line { display: block; margin-top: 6px; max-width: 40ch; font-size: 15px; line-height: 1.6; color: var(--muted); }
/* the linked stops (Process page) use the site's pencil-line underline, like .text-link; box-decoration-break keeps it on every line of a two-line title */
.journey__stop a .journey__u { display: inline; background-image: linear-gradient(currentColor, currentColor); background-size: 0% 1px; background-repeat: no-repeat; background-position: left calc(100% - 1px); transition: background-size 0.35s ease; -webkit-box-decoration-break: clone; box-decoration-break: clone; }
.journey__stop a:hover .journey__u, .journey__stop a:focus-visible .journey__u { background-size: 100% 1px; }
@media (prefers-reduced-motion: reduce) { .journey__stop a .journey__u { transition: none; } }
@media (min-width: 900px) {
  .journey { grid-template-columns: repeat(6, 1fr); column-gap: 24px; }
  .journey__stop { padding: 32px 0 0; }
  .journey__stop::before { top: 0; }
  .journey__stop:not(:last-child)::after { left: 11px; right: -24px; top: 5px; bottom: auto; width: auto; height: 1px; }
  .journey__line { font-size: 14px; }
}
.step[id^="step-"] { scroll-margin-top: 96px; }

/* Pre-launch polish (2026-10-08) */
/* No paragraph, caption or short line ends on one lonely word where the browser can help it. */
p, figcaption, li, .journey__line, .step__subtitle, .step__body p, .belief__body, .team-card__role, .project-card__meta { text-wrap: pretty; }
/* Timeline: titles keep room for two lines on wide screens, so the lines under them start level. */
@media (min-width: 900px) { .journey__title { min-height: 2.8em; } }
.portrait-pending { display: block; width: 100%; height: 100%; }
