/* ============ NAV ============ */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: var(--bg);
  border-bottom: 1px solid var(--line);
  transition: background-color .5s ease, border-color .5s ease;
}
.nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 24px 44px;
}
.wordmark {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 21px;
  color: var(--ink);
  transition: opacity .4s ease;
}

/* ============ HOMEPAGE LOGO INTRO ============
   Header starts transparent with its own wordmark hidden; a fullscreen
   overlay shows a giant centered wordmark instead, then collapses that
   text down into the nav's corner position while the header's real
   background fades in behind it. See assets/js/main.js for the trigger. */
.site-header.has-logo-intro {
  background: transparent;
  border-bottom-color: transparent;
}
.site-header.has-logo-intro .wordmark { opacity: 0; }
.site-header.has-logo-intro.is-revealed {
  background: var(--bg);
  border-bottom-color: var(--line);
}
.site-header.has-logo-intro.is-revealed .wordmark { opacity: 1; }

.logo-intro {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg);
  pointer-events: none;
}
.logo-intro-text {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(48px, 11vw, 160px);
  color: var(--ink);
  white-space: nowrap;
  transition: transform 1.1s cubic-bezier(0.65, 0, 0.24, 1), opacity 0.6s ease 0.5s;
}
/* Target roughly matches the nav wordmark's resting spot (44px page padding,
   ~24px top padding); good enough across common viewport sizes without
   needing per-frame JS measurement. */
.logo-intro.is-exiting .logo-intro-text {
  transform: translate(calc(-50vw + 150px), calc(-50vh + 46px)) scale(0.15);
  opacity: 0;
}
.logo-intro.is-hidden { display: none; }
@media (prefers-reduced-motion: reduce) {
  .logo-intro { display: none; }
}
.nav-links {
  display: flex;
  gap: 36px;
  list-style: none;
}
.nav-links a {
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--nav-ink);
  font-weight: 400;
}
.nav-item.active > a { color: var(--ink); }
.lang-switch {
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-soft);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 7px 14px;
}

/* ============ MOBILE NAV (hamburger + full-screen drawer) ============
   Hidden entirely on desktop (.nav-toggle display:none by default) —
   .nav-links already handles desktop nav via the mega-menu block below.
   Becomes visible only under the 900px breakpoint, replacing .nav-links
   which goes display:none there (see the RESPONSIVE section). */
.nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: space-between;
  width: 26px;
  height: 18px;
  background: transparent;
  border: none;
  padding: 0;
  cursor: pointer;
  z-index: 210;
  flex-shrink: 0;
}
.nav-toggle span {
  display: block;
  width: 100%;
  height: 2px;
  background: var(--ink);
  transition: transform .25s ease, opacity .2s ease;
}
.nav-toggle.is-active span:nth-child(1) { transform: translateY(8px) rotate(45deg); }
.nav-toggle.is-active span:nth-child(2) { opacity: 0; }
.nav-toggle.is-active span:nth-child(3) { transform: translateY(-8px) rotate(-45deg); }

.mobile-nav {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: var(--bg);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  overflow-y: auto;
  transition: opacity .25s ease, visibility .25s ease;
}
.mobile-nav.is-open {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
}
.mobile-nav-inner {
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-width: 480px;
  margin: 0 auto;
  padding: 110px 32px 60px;
}
.mobile-nav-link {
  font-family: var(--font-ui);
  font-size: 15px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink);
  padding: 14px 0;
  border-bottom: 1px solid var(--line);
}
.mobile-nav-section { display: flex; flex-direction: column; }
.mobile-nav-section .mobile-nav-link { border-bottom: none; }
.mobile-nav-sublinks {
  display: flex;
  flex-direction: column;
  padding: 0 0 10px 18px;
  border-bottom: 1px solid var(--line);
}
.mobile-nav-sublinks a {
  font-family: var(--font-ui);
  font-size: 13px;
  color: var(--ink-soft);
  padding: 8px 0;
}
.mobile-nav-lang {
  display: inline-block;
  align-self: flex-start;
  margin-top: 20px;
  font-family: var(--font-ui);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-soft);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 7px 14px;
}

/* ============ MEGA MENU ============ */
.nav-item.has-mega { position: relative; }
.mega-menu {
  /* top: 100% with zero gap is deliberate — any gap between the trigger
     and the menu is dead space the cursor has to cross, and CSS :hover
     drops the instant it leaves the li's box, so the menu vanishes before
     the mouse ever reaches it. Visual breathing room comes from the
     30px padding below instead of a positional offset. */
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 30px 40px;
  min-width: 620px;
  box-shadow: 0 24px 48px -24px rgba(48, 45, 40, 0.25);
  opacity: 0;
  visibility: hidden;
  transition: opacity .22s ease, visibility .22s ease;
  z-index: 50;
}
.nav-item.has-mega:hover .mega-menu,
.nav-item.has-mega:focus-within .mega-menu,
.mega-menu.is-open {
  opacity: 1;
  visibility: visible;
}
.mega-menu-inner {
  display: flex;
  gap: 56px;
}
.mega-cat {
  font-family: var(--font-display);
  font-style: italic;
  font-size: 21px;
  color: var(--ink);
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.mega-cat-count {
  font-family: var(--font-ui);
  font-style: normal;
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-soft);
  opacity: 0.75;
}

/* ============ HERO ============ */
.hero {
  position: relative;
  height: 92vh;
  min-height: 560px;
  overflow: hidden;
}
/* Outer wrapper still gets the parallax translateY from main.js — unchanged hook */
.hero-image-layer {
  position: absolute;
  inset: -6%;
  overflow: hidden;
}
/* Each slide stacks in the same spot; only .is-active is visible */
.hero-slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 1.4s ease;
}
.hero-slide.is-active { opacity: 1; z-index: 2; }
.hero-slide img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Default crop point; individual slides can override via --focal-y set
     inline on .hero-slide (see data/hero-slides.php 'focal_y' field and
     the loop in en/index.php / ar/index.php) — some shots need a different
     vertical anchor than the site-wide default, e.g. one where 28% cropped
     off the top of the frame. */
  object-position: center var(--focal-y, 28%);
  animation: kenburns 20s ease-in-out infinite alternate;
  transform-origin: 62% 40%;
  will-change: transform;
}
@keyframes kenburns {
  0%   { transform: scale(1) translate(0, 0); }
  100% { transform: scale(1.16) translate(-2.4%, -1.8%); }
}
/* Video slides: same fit/crop behavior as images, but deliberately no Ken
   Burns — the footage already has its own motion, stacking a pan/zoom on
   top of that reads as busy rather than adding interest the way it does
   on a static photo. */
.hero-slide video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center var(--focal-y, 28%);
  display: block;
}
@media (prefers-reduced-motion: reduce) {
  .hero-slide img { animation: none; }
  .hero-slide { transition: none; }
}
/* No full-width scrim here anymore — see .hero-caption::before for the
   localized darkening confined to the title's corner. */
/* Caption wrapper gets the parallax translateY — same #heroCaption hook as before.
   Client wants the title confined to the last quarter of the image, contained,
   no full-width scrim underneath — so the darkening lives only behind this
   corner, not as a bar across the whole photo. */
