/* Bullish Media — service + about pages.
   Resolved from lamalama's compiled Tailwind + token system, archived at
   docs/reference/2026-08-05/lama.css. Utility classes are expanded into real
   CSS so the site keeps its zero-dependency, no-build-step rule.

   Typeface deviation as everywhere else: the reference sets SuisseBPIntl and
   Sometype; both are commercial, so nav/body map to Inter and mono to
   JetBrains Mono. All other metrics are the reference's own. */

:root {
  /* grid — mobile first, exactly the reference's breakpoint at 1000px */
  --ll-col-count: 6;
  --ll-grid-gap: 0.625rem;
  --ll-grid-margin: 1rem;

  /* section rhythm */
  --section-3xs: max(calc(10 / 16 * 1rem), calc(20 / 1440 * 100vw));
  --section-2xs: max(calc(20 / 16 * 1rem), calc(40 / 1440 * 100vw));
  --section-xs:  max(calc(30 / 16 * 1rem), calc(60 / 1440 * 100vw));
  --section-sm:  max(calc(40 / 16 * 1rem), calc(80 / 1440 * 100vw));
  --section-md:  max(calc(60 / 16 * 1rem), calc(120 / 1440 * 100vw));
  --section-lg:  max(calc(80 / 16 * 1rem), calc(160 / 1440 * 100vw));
  --section-xl:  max(calc(100 / 16 * 1rem), calc(200 / 1440 * 100vw));
  --section-2xl: max(calc(110 / 16 * 1rem), calc(220 / 1440 * 100vw));
  --section-3xl: max(calc(120 / 16 * 1rem), calc(240 / 1440 * 100vw));
}

@media (min-width: 1000px) {
  :root {
    --ll-col-count: 12;
    --ll-grid-gap: 1.5rem;
    --ll-grid-margin: 2.5rem;
  }
}

/* Static pages scroll natively — unlike the gallery, which is virtual.

   Colour comes entirely from the theme tokens declared in menu.css (the one
   stylesheet every page loads). Measured on the reference: its service pages
   are <main data-theme="light"> — body computes rgb(249,244,235) on
   rgb(1,1,1) — and About/home are data-theme="dark" (#1A1C1C on #F9F4EB).
   Every section just inherits; there are no per-section colours.

   html is themed too, not only body: an unthemed html paints the canvas (and
   therefore the overscroll gutter) with styles.css's near-black. */
html[data-theme] {
  background: var(--bgPrimary);
  color: var(--textPrimary);
}
body[data-page='static'] {
  overflow-y: auto;
  height: auto;
  min-height: 100%;
  /* Deliberately no background: html paints --bgPrimary above, and the
     cursor trail canvas sits at z -1 — between html's paint and the body's
     content. A body background would sit on top of it. */
  background: transparent;
  color: var(--textPrimary);
}

.ll-container {
  padding-left: var(--ll-grid-margin);
  padding-right: var(--ll-grid-margin);
}

.ll-grid {
  display: grid;
  grid-template-columns: repeat(var(--ll-col-count), minmax(0, 1fr));
  column-gap: var(--ll-grid-gap);
}

/* ------------------------------------------------------------ type scale */

.ll-display-rg,
.ll-heading-1 {
  font-family: var(--font-sans);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: -0.02em;
  line-height: 0.8;
  margin: 0;
}
.ll-display-rg { font-size: clamp(3.25rem, 1.0625rem + 4.38vw, 5rem); }
.ll-heading-1  { font-size: clamp(2.5rem, 0.9375rem + 3.13vw, 3.75rem); }

.ll-heading-2,
.ll-heading-3 {
  font-family: var(--font-sans);
  font-weight: 400;
  letter-spacing: -0.02em;
  margin: 0;
}
.ll-heading-2 { font-size: clamp(2rem, 0.75rem + 2.5vw, 3rem); line-height: 0.9; }
.ll-heading-3 { font-size: clamp(1.75rem, 0.8125rem + 1.88vw, 2.5rem); line-height: 1.05; }

.ll-body-md, .ll-body-rg, .ll-body-sm {
  font-family: var(--font-sans);
  font-weight: 400;
  letter-spacing: -0.02em;
  margin: 0;
}
.ll-body-md { font-size: clamp(1rem, 0.6875rem + 0.63vw, 1.25rem); line-height: 1.2; }
.ll-body-rg { font-size: clamp(0.875rem, 0.71875rem + 0.31vw, 1rem); line-height: 1.4; }
.ll-body-sm { font-size: clamp(0.75rem, 0.59375rem + 0.31vw, 0.875rem); line-height: 1.5; }

