/* ============================================================
   Design tokens
   ============================================================ */
:root {
  --font-serif: 'Libre Baskerville', Georgia, serif;

  --color-ink: #111111;
  --color-dark: #0e0e0e;
  --color-paper: #ffffff;
  --color-card-border: #cccccc;
  --color-accent: #bed634;
  --color-arrow: #f4d03f;

  --shadow-card: 3px 3px 4px rgba(0, 0, 0, 0.35);
  --text-shadow-dark: 2px 2px 2px rgba(0, 0, 0, 0.6);

  --content-max-width: clamp(320px, 92vw, 1200px);
  --space-xs: clamp(0.5rem, 0.45rem + 0.25vw, 0.75rem);
  --space-sm: clamp(0.75rem, 0.65rem + 0.5vw, 1.25rem);
  --space-md: clamp(1.25rem, 1rem + 1vw, 2rem);
  --space-lg: clamp(2rem, 1.5rem + 2vw, 3.5rem);
  --space-xl: clamp(3rem, 2rem + 4vw, 6rem);

  --fs-body: clamp(1rem, 0.95rem + 0.2vw, 1.125rem);
  --fs-h1: clamp(2.5rem, 1.8rem + 3.5vw, 5.5rem);
  --fs-h2: clamp(1.75rem, 1.4rem + 1.5vw, 2.75rem);
  --fs-h3: clamp(1.25rem, 1.1rem + 0.75vw, 1.75rem);
  --fs-quote: clamp(1.75rem, 1.3rem + 2vw, 3.25rem);
  --fs-nav: clamp(0.85rem, 0.8rem + 0.15vw, 0.9375rem);

  --header-height: clamp(64px, 6vw, 76px);
  --menu-size: 128px;
  --menu-lift: -60px;

  --curtain-duration: 1.2s;
}

/* ============================================================
   Reset
   ============================================================ */
*, *::before, *::after {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
  font-family: var(--font-serif);
  font-size: var(--fs-body);
  color: var(--color-ink);
  background: #000;
  overflow-x: hidden;
}

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

button {
  font-family: inherit;
  color: inherit;
}

.main-content {
  opacity: 0;
}

body.curtains-open .main-content {
  opacity: 1;
  transition: opacity 0.6s ease;
}

/* ============================================================
   Curtains
   ============================================================ */
.curtain {
  position: fixed;
  left: 0;
  width: 100%;
  height: 50%;
  background: #0a0a0a url('../images/curtain-pattern.jpg') top center repeat;
  z-index: 9999;
  transition: transform var(--curtain-duration) ease-in;
}

.curtain--top {
  top: 0;
}

.curtain--bottom {
  bottom: 0;
}

.curtain__inner {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
}

.curtain--top .curtain__inner {
  bottom: var(--space-lg);
}

.curtain--bottom .curtain__inner {
  top: var(--space-md);
}

.curtain__logo {
  width: clamp(280px, 45vw, 640px);
  height: auto;
  margin-bottom: var(--space-md);
}

.curtain__preloader {
  width: clamp(96px, 14vw, 128px);
  height: auto;
}

.loadbar {
  width: min(460px, 74vw);
  height: 20px;
  background: rgba(255, 255, 255, 0.15);
  border: 2px solid rgba(255, 255, 255, 0.3);
  border-radius: 10px;
  overflow: hidden;
}

.loadbar__fill {
  height: 100%;
  width: calc(var(--loadbar-progress, 0) * 1%);
  background: url('../images/preloader-fill.jpg') center / 90px 90px repeat;
  transition: width 0.2s linear;
}

body.curtains-open .curtain--top {
  transform: translateY(-105%);
}

body.curtains-open .curtain--bottom {
  transform: translateY(105%);
}

body.curtains-hidden .curtain {
  visibility: hidden;
}

/* ============================================================
   Header
   ============================================================ */
.site-header {
  position: relative;
  z-index: 3;
  background: var(--color-paper);
  height: var(--header-height);
  flex: 0 0 auto;
  display: flex;
  align-items: center;
}

.site-header__inner {
  width: 100%;
  max-width: var(--content-max-width);
  margin-inline: auto;
  padding-inline: var(--space-md);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
}

.site-header__logo {
  height: clamp(32px, 4vw, 44px);
  width: auto;
}