.hero-caption {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  width: min(30%, 460px);
  z-index: 5;
  color: #FAF8F4;
  will-change: transform;
}
.hero-caption::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg,
    rgba(20, 17, 12, 0) 0%,
    rgba(20, 17, 12, 0.12) 34%,
    rgba(20, 17, 12, 0.6) 100%);
  pointer-events: none;
}
.hero-caption-slide {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
  /* Was justify-content: flex-end (bottom-anchored) with heavy asymmetric
     bottom padding (140px) to clear the hero's bottom edge during the
     scroll-parallax offset in main.js. Now vertically centered per client
     request — padding rebalanced to be roughly symmetric top/bottom
     instead, since the old 140px was specifically compensating for
     bottom-anchoring and would otherwise visually push centered content
     upward off true center. */
  padding: 60px 28px 60px 40px;
  box-sizing: border-box;
  opacity: 0;
  transition: opacity 1.4s ease;
}
.hero-caption-slide.is-active { opacity: 1; z-index: 2; }
.hero-caption-slide .eyebrow { color: #FAF8F4; opacity: 0.85; display: block; margin-bottom: 12px; }
.hero-caption-slide h1 {
  font-family: var(--font-display);
  font-weight: 400;
  font-style: italic;
  font-size: clamp(19px, 1.7vw, 28px);
  line-height: 1.32;
  overflow-wrap: break-word;
  hyphens: auto;
}

/* ============ HOMEPAGE MARKETING SECTION ============
   Edge-to-edge 16:9 background photo (set inline via style="background-image"
   in en/index.php + ar/index.php) with a page-color tint overlay so the
   headline and copy stay legible over any photo. Content is grouped into a
   compact centered block rather than spread edge-to-edge. */
.marketing {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 60px;
  overflow: hidden;
  background-size: cover;
  background-position: center;
}
.marketing::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  background: var(--bg);
  opacity: 0.85;
}
.marketing-inner {
  position: relative;
  z-index: 1;
  max-width: 1000px;
  width: 100%;
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 40px;
  align-items: center;
}
.marketing-headline h2 {
  font-family: var(--font-ui);
  font-weight: 500;
  /* increased per client feedback — this is the section's focal statement */
  font-size: clamp(40px, 4.8vw, 72px);
  line-height: 1.1;
  text-transform: uppercase;
  letter-spacing: 0.01em;
  color: var(--ink);
}
.marketing-headline h2 em {
  /* Moodboard's italic accent-word treatment (see "captured with *earned*
     intimacy" in the reference). Switches to the display serif specifically
     for the emphasized word rather than italicizing the whole uppercase
     sans headline, which would look like a typo rather than an accent. */
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 500;
  text-transform: none;
}
.marketing-copy p {
  font-family: var(--font-ui);
  font-size: 15px;
  line-height: 1.75;
  color: var(--ink-soft);
}
.marketing-copy p + p { margin-top: 20px; }
.cta-link {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-top: 36px;
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink);
  font-weight: 500;
  border-bottom: 1px solid var(--ink);
  padding-bottom: 4px;
  transition: opacity .2s ease;
}
.cta-link:hover { opacity: 0.6; }
.cta-play {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 1px solid currentColor;
  font-size: 8px;
  flex-shrink: 0;
}
.cta-link--light { color: var(--bg); border-bottom-color: var(--bg); }

/* ============ COLLECTION TILES (homepage) ============ */

.tiles {
  display: grid;
  grid-template-columns: 1.3fr 1fr 1fr;
  gap: 2px;
}
.tile { position: relative; overflow: hidden; min-height: 280px; }
.tile:first-child { grid-row: span 2; min-height: 562px; }
.tile img { width: 100%; height: 100%; object-fit: cover; display: block; }
.tile::after {
  content: '';
  position: absolute; left: 0; right: 0; bottom: 0; height: 46%;
  background: linear-gradient(180deg, rgba(48,45,40,0) 0%, rgba(48,45,40,0.15) 40%, rgba(48,45,40,0.72) 100%);
  pointer-events: none;
}
.tile-label {
  position: absolute; left: 20px; bottom: 18px; z-index: 2;
  color: #FAF8F4; font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase;
  text-shadow: 0 1px 3px rgba(0,0,0,0.25);
}

/* ============ COLLECTION GALLERY (Signature/Exclusive category pages) ============
   Masonry-via-grid, same technique as the Exhibitions page
   (.exhibit-gallery) — grid-row-end span per tile, picked from a 3-tier
   orientation approximation (portrait/landscape/square) rather than real
   pixel dimensions, since none exist for these 228 catalogue images (see
   data/signature-images.php / data/exclusive-images.php header comments).
   Edge-to-edge, consistent with every other gallery on the site. */
.collection-gallery {
  width: 100%;
  overflow-x: hidden;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: 10px;
  grid-auto-flow: row dense;
  gap: 4px;
  padding: 4px 0 80px;
}
.collection-tile {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--panel);
}
.collection-tile--portrait { grid-row-end: span 46; } /* was 34 — taller, less severe cropping on face-heavy portrait shots */
.collection-tile--landscape { grid-row-end: span 22; } /* was 20 */
.collection-tile--square { grid-row-end: span 30; } /* was 26 */

.collection-tile-media {
  position: relative;
  flex: 1 1 auto;
  overflow: hidden;
  cursor: zoom-in;
}
.collection-tile-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Biased slightly above dead-center (default cover behavior) — most of
     these are close portraits where the subject's eyes/face sit in the
     upper part of the frame, so this protects more of that area than a
     50/50 top/bottom crop would, at the cost of a bit more off the
     bottom (chin/shoulders) instead. Doesn't fix a badly-mismatched crop
     on its own — see the note in the .collection-gallery comment above
     about why real per-image dimensions are the actual fix. */
  object-position: center 35%;
  display: block;
  transition: transform .6s ease;
}
.collection-tile-media:hover img { transform: scale(1.05); }

.mail-btn {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  border: 1px solid var(--line);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--ink-soft);
  flex-shrink: 0;
  transition: border-color .2s ease, color .2s ease;
}
.mail-btn:hover { border-color: var(--accent); color: var(--accent); }
.mail-btn svg { width: 13px; height: 13px; }
.collection-tile .mail-btn {
  position: absolute;
  top: 12px;
  right: 12px;
  z-index: 2;
  background: rgba(250, 248, 244, 0.92);
}

.collection-tile-meta {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 14px;
}
.collection-tile-caption { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.collection-tile-location {
  font-family: var(--font-ui);
  font-size: 13px;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.collection-tile-year { font-family: var(--font-ui); font-size: 11px; color: var(--ink-soft); }
.collection-tile-status {
  flex-shrink: 0;
  font-family: var(--font-ui);
  font-size: 11px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  text-align: right;
  white-space: nowrap;
}
.collection-tile-status--edition { color: var(--accent); }
.collection-tile-status--gallery { color: var(--ink-soft); font-style: italic; }

/* Category page header (signature/camels.php etc, both collections) */
.collection-category-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 90px 32px 40px;
}
.collection-category-header .eyebrow { display: block; margin-bottom: 16px; }
.collection-category-header h1 {
  flex: 0 1 auto;
  text-align: center;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(30px, 3.2vw, 44px);
  color: var(--ink);
}
/* Prev/next category nav, same row as the title (mockup: "< CHILDREN ...
   Nature ... PEOPLE >"). Both sides get flex:1 so they take up equal
   width regardless of how long each category's name is, which is what
   actually keeps the h1 centered — text-align: start/end (not left/right)
   so this flips correctly under RTL without needing a manual override;
   flexbox already mirrors the left-to-right DOM order automatically the
   same way it does everywhere else on this site. */
.collection-category-nav {
  flex: 1 1 0;
  display: flex;
  align-items: center;
  gap: 4px;
  font-family: var(--font-ui);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink);
  white-space: nowrap;
  transition: color .2s ease;
}
.collection-category-nav:hover { color: var(--accent); }
.collection-category-nav--prev { justify-content: flex-start; text-align: start; }
.collection-category-nav--next { justify-content: flex-end; text-align: end; }

/* Collection intro block, top of signature/index.php and exclusive/index.php */
.collection-intro {
  max-width: 720px;
  margin: 0 auto;
  padding: 90px 32px 60px;
  text-align: center;
}
.collection-intro .eyebrow { display: block; margin-bottom: 20px; }
.collection-intro p {
  font-family: var(--font-ui);
  font-size: 14px;
  line-height: 1.75;
  color: var(--ink-soft);
  max-width: 560px;
  margin: 0 auto;
}
.collection-intro p + p { margin-top: 14px; }
/* Extra breathing room above this specific line — client wanted more
   separation from the sizes list right above it than the standard 14px
   paragraph spacing gives. */
.collection-intro p.collection-intro-border-note { margin-top: 36px; }
.collection-intro-sizes { margin-top: 26px; }
.collection-intro-sizes-label {
  display: block;
  font-family: var(--font-ui);
  font-size: 13px;
  color: var(--ink);
  margin-bottom: 4px;
}
.collection-intro-sizes-value {
  display: block;
  font-family: var(--font-ui);
  font-size: 13px;
  color: var(--ink-soft);
  letter-spacing: 0.02em;
}
.collection-intro-sizes-value + .collection-intro-sizes-label { margin-top: 18px; }
.collection-intro-contact { margin-top: 28px; font-family: var(--font-ui); font-size: 13px; color: var(--ink-soft); }
.collection-intro-contact a { color: var(--accent); border-bottom: 1px solid currentColor; }
.collection-intro-cta {
  display: inline-block;
  margin-top: 32px;
  font-family: var(--font-ui);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink);
  border-bottom: 1px solid var(--ink);
  padding-bottom: 4px;
}
.collection-intro-cta:hover { opacity: 0.6; }