@media (min-width: 1000px) {
  .ll-display-rg { font-size: clamp(5rem, 2.3075rem + 2.99vw, 7.6925rem); }
  .ll-heading-1  { font-size: clamp(3.75rem, 1.875rem + 2.08vw, 5.625rem); }
  .ll-heading-2  { font-size: clamp(3rem, 1.5rem + 1.67vw, 4.5rem); }
  .ll-heading-3  { font-size: clamp(2.5rem, 1.42875rem + 1.19vw, 3.57125rem); }
  .ll-body-md    { font-size: clamp(1.25rem, 0.9375rem + 0.35vw, 1.5625rem); }
  .ll-body-rg    { font-size: clamp(1rem, 0.856875rem + 0.16vw, 1.14313rem); }
  .ll-body-sm    { font-size: clamp(0.875rem, 0.729375rem + 0.16vw, 1.02063rem); }
}

/* The bracketed mono label used all over the reference. */
.ll-tag {
  font-family: var(--font-mono);
  font-size: 0.625rem;
  font-weight: 500;
  letter-spacing: -0.02em;
  line-height: 1.8;
  text-transform: uppercase;
}

/* Small filled pill, e.g. the service tags under the hero headline.
   Reference: bg-bgSecondary + text-textPrimary, so on a light page it is a
   solid white chip with near-black type, and on a dark page a black chip with
   cream type. Token-driven for exactly that reason — the first pass hard-coded
   white-on-black and went unreadable the moment the page turned cream. */
.ll-tag-item {
  display: flex;
  align-items: center;
  width: max-content;
  height: 1.375rem;
  padding: 0 0.5rem;
  background: var(--bgSecondary);
  color: var(--textPrimary);
  border-radius: 2px;
}

/* ------------------------------------------------------------- image fx */

/* One shared plane canvas for every [data-fx] photo on the page — the
   reference draws all of its webgl_images on a single composer canvas too.
   Above the page so it can paint over the <img>s it is warping, below the
   floating pill (z 60) so the menu is never behind a smear, and transparent
   to the pointer so the press-and-hold still lands on the image itself.

   src/image-fx.js creates this element only when it actually mounts; without
   WebGL2, with reduced motion, or on a pointerless device there is no canvas
   at all and the plain <img>s are the whole page. */
.image-fx {
  position: fixed;
  inset: 0;
  z-index: 5;
  pointer-events: none;
}

/* --------------------------------------------------------- scroll reveal */

/* The reference ships every revealable block at opacity 0 and animates it in
   on intersection. Anything that never gets observed must still end up
   visible, so the reveal is opt-in via .is-in rather than a permanent 0. */
.reveal {
  opacity: 0;
  transform: translateY(1.25rem);
  transition: opacity .8s cubic-bezier(.165,.84,.44,1),
              transform .8s cubic-bezier(.165,.84,.44,1);
}
.reveal.is-in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; transition: none; }
}

/* text-reveal.js line wrapper — the reference splits with
   linesClass "whitespace-nowrap"; the clip mask rides each line's own box. */
.tr-line { display: block; white-space: nowrap; }

/* --------------------------------------------------------------- section */

.ll-section { position: relative; }
.ll-section--hero-service { padding-top: var(--section-2xl); }
.ll-section--intro        { padding-top: var(--section-lg); }
.ll-section--intro-media  { padding-top: var(--section-lg); }
.ll-section--usps         { padding-top: var(--section-xl); }
.ll-section--process      { padding-top: var(--section-xl); }
.ll-section--split        { padding-top: var(--section-xl); }
.ll-section--others       { padding-top: var(--section-xl); padding-bottom: var(--section-2xl); }

/* Every page clears the floating pill. */
.page-main { padding-top: 4.5rem; }

/* ------------------------------------------------------------ hero (svc) */

.hero-service { display: flex; flex-direction: column; align-items: center; text-align: center; }
.hero-service__title { margin-top: 1.5rem; }
.hero-service__title br { display: none; }
@media (min-width: 1000px) {
  .hero-service__title br { display: inline; }
}

.hero-service__tags { display: flex; gap: 0.125rem; margin-top: 1.5rem; }
@media (min-width: 1000px) { .hero-service__tags { margin-top: 2.5rem; } }

