:root {
  --bg: #f0e4d6;
  --ink: #3f372d;
  --fg: var(--ink);
}

* { box-sizing: border-box; }

/* Self-hosted, not loaded via Google Fonts: the salt/ss01 stylistic-
   alternates feature below (single-storey g, untailed l) is present in
   Public Sans's own source but silently doesn't render through Google's
   hosted delivery — confirmed by testing the exact same CSS against
   Google's file vs. these files pulled straight from the font's own
   GitHub repo (uswds/public-sans/fonts/webfonts), where it works.
   Matches a known open report of the same gap (uswds/public-sans#243). */
@font-face {
  font-family: 'Public Sans';
  src: url('../assets/fonts/PublicSans-Regular.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Public Sans';
  src: url('../assets/fonts/PublicSans-SemiBold.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

/* Licensed display face (Light only) — used as live text for the
   homepage hero, mobile menu branding, project page titles and journal
   post titles, replacing the pre-rendered SVG wordmarks and the Georgia
   stand-in. Metrics (units/em 1000): cap-height 695, x-height 474. */
@font-face {
  font-family: 'ABC Arizona Flare';
  src: url('../assets/fonts/ABCArizonaFlare-Light.woff2') format('woff2');
  font-weight: 300;
  font-style: normal;
  /* block, not swap: at display sizes a flash of a serif stand-in
     before the real face loads is far more jarring than a brief
     invisible period. */
  font-display: block;
}

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  overflow: hidden;
  background: var(--bg);
  color: var(--fg);
  /* Public Sans replaces Helvetica Now Text — Helvetica Now was never
     actually licensed/loaded as a real font file here, so every visitor
     was already seeing the fallback (Helvetica Neue on Mac/iOS, Arial
     elsewhere); that same fallback chain is kept after Public Sans as a
     safety net if the self-hosted files above fail to load for any
     reason. Medium (500) has been remapped to Public Sans's SemiBold
     (600) throughout the site to match Helvetica Now Medium's visual
     weight — see the font-weight rules below and per-page styles. */
  font-family: 'Public Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  /* Turns on the single-storey alternate g and untailed alternate l
     site-wide (see the @font-face comment above for why this needs the
     self-hosted files to actually take effect). Only affects Public
     Sans itself; the Helvetica/Arial fallback chain has no such feature
     and just ignores this. */
  font-feature-settings: "salt" 1;
}

a { text-decoration: none; color: inherit; }

/* Visually hidden but available to screen readers and search engines —
   used for the per-page <h1> (the visible page title is set in brand
   artwork, so the real heading text is carried here instead). */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

.page {
  position: relative;
  display: grid;
  grid-template-columns: repeat(24, minmax(0, 1fr));
  gap: 20px;
  padding: 0 20px;
  min-width: 960px;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
}

/* Logo — a small fixed-size monogram mark (was the "Andrew Taberner
   Architects" wordmark in text; replaced site-wide per the updated
   Figma nav). Same 46x44 size at every breakpoint (Figma specifies the
   same box on both its mobile and desktop frames — a small icon, not
   something that needs to scale with viewport width). Ink-coloured
   asset for this rule; the homepage hero overrides it to the white
   copy (home-monogram.svg) below, same "two colour variants" pattern
   already used for the footer wordmark. */
.logo {
  position: fixed;
  left: 20px;
  top: 14px;
}
.logo a {
  display: block;
}
.logo img {
  display: block;
  width: 46px;
  height: 44px;
}

/* Primary nav */
.nav {
  position: fixed;
  left: calc(25% + 15px);
  top: 14px;
  width: 335px;
}
.nav ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
.nav li {
  display: block;
}
.nav a,
.nav .pill-current {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 24px;
  padding: 0 8px;
  margin-left: -8px;
  border-radius: 12px;
  font-size: 12px;
  font-weight: 600;
  line-height: 20px;
  letter-spacing: 0.33px;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--fg);
  opacity: 1;
  transition: opacity 150ms ease;
}
.nav a:hover {
  opacity: 0.5;
}
.nav .pill-current {
  opacity: 0.5;
}

.menu-toggle {
  display: none;
}

.mobile-menu {
  display: none;
}

/* Body copy */
.intro {
  position: fixed;
  left: calc(25% + 15px);
  bottom: 79.56px;
  width: calc(25vw - 25px);
  max-width: 400px;
  font-size: 13px;
  font-weight: 400;
  line-height: 20px;
  letter-spacing: 0.36px;
  color: var(--fg);
}
.intro p { margin: 0; }

/* Location tag, top right — shared across pages (was previously
   duplicated per-page since only the homepage used it; now that a
   second page needs the identical rule, it lives here instead). A
   page can still override this for its own mobile treatment, as the
   homepage does. */
.location {
  position: relative;
  grid-column: 20 / span 5;
  grid-row: 1;
  justify-self: stretch;
  align-self: start;
  padding: 14px 0 0;
  margin: 0;
  font-size: 12px;
  font-weight: 600;
  line-height: 20px;
  letter-spacing: 0.33px;
  text-transform: uppercase;
  text-align: right;
  color: var(--fg);
  white-space: nowrap;
}

/* Mobile layout */
@media (max-width: 1023px) {
  html, body {
    height: auto;
    overflow: visible;
  }

  .page {
    display: block;
    min-width: 0;
    height: auto;
    overflow: visible;
    padding: 0 15px;
  }

  /* Not pinned: it's a normal flow element now, so it scrolls away
     with the page and is only visible again back at the top. The
     negative margin cancels .page's own 15px side padding (which a
     fixed header used to ignore entirely) so it still spans full
     width, with its own padding reinstating the same visual inset.
     position:relative (plus z-index) is needed too, on the homepage
     specifically: .hero-media is position:absolute, and a positioned
     element always paints above a non-positioned one regardless of
     DOM order — without this the header (and its Menu button) was
     rendering invisibly underneath the hero photo. */
  .mobile-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    position: relative;
    z-index: 1;
    height: 88px;
    margin: 0 -15px;
    padding: 0 15px;
    background: rgba(240, 228, 214, 0.72);
  }

  .logo,
  .nav {
    position: static;
    width: auto;
  }

  .nav {
    display: flex;
    align-items: center;
  }

  .nav ul {
    display: none;
  }

  .menu-toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 62px;
    height: 24px;
    padding: 8px 12px;
    border: none;
    border-radius: 40px;
    background: var(--ink);
    color: #fff;
    font-family: inherit;
    font-size: 12px;
    font-weight: 600;
    line-height: 20px;
    letter-spacing: 0.33px;
    text-transform: uppercase;
    cursor: pointer;
    opacity: 1;
    transition: opacity 200ms ease;
  }
  .menu-toggle:hover {
    opacity: 0.8;
  }

  .intro {
    position: static;
    width: 100%;
    max-width: 540px;
    margin-top: 80px;
    padding: 40px 0;
  }

  /* Expanded mobile menu */
  body.menu-open {
    overflow: hidden;
  }

  /* While the panel is expanded the header pins to the top regardless
     of scroll position — same reasoning as the mobile-menu panel
     below, which is anchored to a fixed top:88px assuming the header
     is sitting right above it. */
  body.menu-open .mobile-header {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 20;
    margin: 0;
    background: var(--ink);
  }

  body.menu-open .logo a {
    color: #fff;
  }

  /* The monogram is an ink-coloured <img> on every page except the
     homepage (which already uses a white copy), so it needs inverting
     to read against the dark panel — brightness(0) flattens it to black
     first so the invert lands on pure white regardless of source colour. */
  body.menu-open .logo img {
    filter: brightness(0) invert(1);
  }

  body.menu-open .menu-toggle {
    background: #fff;
    color: var(--ink);
  }

  .mobile-menu {
    display: block;
    position: fixed;
    top: 88px;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 15;
    background: var(--ink);
    overflow-y: auto;
    visibility: hidden;
    opacity: 0;
  }

  body.menu-open .mobile-menu {
    visibility: visible;
    opacity: 1;
  }

  .mobile-menu-links {
    display: flex;
    flex-direction: column;
    gap: 24px;
    padding: 40px 15px 0;
    margin: 0;
    list-style: none;
  }

  .mobile-menu-links li {
    width: 100%;
  }

  .mobile-menu-link {
    position: relative;
    display: flex;
    align-items: center;
    width: 100%;
    padding-bottom: 8px;
    color: #fff;
    font-size: 12px;
    font-weight: 600;
    line-height: 20px;
    letter-spacing: 0.33px;
    text-transform: uppercase;
  }

  .mobile-menu-link::after {
    content: '';
    position: absolute;
    left: 0;
    bottom: 0;
    width: 100%;
    height: 1px;
    background: rgba(255, 255, 255, 0.1);
  }

  /* ANDREW / TABERNER lockup — live text now (ABC Arizona Flare Light),
     same sizing as the homepage hero's own brand marks, just bottom-
     anchored here instead of vertically centred. font-size is the old
     SVG height formula (calc(6.816vw - 2.556px), 23px at the 375px
     reference) divided by the font's cap-height (0.695em); with
     line-height set to that same 0.695 each box is exactly cap-top to
     baseline, so bottom: 91.889px lands the baseline exactly where the
     old graphic's bottom edge sat. TABERNER carries extra tracking
     (0.0687em) to span the same width as the original artwork, with a
     matching negative margin so the trailing tracking after the last
     letter (and its -0.013em side-bearing) don't push the ink off the
     right margin. */
  .mobile-menu-brand {
    position: absolute;
    left: 15px;
    right: 15px;
    bottom: 91.889px;
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    color: #fff;
    font-family: 'ABC Arizona Flare', Georgia, 'Times New Roman', serif;
    font-weight: 300;
    font-size: calc(9.807vw - 3.678px);
    line-height: 0.695;
    text-transform: uppercase;
    white-space: nowrap;
  }
  .mobile-menu-brand .brand-andrew {
    margin-left: -0.004em;
  }
  .mobile-menu-brand .brand-taberner {
    letter-spacing: 0.0687em;
    margin-right: -0.0557em;
  }

  /* The small ARCHITECTS sub-wordmark: fixed 17px (not fluid, same as
     the old fixed-size graphic), tracked 0.0314em to match the old
     105px width. Cap-top sits at 44.9px + 11.8px above the panel's
     bottom — i.e. baseline at 44.9px (the old graphic's bottom edge at
     44.754px included the 0.01em overshoot of the round letters). */
  .mobile-menu-architects-sub {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 44.9px;
    text-align: center;
    padding-left: 0.0314em;
    color: #fff;
    font-family: 'ABC Arizona Flare', Georgia, 'Times New Roman', serif;
    font-weight: 300;
    font-size: 17px;
    line-height: 0.695;
    letter-spacing: 0.0314em;
    text-transform: uppercase;
    white-space: nowrap;
  }

  /* This sits after the structural rules above on purpose: several of
     them (::after's base "width: 100%" fallback for reduced-motion
     users) declare the same properties this block animates, and at
     equal specificity the later rule in the file wins the cascade —
     so the animated versions must come last to actually take effect. */
  @media (prefers-reduced-motion: no-preference) {
    .mobile-menu {
      transition: opacity 400ms cubic-bezier(0.16, 1, 0.3, 1),
                  visibility 0s linear 400ms;
    }
    body.menu-open .mobile-menu {
      transition: opacity 400ms cubic-bezier(0.16, 1, 0.3, 1),
                  visibility 0s linear 0s;
    }

    /* Keylines draw in first, one at a time, top to bottom — each line
       itself grows left to right, since width simply animates up from
       0 at a fixed left edge. Only once every line has finished does
       the link text fade in, all at once, no movement — the branding
       at the bottom is left alone here so it stays visible throughout
       (it just appears with the panel itself). */
    .mobile-menu-link::after {
      width: 0;
      transition: width 350ms cubic-bezier(0.16, 1, 0.3, 1);
    }

    body.menu-open .mobile-menu-link::after {
      width: 100%;
    }

    .mobile-menu-links li:nth-child(1) .mobile-menu-link::after { transition-delay: 80ms; }
    .mobile-menu-links li:nth-child(2) .mobile-menu-link::after { transition-delay: 150ms; }
    .mobile-menu-links li:nth-child(3) .mobile-menu-link::after { transition-delay: 220ms; }
    .mobile-menu-links li:nth-child(4) .mobile-menu-link::after { transition-delay: 290ms; }
    .mobile-menu-links li:nth-child(5) .mobile-menu-link::after { transition-delay: 360ms; }

    /* The last keyline starts at 360ms and takes 350ms to draw, so it
       finishes at 710ms; the text fade below waits until just after. */
    .mobile-menu-link-text {
      opacity: 0;
      transition: opacity 350ms ease;
      transition-delay: 750ms;
    }

    body.menu-open .mobile-menu-link-text {
      opacity: 1;
    }
  }
}

