/* Mobile + responsive — @media + prefers-reduced-motion. Load LAST so media queries win. */

/* ═══════════════════════════════════════ */
/*  RESPONSIVE                             */
/* ═══════════════════════════════════════ */
@media (max-width: 1180px) {
  .home-featured-grid { grid-template-columns: 1fr 1fr; grid-template-rows: 1fr; min-height: 0; }
  .feat-hero { grid-row: auto; min-height: 320px; }
  .feat-card { grid-template-columns: 1fr; }
  .feat-card-img { height: 200px; }
  .coll-grid { grid-template-columns: repeat(2, 1fr); }
  .gallery-grid { grid-template-columns: repeat(3, 1fr); }
  .hero-inner { padding: 56px 32px 44px; gap: 32px; }
  /* .home-featured intentionally NOT tightened here — it holds the base
     64px/56px/36px margin down to the phone breakpoint (≤767px) to match the
     Webflow treatment (consistent card margin across desktop/tablet). */
  .home-trust, .home-reviews { padding-left: 32px; padding-right: 32px; }
  /* Airshow logo nudge: -10px @ desktop = ~26% of 38px image height; at
     smaller image height the same -10px is proportionally heavier
     (~31% of 32px). -8px holds the wordmark on the row centerline at
     mobile sizes. */
  .client-mark img[src*="abbotsford"] { transform: translateY(-8px); }
  .home-reviews { padding-top: 64px; padding-bottom: 64px; }
  .view-collection { grid-template-columns: 240px 1fr; padding: 16px; gap: 16px; }

  /* Corporate page — tighten hero + collapse 3-card grid to 1-up so
     each card breathes. Single column reads better than 2 + 1 orphan. */
  .corp-hero-inner { padding: 64px 32px 44px; }
  .corp-diff { padding: 56px 32px 28px; }
  .corp-diff-grid { grid-template-columns: 1fr; gap: 16px; }
  .corp-reviews { padding-left: 32px; padding-right: 32px; padding-top: 64px; padding-bottom: 64px; }
}