.site-nav {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  flex: 1;
  justify-content: flex-end;
}

.site-nav__item {
  background: none;
  border: none;
  cursor: pointer;
  font-family: var(--font-serif);
  font-size: var(--fs-nav);
  color: var(--color-ink);
  padding: var(--space-xs) 0;
  transition: color 0.3s linear;
}

.site-nav__item:hover,
.site-nav__item:focus-visible {
  color: var(--color-accent);
}

.sound-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  cursor: pointer;
  padding: var(--space-xs);
  color: var(--color-ink);
  vertical-align: middle;
}

.sound-icon {
  width: 18px;
  height: 18px;
}

.sound-icon polygon {
  fill: currentColor;
}

.sound-icon__wave {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  transition: opacity 0.2s ease;
}

.sound-icon__mute-line {
  stroke: #d64545;
  stroke-width: 2.2;
  stroke-linecap: round;
  opacity: 0;
  transition: opacity 0.2s ease;
}

.sound-toggle[aria-pressed="true"] .sound-icon__wave {
  opacity: 0.25;
}

.sound-toggle[aria-pressed="true"] .sound-icon__mute-line {
  opacity: 1;
}

.sound-toggle--footer {
  color: #cccccc;
  padding: 0 0 0 var(--space-xs);
}

.sound-toggle--footer:hover,
.sound-toggle--footer:focus-visible {
  color: var(--color-accent);
}

.site-footer__copyright {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
}

/* ============================================================
   Social icons + speech-bubble popup
   ============================================================ */
.social-icons {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--space-xs);
}

.social-icons__item {
  background: none;
  border: none;
  cursor: pointer;
  padding: 2px;
  line-height: 0;
  opacity: 0.85;
  transition: opacity 0.2s ease;
}

.social-icons__item:hover,
.social-icons__item:focus-visible {
  opacity: 1;
}

.social-icons__item img {
  display: block;
  width: 22px;
  height: 22px;
}

/* Position: centered under the social-icon cluster, then shifted further
   left by the fixed pixel amount below (the --speech-bubble-shift value).
   TO ADJUST: change that one number -- bigger = further left, smaller/
   negative = further right. Nothing else here needs to change. */
:root {
  --speech-bubble-shift: 120px;
}

.speech-bubble {
  position: absolute;
  top: calc(100% + 8px);
  left: 50%;
  z-index: 10;
  width: min(260px, 80vw);
  opacity: 0;
  transform: translate(calc(-50% - var(--speech-bubble-shift)), -6px);
  transition: opacity 0.25s ease, transform 0.25s ease;
  pointer-events: none;
}

.speech-bubble.is-visible {
  opacity: 1;
  transform: translate(calc(-50% - var(--speech-bubble-shift)), 0);
}

.speech-bubble img {
  display: block;
  width: 100%;
  height: auto;
}

@media (max-width: 900px) {
  .social-icons {
    display: none;
  }
}

.site-header__actions {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
}

/* ============================================================
   Hamburger + mobile overlay menu
   ============================================================ */
.hamburger {
  display: none;
  position: relative;
  width: 26px;
  height: 20px;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
}

.hamburger span {
  position: absolute;
  left: 0;
  width: 100%;
  height: 2px;
  border-radius: 1px;
  background: var(--color-ink);
  transition: transform 0.25s ease, opacity 0.25s ease;
}

.hamburger span:nth-child(1) { top: 0; }
.hamburger span:nth-child(2) { top: 9px; }
.hamburger span:nth-child(3) { top: 18px; }

.hamburger[aria-expanded="true"] span:nth-child(1) {
  transform: translateY(9px) rotate(45deg);
}

.hamburger[aria-expanded="true"] span:nth-child(2) {
  opacity: 0;
}

.hamburger[aria-expanded="true"] span:nth-child(3) {
  transform: translateY(-9px) rotate(-45deg);
}

.mobile-menu[hidden] {
  display: none;
}

.mobile-menu {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: rgba(255, 255, 255, 0.92);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  opacity: 0;
  transition: opacity 0.3s ease;
}

.mobile-menu.is-open {
  opacity: 1;
}

.mobile-menu__close {
  position: absolute;
  top: var(--space-md);
  right: var(--space-md);
  width: 44px;
  height: 44px;
  background: none;
  border: none;
  font-size: 2rem;
  line-height: 1;
  color: var(--color-ink);
  cursor: pointer;
}