/* Page-load and scroll reveal. .reveal is the generic, reusable version
   of the same treatment .project already gets on the Projects page —
   add class="reveal" to anything elsewhere that should fade/lift into
   place as it scrolls into view (site.js observes both classes the
   same way), rather than inventing a new animation per page. */
@media (prefers-reduced-motion: no-preference) {
  .logo,
  .nav li,
  .intro,
  .project,
  .reveal {
    opacity: 0;
    /* A slightly longer lift (was 14px) reads as more deliberate now
       that it starts earlier (see the observer's rootMargin in
       site.js) — enough runway left to still feel like a graceful
       arrival rather than a snap into place. */
    transform: translateY(22px);
    transition: opacity 1100ms cubic-bezier(0.16, 1, 0.3, 1),
                transform 1100ms cubic-bezier(0.16, 1, 0.3, 1);
  }
  .logo.is-visible,
  .nav li.is-visible,
  .intro.is-visible,
  .project.is-visible,
  .reveal.is-visible {
    opacity: 1;
    transform: translateY(0);
  }
  .nav li:nth-child(1) { transition-delay: 80ms; }
  .nav li:nth-child(2) { transition-delay: 140ms; }
  .nav li:nth-child(3) { transition-delay: 200ms; }
  .nav li:nth-child(4) { transition-delay: 260ms; }
  .nav li:nth-child(5) { transition-delay: 320ms; }
  .intro { transition-delay: 380ms; }
}

