/* Aurise Marketing — base styles */

:root {
  --color-primary: #532439;
  --color-secondary: #666403;

  --color-bg-1: #E0DF99;
  --color-bg-2: #F5DBDD;

  --color-accent-1: #A89DCA;
  --color-accent-2: #CC4C54;

  /* --color-accent is the "pop" color (hover states, CTAs, badges,
     eyebrow labels); --color-muted is the softer decorative/border tone.
     Kept as their own indirection layer (rather than using --color-accent-1/2
     directly at every call site) so which named color plays which role can
     be swapped in one place. */
  --color-accent: var(--color-accent-2);
  --color-muted: var(--color-accent-1);

  /* Default ("non-highlighted") text color, for copy sitting on the light
     surfaces (--color-surface, --color-bg-1/2, white cards) that make up
     almost every page. --color-text-on-dark is the one exception: the
     handful of elements (nav links, the hamburger icon, the hero title)
     that render directly on the dark navbar/footer/hero chrome
     (--color-secondary / --color-primary) with no background of their own,
     where --color-text would be unreadable against its own container. */
  --color-text: var(--color-secondary);
  --color-text-on-dark: var(--color-bg-2);

  --color-surface: color-mix(in srgb, var(--color-primary) 20%, #FBF7F1);

  --font-heading: 'Playfair Display', serif;
  --font-subheading: 'Cormorant Garamond', 'Playfair Display', serif;
  --font-body: 'DM Sans', sans-serif;
}

* {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
  font-family: var(--font-body);
  font-weight: 700;
  color: var(--color-text);
  background: var(--color-surface);
}

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

a {
  color: inherit;
}

.breadcrumb-link {
  color: var(--color-accent);
}

h1 {
  font-family: var(--font-heading);
  font-weight: 400;
  margin: 0 0 16px;
}

h2, h3 {
  font-family: var(--font-subheading);
  font-style: italic;
  font-weight: 500;
  margin: 0 0 16px;
}

/* Top decorative bar */

.topbar {
  height: 40px;
  background: var(--color-secondary);
}

/* Header / nav */

.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: var(--color-secondary);
  border-bottom: 1px solid color-mix(in srgb, var(--color-secondary) 40%, transparent);
  overflow: hidden;
}

.navbar {
  position: relative;
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px 40px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 32px;
}

.logo img {
  height: 44px;
  width: auto;
  border-radius: 6px;
}

.nav-links {
  list-style: none;
  display: flex;
  gap: 36px;
  margin: 0;
  padding: 0;
  flex: 1;
  justify-content: center;
}

.nav-links a {
  text-decoration: none;
  font-size: 15px;
  letter-spacing: 0.03em;
  color: var(--color-text-on-dark);
  padding-bottom: 6px;
  border-bottom: 2px solid transparent;
  transition: color 0.2s ease, border-color 0.2s ease;
}

.nav-links a:hover {
  color: var(--color-primary);
}

.nav-links li.active a {
  border-bottom-color: var(--color-primary);
  color: var(--color-primary);
}

.nav-links-cta {
  display: none;
}

/* Hamburger toggle (mobile only) */

.nav-toggle {
  display: none;
  width: 32px;
  height: 22px;
  padding: 0;
  border: none;
  background: none;
  cursor: pointer;
  flex-direction: column;
  justify-content: space-between;
}

.nav-toggle span {
  display: block;
  height: 2px;
  width: 100%;
  background: var(--color-text-on-dark);
  border-radius: 2px;
  transition: transform 0.25s ease, opacity 0.25s ease;
}

.nav-toggle.is-active span:nth-child(1) {
  transform: translateY(10px) rotate(45deg);
}

.nav-toggle.is-active span:nth-child(2) {
  opacity: 0;
}

.nav-toggle.is-active span:nth-child(3) {
  transform: translateY(-10px) rotate(-45deg);
}

.btn-book {
  background: var(--color-accent);
  color: var(--color-primary);
  text-decoration: none;
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 14px 30px;
  border-radius: 999px;
  white-space: nowrap;
  transition: background 0.2s ease, color 0.2s ease;
}

.btn-book:hover {
  background: var(--color-text);
  color: #fff;
}

/* Landing page hero (split: image left, copy right) */

.hero-split {
  position: relative;
  display: flex;
  align-items: center;
  min-height: 50vh;
  background: var(--color-primary);
  overflow: hidden;
}

/* Wavy divider at the bottom of the hero, so it hands off to the next
   section on a soft curved seam instead of a hard straight line — same
   wave signature as .card-body::before, stretched full-width and taller.

   This is a real inline <svg> in home.html (.hero-wave), NOT a CSS
   background-image/mask-image data-URI like the card version — but that
   swap alone did NOT fix the actual bug, despite being a reasonable first
   guess (data-URI SVGs get rasterized then stretched via background-size,
   which can cause resampling artifacts; real SVG elements render as
   vectors and don't). A ~2px seam showed up right at .hero-split's
   overflow:hidden clip edge with EVERY technique tried (mask-image,
   background-image, real SVG) — confirmed via pixel sampling and
   bisection (toggling this element off) that it's specifically the wave
   element's content meeting that exact clip line, not a technique-specific
   rendering bug.

   Fix: the path's fill (and the SVG's height) overshoot 3 viewBox units
   (6px) past the visible wave — viewBox is 23 tall not 20, the closing
   line is L100,23/L0,23 not L100,20/L0,20 — while .hero-wave's
   margin-top stays -40px (unchanged), so the shape's true bottom edge
   lands 6px BELOW .hero-split's clip line instead of exactly on it. The
   visible 40px band still sits entirely inside solid fill, clear of any
   edge, wherever the actual seam origin is.

   Fill uses fill="var(--color-surface)" directly on the <path> (inline
   SVGs in the document DOM can read CSS custom properties; data-URI ones
   can't), so unlike the card version this stays in sync automatically if
   the palette is retheme'd — no hardcoded hex to keep updated. Do NOT put
   a background-color on the .hero-wave div itself to try to reinforce
   this — that was tried too, and it defeats the SVG's transparency (the
   "trough" areas are meant to show .hero-split's purple through; a solid
   div background behind the SVG paints over that instead, flattening the
   whole wave into a solid rectangle). */

.hero-wave {
  position: relative;
  z-index: 1;
  margin-top: -40px;
  pointer-events: none;
}

.hero-wave svg {
  display: block;
  width: 100%;
  height: 46px;
}

/* Bottom wave for #intro — see the HTML comment above .intro-wave in
   home.html for how this mirrors .hero-wave.

   Unlike .hero-wave, there's no ancestor with overflow:hidden here to
   swallow the SVG's 6px overshoot (viewBox 23 tall vs. the 20-tall visible
   wave — see the .hero-wave comment above for why that overshoot exists).
   Without a clip, that overshoot is fully exposed, and the same class of
   sub-pixel mismatch between the wave's layout box and its rasterized
   content that .hero-wave's clip edge was hiding shows up here as a thin
   seam right after the wave. Fix: clip locally instead of relying on a
   parent — height:40px + overflow:hidden reproduces .hero-wave's exact
   working geometry (40px visible, 6px overshoot clipped away) on this
   element itself. */

.intro-wave {
  position: relative;
  z-index: 1;
  margin-top: -40px;
  height: 40px;
  overflow: hidden;
  pointer-events: none;
}

.intro-wave svg {
  display: block;
  width: 100%;
  height: 46px;
}

/* Image lives INSIDE the hero now — a smaller, inset, rounded panel on the
   left rather than a full-bleed edge-to-edge split — so the purple
   .hero-split background (and its k64 texture) shows around it and
   .hero-split-copy reads as the dominant surface.

   .hero-split-row constrains the media+copy pair to the same max-width +
   horizontal padding as .landing-section-inner (the card grid below the
   hero), so the image's left edge and the card's left edge line up
   instead of the hero running full-bleed while the content below it sits
   in a centered, inset column. */

.hero-split-row {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 1100px;
  margin: 0 auto;
  padding: 0 40px;
  display: flex;
  align-items: center;
  gap: 32px;
}

