/* =========================================================
   Mayra — Art Portfolio
   Minimal · Romantic · Vintage, with modern motion
   ========================================================= */

/* Monarcha loads from your Adobe Fonts kit (uxo1imx) via the
   <link> tag in each page's <head>. Weights available: Book (300),
   Regular (400), SemiBold (600), Bold (700) — each with a matching
   italic. Headings below use Regular (400); bump to 600 for a
   heavier accent if you want one later. */
@import url('https://fonts.googleapis.com/css2?family=Karla:wght@300;400;500;700&display=swap');

:root {
  --ivory: #f8f4ec;
  --paper: #f2ece1;
  --charcoal: #2a2422;
  --ink: #35302c;
  --wine: #7a3b3b;
  --wine-deep: #5c2a2a;
  --gold: #b08d57;
  --rose: #c98f8f;
  --line: rgba(42, 36, 34, 0.15);
  --shadow: rgba(42, 36, 34, 0.12);

  --serif: 'monarcha', Georgia, serif;
  --sans: 'Karla', 'Helvetica Neue', Arial, sans-serif;

  --max-width: 1180px;
  --transition-slow: 0.9s cubic-bezier(.22,.61,.36,1);
  --transition: 0.4s cubic-bezier(.22,.61,.36,1);
}

/* Kills the default gray/blue tap-highlight flash mobile browsers paint
   over buttons and links on tap — most noticeable on things like the
   hamburger menu, where a big visual change (the nav overlay opening)
   follows right behind it, making the flash stand out. */
* {
  box-sizing: border-box;
  -webkit-tap-highlight-color: transparent;
}

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--ivory);
  color: var(--ink);
  font-family: var(--sans);
  font-weight: 300;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* subtle paper grain overlay */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 9999;
  opacity: 0.035;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

h1, h2, h3, h4 {
  font-family: var(--serif);
  font-weight: 400; /* Monarcha Regular — SemiBold (600) is also loaded in your kit if you want a heavier accent */
  color: var(--charcoal);
  letter-spacing: 0.01em;
  margin: 0 0 0.5em;
}

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

img { max-width: 100%; display: block; }

.eyebrow {
  font-family: var(--sans);
  text-transform: uppercase;
  letter-spacing: 0.28em;
  font-size: 0.72rem;
  color: var(--wine);
  font-weight: 500;
}

.container {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 0 6vw;
}

/* ---------- Header / Nav ---------- */

.site-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 500;
  /* A 3-column grid (rather than flex space-between) keeps nav.main-nav
     visually centered no matter what's in the right-hand column — with
     space-between, removing the old wallet button left only 2 items
     (logo, nav), which shoved the nav out to the far right edge instead
     of sitting centered the way it did with 3 items. The two 1fr side
     columns stay equal width even when the right column is empty. */
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  padding: 1.6rem 6vw;
  transition: padding var(--transition);
}
/* The scrolled background/blur lives on this pseudo-element instead of
   directly on .site-header. backdrop-filter (and transform/filter/etc.)
   on an element creates a containing block for any position:fixed
   descendants — and the mobile nav overlay (nav.main-nav.open, itself
   position:fixed) is a real DOM child of .site-header. With the blur on
   the header directly, opening the mobile menu anywhere past a 40px
   scroll made the "fullscreen" overlay size itself to the header's own
   small box instead of the viewport, so it only covered the top sliver
   of the screen and page content showed through underneath it. A
   sibling pseudo-element isn't an ancestor of nav.main-nav, so it can't
   affect its containing block. */
.site-header::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(to bottom, rgba(248,244,236,0.92), rgba(248,244,236,0));
  transition: background var(--transition), backdrop-filter var(--transition);
}
/* grid-column is pinned explicitly on all three rather than relying on
   DOM order for auto-placement. Grid auto-placement skips display:none
   items entirely — on mobile nav.main-nav (the middle item) is hidden,
   so without an explicit column .nav-end would auto-place into the
   now-vacant 2nd column right next to .logo instead of the 3rd (actual
   right-hand) column, clustering the heart/hamburger at the left with
   the real right-hand column sitting empty. */
.site-header > .logo { justify-self: start; grid-column: 1; }
.site-header > nav.main-nav { justify-self: center; grid-column: 2; }
.site-header > .nav-end {
  justify-self: end;
  grid-column: 3;
  display: flex;
  align-items: center;
  gap: 1.2rem;
}
.nav-heart {
  color: var(--wine);
  font-size: 1.15rem;
  line-height: 1;
}

.site-header.scrolled {
  padding: 0.9rem 6vw;
  border-bottom: 1px solid var(--line);
}
.site-header.scrolled::before {
  background: rgba(248,244,236,0.96);
  backdrop-filter: blur(6px);
}

.logo {
  font-family: var(--serif);
  font-size: 1.5rem;
  letter-spacing: 0.04em;
  color: var(--charcoal);
}

.logo em {
  font-style: italic;
  color: var(--wine);
}

.logo img.logo-mark {
  height: 58px;
  width: auto;
}

nav.main-nav ul {
  list-style: none;
  display: flex;
  gap: 2.2rem;
  margin: 0;
  padding: 0;
}

nav.main-nav a {
  font-size: 0.82rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  position: relative;
  padding-bottom: 4px;
}

nav.main-nav a::after {
  content: "";
  position: absolute;
  left: 0; bottom: 0;
  width: 0%;
  height: 1px;
  background: var(--wine);
  transition: width var(--transition);
}

nav.main-nav a.active::after {
  width: 100%;
}

/* Scoped to real hover-capable pointers (mouse/trackpad) only. On touch
   devices, tapping a link fires :hover too, kicking off the width
   transition below right as the page navigates away — so screenshots
   mid-navigation caught the underline frozen half-drawn. Devices
   without real hover never trigger this, so the effect just doesn't
   fire on mobile taps at all instead of rendering incompletely. */
@media (hover: hover) and (pointer: fine) {
  nav.main-nav a:hover::after {
    width: 100%;
  }
}

.nav-toggle {
  display: none;
  background: none;
  border: none;
  cursor: pointer;
  flex-direction: column;
  gap: 5px;
}
.nav-toggle span {
  width: 26px;
  height: 1px;
  background: var(--charcoal);
}

