/** Shopify CDN: Minification failed

Line 1655:53 Unexpected "*"

**/
/* SHOPIFY_STYLESHEETS_VERSION: 1.0 */


/* CSS from section stylesheet tags */
/* START_SECTION:complete-the-look (INDEX:0) */
.complete-the-look {
  border-top: 1px solid var(--color-border);
}

.complete-the-look__heading {
  /* Typography refinement (round 2): the previous pass made this too
     small/weak — now noticeably larger and bold for real section-
     heading presence, while staying well under the product title's
     max size so it never competes with the page's actual H1. Tracking
     (already an established brand value, matching
     kelain-culture-editorial__cta-link) and position/layout unchanged. */
  font-size: clamp(16px, 2vw, 20px);
  font-weight: var(--weight-bold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin-bottom: 32px;
}

.complete-the-look__card {
  display: block;
  max-width: 320px;
}

/* Bold identity refinement: the per-card overrides that used to live
   here are no longer needed — the shared .product-card__title rule is
   now bold and .product-card__price is now regular storefront-wide, so
   this card's product name and price already come out bold/regular
   without any duplicate rule. No image/card-structure/layout change. */
/* END_SECTION:complete-the-look */

/* START_SECTION:kelain-culture-editorial (INDEX:4) */
.kelain-culture-editorial__sequence {
  display: flex;
  flex-direction: column;
  gap: 56px;
}

.kelain-culture-editorial__item {
  position: relative;
  overflow: hidden;
  background: var(--color-border);
}

.kelain-culture-editorial__image,
.kelain-culture-editorial__placeholder {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.kelain-culture-editorial__placeholder {
  background: var(--color-border);
}

.kelain-culture-editorial__pair {
  display: flex;
  flex-direction: column;
  gap: 24px;
}

.kelain-culture-editorial__item--1 { aspect-ratio: 3 / 4; }
.kelain-culture-editorial__item--2 { aspect-ratio: 4 / 5; }
.kelain-culture-editorial__item--3 { aspect-ratio: 4 / 3; }
.kelain-culture-editorial__item--4 { aspect-ratio: 3 / 4; }

@media (min-width: 750px) {
  .kelain-culture-editorial__sequence {
    gap: 96px;
  }

  .kelain-culture-editorial__pair {
    flex-direction: row;
    align-items: flex-start;
    gap: 5%;
  }

  .kelain-culture-editorial__pair .kelain-culture-editorial__item--1 {
    width: 58%;
  }

  .kelain-culture-editorial__pair .kelain-culture-editorial__item--2 {
    width: 33%;
    margin-top: 18%;
  }

  .kelain-culture-editorial__item--3 {
    aspect-ratio: 21 / 9;
  }

  .kelain-culture-editorial__offset {
    display: flex;
    justify-content: flex-end;
  }

  .kelain-culture-editorial__offset .kelain-culture-editorial__item--4 {
    width: 46%;
  }
}
/* END_SECTION:kelain-culture-editorial */

/* START_SECTION:kelain-culture-hero (INDEX:5) */
.kelain-culture-hero {
  position: relative;
  display: flex;
  width: 100%;
  overflow: hidden;
  background: var(--color-border);
  min-height: 80svh;
}

@media (min-width: 750px) {
  .kelain-culture-hero {
    /* Compact editorial refinement: reduced from 88svh so the hero reads
       as a strong opening visual rather than a near-full-screen block —
       media behavior/proportions (object-fit: cover, overlay, video)
       are unchanged, only the section's height. */
    min-height: calc(68svh - var(--header-height, 0px));
  }
}

.kelain-culture-hero__media {
  position: absolute;
  inset: 0;
}

.kelain-culture-hero__image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.kelain-culture-hero__placeholder {
  position: absolute;
  inset: 0;
  background: var(--color-border);
}

.kelain-culture-hero__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 0.4s ease;
}

.kelain-culture-hero__video[data-kelain-hero-ready] {
  opacity: 1;
}

.kelain-culture-hero__overlay {
  position: absolute;
  inset: 0;
  background: #000;
  opacity: var(--kelain-culture-hero-overlay, 0.2);
}

@media (prefers-reduced-motion: reduce) {
  .kelain-culture-hero__video {
    display: none;
  }
}
/* END_SECTION:kelain-culture-hero */

/* START_SECTION:kelain-culture-inside (INDEX:6) */
.kelain-culture-inside__heading {
  margin-bottom: 8px;
  /* Tighter tracking than the shared .page-section__heading default
     (0.03em), scoped to this section only so the Collection and Cart
     page headings — which also use .page-section__heading — are
     unaffected. Brings this heading's tracking closer to the header
     nav / footer heading system. Weight (700, inherited) and font-size
     (inherited from .page-section__heading) are untouched. */
  letter-spacing: 0.01em;
}

.kelain-culture-inside__intro {
  margin: 0 0 32px;
  max-width: 44ch;
  font-size: clamp(13px, 1.2vw, 15px);
  font-weight: var(--weight-regular);
  line-height: 1.7;
  color: var(--color-text);
  opacity: 0.75;
}

.kelain-culture-inside__row {
  /* Mobile: one vertical card per row (a simple stack), not the
     horizontal-scroll layout used previously — no overflow/scroll-snap
     needed since there's nothing to scroll past. */
  display: flex;
  flex-direction: column;
  gap: 16px;
  margin-top: 20px;
}

.kelain-culture-inside__card {
  width: 100%;
}

.kelain-culture-inside__media {
  position: relative;
  overflow: hidden;
  aspect-ratio: 4 / 5;
  background: var(--color-border);
}

.kelain-culture-inside__video,
.kelain-culture-inside__placeholder,
.kelain-culture-inside__image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.kelain-culture-inside__placeholder {
  background: var(--color-border);
}

@media screen and (max-width: 749px) {
  .kelain-culture-inside__row {
    /* Slightly tighter than the shared 16px gap above -- desktop's own
       gap (set separately below, in the 750px+ media query) is
       untouched. */
    gap: 12px;
  }

  .kelain-culture-inside__media {
    /* Mobile only: the shared 4:5 aspect-ratio above (and the previous
       mobile-only 4:4.2 override) forced every card into one fixed box
       shape. Combined with object-fit: cover on the video/image below,
       that crops any asset whose real proportions don't match the box,
       cutting off part of the original frame. Removing the fixed ratio
       here lets the box's height come from the video/image itself
       (switched to normal in-flow sizing just below), so each of the
       three assets shows its own true aspect ratio, complete and
       uncropped. Desktop is untouched -- it still uses the 4:5
       aspect-ratio + object-fit: cover rule above. */
    aspect-ratio: auto;
  }

  .kelain-culture-inside__video,
  .kelain-culture-inside__image {
    /* Turn off the absolute-fill-and-crop pattern for mobile only: back
       to normal document flow, full card width, auto height -- each
       item renders at its own native aspect ratio with nothing cut off.
       object-fit: contain is kept as a safety net (harmless once
       height is auto) rather than as the active mechanism. The
       placeholder layer (video cards only) is left absolute/inset: 0
       above -- it still fills the card correctly because the card's
       height is now set by this in-flow video/image. */
    position: static;
    display: block;
    width: 100%;
    height: auto;
    object-fit: contain;
  }
}

.kelain-culture-inside__video {
  opacity: 0;
  transition: opacity 0.4s ease;
}

.kelain-culture-inside__video[data-kelain-culture-inside-ready] {
  opacity: 1;
}

.kelain-culture-inside__play {
  /* Minimal, subtle control: a bare icon centered over the video, no
     button background/shape of its own — appropriate for an editorial
     fashion page rather than a typical media-player look. The drop
     shadow (not a background) is only there so the white icon stays
     legible over bright footage. */
  position: absolute;
  inset: 0;
  margin: auto;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  background: none;
  color: #fff;
  cursor: pointer;
  opacity: 1;
  transition: opacity 0.2s ease;
}

.kelain-culture-inside__play svg {
  width: 100%;
  height: 100%;
  fill: currentColor;
  filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.4));
}

