/* ==========================================================================
   Media + image motion layer.

   WIREFRAME STAGE: every photographic asset is a placeholder. No third-party
   imagery is hotlinked. Each slot carries a caption describing the shot the
   final asset should be, so the client can approve art direction before
   anything is commissioned.

   Motion vocabulary measured off forhers.com computed styles:
     reveal   opacity + transform   600ms  cubic-bezier(.72, 0, .45, 1)
     settle   670ms cubic-bezier(.71, 0, .18, 1), 8% overshoot then -2%
     drift    transform 3s ease, slow ambient movement
     float    translateY 0 -> -15px -> 0, slow, infinite
   ========================================================================== */

/* ---------------------------------------------------------------- slots -- */
.media {
  position: relative;
  border-radius: var(--r-card, 24px);
  overflow: hidden;
  background: linear-gradient(140deg, #56422A 0%, #453421 48%, #6B563A 100%);
  isolation: isolate;
}
.media.ratio-16x9 { aspect-ratio: 16/9; }
.media.ratio-4x3  { aspect-ratio: 4/3; }
.media.ratio-1x1  { aspect-ratio: 1/1; }
.media.ratio-3x4  { aspect-ratio: 3/4; }
.media.light { background: linear-gradient(140deg, #FBF8F5 0%, #F5F0E8 52%, #F7EFE4 100%); }

/* slow drifting colour field, the "photograph" stand-in */
.media::before {
  content: ""; position: absolute; inset: -18%; z-index: 0; pointer-events: none;
  background:
    radial-gradient(38% 42% at 24% 26%, rgba(255,198,113,.50), transparent 66%),
    radial-gradient(34% 38% at 78% 34%, rgba(185,130,103,.42), transparent 68%),
    radial-gradient(44% 48% at 56% 84%, rgba(69,52,33,.42), transparent 70%);
  filter: blur(28px);
  animation: media-drift 22s cubic-bezier(.4,0,.2,1) infinite alternate;
}
.media.light::before { opacity: .8; }

@keyframes media-drift {
  0%   { transform: translate3d(0,0,0) scale(1); }
  50%  { transform: translate3d(-3%, 2.5%, 0) scale(1.08); }
  100% { transform: translate3d(2.5%, -3%, 0) scale(1.04); }
}

/* fine grain so the placeholder does not read as a flat swatch */
.media::after {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none; opacity: .16;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='140'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/></filter><rect width='140' height='140' filter='url(%23n)' opacity='.55'/></svg>");
}

/* real imagery inside a media slot: fills the frame, sits under grain + play */
.media > img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; z-index: 0; display: block;
}
.media:has(> img)::before { display: none; }   /* drop the drift field once a real image exists */
.media:has(> img) .slot { display: none; }     /* and the placeholder caption */

/* the caption that tells the client what the real shot is */
.media .slot {
  position: absolute; inset: 0; z-index: 2; display: grid; place-content: center;
  text-align: center; padding: var(--s-5); gap: var(--s-2);
}
/* when a play control sits in the centre, drop the caption to the base so the
   two do not overlap */
.media:has(.play) .slot { align-content: end; padding-bottom: var(--s-4); }
.media:has(.play) .slot .desc { font-size: var(--t-xs); max-width: 40ch; line-height: 1.4; }
.media .slot .tag {
  font-size: 10px; font-weight: 600; letter-spacing: .18em; text-transform: uppercase;
  color: rgba(255,255,255,.72);
}
.media.light .slot .tag { color: rgba(36,36,36,.55); }
.media .slot .desc {
  font-size: var(--t-sm); color: #fff; max-width: 34ch; margin: 0 auto; line-height: 1.45;
}
.media.light .slot .desc { color: #242424; }

/* ---------------------------------------------------- image motion ------- */

/* ken burns: a very slow scale + pan, the Hers ambient-drift register */
.media.kenburns > img,
.media.kenburns .slot { animation: kenburns 26s ease-in-out infinite alternate; }
@keyframes kenburns {
  from { transform: scale(1)    translate3d(0,0,0); }
  to   { transform: scale(1.07) translate3d(-1.5%, -1%, 0); }
}

/* float: for cut-out product shots and small cards */
.floats { animation: media-float 7s ease-in-out infinite; }
@keyframes media-float {
  0%,100% { transform: translateY(0); }
  50%     { transform: translateY(-15px); }
}

/* reveal-with-scale, on the Hers curve, for media entering the viewport */
.js-motion [data-reveal="media"] { opacity: 0; transform: translate3d(0,26px,0) scale(.97); }
.js-motion [data-reveal="media"].in {
  opacity: 1; transform: none;
  transition: opacity .6s cubic-bezier(.72,0,.45,1), transform .6s cubic-bezier(.72,0,.45,1);
}

/* hover: glass-aware, matches the .3s ease Hers uses on colour + backdrop */
.media.interactive { cursor: pointer; transition: transform .2s ease-in-out, box-shadow .3s cubic-bezier(.4,0,.2,1); }
.media.interactive:hover { transform: translateY(-3px); box-shadow: var(--e-3); }

/* play control sitting over media */
.media .play {
  position: absolute; inset: 0; margin: auto; z-index: 3;
  width: 60px; height: 60px; border-radius: 50%; display: grid; place-items: center;
  background: rgba(255,255,255,.34);
  -webkit-backdrop-filter: saturate(150%) blur(24px); backdrop-filter: saturate(150%) blur(24px);
  border: 1px solid rgba(255,255,255,.62); color: #fff; cursor: pointer;
  box-shadow: 0 8px 26px rgba(0,0,0,.3), inset 0 1px 0 rgba(255,255,255,.7);
  transition: transform .2s ease-in-out, background .3s cubic-bezier(.4,0,.2,1);
}
.media:hover .play { transform: scale(1.07); background: rgba(255,255,255,.44); }
.media .play:active { transform: scale(.96); }

/* ------------------------------------------------------ product stack ---- */
/* The bundle mockup is a transparent cut-out, so it sits directly on the page
   with no frame, no background and no crop. Never wrap it in .media. */
.stack-shot {
  display: block; width: 100%; height: auto; max-width: 780px;
  margin-inline: auto; background: none; border: 0;
}
.stack-shot.sm { max-width: 420px; }
.stack-shot.lg { max-width: 980px; }
/* a very soft ground shadow so the cut-out sits on the page rather than floats */
.stack-wrap { position: relative; }
.stack-wrap::after {
  content: ""; position: absolute; left: 12%; right: 12%; bottom: 4%; height: 26px; z-index: -1;
  background: radial-gradient(50% 50% at 50% 50%, rgba(69,52,33,.20), transparent 72%);
  filter: blur(10px);
}

/* ==========================================================================
   BEFORE / AFTER PROOF GRID
   Layout is production-ready. The cells are deliberately empty slots carrying
   a shot spec, because a before/after is EVIDENCE: the only version that can
   ship is a real, dated, permissioned client pair. Drop the real image in as
   a <img> inside .ba-cell and the slot furniture hides itself automatically,
   exactly like .media does.
   ========================================================================== */
.ba-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--s-4);
}
.ba-card {
  border-radius: var(--r-md); overflow: hidden; background: var(--surface);
  border: 1px solid var(--line); box-shadow: var(--e-1);
}
.ba-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 2px; background: var(--line); }