/* Close (x) control for the mobile nav overlay, injected by JS into
   nav.main-nav on every page. Hidden unconditionally here — it's only
   ever shown inside the mobile media query below, when the overlay is
   open. Without this base rule it had no default styling above the
   780px breakpoint at all and rendered as a bare, unstyled button (a
   plain white/gray box) sitting next to the desktop nav links. */
.nav-close { display: none; }

.wallet-btn {
  border: 1px solid var(--charcoal);
  padding: 0.5rem 1.1rem;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  border-radius: 999px;
  transition: var(--transition);
  cursor: pointer;
  background: transparent;
}
.wallet-btn:hover {
  background: var(--charcoal);
  color: var(--ivory);
}
.wallet-btn.wallet-btn-wine:hover {
  background: var(--wine);
  border-color: var(--wine);
  color: var(--ivory);
}

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

.btn {
  display: inline-block;
  padding: 0.85rem 2rem;
  border: 1px solid var(--charcoal);
  border-radius: 999px;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  transition: var(--transition);
}
.btn:hover {
  background: var(--charcoal);
  color: var(--ivory);
}
.btn.btn-wine {
  border-color: var(--wine);
  background: var(--wine);
  color: var(--ivory);
}
.btn.btn-wine:hover {
  background: var(--wine-deep);
  border-color: var(--wine-deep);
}

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

.hero {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  position: relative;
  padding: 8rem 6vw 4rem;
}

.hero .eyebrow { margin-bottom: 1.2rem; }

.hero h1 {
  font-size: clamp(2.2rem, 5.5vw, 4.2rem);
  line-height: 1.1;
  max-width: 16ch;
}

.hero h1 em { font-style: italic; color: var(--wine); }

.hero p.sub {
  max-width: 46ch;
  margin: 1.4rem auto 2.2rem;
  font-size: 1.05rem;
  color: var(--ink);
  opacity: 0.85;
}

.hero-frame {
  margin-top: 3rem;
  width: min(720px, 80vw);
  aspect-ratio: 16/10;
  border: 1px solid var(--line);
  background: var(--paper);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--gold);
  font-family: var(--serif);
  font-style: italic;
  overflow: hidden;
  position: relative;
}
.hero-frame img, .hero-frame video {
  width: 100%; height: 100%; object-fit: cover;
}

.piece-caption {
  margin: 0.9rem 0 0;
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(42, 36, 34, 0.55);
  font-family: var(--sans);
}
/* ---------- Link underline bloom (prose links throughout the site) ---------- */

.piece-caption a,
.eyebrow a,
main p a,
.post-item a,
.piece-desc a {
  position: relative;
  display: inline-block;
  color: var(--wine);
  font-weight: 500;
  text-decoration: none;
}
.piece-caption a::after,
.eyebrow a::after,
main p a::after,
.post-item a::after,
.piece-desc a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -2px;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: center;
  transition: transform 0.35s ease;
}
.piece-caption a:hover,
.eyebrow a:hover,
main p a:hover,
.post-item a:hover,
.piece-desc a:hover {
  color: var(--wine-deep);
}
.piece-caption a:hover::after,
.eyebrow a:hover::after,
main p a:hover::after,
.post-item a:hover::after,
.piece-desc a:hover::after {
  transform: scaleX(1);
}

/* A press/source link inside a Past Exhibitions title (e.g. the NPS
   article) should read as plain text at rest, like the other entries
   around it that have no link at all — the wine-colored bloom treatment
   above is too loud for a heading. Hovering still reveals it's a link. */
.post-item h3 a {
  color: inherit;
  font-weight: inherit;
}

.scroll-cue {
  margin: 3rem auto 0;
  font-size: 0.7rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  opacity: 0.6;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
}
.scroll-cue .line {
  width: 1px;
  height: 40px;
  background: var(--charcoal);
  animation: pulseLine 2.4s ease-in-out infinite;
}
@keyframes pulseLine {
  0%, 100% { transform: scaleY(0.4); opacity: 0.4; }
  50% { transform: scaleY(1); opacity: 1; }
}

/* ---------- Sections ---------- */

section {
  padding: 6.5rem 0;
}

.section-head {
  text-align: center;
  max-width: 60ch;
  margin: 0 auto 3.5rem;
}

.divider {
  width: 60px;
  height: 1px;
  background: var(--gold);
  margin: 1.4rem auto;
}

/* ---------- Reveal animation ---------- */

.reveal {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity 1s cubic-bezier(.22,.61,.36,1), transform 1s cubic-bezier(.22,.61,.36,1);
}
.reveal.is-visible {
  opacity: 1;
  transform: translateY(0);
}
.reveal-delay-1 { transition-delay: 0.12s; }
.reveal-delay-2 { transition-delay: 0.24s; }
.reveal-delay-3 { transition-delay: 0.36s; }
.reveal-delay-4 { transition-delay: 0.48s; }

/* ---------- Gallery Grid ---------- */

.gallery-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 2.2rem;
}

@media (max-width: 900px) {
  .gallery-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 600px) {
  .gallery-grid { grid-template-columns: 1fr; }
}

/* Centers a trailing incomplete row instead of leaving it flush left */
.gallery-grid.series-grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
}
.gallery-grid.series-grid .art-card {
  flex: 0 0 calc((100% - 4.4rem) / 3);
}
@media (max-width: 900px) {
  .gallery-grid.series-grid .art-card { flex: 0 0 calc((100% - 2.2rem) / 2); }
}
@media (max-width: 600px) {
  .gallery-grid.series-grid .art-card { flex: 0 0 100%; }
}

.art-card {
  position: relative;
  cursor: pointer;
  overflow: hidden;
  background: var(--paper);
  border: 1px solid var(--line);
}
a.art-card {
  display: block;
}

.art-card .media {
  aspect-ratio: 4/5;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--gold);
  font-family: var(--serif);
  font-style: italic;
  font-size: 0.95rem;
  text-align: center;
  /* Extra breathing room at the top of every frame (vs. the sides/bottom)
     so photos don't sit flush against the top edge — this used to be a
     one-off inline style on just the Sea of Flowers card; it's a baseline
     now so every gallery-grid frame across the site (home + portfolio)
     gets the same consistent top space. */
  padding: 2.25rem 1rem 1rem;
}
.art-card .media img,
.art-card .media video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: saturate(0.85) sepia(0.08);
  transition: transform 1.2s cubic-bezier(.22,.61,.36,1), filter 0.6s ease;
}
.art-card:hover .media img,
.art-card:hover .media video {
  transform: scale(1.06);
  filter: saturate(1.05) sepia(0);
}