.kelain-culture-inside__card[data-kelain-culture-inside-playing] .kelain-culture-inside__play {
  /* Hidden while playing, per spec — kept in the DOM (not display:
     none) so it stays reachable/operable via keyboard, which also
     doubles as a keyboard pause control since the click handler below
     toggles playback either way. */
  opacity: 0;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .kelain-culture-inside__video {
    display: none;
  }

  .kelain-culture-inside__play {
    display: none;
  }
}

/* Compact editorial refinement: vertical padding reduced from the
   shared .page-section defaults (48px/20px mobile, 80px/40px desktop)
   via a compound selector, matching the same pattern used on the
   manifesto and social sections — .page-section still supplies the
   horizontal padding and every other page's padding is untouched. */
.page-section.kelain-culture-inside {
  padding-top: 28px;
  padding-bottom: 28px;
}

@media screen and (min-width: 990px) {
  .page-section.kelain-culture-inside {
    padding-top: 40px;
    padding-bottom: 40px;
  }
}

@media (min-width: 750px) {
  .kelain-culture-inside__row {
    /* Desktop: CSS Grid with exactly 3 fixed columns — every card gets
       the same column width, and since each card's height is driven
       entirely by aspect-ratio (4:5) on .kelain-culture-inside__media,
       equal width also guarantees equal height for all three, video
       or image alike. */
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 20px;
    margin-top: 32px;
  }

  .kelain-culture-inside__card {
    width: auto;
  }

  /* Explicit column placement (not auto-placement) so the fixed
     Image 1 / Video / Image 2 order is preserved even when a slot is
     left unset — e.g. Image 1 + Image 2 with no video still sit in
     columns 1 and 3, leaving column 2 visibly empty, rather than
     sliding together into columns 1 and 2. */
  .kelain-culture-inside__card--image-1 {
    grid-column: 1;
  }

  .kelain-culture-inside__card--video {
    grid-column: 2;
  }

  .kelain-culture-inside__card--image-2 {
    grid-column: 3;
  }
}
/* END_SECTION:kelain-culture-inside */

/* START_SECTION:kelain-culture-manifesto (INDEX:7) */
.page-section.kelain-culture-manifesto {
  /* Black background / white typography everywhere, mobile included --
     reuses the theme's existing inverse color tokens (already used by
     the header) instead of introducing new hardcoded colors. */
  background: var(--color-inverse-background);
  color: var(--color-inverse-text);
  padding-top: 40px;
  padding-bottom: 40px;
}

.kelain-culture-manifesto__inner {
  display: flex;
  flex-direction: column;
  gap: 28px;
}

.kelain-culture-manifesto__top {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  text-align: left;
  gap: 14px;
}

.kelain-culture-manifesto__heading {
  margin: 0;
  font-family: var(--font-heading-family);
  font-style: var(--font-heading-style);
  /* The strongest text on the page -- bold, uppercase, largest beat in
     the composition, but capped well short of "oversized poster type"
     so it still sits naturally with the manifesto/quote beneath it. */
  font-weight: var(--weight-bold);
  font-size: clamp(30px, 9vw, 40px);
  line-height: 0.98;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--color-inverse-text);
}

.kelain-culture-manifesto__text {
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: 100%;
}

.kelain-culture-manifesto__p {
  margin: 0;
  max-width: 480px;
  font-size: 14px;
  line-height: 1.55;
  font-weight: var(--weight-semibold);
  color: var(--color-inverse-text);
}

.kelain-culture-manifesto__quote {
  margin: 0;
  max-width: 460px;
}

.kelain-culture-manifesto__quote p {
  /* Visually stronger than the manifesto copy (larger size) but a
     different, non-uppercase treatment so it never competes with the
     all-caps headline above it. */
  margin: 0;
  font-family: var(--font-heading-family);
  font-style: var(--font-heading-style);
  font-weight: var(--weight-semibold);
  font-size: clamp(20px, 5.5vw, 26px);
  line-height: 1.28;
  color: var(--color-inverse-text);
}

.kelain-culture-manifesto__origin {
  margin: 0;
  font-family: var(--font-heading-family);
  font-weight: var(--weight-semibold);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-inverse-text);
  opacity: 0.7;
}

.kelain-culture-manifesto__statement {
  /* A second, smaller editorial tier: more emphasis than the plain
     .kelain-culture-manifesto__p body copy (larger size), but clearly
     secondary to the large .kelain-culture-manifesto__quote turning
     point above it -- same family/color, not bold, not uppercase, so
     it never competes with either the headline or the large quote. */
  margin: 0;
  max-width: 460px;
  font-family: var(--font-heading-family);
  font-style: var(--font-heading-style);
  font-weight: var(--weight-semibold);
  font-size: 16px;
  line-height: 1.4;
  color: var(--color-inverse-text);
}

.kelain-culture-manifesto__media-group {
  /* Mobile/tablet: gap: 0 -- explicit, different per-item margins
     below express "small gap from a label to its own media, larger
     editorial gap before the next chapter" (one uniform gap value
     can't express both). Desktop below overrides this with its own
     grid gap. */
  display: flex;
  flex-direction: column;
  gap: 0;
  width: 100%;
}

.kelain-culture-manifesto__media {
  /* Mobile/tablet: a normal block, deliberate portrait crop (4:5) --
     changed from the previous true 1:1 square, which existed only to
     visually match the now-removed sketch image; with no sketch left
     to match, the finished product panel goes back to a portrait
     presentation instead. No border, border-radius, card background,
     or overlay of any kind -- the image itself is the only content
     (its optional label renders as its own block above this one, see
     .kelain-culture-manifesto__media-label below). margin-bottom: 0
     because this is always the last media item -- the gap to FOLLOW
     THE CULTURE comes from .kelain-culture-manifesto__inner's own
     top-level gap instead. */
  position: relative;
  overflow: hidden;
  width: 100%;
  aspect-ratio: 4 / 5;
  background: rgba(255, 255, 255, 0.08);
  margin-bottom: 0;
}

.kelain-culture-manifesto__image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.kelain-culture-manifesto__media-label {
  /* Small, minimal editorial annotation shown above its media item --
     not a heading, no supporting line, no box/background/border (the
     former Media 2 caption's heading+text split is gone along with
     the sketch it annotated; these labels are a single short line
     each). Renders nothing at all when its own setting
     (media_1_label / media_2_label) is left blank -- see the
     markup's conditionals. On mobile this is a plain block in normal
     document flow (margin-bottom is the "belongs to this media" gap);
     desktop places it in its own dedicated grid row instead, see
     .kelain-culture-manifesto__media-group below. */
  margin: 0 0 10px;
  font-family: var(--font-heading-family);
  font-style: var(--font-heading-style);
  font-weight: var(--weight-semibold);
  font-size: 11px;
  line-height: 1.3;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-inverse-text);
  opacity: 0.85;
}

.kelain-culture-manifesto__mini-video {
  /* Mobile/tablet: a normal block, full content width -- both media
     items (this BTS video and the finished-product panel) share the
     same left/right content boundaries, per the brief. aspect-ratio
     stays 3 / 4 (unchanged, still portrait, never cropped into a
     square) -- only the width behavior changes. Desktop overrides
     size/position below. Background matches the page's own black
     (not a lighter placeholder tint) because object-fit: contain
     below can leave letterboxed space inside this box, and that
     space needs to visually disappear into the Culture section
     rather than show as a visible panel. margin-bottom is the
     editorial gap to the next label/chapter -- zeroed below when
     this is the finished-product panel (always the last item, see
     the slot='3' override immediately below), since the gap to
     FOLLOW THE CULTURE then comes from
     .kelain-culture-manifesto__inner's own top-level gap instead. */
  position: relative;
  overflow: hidden;
  width: 100%;
  aspect-ratio: 3 / 4;
  background: var(--color-inverse-background);
  margin-bottom: 20px;
}