/* Category tile grid — signature/index.php and exclusive/index.php link out
   to their 5 category pages instead of dumping every image in one wall,
   which is the whole reason Exclusive got categories in the first place. */
.category-tiles {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 4px;
  padding: 0 0 4px;
}
.category-tile {
  display: flex;
  flex-direction: column;
}
/* Bar sits above the image as its own block — not overlaid on the photo,
   per client request (the previous version had the category name as
   text overlaid on the image itself with a dark gradient behind it). */
.category-tile-bar {
  /* Was background: var(--ink); color: var(--bg); (dark) — changed to
     match the Photo Tours page's text-panel card combo (.tour-gallery-tile--panel):
     light cream background, bronze accent text. Shared class, so this
     applies to both Signature and Exclusive hub pages automatically. */
  background: var(--panel);
  color: var(--accent);
  text-align: center;
  padding: 14px 12px;
  font-family: var(--font-ui);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.category-tile-media {
  position: relative;
  overflow: hidden;
  aspect-ratio: 3 / 4;
}
.category-tile-media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .6s ease;
}
.category-tile:hover .category-tile-media img { transform: scale(1.06); }

/* ============ ABOUT / E.E.A.T. — portrait circle beside copy (panning on scroll) ============
   Shared by the homepage E.E.A.T. section and the standalone about.php page.
   The background is edge-to-edge via a spread box-shadow + clip-path — this
   avoids adding a markup wrapper just to get full-bleed color while keeping
   the actual grid content comfortably centered at max-width: 1100px.
   --linen (not --panel — see base.css) so the section actually reads as a
   distinct band rather than blending into the page. */
.about {
  background: var(--linen);
  box-shadow: 0 0 0 100vmax var(--linen);
  clip-path: inset(0 -100vmax);
  max-width: 1100px;
  margin: 0 auto;
  padding: 90px 32px 130px;
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: 64px;
  text-align: left;
}
.portrait-window {
  width: min(42vw, 400px);
  aspect-ratio: 1 / 1;
  border-radius: 50%;
  overflow: hidden;
  margin: 0;
  position: relative;
  flex-shrink: 0;
  /* subtle ring so the circle reads clearly against --linen instead of
     the photo's dark edge just bleeding into the panel color */
  box-shadow: 0 0 0 1px rgba(48, 45, 40, 0.15);
}
.portrait-window img {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 148%;
  max-width: none;
  transform: translate(-50%, -50%);
  filter: grayscale(1) contrast(1.05);
  will-change: transform;
}
.about-copy { text-align: left; }
/* --linen is a mid-tone, so the standard --accent eyebrow (also mid-tone
   bronze) loses contrast here — darken to --ink specifically in this panel. */
.about-copy .eyebrow { display: block; margin-bottom: 24px; color: var(--ink); }
.about-copy p {
  font-family: var(--font-display);
  font-size: 22px;
  line-height: 1.55;
  color: var(--ink);
  font-weight: 300;
  max-width: 480px;
  margin: 0;
}

/* E.E.A.T. credential chips — concrete trust signals (experience, expertise,
   authority, recognition), not just thematic tags, per the moodboard's chip
   vocabulary but built from David's actual real credentials instead of
   generic subject-matter labels. */
.about-credentials {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 28px;
  max-width: 480px;
}
.about-credential {
  display: inline-flex;
  align-items: center;
  padding: 7px 14px;
  border-radius: 999px;
  font-family: var(--font-ui);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  line-height: 1.3;
  white-space: nowrap;
}
.about-credential--bronze {
  background: var(--accent);
  color: var(--bg);
}
.about-credential--outline {
  background: transparent;
  color: var(--ink);
  border: 1px solid rgba(48, 45, 40, 0.35);
}

/* ============ HOMEPAGE GALLERY PREVIEW ============
   Three auto-scrolling marquee rows of pure photos — no CTA embedded in the
   scroll itself (that was tried two ways: as a tile in the loop, then as a
   pinned overlay, and both were confusing/unreliable in review). Each row's
   markup is rendered twice back-to-back (see en/index.php / ar/index.php)
   so translateX(-50%) loops seamlessly with no visible seam. Row 1 + row 3
   scroll left-to-right, row 2 scrolls right-to-left. Hovering a row pauses
   it. Row height is set ONCE here (.gallery-row) and everything inside
   inherits it via height:100% — a single source of truth so nothing can
   drift out of sync between rows.
   The CTA is a plain, always-visible, full-width banner (.gallery-cta-banner)
   directly under the three rows, with separate links to the Signature and
   Exclusive collections. */
.gallery-preview { overflow: hidden; }
.gallery-rows {
  /* Isolates the whole marquee (all 3 rows) from the page's RTL context.
     The previous fix only set direction:ltr on .gallery-track itself,
     which wasn't enough — rows 1 and 3 (plain .gallery-row, using the
     gallery-scroll-ltr keyframes) were still rendering blank on the
     Arabic page even after that fix, while row 2 (.gallery-row--rtl)
     displayed correctly. Setting it here at the wrapper level instead
     isolates the entire subtree in one place rather than patching each
     inner piece individually. */
  direction: ltr;
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-bottom: 4px;
}
.gallery-row {
  position: relative;
  overflow: hidden;
  width: 100%;
  height: 227px; /* was 340px, reduced to 2/3 per client request */
}
.gallery-track {
  display: flex;
  /* Forces the track's internal flex layout to stay left-to-right even
     on the Arabic page (dir="rtl"). Without this, a flex container
     auto-mirrors its item order/direction under RTL, which conflicts
     with the translateX()-based scroll animation below (built assuming
     a fixed LTR layout) — tiles ended up bunched at one edge instead of
     scrolling across the row. The row itself still sits correctly
     within the RTL page; only this specific mechanical/animated
     component is pinned to LTR internally, same as any marquee/carousel
     whose scroll math shouldn't flip just because the page language
     does. */
  direction: ltr;
  align-items: stretch;
  gap: 4px;
  height: 100%;
  min-height: 0;
  width: max-content;
  will-change: transform;
  animation: gallery-scroll-ltr 90s linear infinite;
}
.gallery-row--rtl .gallery-track {
  animation-name: gallery-scroll-rtl;
  animation-duration: 102s;
}
.gallery-row:hover .gallery-track { animation-play-state: paused; }
@keyframes gallery-scroll-ltr {
  from { transform: translateX(-50%); }
  to   { transform: translateX(0); }
}
@keyframes gallery-scroll-rtl {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
  .gallery-track { animation: none; }
}
.gallery-tile {
  flex: 0 0 227px; /* was 340px, reduced to 2/3 per client request */
  height: 100%;
  min-height: 0;
  box-sizing: border-box;
  position: relative;
  overflow: hidden;
  background: var(--panel);
}
.gallery-tile img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform .6s ease;
}
.gallery-tile:hover img { transform: scale(1.06); }
.gallery-cta-banner {
  width: 100%;
  box-sizing: border-box;
  background: var(--ink);
  color: var(--bg);
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 20px 40px;
  padding: 40px 60px;
}
.gallery-cta-banner h3 {
  font-family: var(--font-ui);
  font-weight: 500;
  font-size: clamp(17px, 1.7vw, 26px);
  line-height: 1.3;
  text-transform: uppercase;
  color: var(--bg);
  margin: 0;
  white-space: nowrap;
}
.gallery-cta-links {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 16px 40px;
}
.gallery-cta-links .cta-link { margin-top: 0; }
@media (max-width: 900px) {
  .gallery-row { height: 187px; } /* was 280px, reduced to 2/3 per client request */
  .gallery-tile { flex-basis: 187px; }
  .gallery-cta-banner { padding: 32px 28px; }
  /* Same fixed 46s/52s duration as desktop was covering the tablet-size
     track (smaller tiles = less total distance) just as fast in wall-clock
     time, which — on a narrower viewport — meant the loop swept across the
     visible screen far quicker than on desktop, reading as "way too fast"
     even though the raw px/s speed was actually lower. Slowing the
     duration down here keeps the felt pace closer to desktop's. Values
     below scale from the new 90s/102s desktop base by the same factors
     used before (~1.39x tablet, 2x mobile) — only the base changed, not
     the compensation logic itself. */
  .gallery-track { animation-duration: 126s; }
  .gallery-row--rtl .gallery-track { animation-duration: 142s; }
}
@media (max-width: 560px) {
  .gallery-row { height: 147px; } /* was 220px, reduced to 2/3 per client request */
  .gallery-tile { flex-basis: 147px; }
  .gallery-cta-banner h3 { white-space: normal; }
  .gallery-cta-banner { flex-direction: column; align-items: flex-start; padding: 28px; }
  /* Same reasoning as the 900px breakpoint above, scaled further for the
     even narrower mobile viewport. */
  .gallery-track { animation-duration: 180s; }
  .gallery-row--rtl .gallery-track { animation-duration: 204s; }
}