/* On mobile, .logo lives in persistent header chrome — often
   position:fixed (see each page's own .mobile-header rules) — rather
   than page content, so replaying its fade/lift on every single
   navigation reads as repetitive chrome-churn rather than a
   considered entrance. Excluded here, after the block above so it
   wins on source order (equal specificity); .nav li/.intro/.reveal
   keep the desktop-style page-load feel since they're not persistent
   the same way (.nav's own links are hidden on mobile behind the
   Menu toggle anyway). */
@media (max-width: 1023px) and (prefers-reduced-motion: no-preference) {
  .logo {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* Site footer — shared across any page that includes it. Same layout
   shape at both breakpoints: a monogram + "brand" text stack + contact
   block, re-columned per breakpoint. The old two-SVG "A.T. /
   ARCHITECTS" graphic wordmark (ABC Arizona Flare shapes,
   footer-at-mark.svg etc.) is fully retired by this design at both
   breakpoints — replaced by a small text wordmark (Public Sans, live
   text) plus the same ink monogram used in the header logo. A
   signature graphic and a top divider both briefly appeared in earlier
   iterations of this design; this version drops both, per an explicit
   request to remove the keyline and just use a flat 40px bottom
   padding instead — top padding keeps the same total lead-in the
   divider used to share with it (135px mobile / 310px desktop), rather
   than shrinking now that the line itself is gone. */
.footer {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 15px;
  padding: 135px 0 40px;
}

/* display:contents lets the labels/values columns participate
   directly in .footer's own grid as if .footer-contact weren't there
   at all. */
.footer-contact {
  display: contents;
}
.footer-contact-labels {
  grid-column: 1 / span 2;
  grid-row: 2;
  align-self: start;
}
.footer-contact-values {
  grid-column: 3 / span 4;
  grid-row: 2;
  align-self: start;
}
.footer-contact-labels,
.footer-contact-values {
  display: flex;
  flex-direction: column;
}
.footer-contact-item {
  height: 24px;
  display: flex;
  align-items: center;
  margin: 0;
  font-size: 12px;
  font-weight: 400;
  line-height: 20px;
  letter-spacing: 0.33px;
  color: var(--ink);
  white-space: nowrap;
}
.footer-contact-labels .footer-contact-item {
  font-weight: 600;
}
a.footer-contact-item {
  opacity: 1;
  transition: opacity 150ms ease;
}
a.footer-contact-item:hover {
  opacity: 0.5;
}

/* Standalone monogram — same Union artwork as the header logo, just a
   dedicated export here (footer-monogram-mobile.svg) since Figma boxes
   it with its own built-in padding (6px top, ~28px trailing right) to
   exactly fill a 2-column span; used at 100% width so it stays fluid
   with the mobile grid like everything else at this breakpoint. */
.footer-monogram {
  display: block;
  grid-column: 1 / span 2;
  grid-row: 1;
  align-self: start;
}
/* Two <img> tags (mobile/desktop), toggled with display, since the two
   breakpoints use different exports (see below) rather than one asset
   reused at different sizes. */
.footer-monogram img {
  display: none;
}
.footer-monogram img.is-mobile {
  display: block;
  width: 100%;
  height: auto;
}

/* Wordmark text + copyright, grouped as flex column with a 4px gap
   between the two lines — confirmed against Figma metadata at both
   breakpoints (wordmark bottom to copyright top: 24-20=4). */
.footer-brand {
  display: flex;
  flex-direction: column;
  gap: 4px;
  grid-column: 3 / span 4;
  grid-row: 1;
  align-self: start;
  padding-bottom: 80px;
}
/* Same uppercase-label treatment as .nav a / .location (12px/600/
   0.33px tracking). */
.footer-wordmark-text {
  display: block;
  margin: 0;
  font-size: 12px;
  font-weight: 600;
  line-height: 20px;
  letter-spacing: 0.33px;
  text-transform: uppercase;
  color: var(--ink);
  white-space: nowrap;
  opacity: 1;
  transition: opacity 150ms ease;
}
.footer-wordmark-text:hover {
  opacity: 0.5;
}
.footer-copyright {
  margin: 0;
  font-size: 12px;
  line-height: 20px;
  letter-spacing: 0.33px;
  color: rgba(63, 55, 45, 0.5);
  white-space: nowrap;
}

/* Desktop: its own nested 24-col grid, same technique used throughout
   the P&R House page's own modules. 310px padding-top is the same
   total lead-in the divider used to share with the padding (250px
   padding-top + its own 40px box + 20px gap), kept the same now the
   line itself is gone; 40px padding-bottom replaces what used to be
   sized off the contact block's own height. */
@media (min-width: 1024px) {
  .footer {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: repeat(24, minmax(0, 1fr));
    gap: 20px;
    padding: 310px 0 40px;
  }

  .footer-contact-labels {
    grid-column: 19 / span 2;
    grid-row: 1;
  }
  .footer-contact-values {
    grid-column: 21 / span 4;
    grid-row: 1;
  }

  /* Fixed pixel height, not vw-scaled, same "static footer element"
     convention used elsewhere on this page — swaps back to the plain
     shared monogram.svg (tightly cropped, unlike mobile's padded
     export) since a fixed height + aspect-derived width doesn't need
     the built-in padding mobile's fluid width relies on. */
  .footer-monogram {
    grid-column: 1;
    grid-row: 1;
  }
  .footer-monogram img.is-mobile {
    display: none;
  }
  .footer-monogram img.is-desktop {
    display: block;
    width: auto;
    height: 67.913px;
  }

  /* Moved from col 7 to col 3 in a previous iteration of this design.
     The 2px top margin is a small deliberate offset confirmed against
     Figma metadata (the monogram sits at its row's very top, while
     this text stack starts 2px lower). */
  .footer-brand {
    grid-column: 3 / span 3;
    grid-row: 1;
    margin-top: 2px;
    padding-bottom: 0;
  }
}

/* Project detail pages (body.project-page): each one is built as a
   stack of self-contained modules (own local grid, own explicit
   height) rather than the homepage's single fixed-height grid, so a
   couple of things need handling only here. Header/nav are back to
   the shared default position:fixed (no override needed) now that
   the intro module's own parallax scroll is meant to cover them too —
   position:fixed removes an element from grid layout entirely, which
   also means it no longer needs the explicit grid placement/z-index
   this block used to give it to dodge .page's auto-placement. */
@media (min-width: 1024px) {
  /* Each module manages its own internal spacing precisely (e.g. the
     Project Introduction module's own fixed 60px under its graphics)
     — .page's general-purpose row-gap would just add an extra,
     un-designed gap on top of that between modules, so it's removed
     here. Column-gap (unused at this outer level anyway) is left
     alone. */
  body.project-page .page {
    row-gap: 0;
  }
}