.hero-split-media {
  position: relative;
  flex: 0 1 680px;
  align-self: stretch;
  min-width: 0;
  margin: 32px 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.hero-split-media img,
.hero-split-media .img-placeholder {
  width: auto;
  height: 100%;
  aspect-ratio: 4 / 5;
  max-width: 100%;
  object-fit: cover;
  border-radius: 20px;
  overflow: hidden;
  box-shadow: 0 24px 48px rgba(0, 0, 0, 0.28);
}

.hero-split-copy {
  position: relative;
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  padding: 44px 0;
  overflow: hidden;
}

.hero-split-inner {
  position: relative;
  max-width: 300px;
}

.hero-eyebrow {
  text-transform: uppercase;
  letter-spacing: 0.16em;
  font-size: 13px;
  color: var(--color-muted);
  margin-bottom: 20px;
}

.hero-split-title {
  font-family: var(--font-heading);
  font-size: 44px;
  line-height: 1.3;
  color: var(--color-text-on-dark);
  margin: 0 0 24px;
}

/* Kinetic hero intro — "Amplify. Unite. Rise." revealed one word at a time */

.hero-kinetic-title {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.hero-kinetic-word {
  display: block;
  opacity: 0;
  transform: translateY(22px);
  letter-spacing: 0.06em;
  animation: hero-kinetic-in 0.9s cubic-bezier(0.22, 1, 0.36, 1) forwards;
}

.hero-kinetic-word:nth-child(1) {
  animation-delay: 0.3s;
}

.hero-kinetic-word:nth-child(2) {
  animation-delay: 0.75s;
}

.hero-kinetic-word:nth-child(3) {
  animation-delay: 1.2s;
}

/* "Rise." shine — a conic-gradient text fill that spins continuously and
   recenters on the cursor (--mx/--my, written by main.js on pointermove;
   the 50% fallback in var(--mx, 50%) keeps it centered before JS runs or
   on touch devices that never fire pointermove here). @property --angle is
   required, not decorative — without registering it as an <angle>, the
   browser can't interpolate --angle across the keyframe and the gradient
   would just snap instead of spinning.

   Colors are all derived from the site's five brand variables (see :root)
   rather than hardcoded hex, mixed with white for the bright highlight
   moments a "shine" effect needs — the raw brand palette is fairly dark
   and muted on its own and reads flat without them. Every color in the
   sequence corresponds to one of the five vars so the shine restyles
   itself automatically if the brand palette is ever swapped. First and
   last stops match (var(--color-muted) both times) so the loop has no
   seam at the 0deg/360deg wrap. */

@property --angle {
  syntax: '<angle>';
  inherits: false;
  initial-value: 0deg;
}

.hero-kinetic-word-accent {
  font-style: italic;
  font-size: 68px;
  background-image: conic-gradient(
    from var(--angle) at var(--mx, 50%) var(--my, 50%),
    var(--color-muted),
    color-mix(in srgb, var(--color-accent) 45%, white),
    color-mix(in srgb, var(--color-primary) 35%, white),
    var(--color-secondary),
    color-mix(in srgb, var(--color-text) 55%, white),
    var(--color-muted)
  );
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  animation:
    hero-kinetic-in 0.9s cubic-bezier(0.22, 1, 0.36, 1) 1.2s forwards,
    hero-word-shine 14s linear 1.2s infinite;
}

@keyframes hero-word-shine {
  to {
    --angle: 360deg;
  }
}

@media (prefers-reduced-motion: reduce) {
  .hero-kinetic-word-accent {
    animation: hero-kinetic-in 0.9s cubic-bezier(0.22, 1, 0.36, 1) 1.2s forwards;
  }
}

@keyframes hero-kinetic-in {
  from {
    opacity: 0;
    transform: translateY(22px);
    letter-spacing: 0.06em;
  }
  to {
    opacity: 1;
    transform: translateY(0);
    letter-spacing: normal;
  }
}

@media (prefers-reduced-motion: reduce) {
  .hero-kinetic-word {
    animation: none;
    opacity: 1;
    transform: none;
    letter-spacing: normal;
  }
}

/* Generic page sections */

main {
  min-height: 40vh;
}

.page-section {
  max-width: 1100px;
  margin: 0 auto;
  padding: 72px 40px;
}

/* Landing page bands (full-bleed background, centered inner content) */

.landing-section {
  padding: 88px 0;
}

/* Services page's first band, directly under the hero wave — the eyebrow
   that used to open it is gone, so the default 88px top padding now reads
   as a big gap before "What we do" / "Who is it for". Bottom padding is
   untouched. */
.landing-section--tight-top {
  padding-top: 40px;
}

.landing-section-inner {
  max-width: 1100px;
  margin: 0 auto;
  padding: 0 40px;
}

/* Background 1 / Background 2 modifiers for interior pages (About,
   Packages, Portfolio) that use a single .landing-section band below their
   hero, the same full-bleed-band-with-centered-inner-content shape the home
   page's own bands use — rather than the old .page-section, which was only
   ever an inset, centered column with no edge-to-edge background of its
   own. */

.landing-section.bg-1 {
  background: var(--color-bg-1);
}

.landing-section.bg-2 {
  background: var(--color-bg-2);
}

/* Test: k64 texture on the Basic package detail page's own section
   background — masked/multiplied Accent 2, scoped to this one
   .landing-section--k64 instance rather than every bg-2 section, so it
   doesn't leak onto About/Portfolio or the other package tiers.
   z-index:1 on .landing-section-inner lifts the actual page content above
   the texture layer. See .hero-wave below for how the wave itself carries
   this same texture, shaped to its own curve, so the two connect with no
   seam — this rule no longer needs to reach up into the wave's own -40px
   overlap band (an earlier attempt at that fought the wave's z-index and
   caused more problems than it solved; see git history if curious). */

.landing-section--k64 {
  position: relative;
}

.landing-section--k64::before {
  content: "";
  position: absolute;
  inset: 0;
  background-color: var(--color-accent-2);
  -webkit-mask: url("/static/images/k64.06a2bcce2fa3.svg") repeat;
  mask: url("/static/images/k64.06a2bcce2fa3.svg") repeat;
  -webkit-mask-size: 260px;
  mask-size: 260px;
  opacity: 0.4;
  mix-blend-mode: multiply;
  pointer-events: none;
}

/* Same texture, but shaped to .hero-wave's own curve instead of a plain
   rectangle: two mask layers (the k64 tile, and a copy of the wave's own
   path as a mask shape) combined with mask-composite:intersect, so only
   the pixels where BOTH are opaque show through — i.e. exactly the wave's
   visible pink fill, nothing spilling into the hero above it. This lives
   on .hero-wave itself (a ::after, since the wave's own content is a real
   <svg> child, not generated content) rather than as a separate overlay,
   so it inherits the wave's existing z-index:1 automatically instead of
   needing to fight it — no separate positioning/stacking hacks needed.
   :has(+ .landing-section--k64) scopes it to only the wave immediately
   before this test page's section, same reasoning as the plain-rectangle
   version above. */

.hero-wave:has(+ .landing-section--k64)::after {
  content: "";
  position: absolute;
  inset: 0;
  background-color: var(--color-accent-2);
  -webkit-mask-image: url("/static/images/k64.06a2bcce2fa3.svg"),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 23' preserveAspectRatio='none'%3E%3Cpath d='M0,11 C20,20 30,2 50,11 C70,20 80,2 100,11 L100,23 L0,23 Z' fill='white'/%3E%3C/svg%3E");
  mask-image: url("/static/images/k64.06a2bcce2fa3.svg"),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 23' preserveAspectRatio='none'%3E%3Cpath d='M0,11 C20,20 30,2 50,11 C70,20 80,2 100,11 L100,23 L0,23 Z' fill='white'/%3E%3C/svg%3E");
  -webkit-mask-repeat: repeat, no-repeat;
  mask-repeat: repeat, no-repeat;
  -webkit-mask-size: 260px, 100% 100%;
  mask-size: 260px, 100% 100%;
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
  opacity: 0.4;
  mix-blend-mode: multiply;
  pointer-events: none;
}

.landing-section--k64 > .landing-section-inner {
  position: relative;
  z-index: 1;
}

/* Home page band backgrounds — alternating Background 1 / Background 2 /
   Background 1 across #intro (Who We Are, no modifier class needed since
   it's the only .landing-section using the bare background), the Packages
   preview (.section-white) and the Portfolio preview (.section-tint). The
   class names predate this palette (section-white really was white, tint
   really was a primary tint) and are now just identifiers, not literal
   descriptions. */

#intro {
  background: var(--color-bg-1);
}

.landing-section.section-white {
  background: var(--color-bg-2);
}

.landing-section.section-tint {
  background: var(--color-bg-1);
}

.intro-copy {
  max-width: 680px;
  text-align: center;
  margin-left: auto;
  margin-right: auto;
}

.intro-copy p {
  line-height: 2.2;
}

.landing-cta {
  display: inline-block;
  margin-top: 40px;
  text-decoration: none;
}

.landing-section-inner.section-center {
  text-align: center;
}

.portfolio-grid .card img,
.portfolio-grid .card .img-placeholder {
  height: 240px;
  transition: transform 0.4s ease;
}

.portfolio-grid .card:hover img,
.portfolio-grid .card:hover .img-placeholder {
  transform: scale(1.06);
}

.page-section p,
.landing-section.bg-1 p,
.landing-section.bg-2 p {
  line-height: 1.7;
  font-size: 16px;
}

/* The small uppercase label above a section heading — used identically in
   both .landing-section (homepage bands) and .page-section (every other
   page), so it's one unscoped rule rather than two copies of the same
   declarations keyed off each ancestor. */

.eyebrow {
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-size: 13px;
  color: var(--color-accent);
  font-weight: 600;
}

/* Tagline sitting directly under a section's own h2 (e.g. "Three tiers, one
   goal..." under "Social Media Packages"). Keeps the h2's italic subheading
   face so the two read as one unit, a step down in size so it's clearly
   subordinate rather than a second heading — which is also why it's a <p>
   and not another <h2>.

   The selector names the band class as well as the section (same reason
   .landing-section.bg-1 .about-mantra below does) purely to out-specify
   `.landing-section.bg-1/.bg-2 p`'s font-size/line-height above, which a
   bare .section-subheading would silently lose to. */

.landing-section.bg-1 .section-subheading,
.landing-section.bg-2 .section-subheading {
  margin: 0;
  font-family: var(--font-subheading);
  font-style: italic;
  font-weight: 500;
  font-size: 20px;
  line-height: 1.5;
  color: var(--color-secondary);
}

/* The Services page opens its Packages band with a longer, larger version
   of that subheading — same italic face and colour, scaled up so it reads
   as the section's lead rather than a caption under the title. It replaced
   a separate .packages-lead paragraph that used to sit below the spec
   block; the copy moved up here, so the two are now one element.

   Band class in the selector for the usual reason on this page: the shared
   rule above is (0-3-0), so a bare .section-subheading--lead would lose to
   it and the font-size would never apply. The measure cap is what keeps
   ~100 characters at this size from running the full 1020px band width. */

.landing-section.bg-2 .section-subheading--lead {
  max-width: 50ch;
  margin: 0 auto;
  font-size: 26px;
  line-height: 1.45;
}

/* "About Aurise" intro band (About page, above the Founder split section)
   — narrows the section's default 1100px inner column to the same 680px
   reading measure as the home page's #intro copy, since paragraph text
   this long is uncomfortably wide at the full band size. Reuses
   .landing-section.bg-1's own p{line-height:1.7} rather than duplicating
   it here. */

.about-intro {
  max-width: 680px;
  margin-left: auto;
  margin-right: auto;
}

/* Extra .landing-section.bg-1 in the selector isn't just scoping — it's
   needed to out-specificity .landing-section.bg-1 p's own font-size/
   line-height (line ~630ish), which a bare .about-mantra would lose to. */
.landing-section.bg-1 .about-mantra {
  margin-top: 32px;
  font-size: 20px;
  line-height: 1.5;
  color: var(--color-accent-2);
}

/* Founder / split section (About page) */

.split-section {
  display: flex;
  gap: 56px;
  align-items: flex-start;
  flex-wrap: wrap;
}

.split-section img,
.split-section .img-placeholder {
  width: 320px;
  border-radius: 12px;
  flex-shrink: 0;
}

.split-section .img-placeholder {
  aspect-ratio: 4 / 5;
}

.split-section .split-copy {
  flex: 1;
  min-width: 280px;
}

.accent-2 {
  color: var(--color-accent-2);
}

.accent-circle {
  display: inline-block;
  position: relative;
  color: var(--color-accent);
}

.accent-circle::after {
  content: "";
  position: absolute;
  left: -10px;
  right: -10px;
  top: -8px;
  bottom: -6px;
  border: 2px solid var(--color-accent);
  border-radius: 50% 50% 48% 52% / 55% 45% 55% 45%;
  transform: rotate(-2deg);
  pointer-events: none;
}

/* Card grids (Packages / Examples) */

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 32px;
  margin-top: 40px;
}

.card {
  display: block;
  background: #fff;
  border: 1px solid color-mix(in srgb, var(--color-muted) 60%, transparent);
  border-radius: 12px;
  overflow: hidden;
}

/* .card is also used as an <a> (the portfolio listing links each card to
   its client's detail page) alongside its usual <div> use elsewhere - only
   the anchor needs its default link styling stripped. */

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

.card img,
.card .img-placeholder {
  width: 100%;
  height: 180px;
  object-fit: cover;
}

.card-body {
  position: relative;
  padding: 24px;
}