.art-card .info {
  padding: 1.1rem 1.2rem 1.4rem;
}
.art-card .info h3 {
  font-size: 1.3rem;
  margin-bottom: 0.2rem;
}
.art-card .info p {
  margin: 0;
  font-size: 0.82rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--wine);
}

/* ---------- Coming Soon feature (single large centered preview) ---------- */

.coming-soon-feature {
  display: block;
  max-width: 640px;
  margin: 0 auto;
  text-align: center;
}
.coming-soon-frame {
  aspect-ratio: 16/9;
  overflow: hidden;
  background: var(--paper);
  border: 1px solid var(--line);
  margin-bottom: 1.5rem;
}
.coming-soon-frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: saturate(0.85) sepia(0.08);
  transition: transform 1.2s cubic-bezier(.22,.61,.36,1), filter 0.6s ease;
}
.coming-soon-feature:hover .coming-soon-frame img {
  transform: scale(1.06);
  filter: saturate(1.05) sepia(0);
}
.coming-soon-info h3 {
  font-size: 1.6rem;
  margin-bottom: 0.3rem;
}
.coming-soon-info p {
  margin: 0;
  font-size: 0.82rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--wine);
}

/* ---------- Placeholder box (for missing assets) ---------- */

.placeholder {
  border: 1px dashed var(--line);
  background: var(--paper);
  display: flex;
  align-items: center;
  justify-content: center;
  color: rgba(42,36,34,0.45);
  font-family: var(--serif);
  font-style: italic;
  font-size: 0.95rem;
  text-align: center;
  padding: 1.5rem;
}

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

.site-footer {
  border-top: 1px solid var(--line);
  padding: 3.5rem 6vw 2.5rem;
  text-align: center;
}
.footer-flourish {
  width: 42px;
  height: auto;
  margin: 0 auto 1rem;
  opacity: 0.85;
  filter: saturate(0.85);
}
.site-footer .socials {
  display: flex;
  justify-content: center;
  gap: 1.6rem;
  margin: 1.2rem 0 1.8rem;
}
.site-footer .socials a {
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  border-bottom: 1px solid transparent;
  transition: border-color var(--transition);
}
.site-footer .socials a:hover { border-color: var(--wine); }
.site-footer .fine-print {
  font-size: 0.72rem;
  opacity: 0.5;
}

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

.form-row {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-bottom: 1.6rem;
  text-align: left;
}
.form-row label {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--wine);
}
.form-row input,
.form-row textarea {
  font-family: var(--sans);
  font-size: 1rem;
  padding: 0.8rem 0.2rem;
  border: none;
  border-bottom: 1px solid var(--line);
  background: transparent;
  color: var(--ink);
  outline: none;
  transition: border-color var(--transition);
}
.form-row input:focus,
.form-row textarea:focus {
  border-color: var(--wine);
}

.contact-form {
  max-width: 560px;
  margin: 0 auto;
  text-align: center;
}
.form-error {
  color: var(--wine-deep);
  font-size: 0.85rem;
  margin-top: 1.2rem;
}
/* Swaps in for .contact-form on a successful send (see the fetch handler
   near the end of contact.html) — same card treatment as other quiet
   info panels on the site (.wallet-status, .placeholder) rather than a
   plain line of text, so the confirmation feels like a deliberate part
   of the page instead of an afterthought. */
.form-success {
  max-width: 560px;
  margin: 0 auto;
  padding: 2.6rem 2rem;
  text-align: center;
  border: 1px solid var(--line);
  background: var(--paper);
}
.form-success .piece-heart {
  font-size: 1.8rem;
  margin: 0 0 0.8rem;
}
.form-success h3 { margin: 0; }
/* js/shop.js scrolls #order-confirm into view on return from a
   successful Stripe Checkout. .site-header is position:fixed (~100-110px
   tall), so without this, scrollIntoView's default "align to the very
   top of the viewport" tucks this box's own top padding/heart emoji
   right underneath the fixed nav instead of leaving room for it. */
#order-confirm {
  scroll-margin-top: 140px;
}

.contact-meta {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 2rem;
  max-width: 900px;
  margin: 4rem auto 0;
  text-align: center;
}
@media (max-width: 700px) {
  .contact-meta { grid-template-columns: 1fr; }
}
.contact-meta h4 {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--wine);
  font-family: var(--sans);
  font-weight: 500;
}

/* Shipping/Returns/Privacy page (policies.html) — plain-prose sections,
   each with a small serif heading in the site's wine tone, spaced apart
   like paragraphs in an article rather than cards or a form. */
.policy-copy h3 {
  font-family: var(--serif);
  font-size: 1.3rem;
  color: var(--wine);
  margin: 2.5rem 0 0.8rem;
}
.policy-copy h3:first-child {
  margin-top: 0;
}
.policy-copy p {
  margin-bottom: 1rem;
  line-height: 1.7;
}

/* ---------- Shop ---------- */

/* TEMPORARY coming-soon holding screen — see the matching comment in
   shop.html. Same min-height/ivory-background treatment as
   .lc3-coming-soon so the page doesn't look awkwardly short with just
   one short message in it. Remove alongside the markup in shop.html once
   the shop reopens. */
.shop-coming-soon {
  min-height: 70vh;
  background: var(--ivory);
}

.shop-controls {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 2.6rem;
  margin: 0 0 2.8rem;
}
.shop-control {
  display: flex;
  align-items: baseline;
  gap: 0.7rem;
}
.shop-control label {
  font-family: var(--sans);
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--ink);
  opacity: 0.5;
}
.shop-control select {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  font-family: var(--serif);
  font-size: 0.95rem;
  color: var(--ink);
  background: transparent
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%237a3b3b' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E")
    no-repeat right center / 13px;
  border: none;
  border-bottom: 1px solid var(--line);
  border-radius: 0;
  padding: 0.2rem 1.4rem 0.35rem 0;
  cursor: pointer;
  transition: border-color var(--transition);
}
.shop-control select:hover,
.shop-control select:focus {
  border-color: var(--wine);
  outline: none;
}
.shop-control select::-ms-expand { display: none; }
.shop-empty {
  grid-column: 1 / -1;
  text-align: center;
  opacity: 0.6;
  font-family: var(--serif);
  font-style: italic;
}