.kelain-culture-manifesto__mini-video[data-kelain-media-slot='3'] {
  margin-bottom: 0;
}

.kelain-culture-manifesto__mini-video-poster,
.kelain-culture-manifesto__mini-video-el {
  /* object-fit: contain (not cover) -- the wrapper's box aspect ratio
     is driven by the merchant's Video width setting plus the shared
     desktop media height, which has nothing to do with the source
     video's own aspect ratio; cover was cropping whatever didn't fit
     that arbitrary box. contain shows the complete frame instead and
     letterboxes into the wrapper's own (now black) background.
     object-position is left at its default (centered), so the
     visible video frame is centered in the box either way -- which
     is what keeps the centered Play/Pause button below correctly
     centered on the actual video, not just on the wrapper. Mobile-
     only override just below switches this to cover -- see that
     rule's own comment for why. */
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

@media screen and (max-width: 989px) {
  /* Mobile-only fix: the BTS video's OUTER box (.mini-video) is
     already width: 100% -- exactly like .media (the finished product
     image's box) -- so both media containers already share the same
     mobile width and left/right alignment; nothing about their outer
     box, margins or padding differs. The video only LOOKED narrower
     and inset because object-fit: contain (the base rule above)
     pillarboxes it inside that box whenever the source video's own
     aspect ratio is narrower than the box's fixed 3 / 4 -- the box
     itself never moved, only the visible video frame inside it did.
     cover fills the box edge-to-edge instead (the same treatment
     desktop already uses for this exact video, in the object-fit:
     cover override further down), without stretching or distorting --
     aspect-ratio: 3 / 4 on the box is unchanged, so the box (and so
     the video's own portrait presentation) stays exactly as before;
     this only removes the pillarboxing, it does not change the box's
     size, position, or ratio. */
  .kelain-culture-manifesto__mini-video-poster,
  .kelain-culture-manifesto__mini-video-el {
    object-fit: cover;
  }
}

.kelain-culture-manifesto__mini-video-toggle {
  /* Small circular overlay, dead-centered on the video -- the only
     interactive control on it; no native browser controls are used
     (controls attribute is never added to the <video>). Soft,
     translucent background rather than a solid white chip so it
     reads as a quiet, premium affordance instead of a UI widget. */
  position: absolute;
  z-index: 1;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.4);
  backdrop-filter: blur(2px);
  color: #000;
  cursor: pointer;
}

.kelain-culture-manifesto__mini-video-toggle:focus-visible {
  /* White outline (not the default --color-text) -- this section's
     background is black, so a dark outline would be invisible. */
  outline: 2px solid var(--color-inverse-text);
  outline-offset: 2px;
}

.kelain-culture-manifesto__mini-video-icon {
  width: 11px;
  height: 11px;
}

.kelain-culture-manifesto__mini-video-icon--pause {
  /* Hidden by default -- the video starts paused (no autoplay), so
     the icon shown is the action a click will perform next (play),
     matching the wrapper's default
     data-kelain-culture-manifesto-mini-video-playing="false" in the
     markup. The script keeps both the icon and the wrapper's playing
     attribute in sync with the video's real state. */
  display: none;
}

[data-kelain-culture-manifesto-mini-video-playing="true"] .kelain-culture-manifesto__mini-video-icon--play {
  display: none;
}

[data-kelain-culture-manifesto-mini-video-playing="true"] .kelain-culture-manifesto__mini-video-icon--pause {
  display: block;
}

/* ------------------------------------------------------------
   Entrance animation -- subtle, premium reveal on page load, CSS
   only (no JS). Sequence: heading first, then the manifesto copy
   (opening paragraphs get a very small per-paragraph stagger, then
   the quote, the follow-up copy, and the secondary statement), the
   right-side media group (a bottom-to-top clip-path reveal with a
   slight scale(1.025) -> scale(1)), and finally the origin line and
   social block together, last. Total sequence lands at ~1.5s
   (durations/delays scaled up ~25% from an earlier ~1.2s pass for a
   slightly slower, more cinematic feel -- same style/movement/scale/
   direction/easing throughout, only the timing changed).
   Every rule only ever changes opacity/transform/clip-path -- never
   a layout-affecting property -- so none of this can shift layout,
   and existing classes are reused for targeting (via :nth-of-type /
   :nth-child on the already-repeated .text/.p elements) rather than
   adding new markup. Fully disabled, with content shown immediately,
   under prefers-reduced-motion: reduce below. */