/* Wavy divider between a card's image and its body — echoes the site's
   hand-carved motif used elsewhere (the hero title's wavy underline, the
   k64.svg texture). A white wave overlaps the bottom of the image, so the
   body reads as "waving up" into it, rather than a hard horizontal seam.
   Only applies where .card-body actually follows .card img — the
   portfolio grid's image-only cards have no .card-body, so they're
   untouched automatically without needing an extra selector to exclude them. */

.card-body::before {
  content: "";
  position: absolute;
  top: -20px;
  left: 0;
  right: 0;
  height: 20px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 20' preserveAspectRatio='none'%3E%3Cpath d='M0,11 C20,20 30,2 50,11 C70,20 80,2 100,11 L100,20 L0,20 Z' fill='white'/%3E%3C/svg%3E");
  background-size: 100% 100%;
  background-repeat: no-repeat;
  pointer-events: none;
}

.card-body h3 {
  font-size: 22px;
  margin-bottom: 8px;
}

.card-body p {
  font-size: 15px;
  color: var(--color-text);
  opacity: 0.85;
}

/* "What We Offer" summary (home page) — four lines saying what the service
   actually is. Replaced an earlier preview of the three packages (cards
   with a name, tagline and video count); the tier-by-tier breakdown belongs
   on the Services page, so this band summarises the work instead of
   duplicating that list.

   Purely typographic, echoing the label-over-copy pairing the Services page
   uses for "What we do" / "Who is it for" (.detail-pair-bare): an uppercase
   letterspaced label in the primary colour, a short accent rule, then the
   line itself in the italic subheading face. No icons, no cards, no SVG —
   the accent rule is the only ornament. */

/* .section-subheading is scoped to .landing-section.bg-1/.bg-2 and this
   band is .section-white, so it can't be reused here — hence a local class
   with the same italic-subheading intent. */

/* Nothing else on the site colours an h2, so this band's heading inherits
   body's --color-text (olive) by default. Named for its section rather than
   added as a generic .heading-primary utility, since this is the only
   heading that wants the plum. */

.offer-heading {
  color: var(--color-primary);
}

.offer-lead {
  max-width: 52ch;
  margin: 0 auto;
  font-family: var(--font-subheading);
  font-style: italic;
  font-weight: 500;
  font-size: 20px;
  line-height: 1.6;
  color: var(--color-secondary);
}

/* auto-fit rather than an explicit 2-column track plus a breakpoint (the
   pattern used by .detail-pair-bare / .addons-grid / .packages-spec): the
   780px cap is what makes 300px columns resolve to two across on desktop,
   and the same rule folds them to one on a phone with no media query. */

.summary-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 44px 56px;
  max-width: 780px;
  margin: 56px auto 0;
  text-align: left;
}

/* Overrides the global h2,h3 italic-Cormorant rule — the label is the
   upright, letterspaced half of the pair, which is what sets it against the
   italic line beneath it. Sized like .detail-pair-bare__header, the same
   role on the Services page. */

.summary-item__label {
  margin: 0;
  font-family: var(--font-body);
  font-style: normal;
  font-weight: 600;
  font-size: 16px;
  line-height: 1.5;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--color-primary);
}

.summary-item__label::after {
  content: "";
  display: block;
  width: 34px;
  height: 2px;
  margin-top: 14px;
  border-radius: 2px;
  background: var(--color-accent);
}

.summary-item__text {
  margin: 14px 0 0;
  font-family: var(--font-subheading);
  font-style: italic;
  font-weight: 500;
  font-size: 19px;
  line-height: 1.6;
  color: var(--color-secondary);
}

/* Same stroked wave that divides one tier from the next, reused twice here
   to bracket the two spec lines — one above, one below. Narrower than a full
   .tier-rule (which spans the whole 1100px band) so the pair reads as small
   punctuation marks around the specs rather than full-width dividers.

   Only max-width/margin are set — height stays .tier-rule's own 24px, which
   at 220px wide happens to be almost exactly the 100x12 viewBox's natural
   ratio, so unlike the full-width rules this one isn't flattened by
   preserveAspectRatio="none" and draws as a proper little squiggle.
   (Overriding height here wouldn't take anyway: .tier-rule is the same
   specificity and comes later in the file.) */

.packages-spec-rule {
  max-width: 220px;
  margin: 28px auto 0;
}

/* Three parallel spec lines (video length/quality, platform formats,
   voiceover/subtitles), side by side on the same auto-fit grid the "What we
   do" / "Who is it for" pair uses above — one item per concern instead of
   stacking the platform logos and the voiceover line into the same column,
   which read as one lopsided, uneven-height column next to a short one.
   Narrower min/wider max than that pair's grid so three columns actually
   fit side by side at typical widths instead of wrapping to 2-then-1.
   Centred to match the rest of the block; the .tier-list below resets to
   text-align:left on its own. */

.packages-spec {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 32px 48px;
  max-width: 900px;
  margin: 36px auto 0;
  padding: 0;
  list-style: none;
  text-align: left;
}

/* The three items are .summary-item__label / __text (see "What We Offer" on
   the home page), and that pairing only reads as one component when the
   label, its rule and the line beneath all start from the same left edge —
   so this grid opts out of the .section-center inherited from the band.

   __text needs re-stating here because of the specificity trap this file
   keeps running into: `.landing-section.bg-2 p` (0-2-1) sets 16px/1.7 and
   beats a bare .summary-item__text (0-1-0). The home page's copy of this
   component sits in .section-white, which has no such p rule, so it works
   there unscoped and would silently shrink here without this. */

.landing-section.bg-2 .packages-spec .summary-item__text {
  font-size: 19px;
  line-height: 1.6;
}

/* Platform logos under "Edited for" — full color (not currentColor), so
   they read as brand marks rather than themed icons. Left-aligned and
   given .summary-item__text's own 14px top margin, so the logos sit where
   the italic line sits in the other two items. */

.packages-spec-logos {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 14px;
  margin-top: 14px;
}

.packages-spec-logo {
  height: 52px;
  width: auto;
}

/* Tier list (Services page) — Basic / Plus / Pro sharing one unbroken
   Background 2 surface, separated only by .tier-rule. Deliberately has no
   card, border, or per-tier background: the wavy rule is the ONLY divider,
   so anything that boxes a .tier would fight it.

   .tier-rule is the site's wave path stroked rather than filled. It's
   inline SVG (not a data-URI background) for two reasons: stroke can then
   read var(--color-accent-2) so it tracks the palette, and
   vector-effect:non-scaling-stroke keeps the line an even 2px — without it
   preserveAspectRatio="none" stretches the viewBox ~10x horizontally and
   drags the stroke width along with it, so the wave's steep sections
   render visibly fatter than its flat ones. */

.tier-list {
  display: flex;
  flex-direction: column;
  margin-top: 48px;
  text-align: left;
}

.tier {
  padding: 40px 0;
}

.tier__name {
  font-size: 30px;
  margin-bottom: 12px;
  color: var(--color-primary);
}

/* The tier name is the link to its detail page. Styled to keep reading as a
   heading (inherits size/family/color, no default underline) with the
   underline only appearing on hover/focus, so the list doesn't turn into a
   row of obviously-clickable blue text. */

.tier__link {
  color: inherit;
  text-decoration: none;
}

.tier__link:hover,
.tier__link:focus-visible {
  color: var(--color-accent);
  text-decoration: underline;
  text-underline-offset: 4px;
  text-decoration-thickness: 2px;
}

.tier__text {
  font-size: 16px;
  color: var(--color-text);
  opacity: 0.85;
  max-width: 62ch;
}

/* The "🎞️ N Videos" line inside .tier__text. The <br> above it only breaks
   the line, with no space at all, so the margin here is what stops the count
   from crowding the pitch above it — inline-block purely so that margin
   applies (margin-top is ignored on a plain inline box).

   Differentiated from the pitch by colour alone. NOT by opacity: .tier__text
   sets opacity:0.85, which composites the whole subtree as one group, so an
   opacity:1 here would do exactly nothing. */

.tier__count {
  display: inline-block;
  margin-top: 10px;
  color: var(--color-primary);
}

.tier-rule {
  display: block;
  width: 100%;
  height: 24px;
  overflow: visible;
}

/* Scroll snap for the tier lists (Services page) — the page settles on a
   whole package as you scroll past Basic / Plus / Pro rather than stopping
   mid-tier.

   The snap container is the ROOT scroller, not .tier-list: the tiers scroll
   with the page, and making .tier-list its own overflow:auto scroller to
   host the snapping would trap a nested scrollbar inside the section. That
   also means this declaration is live on every page, which is harmless —
   .tier only exists on the Services page, so nowhere else has snap points
   for it to act on.

   PROXIMITY, not mandatory. A .tier is taller than the viewport (Pro's
   contents alone run past a screen, and the expandable reel items grow
   taller still when opened), and mandatory snapping on an over-tall block
   forces the scroller back to a snap point the moment the user lets go —
   so the middle of a tier becomes unreachable. Proximity only pulls when
   the scroll ends near a snap point, so long tiers still scroll freely.
   Switch to mandatory only if the tiers ever get shorter than a viewport.

   --tier-snap-offset clears the sticky .site-header (44px logo + 2x20px
   .navbar padding + border ~= 85px), which scroll-snap-align knows nothing
   about; without it the tier heading lands underneath the header. .tier's
   own 40px top padding sits below that offset and supplies the air between
   the header and the heading. */

:root {
  --tier-snap-offset: 88px;
}

@media (prefers-reduced-motion: no-preference) {
  html {
    scroll-snap-type: y proximity;
  }

  .tier {
    scroll-snap-align: start;
    scroll-margin-top: var(--tier-snap-offset);
  }
}

/* Add-ons block (Services page) — the four items that used to be repeated
   inside all three package promos, now one block below Pro, still inside
   the Social Media Packages band.

   .tier-list sets text-align:left for the tiers; this sits after it, back
   under .section-center, so it recentres on its own.

   The font-size is the one real knob here. .pkg-promo-feature-icon/-text
   are sized in em (1.4em / 0.85em) because inside a package promo they want
   to be dense; standing alone as a section they read as fine print at the
   inherited 16px. Scaling the container scales the whole component in
   proportion instead of overriding each part. The two headings above are in
   px, so they don't move. */

.addons {
  margin-top: 40px;
  font-size: 19px;
}

/* Same auto-fit pair-grid the rest of this page uses (.detail-pair-bare,
   .packages-spec) so the four items land 2x2 and fold to one column at the
   same sort of width. Centred as a block, but the items themselves stay
   left-aligned inside it — .pkg-promo-feature-item is a flex row with the
   [Extra] box first, and centring those would leave the boxes on a ragged
   edge instead of the straight line that makes it read as a checklist. */

.addons-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 20px 40px;
  max-width: 760px;
  margin: 32px auto 0;
  text-align: left;
}