@media (max-width: 1023px) {
  /* ══ MOBILE LAYOUT ══
     Breakpoint bumped 860 → 1023 (s40) so phone-landscape widths
     (852/932/956 = iPhone Pro/Pro Max/17 Pro Max landscape) get the
     mobile hamburger instead of being stuck in a desktop layout that
     doesn't fit. iPad-landscape (1024+) keeps desktop.
     ══ MOBILE LAYOUT (original notes) ══
     s21 (issue #5): the previous horizontal scroll-snap nav pattern
     between views was undiscoverable per the Kira bride-persona review
     AND was blocking the testimonial carousel swipe gesture on iOS
     (the .app-main horizontal scroll captured every horizontal touch
     before the testimonial pointer handlers fired). Replaced with the
     same opacity-cross-fade pattern desktop uses: tap a tab → only
     that view is visible. Single-page-app feel without horizontal
     scroll competition.

     iOS Safari fix: 100vh is the LARGE viewport (excludes address bar),
     so 100vh of content gets hidden under the Safari address bar +
     Dynamic Island. 100dvh is the DYNAMIC viewport — adapts as the
     address bar shows/hides. Also pad the top by safe-area-inset-top
     so the mockup-bar + nav clear the notch/island physically.

     Body is locked non-scrollable so rubber-band overscroll can't shift
     the nav during scroll-up gestures (s23: prior 1px-overscan hack
     coupled with nudgeSafariToolbar() let body move on iOS, which
     visibly bumped the header and clipped the logo). Modern iOS Safari
     (15.4+) shrinks the address bar from inner scroll containers, so
     the toolbar-shrink hack is unnecessary — the .view's vertical
     scroll triggers it natively. */
  html {
    overflow: hidden;
    overscroll-behavior: none;
    height: 100%;
  }
  body {
    overflow: hidden;
    overscroll-behavior: none;
    height: 100%;
    -webkit-overflow-scrolling: touch;
  }
  .app {
    height: 100dvh;
    min-height: 100dvh;
    overflow: hidden;
    padding-top: env(safe-area-inset-top, 0px);
    padding-bottom: env(safe-area-inset-bottom, 0px);
    box-sizing: border-box;
  }

  /* On mobile, keep the version stamp visible alongside the theme
     switcher (s21 — previously hidden when the span carried verbose
     iteration notes; now it's just `build.N · hash · date` which is
     useful for cache-verification on a phone). Shrink + truncate so
     it doesn't crowd the theme switcher. */
  .mockup-bar {
    justify-content: space-between;
    padding: 0 14px;
    overflow: hidden;
    gap: 10px;
  }
  .mockup-bar-notes {
    font-size: 10px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
    flex: 1 1 auto;
  }
  /* 8 chips + 2 group labels won't fit horizontally on phones inside the
     32px bar. Allow the chip strip to scroll horizontally; the version
     stamp stays pinned left and the chips swipe under it. */
  .mb-theme {
    padding-left: 0;
    border-left: none;
    flex-shrink: 1;
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;     /* Firefox */
    min-width: 0;
  }
  .mb-theme::-webkit-scrollbar { display: none; }  /* WebKit */
  .mb-theme-label { font-size: 10px; flex-shrink: 0; }
  .mb-theme-btn { padding: 3px 11px; font-size: 10.5px; flex-shrink: 0; }

  .app-nav {
    /* Desktop uses grid 1fr/auto/1fr to center the tabs on the viewport.
       Tabs are display:none on mobile, which collapses out of the grid and
       lets nav-right slide into the middle track. Switch to flex on mobile
       so the remaining two children sit at the edges via space-between.
       position: relative establishes the containing block for the
       absolutely-positioned .nav-phone below (see comment there). */
    display: flex;
    padding: 0 14px;
    /* Landscape notched phones: keep the logo (left) and the phone/CTA/burger
       cluster (right) clear of the Dynamic Island + rounded-corner safe area.
       viewport-fit=cover lets content fill edge-to-edge, so we inset by hand.
       max() is a no-op in portrait / on desktop (insets are 0 there). */
    padding-left: max(14px, env(safe-area-inset-left, 0px));
    padding-right: max(14px, env(safe-area-inset-right, 0px));
    gap: 10px;
    height: 64px;
    --nav-h: 64px;
    justify-content: space-between;
    position: relative;
    /* Drop the 18px backdrop-blur on mobile — combined with the
       grain overlay (now hidden on mobile) and pinch-zoom, it was a
       known iOS Safari crash vector. Solid cream background carries
       the editorial restraint just fine without the GPU cost. */
    background: var(--cream);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
  .nav-logo { height: 40px; flex-shrink: 0; }
  .nav-logo-img { height: 32px; }
  .nav-tabs { display: none; }
  /* ── Nav phone — PLAIN at every width: icon + tabular-num number, plum
     text, NO resting background or border. Matches the desktop treatment
     (components.css) so the phone never switches between a plain link and a
     pill — only its MODE changes (full number ⟷ icon), driven by room.

     COMPACT (600–1023, this base): full number, in NORMAL right-anchored
     flow inside .nav-right alongside the CTA + hamburger. There is room for
     logo + full-phone + CTA + hamburger here, so the phone always shows its
     number and never collapses. The icon-only collapse + the absolute-
     centered choreography live in the nested NARROW block below. */
  .nav-phone {
    position: static;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    height: 40px;
    padding: 0 6px;
    border-radius: 999px;     /* shapes the :active touch-feedback tint only */
    color: var(--brand);
    background: transparent;
    border: none;
    flex-shrink: 0;
    white-space: nowrap;
    transition: color 0.2s var(--ease), background-color 0.16s var(--ease);
  }
  .nav-phone:hover { color: var(--accent); }
  .nav-phone:active { background: rgba(58, 40, 24, 0.08); color: var(--accent); }
  .nav-phone-icon { width: 22px; height: 22px; flex-shrink: 0; }
  .nav-phone-num {
    font-size: 14px;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    color: var(--brand);
    white-space: nowrap;
  }

  /* ── NARROW (<600, portrait phones) — logo + full-phone + visible-CTA +
     hamburger can't all fit, so the phone collapses to an icon-only tap
     target and the CTA carries the action. The phone is position:absolute
     (out of .nav-right's right-anchored flow) so (a) the icon centers
     independently of CTA layout pressure, and (b) the CTA's reserved
     opacity:0 slot on home-top can't force a horizontal overflow at phone
     widths. Two states share one DOM, each centered against a different pair
     of flanking elements; `left` is in the transition list so the icon glides
     between them on scroll.

     Expanded (full number, STILL PLAIN — no pill bg/border) fires on the same
     three triggers that hide the CTA — home-top with hero CTAs in view, the
     /quote view, and cart-bar-up — so the header never shows a bare icon with
     no CTA. This preserves the scroll-reveal choreography exactly; only the
     pill background/border was dropped (per the plain-everywhere decision). */
  @media (max-width: 599px) {
    .nav-phone {
      position: absolute;
      /* Collapsed: center icon between logo right and CTA left.
         icon_left = icon_center - 20; cta_left = vw - 66 - cta_width (148).
         Recalibrates at ≤380 below where the CTA narrows for fit. */
      left: calc(50% - 62.5px);
      top: 12px;
      gap: 8px;
      justify-content: flex-start;
      min-width: 40px;
      max-width: 40px;
      padding: 0 9px;
      overflow: hidden;
      transition:
        left 220ms var(--ease-in),
        max-width 160ms var(--ease-in),
        background-color 160ms var(--ease-in);
    }
    .nav-phone-num {
      max-width: 0;
      opacity: 0;
      overflow: hidden;
      transition:
        max-width 160ms var(--ease-in),
        opacity 160ms var(--ease-in);
    }
    /* Expanded position: full number centered between logo right and
       hamburger left (CTA hidden in these states). */
    html[data-active-view="quote"] .nav-phone,
    html[data-cart-has-items="true"]:not([data-active-view="my-event"]):not([data-active-view="quote"]) .nav-phone {
      left: calc(50% - 45px);
      max-width: 220px;
    }
    html[data-active-view="quote"] .nav-phone-num,
    html[data-cart-has-items="true"]:not([data-active-view="my-event"]):not([data-active-view="quote"]) .nav-phone-num {
      max-width: 140px;
      opacity: 1;
    }
    /* home-top carries the 220ms delay so the phone expands only after the
       header CTA's hide animation finishes (scroll choreography). */
    html[data-active-view="home"][data-hero-cta-in-view="true"] .nav-phone {
      left: calc(50% - 45px);
      max-width: 220px;
      transition:
        left 220ms 220ms var(--ease-in),
        max-width 160ms 220ms var(--ease-in);
    }
    html[data-active-view="home"][data-hero-cta-in-view="true"] .nav-phone-num {
      max-width: 140px;
      opacity: 1;
      transition:
        max-width 160ms 220ms var(--ease-in),
        opacity 160ms 220ms var(--ease-in);
    }
  }
  /* Hamburger always gets its 44px — never let the expanded phone number
     push it off-canvas on narrow viewports. */
  .nav-hamburger { flex-shrink: 0; }

  /* ── Smart cart bar — slides up from bottom when cart has items
     (and the user isn't already on my-event or quote, where the bar is
     redundant). Editorial-restrained: cream-2 surface, hairline top,
     espresso copy, clay accent on the CTA arrow. The pull-tab grab
     handle reads "this came up from below" without screaming. */
  .smart-cart-bar {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 90;
    background: var(--cream-2);
    border-top: 1px solid var(--border-strong);
    box-shadow: 0 -10px 28px rgba(58, 40, 24, 0.10);
    padding: 14px 20px;
    padding-bottom: calc(14px + env(safe-area-inset-bottom, 0px));
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
    transform: translateY(120%);
    transition: transform 0.4s var(--ease);
    text-decoration: none;
    color: var(--ink);
  }
  .smart-cart-bar-grab {
    align-self: center;
    width: 38px;
    height: 4px;
    border-radius: 999px;
    background: var(--border-strong);
    opacity: 0.5;
    margin-bottom: 2px;
  }
  .smart-cart-bar-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    min-height: 44px;
  }
  .smart-cart-bar-count {
    font-size: 13px;
    color: var(--muted);
    font-weight: 400;
    letter-spacing: 0.01em;
  }
  .smart-cart-bar-count strong {
    color: var(--ink);
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    margin-right: 2px;
  }
  .smart-cart-bar-cta {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: 14px;
    color: var(--accent);
    font-weight: 500;
    letter-spacing: 0.01em;
  }
  .smart-cart-bar:active { background: var(--cream-3); }
  .smart-cart-bar:active .smart-cart-bar-cta { transform: translateX(1px); }
  /* Slide UP when cart has items + we're on a browse view */
  html[data-cart-has-items="true"]:not([data-active-view="my-event"]):not([data-active-view="quote"]) .smart-cart-bar {
    transform: translateY(0);
  }
  @media (prefers-reduced-motion: reduce) {
    .smart-cart-bar { transition: none; }
  }

  /* When the smart cart bar is up (cart has items on a browse view), the
     bar carries forward-to-quote, so the header CTA steps aside — and per
     the "CTA hidden ⟺ phone shows its full number" invariant, the phone
     expands at NARROW (see the expanded-state rules above, which include
     this same condition; at COMPACT the phone is already full). Net: header
     = logo · full phone number · hamburger. The redundant header cart pill
     and the shrink-to-coin progressive disclosure were both removed; the
     count is surfaced on the bar + the hamburger "My event" badge + the
     desktop tab badge. */
  html[data-cart-has-items="true"]:not([data-active-view="my-event"]):not([data-active-view="quote"]) .nav-cta-mobile {
    display: none;
  }

  /* Help bubble overlaps the smart cart bar when both are bottom-fixed.
     Lift it above the bar's footprint whenever the bar is showing — i.e.
     cart has items AND we're not on the my-event or quote view. Bar
     content is ~44px row + 14px top/bottom padding + ~10px grab + safe
     area = ~90-100px on iPhone. 92px clears it without overshooting. */
  html[data-cart-has-items="true"]:not([data-active-view="my-event"]):not([data-active-view="quote"]) .help-bubble {
    bottom: calc(env(safe-area-inset-bottom, 0px) + 92px);
  }
  /* Back-to-top lifts with it, staying 12px above (92 + 50 + 12 = 154). */
  html[data-cart-has-items="true"]:not([data-active-view="my-event"]):not([data-active-view="quote"]) .back-to-top {
    bottom: calc(env(safe-area-inset-bottom, 0px) + 154px);
  }

  /* Toast is hidden on mobile — the smart cart bar carries the
     forward-motion CTA the toast was designed for, at the same
     physical position, persistent, with a stronger CTA target
     (/quote vs /my-event). Toast remains on desktop where there's
     no cart bar. JS still calls showToast() on every add; this
     CSS rule makes the call a no-op on mobile. */
  .toast { display: none !important; }

  /* Smart cart bar covers the bottom of the scrolling view. Without
     internal bottom padding the last card in collection (and the last
     content row on home/gallery/corporate) clips under the bar with
     no way to scroll past. Custom property approach: --cart-bar-h is
     0 by default, kicks to ~100px when the bar is visible. .view
     reads it as padding-bottom so the scroll area extends past the
     bar's footprint. */
  html[data-cart-has-items="true"]:not([data-active-view="my-event"]):not([data-active-view="quote"]) {
    --cart-bar-h: calc(env(safe-area-inset-bottom, 0px) + 100px);
  }
  .view { padding-bottom: var(--cart-bar-h, 0px); }
  .nav-right { gap: 8px; }
  /* WCAG 2.5.5 minimum hit target: 44x44px. Was 36px tall (then 44).
     Text bumped 12 to 14 (no trailing arrow on this CTA, so the freed
     chrome space turns into legible CTA copy). Symmetric padding now
     that the asymmetric icon-padding is no longer needed. */
  .nav-cta-mobile { padding: 11px 18px; font-size: 14px; flex-shrink: 1; min-width: 0; min-height: 44px; }
  .nav-hamburger { display: grid; width: 44px; height: 44px; }

  /* .app-main + .view inherit the desktop pattern: .app-main is
     position:relative + overflow:hidden; .view is position:absolute
     + opacity-fade. overflow-x: hidden here is explicit (defensive
     armor for iOS Safari letting horizontal pan escape nested
     overflow:hidden parents). Vertical scroll within a view still
     works because of overflow-y: auto inherited from base.

     Note (s23): touch-action: pan-y used to be set on both layers
     as belt-and-suspenders for the testimonial Swiper's pre-init
     horizontal-pan escape. That armor blocked horizontal pan in
     every descendant — including the Collection page chip strip,
     which is a CSS-native horizontal scroller. Since .review-stage
     already carries its own touch-action: pan-y (sections.css:491),
     the outer pan-y was redundant. Removed to unblock the chip
     strip; .review-stage's local rule still protects the Swiper. */
  .app-main {
    overflow-x: hidden;
  }
  .view {
    overflow-x: hidden;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
  }

  /* Home */
  .hero { min-height: 460px; }
  .hero-inner {
    /* Bumped padding-bottom 32→72 so the scroll cue has dedicated space
       below the CTAs instead of overlapping them. */
    padding: 40px 22px 72px;
    /* Landscape notched phones: bring the headline in past the side safe area
       so it isn't tucked under the Dynamic Island / clipped by the corner.
       max() = no-op in portrait / desktop (insets 0). */
    padding-left: max(22px, env(safe-area-inset-left, 0px));
    padding-right: max(22px, env(safe-area-inset-right, 0px));
    grid-template-columns: 1fr;
    gap: 24px;
  }
  .hero-quote { display: none; }  /* keep hero focused on phone */
  /* Restore the elegant lighter weight at phone sizes where the h1 is
     smaller; default bumped to 400 for desktop firmness per Kira. */
  .hero h1 { font-size: clamp(38px, 9vw, 52px); font-weight: 300; }
  .hero-sub { font-size: 18px; }
  /* .home-featured holds its base margin here too — it steps down only at
     ≤767px (see the dedicated block below), matching Webflow's single, clean
     phone breakpoint instead of the earlier 1180/1023 reductions. */
  .home-trust { padding: 32px 20px; }
  .home-reviews { padding: 48px 20px; }
  /* Quote mark scales down on phones so it reads as a flourish,
     not a dominant element. */
  .review-text { font-size: 19px; }
  /* Bump arrow opacity at mobile so they read against the cream
     background without thumb-squinting. Size stays 28×28 (44×44 hit
     area via the ::after halo). */
  .review-nav-btn { opacity: 0.7; }
  /* Stack head vertically so the H2 gets full content-width instead of
     wrapping into a ~140px column next to the fixed-width link. */
  .home-featured-head {
    flex-direction: column;
    align-items: flex-start;
    gap: 18px;
  }
  .home-featured-head h2 { max-width: none; }
  .home-featured-grid { grid-template-columns: 1fr; }
  /* On mobile the desktop "editorial lead" treatment (overlay text on
     full-bleed photo) reads as inconsistent next to the image-top /
     text-below feat-cards. Collapse the lead card into the same layout. */
  .feat-hero {
    min-height: 0;
    display: flex;
    flex-direction: column;
    background: var(--cream-2);
  }
  .feat-hero img { position: relative; height: 200px; }
  .feat-hero::after { display: none; }
  .feat-hero-body {
    position: relative;
    padding: 22px 24px;
    color: var(--ink);
  }
  .feat-hero-tag { color: var(--faint); margin-bottom: 6px; }
  .feat-hero-title {
    color: var(--ink);
    font-size: 22px;
    font-weight: 400;
    margin-bottom: 4px;
  }
  .feat-hero-meta { color: var(--muted); }
  /* Horizontal stat rows on phone: number on the left (fixed slot),
     label flows right. Uses the available width instead of stacking
     everything left-aligned with empty space on the right. Works from
     360px to 440px+ — the only stat whose label wraps is the long
     middle one and that's intentional rhythm, not a bug.
     At tablet/phone-landscape widths (480–1023) the row is constrained via
     max-width + justify-self so the label column doesn't grow to a
     yawning gap; below that, max-width is non-binding so phone widths
     keep their natural flow. */
  .home-trust {
    grid-template-columns: 1fr;
    gap: 20px;
    padding: 32px 24px;
    justify-items: center;
  }
  .trust-stat {
    display: grid;
    grid-template-columns: 96px 1fr;
    align-items: center;
    gap: 18px;
    width: 100%;
    max-width: 380px;
    text-align: left;
  }
  .trust-stat-n { font-size: 36px; line-height: 1; }
  .trust-stat-l { margin-top: 0; max-width: none; font-size: 11px; line-height: 1.4; text-align: left; }
  .clients-strip { padding: 24px 20px 36px; gap: 14px; }
  .clients-strip-row { gap: 28px; }
  .client-mark { font-size: 18px; }
  .client-mark-img { height: 32px; }
  .site-footer { padding: 48px 24px 28px; }
  .footer-inner { grid-template-columns: 1fr; gap: 32px; }
  .footer-legal { flex-direction: column; gap: 6px; margin-top: 28px; padding-top: 20px; }

  /* Collection — stack filter above, content below.
     flex-shrink: 0 on filter prevents the parent's overflow:hidden from
     squashing the strip and clipping the chips.
     coll-main takes remaining space + scrolls internally with min-height:0
     (without min-height:0 a flex item won't shrink below its content size,
     which would push the page taller than the viewport).

     Mobile filter is a borderless horizontal-scroll chip strip — the
     desktop bezel card eats ~33% of the viewport with the cart bar up.
     Flatten the chrome, drop to a single row, scroll-snap + right-edge
     fade hint at more chips off-screen (Aesop / Cereal pattern). */
  .view-collection { display: flex; flex-direction: column; padding: 0; gap: 0; }
  .coll-intro { padding: 20px; flex-shrink: 0; }
  /* coll-body fills the rest and is the flex column that lets .coll-main
     (its flex:1 child) keep being the internal scroll surface. */
  .coll-body { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; padding: 0; overflow: hidden; }
  .coll-filter-bezel {
    margin: 0;
    padding: 0;
    background: none;
    border-radius: 0;
    box-shadow: none;
    max-height: none;
    align-self: stretch;
    min-width: 0;
  }
  .coll-filter {
    padding: 12px 20px 4px;
    background: none;
    border-radius: 0;
    box-shadow: none;
    max-height: none;
    overflow: visible;
    min-width: 0;
  }
  /* Filter → WF parity: a wrapping chip row (not a horizontal scroll strip).
     Wrapping has no overflow to manage, so the old scroll machinery (edge-fade
     mask + iOS touch-pan fixes) is no longer needed. */
  .filter-opts {
    flex-direction: row;
    flex-wrap: wrap;
    gap: 6px;
    padding: 0;
  }
  .filter-opt {
    flex-shrink: 0;
    padding: 6px 12px;
    font-size: 14px;
    border-radius: 20px;
    background: transparent;
    color: var(--muted);
    box-shadow: inset 0 0 0 1px var(--champagne);
  }
  .filter-opt:hover { background: transparent; }
  .filter-opt.active {
    background: var(--ink);
    color: var(--cream);
    box-shadow: inset 0 0 0 1px var(--champagne);
  }
  /* .coll-main is the internal scroll surface on the collection view
     (the .view itself is overflow:hidden — see sections.css:836 — so
     the .view-level --cart-bar-h padding doesn't reach the scrollable
     element). Layer the cart-bar height onto the bottom pad so the
     last product card can scroll above the smart cart bar instead of
     clipping behind it.

     Geometry note (s23): tried matching border-top-radius: 22px on
     this surface to echo the filter card's bottom radius — visually
     read as "upside-down curve" because rounded corners on stacked
     rectangles produce MIRRORED curves (filter card's bottom corners
     pull up; this surface's top corners pull down). Pulled the
     rounding back to 0; the linear fade carries the transition
     cleanly with no competing curve direction. Side inset (margin:
     0 16px) is kept so the scrolling surface vertically aligns with
     the filter card's 16px margin. */
  .coll-main {
    margin: 0 20px;
    padding: 24px 0 calc(32px + var(--cart-bar-h, 0px));
    flex: 1 1 auto;
    min-height: 0;
    /* Eased gradient (4 stops) — matches iOS 26 scrollEdgeEffect.soft.
       Same 24px window length as the linear version we had, but the
       per-pixel alpha curve is non-linear: slow at the start
       (transparent → 40% over the first 8px), then accelerates
       through the middle, then plateaus toward fully opaque. Reads
       as "buttery" rather than "ramp" without lengthening the fade. */
    -webkit-mask-image: linear-gradient(180deg,
      rgba(0, 0, 0, 0)    0,
      rgba(0, 0, 0, 0.40) 8px,
      rgba(0, 0, 0, 0.85) 16px,
      rgba(0, 0, 0, 1)    24px);
    mask-image: linear-gradient(180deg,
      rgba(0, 0, 0, 0)    0,
      rgba(0, 0, 0, 0.40) 8px,
      rgba(0, 0, 0, 0.85) 16px,
      rgba(0, 0, 0, 1)    24px);
  }
  .coll-grid { grid-template-columns: 1fr; gap: 16px; }
  .coll-head { flex-direction: column; align-items: flex-start; gap: 6px; }

  /* Lighter, less-directional shadow for product cards on mobile.
     Desktop's --shadow-card has heavy downward y-offsets (0/+1, 0/+4,
     0/+16) appropriate for a 3-column grid where shadows spread to the
     sides. In the mobile single-column stack with 16px gap, the bottom
     of each card dumps its 16px-offset 36px-blur layer straight into
     that gap before the next card — reads as a darker stripe between
     cards while the left/right cream remains untouched. Swap to a
     compact, mostly-symmetric shadow: tight surround + a small soft
     drop. Total shadow density ~30% of desktop's, gap blends with the
     side cream. */
  .product-shell {
    box-shadow:
      var(--ring-hair),
      0 0 1px rgba(58,40,24,0.06),
      0 2px 8px rgba(58,40,24,0.06);
  }
  /* Hover doesn't reliably fire on touch — keep the rule but match the
     same mobile shadow language so any pointer-device on a narrow
     viewport doesn't snap to the heavy desktop shadow. */
  .product:hover .product-shell {
    box-shadow:
      var(--ring-hair),
      0 0 1px rgba(58,40,24,0.08),
      0 4px 14px rgba(58,40,24,0.08);
  }

  /* My Event — stack panes at NATURAL height and let .view do the scrolling.
     Was display:flex with both panes set to overflow-y:auto, which created
     nested scrolls and clipped the empty-state CTA off the bottom of the
     items pane. Block layout + overflow:visible on the panes lets the
     items-pane content extend naturally and submit-pane sits below; the
     whole view scrolls as one continuous page. */
  .me-cart-shell { padding: 28px 20px 40px; }

  /* Gallery — 2-col bento at phone widths. The nth-child feature tiles still
     apply (a 2×2 feature becomes a full-width 2-row hero; a wide becomes a
     full-width row), but the standalone TALL must collapse to 1 row or it
     punches a hole at 2 cols. */
  .view-gallery { padding: 24px 20px 40px; }
  .gallery-grid { grid-template-columns: repeat(2, 1fr); grid-auto-rows: 150px; gap: 8px; }
  .gallery-grid > .gallery-img:nth-child(8n + 6) { grid-row: span 1; }

  /* Request a Quote */
  .raq-shell { padding: 28px 18px 48px; }
  .raq-head h2 { font-size: clamp(26px, 7vw, 34px); }
  .raq-row { grid-template-columns: 1fr; }
  .raq-block-title { font-size: 19px; }
  .raq-chip { font-size: 13px; padding: 10px 14px; }
  /* Tighten field cards: the small-caps label had a 20px line-height on a 10px
     font (2x) and the 13px card padding stacked on top — fields ran ~90px.
     Field -> ~76px; the input (tap target) is left untouched. */
  .raq-field { padding: 10px 16px; }
  .raq-field label { line-height: 1.2; }

  .help-panel { width: calc(100vw - 36px); right: 18px; max-height: 440px; }
  .help-bubble { bottom: 18px; right: 18px; width: 50px; height: 50px; }
  /* Back-to-top stacks 12px above the help-bubble (18 + 50 + 12 = 80). */
  .back-to-top { bottom: 80px; right: 18px; width: 50px; height: 50px; }

  /* Corporate page — stack the 3 differentiator cards and shrink the
     hero padding to match other views. */
  .corp-hero { min-height: 360px; }
  .corp-hero-inner { padding: 56px 20px 36px; }
  .corp-diff { padding: 48px 20px 24px; }
  .corp-diff-grid { grid-template-columns: 1fr; gap: 14px; }
  .corp-diff-card { padding: 22px 20px 20px; }
  .corp-reviews { padding: 48px 20px; }

  /* Journal index — single-column stack, mirrors the gallery breakpoint. */
  .view-journal { padding: 24px 20px 56px; }
  .journal-head { flex-direction: column; align-items: stretch; gap: 16px; margin-bottom: 24px; }
  .journal-grid { grid-template-columns: 1fr; gap: 18px; }
  .journal-card-img { aspect-ratio: 16 / 10; }
  .journal-card-body { padding: 20px 22px 22px; gap: 8px; }
  .journal-card-title { font-size: 20px; }
  .journal-card-excerpt { font-size: 14px; }

  /* Journal post: taller hero aspect (4:3 fits portrait viewports better than
     16:9), tighter shell padding, body drops one step to 17px serif for
     comfortable mobile reading. Lede + blockquote scale proportionally. */
  .journal-post-hero { aspect-ratio: 4 / 3; max-height: none; }
  .journal-post-shell { padding: 48px 20px 80px; }
  .journal-post-header { margin-bottom: 32px; }
  .journal-post-body { font-size: 17px; }
  .journal-post-body > p:first-of-type,
  .journal-post-body .journal-post-lede { font-size: 20px; }
  .journal-post-body blockquote { font-size: 21px; padding-left: 22px; }
  .journal-post-body .journal-post-figure { margin: 1.5em -20px; }
  .journal-post-body .journal-post-figure img { border-radius: 0; }
  .journal-post-body .journal-post-figure figcaption { padding: 0 20px; }
}