@keyframes kelain-culture-reveal-up {
  from {
    opacity: 0;
    transform: translateY(16px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes kelain-culture-media-reveal {
  from {
    clip-path: inset(100% 0 0 0);
    transform: scale(1.025);
  }
  to {
    clip-path: inset(0 0 0 0);
    transform: scale(1);
  }
}

.kelain-culture-manifesto__heading {
  animation: kelain-culture-reveal-up 0.88s cubic-bezier(0.16, 1, 0.3, 1) both;
}

.kelain-culture-manifesto__text:nth-of-type(1) .kelain-culture-manifesto__p {
  animation: kelain-culture-reveal-up 0.81s cubic-bezier(0.16, 1, 0.3, 1) both;
  animation-delay: 0.19s;
}

/* Very small stagger between the opening manifesto's own paragraphs. */
.kelain-culture-manifesto__text:nth-of-type(1) .kelain-culture-manifesto__p:nth-child(2) {
  animation-delay: 0.25s;
}

.kelain-culture-manifesto__text:nth-of-type(1) .kelain-culture-manifesto__p:nth-child(3) {
  animation-delay: 0.31s;
}

.kelain-culture-manifesto__text:nth-of-type(1) .kelain-culture-manifesto__p:nth-child(n + 4) {
  animation-delay: 0.38s;
}

.kelain-culture-manifesto__quote {
  animation: kelain-culture-reveal-up 0.81s cubic-bezier(0.16, 1, 0.3, 1) both;
  animation-delay: 0.38s;
}

.kelain-culture-manifesto__text:nth-of-type(2) .kelain-culture-manifesto__p {
  animation: kelain-culture-reveal-up 0.81s cubic-bezier(0.16, 1, 0.3, 1) both;
  animation-delay: 0.45s;
}

.kelain-culture-manifesto__statement {
  animation: kelain-culture-reveal-up 0.81s cubic-bezier(0.16, 1, 0.3, 1) both;
  animation-delay: 0.53s;
}

.kelain-culture-manifesto__media {
  animation: kelain-culture-media-reveal 1.13s cubic-bezier(0.16, 1, 0.3, 1) both;
  animation-delay: 0.25s;
}

.kelain-culture-manifesto__mini-video {
  animation: kelain-culture-media-reveal 1.13s cubic-bezier(0.16, 1, 0.3, 1) both;
  animation-delay: 0.35s;
}

/* Media 3 reuses the .kelain-culture-manifesto__media /
   .kelain-culture-manifesto__mini-video classes above (same reveal
   language, same duration/easing -- nothing new introduced), with
   only its delay nudged slightly later for a very subtle stagger
   after Media 1/2, continuing their existing 0.10s step. The
   class+attribute selector outranks the single-class rules above
   regardless of source order, and only ever matches the Media 3
   element (data-kelain-media-slot="3"). */
.kelain-culture-manifesto__media[data-kelain-media-slot='3'],
.kelain-culture-manifesto__mini-video[data-kelain-media-slot='3'] {
  animation-delay: 0.45s;
}

/* Labels reveal naturally alongside their own media -- reusing the
   existing text reveal keyframe (kelain-culture-reveal-up) rather
   than introducing a new animation, with delays set just ahead of
   each label's own media (0.35s/0.45s above) for a natural "label,
   then media" reveal order. */
.kelain-culture-manifesto__media-label {
  animation: kelain-culture-reveal-up 0.75s cubic-bezier(0.16, 1, 0.3, 1) both;
}

.kelain-culture-manifesto__media-label--video {
  animation-delay: 0.3s;
}

.kelain-culture-manifesto__media-label--product {
  animation-delay: 0.4s;
}

.kelain-culture-manifesto__origin {
  animation: kelain-culture-reveal-up 0.75s cubic-bezier(0.16, 1, 0.3, 1) both;
  animation-delay: 0.68s;
}

.kelain-culture-manifesto__social {
  animation: kelain-culture-reveal-up 0.75s cubic-bezier(0.16, 1, 0.3, 1) both;
  animation-delay: 0.75s;
}

@media (prefers-reduced-motion: reduce) {
  .kelain-culture-manifesto__mini-video-el,
  .kelain-culture-manifesto__mini-video-toggle {
    /* The static poster underneath is left visible as the fallback;
       nothing is downloaded differently, but it stops playing/moving,
       and the now-pointless Play/Pause control is hidden with it
       (the scoped script above also returns early in this case). */
    display: none;
  }

  /* Entrance animation off entirely -- all content shown immediately
     in its final state, no delay, no motion. */
  .kelain-culture-manifesto__heading,
  .kelain-culture-manifesto__text .kelain-culture-manifesto__p,
  .kelain-culture-manifesto__quote,
  .kelain-culture-manifesto__statement,
  .kelain-culture-manifesto__media,
  .kelain-culture-manifesto__mini-video,
  .kelain-culture-manifesto__media-label,
  .kelain-culture-manifesto__origin,
  .kelain-culture-manifesto__social {
    animation: none;
    opacity: 1;
    transform: none;
    clip-path: none;
  }
}

.kelain-culture-manifesto__social {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.kelain-culture-manifesto__social-heading {
  /* Slightly prominent/bold, per the brief -- the social info beneath
     it stays secondary (handle/link rules below keep their reduced
     opacity treatment). */
  font-family: var(--font-heading-family);
  font-style: var(--font-heading-style);
  font-weight: var(--weight-bold);
  font-size: 13px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-inverse-text);
}

.kelain-culture-manifesto__social-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px;
}

.kelain-culture-manifesto__social-handle {
  font-size: 12px;
  font-weight: var(--weight-regular);
  color: var(--color-inverse-text);
  opacity: 0.6;
}

.kelain-culture-manifesto__social-link {
  font-family: var(--font-heading-family);
  font-weight: var(--weight-semibold);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-inverse-text);
  text-decoration: none;
  opacity: 0.85;
}

.kelain-culture-manifesto__social-link::after {
  content: ' \2197';
}

.kelain-culture-manifesto__social-link:hover,
.kelain-culture-manifesto__social-link:focus-visible {
  opacity: 1;
  text-decoration: underline;
  text-underline-offset: 3px;
}

@media screen and (max-width: 749px) {
  .kelain-culture-manifesto__social-link::after {
    /* Same NE arrow character, plus the U+FE0E "text presentation"
       variation selector -- forces a plain monochrome glyph instead of
       some mobile browsers substituting a colorful emoji-style arrow. */
    content: ' \2197\FE0E';
  }
}

@media screen and (min-width: 750px) {
  .kelain-culture-manifesto__p {
    font-size: 15px;
    line-height: 1.6;
  }

  .kelain-culture-manifesto__quote p {
    font-size: clamp(24px, 4vw, 30px);
  }

  .kelain-culture-manifesto__statement {
    font-size: 17px;
  }
}

@media screen and (min-width: 990px) {
  .page-section.kelain-culture-manifesto {
    /* vh-aware padding so it shrinks on a shorter laptop screen
       instead of eating into the one-viewport budget below --
       tightened slightly from the previous revision to make room for
       the two added manifesto copy blocks (manifesto_followup,
       secondary_statement) without touching type sizes. padding-top
       was raised once (clamp(24px, 4vh, 48px) -> clamp(28px, 8vh,
       90px)) alongside .top/.media-group's align-self change below
       (center -> start), then nudged down again here (-> clamp(20px,
       5.8vh, 65px)) to bring the whole manifesto + media composition
       a further ~20-30px closer to the header on large desktop, per
       the "too much unused space around the composition" feedback --
       the header itself is untouched either way, this is only ever
       the gap below it. 5.8vh ~= 52px at 900px tall, ~63px at 1080px
       tall, still shrinking further on a shorter viewport; the
       dedicated (max-height: 820px) pass below keeps its own smaller
       fixed 18px for short laptops, unaffected by this clamp. */
    padding-top: clamp(20px, 5.8vh, 65px);
    padding-bottom: clamp(20px, 3.5vh, 40px);
    /* Exactly one viewport below the header, not just a minimum --
       the actual no-scroll behavior comes from every child below
       sizing itself off vh/vw via clamp()/min(), not from this box
       alone. --header-height is already published by
       assets/header.js (used the same way by base.css's own mobile
       header-offset rule and by the other full-height hero
       sections); this file does not touch the header itself. svh
       (not vh) matches those other sections' own convention. */
    height: calc(100svh - var(--header-height, 0px));
    display: flex;
    align-items: stretch;
  }

  .kelain-culture-manifesto__inner {
    /* Two columns, both fr-based (flexible) so together they always
       sum to exactly the row's available width, however the merchant
       sets the widths below -- text/manifesto side (minmax(300px, ...)
       so it can never become unreadably narrow) and the editorial
       media group (minmax(0, ...)), sized by the text_column_width
       setting and its 100-minus complement via --text-column-fr /
       --media-group-fr (set inline on this element). Two rows within
       the text column only: row 1 is the top cluster
       (heading/manifesto/quote/origin), row 2 is the social line
       beneath it; the media group spans both rows and is vertically
       centered across their combined height -- the same
       span-and-center mechanism this file already used for the
       campaign image, just applied to the group as a whole now. */
    /* The media-sizing chain (--media-size / --panel-height /
       --panel-width) is declared HERE rather than on .media-group
       below -- same reasoning as before this pass: this element's own
       width below needs to read --panel-width too, and a descendant's
       custom properties aren't visible to its ancestor, only the
       other way round. --label-height / --label-gap are set inline on
       this element's own style attribute (both 0px when neither
       media_1_label nor media_2_label has text), the same "fixed
       pixel budget carved out of the vh-capped --media-size" approach
       the removed Media 2 caption reserve used, for the same reason:
       the one-viewport budget must stay exact regardless of label
       text length. */
    --media-size: min(var(--media-height, 650px) * 1.25, 76vh);
    --panel-height: calc(var(--media-size) - var(--label-height, 0px) - var(--label-gap, 0px));
    /* --outer-column-gap is declared here (moved up from its previous
       spot, right before --composition-width) because
       --media-group-safe-cap below needs it. Same clamp()/value as
       before this pass -- only its position in the file moved. */
    --outer-column-gap: clamp(28px, 3.2vw, 48px);
    /* Safety cap, same reverse-math idea as --composition-width
       further down: the largest --media-group-actual-width that could
       ever be fed into that formula without asking .inner to exceed
       the theme's own global page width (--page-width, the same
       settings.page_width every other section respects) is
       (page-width - outer-gap) * media-group-pct / 100 -- i.e. "the
       media column's fr-share of the widest .inner could ever
       legally be". Removing the sketch and letting both panels use
       the FULL --panel-height (rather than half of it, as when two
       squares were stacked) makes the realistic actual-width
       meaningfully larger than before, enough that at the extreme end
       of the settings range (max Desktop media height, max Media
       panel width %) this cap is the one that actually engages --
       capping --panel-width here keeps --composition-width below
       provably always resolvable within --page-width, with no
       overflow, instead of silently exceeding it. At any setting
       short of that extreme, the uncapped (height-derived) value
       inside min() below is already smaller, so this stays dormant
       and nothing about the composition's sizing changes from what
       the Media panel width / Desktop media height settings alone
       would produce. */
    --media-group-safe-cap: calc((var(--page-width, 1600px) - var(--outer-column-gap)) * var(--media-group-pct, 64) / 100);
    --panel-width: min(
      calc(var(--panel-height) * var(--panel-ratio-pct, 56) / 100),
      calc((var(--media-group-safe-cap) - var(--media-gap, 24px)) / 2)
    );
    /* The media composition's own actual rendered width (video panel
       + media-gap + product panel -- both panels always exactly
       --panel-width) -- exactly what .media-group's
       grid-template-columns below produces. Used only to size THIS
       element (see --composition-width / width below); has no effect
       on .media-group's own layout (it already computes the same
       thing implicitly via its columns). */
    --media-group-actual-width: calc(var(--panel-width) * 2 + var(--media-gap, 24px));
    /* Outer alignment fix: previously this element's width came only
       from width: 100% (capped by the global .page-section__inner's
       own max-width: var(--page-width), untouched here), which could
       be noticeably WIDER than the manifesto + media content actually
       needed -- .media-group (narrower than its own grid column, even
       after justify-self: start removed the worst of it) still left
       unused width stranded on the right of the whole composition,
       while the left edge sat flush with no matching margin, so the
       outer black space read as lopsided rather than framing the
       composition symmetrically.
       --composition-width solves this element's two fr columns in
       reverse: if the media column's fr-share of (width - gap) must
       equal --media-group-actual-width, then
       width = actual-width * 100 / media-group-pct + gap. That's the
       narrower of the two candidates passed to max() below; the wider
       one is the same equation but with the text column pinned to its
       own minmax() floor (300px) instead of its fr-share, for the
       (rare, short-viewport) case where the fr-share alone would come
       out under 300px -- without this floor candidate, the grid's own
       300px minimum would quietly steal a few px from the media
       column and reintroduce a small overflow. Either way, the result
       is a container sized to exactly what the text and media columns
       actually need, no more -- the SAME column proportions
       (text_column_width / media_group_width) and the SAME
       media-group size as always, just with no leftover slack baked
       into the container around them. */
    --composition-width: max(
      300px + var(--outer-column-gap) + var(--media-group-actual-width),
      var(--media-group-actual-width) * 100 / var(--media-group-pct, 64) + var(--outer-column-gap)
    );
    display: grid;
    grid-template-columns: minmax(300px, var(--text-column-fr, 36fr)) minmax(0, var(--media-group-fr, 64fr));
    grid-template-rows: 1fr auto;
    column-gap: var(--outer-column-gap);
    row-gap: 0;
    /* min() means this only ever shrinks .inner below the space
       .page-section actually offers (100%) -- at 1366px/1440px-class
       desktop widths --composition-width is typically still wider
       than (or close to) 100% is there, so 100% keeps winning and
       nothing changes from before this pass; margin-inline: auto then
       centers whichever value wins, so on a narrower desktop this
       safely falls back to the previous flush/full-width behavior
       instead of forcing a tight fit that wouldn't have room. */
    width: min(100%, var(--composition-width));
    margin-inline: auto;
    height: 100%;
  }

  .kelain-culture-manifesto__top {
    grid-column: 1;
    grid-row: 1;
    /* start, not center: row 1 is 1fr (all leftover height after row
       2/.social's auto height), and on a tall/wide viewport its
       natural content is much shorter than that, so centering left a
       large empty gap between the header and the first visible line.
       start anchors the content to the top of row 1 (right after the
       section's own padding-top), while the slack it used to be
       centered in now falls below it instead, directly above row 2 --
       .social (row 2) is a separate grid row sized by its own content
       and always sits right after row 1 ends, so it keeps its
       position near the bottom of .inner either way. */
    align-self: start;
    /* Tightened from clamp(14px, 2.2vh, 26px) -- the column now holds
       six copy blocks (heading, manifesto_short, quote,
       manifesto_followup, secondary_statement, origin_line) instead
       of four, so the per-gap value comes down to keep roughly the
       same total gap budget. Heading/quote/statement font sizes are
       unchanged; this is spacing only. */
    gap: clamp(10px, 1.6vh, 18px);
  }

  .kelain-culture-manifesto__heading {
    /* min(vw, vh) so the headline shrinks with EITHER a narrower or a
       shorter viewport, whichever is more constrained -- the vh half
       is what actually protects the one-screen budget on a short
       laptop display. */
    font-size: clamp(30px, min(4.4vw, 7vh), 54px);
    line-height: 0.95;
  }

  .kelain-culture-manifesto__text {
    gap: clamp(6px, 1vh, 10px);
  }

  .kelain-culture-manifesto__p {
    font-size: clamp(14px, 1.3vw, 15px);
    line-height: 1.5;
  }

  .kelain-culture-manifesto__quote p {
    font-size: clamp(22px, min(3vw, 5vh), 36px);
    line-height: 1.22;
  }

  .kelain-culture-manifesto__statement {
    font-size: clamp(16px, min(1.6vw, 2.6vh), 19px);
    line-height: 1.35;
  }

  .kelain-culture-manifesto__social {
    grid-column: 1;
    grid-row: 2;
    /* Tightened from clamp(16px, 2.4vh, 32px) alongside .top's own
       gap, for the same reason (more copy blocks above it now). */
    margin-top: clamp(12px, 1.8vh, 24px);
  }

  .kelain-culture-manifesto__media-group {
    /* Two equal-width, equal-height portrait panels side by side --
       BTS video (column 1) and finished product (column 2) -- a true
       editorial diptych now that the sketch (the former Media 2) has
       been removed; previously this was a video column beside two
       stacked squares. Column widths are explicit lengths derived
       entirely from this element's own height (--panel-width, calc'd
       from --media-height via .kelain-culture-manifesto__inner above),
       so the composition's pixel size depends only on --media-height,
       never on how much row width happens to be available --
       identical at 1366px, 1440px and 1920px provided the viewport
       height is the same; width: 100% is never set (so there's
       nothing to stretch), and max-width below is an explicit
       responsive cap for unusual setting combinations. */
    /* justify-self: start keeps the composition as close to the
       manifesto as .inner's own column-gap allows, with any remaining
       unused width consolidated on the right as intentional framing --
       unchanged from the previous revision. .inner above sizes itself
       around whatever this group's actual width turns out to be (see
       --media-group-actual-width / --composition-width on .inner), so
       removing the sketch and growing these two panels larger
       automatically uses the space it freed up, rather than leaving
       it empty, while the complete manifesto + media composition
       stays horizontally balanced/centered exactly as before. */
    /* grid-template-rows is 3 explicit rows -- [label] [label-gap]
       [panel] -- replacing the previous 5-row stacked-squares
       structure; row-gap is 0 because the label-to-panel gap is its
       own explicit row rather than the grid's uniform row-gap (which
       could not give a different value to "label to its own panel"
       vs. some other relationship). --label-height / --label-gap
       (declared on .kelain-culture-manifesto__inner, both 0px when
       neither media_1_label nor media_2_label has text) are shared by
       both columns, so when either label has text both panels still
       start at the same row and stay exactly the same height -- top/
       bottom aligned by construction, not by coincidence. */
    /* --media-size / --panel-height / --panel-width are declared on
       .kelain-culture-manifesto__inner (this element's parent) rather
       than here, and simply inherited -- .inner's own width needs to
       read --panel-width too (to size the outer wrapper to the
       composition's actual width), and a custom property set on a
       descendant isn't visible to its ancestor, only the other way
       round. See .kelain-culture-manifesto__inner's own comment for
       the full formulas. */
    grid-column: 2;
    grid-row: 1 / span 2;
    align-self: start;
    justify-self: start;
    display: grid;
    grid-template-columns: var(--panel-width) var(--panel-width);
    grid-template-rows: var(--label-height, 0px) var(--label-gap, 0px) var(--panel-height);
    column-gap: var(--media-gap, 24px);
    row-gap: 0;
    max-width: clamp(620px, 57vw, 1080px);
    height: var(--media-size);
  }

  .kelain-culture-manifesto__media {
    /* The finished-product panel (column 2, row 3 -- row 3 is the
       shared panel row; rows 1-2 are the optional label area above
       both columns, see .kelain-culture-manifesto__media-group and
       .kelain-culture-manifesto__media-label). Kept on the
       data-kelain-media-slot="3" attribute from the previous revision
       purely so the existing animation-stagger selector further below
       (.media[slot='3'], .mini-video[slot='3']) keeps matching
       unchanged -- there is only one kind of .media element now, so
       the attribute is no longer needed for placement itself. Fills
       its grid cell exactly (width/height: 100%); aspect-ratio: 3 / 5
       is kept as an explicit, documented intent matching the Media
       panel width setting's default, with object-fit: cover
       (inherited from the base rule) absorbing the rest without ever
       distorting it. Crop focal point stays merchant-controlled
       (Product image position X / Y settings). Explicitly overrides
       the base rule's fixed aspect-ratio: 4/5 and margin-bottom: 0
       (both mobile/tablet only). */
    grid-column: 2;
    grid-row: 3;
    aspect-ratio: 3 / 5;
    width: 100%;
    height: 100%;
    margin-bottom: 0;
  }

  .kelain-culture-manifesto__image {
    /* object-fit: cover is inherited unchanged from the base rule
       above. The crop's focal point is merchant-controlled from the
       Theme Editor (Product image position X / Y settings) via the
       --product-image-position custom property set inline on
       .kelain-culture-manifesto__media, without touching the
       mobile/tablet crop below 990px. */
    object-position: var(--product-image-position, 50% 50%);
  }

  .kelain-culture-manifesto__mini-video {
    /* The BTS video panel (column 1, row 3 -- row 3 is the shared
       panel row the finished-product panel also uses in column 2;
       rows 1-2 are the optional label area above both). Fills its
       grid cell exactly (width/height: 100%), the same as the
       finished-product panel -- both panels always come out exactly
       the same size, by construction. aspect-ratio: 3 / 5 is kept as
       an explicit, documented intent matching the Media panel width
       setting's default, same as .kelain-culture-manifesto__media
       above (previously 9 / 16, when this was a single tall column
       spanning two stacked squares; now a single equal-height panel
       beside the product panel, sharing its ratio). The slot='3'
       override below shifts this to column 2 when the finished
       product is set to a video instead of an image. object-fit:
       cover (set further down, desktop only) replaces the mobile/
       tablet object-fit: contain above -- this portrait frame is a
       deliberate editorial crop, not an arbitrary box to letterbox
       inside, and cover never distorts the source, only crops it. */
    grid-column: 1;
    grid-row: 3;
    aspect-ratio: 3 / 5;
    width: 100%;
    height: 100%;
    max-width: none;
  }

  .kelain-culture-manifesto__mini-video-poster,
  .kelain-culture-manifesto__mini-video-el {
    /* Desktop-only override of the base rule's object-fit: contain --
       see the comment on .kelain-culture-manifesto__mini-video above. */
    object-fit: cover;
  }

  .kelain-culture-manifesto__mini-video[data-kelain-media-slot='3'] {
    /* The finished product, when it's a video, uses the same panel
       row/size as .kelain-culture-manifesto__media above (grid-row: 3,
       aspect-ratio: 3 / 5, both already set by the bare rule above) --
       only the column needs overriding, to column 2 (the bare rule
       defaults to column 1, the BTS video's column). */
    grid-column: 2;
  }

  .kelain-culture-manifesto__media-label {
    /* Desktop: its own dedicated grid row (row 1, --label-height) at
       the top of .kelain-culture-manifesto__media-group, directly
       above its own panel in the same column -- the base rule's
       10px margin-bottom (a mobile-only "belongs to this media" gap)
       is zeroed here because the gap to the panel below is already
       the dedicated row 2 (--label-gap). */
    grid-row: 1;
    margin: 0;
  }

  .kelain-culture-manifesto__media-label--video {
    grid-column: 1;
  }

  .kelain-culture-manifesto__media-label--product {
    grid-column: 2;
  }
}

@media screen and (min-width: 990px) and (max-height: 820px) {
  /* Extra compact pass for shorter laptop displays (e.g. 1366x768) --
     proportionally reduces headline size, gaps, padding and the
     shared media height on top of the vh-aware clamp()/min() values
     above, instead of ever letting the page scroll. */
  .page-section.kelain-culture-manifesto {
    padding-top: 18px;
    padding-bottom: 16px;
  }

  .kelain-culture-manifesto__top {
    gap: 8px;
  }

  .kelain-culture-manifesto__heading {
    font-size: clamp(26px, min(3.6vw, 5.4vh), 38px);
  }

  .kelain-culture-manifesto__quote p {
    font-size: clamp(18px, min(2.4vw, 4vh), 24px);
  }

  .kelain-culture-manifesto__statement {
    font-size: clamp(15px, min(1.4vw, 2.2vh), 17px);
  }

  .kelain-culture-manifesto__social {
    margin-top: 10px;
  }

  .kelain-culture-manifesto__inner {
    /* Same 1.25 enlargement factor as the 990px rule above, just
       capped against this breakpoint's own tighter 60vh instead of
       76vh (a smaller relative bump than the main rule's 62->72->76,
       since a short laptop has less spare height to begin with) --
       deliberately NOT bumped alongside the main rule's 72->76 change,
       since "do not break 1366x768" takes priority over the large-
       desktop-only width/size refinement at this tight breakpoint.
       Declared on .inner (not .media-group) because --media-size now
       lives there -- overriding it here correctly recomputes
       --panel-height / --panel-width /
       --media-group-actual-width / --composition-width all the way
       through, so .inner's own width and .media-group's actual
       rendered size always agree, even at this breakpoint. The main
       rule's justify-self: start and the tightened column-gap still
       apply here too (inherited, not overridden), so this breakpoint
       still gets the "move media closer to the manifesto" + "center
       the outer composition" parts of those fixes as well -- just not
       the main rule's extra vh-cap growth, to keep this tight
       breakpoint's no-scroll safeguard exactly as conservative as
       before. */
    --media-size: min(var(--media-height, 650px) * 1.25, 60vh);
  }
}
/* END_SECTION:kelain-culture-manifesto */

/* START_SECTION:kelain-culture-social (INDEX:8) */
.kelain-culture-social {
  border-top: 1px solid var(--color-border);
  text-align: center;
}

.kelain-culture-social__inner {
  /* Centered column composition at every breakpoint -- heading,
     handle, the Instagram/TikTok pair and the Shop Kelain link all
     share one center axis, so nothing needs separate desktop grid
     placement or a mobile-only align-self override. */
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
}

.kelain-culture-social__heading {
  /* Editorial redesign: significantly larger and more confident than a
     generic small section label — still clearly secondary in scale to
     the manifesto's poster-size "WHY NOT YOU?" above it on the page.
     Compact editorial refinement: scale reduced ~28% (clamp values
     scaled proportionally); weight, tracking, case unchanged. */
  margin: 0;
  font-family: var(--font-heading-family);
  font-style: var(--font-heading-style);
  font-weight: var(--weight-bold);
  font-size: clamp(24px, 4.5vw, 46px);
  line-height: 1;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  color: var(--color-text);
}

.kelain-culture-social__handle {
  margin: 0;
  font-size: 15px;
  font-weight: var(--weight-regular);
  color: var(--color-text);
  opacity: 0.65;
}

.kelain-culture-social__links {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 32px;
  margin-top: 4px;
}

.kelain-culture-social__link {
  font-family: var(--font-heading-family);
  font-weight: var(--weight-semibold);
  font-size: 13px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-text);
  text-decoration: none;
}