/* Phone-mockup package cards (Packages page) — each package's name and
   tagline sit on a lock-screen-style display inset inside a white bezel,
   rather than printed flat on the same white surface as the frame (the
   original version had no visual separation between "bezel" and "screen").
   Recolored from the flat black/white reference to the brand palette
   (--color-primary for the frame/hardware) so it reads as an Aurise card
   rather than a generic device mockup. Laid out with flex + wrap instead
   of reusing .card-grid's auto-fit grid, since a phone's tall, narrow
   aspect ratio works better centered in a wrapping row than stretched
   into grid columns. */

.phone-card-grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 48px;
  margin-top: 40px;
}

.phone-card {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 160px;
  aspect-ratio: 8 / 15;
  padding: 34px 10px 10px;
  border: 4px solid var(--color-primary);
  border-radius: 24px;
  background: #fff;
  box-shadow: 5px 5px 2.5px 6px color-mix(in srgb, var(--color-muted) 45%, transparent);
  text-decoration: none;
  color: inherit;
  transform-origin: bottom center;
  transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1), box-shadow 0.4s ease;
}

/* Hover tilts the card like it's been picked up off a table, alternating
   lean direction card-to-card (odd cards lean left, even lean right) so a
   row of them doesn't all rock the same way — plus the screen "wakes up"
   below (see .phone-card__screen::after). */

.phone-card:hover,
.phone-card:focus-visible {
  transform: translateY(-10px) rotate(-3deg) scale(1.03);
  box-shadow: 8px 18px 4px 6px color-mix(in srgb, var(--color-muted) 45%, transparent);
}

.phone-card:nth-child(even):hover,
.phone-card:nth-child(even):focus-visible {
  transform: translateY(-10px) rotate(3deg) scale(1.03);
}

/* Plus package (test): a different phone model (found on Uiverse), shape
   only — the original had a time/date readout, a fingerprint icon and
   camera/phone icons baked in; none of that is used here, just its frame
   geometry (tighter 16px corners, and a notch that sits flush against the
   top edge as an in-flow bar instead of floating below it — see
   .phone-card__notch--flush). Same 160x300 footprint as the other two
   cards, so it drops into the same grid without a size mismatch. */

.phone-card--alt {
  padding: 0 10px 10px;
  border-radius: 16px;
}

/* Speaker notch, in the bezel above the screen. */

.phone-card__notch {
  position: absolute;
  top: 16px;
  left: 50%;
  transform: translateX(-50%);
  width: 56px;
  height: 6px;
  border-radius: 0 0 8px 8px;
  background: var(--color-primary);
}

/* Flush variant (Plus card) — a real flex item instead of an absolutely
   positioned pill, so with .phone-card--alt's padding-top:0 it sits
   directly against the frame's inner top edge with no gap, matching the
   reference model's .top-border. .phone-card__screen (flex:1, the next
   sibling) fills whatever vertical space is left below it. */

.phone-card__notch--flush {
  position: static;
  align-self: center;
  transform: none;
  width: 80px;
  height: 8px;
  border-radius: 0 0 16px 16px;
}

/* Volume/power buttons on the right edge — outlined, not filled, to match
   the reference's plain border-only side buttons. */

.phone-card__button {
  position: absolute;
  right: -6px;
  width: 4px;
  border: 4px solid var(--color-primary);
  border-radius: 6px;
}

.phone-card__button--top {
  top: 64px;
  height: 24px;
}

.phone-card__button--bottom {
  bottom: 96px;
  height: 34px;
}

/* The "screen" — filled with --color-surface (the page's own background
   color) and inset from the white bezel, so it reads as its own surface
   rather than blending into the frame around it. */

.phone-card__screen {
  position: relative;
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  padding: 20px 14px;
  border-radius: 16px;
  background: var(--color-surface);
  text-align: center;
  overflow: hidden;
}

/* Plus package (test): the whole screen is the artwork (insta.svg, a full
   app-screen mockup) instead of badge + tagline, with pro-paint.svg
   layered on top.

   .phone-card__insta-stack now spans the full screen box edge-to-edge
   (no aspect-ratio match to insta.svg's own viewBox, unlike the previous
   version) — insta.svg is fine to stretch off-ratio since it's flat SVG
   linework, so filling height as well as width (instead of leaving a
   letterboxed gap top/bottom) reads fine and gets the artwork to the
   screen's edges. Because the stack IS the screen's full box now, sizing
   pro-paint.svg in percentages of the stack still guarantees it stays
   inside insta.svg's boundaries — the two boundaries are now the same
   box, there's no separate "true image box" to fall outside of. */

.phone-card__insta-stack {
  position: absolute;
  inset: 0;
}

.phone-card__insta-image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* pro-paint.svg, over the Instagram mockup, pushed up toward the top of
   the screen rather than dead-centered (top: 30% instead of 50%).
   max-width/max-height (not width/height) keep it within 60% of the stack
   in both dimensions while width:auto/height:auto let the browser
   preserve pro-paint.svg's own aspect ratio — it can only shrink to fit,
   never crop or stretch, so it can't spill past the screen's edges.
   filter:drop-shadow (not box-shadow) follows the artwork's own alpha
   silhouette rather than casting a rectangular shadow behind it. */

.phone-card__insta-overlay {
  position: absolute;
  top: 30%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: auto;
  height: auto;
  max-width: 60%;
  max-height: 60%;
  filter: drop-shadow(0 6px 10px color-mix(in srgb, var(--color-primary) 55%, transparent));
}

/* The rounded screen corners were clipping into insta.svg's own artwork
   at the edges — square them off for this screen so the full image shows
   uncropped. */

.phone-card__screen--flush {
  border-radius: 0;
}

/* Screen "wake" glow — a soft highlight over the badge that's invisible at
   rest and fades in on hover, like the display lighting up when picked
   up. Painted last (a ::after, so it stacks above the name/tagline text)
   but capped at 0.5 opacity and pointer-events:none so it reads as a
   glare rather than obscuring the content or blocking the click. Tinted
   with --color-accent rather than white — on the light --color-surface
   screen a white glow would barely register. */

.phone-card__screen::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at 50% 28%, color-mix(in srgb, var(--color-accent) 45%, transparent), transparent 65%);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.4s ease;
}

.phone-card:hover .phone-card__screen::after,
.phone-card:focus-visible .phone-card__screen::after {
  opacity: 0.5;
}

/* Package name as a squircle badge (rounded-square, iOS app-icon style)
   over the screen, rather than a pill or plain text — gives Basic/Plus/Pro
   a distinct focal point the way an app icon would on a real lock screen. */

.phone-card__name {
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  width: 74px;
  height: 74px;
  border-radius: 20px;
  background: color-mix(in srgb, var(--color-primary) 14%, white);
  border: 1px solid color-mix(in srgb, var(--color-primary) 30%, transparent);
  font-family: var(--font-subheading);
  font-style: italic;
  font-size: 18px;
  color: var(--color-primary);
}

/* Basic package swaps the plain text badge for its own app-icon artwork
   (basic.png) — fills the squircle edge-to-edge and carries its own
   border/shadow so it reads as a real iOS-style app icon tile rather than
   an image floating inside the badge chip. Radius matches .phone-card__name
   exactly (20px) so the image's clipped corners line up with the badge's
   own border underneath, with no mismatched double-edge at the corners. */

.phone-card__name-icon {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 20px;
  border: 2px solid color-mix(in srgb, white 70%, transparent);
  box-shadow: 0 3px 6px color-mix(in srgb, var(--color-primary) 35%, transparent);
}

.phone-card__tagline {
  margin: 0;
  font-size: 13px;
  line-height: 1.5;
  color: var(--color-text);
}

/* Package detail page — each section of package data (goal, deliverables,
   shooting time, outcome) gets its own card instead of running together
   as plain page-section paragraphs, so the pricing/scope info reads as
   distinct, scannable chunks. */

.detail-cards {
  display: flex;
  flex-direction: column;
  gap: 96px;
  margin-top: 40px;
}

.detail-card {
  background: #fff;
  border: 1px solid color-mix(in srgb, var(--color-muted) 60%, transparent);
  border-radius: 16px;
  padding: 32px;
}

.detail-card h2,
.detail-card h3 {
  margin-top: 0;
}

/* The goal/ideal-for pair sits side by side as two fully separated cards
   rather than stacked in one — auto-fit collapses gracefully to a single
   full-width card on packages like Pro that have no ideal_for text. */

/* margin-top clears the folder-tab header floating above each card
   (position:absolute; bottom:100% — see .detail-card-pair .detail-card-header
   below) - the tab lives outside the card's own box, so .detail-cards' gap
   above this element is measured to the CARD's top edge, not the tab's.
   Without this, a wide enough gap up top made the tab clear whatever came
   before it by luck; a card directly above (as when the Basic package's
   promo card sits right above this pair) had its bottom edge crowded by
   the tab regardless of the gap value. */

.detail-card-pair {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 28px;
  margin-top: 56px;
}

/* Header and body each get their own texture layer rather than one shared
   whole-card layer, so opacity/asset/etc. can be tuned per region without
   affecting the other. The header's ::before is inset:0 on the header
   itself, so it's automatically exactly the header's box. The body texture
   needs its own wrapper (.detail-card-body, added in the template around
   the <p>) rather than living on the <p> directly - the <p> only sizes to
   its own text, but flex-direction:column + flex:1 on this wrapper makes it
   stretch to fill all the remaining card height (including the dead space
   below shorter paragraphs, once grid stretch equalizes the two cards'
   heights), so the texture actually covers "the rest of the card" instead
   of just hugging the text. */

/* padding:0 here (overriding .detail-card's own 32px) is the actual fix for
   the white gap around the header/body textures: previously the CARD had
   the padding, so the header/body boxes only ever spanned the card's inner
   content area - inset:0 on their own ::before could never reach past that
   padding to the card's real edge. Padding is moved onto the header/body
   elements themselves below, so the text sits in the same visual place but
   each element's box (and therefore its ::before) now runs edge-to-edge. */

.detail-card-pair .detail-card,
.detail-card--deliverables {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 0;
}

/* Folder-tab header: on the pair cards only, the header detaches from the
   card's own top edge into a small tab floating above it (bottom:100%)
   instead of a full-width band. The top-left corner squares off (0) to
   read as "the tab is attached here" while the other three corners stay
   rounded; overflow stays visible (the default - nothing here sets hidden)
   since the tab now lives outside the card's own box. */

.detail-card-pair .detail-card {
  border-radius: 0 16px 16px 16px;
  overflow: visible;
}

.detail-card-pair .detail-card,
.detail-card--deliverables {
  transition: transform 0.35s ease, box-shadow 0.35s ease, border-color 0.35s ease;
}

/* Resting drop-shadow, same color-mix(--color-primary, transparent) family
   as the shared :hover rule below, just lighter — present on all three of
   these cards now (not hover-only), so hovering reads as an accentuation
   of an already-present shadow rather than one appearing from nothing. */

