/* ==========================================================================
   4+1 Design House — stylesheet
   Palette + type pulled from Figma design context (mobile + desktop frames)
   ========================================================================== */

:root {
  --charcoal-1: #2e2d2c;   /* header / hero background */
  --charcoal-2: #3a3837;   /* body copy, dark sections */
  --cream: #fffbf1;        /* light background, text on dark */
  --gold: #c0aa69;         /* borders, dividers */
  --gold-light: #d5c69b;   /* nav links, accents */
  --gold-tint: rgba(213, 198, 155, 0.2); /* input fill, badge fill */
  --panel-bg: #f7f4eb;

  --font-head: "Poppins", "Segoe UI", sans-serif;
  --font-body: "Lato", "Segoe UI", sans-serif;

  --max-width: 1360px;
  --gap-section: 80px; /* matches Figma's p-[80px] convention on desktop sections */

  --ease: cubic-bezier(0.22, 1, 0.36, 1);
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--cream);
  color: var(--charcoal-2);
  font-family: var(--font-body);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

h1, h2, h3 {
  font-family: var(--font-head);
  font-weight: 700;
  margin: 0;
  text-transform: uppercase;
  letter-spacing: 0.01em;
}

p { margin: 0; }

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

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

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--cream);
  color: var(--charcoal-1);
  padding: 12px 20px;
  z-index: 999;
}
.skip-link:focus { left: 12px; top: 12px; }

.section-inner {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 60px 20px;
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-body);
  font-weight: 700;
  border: none;
  border-radius: 12px;
  cursor: pointer;
  transition: transform 0.25s var(--ease), background 0.25s var(--ease);
}
.btn:hover { transform: translateY(-2px); }

.btn-ghost {
  background: var(--gold-tint);
  color: var(--cream);
  padding: 12px 24px;
  font-size: 16px;
}
.btn-ghost img { filter: invert(1) brightness(2); }

.btn-solid {
  background: var(--cream);
  color: var(--charcoal-2);
  padding: 14px 40px;
  font-size: 16px;
  justify-content: center;
  width: 100%;
}

/* ==========================================================================
   Header
   ========================================================================== */

.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: var(--charcoal-1);
  transition: background-color 0.35s var(--ease);
}
.site-header.is-scrolled { background: var(--gold-light); }

.header-inner {
  max-width: var(--max-width);
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 20px;
}

.brand { color: var(--gold-light); display: inline-flex; }

/* Logo crossfades between the top-of-page and scrolled header states.
   (Used to also crossfade the hamburger icon — removed along with the
   mobile menu, since there are no About/Contact pages to link to yet.) */
.logo-swap {
  position: relative;
  display: inline-flex;
}
.logo-mark { width: 90px; height: auto; display: block; }
.logo-mark--scrolled {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 0.35s var(--ease);
}
.site-header.is-scrolled .logo-mark--scrolled { opacity: 1; }

/* Visible on both mobile and desktop now — just two short links (Services,
   Contact), so it fits fine inline next to the logo at any width without
   needing a hamburger/drawer. Desktop widens the gap a bit further down. */
.site-nav { display: flex; gap: 20px; font-size: 15px; color: var(--gold-light); }
.site-nav a { transition: color 0.2s var(--ease); }
.site-nav a:hover { color: var(--cream); }
.site-header.is-scrolled .site-nav { color: var(--charcoal-2); }
.site-header.is-scrolled .site-nav a:hover { color: var(--charcoal-1); }

/* ==========================================================================
   Hero
   ========================================================================== */

.hero {
  position: relative;
  background: var(--charcoal-1);
  overflow: hidden;
  padding: 100px 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  min-height: 70vh;
}

/* Mobile: static pre-blurred glow photo behind the hero copy */
.hero-bg {
  position: absolute;
  inset: 0;
  background-image: url('../img/hero-mobile.jpg');
  background-size: cover;
  background-position: center;
}

/* Desktop: sharp logo mark, blurred by default, that "focuses" into view on scroll */
.hero-logo-mark {
  display: none;
  position: absolute;
  top: 50%;
  left: 50%;
  width: 640px;
  max-width: 62vw;
  transform: translate(-50%, -50%);
  filter: blur(46px);
  opacity: 0.92;
  pointer-events: none;
  will-change: filter;
}