.kelain-culture-social__link::after {
  content: ' \2197';
}

@media screen and (max-width: 749px) {
  .kelain-culture-social__link::after {
    /* Same NE arrow character, plus the U+FE0E "text presentation"
       variation selector -- this is the standard, font/OS-independent
       way to force a plain monochrome glyph instead of some mobile
       browsers substituting a colorful emoji-style arrow for the bare
       codepoint above. No character, label, link, or desktop styling
       changes -- only how this one glyph renders on mobile. */
    content: ' \2197\FE0E';
  }
}

.kelain-culture-social__link:hover,
.kelain-culture-social__link:focus-visible {
  text-decoration: underline;
  text-underline-offset: 3px;
}

.kelain-culture-social__shop-link {
  /* Secondary editorial CTA, centered along with everything else in
     the column (align-self here matches the parent's align-items, so
     it's mostly a no-op kept for clarity/robustness). Bold (not a
     filled button) so it reads as a strong text link, one notch below
     the platform links in tracking so it doesn't compete with them. */
  align-self: center;
  position: relative;
  display: inline-block;
  margin-top: 8px;
  font-family: var(--font-heading-family);
  font-weight: var(--weight-bold);
  font-size: 13px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-text);
  text-decoration: none;
  padding-bottom: 3px;
}