/* Featured card margin steps down ONCE, at the phone breakpoint — matching
   Webflow's single 767px step (generous 56px side margin held across
   desktop + tablet, then tighter on phone). Base = sections.css .home-featured
   (64px 56px 36px). Replaces the earlier 1180/1023 reductions that made the
   card margin inconsistent across breakpoints. */
@media (max-width: 767px) {
  .home-featured { padding: 32px 20px 16px; }

  /* Home journal teaser — single column at phone only. Moved up from the
     1023px block to match Webflow's single 767px step (the teaser was
     collapsing to 1-col a breakpoint early, ahead of WF's 3-col-until-767). */
  .home-journal { padding: 40px 20px 8px; }
  .home-journal-head { flex-direction: column; align-items: stretch; gap: 12px; margin-bottom: 20px; }
  .home-journal-grid { grid-template-columns: 1fr; gap: 16px; }
}

@media (max-width: 380px) {
  .mockup-bar { font-size: 10px; }
  /* iPhone SE / Galaxy A class. Logo + 40px icon + default CTA + hamburger
     doesn't fit horizontally; the CTA shrinks (font 14 to 12, padding
     11/18 to 11/10) so the icon can sit between logo and CTA without
     overlap. The icon `left:` calc recalibrates to the narrower CTA. */
  .nav-cta-mobile { padding: 11px 10px; font-size: 12px; }
  .nav-phone { left: calc(50% - 44.5px); }
}

/* Reduced motion — kill all entrance/transform animations */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  [data-reveal], [data-stagger-item] {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
  }
}