.hero-service__cta {
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  width: max-content;
  margin-top: 2rem;
  padding: 0.85em 1.4em;
  border: 1px solid currentColor;
  border-radius: 2rem;
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  transition: background-color .4s ease, color .4s ease;
}
.hero-service__cta:hover { background: var(--textPrimary); color: var(--bgPrimary); }

/* ------------------------------------------------- introduction (service) */

/* The reference's introduction_service, measured off the live site at 1600w
   (Alvaro's capture): statement left (cols 1-5), a half-width 16:9 video
   right (cols 7-12), and the body paragraph riding the video's own column
   below it. The fixed aspect-ratio reserves the box before decode. */
.intro-split { display: flex; flex-direction: column; gap: 2.5rem; }
@media (min-width: 1000px) {
  .intro-split {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    column-gap: 1.5rem;
    align-items: start;
  }
  .intro-split__left  { grid-column: 1 / span 5; }
  .intro-split__right { grid-column: 7 / span 6; }
}
.intro-split__video {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: 4px;
}
.intro-split__right p { margin: 2.5rem 0 0; max-width: 34rem; opacity: 0.75; }

/* ------------------------------------------------------------------ usps */

.usps { display: flex; flex-direction: column; gap: 3rem; }
@media (min-width: 1000px) {
  .usps { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: 1.5rem; }
  /* Rows are explicit on purpose. With auto-placement the card (columns 1-3)
     cannot back-fill row 1 once the lede has advanced the cursor past
     column 10, so it dropped to its own row and left a void beside it. */
  .usps__lede  { grid-column: 7 / span 4; grid-row: 1; margin-bottom: 6.25rem; }
  .usps__card  { grid-column: 1 / span 3; grid-row: 1 / span 2; margin-top: 0.5rem; }
  .usps__stats { grid-column: 7 / span 5; grid-row: 2; }
}

/* Bordered quote card — reference .ll-block--testimonial-card */
.usps__card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 2.5rem;
  padding: 2rem;
}
.usps__card::before {
  content: '';
  position: absolute;
  inset: 0;
  border: 1px solid currentColor;
  border-radius: 4px;
  /* .1 vanished once the page turned cream — a hairline of near-black at 10%
     on #F9F4EB is under 1:1.1 contrast. */
  opacity: 0.18;
  pointer-events: none;
}
/* Reference card head: a ~90px portrait beside the mono role label. */
.usps__card-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 1rem; }
.usps__card-head > div { text-align: right; }
.usps__card-head img { width: 5.625rem; height: auto; border-radius: 2px; }
.usps__card-role { opacity: 0.55; }

.usps__stats { display: flex; flex-direction: column; gap: 2.5rem; }
.usps__stat-value { line-height: 0.9; }
.usps__stat-label { opacity: 0.6; margin-top: 0.5rem; }

/* --------------------------------------------------------------- process */

/* The reference's stacking-cards process (ll-block--stacking-cards +
   blocks/process_item, measured off lama-svc-branding.html + lama.css +
   the stacking_cards chunk): fixed-height cards, each in its own sticky
   slot; a hidden in-flow sizing copy (our ghosts) gives the block the
   scroll distance the pinned cards play out over; every card's top
   hairline carries a scroll progress bar. Type is the reference's exact
   clamps — number and title at display scale, stepped at our 1000px
   breakpoint like the rest of pages.css's scale (theirs steps at 1440). */

.process__intro { margin-bottom: 3.75rem; }
@media (min-width: 1000px) {
  .process__intro { width: calc(5 / 12 * 100%); margin-bottom: 6.25rem; }
}

.ll-body-lg {
  font-family: var(--font-sans);
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 1.2;
  font-size: clamp(1.25rem, 0.9375rem + 0.63vw, 1.5rem);
}
.ll-add-number {
  font-family: var(--font-sans);
  font-weight: 700;
  text-transform: uppercase;
  line-height: 0.8;
  font-size: clamp(2.5rem, 0.15625rem + 4.69vw, 4.375rem);
}
@media (min-width: 1000px) {
  .ll-body-lg { font-size: clamp(1.5rem, 1.2rem + 0.33vw, 1.8rem); }
  .ll-add-number { font-size: clamp(4.375rem, 1.09375rem + 3.65vw, 7.65625rem); }
}