.mobile-menu__nav {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-lg);
}

.mobile-menu__item {
  background: none;
  border: none;
  cursor: pointer;
  font-family: var(--font-serif);
  font-size: clamp(1.25rem, 1rem + 1.5vw, 1.75rem);
  color: var(--color-ink);
  padding: var(--space-xs) var(--space-md);
  transition: color 0.3s linear;
}

.mobile-menu__item:hover,
.mobile-menu__item:focus-visible {
  color: var(--color-accent);
}

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

@media (max-width: 900px) {
  .site-nav {
    display: none;
  }

  .hamburger {
    display: block;
  }
}

/* ============================================================
   Stage + slides
   ============================================================ */
.stage {
  position: relative;
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  color: #ffffff;
  overflow: hidden;
  background: #000000 url('../images/hero-bg.jpg') top center / auto 100% repeat-x;
}

.stage__bg-layer {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  z-index: 0;
  opacity: 0;
  transition: opacity 800ms ease;
}

/* Slide-1's hero background holds its native height and tiles horizontally
   (it's a wall-curving-into-floor "stage" scene, not a photo meant to be
   cropped/stretched to cover) instead of the cover/center used by every
   other slide's crossfade background. */
.stage__bg-layer--tile {
  background-size: auto 100%;
  background-position: top center;
  background-repeat: repeat-x;
}

.stage__bg-layer.is-visible {
  opacity: 1;
}

.stage__overlay {
  position: absolute;
  inset: 0;
  z-index: 0;
  background: linear-gradient(rgba(0, 0, 0, 0.35), rgba(0, 0, 0, 0.55));
  opacity: 0;
  transition: opacity 800ms ease;
  pointer-events: none;
}

.stage.stage--dim .stage__overlay {
  opacity: 1;
}

.stage__slides {
  position: relative;
  /* Higher than .hero-float's z-index:1 (a sibling under .stage) so the
     logo/quote text always renders on top of the floating collage image,
     even if the collage's size/position ever miscalculates and overlaps
     it -- a safety net for unusual aspect ratios (e.g. ultra-wide
     monitors) on top of the sizing fix below. */
  z-index: 2;
  flex: 1;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-xl) var(--space-md);
  width: 100%;
}

.slide {
  display: none;
  width: 100%;
  max-width: var(--content-max-width);
  margin-inline: auto;
}

.slide.is-active {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-md);
}

/* Both start invisible (opacity:0) -- their one-time curtain-open entrance
   animation (played via playOnce() in js/main.js) is what reveals them, so
   they never flash fully-visible-then-fade the instant the curtain opens.
   See js/entrance-timing.js to tune the reveal delays/distances. */
.slide__logo {
  max-width: 480px;
  width: 62%;
  height: auto;
  opacity: 0;
}

.slide__quote {
  font-size: clamp(1.15rem, 0.9rem + 1.1vw, 1.9rem);
  font-style: italic;
  text-shadow: var(--text-shadow-dark);
  margin: 0;
  opacity: 0;
  transition: color 0.5s linear;
}

/* Nudged up so the hero collage and circular menu below have room to sit
   fully inside the stage instead of getting clipped by its overflow:hidden
   edge, plus a flat -20px on top of that (same at every viewport width)
   so the collage banner clears "The Works of Oleksiy Gorbenko" instead of
   touching it, most noticeably on wide screens. */
#slide-1 {
  margin-top: clamp(-120px, calc(-10vw - 20px), -70px);
}

.slide__quote:hover {
  color: var(--color-accent);
}

.hero-float {
  display: block;
  position: absolute;
  left: 50%;
  /* Rises higher as the viewport narrows (bigger bottom offset), so it
     stays clear of the circular menu row instead of getting covered by
     it, and moves up closer to the logo/subtext as they shrink. Desktop
     stays flat at the 105px floor; narrow screens climb toward 200px. */
  bottom: clamp(105px, calc(218px - 7vw), 200px);
  transform: translate(-50%, 0);
  z-index: 1;
  /* Real width (not just a max-width ceiling) with a floor of 340px so it
     doesn't keep shrinking away to nothing on narrow screens; max-width
     is a pure overflow safety net for screens under ~360px. The min(...)
     with a vh-based term only ever bites on short/wide viewports (e.g. an
     ultra-wide monitor) -- at normal desktop and portrait-phone aspect
     ratios 105vh comfortably exceeds 68vw so it's a no-op there, but on a
     short-height screen it reins the collage in before it can grow tall
     enough to cover "The Works of Oleksiy Gorbenko" above it. */
  width: clamp(340px, min(68vw, 105vh), 940px);
  max-width: 94vw;
  pointer-events: none;
}