.hero-inner {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 24px;
  max-width: 900px;
}

.hero h1 {
  color: var(--cream);
  font-size: 34px;
  line-height: 1.1;
}

.hero-sub {
  color: var(--cream);
  font-size: 17px;
  line-height: 1.5;
  max-width: 640px;
}

.hero-tag {
  color: var(--cream);
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 18px;
  margin-top: -10px;
  overflow: hidden;
  line-height: 1.3;
}

.hero-tag-ticker {
  display: inline-block;
  transition: opacity 0.4s var(--ease), transform 0.4s var(--ease);
}
.hero-tag-ticker.is-out {
  opacity: 0;
  transform: translateY(-100%);
}
.hero-tag-ticker.is-in {
  opacity: 0;
  transform: translateY(100%);
}

/* ==========================================================================
   About
   ========================================================================== */

.about .section-inner { padding-bottom: 0; }

.about h2 {
  font-size: 28px;
  color: var(--charcoal-2);
  margin-bottom: 16px;
  letter-spacing: 0.04em;
}
.about p {
  font-size: 17px;
  line-height: 1.7;
  max-width: 720px;
}
.about em {
  font-style: normal;
  font-weight: 900;
}

/* ==========================================================================
   Services
   ========================================================================== */

.services .section-inner { padding-top: 40px; }

.services-title {
  font-size: 28px;
  letter-spacing: 0.04em;
  margin-bottom: 28px;
}

.offerings {
  border-top: 1px solid rgba(192, 170, 105, 0.2);
}

.offering {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  border-bottom: 1px solid rgba(192, 170, 105, 0.2);
  padding: 22px 0;
  font-family: var(--font-head);
  cursor: pointer;
}

.offering-name {
  display: block;
  font-size: 20px;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: rgba(58, 56, 55, 0.4);
  transition: color 0.25s var(--ease);
}
.offering.is-active .offering-name { color: var(--charcoal-2); }

/* Grid-row trick lets height animate smoothly without knowing the
   content's pixel height up front. This closed-by-default state is what
   desktop uses (hover swaps which card is open); mobile overrides it to
   force every panel open all the time — see the max-width query below. */
.offering-panel {
  display: grid;
  grid-template-rows: 0fr;
  opacity: 0;
  transform: translateY(-6px);
  margin-top: 0;
}
.offering.is-active .offering-panel {
  grid-template-rows: 1fr;
  opacity: 1;
  transform: translateY(0);
  margin-top: 18px;
  transition: grid-template-rows 0.5s var(--ease), opacity 0.4s var(--ease), transform 0.45s var(--ease), margin-top 0.5s var(--ease);
}

/* Description text and artwork live inside one shared card (background,
   padding, rounded corners) instead of sitting as two separate unstyled
   elements — matches Figma node 234:1241. */
.offering-panel-inner {
  background: var(--panel-bg);
  border-radius: 16px;
  padding: 24px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 20px;
  min-height: 0;
  overflow: hidden;
}

.offering-panel p {
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.6;
  color: var(--charcoal-2);
  max-width: 480px;
}
.offering-panel .offering-meta {
  font-weight: 700;
  margin-top: 10px;
  font-size: 14px;
}
.offering-image {
  /* Real per-service artwork already ships as a complete square card
     (baked-in corners + background), so we just scale it, no cropping.
     will-change hints the browser about the parallax translateY script.js
     applies continuously on mobile (see computeOfferingParallax). */
  width: 100%;
  max-width: 300px;
  height: auto;
  border-radius: 12px;
  will-change: transform;
}

/* Mobile: no accordion. Every card's panel is forced open all the time —
   after several rounds of scroll-driven "only one card open" mechanisms
   (mandatory snap, sticky titles, a pinned stack, proximity snap) each
   producing their own jump/skip/stuck-scrolling issue, showing everything
   already open removes the whole category of problem, since there's no
   "which card is current" state left to get out of sync with scrolling.
   What's left is purely decorative, transform/opacity only, and driven by
   reading scroll position rather than setting it: each row fades + slides
   up into place the first time it enters the viewport (.is-revealed,
   toggled once by an IntersectionObserver in script.js), and each card's
   image gets a subtle parallax drift (applyOfferingParallax). */