.kelain-culture-social__shop-link::after {
  content: '';
  position: absolute;
  left: 0;
  right: 100%;
  bottom: 0;
  height: 1px;
  background: currentColor;
  transition: right 0.3s ease;
}

.kelain-culture-social__shop-link:hover::after,
.kelain-culture-social__shop-link:focus-visible::after {
  right: 0;
}

@media (prefers-reduced-motion: reduce) {
  .kelain-culture-social__shop-link::after {
    transition: none;
  }
}

/* Compact editorial refinement: vertical padding reduced from the
   shared .page-section defaults (48px/20px mobile, 80px/40px desktop)
   via a compound selector — .page-section still supplies the
   horizontal padding and every other page's padding is untouched. */
.page-section.kelain-culture-social {
  padding-top: 24px;
  padding-bottom: 24px;
}


@media screen and (min-width: 990px) {
  .page-section.kelain-culture-social {
    padding-top: 32px;
    padding-bottom: 32px;
  }
}
/* END_SECTION:kelain-culture-social */

/* START_SECTION:kelain-image-hero (INDEX:9) */
.kelain-hero {
  position: relative;
  width: 100%;
  display: flex;
  overflow: hidden;
  background: #000;
  color: #fff;
}

.kelain-hero--h-small { min-height: calc(60svh - var(--header-height, 0px)); }
.kelain-hero--h-medium { min-height: calc(80svh - var(--header-height, 0px)); }
/* Desktop only -- the mobile media query directly below restates the
   original calc(100svh ...) unchanged, so mobile's height is untouched.
   No viewport-percentage guess can ever exactly match an arbitrary
   photo's own proportions, so object-fit: cover was always going to crop
   *something* against a fixed/guessed height. Sizing the box to the
   REAL selected image's own aspect ratio instead (read from the actual
   Shopify image object, not hardcoded) makes the box's ratio equal the
   image's ratio exactly -- object-fit: cover then has nothing left to
   crop, and the hero's height simply follows from its full-bleed width,
   shorter or taller than one viewport as the photo's own shape dictates. */