.product-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 2.4rem;
}
@media (max-width: 900px) { .product-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 600px) { .product-grid { grid-template-columns: 1fr; } }

.product-card {
  background: var(--paper);
  border: 1px solid var(--line);
}
.product-card .media {
  position: relative;
  aspect-ratio: 1/1;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--gold);
  font-family: var(--serif);
  font-style: italic;
  overflow: hidden;
}
.product-card .media img { width: 100%; height: 100%; object-fit: cover; }
.media-expand-btn {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: rgba(248, 244, 236, 0.9);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  opacity: 0;
  transition: opacity var(--transition), background var(--transition), border-color var(--transition);
}
.product-card .media:hover .media-expand-btn,
.piece-frame:hover .media-expand-btn,
.media-expand-btn:focus-visible {
  opacity: 1;
}
.media-expand-btn:hover {
  background: var(--ivory);
  border-color: var(--wine);
}
.media-expand-btn svg {
  width: 15px;
  height: 15px;
  stroke: var(--ink);
}
.product-card .info { padding: 1.2rem 1.3rem 1.6rem; }
.product-card .price {
  font-family: var(--serif);
  font-size: 1.35rem;
  color: var(--wine);
  margin: 0 0 1.3rem;
  text-align: center;
}
.size-options {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 1.3rem;
}
.size-chip {
  border: 1px solid var(--wine);
  background: transparent;
  color: var(--wine);
  font-family: var(--sans);
  font-size: 0.8rem;
  padding: 0.45rem 0.9rem;
  border-radius: 999px;
  cursor: pointer;
  transition: background var(--transition), color var(--transition), border-color var(--transition);
}
.size-chip:hover {
  background: rgba(122, 59, 59, 0.08);
}
.size-chip.is-active {
  background: var(--wine);
  color: var(--ivory);
  border-color: var(--wine);
}
.size-chip.is-active:hover {
  background: var(--wine-deep);
  border-color: var(--wine-deep);
}
.product-card .btn {
  display: block;
  width: max-content;
  margin: 0 auto;
  padding: 0.65rem 1.6rem;
  font-size: 0.7rem;
  letter-spacing: 0.13em;
}
.product-card .buy-note {
  font-size: 0.8rem;
  margin-top: 0.7rem;
  opacity: 0.75;
  text-align: center;
}
.product-card .buy-note.error { color: var(--wine); opacity: 1; }

/* ---------- Shop lightbox: enlarge product image ---------- */
.lightbox-overlay {
  position: fixed;
  inset: 0;
  /* Same fixed+inset:0 pattern as nav.main-nav.open and .enter-gate above,
     so it gets the same explicit dvh height rather than relying on
     top:0/bottom:0 alone — otherwise this overlay could be left with the
     same kind of sliver of un-dimmed page peeking through on whichever
     phone sizes hit the toolbar/viewport mismatch, just here it'd show as
     a gap in the dark backdrop instead of a broken nav. */
  height: 100vh;
  height: 100dvh;
  z-index: 999;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2rem;
  background: rgba(42, 36, 34, 0.86);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--transition);
}
.lightbox-overlay.is-open {
  opacity: 1;
  pointer-events: auto;
}
.lightbox-overlay img[data-lightbox-img] {
  max-width: 88vw;
  max-height: 85vh;
  object-fit: contain;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4);
}
/* True-zoom variant, shared by the portfolio piece pages and the shop
   (js/main.js and js/shop.js both add this class to their overlay). At
   rest it behaves the same as the plain lightbox above (fit-to-screen,
   click to enlarge); clicking the enlarged image swaps to native pixel
   resolution — scrollable/pannable — centered on wherever was clicked,
   so detail actually gets bigger instead of just re-displaying at
   roughly the same size. */
.lightbox-overlay.is-piece-lightbox img[data-lightbox-img] {
  cursor: zoom-in;
}
.lightbox-overlay.is-piece-lightbox.is-zoomed-view {
  display: block;
  overflow: auto;
  padding: 0;
}
.lightbox-overlay.is-piece-lightbox.is-zoomed-view img[data-lightbox-img] {
  max-width: none;
  max-height: none;
  width: auto;
  height: auto;
  display: block;
  margin: 2rem auto;
  cursor: zoom-out;
  box-shadow: none;
}
.lightbox-close {
  position: absolute;
  top: 22px;
  right: 26px;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1px solid rgba(248, 244, 236, 0.4);
  background: rgba(248, 244, 236, 0.12);
  color: var(--ivory);
  font-size: 1.4rem;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background var(--transition);
}
.lightbox-close:hover { background: rgba(248, 244, 236, 0.28); }
.shop-loading {
  grid-column: 1 / -1;
  text-align: center;
  opacity: 0.6;
  font-family: var(--serif);
  font-style: italic;
}
.pod-note {
  text-align: center;
  max-width: 60ch;
  margin: 3rem auto 0;
  font-size: 0.85rem;
  opacity: 0.65;
}

/* ---------- NFT / Web3 ---------- */

.chain-tabs {
  display: flex;
  justify-content: center;
  gap: 1rem;
  margin-bottom: 3rem;
}
.chain-tab {
  padding: 0.6rem 1.4rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  cursor: pointer;
  background: transparent;
  transition: var(--transition);
}
.chain-tab.active,
.chain-tab:hover {
  background: var(--wine);
  border-color: var(--wine);
  color: var(--ivory);
}

.nft-card {
  background: var(--paper);
  border: 1px solid var(--line);
  overflow: hidden;
}
.nft-card .media {
  aspect-ratio: 1/1;
  display: flex; align-items: center; justify-content: center;
  color: var(--gold);
  font-family: var(--serif);
  font-style: italic;
}
.nft-card .media img { width: 100%; height: 100%; object-fit: cover; }
.nft-card .info { padding: 1.1rem 1.2rem; }
.nft-card .chain-badge {
  display: inline-block;
  font-size: 0.65rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  padding: 0.2rem 0.6rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  margin-bottom: 0.6rem;
}

.wallet-status {
  max-width: 640px;
  margin: 0 auto 2rem;
  text-align: center;
  padding: 1.2rem;
  border: 1px solid var(--line);
  background: var(--paper);
  font-size: 0.85rem;
}
.wallet-status.connected { border-color: var(--wine); }