/* ============ FOOTER ============ */
.site-footer {
  border-top: 1px solid var(--line);
  padding: 72px 44px 0;
}
.footer-top {
  max-width: 1200px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1.6fr 1fr 1fr 1.2fr;
  gap: 40px;
  padding-bottom: 56px;
}
.footer-name {
  display: inline-block;
  font-family: var(--font-display);
  font-style: italic;
  font-size: 20px;
  color: var(--ink);
}
.footer-tagline {
  margin-top: 10px;
  font-family: var(--font-ui);
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.footer-nav-col,
.footer-contact {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.footer-heading {
  font-family: var(--font-ui);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 4px;
}
.footer-nav-col a {
  font-family: var(--font-ui);
  font-size: 14px;
  color: var(--ink-soft);
  transition: color .2s ease;
}
.footer-nav-col a:hover { color: var(--ink); }
.footer-email {
  font-family: var(--font-ui);
  font-size: 14px;
  color: var(--ink);
  word-break: break-word;
}
.footer-email:hover { color: var(--accent); }
.footer-location {
  font-family: var(--font-ui);
  font-size: 13px;
  color: var(--ink-soft);
}
.footer-bottom {
  max-width: 1200px;
  margin: 0 auto;
  border-top: 1px solid var(--line);
  padding: 24px 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  flex-wrap: wrap;
}
.footer-meta { font-size: 11px; color: var(--ink-soft); letter-spacing: 0.04em; }
.footer-lang {
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent);
}
.footer-lang:hover { color: var(--ink); }

/* ============ HOMEPAGE PHOTO TOURS TEASER ============
   Secondary site objective (primary is print sales via Signature/Exclusive
   — see .gallery-cta-banner above). Left third: copy over a tinted photo
   background. Right two-thirds: 3 images that "open" via a clip-path wipe
   when scrolled into view — see .tours-reveal below and the
   IntersectionObserver in assets/js/main.js. Animation choice follows the
   project's animation-craft guidance: entrances use a strong custom
   ease-out curve (never ease-in — it reads as sluggish), duration is on
   the long end (900ms) since this is an occasional, first-view marketing
   moment rather than frequent UI chrome, and the three images stagger via
   --i so it reads as one coordinated reveal, not three separate ones. */
.tours-teaser {
  position: relative;
  width: 100%;
  min-height: 620px;
  display: grid;
  grid-template-columns: 1fr 2fr;
  background-size: cover;
  background-position: center;
  overflow: hidden;
}
.tours-teaser::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  /* Tints the left column solid enough to read text on any photo, fades
     out by ~70% across so the right-hand images stay clean and untinted. */
  background: linear-gradient(90deg,
    var(--ink) 0%,
    rgba(48, 45, 40, 0.88) 30%,
    rgba(48, 45, 40, 0.35) 50%,
    rgba(48, 45, 40, 0.05) 68%,
    transparent 80%);
}
.tours-teaser-copy {
  position: relative;
  z-index: 1;
  padding: 90px 48px;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.tours-teaser-copy .eyebrow { color: var(--bg); opacity: 0.85; }
.tours-teaser-copy h2 {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 500;
  font-size: clamp(28px, 3vw, 42px);
  line-height: 1.25;
  color: var(--bg);
  margin: 16px 0 20px;
  max-width: 360px;
}
.tours-teaser-copy p {
  font-family: var(--font-ui);
  font-size: 15px;
  line-height: 1.75;
  color: rgba(250, 248, 244, 0.82);
  max-width: 340px;
  margin-bottom: 32px;
}
.tours-teaser-images {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 4px;
  padding: 4px;
}
.tours-reveal {
  position: relative;
  overflow: hidden;
  aspect-ratio: 3 / 4;
  background: var(--panel);
  align-self: center;
}
.tours-reveal img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  opacity: 0;
  transform: scale(1.15);
  clip-path: inset(0 100% 0 0); /* fully hidden — "curtain" closed from the right */
  transition:
    clip-path 900ms cubic-bezier(0.23, 1, 0.32, 1),
    transform 900ms cubic-bezier(0.23, 1, 0.32, 1),
    opacity 500ms ease-out;
  transition-delay: calc(var(--i, 0) * 140ms);
}
.tours-reveal.is-visible img {
  opacity: 1;
  transform: scale(1);
  clip-path: inset(0 0% 0 0); /* curtain fully open */
}
@media (prefers-reduced-motion: reduce) {
  .tours-reveal img {
    transition: none;
    opacity: 1;
    transform: none;
    clip-path: inset(0 0% 0 0);
  }
}

/* ============ TOURS PAGE (tours.php) ============
   Built from Phototour_to_Zanzibar_Info.docx. Reuses existing tokens
   (--ink, --accent, --panel, --font-display, --font-ui, .cta-link,
   .eyebrow) rather than inventing a parallel design language. */