/* a single supplied diptych (one photo containing both halves) */
.ba-shot { position: relative; aspect-ratio: 16/9; overflow: hidden; background: var(--navy); }
.ba-shot > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.ba-shot .tag-before,
.ba-shot .tag-after {
  position: absolute; bottom: 10px; z-index: 2;
  font-size: 10px; font-weight: 800; letter-spacing: .16em; text-transform: uppercase;
  padding: 4px 10px; border-radius: var(--r-full);
  background: rgba(6,26,36,.78); color: #fff; backdrop-filter: blur(6px);
}
.ba-shot .tag-before { left: 10px; }
.ba-shot .tag-after  { right: 10px; background: var(--amber); color: var(--on-amber); }
/* the divider between the two halves of the supplied photo */
.ba-shot::before {
  content: ""; position: absolute; top: 0; bottom: 0; left: 50%; width: 2px; z-index: 2;
  background: rgba(255,255,255,.5);
}
.ba-cell {
  position: relative; aspect-ratio: 3/4; overflow: hidden;
  background: linear-gradient(150deg, #4A3826 0%, #6B563A 52%, #56422A 100%);
  display: grid; place-content: center; text-align: center; padding: var(--s-4);
}
.ba-cell > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: 1; }
.ba-cell:has(> img) .ba-slot { display: none; }
.ba-slot .lbl {
  font-size: 10px; font-weight: 800; letter-spacing: .2em; text-transform: uppercase;
  color: var(--amber); margin-bottom: 6px;
}
.ba-slot .spec { font-size: var(--t-xs); color: rgba(255,255,255,.72); line-height: 1.45; max-width: 22ch; margin: 0 auto; }
.ba-cell::after {
  content: "PLACEHOLDER"; position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  font-size: 9px; font-weight: 800; letter-spacing: .18em; text-align: center;
  padding: 4px 0; background: rgba(255,198,113,.92); color: var(--on-amber);
}
.ba-cell:has(> img)::after { content: "REPLACE WITH REAL CLIENT PHOTO"; }
.ba-meta { padding: var(--s-4); }
.ba-meta h4 { margin: 0 0 var(--s-1); font-size: var(--t-md); font-weight: 700; }
.ba-meta p { margin: 0; font-size: var(--t-sm); color: var(--text-muted); }
.ba-meta .nums { display: flex; gap: var(--s-3); flex-wrap: wrap; margin-top: var(--s-3); }
.ba-meta .nums span {
  font-size: var(--t-xs); font-weight: 800; background: var(--wash); color: var(--navy);
  padding: 4px 10px; border-radius: var(--r-full);
}