.wallet-account-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.8rem;
  padding: 0.35rem 0;
  color: var(--wine);
}
.wallet-account-row .disconnect-btn {
  border: none;
  background: none;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink);
  opacity: 0.55;
  cursor: pointer;
  text-decoration: underline;
  padding: 0;
}
.wallet-account-row .disconnect-btn:hover { opacity: 1; color: var(--wine-deep); }

.buy-native-btn[disabled] {
  opacity: 0.5;
  cursor: wait;
}
.nft-card .info .tx-note {
  font-size: 0.72rem;
  margin-top: 0.6rem;
  opacity: 0.7;
}
.nft-card .info .tx-note.error { color: var(--wine-deep); }
.nft-card .info .tx-note a { text-decoration: underline; }

.listings-empty {
  text-align: center;
  padding: 3rem 1rem;
  opacity: 0.6;
  font-family: var(--serif);
  font-style: italic;
}

/* ---------- Poetry ---------- */

.poem-list {
  max-width: 640px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
}
.poem-card {
  display: block;
  text-align: center;
  padding: 2.6rem 2rem;
  border: 1px solid var(--line);
  background: var(--paper);
  transition: border-color var(--transition), transform var(--transition), box-shadow var(--transition);
}
.poem-card:hover {
  border-color: var(--wine);
  transform: translateY(-4px);
}
.poem-card time {
  display: block;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: rgba(42, 36, 34, 0.55);
  margin-bottom: 0.6rem;
}
.poem-card h3 {
  font-size: 1.7rem;
  margin-bottom: 0.9rem;
  transition: color var(--transition);
}
.poem-card:hover h3 { color: var(--wine); }
.poem-card .poem-excerpt {
  font-family: var(--serif);
  font-style: italic;
  color: var(--ink);
  opacity: 0.85;
  max-width: 46ch;
  margin: 0 auto;
  line-height: 1.8;
}
.poem-card .poem-cta {
  display: inline-block;
  margin-top: 1.4rem;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--wine);
  font-family: var(--sans);
}
.poem-card .poem-cta span {
  display: inline-block;
  transition: transform var(--transition);
}
.poem-card:hover .poem-cta span { transform: translateX(4px); }
.poem-empty {
  text-align: center;
  padding: 3rem 1rem;
  opacity: 0.6;
  font-family: var(--serif);
  font-style: italic;
}
.poem-detail {
  max-width: 56ch;
  margin: 0 auto;
  font-family: var(--serif);
  font-size: 1.05rem;
  line-height: 1.9;
}
.poem-detail p { margin-bottom: 1.6rem; }
.poem-detail p:last-child { margin-bottom: 0; }

/* ---------- Writing ---------- */

.post-list {
  max-width: 760px;
  margin: 0 auto;
}
.post-item {
  padding: 2.2rem 0;
  border-bottom: 1px solid var(--line);
  display: grid;
  grid-template-columns: 100px 1fr;
  gap: 1.5rem;
}
.post-item time {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--wine);
}
.post-item h3 { font-size: 1.5rem; margin-bottom: 0.4rem; }
.post-item p { margin: 0; opacity: 0.75; font-size: 0.95rem; }
@media (max-width: 600px) {
  .post-item { grid-template-columns: 1fr; }
}

/* ---------- About ---------- */

.about-layout {
  display: grid;
  grid-template-columns: 0.85fr 1.15fr;
  gap: 4rem;
  align-items: center;
}
@media (max-width: 850px) {
  .about-layout { grid-template-columns: 1fr; }
  .about-cta {
    display: block;
    width: fit-content;
    margin-left: auto;
    margin-right: auto;
  }
}
.about-portrait {
  aspect-ratio: 4/5;
  border: 1px solid var(--line);
  background: var(--paper);
  overflow: hidden;
}
.about-portrait img { width: 100%; height: 100%; object-fit: cover; }

.about-copy p { margin-bottom: 1.2rem; }

.stat-row {
  display: flex;
  gap: 3rem;
  margin-top: 2.5rem;
}
.stat-row .stat h4 {
  font-family: var(--serif);
  font-size: 2rem;
  color: var(--wine);
  margin-bottom: 0.1rem;
}
.stat-row .stat span {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  opacity: 0.6;
}

/* ---------- Series / Piece detail pages ---------- */

.piece-detail {
  max-width: 780px;
  margin: 0 auto;
}
.piece-frame {
  border: 1px solid var(--line);
  overflow: hidden;
  margin: 0 auto 1.2rem;
  width: fit-content;
  max-width: 100%;
  position: relative;
}
.piece-frame img,
.piece-frame video {
  display: block;
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 85vh;
}
.piece-detail .piece-caption {
  text-align: center;
  margin-bottom: 3rem;
}

/* Photo + text-card diptych (Appointment with Sophie Calle): the two
   images sit side by side as one piece rather than photo-then-caption
   stacked vertically. Wider max-width than the standard .piece-detail
   since it's two frames across instead of one. */
.piece-detail.piece-diptych {
  max-width: 960px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.5rem;
  align-items: center;
}
.piece-diptych .piece-diptych-frame {
  width: 100%;
  margin: 0;
}
.piece-diptych .piece-diptych-frame img {
  width: 100%;
  height: auto;
  max-height: none;
}
@media (max-width: 700px) {
  .piece-detail.piece-diptych {
    grid-template-columns: 1fr;
  }
}

.piece-desc {
  max-width: 60ch;
  margin: 0 auto;
  font-size: 1.02rem;
  line-height: 1.85;
  text-align: center;
}
.piece-desc p { margin-bottom: 1.2rem; }
.piece-desc .piece-heart {
  text-align: center;
  color: var(--wine);
  font-size: 1.3rem;
  margin: 1.6rem 0;
}
.piece-poetic {
  font-family: var(--serif);
  font-style: italic;
  color: var(--ink);
  text-align: center;
}
.series-list + .series-list {
  margin-top: 5rem;
}

/* Prev/Next between series or standalone pieces — sits below the last
   piece, above the footer. Order follows the same sequence as the
   Series / Standalone Pieces grids on portfolio.html, wrapping around
   from last to first within each group. Explicit two-column grid (not
   flex + space-between) so prev/next always occupy their own half no
   matter how short the titles are — with an explicit "Previous"/"Next"
   label above each title, so the two links read as clearly distinct
   rather than running together as one line. */