@media (max-width: 959px) {
  .offering-panel {
    grid-template-rows: 1fr;
    opacity: 1;
    transform: translateY(0);
    margin-top: 18px;
  }
  .offering-name { color: var(--charcoal-2); }

  /* This is only the pre-JS fallback paint. The real opacity/translateY
     values are driven continuously by script.js as a direct function of
     scroll position (see computeOfferingsReveal), not a one-shot
     IntersectionObserver + fixed-duration CSS transition. A timed
     transition races the user's own scroll speed — on a normal scroll it
     can finish playing before the row is even fully on screen, so nothing
     visibly "fades in" by the time it's actually looked at. Tying the
     value straight to scroll position guarantees the motion is happening
     while the row is visibly moving into place, at any scroll speed. No
     CSS transition here on purpose: script.js already updates this every
     scroll frame, so a transition would just fight those frequent updates. */
  .offering {
    opacity: 0;
    transform: translateY(28px);
  }

  /* Same reasoning as above — image opacity is also set inline by
     script.js, lagging a beat behind its row's own progress so the reveal
     reads as layered (text first, image after) rather than one flat
     block. */
  .offering-image {
    opacity: 0;
  }
}

/* ==========================================================================
   Gallery
   ========================================================================== */

.gallery {
  background: var(--gold-tint);
  padding: 50px 0 60px;
  overflow: hidden;
}
.gallery h2 {
  text-align: center;
  font-size: 28px;
  margin-bottom: 28px;
  padding: 0 20px;
}

.carousel { position: relative; }

.carousel-track {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 0 20px 8px;
  overflow-x: auto;
  /* No scroll-snap-type here on purpose. The browser's native scroll-snap
     recalculates its target snap point off each item's live geometry —
     but script.js is changing every item's width every frame *during* the
     same scroll gesture, so the snap target was a moving goalpost. Late in
     a scroll (especially trackpad inertia), the browser would "correct"
     the offset toward a snap point that had already shifted since it was
     last computed, producing a hard, uncommanded jump independent of our
     own resize code. Centering is handled entirely by script.js instead
     (it already drives which item is "selected" from live position), and
     the prev/next buttons snap explicitly via scrollIntoView, so nothing
     is lost by removing native snap. */
  scrollbar-width: none;
  /* Fixed to the tallest ("selected") item height, plus a small buffer
     (see --h1 below — this used to match it exactly, 290px). Without the
     fixed height, the row's own height would follow whichever item is
     currently biggest, pushing the caption and arrows below it up and
     down as you scroll. The buffer matters too: at an exact match, a
     fully-selected item and its container were the same height with zero
     tolerance for sub-pixel rounding, so a selected item could end up a
     fraction of a pixel taller than the track and get clipped by its
     overflow — invisibly in most spots, but right at the top edge that
     was enough to shave off the rounded corner and make it read as
     square. A few px of headroom means that can't happen. */
  height: 298px;
}
.carousel-track::-webkit-scrollbar { display: none; }

/* Width set by script.js — see the HTML comment above the spacer markup. */
.carousel-spacer { flex: 0 0 auto; height: 1px; }

/* --w0/--h0 (resting size) and --w1/--h1 (fully-centered size) are read by
   script.js, which sets width/height directly every scroll frame as a
   continuous function of distance from center — not a discrete "selected"
   class + CSS transition. That's what keeps the resize gliding in lockstep
   with the scroll instead of flipping in discrete steps. Sizes are split
   by "shape" — landscape architecture/millwork shots, the near-square
   visual identity shot, and the portrait app screens. */