.process-stack {
  /* 375px cards, 360px at lg — the reference's fixed card heights. The
     60px peek is the sliver every stacked card keeps once the next one
     pins over it (stack-cards.js clips the rest away). */
  --stack-h: 23.4375rem;
  --stack-peek: 3.75rem;
  position: relative;
  display: flex;
  flex-direction: column;
}
@media (min-width: 1000px) { .process-stack { --stack-h: 22.5rem; } }

/* The 82px probe stack-cards.js reads its rem scale from — the reference's
   js-padding element, kept as a live measurement so zoomed text scales the
   whole mechanic. */
.process-stack__pad { position: absolute; height: 5.125rem; }

/* Ghosts hidden until the JS drives; without it the slots are plain flow
   and the page reads top to bottom like any other. */
.process-stack__spacer { display: none; }
.is-stacked .process-stack__spacer { display: block; }
.process-stack__ghost { height: var(--stack-h); }

/* The reference's real cards do NOT sit in flow after the sizing copy —
   they ride an absolute overlay on top of it (absolute inset-0, inner
   wrapper anchored to the block's bottom), so the block's height comes
   from the ghosts alone and the first card is pinned the moment the
   section arrives. Static (flow) until the JS mounts. */
.is-stacked .process-stack__layer { position: absolute; inset: 0; }
/* Top-anchored on purpose: the bed is taller than the ghosts alone (each
   slot carries its release padding), and a bottom anchor hung that excess
   ABOVE the section — cards over the intro paragraph and the section
   before it. stack-cards.js stretches the spacer to the bed's real height,
   so anchoring top keeps the overlay exactly inside the section. */
.is-stacked .process-stack__bed { position: absolute; left: 0; right: 0; top: 0; }

.process-stack__slot { position: relative; }
.is-stacked .process-stack__slot { position: sticky; } /* top + pb set by JS */

.process-stack__card {
  position: relative;
  height: var(--stack-h);
  padding: 2.5rem 0;
}
@media (min-width: 1000px) {
  .process-stack__card { padding: 1.875rem 0 3.75rem; }
}

.process-stack__rule { position: absolute; top: 0; left: 0; right: 0; height: 1px; }
.process-stack__rule::before {
  content: '';
  position: absolute;
  inset: 0;
  background: currentColor;
  opacity: 0.2;
}
.process-stack__bar {
  position: absolute;
  inset: 0;
  display: block;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left center;
}

/* Card anatomy — the reference's proportions: number 2 columns, title 5,
   both inside a 7/12 main column; label + deliverable lines indented 2
   columns under them; description 3/12 on the right, bottom-aligned on
   phones by the column layout's space-between. */
.process__step {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 1.5rem;
  height: 100%;
}
.process__step-head { display: flex; gap: 0.5625rem; }
.process__step-title { margin: 0; }
.process__step-detail { margin-top: 1rem; }
.process__step-lines { margin-top: 1rem; }
.process__step-body { margin: 0; width: calc(5 / 6 * 100%); }
@media (min-width: 1000px) {
  .process__step { flex-direction: row; gap: 1.5rem; }
  .process__step-main {
    width: calc(7 / 12 * 100%);
    display: flex;
    flex-direction: column;
    justify-content: space-between;
  }
  .process__step-head { gap: 1.5rem; }
  .process__step-num { width: calc(2 / 7 * 100%); }
  .process__step-title { width: calc(5 / 7 * 100%); }
  .process__step-detail { margin-top: 0; padding-left: calc(2 / 7 * 100%); }
  .process__step-lines { margin-top: 1.25rem; }
  .process__step-body { width: calc(3 / 12 * 100%); }
}

.process__step-line {
  font-family: var(--font-sans);
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 1.2;
  font-size: clamp(1.25rem, 1.09375rem + 0.31vw, 1.375rem);
}
.process__step-body {
  font-family: var(--font-sans);
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 1.2;
  font-size: clamp(0.875rem, 0.5625rem + 0.63vw, 1.125rem);
}
@media (min-width: 1000px) {
  .process__step-line { font-size: clamp(1.375rem, 1.2375rem + 0.15vw, 1.5125rem); }
  .process__step-body { font-size: clamp(1.125rem, 0.80375rem + 0.36vw, 1.44625rem); }
}

/* ----------------------------------------------------------------- split */

.split { display: flex; flex-direction: column; gap: 2.5rem; }
@media (min-width: 1000px) {
  .split { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: 1.5rem; align-items: center; }
  .split__media { grid-column: 1 / span 6; }
  .split__body  { grid-column: 8 / span 4; }
}
.split__media img { width: 100%; height: auto; border-radius: 4px; }
.split__body p { margin: 1.25rem 0 0; opacity: 0.75; }