.hero-float img {
  display: block;
  width: 100%;
  height: auto;
}

.hero-float[hidden] {
  display: none;
}

.slide__panel {
  background: rgba(255, 255, 255, 0.94);
  color: var(--color-ink);
  border-radius: 8px;
  padding: var(--space-lg);
  max-width: 600px;
  box-shadow: var(--shadow-card);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-sm);
}

.slide__heading-img {
  max-width: 260px;
}

.slide__body {
  margin: 0;
  line-height: 1.6;
}

.slide__cta {
  font-family: var(--font-serif);
  background: var(--color-dark);
  color: #ffffff;
  border: none;
  padding: var(--space-sm) var(--space-md);
  border-radius: 4px;
  cursor: pointer;
  font-size: var(--fs-nav);
  transition: background 0.3s ease, color 0.3s ease;
}

.slide__cta:hover,
.slide__cta:focus-visible {
  background: var(--color-accent);
  color: var(--color-ink);
}

/* ============================================================
   Circular menu
   ============================================================
   Hitbox fix: .menu-btn is the click/hover target and NEVER receives a
   transform — its box stays put through the whole animation. Only the
   child .menu-btn__visual is transformed on hover/focus, so the button's
   hoverable/clickable area never drifts away from where the eye thinks
   it is, and rapid clicks register no matter where the icon currently
   sits mid-animation.
   ============================================================ */
/* Starts invisible -- revealed once by the curtain-open entrance sequence
   (js/main.js openCurtains(), .anim-menuRiseIn), rising up into its
   resting position. In normal flex-column flow the menu row already sits
   flush against .stage's bottom edge (its height is what shrinks
   .stage__slides via flex:1), so any positive translateY here pushes it
   straight past .stage's overflow:hidden clip line -- a fixed small
   negative offset (rather than the previous translateY(50%), which
   dropped half the buttons and their whole shadow off the clipped edge)
   keeps the icon, label and shadow fully visible at every width,
   including when the row wraps to 3+2 on narrow screens. */
.circular-menu {
  position: relative;
  z-index: 2;
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  margin-top: auto;
  transform: translateY(-10px);
  opacity: 0;
}