.detail-card-pair .detail-card,
.detail-card--deliverables {
  box-shadow: 0 10px 24px color-mix(in srgb, var(--color-primary) 12%, transparent);
}

.detail-card-pair .detail-card:hover,
.detail-card--deliverables:hover {
  transform: translateY(-8px);
  border-color: color-mix(in srgb, var(--color-accent) 45%, transparent);
  box-shadow: 0 22px 40px color-mix(in srgb, var(--color-primary) 20%, transparent);
}

/* The corner leaf/fruit "come alive" on hover too, rotating and growing
   slightly (transition lives on .detail-card-leaf/.detail-card-fruit
   themselves, further down) - pointer-events:none on the images just means
   the hover has to be detected on the card, which is fine since that's
   already the whole hover target. */

.detail-card--leaf:hover .detail-card-leaf {
  transform: translateY(-50%) rotate(-6deg) scale(1.06);
}

.detail-card--fruit:hover .detail-card-fruit {
  transform: rotate(8deg) scale(1.1);
}

/* Flat color-muted fill + a small inline SVG noise filter for grain, instead
   of an image asset - a plain background (not a ::before) is enough here
   since a background-image layer doesn't fade the header text the way
   element opacity would, so there's no need for the pseudo-element/z-index
   trick the other textured layers use. */

.detail-card-header {
  font-family: var(--font-heading);
  font-style: normal;
  font-weight: 600;
  font-size: 24px;
  color: var(--color-accent);
  margin: 0;
  padding: 32px 32px 14px;
  text-align: center;
  border-bottom: 2px solid color-mix(in srgb, var(--color-accent) 30%, transparent);
  border-radius: 16px 16px 0 0;
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.25'/%3E%3C/svg%3E")
      repeat,
    var(--color-muted);
}

/* Detaches the header from the card's flow into the tab: width shrinks to
   fit the label instead of spanning edge-to-edge, and the border-bottom
   (meant to divide a full band from the body below) is dropped since the
   tab now sits flush against the card's square corner instead of over it. */

.detail-card-pair .detail-card-header {
  position: absolute;
  z-index: 3;
  bottom: 100%;
  left: 0;
  display: inline-block;
  width: auto;
  padding: 0.6rem 2rem;
  border-bottom: none;
  border-radius: 12px 12px 0 0;
}

.detail-card-pair p {
  color: var(--color-secondary);
  text-align: center;
  line-height: 1.9;
}

/* Chrome-less rendering of the .detail-card-pair content (Services page,
   "Ways to work together"). Same 1x1 auto-fit grid so it still collapses to
   a single column when narrow, and the same typography — but none of the
   card material: no background, border, radius, resting/hover shadow, hover
   lift, folder-tab header (the muted fill + noise texture), paper-bg body
   texture, or leaf/fruit corner art.

   Note this is NOT .detail-card-pair with overrides. Unstyling that class
   would mean cancelling a dozen properties spread across six rules (several
   of them shared with .detail-card--deliverables, so overriding in place
   risks reaching the deliverables card too). A separate class that simply
   never opts into the chrome is both shorter and safer. The two highlight
   treatments ARE reused as-is — .detail-card-emphasis--glow/--double below
   are defined unscoped precisely so they work outside a card. */

.detail-pair-bare {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 28px;
  margin-top: 40px;
}

/* Shared label treatment for .label-heading ("Social Media Packages",
   "Web Services" h2s) and .detail-pair-bare__header ("What we do"/"Who is
   it for" h3s, matching the old "Ways to work together" .eyebrow they used
   to sit under): same face, weight, line-height, uppercase and tracking.
   The tracking + uppercase are what were missing before — without them the
   text read as a plain heading rather than a label.

   font-family/font-style must be restated regardless, to beat the global
   `h2, h3` rule's italic subheading face.

   text-align stays centred (not the eyebrow's left) to keep each header
   over its own centred column.

   font-size is set per-class below, not here: .label-heading's h2s are a
   section's own title and read larger, while .detail-pair-bare__header's
   h3s stay at the original 16px match to the old eyebrow so they don't
   overpower the "What we do"/"Who is it for" copy under them. */

.label-heading,
.detail-pair-bare__header {
  font-family: var(--font-body);
  font-style: normal;
  font-weight: 600;
  line-height: 1.7;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--color-primary);
  margin: 0 0 12px;
  text-align: center;
}

.label-heading {
  font-size: 26px;
}

.detail-pair-bare__header {
  font-size: 16px;
}

/* Italic subheading face, matching the section's own h2 ("Three tiers, one
   goal...") — same font-family/style/weight the global h2,h3 rule sets. */

.detail-pair-bare p {
  margin: 0;
  font-family: var(--font-subheading);
  font-style: italic;
  font-weight: 500;
  color: var(--color-secondary);
  text-align: center;
  line-height: 1.9;
}

/* ...but NOT the highlighted spans inside it, which stay on the body face
   they already had. Without this they'd inherit the italic serif from the
   <p> above and the glow/double-underline treatments would lose the bold
   sans-serif contrast that makes them read as highlights in the first
   place. Scoped to .detail-pair-bare so the detail page's own cards, whose
   paragraphs aren't italic to begin with, are untouched. */

.detail-pair-bare .detail-card-emphasis {
  font-family: var(--font-body);
  font-style: normal;
}

/* The plain sentences that top and tail a highlighted list — "Create the
   essential content set that explains" above one, "seeking a polished,
   trustworthy presence for new clients" below another. Named for that
   framing role rather than the position, since it's used at both ends.

   em, not px, so it scales with whatever context it lands in — the bare
   pair on the Services page and the detail page's card set different base
   sizes. Unscoped on purpose: the copy is a shared partial, so both
   renderings should size it the same way. */

.detail-card-framing {
  font-size: 1.25em;
}

.detail-card-emphasis--glow {
  color: var(--color-accent);
  text-shadow: 0 0 10px color-mix(in srgb, var(--color-accent) 55%, transparent);
}

.detail-card-emphasis--double {
  color: var(--color-accent);
  text-decoration: underline double;
  text-decoration-color: var(--color-accent);
  text-decoration-thickness: 1.5px;
  text-underline-offset: 5px;
}

.detail-card-body {
  position: relative;
  z-index: 0;
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 8px 32px 32px;
}

.detail-card-body::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: 0 0 16px 16px;
  background: url("/static/images/paper-bg.92f533c32012.svg") top left / 480px auto repeat;
  opacity: 0.3;
  pointer-events: none;
}

/* The pair cards' body is now the visible top of the card (the header lives
   above it as a detached tab, not a band over it), so its texture needs the
   same top-right rounding as the card itself - top-left stays square where
   the tab attaches, matching .detail-card-pair .detail-card's radius. */

.detail-card-pair .detail-card-body::before {
  border-radius: 0 16px 16px 16px;
}

/* The matcha cup overflows the deliverables card's top-left corner rather
   than sitting inside it, so that header needs extra top clearance (on top
   of its own base 32px) so the heading clears it instead of sitting
   underneath. The pair cards' leaf/fruit don't need this - their header is
   a detached tab above the card, not a band over it. */

.detail-card--deliverables .detail-card-header {
  padding-top: 40px;
}

/* The leaf overflows the card's left edge, vertically centered, rather
   than either left corner - the top-left is where the folder-tab header
   attaches (see .detail-card-pair .detail-card-header above), and the
   bottom-left collided with the matcha cup overflowing the top of the
   deliverables card directly below (the two cards' overflow zones met in
   .detail-cards' 28px gap). Middle-left overflows the same amount without
   competing with either neighbor. */

.detail-card-leaf {
  position: absolute;
  z-index: 2;
  top: 50%;
  left: -32px;
  width: 154px;
  height: auto;
  transform: translateY(-50%);
  pointer-events: none;
  transition: transform 0.45s ease;
}

/* col-matcha.svg is a circular glass filling most of its square canvas,
   unlike col-leaf-1's irregular diagonal silhouette - a circle's own mass
   is furthest from its bounding box's corners, so reusing col-leaf-1's
   offsets left it floating above the card instead of covering the corner.
   Centering it roughly ON the corner point instead (half in, half out)
   is what actually hides the corner. This top/left pair is the cup's true
   "home" (the corner) - at rest it's visually displaced over near the
   stain mark instead via `transform` below, so hovering can animate it
   sliding back home with a single transition rather than juggling two
   different top/left states. */

.detail-card--deliverables .detail-card-leaf {
  top: -80px;
  bottom: auto;
  left: -80px;
  width: 160px;
  transform: translate(208px, 78px) scale(0.72) rotate(-9deg);
  transition: transform 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}

.detail-card--deliverables:hover .detail-card-leaf {
  transform: translate(0, 0) scale(1) rotate(0deg);
}

/* A smaller coffee-ring stain mark next to the matcha glass, tinted with
   the accent color via mask rather than kept as an <img> - col-stain.svg's
   own fill is a hardcoded maroon that wouldn't match the palette.

   Story: at rest, the cup sits over near this spot (see the transform
   above), so the ring stays hidden - it's what the cup was resting on. On
   hover the cup starts sliding away to the corner and the ring fades in
   right alongside it (no delay), like it was uncovered the moment the cup
   moved. Reverses instantly on mouse-out too. */

.detail-card-stain {
  position: absolute;
  z-index: 2;
  top: 2px;
  left: 126px;
  width: 92px;
  height: 92px;
  pointer-events: none;
  background-color: var(--color-accent);
  -webkit-mask: url("/static/images/col-stain.4f9e43b3fb95.svg") no-repeat center / contain;
  mask: url("/static/images/col-stain.4f9e43b3fb95.svg") no-repeat center / contain;
  opacity: 0;
  transition: opacity 0.3s ease;
}

.detail-card--deliverables:hover .detail-card-stain {
  opacity: 1;
  transition: opacity 0.4s ease;
}

.detail-card-fruit {
  position: absolute;
  z-index: 2;
  bottom: -20px;
  right: -16px;
  width: 75px;
  height: auto;
  pointer-events: none;
  transition: transform 0.45s ease;
}

/* Deliverable tile card - https://uiverse.io/akshat-patel28, media area
   swapped for the real .video-placeholder (no separate "image container"
   wrapper needed, it already carries its own aspect-ratio/radius/overflow),
   description dropped entirely per request
   (title only). Kept literal off the reference (white card, black-ish
   shadow, radius, padding) since that's the shape/material actually being
   asked for; title color/font swapped to the site's own ink/subheading
   font since the reference's arbitrary teal and "Lucida Sans" aren't
   brand-load-bearing the way e.g. the like-button's Instagram red is. */