.tour-hero {
  position: relative;
  min-height: 494px; /* was 380px, +30% per client request */
  display: flex;
  align-items: center;
  background-size: cover;
  background-position: center;
  overflow: hidden;
}
.tour-hero-inner {
  position: relative;
  z-index: 1;
  max-width: 900px;
  margin: 0 auto;
  width: 100%;
  padding: 40px 32px;
}
.tour-hero-inner .eyebrow { color: var(--bg); opacity: 0.85; }
.tour-hero-inner h1 {
  /* Was font-family: var(--font-display); font-style: italic; — changed
     to match the homepage's .marketing-headline h2 treatment exactly per
     client request (same font-family/size/transform; kept color: var(--bg)
     since this sits over a dark photo, unlike the homepage version which
     sits on a light background with dark text). */
  font-family: var(--font-ui);
  font-weight: 500;
  font-size: clamp(40px, 4.8vw, 72px);
  line-height: 1.1;
  text-transform: uppercase;
  letter-spacing: 0.01em;
  color: var(--bg);
  margin-top: 12px;
}
.tour-section {
  max-width: 900px;
  margin: 0 auto;
  padding: 56px 32px;
  border-bottom: 1px solid var(--line);
}
.tour-section:last-of-type { border-bottom: none; }
.tour-lead p {
  font-family: var(--font-display);
  font-size: 19px;
  line-height: 1.65;
  color: var(--ink-soft);
  font-weight: 300;
}
.tour-lead p + p { margin-top: 18px; }
.tour-heading {
  font-family: var(--font-ui);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 20px;
}
.tour-facts-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px 32px;
}
.tour-fact { display: flex; flex-direction: column; gap: 4px; }
.tour-fact-label {
  font-family: var(--font-ui);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.tour-fact-value {
  font-family: var(--font-display);
  font-size: 18px;
  color: var(--ink);
}
.tour-itinerary {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.tour-itinerary li {
  font-family: var(--font-ui);
  font-size: 15px;
  color: var(--ink);
  padding: 14px 18px;
  background: var(--panel);
  border-radius: 4px;
}
.tour-note {
  margin-top: 18px;
  font-family: var(--font-ui);
  font-size: 13px;
  color: var(--ink-soft);
  font-style: italic;
}
.tour-columns {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 48px;
}
.tour-columns .tour-heading:not(:first-child) { margin-top: 0; }
.tour-list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.tour-list li {
  font-family: var(--font-ui);
  font-size: 14px;
  line-height: 1.55;
  color: var(--ink-soft);
  padding-inline-start: 24px;
  position: relative;
}
.tour-list--check li::before {
  content: '✓';
  position: absolute;
  inset-inline-start: 0;
  color: var(--accent);
  font-weight: 600;
}
.tour-list--cross li::before {
  content: '—';
  position: absolute;
  inset-inline-start: 0;
  color: var(--ink-soft);
}
.tour-guarantee {
  margin-top: 24px;
  padding: 18px 20px;
  background: var(--panel);
  border-radius: 4px;
  font-family: var(--font-ui);
  font-size: 13px;
  line-height: 1.6;
  color: var(--ink);
}
.tour-inline-link {
  color: var(--accent);
  border-bottom: 1px solid currentColor;
  font-weight: 500;
}
.tour-inline-link:hover { color: var(--ink); }
.tour-section p {
  font-family: var(--font-ui);
  font-size: 14px;
  line-height: 1.75;
  color: var(--ink-soft);
}
.tour-section p + p { margin-top: 10px; }
.tour-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
.tour-tag {
  display: inline-flex;
  align-items: center;
  padding: 7px 14px;
  border-radius: 999px;
  border: 1px solid rgba(48, 45, 40, 0.25);
  font-family: var(--font-ui);
  font-size: 12px;
  color: var(--ink);
  white-space: nowrap;
}
.tour-cta {
  max-width: 900px;
  margin: 0 auto;
  padding: 72px 32px 100px;
  text-align: center;
}
.tour-cta h2 {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 500;
  font-size: clamp(26px, 3vw, 36px);
  color: var(--ink);
}
.tour-cta p {
  font-family: var(--font-ui);
  font-size: 14px;
  color: var(--ink-soft);
  max-width: 480px;
  margin: 16px auto 32px;
}
.tour-cta-links {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 20px 40px;
}
.tour-cta-links .cta-link { margin-top: 0; }

/* ============ TOUR GALLERY (tours.php, edge-to-edge editorial grid) ============
   Mirrors the Michael Tyler reference: one large photo + one text/CTA panel
   in the first row, then a trio, a full-width feature, and a closing pair.
   No page margins — deliberately full-bleed like .gallery-preview and
   .tours-teaser elsewhere on the site. */
.tour-gallery {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.tour-gallery-row {
  display: grid;
  gap: 4px;
}
.tour-gallery-row--hero { grid-template-columns: 1fr 1.4fr; } /* was 1.4fr 1fr — flipped since the photo/panel swapped sides */
.tour-gallery-row--trio { grid-template-columns: repeat(3, 1fr); }
.tour-gallery-row--pair { grid-template-columns: repeat(2, 1fr); }

.tour-gallery-tile {
  position: relative;
  overflow: hidden;
  min-height: 468px; /* was 360px, +30% per client request */
  cursor: zoom-in;
}
.tour-gallery-row--hero .tour-gallery-tile { min-height: 728px; } /* was 560px, +30% */
.tour-gallery-row--pair .tour-gallery-tile { min-height: 702px; } /* was 468px, +50% per client request */
.tour-gallery-tile--photo {
  background-size: cover;
  background-position: center;
}
.tour-gallery-tile--photo::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, transparent 50%, rgba(20, 17, 12, 0.7) 100%);
}
.tour-gallery-caption {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1;
  padding: 24px 28px;
}
.tour-gallery-caption .eyebrow { color: var(--bg); opacity: 0.85; }
.tour-gallery-caption h3 {
  font-family: var(--font-ui);
  font-weight: 500;
  font-size: 16px;
  letter-spacing: 0.02em;
  color: var(--bg);
  margin-top: 8px;
}
.tour-gallery-tile--panel {
  background: var(--panel);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 56px 40px;
  cursor: default;
}
.tour-gallery-tile--panel .eyebrow { color: var(--accent); }
.tour-gallery-tile--panel h3 {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(24px, 2.4vw, 32px);
  color: var(--ink);
  margin: 14px 0 18px;
}
.tour-gallery-tile--panel p {
  font-family: var(--font-ui);
  font-size: 14px;
  line-height: 1.7;
  color: var(--ink-soft);
  max-width: 360px;
  margin-bottom: 28px;
}
.tour-gallery-panel-cta {
  font-family: var(--font-ui);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink);
  border-bottom: 1px solid var(--ink);
  padding-bottom: 4px;
  transition: opacity .2s ease;
}
.tour-gallery-panel-cta:hover { opacity: 0.6; }

/* ============ TOUR VIDEO (tours.php, under "Where You'll Stay") ============ */
.tour-video-frame {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: 4px;
  background: var(--panel);
}
.tour-video-frame iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

/* ============ LIGHTBOX (tours.php, .tour-gallery photos) ============
   Hidden by default; shown/populated entirely by JS (assets/js/main.js).
   Dependency-free — no external lightbox library. */
.lightbox {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 300;
  align-items: center;
  justify-content: center;
  background: rgba(15, 13, 10, 0.94);
}
.lightbox.is-open { display: flex; }
.lightbox-image {
  /* Was max-width/max-height — those only cap an image that's BIGGER than
     the frame, they never grow a smaller one up to match. That's exactly
     why some Exclusive/People photos were filling the lightbox nicely
     while others (genuinely lower native resolution) sat small in the
     middle of a lot of dark space. width/height (not max-) makes the
     frame itself a fixed size regardless of the source image's own
     resolution; object-fit: contain still scales each image
     proportionally to fit inside it, exactly as before for the
     already-large photos. Trade-off worth knowing: a lower-resolution
     source image now gets scaled UP to fill this frame, so it'll look
     softer than a native-resolution one at the same size — that's an
     inherent property of upscaling, not something CSS can avoid. Real
     fix for genuinely low-res source files is a higher-resolution
     export, not this. */
  width: 88vw;
  height: 84vh;
  object-fit: contain;
  box-shadow: 0 24px 64px rgba(0, 0, 0, 0.45);
}
.lightbox-close,
.lightbox-prev,
.lightbox-next {
  position: absolute;
  background: transparent;
  border: 0;
  color: var(--bg);
  cursor: pointer;
  line-height: 1;
  padding: 14px;
  opacity: 0.85;
  transition: opacity .2s ease;
}
.lightbox-close:hover,
.lightbox-prev:hover,
.lightbox-next:hover { opacity: 1; }
.lightbox-close { top: 16px; right: 20px; font-size: 32px; }
.lightbox-prev { left: 12px; top: 50%; transform: translateY(-50%); font-size: 22px; }
.lightbox-next { right: 12px; top: 50%; transform: translateY(-50%); font-size: 22px; }
@media (max-width: 560px) {
  .lightbox-prev { left: 4px; }
  .lightbox-next { right: 4px; }
}

/* ============ EXHIBITIONS PAGE (exhibitions/index.php) ============ */
.exhibit-hero {
  position: relative;
  width: 100%;
  /* Real image is 1920x1440 (4:3). Height reduced 30% per client request
     (1440 * 0.7 = 1008) by using a shorter aspect-ratio rather than a
     fixed pixel height, so it still scales responsively at any viewport
     width instead of being a hardcoded band. background-position: bottom
     anchors the crop to the bottom of the frame — the 30% that's now
     cropped away comes off the top, not split evenly top/bottom. */
  aspect-ratio: 1920 / 1008;
  background-size: cover;
  background-position: center bottom;
  overflow: hidden;
}
/* Shared by .about-hero and .exhibit-hero — a narrow tinted column
   running the full height of the hero, left-aligned, content vertically
   centered within it. Exactly the same technique as the homepage hero's
   caption (.hero-caption / .hero-caption-slide), just as a single static
   element instead of a multi-slide rotation, since these two pages only
   ever show one hero image. Replaces the previous .hero-text-tint (a
   small box hugging just the text) — client wanted this to match the
   homepage exactly instead. */
.hero-side-caption {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  width: min(30%, 460px);
  z-index: 2;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
  padding: 60px 28px 60px 40px;
  box-sizing: border-box;
  color: var(--bg);
}
.hero-side-caption::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  /* Same gradient values as the homepage's .hero-caption::before. */
  background: linear-gradient(180deg,
    rgba(20, 17, 12, 0) 0%,
    rgba(20, 17, 12, 0.12) 34%,
    rgba(20, 17, 12, 0.6) 100%);
  pointer-events: none;
}
.hero-side-caption .eyebrow { color: var(--bg); opacity: 0.85; display: block; margin-bottom: 12px; }
.hero-side-caption h1 {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 500;
  font-size: clamp(28px, 3.4vw, 44px);
  color: var(--bg);
  line-height: 1.2;
}