.menu-btn {
  position: relative;
  width: var(--menu-size);
  height: var(--menu-size);
  margin: var(--space-sm);
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.menu-btn__shadow {
  position: absolute;
  left: 50%;
  bottom: -6px;
  transform: translateX(-50%) scale(1);
  width: 80%;
  height: 22%;
  background: radial-gradient(ellipse at center, rgba(0, 0, 0, 0.55) 0%, rgba(0, 0, 0, 0) 70%);
  transition: opacity 0.35s ease, transform 0.35s ease;
  opacity: 1;
  pointer-events: none;
}

.menu-btn__visual {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: 10% 12% 0 12%;
  border-radius: 50%;
  background: var(--color-dark);
  border: 3px solid var(--color-dark);
  outline: 2px solid rgba(255, 255, 255, 0.15);
  outline-offset: -2px;
  transition: transform 0.35s ease;
  transform: translateY(0);
}

.menu-btn__icon {
  width: 26%;
  height: 26%;
  flex: 0 0 auto;
  fill: none;
  stroke: #ffffff;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.menu-btn__label {
  color: #ffffff;
  font-family: var(--font-serif);
  font-size: clamp(0.7rem, 0.6rem + 0.4vw, 0.85rem);
  line-height: 1.15;
  text-align: center;
}

.menu-btn__flourish {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  margin-top: 2px;
}

.menu-btn__flourish::before {
  content: '';
  width: 55%;
  height: 1px;
  background: rgba(255, 255, 255, 0.3);
}

.menu-btn__stars {
  font-size: 0.5rem;
  letter-spacing: 1px;
  color: rgba(255, 255, 255, 0.55);
}

.menu-btn:focus-visible .menu-btn__visual {
  transform: translateY(var(--menu-lift));
  outline: 2px solid var(--color-accent);
  outline-offset: 3px;
}

.menu-btn:focus-visible .menu-btn__shadow {
  opacity: 0.35;
  transform: translateX(-50%) scale(0.6);
}

@media (hover: hover) and (pointer: fine) {
  .menu-btn:hover .menu-btn__visual {
    transform: translateY(var(--menu-lift));
  }

  .menu-btn:hover .menu-btn__shadow {
    opacity: 0.35;
    transform: translateX(-50%) scale(0.6);
  }
}

/* ============================================================
   Section-loading arrow
   ============================================================ */
/* position:absolute (out of normal flow) is load-bearing, not decorative:
   the arrow is shown/hidden via [hidden] (display:none) on a timer
   independent of the rest of the page, ~1.6s after a section reveals. If
   it were a normal in-flow element, that display toggle would shrink the
   whole document's height by the arrow's own box the instant it
   disappears -- shifting every bit of content below it (and the footer)
   upward by that amount with no animation, which reads as the page
   randomly jumping/scrolling a moment after everything already settled.
   Taking it out of flow means toggling it can never move anything else. */
.load-arrow {
  position: absolute;
  top: var(--space-sm);
  left: 50%;
  transform: translateX(-50%);
  text-align: center;
  font-size: 2rem;
  line-height: 1;
  color: var(--color-arrow);
  margin: 0;
  pointer-events: none;
}

/* ============================================================
   Content sections (About / Services / Prices / Portfolio /
   Testimonials / Contact details)
   ============================================================ */
.content-section {
  position: relative;
  background: #f4f4f2 url('../images/content-bg.jpg') top left repeat;
  padding-block: var(--space-xl);
}

/* Held invisible while js/sections.js waits on a section's images to
   finish loading (currently just #about) before playing its fade+drop-in
   reveal, so it never flashes in half-loaded then "re-animates". */
/* Applied to whichever content element (.content-section__inner, or just
   the <h2> for #portfolio -- see js/sections.js) is waiting to fade+drop
   in -- never to .content-section itself, since the section's own
   background/card surface should already be there the moment a visitor
   scrolls to it. */
.is-pending-reveal {
  opacity: 0;
}

.content-section__inner {
  max-width: var(--content-max-width);
  margin-inline: auto;
  padding-inline: var(--space-md);
}

.content-section h2 {
  font-size: var(--fs-h2);
  font-weight: 400;
  text-align: center;
  margin: 0 0 var(--space-lg) 0;
}

.card {
  background: var(--color-paper);
  border: 1px solid var(--color-card-border);
  box-shadow: var(--shadow-card);
  border-radius: 4px;
  padding: var(--space-md);
}

/* About */
.about__layout {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-lg);
}

.about__art {
  position: relative;
  flex: 0 0 auto;
  width: clamp(240px, 26vw, 300px);
  margin: 4.5rem 0 0 3rem;
}

.about__base {
  display: block;
  width: 100%;
  height: auto;
}

.about__thoughts {
  position: absolute;
  top: -90px;
  left: -55px;
  width: 82%;
  height: auto;
}

.about__bubbles {
  position: absolute;
  top: 46px;
  left: 51%;
  width: 15%;
  height: auto;
}

.about__bio {
  flex: 1 1 380px;
  max-width: 460px;
  line-height: 1.7;
  color: #444444;
}

/* Services */
.services__heading-accent {
  color: var(--color-accent);
}

.services__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--space-md);
}

.service-card {
  background: var(--color-paper);
  border: 1px solid var(--color-card-border);
  box-shadow: var(--shadow-card);
  border-radius: 6px;
  padding: var(--space-lg) var(--space-md);
  font-family: var(--font-serif);
  color: var(--color-ink);
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  transition: transform 0.25s ease;
}

.service-card:hover {
  transform: translateY(-4px);
}

.service-card__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: var(--color-dark);
  margin-bottom: var(--space-sm);
}

.service-card__icon svg {
  width: 30px;
  height: 30px;
  fill: none;
  stroke: #ffffff;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.service-card h3 {
  margin: 0 0 var(--space-sm) 0;
  font-size: var(--fs-h3);
  font-weight: 400;
}

.service-card p {
  margin: 0 0 var(--space-md) 0;
  line-height: 1.6;
  color: #555555;
  flex: 1;
}

