/*
  CarlosSuarezArt — Layout
  Structural page scaffolding: containers, the header/nav, the footer,
  and the asymmetric grid primitive used for artwork listings. This file
  has no opinion about individual components' internal styling — see
  components.css for that.
*/

/* ===== Containers ===== */

.container{
  max-width: var(--content-max);
  margin: 0 auto;
  padding-left: var(--space-4);
  padding-right: var(--space-4);
}

.container--reading{
  max-width: var(--reading-max);
  margin: 0 auto;
}

/* Hero / single-artwork moments break out to full viewport width
   (Gagosian-style) — deliberately outside the .container constraint. */
.full-bleed{
  width: 100%;
}

/* ===== Header / primary nav =====
   A thin, quiet bar — Gagosian-quiet, per the visual design system.
   Transparent, no fill, sits directly on Gallery White. A hairline
   bottom border everywhere except Home, where it stays invisible
   during the ceremony (see home.css / .site-header--home). */

.site-header{
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 72px;
  padding: 0 var(--space-4);
  border-bottom: 0.5px solid var(--color-border);
  /* On the Homepage, .site-header--home's ceremony animation touches
     transform, which creates its own stacking context for the whole
     header even once the animation has settled (the computed transform
     reads as an identity matrix, but the element still counts as
     "having a transform" for stacking purposes). Without an explicit
     z-index here, that traps .site-nav's own z-index inside the header's
     local context, so the header (as one unit, z-index:auto) still lost
     to .hero__frame's z-index:1 (home.css) at the outer level — the real
     cause of the mobile Collections-link tap bug. This must sit above
     any content z-index on any page, on purpose, always. */
  z-index: 10;
}

.site-header--home{
  border-bottom: none;
}

/* Toggled by nav.js for exactly as long as the mobile menu is open.
   .site-header--home's own ceremony animation (home.css: "reveal-up")
   animates BOTH transform and opacity — confirmed directly from that
   animation's rule, the same two properties html.csa-skip already
   force-resets for the same reason. Either one alone creates a new
   containing block for position:fixed descendants per the CSS spec (an
   opacity other than 1, exactly as much as a transform, does this) — so
   neutralizing only transform still left a real window, mid-ceremony,
   where the header's opacity hadn't yet reached 1 and .site-nav's
   position:fixed silently anchored to the header's own 72px box instead
   of the true viewport. Confirmed by testing with a fresh session
   (ceremony actually running, not skipped): Collections/Contact were
   visually positioned correctly but did not receive taps at all,
   exactly matching the reported symptom. Forcing both here, for exactly
   as long as the menu is open, removes every containing block the
   ceremony can create, regardless of where in its timeline it is. */
.nav-open-no-transform{
  transform: none !important;
  opacity: 1 !important;
}

/* Locks page scroll while the full-height mobile menu is open — without
   this, the Hero and page content underneath remain scrollable, which
   both looks broken and lets a visitor scroll content behind an
   ostensibly full-screen panel.

   Also neutralizes transform/opacity on body itself, for the same
   containing-block reason as .nav-open-no-transform above, but sitewide
   rather than Homepage-only: EVERY page runs a brief page-load fade-in
   animation on <body> (--duration-fade in tokens.css), which sets
   opacity < 1 for that animation's duration. If the menu is opened
   during that window, body's own opacity would create a containing
   block for .site-nav's position:fixed, the exact same failure mode as
   the Homepage ceremony, just shorter-lived and present on every page. */
body.nav-scroll-lock{
  overflow: hidden;
  transform: none !important;
  opacity: 1 !important;
}

.site-header__wordmark{
  font-family: var(--font-serif);
  font-size: 1rem;
  letter-spacing: 0.1em;
  color: var(--color-blue);
  text-decoration: none;
  white-space: nowrap;
}

.site-nav{
  display: flex;
  gap: var(--space-4);
  list-style: none;
}

.site-nav a{
  font-family: var(--font-sans);
  font-size: var(--text-micro);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--color-gray);
  text-decoration: none;
  padding-bottom: 4px;
  border-bottom: 0.5px solid transparent;
  transition: color 0.4s ease, border-color 0.4s ease;
}

.site-nav a:hover,
.site-nav a[aria-current="page"]{
  color: var(--color-blue);
  border-color: var(--color-blue);
}

/* Mobile nav toggle — thin-line only, no fill, no personality
   (Bible §17 Iconography & Button Philosophy). The icon itself stays
   visually minimal (28x20) but the tappable button is 44x44 — WCAG's
   comfortable touch-target minimum — so restraint never comes at the
   cost of usability (Bible §18: Human Connection extends to every
   visitor). The icon is centered inside the larger invisible hit area. */
.nav-toggle{
  display: none;
  width: 44px;
  height: 44px;
  position: relative;
  background: none;
  border: none;
  cursor: pointer;
  /* Must stay above .site-nav's own z-index (below) so the toggle — which
     turns into an X when open — remains visible and tappable to close the
     menu once the full-height panel is covering the page beneath it. */
  z-index: 21;
}

.nav-toggle span{
  position: absolute;
  left: 50%;
  width: 24px;
  height: 1px;
  background: var(--color-black);
  transform: translateX(-50%);
  transition: transform 0.35s var(--ease-gentle), opacity 0.35s var(--ease-gentle);
}