.piece-nav {
  max-width: 780px;
  margin: 4rem auto 0;
  padding-top: 2rem;
  border-top: 1px solid var(--line);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.5rem;
}
.piece-nav-link {
  display: block;
  text-decoration: none;
  transition: color var(--transition);
}
.piece-nav-link.prev {
  text-align: left;
}
.piece-nav-link.next {
  grid-column: 2;
  text-align: right;
}
.piece-nav-label {
  display: block;
  font-family: var(--sans);
  font-size: 0.68rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink);
  opacity: 0.5;
  margin-bottom: 0.4rem;
}
.piece-nav-title {
  display: block;
  font-family: var(--serif);
  font-size: 0.95rem;
  color: var(--ink);
}
.piece-nav-link:hover .piece-nav-title {
  color: var(--wine);
}
@media (max-width: 600px) {
  .piece-nav { grid-template-columns: 1fr; gap: 1.6rem; }
  .piece-nav-link.next { grid-column: 1; text-align: left; }
}

/* ---------- Page transitions ---------- */

.page-fade {
  animation: fadeInPage 0.8s cubic-bezier(.22,.61,.36,1);
}
@keyframes fadeInPage {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* ---------- Utility ---------- */

.text-center { text-align: center; }
.mt-large { margin-top: 5rem; }

@media (max-width: 780px) {
  nav.main-nav { display: none; }
  .nav-toggle { display: flex; }
  /* On desktop the header fades from ~92% opaque at rest to fully
     transparent at its own bottom edge (plus a blur once scrolled) so it
     sits nicely over a hero photo. On mobile the fixed header sits
     directly on top of ordinary page content the whole time you scroll
     (no separate hero area under it), so that same fade let artwork show
     through faintly underneath it. Forcing a flat, fully opaque ivory
     background here overrides both the resting and .scrolled states. */
  .site-header::before,
  .site-header.scrolled::before {
    background: var(--ivory);
    backdrop-filter: none;
  }
  /* On mobile the heart and hamburger used to sit right next to each
     other at the header's right edge (both packed into .nav-end with a
     small gap). Filling the whole grid column and spacing its two
     children apart pushes the heart back toward center while the
     hamburger lands alone at the true right edge. */
  .site-header > .nav-end {
    width: 100%;
    justify-content: space-between;
  }
  nav.main-nav.open {
    display: flex;
    position: fixed;
    /* .site-header > nav.main-nav has an explicit grid-column: 2 for its
       normal desktop layout inside the header's 3-column grid. Once this
       becomes position:fixed, browsers still resolve its containing block
       against that specific (narrow, auto-sized, centered) grid cell
       instead of the true viewport unless grid-column/justify-self are
       reset here — without this, inset:0 sized the overlay to the grid
       cell, not the screen, leaving page content and the hamburger icon
       visible on either side of a narrow centered strip. */
    grid-column: auto;
    justify-self: auto;
    inset: 0;
    /* inset:0's height (from top:0/bottom:0) is measured against Safari's
       collapsible-toolbar "layout viewport" on some iOS versions/devices
       rather than what's actually visible on screen — same class of bug
       already fixed on .enter-gate below. On phones where the mismatch is
       bigger (reported on iPhone 17, not reproducing on iPhone 11) this
       left a real gap where the overlay's ivory background didn't reach,
       showing page content through it. 100dvh tracks the true visible
       viewport instead; 100vh stays first as a fallback. */
    height: 100vh;
    height: 100dvh;
    /* Above .site-header's z-index (500) so the solid background fully
       covers the header instead of the header's own translucent gradient
       (plus logo/wallet button/hamburger) showing on top of the menu. */
    z-index: 600;
    background: var(--ivory);
    flex-direction: column;
    align-items: flex-end;
    justify-content: center;
    padding-right: 10vw;
  }
  nav.main-nav.open ul {
    flex-direction: column;
    text-align: right;
    gap: 2rem;
  }
  nav.main-nav.open a { font-size: 1.1rem; }

  /* Close (×) control injected by JS directly into the overlay — a
     close button left in .site-header can't be reached once the
     overlay is open, since it renders below the overlay's stacking
     context regardless of its own z-index. */
  .nav-close {
    display: none;
  }
  nav.main-nav.open .nav-close {
    display: flex;
    position: absolute;
    top: 1.7rem;
    right: 6vw;
    width: 26px;
    height: 26px;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    cursor: pointer;
  }
  nav.main-nav.open .nav-close span {
    position: absolute;
    width: 22px;
    height: 1px;
    background: var(--charcoal);
  }
  nav.main-nav.open .nav-close span:first-child { transform: rotate(45deg); }
  nav.main-nav.open .nav-close span:last-child { transform: rotate(-45deg); }
}

/* ---------- Entrance Gate ----------
   Fullscreen splash on the homepage — fades out on "Enter" and
   is skipped for the rest of the browser session (see the inline
   script in index.html). */

.enter-gate {
  position: fixed;
  inset: 0;
  /* On mobile, inset:0 alone can leave a gap at the bottom equal to the
     browser's collapsing address-bar toolbar (Safari/Chrome resize the
     layout viewport inconsistently as it shows/hides), which reads as
     white space below the gate and a background photo that doesn't
     quite reach the bottom edge. 100dvh tracks the real visible
     viewport instead, so the gate (and everything inset:0 inside it,
     including .enter-gate-bg's photo) always fills the actual screen.
     100vh stays first as a fallback for browsers without dvh support. */
  height: 100vh;
  height: 100dvh;
  z-index: 10000;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  background: var(--charcoal);
  transition: opacity 1.1s cubic-bezier(.22,.61,.36,1), visibility 1.1s;
}
.enter-gate.is-hidden {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

.enter-gate-bg {
  position: absolute;
  inset: 0;
}
.enter-gate-bg img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.94;
}

.enter-gate-flicker {
  display: none;
}
/* A light, hazy wash across the whole image (rather than a dark
   vignette) keeps the artwork's own colors readable, plus a soft
   dark pool centered behind the logo/button only, so they stay
   legible without darkening the rest of the photo. */
.enter-gate-bg::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(rgba(248,244,236,0.1), rgba(248,244,236,0.1)),
    radial-gradient(ellipse at center, rgba(20,17,15,0.4) 0%, rgba(20,17,15,0) 60%);
}