.carousel-item {
  margin: 0;
  flex: 0 0 auto;
  border-radius: 12px;
  overflow: hidden;
  --h0: 220px; --h1: 290px;
  --w0: 150px; --w1: 165px;
  width: var(--w0);
  height: var(--h0);
}
/* Architectural Design, Visual Identity, and Bespoke Millwork (landscape
   + square shapes) get a slightly larger 16px radius than the default —
   Sofia's call to make those three specifically read a touch softer.
   UX Design (portrait) keeps the original 12px. */
.carousel-item[data-shape="landscape"] { --w0: 300px; --w1: 380px; border-radius: 16px; }
.carousel-item[data-shape="square"] { --w0: 200px; --w1: 250px; border-radius: 16px; }
.carousel-item[data-shape="portrait"] { --w0: 125px; --w1: 165px; }

/* border-radius is set here too, not just relied on from the parent's
   overflow:hidden clip — Safari/WebKit can fail to clip an overflow:hidden
   box's corners when that box is being resized via JS on every frame
   (as these are), promoting it to its own composited layer and losing the
   clip on the top edge specifically. Declaring the radius directly on the
   img sidesteps that rather than depending on the parent to clip it. */
.carousel-item img { width: 100%; height: 100%; object-fit: cover; display: block; border-radius: 12px; }
.carousel-item[data-shape="landscape"] img,
.carousel-item[data-shape="square"] img { border-radius: 16px; }

.carousel-caption {
  display: flex;
  align-items: baseline;
  gap: 14px;
  justify-content: center;
  padding: 24px 20px 0;
  font-family: var(--font-body);
  font-weight: 700;
}
.carousel-index { display: none; } /* number hidden per Sofia's request — label text carries the caption alone now */
.carousel-label { font-size: 18px; }

.carousel-controls {
  display: flex;
  justify-content: center;
  gap: 12px;
  margin-top: 20px;
}
.carousel-btn {
  width: 42px;
  height: 42px;
  border-radius: 40px;
  border: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--charcoal-2);
  box-shadow: 0 10px 20px rgba(0,0,0,0.1);
  transition: transform 0.2s var(--ease), background 0.2s var(--ease);
}
.carousel-btn img { filter: invert(1) brightness(2); width: 16px; }
.carousel-btn img.flip { transform: rotate(180deg); }
.carousel-btn:hover { transform: translateY(-2px); }

/* ==========================================================================
   Partner With Us / Contact
   ========================================================================== */

.partner {
  position: relative;
  background: var(--charcoal-1);
  color: var(--cream);
  overflow: hidden;
}
.partner-bg {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(circle at 20% 20%, rgba(213,198,155,0.18) 0%, rgba(213,198,155,0) 45%),
    radial-gradient(circle at 80% 80%, rgba(192,170,105,0.15) 0%, rgba(192,170,105,0) 50%);
}
.partner-inner {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 24px;
}
.partner h2 { font-size: 26px; }
.partner > .section-inner > p { max-width: 600px; font-size: 16px; line-height: 1.6; }

.contact-form {
  width: 100%;
  max-width: 560px;
  display: flex;
  flex-direction: column;
  gap: 20px;
  margin-top: 12px;
  text-align: left;
}
.field { display: flex; flex-direction: column; gap: 8px; }

/* Netlify Forms honeypot — present in the markup so bots (which fill in
   every field they find) trip it, but hidden from real visitors and
   skipped by screen readers/tab order. display:none would also hide it
   from some bots that specifically check for that and skip the field,
   so this uses an off-screen position instead, which is what Netlify's
   own docs recommend. */
.hp-field {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}
.field label { font-family: var(--font-body); font-weight: 700; font-size: 15px; }
.field input,
.field textarea {
  background: var(--gold-tint);
  border: 1px solid transparent;
  border-radius: 4px;
  padding: 12px 16px;
  font-family: var(--font-body);
  font-size: 15px;
  color: var(--cream);
  resize: vertical;
}
.field input::placeholder,
.field textarea::placeholder { color: rgba(255,255,255,0.55); }
.field input:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--gold-light);
}

.form-note {
  font-size: 14px;
  color: var(--gold-light);
  min-height: 20px;
}

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