/* -------------------------------------------------------------- showcase */

/* The websites page's portfolio grid: screenshot cards of the sites Bullish
   has built (media/sites/, 1280x800 hero captures). Two columns at lg, the
   full column width on phones. */
.ll-section--showcase { padding-top: var(--section-xl); }
.showcase__lede { max-width: 42rem; margin-top: 1.25rem; }
.showcase__grid {
  display: flex;
  flex-direction: column;
  gap: 3.5rem;
  margin-top: var(--section-sm);
}
@media (min-width: 1000px) {
  .showcase__grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 4.5rem 1.5rem;
  }
}
.showcase__item { display: block; color: inherit; text-decoration: none; }
.showcase__media {
  margin: 0;
  overflow: hidden;
  border-radius: 4px;
  border: 1px solid color-mix(in srgb, currentColor 12%, transparent);
}
.showcase__media img { display: block; width: 100%; height: auto; }
.showcase__meta {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 1.25rem;
}
.showcase__meta .ll-tag { opacity: 0.55; white-space: nowrap; }
.showcase__body { margin: 0.5rem 0 0; max-width: 34rem; opacity: 0.7; }

/* ---------------------------------------------------------------- others */

.others__list { display: flex; flex-direction: column; margin-top: 2.5rem; }
.others__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.5rem 0;
  border-top: 1px solid var(--rule);
  transition: padding-left .5s cubic-bezier(.165,.84,.44,1), opacity .4s ease;
}
.others__item:last-child { border-bottom: 1px solid var(--rule); }
.others__item:hover { padding-left: 1rem; }
.others__item span:last-child { opacity: 0.5; font-family: var(--font-mono); font-size: 0.75rem; }

/* ------------------------------------------------------------ about page */

/* hero_extended. Reference: min-h-dvh, a fullscreen looping background video,
   and the CONTENT layer (not the section) in mix-blend-mode: exclusion.
   Blending the whole section would blend the video with the page behind it. */
.about-hero {
  position: relative;
  display: flex;
  align-items: center;
  min-height: 100vh;
  min-height: 100dvh;
  padding-top: var(--section-md);
  padding-bottom: var(--section-md);
  /* The reel is full-bleed, so the section owes nothing to .page-main's
     clearance for the pill; pull it back up under the bar. */
  margin-top: -4.5rem;
}
.about-hero__media { position: absolute; inset: 0; overflow: hidden; }
.about-hero__video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* Ours, not the reference's: their hero film is graded dark enough to carry
   cream type on its own. The Bullish reel opens on bright turquoise water,
   and exclusion against a saturated backdrop returns its complement — cream
   type came out salmon. Pushing the scrim toward black both restores the
   headline's colour (exclusion against black is the identity) and keeps it
   legible; the reel still reads clearly underneath. */
.about-hero__scrim {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to top, rgb(0 0 0 / 0.75), rgb(0 0 0 / 0.45) 60%),
    rgb(0 0 0 / 0.62);
}
.about-hero__content {
  position: relative;
  width: 100%;
  mix-blend-mode: exclusion;
}

.about-intro { padding-top: var(--section-2xl); padding-bottom: var(--section-lg); }
.about-intro__pills {
  display: flex;
  flex-wrap: wrap;
  gap: 0.125rem;
  margin-bottom: var(--section-2xs);
}
.about-intro__lede { max-width: 52rem; }
@media (min-width: 1000px) {
  .about-intro { padding-top: var(--section-xl); }
}

/* The reference stacks three photos on top of one another — a tall lead plate
   with two much smaller flanking ones overlapping its edges. Theirs are WebGL
   planes; these are plain <img>s in the same composition. */
.about-stack {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  margin-top: var(--section-md);
}
.about-stack img { width: 100%; height: 100%; object-fit: cover; border-radius: 2px; }
.about-stack__item--lead {
  position: relative;
  z-index: 1;
  width: min(60vw, 26rem);
  aspect-ratio: 2 / 3;
}
.about-stack__item--flank {
  width: min(22vw, 11.25rem);
  aspect-ratio: 180 / 272;
}
/* Overlap the flanks under the lead plate, as the reference's absolutely
   positioned stack does, and stagger them vertically — level flanks read as a
   three-up row rather than as a stack. */