.deliverable-card {
  display: flex;
  flex-direction: column;
  background: #fff;
  border-radius: 10px;
  padding: 10px;
  box-sizing: border-box;
  box-shadow: 0 10px 12px rgba(0, 0, 0, 0.08), -4px -4px 12px rgba(0, 0, 0, 0.08);
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.deliverable-card:hover {
  transform: translateY(-10px);
  box-shadow: 0 20px 20px rgba(0, 0, 0, 0.1), -4px -4px 12px rgba(0, 0, 0, 0.08);
}

.deliverable-card-title {
  margin: 10px 0 0;
  text-align: center;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 18px;
  color: var(--color-accent);
}

.detail-card ul {
  margin: 16px 0 0;
  padding-left: 20px;
}

.detail-card li {
  margin-bottom: 8px;
  line-height: 1.6;
}

.detail-card p:last-child {
  margin-bottom: 0;
}

/* The Deliverables card is the "big card with smaller cards inside" —
   one video slot per deliverable, each in its own tile within the outer
   .detail-card. */

.deliverable-grid {
  width: 100%;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 28px;
  margin-top: 24px;
}

.deliverable-card-frame {
  position: relative;
}

.deliverable-bonus {
  display: inline-block;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-accent);
  background: color-mix(in srgb, var(--color-accent) 15%, white);
  padding: 4px 10px;
  border-radius: 999px;
  margin-bottom: 10px;
}

/* "Content Package" promo card — Uiverse.io (seoulchik) template, heavily
   customized for the Basic package: copy/CTA rewritten, icon glyphs
   stripped down to plain squares, and the price + dashed "cut line" +
   scissors icon removed. Classes are prefixed pkg-promo- (not the
   original card/card-body/etc names) because .card and .card-body are
   already used site-wide for the Packages/Examples grid and portfolio
   links - reusing those names here would collide with them.

   Every color on the card resolves through
   the --color-* variables from :root, via this local --primary/--secondary/
   etc indirection layer. Editing the site's palette in :root re-themes
   this card automatically - nothing here should ever be a literal hex/rgb
   value for a brand color (shadow/overlay rgba() tints for generic
   depth/shine are fine, those aren't brand colors). --secondary-hover
   is derived with color-mix rather than pointed at --color-text, since
   --color-text isn't guaranteed to contrast with --bg/--text the way a
   darkened --color-accent reliably does. */

.pkg-promo-standalone {
  display: flex;
  justify-content: center;
}

/* The colour indirection layer lives on its own so BOTH wrappers of
   _basic_package_contents.html can supply it: the full card below, and
   .pkg-promo-bare (the Services page's chrome-less rendering of the same
   partial). Without this split, dropping .pkg-promo-card would leave every
   inner box — tick squares, shooting-time badge, outcome card — with
   unresolved var()s and no fill at all. */

.pkg-promo-card,
.pkg-promo-bare {
  --primary: var(--color-primary);
  --secondary: var(--color-accent);
  --secondary-hover: color-mix(in srgb, var(--color-accent) 75%, black);
  --muted: var(--color-muted);
  --text: var(--color-secondary);
  --bg: var(--color-bg-1);
  font-family: var(--font-body);
}

/* Contents-only rendering of the promo partial (Services page tiers) —
   vars above, nothing else: no background, border, radius, shadow, hover
   transform, pattern grid, title bar or corner leaf. */

.pkg-promo-bare {
  margin-top: 28px;
}

/* --bg isn't "the card's colour", it's "the surface this component sits
   on": it's the knocked-out text colour on the red shooting-time/outcome
   badges (color: var(--bg)). Keying it off the section's own background
   band means a .pkg-promo-bare picks up the correct one automatically
   wherever it's dropped — Social Media Packages on Background 2, Web
   Services on Background 1 — instead of needing a modifier class per
   section, and a badge can't end up printing stray yellow text on pink.
   .pkg-promo-card is deliberately not matched: it paints its own surface,
   so it keeps the --bg from the shared block above. */

.bg-1 .pkg-promo-bare {
  --bg: var(--color-bg-1);
}

.bg-2 .pkg-promo-bare {
  --bg: var(--color-bg-2);
}

.pkg-promo-card {
  position: relative;
  width: 100%;
  box-sizing: border-box;
  background: var(--bg);
  border: 1px solid var(--text);
  border-radius: 0.6em;
  /* Same drop-shadow family as .detail-card-pair .detail-card/
     .detail-card--deliverables (color-mix(--color-primary, transparent)),
     just present at rest here instead of hover-only — lighter blur/spread/
     opacity at rest, accentuated on :hover below. */
  box-shadow: 0 10px 24px color-mix(in srgb, var(--color-primary) 12%, transparent);
  transition: transform 0.4s cubic-bezier(0.23, 1, 0.32, 1), box-shadow 0.4s ease;
  overflow: visible;
  transform-origin: center;
}

.pkg-promo-card:hover {
  transform: translate(-0.4em, -0.4em) scale(1.02);
  box-shadow: 0 26px 44px color-mix(in srgb, var(--color-primary) 24%, transparent);
}

.pkg-promo-card:active {
  transform: translate(0.1em, 0.1em) scale(0.98);
}

/* border-radius rounds this layer's own corners to match the card's, so
   its background stays clipped correctly now that the card itself is
   overflow:visible (needed below so .pkg-promo-leaf can overflow the
   corner) — a background always respects its own element's radius
   regardless of overflow, so this doesn't need overflow:hidden of its
   own to work.

   calc(0.6em - 1px), not a plain border-radius:inherit of the card's own
   0.6em: inset:0 on an absolutely-positioned child sits at the card's
   PADDING edge, one border-width inside the card's own border-box (where
   0.6em is measured) — reusing that same 0.6em on a box that's 1px
   smaller all around curves slightly tighter than the border's own inner
   curve, leaving a sliver of the page background showing through at each
   corner instead of a flush nested curve. Subtracting the border width
   is the standard fix for nesting a rounded corner inside another one. */

.pkg-promo-pattern-grid {
  position: absolute;
  inset: 0;
  border-radius: calc(0.6em - 1px);
  background-image: linear-gradient(
      to right,
      rgba(0, 0, 0, 0.05) 1px,
      transparent 1px
    ),
    linear-gradient(to bottom, rgba(0, 0, 0, 0.05) 1px, transparent 1px);
  background-size: 0.5em 0.5em;
  pointer-events: none;
  opacity: 0.25;
  transition: opacity 0.4s ease;
  z-index: 1;
}

/* Color scheme matches .detail-card-header (the "What we do" card's
   header): --muted background, --secondary (accent) text and
   border-bottom, rather than this card's own --primary/--bg pairing.
   ::before below (the k64 texture) is untouched on purpose — its
   multiply-blend darkening reads fine over the new background too, no
   need to retune it alongside the color swap. */

/* border-radius (top corners only, this sits at the top of the card) —
   needed now that the card itself is overflow:visible (for .pkg-promo-leaf
   to overflow its corner), so this header's own square corners no longer
   get clipped to the card's rounded shape for free. calc(0.6em - 1px), not
   the card's own plain 0.6em, for the same nesting-inside-a-border reason
   as .pkg-promo-pattern-grid above — this header sits one border-width
   inside the card's own border-box, so reusing the border-box's radius
   curves it a hair too tight and leaves a gap at the very tip of the
   corner where the card's background/border shows through. */

.pkg-promo-title-area {
  position: relative;
  padding: 1.4em;
  background: var(--muted);
  color: var(--secondary);
  font-family: var(--font-heading);
  font-weight: 800;
  font-size: 1.2em;
  display: flex;
  justify-content: space-between;
  align-items: center;
  border-bottom: 0.15em solid color-mix(in srgb, var(--secondary) 30%, transparent);
  border-radius: calc(0.6em - 1px) calc(0.6em - 1px) 0 0;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  z-index: 2;
  overflow: hidden;
}

/* Corner accent overflowing the card's top-right edge, same technique as
   .detail-card--deliverables .detail-card-leaf (col-matcha.svg overflowing
   its card's top-left corner) — z-index:3 puts it above .pkg-promo-
   title-area (z-index:2) rather than tucked behind it like the plain
   .detail-card-leaf sits relative to its card's tab, since here it's meant
   to visibly perch on/over the corner rather than peek out from under it. */

.pkg-promo-leaf {
  position: absolute;
  z-index: 3;
  top: -56px;
  right: -56px;
  width: 150px;
  height: auto;
  pointer-events: none;
  transform: rotate(6deg);
  transition: transform 0.45s ease;
}

.pkg-promo-card:hover .pkg-promo-leaf {
  transform: rotate(-6deg) scale(1.06);
}

.pkg-promo-body {
  position: relative;
  padding: 1.5em;
  z-index: 2;
}

/* Side-by-side sections (What's included / Addons / Shooting Time) instead
   of one stacked underneath the other - auto-fit collapses to fewer columns
   (down to one) on narrow viewports rather than needing a separate
   breakpoint, matching .detail-card-pair's approach. */

.pkg-promo-sections {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 2em;
}

.pkg-promo-section {
  position: relative;
  min-width: 0;
}

/* "What's included" carries two stacked subsections (Videos, then Strategic
   Guidance) rather than being one flat list, so it takes two of the
   auto-fit tracks while Addons and the badge column keep one each - the row
   still adds up to the four tracks' worth of width it filled back when
   these were four equal sections. span 2 is clamped to the available count
   automatically once auto-fit drops to a single column, so no breakpoint is
   needed to unwind it. */

.pkg-promo-section--wide {
  grid-column: span 2;
}

/* Addons is a short column sitting next to a much taller one, so with the
   grid's default align-items:stretch it gets stretched full height and its
   content ends up pinned to the top edge with a lot of dead space beneath.
   Centering the grid item shrinks it back to its content height and floats
   it in the middle of the row instead.

   The trailing margin on its last feature-grid is zeroed so this lands on
   optical centre - otherwise that 1.5em of empty margin counts as part of
   the box and the visible content sits ~12px high. Harmless once auto-fit
   collapses to one column, where every row is content-height anyway. */

.pkg-promo-section--center {
  align-self: center;
}

.pkg-promo-section--center .pkg-promo-feature-grid:last-child {
  margin-bottom: 0;
}

/* .pkg-promo-feature-grid's own margin-bottom already separates the two
   subsections; this just buys the second subheading a little more room so
   it reads as a new group rather than a continuation of the list above. */

.pkg-promo-subsection + .pkg-promo-subsection {
  margin-top: 0.5em;
}

/* Subsection heading - has to sit clearly below .pkg-promo-description (the
   section heading above it) while staying distinct from
   .pkg-promo-feature-text below it, so it borrows the small-caps label
   treatment already used by .pkg-promo-shooting-card-label instead of being
   another weight/size step in the same style. */

.pkg-promo-subheading {
  margin-bottom: 1em;
  color: var(--primary);
  font-size: 0.78em;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.pkg-promo-description {
  margin-bottom: 1.5em;
  color: var(--secondary);
  font-size: 0.95em;
  line-height: 1.4;
  font-weight: 500;
}

.pkg-promo-feature-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1em;
  margin-bottom: 1.5em;
}