.nav-toggle span:nth-child(1){ top: 16px; }
.nav-toggle span:nth-child(2){ top: 22px; }
.nav-toggle span:nth-child(3){ top: 28px; }

.nav-toggle[aria-expanded="true"] span:nth-child(1){ transform: translateY(9px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] span:nth-child(2){ opacity: 0; }
.nav-toggle[aria-expanded="true"] span:nth-child(3){ transform: translateY(-9px) rotate(-45deg); }

@media (max-width: 760px){
  .nav-toggle{ display: block; }

  .site-nav{
    display: none;
    /* position:fixed here is only unambiguous while .nav-open-no-transform
       (above) has removed any transform/opacity from the header and body
       — otherwise an animated ancestor becomes this element's containing
       block instead of the real viewport, and "fixed" silently stops
       meaning "fixed to the screen." nav.js applies those classes for
       exactly as long as this panel is open, so that part is handled.
       Separately, and confirmed by direct testing: relying on
       top+bottom (both set) with height:auto to imply the full height
       does NOT reliably resolve while the Homepage's ceremony animation
       is actively running elsewhere on the page — even with every
       containing-block property clean, the auto-height calculation came
       out as just the content's own height (one row) instead of the
       full remaining viewport, so Collections/Contact rendered off the
       bottom edge of this panel's own box. An explicit height computed
       from vh sidesteps that resolution path entirely and was confirmed
       correct in every state tested (ceremony running, settled, and
       skipped) — real, load-bearing, not decorative. */
    position: fixed;
    top: 72px;
    right: 0;
    left: 0;
    height: calc(100vh - 72px);
    /* No overflow-y here on purpose. This panel only ever holds a few
       short nav links — it never actually needs to scroll on any real
       phone — but marking it as a scrollable container was enough on its
       own to break taps on real touch hardware: a human finger is never
       perfectly stationary between touchstart and touchend, and on a
       scrollable ancestor the browser's gesture recognizer treats that
       motion as a scroll attempt and never synthesizes the click at all.
       That's a native input-pipeline decision, invisible to any
       .click()-based or mouse-based test (which is why every previous
       round of testing in this file's history missed it) — confirmed via
       code audit: no pointer-events restriction, no preventDefault, no
       overlay, and zero touch-event listeners anywhere in nav.js or any
       other page script, which rules out anything JS-side as the cause. */
    flex-direction: column;
    gap: var(--space-3);
    background: var(--color-white);
    padding: var(--space-4);
    /* Without an explicit z-index, this panel has no defense against any
       other positioned element on the page that declares its own —
       .hero__frame's z-index:1 (home.css) was winning the stacking order
       and silently capturing taps meant for these links, even though the
       link text was fully visible and its href was completely correct.
       20 clears every current content z-index on the site (highest found
       elsewhere is 5) with real headroom for future sections, while
       staying below the skip-to-content link's 100 (base.css) and
       .nav-toggle's own 21 (so the toggle — which turns into an X —
       stays tappable to close this panel once it's covering the page). */
    z-index: 20;
  }

  .site-nav.is-open{
    display: flex;
  }
}

/* ===== Footer ===== */

.site-footer{
  text-align: center;
  padding: var(--space-6) var(--space-4) var(--space-7);
  border-top: 0.5px solid var(--color-border);
}

.site-footer p{
  font-size: var(--text-micro);
  letter-spacing: 0.1em;
  color: var(--color-border);
  text-transform: uppercase;
  max-width: none;
}

/* ===== Asymmetric grid primitive (Bible §10) =====
   Museum-catalogue in spirit, never a uniform e-commerce tile grid.
   Column spans are content-driven and vary per listing — these three
   stagger patterns are the recurring shapes used across Gallery,
   Collection detail, and New Works, not a rigid fixed system. */

.stagger-grid{
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: var(--space-7) var(--space-4);
}

/* Offsets use transform, not margin-top: a visual stagger that doesn't
   add to document flow height. Margin-based offsets compound with each
   card's own (now-variable, true-ratio) height and can inflate a
   three-card section well past what the composition intends. Modest
   values here read as "hung at slightly different heights," not a
   slow cumulative descent down the page. */
.stagger-grid .span-a{ grid-column: 1 / 8; }
.stagger-grid .span-b{ grid-column: 8 / 13; transform: translateY(var(--space-4)); }
.stagger-grid .span-c{ grid-column: 3 / 10; transform: translateY(var(--space-2)); }

@media (max-width: 760px){
  .stagger-grid{
    grid-template-columns: 1fr;
    gap: var(--space-8);
  }
  .stagger-grid .span-a,
  .stagger-grid .span-b,
  .stagger-grid .span-c{
    grid-column: 1;
    transform: none;
  }
}

/* ===== Museum grid — a scalable listing for an arbitrary number of
   pieces (a full Collection, later a full Gallery), where .stagger-grid's
   fixed three-item composition doesn't apply. Two columns, alternating
   items offset vertically by one fixed amount (not additive — total
   height never inflates regardless of how many pieces there are), which
   reads as "hung at slightly different heights" rather than a uniform,
   interchangeable tile grid (Bible §10). ===== */
.museum-grid{
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-8) var(--space-5);
}

.museum-grid > *:nth-child(even){
  margin-top: var(--space-8);
}

@media (max-width: 760px){
  .museum-grid{
    grid-template-columns: 1fr;
    gap: var(--space-7);
  }
  .museum-grid > *:nth-child(even){
    margin-top: 0;
  }
}