/* Lead section: Left-of-content.webp beside the intro copy. Reuses
   .tour-lead p for paragraph typography (still applies via that class on
   the same wrapper) — .exhibit-lead just adds the two-column grid on top. */
.exhibit-lead {
  display: grid;
  grid-template-columns: 0.9fr 1.1fr;
  gap: 48px;
  align-items: stretch;
}
.exhibit-lead-media {
  min-height: 380px;
  border-radius: 4px;
  overflow: hidden;
}
.exhibit-lead-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.exhibit-lead-copy { display: flex; flex-direction: column; justify-content: center; }

/* Timeline: reuses .tour-section for the constrained-width padded wrapper
   (same treatment as the Photo Tours page) — these two are the only pages
   using that pattern so far, not worth splitting into a separately-named
   generic class yet. */
.exhibit-year { padding: 8px 0 40px; }
.exhibit-year:last-child { padding-bottom: 0; }
.exhibit-year-heading {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(30px, 3.2vw, 44px);
  color: var(--accent);
  margin-bottom: 20px;
}
.exhibit-list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.exhibit-item {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 10px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--line);
}
.exhibit-item:last-child { border-bottom: none; padding-bottom: 0; }
.exhibit-item-title {
  font-family: var(--font-ui);
  font-weight: 500;
  font-size: 15px;
  color: var(--ink);
}
.exhibit-item-solo {
  font-weight: 400;
  color: var(--accent);
  font-size: 12px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.exhibit-item-venue {
  font-family: var(--font-ui);
  font-size: 14px;
  color: var(--ink-soft);
}
.exhibit-item-venue::before { content: '\2014'; margin-inline-end: 10px; color: var(--line); }
.exhibit-item-detail {
  font-family: var(--font-ui);
  font-size: 13px;
  font-style: italic;
  color: var(--ink-soft);
  flex-basis: 100%;
}

/* Masonry gallery — edge-to-edge, grouped by exact pixel dimensions (see
   data/exhibition-gallery.php for the full explanation). CSS-grid-only
   masonry via grid-row-end: span (set inline per brick from PHP), no JS
   layout library. width:100% rather than the client's suggested 100vw —
   100vw includes the scrollbar's width and reliably causes a few pixels
   of horizontal overflow on desktop; every other edge-to-edge section on
   this site (.gallery-preview, .tours-teaser) already avoids that same
   way, so this stays consistent with the rest of the codebase. */
.exhibit-gallery {
  width: 100%;
  overflow-x: hidden;
  display: grid;
  /* Fixed column count (was auto-fill with a min width, which on a wide
     desktop screen was producing 8-9 thin columns — much busier than
     intended). 5 columns at any desktop width, narrowing at the
     breakpoints below. */
  grid-template-columns: repeat(5, 1fr);
  grid-auto-rows: 10px;
  grid-auto-flow: row dense;
  gap: 4px;
  /* Darker band from the existing palette (same var(--ink) used by
     .gallery-cta-banner and the marketing section's tint) rather than
     blending into the page background — shows through in the 4px gaps
     between bricks. */
  background: var(--ink);
  padding: 60px 0;
}
.exhibit-brick,
.exhibit-textbox {
  position: relative;
  overflow: hidden;
  background: var(--ink);
  /* Entrance reveal: fades/scales in once scrolled near, staggered by
     --i (set inline per item in en/exhibitions/index.php /
     ar/exhibitions/index.php). Previously only the two multi-image
     bricks had any motion — everything else just sat there statically. */
  opacity: 0;
  transform: scale(0.94);
  transition: opacity 700ms cubic-bezier(0.23, 1, 0.32, 1), transform 700ms cubic-bezier(0.23, 1, 0.32, 1);
  transition-delay: calc(var(--i, 0) * 60ms);
}
.exhibit-brick.is-revealed,
.exhibit-textbox.is-revealed {
  opacity: 1;
  transform: scale(1);
}
.exhibit-brick {
  cursor: zoom-in;
}
.exhibit-brick img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 800ms ease, transform 600ms ease;
}
.exhibit-brick img.is-active {
  opacity: 1;
  z-index: 1;
}
.exhibit-brick:hover img.is-active {
  transform: scale(1.05);
}
.exhibit-textbox {
  color: var(--bg);
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 28px 26px;
}
/* Distinct background per box, pulled from the existing palette — plain
   var(--ink) (same as the surrounding .exhibit-gallery container) made
   them read as floating text rather than actual boxes, since there was
   no contrast between a box and what's behind it. */
.exhibit-textbox--accent { background: var(--accent); }
.exhibit-textbox--linen {
  background: var(--linen);
  color: var(--ink);
}
.exhibit-textbox--linen .exhibit-stat-value { color: var(--ink); }
.exhibit-textbox--linen .exhibit-stat-label { color: var(--ink-soft); }
.exhibit-textbox--panel {
  background: var(--panel);
  color: var(--ink);
}
.exhibit-textbox--panel .exhibit-stat-value { color: var(--ink); }
.exhibit-textbox--panel .exhibit-stat-label { color: var(--ink-soft); }
.exhibit-stat-value {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(34px, 3.4vw, 52px);
  line-height: 1;
  color: var(--bg);
}
.exhibit-stat-label {
  margin-top: 12px;
  font-family: var(--font-ui);
  font-size: 13px;
  line-height: 1.5;
  color: rgba(250, 248, 244, 0.78);
}
@media (prefers-reduced-motion: reduce) {
  .exhibit-brick img { transition: none; }
  .exhibit-brick, .exhibit-textbox { transition: none; opacity: 1; transform: none; }
}

/* ============ BOOKS PAGE (books/index.php) ============
   Full build — was an empty stub. One traditionally-published art book
   (Al Sawan, featured/prominent, larger single image, "Available Soon"
   badge + external publisher link) followed by three self-published
   catalogues (Al Hejin / Encounters / Interpretations — cover + spread
   image pair each, fixed price, direct email order), which scroll-reveal
   in as the client requested, reusing the exact same fade/scale
   technique already established for .exhibit-brick/.exhibit-textbox
   (same easing, same --i stagger pattern) rather than inventing a new
   one. See data/books.php for all copy/spec content and real image
   dimensions — every image here uses its own real aspect-ratio (set
   inline from that data), not an assumed uniform one, since the cover
   images are consistently 2338px wide across all three catalogues but
   the spread images are NOT (Encounters' spread is narrower than the
   other two's). */
.books-hero {
  position: relative;
  width: 100%;
  /* No real pixel dimensions were given for this hero image — using the
     same aspect-ratio as the Exhibitions hero as a reasonable default.
     Adjust if the real image's proportions crop awkwardly. */
  aspect-ratio: 1920 / 1008;
  background-size: cover;
  background-position: center;
  overflow: hidden;
}