/* Each section is a narrower column now (a third of the card, not the
   whole thing), so its own feature-grid drops to a single column - two-up
   sub-columns at this width left item text ("Frequently Asked Questions
   Video", "1-Month Content Calendar") wrapping awkwardly. */

.pkg-promo-section .pkg-promo-feature-grid {
  grid-template-columns: 1fr;
}

/* ...except in the double-width section, where there IS room for two-up
   again. Same auto-fit idiom as the parent grid rather than a hard `1fr
   1fr`, so it folds back to one column on its own when the section narrows;
   the minimum is also what stops a THIRD column appearing.

   The 1100px-container widths this minimum is tuned against differ by
   caller, because the two now hold a different number of sections:

     - Package partials (Basic/Plus/Pro): Addons moved out to its own block
       below the tier list, leaving only this section and the badge column.
       The parent's auto-fit COLLAPSES the empty fourth track, so the three
       surviving ones share the full ~1020px at ~319px each and this section
       becomes ~669px. Three sub-columns would need 3*min + 32px of gaps.
     - _web_service_contents.html: still three sections filling all four
       tracks at ~231px, so this section stays ~494px. Two sub-columns need
       2*min + 16px.

   So the minimum has to satisfy 3*min + 32 > 669 (no third column in the
   packages) AND 2*min + 16 <= 494 (still two in web services) - i.e.
   213 <= min <= 239. 225px sits mid-range with ~13px of slack either side.
   Items land ~326px wide in the packages and ~239px in web services, both
   at or above the ~239px this was originally tuned to.

   Must stay AFTER the single-column rule above - equal specificity, so
   source order is what decides it. */

.pkg-promo-section--wide .pkg-promo-feature-grid {
  grid-template-columns: repeat(auto-fit, minmax(225px, 1fr));
}

/* ...and an opt-out for a subsection that should stack regardless of the
   room available. Only "Strategic Guidance" uses it today (in all four
   partials): it holds exactly two items, and two items filling one wide
   row read as a pair of loose labels rather than a continuation of the
   checklist above them. Stacked, they stay a list.

   Deliberately NOT keyed off the item count (:has, :only-child, nth-child
   tricks) - a subsection wanting a single column is an editorial decision
   about that subsection, not a rule that two items always stack. Videos
   runs 3/6/9 items across the tiers and wants every column it can get.

   The class is doubled up in the selector purely for specificity: the rule
   above is 0-2-0, so a lone .pkg-promo-feature-grid--stack (0-1-0) would
   lose to it no matter where it sat in the file. */

.pkg-promo-feature-grid.pkg-promo-feature-grid--stack {
  grid-template-columns: 1fr;
}

/* Shooting Time's own small parallelogram badge, standing in for that
   section's heading + body text (its label is baked into the card's own
   copy rather than a separate .pkg-promo-description above it) - skewed
   via the classic two-layer technique: the outer box skews, an inner
   counter-skewed wrapper (.pkg-promo-shooting-card-inner) skews back the
   opposite amount so the icon/text stay upright and readable. Border +
   hard offset shadow (not a soft blur) matches the neubrutalist language
   already used elsewhere on this card (.pkg-promo-feature-icon's shadow,
   the outcome card above it) - a clock icon plus a label/value split
   (rather than one flat line) is what gives it more presence than the
   first pass.

   --muted is this card's local alias for --color-accent-1 (:root maps
   --color-muted -> --color-accent-1), so this stays inside the file's "no
   literal brand colours, always via the indirection layer" rule rather than
   hardcoding var(--color-accent-1) here. Splits it away from the outcome
   card above, which holds --secondary/Accent 2.

   Sits in the bottom-right corner of the promo box. The grid stretches
   every column to the height of the tallest, so the LAST column's
   bottom-right corner already IS the box's bottom-right corner - making
   that column a flex column (rule below) and letting margin-top:auto
   swallow the leftover space puts the badge there without taking it out of
   flow. align-self:flex-end does double duty: right-aligns it, and keeps it
   shrink-wrapped instead of stretching full-width like the checklist
   columns next to it.

   Deliberately NOT position:absolute against .pkg-promo-bare - auto-fit
   drops this grid to two rows below ~975px viewport and to one column below
   ~510px, and an out-of-flow badge would then sit on top of whatever
   wrapped underneath it. This version simply falls back to sitting under
   the outcome card. */

.pkg-promo-sections > .pkg-promo-section:last-child {
  display: flex;
  flex-direction: column;
}

.pkg-promo-shooting-card {
  display: inline-block;
  align-self: flex-end;
  margin-top: auto;
  margin-bottom: 0;
  padding: 0.8em 1.2em;
  background: var(--muted);
  border: 0.12em solid var(--text);
  border-radius: 0.4em;
  box-shadow: 0.25em 0.25em 0 var(--primary);
  transform: skewX(-10deg);
}

.pkg-promo-shooting-card-inner {
  display: flex;
  align-items: center;
  gap: 0.7em;
  transform: skewX(10deg);
}

.pkg-promo-shooting-card-icon {
  width: 1.7em;
  height: 1.7em;
  flex-shrink: 0;
  color: var(--bg);
}

.pkg-promo-shooting-card-copy {
  display: flex;
  flex-direction: column;
  white-space: nowrap;
}