/* Vintage touch: a real film-gate overlay clip layered on top of the
   background image. Currently on option 2 (vintage-film-overlay-2.mp4) —
   trimmed to a clean loop that captures exactly one flash and settles back
   near baseline right before the native <video loop> restarts it, then
   slowed an additional 15% (setpts=PTS/0.85) on top of that, landing at an
   exact 3.5s loop. Blended with screen so the near-black grain recedes and
   the flash washes over the frame properly. The logo and Enter button text
   flash to orange exactly when the video itself flashes — driven live by
   JS reading this video's currentTime (see the script near the end of
   index.html and .enter-gate-logo-wrap::after / .enter-gate-btn.is-flashing
   below), not a separately-timed animation, so it can't drift out of sync.

   Two other options are preserved on disk if you want to switch back:
     - video/vintage-film-overlay-sprocket.mp4 (option 1 — calm sprocket
       edge, grain/dust/scratches, no flashing). Needs mix-blend-mode:
       multiply and opacity: 0.85 — its black margin was meant to darken
       into a vignette, which screen would wash out instead.
     - video/vintage-film-overlay-3.mp4 (option 3 — grain plus a slow warm
       orange/red light-leak burn, no flashing at all). Also uses screen.
   Swap the <source> in index.html and adjust mix-blend-mode here to match
   whichever option is live — the right blend mode depends on that specific
   clip's content, not a fixed rule. */
.enter-gate-film-overlay {
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* auto (not none): some browsers show a native "tap to play" affordance
     directly on the <video> when autoplay is blocked — pointer-events:none
     would make that tap silently do nothing. It still sits below
     .enter-gate-content and .enter-gate-sparkles (painted after it in
     the DOM at the same z-index), so it doesn't steal clicks meant for
     the Enter button or hover meant for the sparkles. */
  pointer-events: auto;
  mix-blend-mode: screen;
  opacity: 0.85;
}
/* Safari/WebKit draws its own large "tap to play" button directly on the
   <video> when it blocks true autoplay — visually jarring sitting on top
   of the vintage overlay. Safe to hide entirely: the JS unlock() fallback
   above listens on `document` for pointerdown/mousemove/touchstart/keydown/
   scroll/click (not specifically a tap on this button), so the video still
   starts on the visitor's very first interaction anywhere on the page. */
.enter-gate-film-overlay::-webkit-media-controls-start-playback-button {
  display: none !important;
  -webkit-appearance: none;
}

/* Vintage touch: a soft animated film-grain texture over the whole
   gate, on top of the other layers. Same feTurbulence noise recipe as
   the site-wide body::before paper grain, just sized/opacity'd to
   read clearly here. The "animation" is only ever a gentle translate
   of the tiled noise pattern via steps() — never an opacity/brightness
   change — so it reads as shifting grain rather than a flash/strobe
   (see the note on the removed 8mm-flicker effect above: anything that
   changes overall brightness on a fast interval is a photosensitivity
   risk; repositioning a low-opacity texture is not). Oversized via a
   negative inset so the steps never reveal a tile edge. */
.enter-gate-grain {
  position: absolute;
  inset: -10%;
  z-index: 1;
  pointer-events: none;
  opacity: 0.16;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 140px 140px;
  animation: grain-shift 0.5s steps(4) infinite;
}
@keyframes grain-shift {
  0%   { transform: translate(0%, 0%); }
  25%  { transform: translate(-2%, 1.5%); }
  50%  { transform: translate(1.5%, -2%); }
  75%  { transform: translate(-1%, -1%); }
  100% { transform: translate(0%, 0%); }
}

.enter-gate-petals {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
}
/* Each .petal is a single organic petal shape drawn with an asymmetric
   border-radius (no image assets needed) — a soft blush/rose gradient,
   picked from a small two-tone set via the --petal-hue custom property
   set in JS. There are no fixed/ambient ones — every .petal on the
   page is a mouse-trail one, spawned by JS in index.html as the cursor
   moves, playing the one-shot .petal-fall drift below and then
   removing itself. */