.site-footer {
  background: var(--charcoal-1);
  color: var(--gold-light);
}
.footer-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  text-align: center;
  font-size: 13px;
  padding: 40px 20px;
}
.footer-inner .logo-mark--footer { width: 70px; opacity: 0.85; color: var(--gold-light); }

/* ==========================================================================
   Desktop breakpoint (~1024px, matches Figma desktop frame)
   ========================================================================== */

@media (min-width: 960px) {
  .header-inner { padding: 24px 80px; }
  .logo-mark { width: 108px; }
  .site-nav { gap: 32px; font-size: 16px; }

  .section-inner { padding: var(--gap-section); }

  .hero { padding: 140px 40px; min-height: 85vh; }
  .hero h1 { font-size: 68px; }
  .hero-sub { font-size: 26px; max-width: 760px; }
  .hero-tag { font-size: 26px; }
  .btn-ghost { font-size: 20px; padding: 14px 28px; }

  .hero-bg { display: none; }
  .hero-logo-mark { display: block; }

  .about .section-inner { padding-bottom: 0; }
  .about h2 { font-size: 44px; margin-bottom: 20px; }
  .about p { font-size: 20px; line-height: 1.6; }

  .services .section-inner { padding-top: var(--gap-section); }
  .services-title { font-size: 44px; margin-bottom: 32px; }
  /* Positioned relative so every offering's card (regardless of which row
     is active) anchors to the same spot — the top of this list, matching
     where the first (UX Design) card appears. */
  .offerings { border-top: none; position: relative; }

  /* Full-width row (matches Figma node 234:2094). The name sits on the
     left; the card is absolutely positioned to its right so it overlays
     the section instead of pushing the rows below it further down. */
  .offering {
    display: block;
    padding: 20px 0;
    cursor: pointer;
  }
  .offering-name {
    font-size: 26px;
    display: inline-block;
  }

  .offering-panel {
    position: absolute;
    top: 0;
    bottom: auto;
    left: 560px; /* clears the longest title (~340px) + a 220px gap */
    right: 0;
    display: block;
    grid-template-rows: none;
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity 0.3s var(--ease);
    z-index: 2;
  }
  .offering.is-active .offering-panel {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    margin-top: 0;
    /* Restated (not inherited) on purpose: the shared .offering.is-active
       .offering-panel selector also carries its own transition value
       (used when desktop isn't the one matching), and since both rules
       have equal specificity, desktop needs its own explicit value here
       so it isn't affected by whatever that shared one is set to. */
    transition: opacity 0.3s var(--ease);
  }

  /* The shared card — text stacked above artwork — matching Figma node
     234:1241's bg-[#f7f4eb] wrapper. */
  .offering-panel-inner {
    min-width: 0;
    width: 100%;
    gap: 40px;
    padding: 40px;
  }
  .offering-text { max-width: 596px; }
  .offering-panel p { font-size: 18px; max-width: none; }
  /* Matches Figma's desktop "Card 3" wrapper: 164px icon + 40px padding each side */
  .offering-image { width: 244px; max-width: 100%; }

  .gallery { padding: 80px 0; }
  .gallery h2 { font-size: 44px; margin-bottom: 40px; }
  .carousel-track { height: 448px; } /* --h1 (440px) + buffer, see mobile comment above */
  .carousel-item {
    --h0: 320px; --h1: 440px;
    --w0: 200px; --w1: 260px;
  }
  .carousel-item[data-shape="landscape"] { --w0: 460px; --w1: 620px; }
  .carousel-item[data-shape="square"] { --w0: 300px; --w1: 400px; }
  .carousel-item[data-shape="portrait"] { --w0: 190px; --w1: 260px; }
  .carousel-label { font-size: 24px; }
  .carousel-btn { width: 56px; height: 56px; }

  .partner { padding: 40px 0; }
  .partner h2 { font-size: 52px; }
  .partner > .section-inner > p { font-size: 22px; }
  .contact-form { max-width: 680px; }
  .btn-solid { width: auto; padding: 14px 56px; font-size: 18px; }

  .footer-inner { flex-direction: row; justify-content: space-between; padding: 32px 40px; }
}

@media (min-width: 1280px) {
  .hero h1 { font-size: 80px; }
}