/* portrait avatars used in testimonials and expert cards */
.avatar {
  width: 64px; height: 64px; border-radius: 50%; flex: none; position: relative; overflow: hidden;
  background: linear-gradient(140deg, #6B563A, #453421);
  display: grid; place-items: center; color: #fff; font-weight: 600; font-size: var(--t-md);
}
.avatar.lg { width: 88px; height: 88px; font-size: var(--t-lg); }
.avatar::after {
  content: ""; position: absolute; inset: -20%;
  background: radial-gradient(40% 44% at 30% 28%, rgba(255,198,113,.45), transparent 68%);
  animation: media-drift 20s cubic-bezier(.4,0,.2,1) infinite alternate;
}
.avatar span { position: relative; z-index: 1; }

/* real portrait inside an avatar: fills the circle, replaces the drift + initials */
.avatar > img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; z-index: 1; display: block;
}
.avatar:has(> img)::after { display: none; }
.avatar:has(> img) span { display: none; }

/* ------------------------------------------------------ accessibility ---- */
@media (prefers-reduced-motion: reduce) {
  .media::before, .media.kenburns > img, .media.kenburns .slot,
  .floats, .avatar::after { animation: none !important; }
  .js-motion [data-reveal="media"] { opacity: 1 !important; transform: none !important; }
  .media.interactive:hover, .media:hover .play { transform: none !important; }
}
@media (prefers-reduced-transparency: reduce) {
  .media .play { background: #fff !important; color: var(--navy) !important;
                 -webkit-backdrop-filter: none !important; backdrop-filter: none !important; }
}
@media (forced-colors: active) {
  .media { border: 1px solid CanvasText; }
  .media::before, .media::after { display: none; }
}