.service-card__cta {
  font-family: var(--font-serif);
  background: var(--color-dark);
  color: #ffffff;
  border: none;
  padding: var(--space-xs) var(--space-md);
  border-radius: 4px;
  cursor: pointer;
  transition: background 0.3s ease, color 0.3s ease;
}

.service-card__cta:hover,
.service-card__cta:focus-visible {
  background: var(--color-accent);
  color: var(--color-ink);
}

/* Prices */
.pricing__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--space-md);
}

.pricing-card {
  background: var(--color-paper);
  border: 1px solid var(--color-card-border);
  box-shadow: var(--shadow-card);
  border-radius: 6px;
  padding: var(--space-md);
  display: flex;
  flex-direction: column;
}

.pricing-card h3 {
  margin: 0 0 var(--space-sm) 0;
  font-size: var(--fs-h3);
  font-weight: 400;
  color: var(--color-ink);
}

.pricing-card ul {
  list-style: none;
  margin: 0 0 var(--space-md) 0;
  padding: 0;
  flex: 1;
  color: #444444;
  line-height: 1.6;
}

.pricing-card li {
  padding-left: 1.1em;
  position: relative;
}

.pricing-card li::before {
  content: '\2713';
  position: absolute;
  left: 0;
  color: var(--color-accent);
}

.pricing-card__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
}

.pricing-card__buy {
  font-family: var(--font-serif);
  background: var(--color-dark);
  color: #ffffff;
  border: none;
  padding: var(--space-xs) var(--space-sm);
  border-radius: 4px;
  cursor: pointer;
  transition: background 0.3s ease, color 0.3s ease;
}

.pricing-card__buy:hover,
.pricing-card__buy:focus-visible {
  background: var(--color-accent);
  color: var(--color-ink);
}

.pricing-card__price {
  font-size: var(--fs-h3);
  font-weight: 700;
}

/* Shown in place of a section's content while it waits on images to load
   (see js/sections.js waitForImages()) -- currently only the portfolio
   grid, which can gain more items over time and shouldn't show broken/
   half-loaded circles on a slow connection. */
.section-loader {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-xl) 0;
}

.section-loader[hidden] {
  display: none;
}

.section-loader img {
  width: 72px;
  height: auto;
}

/* Thin real-progress bar under the spinner gif -- loaded/total portfolio
   images, reported by js/sections.js's waitForImages() -- so a slow first
   load reads as "in progress" instead of leaving the spinner alone to
   guess at (a spinner never proves anything's actually happening). */
.section-loader__bar {
  width: 140px;
  height: 4px;
  background: rgba(0, 0, 0, 0.12);
  border-radius: 4px;
  overflow: hidden;
}

.section-loader__bar-fill {
  height: 100%;
  width: 0%;
  background: var(--color-ink);
  border-radius: 4px;
  transition: width 0.2s linear;
}

/* Portfolio */
/* NOT display:none -- the grid's own <img loading="lazy"> elements need a
   real layout box to be considered "near the viewport" and start
   fetching at all. display:none gives them no box, so they'd never even
   begin loading and the reveal would sit on the fallback timeout instead
   of genuinely-loaded images. opacity:0 keeps them laid out (so loading
   proceeds normally) while staying invisible and out of the way. */
.portfolio__grid.is-loading {
  opacity: 0;
  pointer-events: none;
}

.portfolio__grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  /* extra row-gap so the bigger shadow below each item has clear room
     before the next row starts; column-gap stays as it was */
  gap: calc(var(--space-lg) + 30px) var(--space-md);
}

.portfolio-item {
  position: relative;
  display: block;
  width: clamp(140px, 16vw, 220px);
  height: clamp(140px, 16vw, 220px);
}

/* Positioned so its center sits at the circle's bottom edge (mostly BELOW
   the circle, not tucked behind it) -- otherwise the visual circle above
   it (same stacking, painted later in the HTML) hides most of the shadow
   image, leaving only its near-transparent feathered edge peeking out.
   To move it further down/up, adjust `bottom` (more negative = lower). */
.portfolio-item__shadow {
  position: absolute;
  left: 50%;
  bottom: -26%;
  transform: translateX(-50%) scale(1);
  width: 140%;
  height: 46%;
  background: url('../images/CircleShadow.png') center / contain no-repeat;
  opacity: 0.9;
  transition: opacity 0.3s ease, transform 0.3s ease;
  pointer-events: none;
}