.kelain-hero--h-full { aspect-ratio: var(--kelain-hero-image-ratio, 0.8); }

@media screen and (max-width: 749px) {
  .kelain-hero--h-small { min-height: 60svh; }
  .kelain-hero--h-medium { min-height: 75svh; }
  .kelain-hero--h-full { min-height: calc(100svh - var(--header-height, 0px)); }
}

.kelain-hero__media {
  position: absolute;
  inset: 0;
}

.kelain-hero__image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.kelain-hero__overlay {
  position: absolute;
  inset: 0;
  background: #000;
  opacity: var(--kelain-hero-overlay, 0.3);
}

.kelain-hero__content {
  position: relative;
  z-index: 1;
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 20px;
  padding: 48px 24px;
  margin: auto;
}

.kelain-hero__content--v-top { align-self: flex-start; }
.kelain-hero__content--v-center { align-self: center; }
.kelain-hero__content--v-bottom { align-self: flex-end; }

.kelain-hero__content--h-left { align-items: flex-start; text-align: left; }
.kelain-hero__content--h-center { align-items: center; text-align: center; }
.kelain-hero__content--h-right { align-items: flex-end; text-align: right; }

.kelain-hero--text-dark .kelain-hero__content {
  color: #000;
}

.kelain-hero__logo img {
  height: 32px;
  width: auto;
}

.kelain-hero__heading {
  /* Editorial, not aggressive: medium weight (lighter than the semibold
     used for nav/CTA), a calmer clamp ceiling, and looser line-height so
     it reads as a fashion headline rather than a bold display banner. */
  margin: 0;
  font-family: var(--font-heading-family);
  font-style: var(--font-heading-style);
  font-weight: var(--weight-medium);
  font-size: clamp(24px, 3.6vw, 42px);
  line-height: 1.25;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  max-width: 18ch;
}

.kelain-hero__subline {
  margin: 0;
  font-size: clamp(13px, 1.2vw, 15px);
  font-weight: var(--weight-regular);
  line-height: 1.7;
  letter-spacing: 0.01em;
  max-width: 38ch;
  opacity: 0.85;
}

.kelain-hero__cta {
  /* Minimal editorial text link (2026-09-23): replaces the previous
     rectangular/bordered button entirely -- no background, no border
     box, no radius, no shadow. Positioned against .kelain-hero itself
     (the nearest positioned ancestor, set up top via position: relative)
     rather than .kelain-hero__content, so it stays pinned to the hero's
     own bottom-left corner regardless of that block's own alignment,
     position-in-Theme-Editor or the desktop-only transform applied to
     it above. Percentages here are therefore relative to the hero box,
     not the viewport, and hold steady across desktop widths. */
  position: absolute;
  z-index: 2;
  left: 4%;
  bottom: 6%;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  /* Changed 2026-09-23: white instead of the Kelain Hot Pink
     (--kelain-hot-pink, still used elsewhere in the theme) that this CTA
     used previously -- text, arrow (inherits color from here) and
     underline all switched together via this one declaration + color
     below. */
  border-bottom: 1px solid #FFFFFF;
  padding-bottom: 2px;
  font-family: var(--font-heading-family);
  font-weight: var(--weight-bold);
  font-size: 18px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-decoration: none;
  color: #FFFFFF;
  line-height: 1;
  transition: opacity 0.2s ease;
}

.kelain-hero__cta:hover {
  /* Same subtle opacity dip as before -- no color swap, no underline/box
     change, so nothing about the layout shifts on hover. */
  opacity: 0.7;
}

.kelain-hero__cta-arrow {
  font-size: 19.5px;
  line-height: 1;
}

@media screen and (min-width: 750px) {
  /* Desktop-only hero content tweak (2026-09-22, updated 2026-09-23):
     subline hidden and headline trimmed down slightly, with the
     remaining headline-only content block recentered so its visual
     CENTER (not its edge) sits at ~29% of the hero width -- into the
     empty wall space, away from the models. align-items/text-align stay
     centered and only a translateX shifts the whole group left;
     translateX % is relative to this element's own box, which is 100%
     of the hero width, so -21% here equals exactly -21% of the hero
     width (50% center - 21% = 29%). The CTA is no longer part of this
     block at all (it moved out to its own bottom-left-pinned element --
     see .kelain-hero__cta above), so there is nothing here to space it
     from anymore. Mobile is completely untouched -- this block only
     ever matches at 750px and up, so the existing max-width: 749px
     block below keeps controlling mobile exactly as before.
     Image/crop/height/overlay are not touched by this block. */
  .kelain-hero__subline {
    display: none;
  }

  .kelain-hero__heading {
    font-size: clamp(20px, 2.6vw, 30px);
  }

  .kelain-hero__content {
    align-items: center;
    text-align: center;
    transform: translateX(-21%);
  }
}