.petal {
  position: absolute;
  opacity: 0;
  border-radius: 0% 70% 60% 40% / 60% 30% 70% 40%;
  /* Falls back to Sea of Flowers' own peach/coral petals; overridden per
     load by the --gate-petal-* custom properties GATE_VARIANTS sets in
     index.html, so the falling petals match whichever photo is showing
     (e.g. golden tones for Valley of the Dolls, amber for Window
     Garden) rather than always being peach regardless of scene. */
  background: linear-gradient(135deg, var(--gate-petal-a, #edc9ba), var(--gate-petal-b, #e4ac95));
  filter: drop-shadow(0 1px 2px rgba(90, 60, 35, 0.25));
}
.petal.petal-warm {
  background: linear-gradient(135deg, var(--gate-petal-b, #e4ac95), var(--gate-petal-c, #dc876a));
}

/* Cursor-trail petals — spawned by JS in index.html as the visitor
   moves their mouse over the gate, so the field feels alive and
   responsive rather than purely decorative. Drifts sideways
   (--petal-drift) and spins (--petal-spin) as it falls and fades,
   then plays once and removes itself (see the mousemove listener). */
.petal-fall {
  --petal-drift: 0px;
  --petal-spin: 90deg;
  animation-name: petal-fall;
  animation-duration: 1.5s;
  animation-timing-function: ease-in;
  animation-iteration-count: 1;
  pointer-events: none;
}
@keyframes petal-fall {
  0%   { opacity: 0; transform: translate(0, 0) rotate(0deg) scale(0.6); }
  12%  { opacity: 0.9; }
  100% { opacity: 0; transform: translate(var(--petal-drift), 46px) rotate(var(--petal-spin)) scale(1); }
}

/* Stretches full-height so the logo can sit near the top while the
   button centers itself in whatever space is left below it (rather
   than the two being stacked as one centered block). */
.enter-gate-content {
  position: absolute;
  inset: 0;
  z-index: 2;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 4rem 2rem 3rem;
}
.enter-gate-logo-wrap {
  position: relative;
  display: inline-block;
  flex-shrink: 0;
}
.enter-gate-logo {
  height: 108px;
  width: auto;
  display: block;
  filter: brightness(0) invert(1) drop-shadow(0 2px 14px rgba(0,0,0,0.45));
}
/* Colored logo overlay, faded in/out during the video's flash — swapped
   per variant via the --gate-logo-flash custom property (a full url(...)
   value) set by GATE_VARIANTS in index.html, so each photo+accent
   pairing flashes its own matching tinted logo (images/logo-wine.png,
   logo-coral.png, logo-blue.png, logo-marigold.png, logo-plum.png)
   instead of always the same orange. Falls back to logo-orange.png if a
   variant doesn't set the property at all. */
.enter-gate-logo-wrap::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: var(--gate-logo-flash, url("../images/logo-orange.png"));
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.15s ease-out;
}
.enter-gate-logo-wrap.is-flashing::after {
  opacity: 1;
}
/* Drops the base white logo's own dark shadow while its colored overlay
   is flashing above it, so the flash reads as a clean flat tinted logo
   with no shadow at all rather than a shadow bleeding through from
   underneath. */
.enter-gate-logo-wrap.is-flashing .enter-gate-logo {
  filter: brightness(0) invert(1);
}
/* Gold border at rest, regardless of variant — a neutral resting state
   that reads fine against any of the gate's rotating background photos.
   The hover fill and the flash text color both switch to --gate-accent,
   a CSS custom property set per page load by the GATE_VARIANTS picker in
   index.html (one of several photo+accent pairings, chosen at random
   each time the gate shows) — see the note there for the full variant
   list. The var's fallback value (the original orange) only matters if
   that JS fails to run for some reason. */
.enter-gate-btn {
  letter-spacing: 0.28em;
  margin-top: auto;
  margin-bottom: auto;
  background: rgba(248,244,236,0.14);
  border: 1px solid var(--gold);
  color: var(--ivory);
  backdrop-filter: blur(3px);
  transition: background var(--transition), border-color var(--transition), color 0.15s ease-out;
}
.enter-gate-btn.is-flashing {
  color: var(--gate-accent, #d97757);
}
.enter-gate-btn:hover {
  background: var(--gate-accent, #d97757);
  border-color: var(--gate-accent, #d97757);
  color: var(--ivory);
}
/* Sea of Flowers wine variant only (GATE_VARIANTS' wine: true entry adds
   .is-wine to #enter-gate) — the resting border reads as wine instead of
   the neutral gold every other variant keeps, since gold read as too
   close to orange against this variant's darker reddish scene. */
.enter-gate.is-wine .enter-gate-btn {
  border-color: var(--gate-accent);
}
/* Glimmer variant only (GATE_VARIANTS' glimmer: true entry adds
   .is-glimmer to #enter-gate) — the resting border matches the petal
   trail's mid-tone rose (--gate-petal-b) instead of the neutral gold
   every other variant keeps, and switches to plum (--gate-accent) on
   hover or during the flash. The hover override needs its own rule
   (rather than relying on the generic .enter-gate-btn:hover below) since
   this resting rule's higher specificity — two ancestor classes plus the
   button class — would otherwise beat the generic hover rule and the
   border would stay rose even while hovering. */
.enter-gate.is-glimmer .enter-gate-btn {
  border-color: var(--gate-petal-b);
}
.enter-gate.is-glimmer .enter-gate-btn:hover,
.enter-gate.is-glimmer .enter-gate-btn.is-flashing {
  border-color: var(--gate-accent);
}

/* ---------- Magenta gate variant (Floral Lovescapes III) ---------- */

.enter-gate.is-magenta .petal {
  background: linear-gradient(135deg, #E795BF, #DB5B9C);
}
.enter-gate.is-magenta .petal.petal-warm {
  background: linear-gradient(135deg, #DB5B9C, #D53F8B);
}
/* Same border/fill/flash-text treatment as .enter-gate-btn's gold/orange
   pairing on the homepage, just in this site's magenta instead. */
.enter-gate.is-magenta .enter-gate-btn {
  border-color: #D53F8B;
}
.enter-gate.is-magenta .enter-gate-btn:hover {
  background: #D53F8B;
  border-color: #D53F8B;
}
.enter-gate.is-magenta .enter-gate-btn.is-flashing {
  color: var(--ivory);
}

/* Logo pinned at the top like the homepage gate's logo. Rendered solid
   black at rest (brightness(0) collapses the pink artwork to black
   while keeping its alpha edges), then the true-color pink version
   fades in on top during the flash window via the ::after overlay
   below — the same white-logo/orange-overlay swap trick the homepage
   uses, just inverted (black base / pink flash instead of white base /
   orange flash) since this logo starts out colored rather than needing
   an invert filter to go white. */
.lc3-top-logo {
  height: 108px;
  width: auto;
  display: block;
  filter: brightness(0) drop-shadow(0 2px 14px rgba(0,0,0,0.45));
}
.enter-gate.is-magenta .enter-gate-logo-wrap::after {
  background-image: url("../images/logo-lovescapes-iii.png");
}
.enter-gate.is-magenta .enter-gate-logo-wrap.is-flashing::after {
  filter: none;
}
/* Drops the base black logo's own drop-shadow while the pink overlay is
   flashing above it — same reasoning as the homepage gate's equivalent
   rule (.enter-gate-logo-wrap.is-flashing .enter-gate-logo above): without
   this, the shadow bleeds through from underneath the flash instead of
   the flash reading as a clean flat logo. */
.enter-gate.is-magenta .enter-gate-logo-wrap.is-flashing .lc3-top-logo {
  filter: brightness(0);
}

/* Title + Enter button live together in the middle of the remaining
   space below the logo (flex:1 fills whatever the logo doesn't use,
   then centers its own content within that space). */
.lc3-middle {
  flex: 1;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2.4rem;
}
.lc3-title {
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(2.4rem, 7vw, 5rem);
  letter-spacing: 0.01em;
  color: var(--ivory);
  filter: drop-shadow(0 2px 14px rgba(0,0,0,0.45));
  margin: 0;
  width: 100%;
  text-align: center;
  transition: color 0.15s ease-out;
}
/* Title flashes to the same magenta as the button/logo, driven by the
   same .is-flashing toggle (see the JS in lovescapes-iii/index.html). */
.enter-gate.is-magenta .lc3-title.is-flashing {
  color: #D53F8B;
}

.lc3-coming-soon {
  min-height: 100vh;
  background: var(--ivory);
  padding-bottom: 4rem;
}
.lc3-coming-soon .eyebrow a {
  color: #D53F8B;
}