.portfolio-item__visual {
  position: absolute;
  inset: 0;
  display: block;
  border-radius: 50%;
  overflow: hidden;
  box-shadow: var(--shadow-card);
  transition: transform 0.3s ease;
}

.portfolio-item__visual img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

@media (hover: hover) and (pointer: fine) {
  .portfolio-item:hover .portfolio-item__visual {
    transform: translateY(-18px);
  }

  .portfolio-item:hover .portfolio-item__shadow {
    opacity: 0.35;
    transform: translateX(-50%) scale(0.65);
  }
}

.portfolio-item:focus-visible .portfolio-item__visual {
  transform: translateY(-18px);
  outline: 2px solid var(--color-accent);
  outline-offset: 3px;
}

.portfolio-item:focus-visible .portfolio-item__shadow {
  opacity: 0.35;
  transform: translateX(-50%) scale(0.65);
}

/* Testimonials */
.testimonial-carousel {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
}

.testimonial-carousel__track {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  gap: var(--space-md);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}

.testimonial-carousel__track::-webkit-scrollbar {
  display: none;
}

.testimonial-card {
  flex: 0 0 100%;
  scroll-snap-align: start;
  background: var(--color-paper);
  border: 1px solid var(--color-card-border);
  box-shadow: var(--shadow-card);
  border-radius: 6px;
  padding: var(--space-md);
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--space-sm) var(--space-md);
  align-items: center;
}

.testimonial-card__photo {
  width: 80px;
  height: 80px;
  border-radius: 50%;
  object-fit: cover;
  grid-row: 1 / span 3;
}

.testimonial-card blockquote {
  margin: 0;
  font-style: italic;
  font-size: var(--fs-h3);
  color: var(--color-ink);
}

.testimonial-card__name {
  margin: 0;
  font-weight: 700;
}

.testimonial-card__works {
  margin: 0;
  font-size: 0.85em;
  color: #777777;
}

.testimonial-carousel__arrow {
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1px solid var(--color-card-border);
  background: var(--color-paper);
  cursor: pointer;
  font-size: 1rem;
}

/* Contact form (stage slide 5) */
.slide__panel--form {
  max-width: 460px;
  width: 100%;
  align-items: stretch;
  text-align: left;
}

.contact-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  width: 100%;
}