.pkg-promo-shooting-card-label {
  color: color-mix(in srgb, var(--bg) 75%, transparent);
  font-size: 0.68em;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.pkg-promo-shooting-card-value {
  color: var(--bg);
  font-size: 1.05em;
  font-weight: 800;
  line-height: 1.3;
}

/* Same material (fill/border/hard shadow) as the shooting-card below it,
   but flat rather than skewed - a full sentence reads much worse skewed
   and wrapped across lines than a two-line stat does, so this is a flat
   sibling in the same visual family instead of forcing the same transform
   on both.

   --secondary is the card's local alias for --color-accent (which :root in
   turn maps to --color-accent-2), same indirection rule the rest of this
   block follows rather than hardcoding the brand colour. Splits it away
   from the shooting-time badge below, which holds --muted/Accent 1. */

.pkg-promo-outcome-card {
  width: fit-content;
  max-width: 220px;
  margin-bottom: 1.5em;
  padding: 0.9em 1.1em;
  background: var(--secondary);
  border: 0.12em solid var(--text);
  border-radius: 0.4em;
  box-shadow: 0.25em 0.25em 0 var(--primary);
  color: var(--bg);
  font-size: 0.85em;
  font-weight: 600;
  line-height: 1.5;
}

/* Pin the outcome card to the promo box's top-right corner, but only once
   the grid is still a single row (~975px+, same threshold the shooting-card
   comment above measures the row-collapse against) - .pkg-promo-section's
   own position:relative (rule near the top of this file) is what the
   absolute positioning resolves against, and since the last section is
   both the rightmost column AND top-aligned with the wide column in a
   single-row layout, "top-right of the last section" and "top-right of
   .pkg-promo-sections" are the same point without needing to move this
   element out of the last section in markup.

   Below that width the grid drops to stacked rows, so the last section is
   no longer flush with the row's top-right corner - falls back to the
   static, in-flow position (top of the section, same as the shooting-card
   below it) rather than floating over whatever wrapped underneath. */

@media (min-width: 975px) {
  .pkg-promo-outcome-card {
    position: absolute;
    top: 0;
    right: 0;
    margin-bottom: 0;
  }
}

.pkg-promo-feature-item {
  display: flex;
  align-items: center;
  gap: 0.6em;
  transition: transform 0.2s ease;
}

.pkg-promo-feature-item:hover {
  transform: translateX(0.3em);
}

.pkg-promo-feature-icon {
  position: relative;
  width: 1.4em;
  height: 1.4em;
  flex-shrink: 0;
  background: var(--muted);
  border: 0.12em solid var(--text);
  border-radius: 0.3em;
  box-shadow: 0.2em 0.2em 0 rgba(0, 0, 0, 0.2);
  transition: all 0.2s ease;
}

/* Hand-ticked checkmark, centered on the box - the short downstroke (start
   + bottom vertex) sits neatly inside the box, only the long upstroke's tip
   flicks past the top-right corner, which is what sells the "hand ticked
   it" look without the whole mark looking oversized. Literal red (not a
   --color-* var, per the like button's red also being literal) but a
   notch darker/less saturated than that button's red so it doesn't read
   as neon. Omitted on the [Extra] box - .pkg-promo-feature-icon--extra has
   no .pkg-promo-feature-tick child in the markup. */

.pkg-promo-feature-tick {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 125%;
  height: 125%;
  transform: translate(-50%, -50%) rotate(-8deg);
  overflow: visible;
  pointer-events: none;
}

.pkg-promo-feature-tick path {
  fill: none;
  stroke: rgb(199, 28, 28);
  stroke-width: 10;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.pkg-promo-feature-item:hover .pkg-promo-feature-icon {
  background: var(--secondary-hover);
  transform: rotate(-5deg);
}

.pkg-promo-feature-icon--extra {
  background: var(--muted);
}

.pkg-promo-feature-text {
  font-size: 0.85em;
  font-weight: 600;
  color: var(--text);
}

/* Expandable variant of .pkg-promo-feature-item - "Space & Service
   Showcase" today, click to reveal an example Instagram embed underneath
   it. Built on native <details>/<summary> rather than a JS toggle: it's
   collapsed by default with no script needed, keyboard/screen-reader
   accessible for free, and Instagram's embed.js can still find + process
   the blockquote while it's closed (closed <details> content is hidden the
   same way display:none is, but stays in the DOM), so the heavy embed
   work happens once up front instead of being deferred to first click.

   .pkg-promo-feature-item's own flex layout moves onto .pkg-promo-feature-summary
   here, since the <details> itself now stacks two blocks (summary, then
   the embed) instead of being the icon+text row directly. */

.pkg-promo-feature-item--expandable {
  display: block;
}

.pkg-promo-feature-item--expandable.pkg-promo-feature-item:hover {
  transform: none;
}

.pkg-promo-feature-summary {
  display: flex;
  align-items: center;
  gap: 0.6em;
  cursor: pointer;
  list-style: none;
  transition: transform 0.2s ease;
}

.pkg-promo-feature-summary::marker,
.pkg-promo-feature-summary::-webkit-details-marker {
  display: none;
}

.pkg-promo-feature-summary:hover {
  transform: translateX(0.3em);
}

/* Chevron, not reusing .pkg-promo-feature-tick's checkmark path - this one
   needs to rotate on open/close, and sharing the tick would mean the "item
   included" checkmark and the "expand this" affordance collapse into one
   ambiguous glyph. */

.pkg-promo-feature-summary::after {
  content: "";
  width: 0.45em;
  height: 0.45em;
  margin-left: auto;
  flex-shrink: 0;
  border-right: 0.14em solid var(--text);
  border-bottom: 0.14em solid var(--text);
  opacity: 0.55;
  transform: rotate(-45deg);
  transition: transform 0.2s ease;
}

.pkg-promo-feature-item--expandable[open] > .pkg-promo-feature-summary::after {
  transform: rotate(45deg);
}

/* Spans the full grid row once open (rather than staying pinned to its own
   column) so the embed gets the row's whole width to lay out in instead of
   being squeezed into a single ~225px-min feature-grid track - the other
   items originally sharing that row simply reflow after it, same as any
   grid item's height change. */

.pkg-promo-feature-grid > .pkg-promo-feature-item--expandable[open] {
  grid-column: 1 / -1;
}

.pkg-promo-feature-embed {
  display: flex;
  justify-content: center;
  margin: 0.9em 0 0.3em;
  animation: pkg-promo-feature-embed-in 0.25s ease;
}

@keyframes pkg-promo-feature-embed-in {
  from {
    opacity: 0;
    transform: translateY(-6px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* Generic "media goes here" placeholder — a bordered box with a diagonal
   cross, the classic wireframe stand-in for an image or video that hasn't
   been shot/supplied yet. Used everywhere a stock photo or stand-in
   YouTube video used to sit; swap the element for a real <img>/embed once
   real photography/video is ready. Sizing (width/height/aspect-ratio) is
   owned by whatever container it sits in (.hero-split-media, .card,
   .split-section, .video-placeholder itself), not by this rule, so one
   class works at any size.

   The cross is two diagonal gradients layered as pseudo-elements rather
   than an SVG/background-image, so the color rides on currentColor /
   color-mix with the rest of the palette instead of a separate asset. */

.img-placeholder {
  position: relative;
  background: color-mix(in srgb, var(--color-muted) 12%, white);
  border: 1px solid color-mix(in srgb, var(--color-muted) 70%, transparent);
  overflow: hidden;
}

.img-placeholder::before,
.img-placeholder::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top right,
    transparent calc(50% - 1px),
    color-mix(in srgb, var(--color-muted) 70%, transparent) calc(50% - 1px),
    color-mix(in srgb, var(--color-muted) 70%, transparent) calc(50% + 1px),
    transparent calc(50% + 1px));
}

.img-placeholder::after {
  background: linear-gradient(to top left,
    transparent calc(50% - 1px),
    color-mix(in srgb, var(--color-muted) 70%, transparent) calc(50% - 1px),
    color-mix(in srgb, var(--color-muted) 70%, transparent) calc(50% + 1px),
    transparent calc(50% + 1px));
}

/* Stand-in for a deliverable video — same diagonal-cross treatment as
   .img-placeholder, just pinned to a 16:9 video frame instead of taking
   its size from an image container. */

.video-placeholder {
  aspect-ratio: 16 / 9;
  border-radius: 8px;
}

/* Book / contact form */

.book-form {
  max-width: 560px;
  display: flex;
  flex-direction: column;
  gap: 18px;
  margin-top: 32px;
}

.book-form label {
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--color-secondary);
  margin-bottom: 6px;
  display: block;
}

.book-form input,
.book-form textarea {
  width: 100%;
  padding: 14px 16px;
  border: 1px solid var(--color-muted);
  border-radius: 8px;
  font-family: var(--font-body);
  font-size: 15px;
  color: var(--color-text);
  background: #fff;
}

/* The submit button reuses .btn-book directly (see book.html) instead of
   duplicating its color/padding/hover rules under a second selector — this
   just resets the couple of browser <button> defaults .btn-book doesn't
   already cover (border, cursor) and positions it in the form's flex
   column. */

.book-form-submit {
  align-self: flex-start;
  border: none;
  cursor: pointer;
}

/* Honeypot wrapper for the form's decoy 'website' field (core/forms.py).
   Parked off-screen rather than given display:none deliberately: a bot that
   checks for hidden fields will skip a display:none input and fill only the
   ones that look real, which is exactly the submission we're trying to
   catch. Off-screen looks like an ordinary field to anything reading the
   markup, while being just as invisible to people. */

.book-form-hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.book-form-error {
  margin-top: 6px;
  font-size: 13px;
  color: var(--color-accent-2);
}

.book-form-messages {
  max-width: 560px;
  margin-top: 32px;
  padding: 0;
  list-style: none;
}

.book-form-message {
  padding: 14px 16px;
  border-radius: 8px;
  border-left: 3px solid;
  font-size: 15px;
  background: #fff;
}

.book-form-message + .book-form-message {
  margin-top: 10px;
}

.book-form-message--success {
  border-left-color: var(--color-secondary);
  color: var(--color-secondary);
}

.book-form-message--error {
  border-left-color: var(--color-accent-2);
  color: var(--color-accent-2);
}

/* Footer */

.site-footer {
  background: var(--color-secondary);
  color: var(--color-primary);
  padding: 56px 40px 28px;
}

.footer-brand,
.footer-links,
.footer-social {
  max-width: 1200px;
  margin: 0 auto;
}

.footer-brand {
  text-align: center;
  margin-bottom: 32px;
}

.footer-brand img {
  height: 40px;
  margin: 0 auto 8px;
  border-radius: 4px;
}

.footer-brand p {
  margin: 0;
  font-size: 13px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0.85;
}

.footer-links {
  list-style: none;
  display: flex;
  justify-content: center;
  gap: 28px;
  padding: 0;
  margin-bottom: 24px;
  flex-wrap: wrap;
}

.footer-links a {
  text-decoration: none;
  font-size: 14px;
  color: var(--color-primary);
}

.footer-links a:hover {
  color: #fff;
}

.footer-social {
  display: flex;
  justify-content: center;
  gap: 24px;
  margin-bottom: 32px;
}

.footer-social a {
  text-decoration: none;
  font-size: 13px;
  letter-spacing: 0.05em;
  color: var(--color-primary);
}

.footer-social a:hover {
  color: #fff;
}

/* Scroll reveal (plain JS + IntersectionObserver, see main.js) */

.reveal {
  opacity: 0;
  transform: translateY(32px);
  transition: opacity 0.7s ease, transform 0.7s ease;
}

.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;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  .reveal {
    transition: none;
    opacity: 1;
    transform: none;
  }
}

.footer-copy {
  text-align: center;
  font-size: 12px;
  color: color-mix(in srgb, var(--color-primary) 70%, transparent);
  border-top: 1px solid color-mix(in srgb, var(--color-muted) 30%, transparent);
  padding-top: 20px;
  margin: 0 auto;
  max-width: 1200px;
}

/* Like button — from Uiverse.io by SalladShooter, dropped in under #intro's
   body copy (see home.html), stripped down to just the heart icon (no
   dotted box chrome, no "Like" label). Every selector below stays scoped
   under .like-wrapper (the original widget used bare .check/.container/
   .icon) so it can't collide with any other component in this file.
   Icon fill was originally white (readable against the widget's own dark
   box) — now that the box is gone it uses the site palette instead, or it
   would be invisible against #intro's light background. Auto-checks
   itself on scroll-into-view via a dedicated IntersectionObserver in
   main.js (separate from the generic .reveal one, since this needs to
   flip the checkbox's `checked` property, not just add a class) — that's
   what replays the same wiggle a real click would. */

.like-wrapper {
  display: flex;
  align-items: center;
  justify-content: center;
  width: fit-content;
  margin: 32px auto 0;
  cursor: pointer;
}

.like-wrapper .check[type="checkbox"] {
  display: none;
}

.like-wrapper .container {
  display: flex;
  align-items: center;
  cursor: pointer;
}

.like-wrapper .icon {
  width: 1.5em;
  height: 1.5em;
  fill: var(--color-primary);
  transition: opacity 0.3s ease-in-out;
}

.like-wrapper .icon.active {
  display: none;
  fill: var(--color-accent-2);
}

.like-wrapper .check[type="checkbox"]:checked + .container .icon.active {
  display: inline-block;
  animation: like-wiggle 0.5s ease-in-out;
}

.like-wrapper .check[type="checkbox"]:checked + .container .icon.inactive {
  display: none;
}

@keyframes like-wiggle {
  0%,
  100% {
    transform: rotate(0deg);
  }
  25% {
    transform: rotate(-10deg);
  }
  50% {
    transform: rotate(10deg);
  }
  75% {
    transform: rotate(-10deg);
  }
}

/* Responsive */

@media (max-width: 860px) {
  /* Header shrinks with .navbar's padding below, so the snap offset that
     clears it shrinks to match (44px logo + 2x16px padding). */
  :root {
    --tier-snap-offset: 78px;
  }

  .navbar {
    flex-wrap: wrap;
    padding: 16px 20px;
    row-gap: 0;
  }

  .logo {
    order: 1;
  }

  .nav-toggle {
    order: 2;
    display: flex;
  }

  .btn-book-desktop {
    display: none;
  }

  .nav-links {
    order: 4;
    flex-basis: 100%;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    max-height: 0;
    overflow: hidden;
    transition: max-height 0.3s ease;
  }

  .nav-links.is-open {
    max-height: 480px;
    padding: 12px 0 20px;
  }

  .nav-links li {
    width: 100%;
    text-align: center;
  }

  .nav-links a {
    display: block;
    padding: 14px 0;
    border-bottom: 1px solid color-mix(in srgb, var(--color-secondary) 30%, transparent);
  }

  /* Overrides the desktop active-link rule's accent border-bottom
     (line ~133) back to the same neutral divider every other mobile item
     gets — in the stacked menu every row already needs a bottom border as
     a row divider, so the accent variant would look like a stray
     underline rather than a "current page" indicator. The accent text
     color from that same desktop rule isn't touched, so the current page
     is still distinguishable by its text color alone. */
  .nav-links li.active a {
    border-bottom: 1px solid color-mix(in srgb, var(--color-secondary) 30%, transparent);
  }

  .nav-links-cta {
    display: block;
    padding-top: 12px;
  }

  .nav-links-cta a {
    border: none;
    display: inline-block;
  }

  .hero-split {
    min-height: 0;
  }

  .hero-split-row {
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 0 20px;
  }

  .hero-split-media {
    flex: none;
    height: 32vh;
    margin: 24px 0 0;
  }

  /* The desktop portrait card (aspect-ratio 3/4, centered) would be too
     narrow to read inside this short 32vh row, so go back to a full-bleed
     cover image here instead of staying vertical. */
  .hero-split-media img,
  .hero-split-media .img-placeholder {
    width: 100%;
    height: 100%;
    aspect-ratio: auto;
  }

  .hero-split-copy {
    flex: none;
    padding: 32px 0 48px;
  }

  .hero-split-title {
    font-size: 32px;
  }

  .page-section {
    padding: 48px 20px;
  }

  .landing-section {
    padding: 56px 0;
  }

  .landing-section--tight-top {
    padding-top: 28px;
  }

  .landing-section-inner {
    padding: 0 20px;
  }

  .card-grid,
  .deliverable-grid {
    grid-template-columns: 1fr;
  }

  .split-section {
    flex-direction: column;
  }

  .split-section img {
    width: 100%;
  }

}