.about-stack__item--flank:first-child  { margin-right: -3vw; transform: translateY(-22%); }
.about-stack__item--flank:last-child   { margin-left: -3vw;  transform: translateY(26%); }

.values { padding-top: var(--section-lg); padding-bottom: var(--section-3xs); }
/* The value cards are the process section's stacking cards — all geometry
   lives with .process-stack above; only the gap under the tag is ours. */
.values__stack { margin-top: var(--section-sm); }

.team { padding-top: var(--section-lg); }
.team__intro { max-width: 44rem; margin-top: 2rem; opacity: 0.75; }
.team__list { display: flex; flex-direction: column; gap: 3rem; margin-top: var(--section-sm); }
@media (min-width: 1000px) {
  .team__list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.5rem; }
}
.team__member img {
  width: 100%;
  height: auto;
  aspect-ratio: 0.8246;   /* the contact-page frame ratio */
  object-fit: cover;
  border-radius: 4px;
}
.team__member-name { margin-top: 1.25rem; }
.team__member-role { opacity: 0.6; margin-top: 0.25rem; }
.team__member-links { display: flex; flex-direction: column; gap: 0.15rem; margin-top: 0.75rem; }
.team__member-links a { opacity: 0.75; text-decoration: none; }
.team__member-links a:hover { opacity: 1; text-decoration: underline; }

/* Height-normalised horizontal strip. The reference runs seven images through
   a draggable WebGL slider; native overflow scrolling with snap points gets
   the same reading at none of the cost, and keeps it usable with a trackpad,
   a touch screen and the keyboard alike. */
.gallery-strip { padding-top: var(--section-3xl); padding-bottom: var(--section-2xl); }
.gallery-strip__scroller {
  display: flex;
  gap: 0.625rem;
  margin-top: var(--section-sm);
  padding: 0 var(--ll-grid-margin);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.gallery-strip__scroller::-webkit-scrollbar { display: none; }
.gallery-strip__item {
  flex: 0 0 auto;
  height: 15rem;
  margin: 0;
  scroll-snap-align: start;
}
@media (min-width: 1000px) {
  .gallery-strip__scroller { gap: 1.5rem; }
  .gallery-strip__item { height: 21.875rem; }   /* the ~350px reference row */
}
/* Width follows the image's own ratio, which is what makes the row read as a
   strip of varied plates rather than a filmstrip of identical boxes. */
.gallery-strip__item img {
  width: auto;
  height: 100%;
  max-width: none;
  object-fit: cover;
  border-radius: 4px;
}

/* ---------------------------------------------------------------- footer */

.site-footer {
  padding: var(--section-md) 0 var(--section-sm);
  border-top: 1px solid var(--rule);
}
.site-footer__inner { display: flex; flex-wrap: wrap; gap: 2rem; justify-content: space-between; }
.site-footer a { text-decoration: none; opacity: 0.75; }
.site-footer a:hover { opacity: 1; }

/* Shared CTA block above the three-column strip. Reference footer: a display
   invitation on the left at lg:w-5/12, and a label + paragraph + two buttons
   on the right at lg:w-4/12, dropped 100px so it sits against the headline's
   second line rather than its cap height. */
.footer-cta {
  display: flex;
  flex-direction: column;
  gap: 2.5rem;
  padding-bottom: var(--section-md);
}
@media (min-width: 1000px) {
  .footer-cta {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    column-gap: 1.5rem;
  }
  .footer-cta__heading { grid-column: 1 / span 6; }
  .footer-cta__body    { grid-column: 8 / span 4; padding-top: 6.25rem; }
}
.footer-cta__heading br { display: none; }
@media (min-width: 1000px) { .footer-cta__heading br { display: inline; } }
.footer-cta__body p { margin: 1rem 0 0; opacity: 0.75; }
.footer-cta__buttons { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 2rem; }
.footer-cta__button {
  display: inline-flex;
  align-items: center;
  width: max-content;
  padding: 0.85em 1.4em;
  border-radius: 2rem;
  background: var(--textPrimary);
  color: var(--bgPrimary);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  opacity: 1;
  transition: opacity .35s var(--power4-out);
}
/* Second button is the quieter of the two — outlined rather than filled. */
.footer-cta__button:nth-child(2) {
  background: none;
  color: inherit;
  border: 1px solid currentColor;
}
.site-footer .footer-cta__button:hover { opacity: 0.75; }