.contact-form__row {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

.contact-form label {
  font-size: 0.875rem;
  color: #555555;
}

.contact-form input,
.contact-form textarea {
  font-family: var(--font-serif);
  font-size: 1rem;
  padding: var(--space-xs);
  border: none;
  box-shadow: inset 2px 2px 2px rgba(0, 0, 0, 0.15);
  border-radius: 2px;
  outline-offset: 2px;
  resize: vertical;
}

.contact-form input:focus-visible,
.contact-form textarea:focus-visible {
  outline: 2px solid var(--color-accent);
}

.contact-form__error {
  margin: 0;
  min-height: 1.1em;
  font-size: 0.8rem;
  color: #c0392b;
}

.contact-form__honeypot {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.contact-form__status {
  margin: 0;
  padding: var(--space-xs) var(--space-sm);
  border-radius: 4px;
  font-size: 0.9rem;
}

.contact-form__status[data-state="success"] {
  background: #e3f5e1;
  color: #256029;
}

.contact-form__status[data-state="error"] {
  background: #fbe4e2;
  color: #922b21;
}

/* Contact details */
.contact-info {
  max-width: 520px;
  margin-inline: auto;
  text-align: center;
}

.contact-info__lead {
  margin: 0 0 var(--space-lg) 0;
  line-height: 1.7;
  color: #444444;
}

.contact-info__lead a {
  color: var(--color-ink);
  font-weight: 700;
}

.contact-info__rows {
  list-style: none;
  margin: 0 auto;
  padding: 0;
  max-width: 340px;
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
  text-align: left;
}

.contact-info__rows li {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
}

/* Wraps the label + link so "General Inquiries" reads as a small heading
   above the phone number instead of running directly into it on one line. */
.contact-info__text {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

.contact-info__label {
  font-size: 0.8125rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: #888888;
  margin-bottom: 2px;
}

.contact-info__icon {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
}

.contact-info__icon svg {
  width: 100%;
  height: 100%;
  fill: none;
  stroke: var(--color-ink);
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.contact-info__rows a {
  color: var(--color-ink);
  font-weight: 700;
}

/* ============================================================
   Responsive
   ============================================================ */
/* Below this width, 5 full-size circular buttons no longer fit on one row
   and the 5th wraps onto a second row that gets clipped by .stage's
   overflow:hidden. Shrinking the buttons keeps them all on a single row
   so they (and their shadows) stay fully visible. */
@media (max-width: 860px) {
  :root {
    --menu-size: 104px;
    --menu-lift: -40px;
  }

  .menu-btn {
    margin: 6px;
  }
}

@media (max-width: 768px) {
  .testimonial-card {
    grid-template-columns: 1fr;
    text-align: center;
    justify-items: center;
  }

  .testimonial-card__photo {
    grid-row: auto;
  }

  .about__layout {
    flex-direction: column;
    text-align: center;
  }
}

@media (max-width: 480px) {
  :root {
    --menu-size: 92px;
    --menu-lift: -30px;
    --header-height: 64px;
  }

  .menu-btn__flourish {
    display: none;
  }

  .site-header__inner {
    padding-inline: var(--space-sm);
    gap: var(--space-xs);
  }

  .menu-btn {
    margin: 4px;
  }

  .slide__panel,
  .slide__panel--form {
    padding: var(--space-sm);
  }
}

/* Mobile PORTRAIT (much taller than wide): the logo/subtext block was
   sized/positioned for a moderate aspect ratio, so on a tall narrow phone
   there's a lot of slack vertical space in .stage__slides' centering,
   leaving a big empty gap between the subtext and the (bottom-anchored)
   collage below it. Making the logo/subtext bigger eats into that slack,
   and pulling both blocks further toward each other closes the rest. */
@media (max-aspect-ratio: 0.75) {
  .slide__logo {
    width: 90%;
    max-width: 640px;
  }

  .slide__quote {
    font-size: clamp(1.4rem, 1rem + 4vw, 2.4rem);
  }

  #slide-1 {
    margin-top: clamp(-160px, calc(-10vw - 60px), -90px);
  }

  .hero-float {
    bottom: clamp(140px, calc(260px - 7vw), 240px);
  }
}

/* Mobile LANDSCAPE (short height): there isn't enough vertical room for
   the logo, subtext AND the collage to all fit without something getting
   clipped by .stage's overflow:hidden. Rather than shrink everything a
   little (still risking a cramped cut-off look), drop the logo/subtext
   entirely and let the collage have the space -- sized directly off the
   viewport height so it always fits fully, and moved down since it's
   fine for the circular menu row to sit over the top of it. */
@media (orientation: landscape) and (max-height: 500px) {
  .slide__logo,
  .slide__quote {
    display: none;
  }

  #slide-1 {
    margin-top: 0;
  }

  .hero-float {
    width: clamp(280px, 142vh, 620px);
    bottom: clamp(0px, 3vh, 20px);
  }
}

/* ============================================================
   Legal pages (privacy / terms / refund)
   ============================================================ */
body.legal-body {
  background: #f4f4f2;
}

.legal-content {
  max-width: 720px;
  margin-inline: auto;
  line-height: 1.7;
  color: #333333;
}

.legal-content h1 {
  font-size: var(--fs-h2);
  font-weight: 400;
  color: var(--color-ink);
  margin-top: 0;
}

.legal-content h2 {
  font-size: var(--fs-h3);
  font-weight: 700;
  text-align: left;
  margin: var(--space-lg) 0 var(--space-sm) 0;
}

/* ============================================================
   Site footer
   ============================================================ */
.site-footer {
  background: var(--color-dark);
  color: #cccccc;
  padding-block: var(--space-md);
}

.site-footer__inner {
  max-width: var(--content-max-width);
  margin-inline: auto;
  padding-inline: var(--space-md);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  font-size: 0.85rem;
}

.site-footer nav {
  display: flex;
  gap: var(--space-md);
}

.site-footer a {
  color: #cccccc;
  text-decoration: none;
}

.site-footer a:hover,
.site-footer a:focus-visible {
  color: var(--color-accent);
}

.site-footer p {
  margin: 0;
}