.book-featured {
  display: grid;
  grid-template-columns: 1.15fr 1fr;
  gap: 96px; /* was 56px — wider gap before the text, per client request */
  align-items: center;
  max-width: 1100px;
  margin: 0 auto;
  padding: 90px 32px 80px;
}
.book-featured-media {
  position: relative;
  /* Was overflow: hidden + box-shadow on this wrapper. box-shadow always
     follows the element's own rectangular box — it has no awareness of
     the image's alpha channel, so even with a genuinely transparent PNG/
     webp inside, the shadow rendered as a solid rectangle behind it,
     which is exactly the "white box behind a transparent image" problem
     the client flagged. drop-shadow() on the <img> itself (below)
     respects transparency and follows the actual visible silhouette
     instead. overflow: hidden removed too, since it would otherwise clip
     that shadow's blur right at the box edge — image and container share
     the same aspect-ratio anyway, so there was never real overflow to
     hide here in the first place. */
  width: 85%; /* was 100% of the column — reduced 15% per client request */
}
.book-featured-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  cursor: zoom-in;
  filter: drop-shadow(0 20px 45px rgba(20, 17, 12, 0.25));
}
.book-type-badge {
  display: inline-block;
  font-family: var(--font-ui);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 10px;
}
.book-featured-copy h2 {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 500;
  font-size: clamp(32px, 3.6vw, 48px);
  color: var(--ink);
  line-height: 1.15;
}
.book-featured-subtitle {
  font-family: var(--font-ui);
  font-size: 16px;
  color: var(--ink-soft);
  margin-top: 6px;
}
.book-edition-badge {
  display: inline-block;
  margin-top: 16px;
  padding: 6px 14px;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-family: var(--font-ui);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.book-description {
  font-family: var(--font-ui);
  font-size: 14px;
  line-height: 1.75;
  color: var(--ink-soft);
  margin-top: 22px;
}
.book-specs {
  list-style: none;
  margin: 24px 0 0;
  padding-top: 20px;
  border-top: 1px solid var(--line);
}
.book-specs li {
  font-family: var(--font-ui);
  font-size: 13px;
  line-height: 1.7;
  color: var(--ink-soft);
}
.book-availability-badge {
  display: inline-block;
  margin-top: 26px;
  padding: 10px 18px;
  background: var(--accent);
  color: var(--bg);
  font-family: var(--font-ui);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.book-publisher {
  margin-top: 14px;
  font-family: var(--font-ui);
  font-size: 13px;
  line-height: 1.7;
  color: var(--ink-soft);
}
.book-publisher-link,
.book-order-cta {
  display: inline-block;
  margin-top: 10px;
  font-family: var(--font-ui);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink);
  border-bottom: 1px solid var(--ink);
  padding-bottom: 3px;
  transition: opacity 0.2s ease;
}
.book-publisher-link:hover,
.book-order-cta:hover { opacity: 0.65; }

.book-catalogues {
  background: var(--panel);
  padding: 80px 0 100px;
}
.book-catalogues-heading {
  text-align: center;
  max-width: 700px;
  margin: 0 auto 64px;
  padding: 0 32px;
}
.book-catalogues-heading .eyebrow { display: block; margin-bottom: 16px; }
.book-catalogues-heading h2 {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 500;
  font-size: clamp(28px, 3vw, 40px);
  color: var(--ink);
}

/* Scroll-reveal — identical technique to .exhibit-brick/.exhibit-textbox:
   fades/scales in once scrolled near, staggered via --i. See
   assets/js/main.js (exhibitRevealItems, extended to also observe
   .book-card). */
.book-card {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 48px;
  align-items: center;
  max-width: 1100px;
  margin: 0 auto 96px;
  padding: 0 32px;
  opacity: 0;
  transform: scale(0.94);
  transition: opacity 700ms cubic-bezier(0.23, 1, 0.32, 1), transform 700ms cubic-bezier(0.23, 1, 0.32, 1);
  transition-delay: calc(var(--i, 0) * 80ms);
}
.book-card:last-child { margin-bottom: 0; }
.book-card.is-revealed {
  opacity: 1;
  transform: scale(1);
}
.book-card-images {
  /* Was a side-by-side grid (cover | spread). Restructured to a 2-row
     stack per client request: cover on top, spread below, cover centered
     relative to the spread's width. All three catalogues now share
     identical image dimensions (cover 1229x1158, spread 1816x921), so
     the cover's width below (68%) is that real ratio (1229/1816 ≈
     67.7%, rounded) rather than an arbitrary guess — the spread runs
     full width of this column, the narrower cover sits centered above
     it at its true proportional size. */
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  order: 1;
}
.book-card-copy { order: 2; }
/* Alternate sides per card for visual rhythm across the list. */
.book-card:nth-child(even) .book-card-images { order: 2; }
.book-card:nth-child(even) .book-card-copy { order: 1; }

.book-cover-media,
.book-spread-media {
  position: relative;
  overflow: hidden;
  cursor: zoom-in;
  width: 100%;
}
.book-cover-media { width: 68%; }
.book-cover-media img,
.book-spread-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.6s ease;
}
.book-card:hover .book-cover-media img,
.book-card:hover .book-spread-media img { transform: scale(1.04); }

.book-card-copy h3 {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 500;
  font-size: clamp(26px, 2.6vw, 36px);
  color: var(--ink);
}
@media (prefers-reduced-motion: reduce) {
  .book-card { transition: none; opacity: 1; transform: none; }
  .book-featured-media img,
  .book-cover-media img,
  .book-spread-media img { transition: none; }
}

/* ============ CONTACT PAGE (contact/index.php) ============
   Three-clip video hero rotation (same crossfade mechanism as the
   homepage's hero rotation — shared CSS classes .hero-slide /
   .hero-slide.is-active, driven by the same JS observer in main.js).
   Body: portrait photo takes the left 1/3, contact details take the
   right 2/3. */
.contact-hero {
  position: relative;
  width: 100%;
  height: 100vh;
  min-height: 540px;
  max-height: 860px;
  overflow: hidden;
  background: var(--ink);
}
/* Reuses .hero-slide / .hero-slide.is-active from the homepage. */
.contact-hero .hero-slide video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* Subtle gradient bottom-fade so the hero bleeds into the page body below. */
.contact-hero::after {
  content: '';
  position: absolute;
  inset: auto 0 0;
  height: 160px;
  background: linear-gradient(to bottom, transparent, var(--bg));
  z-index: 3;
  pointer-events: none;
}
.contact-hero-caption {
  position: absolute;
  inset: 0;
  z-index: 4;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
  width: min(30%, 460px);
  padding: 60px 28px 60px 40px;
  box-sizing: border-box;
  background: linear-gradient(180deg,
    rgba(20, 17, 12, 0) 0%,
    rgba(20, 17, 12, 0.12) 34%,
    rgba(20, 17, 12, 0.6) 100%);
}
.contact-hero-caption .eyebrow { color: var(--bg); opacity: 0.85; display: block; margin-bottom: 12px; }
.contact-hero-caption h1 {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 500;
  font-size: clamp(36px, 4vw, 56px);
  color: var(--bg);
  line-height: 1.15;
}

.contact-body {
  display: grid;
  grid-template-columns: 1fr 2fr;
  /* align-items: stretch so the portrait column grows to match the copy
     column's height, same technique as .about-split — the image then
     covers that full height via position:absolute + inset:0. */
  align-items: stretch;
  min-height: 760px;
  /* No max-width or padding — the portrait runs edge-to-edge on the left
     like the About page photo does. The copy column gets its own padding. */
}
.contact-portrait {
  position: relative;
  overflow: hidden;
}
.contact-portrait img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;
  display: block;
}
.contact-portrait img {
  width: 100%;
  height: auto;
  display: block;
}
.contact-details {
  padding: 80px 64px 80px 56px;
}
.contact-name {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 500;
  font-size: clamp(34px, 3.6vw, 52px);
  color: var(--ink);
  line-height: 1.1;
  margin-bottom: 6px;
}
.contact-title-line {
  font-family: var(--font-ui);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 48px;
}
.contact-block {
  margin-bottom: 40px;
  padding-bottom: 40px;
  border-bottom: 1px solid var(--line);
}
.contact-block:last-child { border-bottom: none; margin-bottom: 0; }
.contact-block-label {
  font-family: var(--font-ui);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent);
  display: block;
  margin-bottom: 14px;
}
.contact-address p {
  font-family: var(--font-ui);
  font-size: 15px;
  line-height: 1.7;
  color: var(--ink-soft);
}
.contact-email-row {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.contact-email-item {
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.contact-email-sublabel {
  font-family: var(--font-ui);
  font-size: 11px;
  letter-spacing: 0.06em;
  color: var(--linen);
  text-transform: uppercase;
}
.contact-email-link {
  font-family: var(--font-ui);
  font-size: 15px;
  color: var(--ink);
  transition: color 0.2s ease;
}
.contact-email-link:hover { color: var(--accent); }
.contact-whatsapp-link {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-ui);
  font-size: 16px;
  font-weight: 500;
  color: var(--ink);
  margin-top: 4px;
  transition: color 0.2s ease;
}
.contact-whatsapp-link:hover { color: var(--accent); }
.contact-whatsapp-icon {
  width: 22px;
  height: 22px;
  flex-shrink: 0;
}
.contact-response-note {
  font-family: var(--font-ui);
  font-size: 13px;
  line-height: 1.7;
  color: var(--ink-soft);
  font-style: italic;
  margin-top: 36px;
}
@media (max-width: 900px) {
  .contact-body { grid-template-columns: 1fr; }
  .contact-portrait { min-height: 480px; position: relative; }
  .contact-details { padding: 48px 32px 64px; }
  .contact-hero-caption { width: min(60%, 460px); }
}
@media (max-width: 560px) {
  .contact-hero-caption { width: 90%; padding: 40px 24px; }
  .contact-portrait { min-height: 380px; }
  .contact-details { padding: 36px 20px 56px; }
}

/* ============ ABOUT PAGE (about/index.php) ============
   Full rebuild — replaces the old stub that reused the shared
   .about/.portrait-window markup (that markup/CSS is untouched; the
   homepage E.E.A.T. section still uses it as-is, this page just doesn't
   anymore). */
.about-hero {
  position: relative;
  width: 100%;
  /* Real image is 1920x1280 (3:2). Height reduced 250px in the image's
     own native pixel terms per client request (1280 - 250 = 1030),
     expressed as a shorter aspect-ratio so it stays responsive at any
     viewport width rather than a fixed pixel value that would only be
     correct at one specific width. background-position: bottom keeps the
     crop anchored to the bottom of the frame, so the 250px comes off the
     top, not split evenly. */
  aspect-ratio: 1920 / 1030;
  background-size: cover;
  background-position: center bottom;
  overflow: hidden;
}

/* 50/50 split — genuinely edge-to-edge (not constrained inside
   .tour-section like the Exhibitions lead), per "50% of the width of the
   page" in the request. Media column stretches to match whatever height
   the copy column naturally renders at (same align-items:stretch +
   object-fit:cover technique as .exhibit-lead), so the image always
   covers its half top-to-bottom regardless of how long the bio runs. */
.about-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: stretch;
  /* Was 720px — bumped for more breathing room around the (vertically
     centered) copy column. The media column stretches to match via
     align-items:stretch, so it grows taller right along with it — that's
     the mechanism for "keep the left image taller" here, not a separate
     height rule on the image itself. */
  min-height: 900px;
}
.about-split-media { position: relative; overflow: hidden; }
.about-split-media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.about-split-copy {
  display: flex;
  flex-direction: column;
  justify-content: center;
  /* 250px top/bottom minimum, per client request — this is what actually
     makes the section taller and lets the left image show more of the
     frame (camera included), not the min-height on .about-split, which
     was only ever a floor. With this much padding the copy's own content
     height plus 500px comfortably clears that floor on its own. */
  padding: 250px 64px;
}
.about-split-copy-inner { max-width: 560px; }
.about-split-copy p {
  font-family: var(--font-display);
  font-size: 18px;
  line-height: 1.75;
  color: var(--ink-soft);
  font-weight: 300;
}
.about-split-copy p + p { margin-top: 20px; }
.about-split-credentials { margin-top: 32px; }
.about-split-copy-heading {
  display: block;
  margin-top: 4px;
}