@media screen and (max-width: 749px) {
  /* Mobile-only editorial composition. Desktop is untouched by this
     block -- it only ever matches at 749px and below (the same mobile
     breakpoint the height variants above already use). This overrides
     whichever vertical/horizontal position the merchant picked in the
     Theme Editor (same specificity as the --v-*/--h-* modifier classes
     above, so it wins here purely by coming later in the file) so the
     content group always sits low and centered on mobile, regardless of
     the desktop-facing position settings, which keep working exactly as
     configured at 750px and up. */
  .kelain-hero__content {
    align-self: flex-end;
    align-items: center;
    text-align: center;
    /* Generous, not flush: the group sits in the lower third with real
       breathing room below it, not pinned to the very bottom edge. */
    padding-bottom: 64px;
  }

  .kelain-hero__heading {
    /* Slightly smaller than the 24px mobile floor (clamp(24px, 3.6vw,
       42px) resolves to its 24px minimum on virtually every phone
       viewport), so the headline reads as balanced rather than
       dominant against a portrait model image. */
    font-size: 21px;
  }

  .kelain-hero__subline {
    /* Same idea as the headline: a touch below the 13px mobile floor
       (clamp(13px, 1.2vw, 15px) also always resolves to 13px here), plus
       a narrower measure so it wraps into a tighter, more editorial
       block instead of stretching wide over the models. */
    font-size: 12px;
    max-width: 30ch;
  }

  .kelain-hero__cta {
    /* Same bottom-left text-link treatment as desktop, just tighter
       spacing. Hero image/crop/height are untouched by this rule.
       Font-size raised 11px -> 13px (+18%, 2026-10-22) so the CTA
       reads as more visually intentional on mobile -- weight, color,
       underline and arrow are untouched. */
    left: 6%;
    bottom: 5%;
    gap: 5px;
    font-size: 16px;
  }

  .kelain-hero__cta-arrow {
    font-size: 17px;
  }

  /* Invisible tap-target expansion (2026-10-22): the visible CTA stays
     exactly as minimal as before (no box, no background, no padding
     change that would shift the underline) -- this just extends the
     actually-tappable area via a blank ::before so mobile taps are
     comfortable. .kelain-hero__cta is already position: absolute, so
     this pseudo-element positions relative to it with no extra markup
     or positioning context needed. */
  .kelain-hero__cta::before {
    content: "";
    position: absolute;
    inset: -14px;
  }

  .kelain-hero__image {
    /* Horizontal-only crop adjustment, mobile only -- the base rule
       above has no object-position (defaults to center/center); this
       is the only object-position declared anywhere for this image,
       so desktop/tablet (750px and up) keep the exact default centered
       crop, untouched. Vertical stays centered (50%) -- no Y control
       exists or was requested. Merchant-adjustable via the Mobile
       image position X setting (mobile_image_position_x) in the
       Theme Editor. */
    object-position: var(--kelain-hero-mobile-image-position-x, 50%) 50%;
  }

  /* Mobile-only entrance strengthening (2026-10-22): same animation
     system as desktop (same keyframes, same 2.8s / cubic-bezier(.16,1,.3,1)
     timing, same 0.55s CTA delay), just a slightly larger starting
     scale and a touch more initial CTA offset so the reveal reads more
     clearly on a phone screen. Desktop's own values (1.09 / 22px) are
     untouched -- see the var() fallbacks above. */
  .kelain-hero--entrance .kelain-hero__image {
    --kelain-hero-entrance-scale-from: 1.13;
  }

  .kelain-hero--entrance .kelain-hero__cta {
    --kelain-hero-entrance-cta-y: 30px;
  }
}

/* ------------------------------------------------------------
   Homepage-only cinematic entrance (2026-10-19): a barely-perceptible
   zoom-out on the hero image plus a slightly-delayed fade-up on the
   CTA. Transform/opacity only -- no layout property is touched, so
   this cannot shift layout or change the image's own dimensions,
   crop or object-position; the hero's own overflow: hidden (above)
   clips the brief 6% scale exactly to the hero box. Scoped to
   .kelain-hero--entrance (homepage only, see is_homepage above) so
   this reusable section never animates this way if placed on another
   page. Disabled under prefers-reduced-motion: reduce below. */
.kelain-hero--entrance .kelain-hero__image {
  /* Slowed 2026-10-25 (2.8s -> 4.5s) after feedback that the previous
     pace read as too quick to notice -- same easing/concept, just a
     longer, more cinematic zoom-out. Shared by both breakpoints since
     this rule is unscoped. */
  animation: kelain-hero-entrance-scale 4.5s cubic-bezier(0.16, 1, 0.3, 1) both;
}

.kelain-hero--entrance .kelain-hero__cta {
  opacity: 0;
  /* Mobile-only strengthening (2026-10-22): reads
     --kelain-hero-entrance-cta-y, set only inside the existing
     max-width: 749px block below (desktop keeps this 22px fallback,
     untouched). */
  transform: translateY(var(--kelain-hero-entrance-cta-y, 22px));
  animation: kelain-hero-entrance-cta-reveal 1.0s cubic-bezier(0.16, 1, 0.3, 1) 0.55s both;
}

@keyframes kelain-hero-entrance-scale {
  from {
    /* Mobile-only strengthening (2026-10-22): reads
       --kelain-hero-entrance-scale-from, set only inside the existing
       max-width: 749px block below, so desktop keeps this exact 1.09
       fallback untouched. One shared keyframe, no duplication. */
    transform: scale(var(--kelain-hero-entrance-scale-from, 1.09));
  }
  to {
    transform: scale(1);
  }
}

@keyframes kelain-hero-entrance-cta-reveal {
  from {
    opacity: 0;
    transform: translateY(var(--kelain-hero-entrance-cta-y, 22px));
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@media (prefers-reduced-motion: reduce) {
  .kelain-hero--entrance .kelain-hero__image {
    animation: none;
    transform: none;
  }

  .kelain-hero--entrance .kelain-hero__cta {
    animation: none;
    opacity: 1;
    transform: none;
  }
}
/* END_SECTION:kelain-image-hero */

/* START_SECTION:kelain-product-grid (INDEX:10) */
.kelain-product-grid__header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 32px;
}

.kelain-product-grid__heading {
  font-size: 14px;
  font-weight: var(--weight-semibold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.kelain-product-grid__view-all {
  font-size: 12px;
  font-weight: var(--weight-regular);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
  opacity: 0.7;
}

.kelain-product-grid__view-all:hover {
  opacity: 1;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.kelain-product-grid .product-card {
  display: block;
}

.kelain-product-grid .product-card__media {
  position: relative;
}

.product-card__image--secondary {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 0.3s ease;
}

@media (hover: hover) {
  .kelain-product-grid .product-card:hover .product-card__image--secondary {
    opacity: 1;
  }
}
/* END_SECTION:kelain-product-grid */

/* START_SECTION:main-product (INDEX:16) */
/* Shipping & returns accordion content: three compact groups (Shipping /
   Returns / Need help), each a short line of copy plus one understated
   text link. Scoped additively via a modifier class, same technique as
   the existing --material-care / --fit-size modifiers above in
   assets/base.css, so Product details, Fit & size and Material & care
   keep their current spacing untouched -- nothing here touches global
   CSS. */
.product-info__details-content--shipping-returns .product-info__shipping-returns-group:not(:last-child) {
  margin-bottom: 16px;
}

.product-info__shipping-returns-group p {
  margin: 0;
}

.product-info__shipping-returns-group p:not(:last-child) {
  margin-bottom: 6px;
}

.product-info__shipping-returns-heading {
  font-weight: var(--weight-semibold);
}

.product-info__shipping-returns-link {
  display: inline-block;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.product-info__shipping-returns-link:hover,
.product-info__shipping-returns-link:focus-visible {
  opacity: 0.6;
}

/* EXPERIMENTAL -- wrapper for the magnetic Add to Cart test (see the
   script below). No visual properties at all beyond display: block,
   so it is completely invisible; it exists purely so the magnetic
   transform has a target that carries no CSS animation of its own
   (the button itself keeps its entrance animation, untouched). */
.kelain-magnetic-btn {
  display: block;
}
/* END_SECTION:main-product */