/* Gallery row — all 5 images share one real pixel height (1280px); only
   their widths differ per aspect ratio, so this is a plain flex row, not
   a grid masonry like Exhibitions. Auto-scrolls continuously (reuses
   @keyframes gallery-scroll-ltr, already defined above for the homepage
   marquee — same technique: track rendered twice for a seamless loop,
   the duplicate copy is aria-hidden and excluded from the lightbox).
   Pauses on hover; each tile opens in the lightbox otherwise. */
.about-gallery { width: 100%; overflow: hidden; direction: ltr; }
.about-gallery-track {
  display: flex;
  /* Same RTL fix as .gallery-track above — see that comment for the full
     explanation. Same underlying mechanism (flex + translateX scroll
     animation), so the same latent bug applied here too. */
  direction: ltr;
  gap: 4px;
  width: max-content;
  will-change: transform;
  animation: gallery-scroll-ltr 55s linear infinite;
}
.about-gallery:hover .about-gallery-track { animation-play-state: paused; }
@media (prefers-reduced-motion: reduce) {
  .about-gallery-track { animation: none; }
}
.about-gallery-tile {
  flex: 0 0 auto;
  height: 440px;
  position: relative;
  overflow: hidden;
  background: var(--panel);
  cursor: zoom-in;
}
.about-gallery-tile img {
  height: 100%;
  width: auto;
  display: block;
  object-fit: cover;
  transition: transform .6s ease;
}
.about-gallery-tile:hover img { transform: scale(1.05); }

/* ============ RESPONSIVE ============ */
@media (max-width: 900px) {
  .nav-links { display: none; }
  .nav-toggle { display: flex; }
  .marketing { aspect-ratio: auto; padding: 90px 28px; }
  .marketing-inner { grid-template-columns: 1fr; gap: 32px; }
  .about { grid-template-columns: 1fr; text-align: center; }
  .about-copy { text-align: center; }
  .about-copy p { margin: 0 auto; }
  .about-credentials { justify-content: center; margin-left: auto; margin-right: auto; }
  .portrait-window { width: min(72vw, 420px); margin: 0 auto; }
  .tiles { grid-template-columns: 1fr; }
  .tile:first-child { grid-row: auto; min-height: 340px; }
  .card-grid { grid-template-columns: 1fr; }
  .footer-top { grid-template-columns: 1fr 1fr; gap: 40px 28px; }
  .footer-brand { grid-column: 1 / -1; }
  .tours-teaser { grid-template-columns: 1fr; min-height: 0; }
  .tours-teaser::before { background: var(--ink); opacity: 0.9; }
  .tours-teaser-copy { padding: 56px 28px 32px; }
  .tours-teaser-copy h2, .tours-teaser-copy p { max-width: none; }
  .tours-teaser-images { grid-template-columns: repeat(3, 1fr); padding: 4px 28px 28px; }
  .tour-facts-grid { grid-template-columns: repeat(2, 1fr); }
  .tour-columns { grid-template-columns: 1fr; gap: 32px; }
  .tour-gallery-row--hero { grid-template-columns: 1fr; }
  .book-featured { grid-template-columns: 1fr; gap: 32px; padding: 56px 24px; }
  .book-card, .book-card:nth-child(even) { grid-template-columns: 1fr; gap: 24px; padding: 0 24px; margin-bottom: 64px; }
  .book-card .book-card-images, .book-card:nth-child(even) .book-card-images { order: 1; }
  .book-card .book-card-copy, .book-card:nth-child(even) .book-card-copy { order: 2; }
  .tour-gallery-row--trio { grid-template-columns: repeat(2, 1fr); }
  .tour-gallery-row--hero .tour-gallery-tile { min-height: 494px; } /* was 380px, +30% */
  .exhibit-gallery { grid-template-columns: repeat(3, 1fr); }
  .collection-gallery { grid-template-columns: repeat(3, 1fr); }
  .category-tiles { grid-template-columns: repeat(3, 1fr); }
  .about-split { grid-template-columns: 1fr; min-height: 0; }
  .about-split-media { min-height: 420px; }
  .about-split-copy { padding: 56px 32px; }
  .about-gallery-tile { height: 320px; }
}
@media (max-width: 560px) {
  .hero-caption { width: 82%; }
  .footer-top { grid-template-columns: 1fr; gap: 32px; }
  .footer-bottom { flex-direction: column; align-items: flex-start; gap: 12px; }
  .tours-teaser-images { grid-template-columns: 1fr 1fr 1fr; gap: 3px; }
  .tour-facts-grid { grid-template-columns: 1fr 1fr; }
  .tour-cta-links { flex-direction: column; align-items: center; }
  .tour-gallery-row--trio { grid-template-columns: 1fr; }
  .tour-gallery-row--pair { grid-template-columns: 1fr; }
  .tour-gallery-tile { min-height: 390px; } /* was 300px, +30% */
  .tour-gallery-row--pair .tour-gallery-tile { min-height: 585px; } /* was 390px, +50% per client request */
  .tour-gallery-tile--panel { padding: 44px 28px; }
  .exhibit-gallery { grid-template-columns: repeat(2, 1fr); }
  .collection-gallery { grid-template-columns: 1fr; } /* was repeat(2, 1fr) — two columns on a phone left captions truncated and images cramped; one column per row reads properly */
  .category-tiles { grid-template-columns: repeat(2, 1fr); }
  .exhibit-item-venue::before { display: block; content: ''; margin: 0; }
  .exhibit-lead { grid-template-columns: 1fr; }
  .exhibit-lead-media { min-height: 260px; }
  .collection-category-header {
    flex-wrap: wrap;
    padding: 70px 24px 28px;
    gap: 8px 16px;
  }
  .collection-category-header h1 { order: -1; flex: 1 0 100%; margin-bottom: 4px; }
  .collection-category-nav { font-size: 11px; }
  .about-gallery-tile { height: 240px; }
}
