/* =========================================================================
   Ciano Meubles — hero demo (take 2)
   The "pinned" layout, unpinned: clips advance on a timer instead of on scroll.
   No divider. Everything below this hero is the live site, untouched.
   Namespaced .d* so nothing here can reach the production pages.

   The palette comes from css/tokens.css, which must load first. The
   --d-* block that used to sit here is gone: it was one of five namespaces
   describing the same five colours, with nothing keeping them in agreement.
   The --d-* names that remain below are JS-driven motion state, not colour.
   ========================================================================= */

/* ------------------------------------------------------------ structure -- */

/* The hero is only a spacer in the document flow. The stage itself is fixed, so
   the page below can ride up over a stationary hero — the floema reveal. */
.dhero {
  position: relative;
  /* One dark ground, shared with the services band and the collections panel.
     Those three used to be var(--x-dark) / var(--x-dark) / var(--x-dark): a 1.04:1 difference,
     which reads as a seam that failed to line up rather than as a step. */
  background: var(--x-dark);
  /* style.css sets a global `section { padding: 120px 0 }` */
  padding: 0;
  height: 100svh;
  min-height: 560px;
}

.dhero-stage {
  position: fixed;
  inset: 0;
  height: 100svh;
  min-height: 560px;
  overflow: hidden;
  z-index: 0;
  /* No scroll-driven scale here. The stage used to shrink as the sheet rode up
     over it; at any real scroll speed that reads as the picture peeling away
     from its own edges rather than as depth. The dim below carries the cue on
     its own. Keeping the transform off also keeps the stage off a promoted
     compositing layer, where the scrim ramps quantise harder and band. */
}

/* Dims the whole stage, type included, as the sheet takes over. */
.dhero-stage::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 5;
  background: var(--x-dark);
  opacity: var(--d-dim, 0);
  pointer-events: none;
}

/* The sheet: everything below the hero, moving as one plane over it. */
.dsheet {
  position: relative;
  z-index: 2;
  background: var(--color-bg, var(--x-paper));
  box-shadow: 0 -34px 70px rgba(var(--x-dark-rgb), 0.30);
}

.dhero-media { position: absolute; inset: 0; z-index: 0; }

.dhero-media video,
.dhero-media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 1.5s var(--x-ease-io);
}

.dhero-media video.is-active,
.dhero-media img.is-active { opacity: 1; }

/* The reel is stills today, but hero.js still plays a <video> slide if one is
   added. Some exports ship letterboxed — picture inside a taller frame, with
   black riding along the top and bottom. Rather than re-cut the file, scaling
   at display time pushes the bars past the edge of the stage. Set --d-lb per
   clip to frame height over picture height (860 in 900 = 1.0465). */
.dhero-media video.is-letterboxed { transform: scale(var(--d-lb, 1.05)); }

/* A still next to moving footage reads as a stall unless it drifts. Slow
   enough that it is felt rather than seen.

   This is a transition rather than a keyframe animation on purpose. An
   animation is bound to `.is-active`, so dropping that class at the cut tore
   the transform away and the outgoing frame snapped back to unzoomed while it
   was still half visible through the 1.5s crossfade. A transition unwinds at
   its own pace instead, invisibly, and is back at the start by the time the
   slide comes round again. */
/* Every endpoint here is a variable because the drift is randomised per
   appearance in js/hero.js — scale, direction and duration all
   change each time a still comes round, so the loop never repeats itself.
   A transition rather than a keyframe animation: an animation is bound to
   `.is-active`, and dropping that class at the cut tore the transform away,
   snapping the outgoing frame back to unzoomed mid-crossfade. */
.dhero-media img {
  transform: scale(var(--i-s0, 1.03)) translate3d(var(--i-x0, 0%), var(--i-y0, 0%), 0);
  transition: opacity 1.5s var(--x-ease-io), transform var(--i-dur, 10s) linear;
}

.dhero-media img.is-active {
  transform: scale(var(--i-s1, 1.1)) translate3d(var(--i-x1, 0%), var(--i-y1, -1%), 0);
}

/* Warm scrim: keeps the type legible without greying the wood tones. Weighted
   to the bottom-left because that is where the content block sits.

   Every ramp is spelled out in ~8 stops rather than 3. The anchor values are
   the ones the design was tuned to; the extra stops round the corners between
   segments and, more importantly, land each ramp on zero alpha with zero
   slope. A three-stop ramp changes gradient abruptly at each stop and stops
   dead at the last one, and every one of those slope breaks prints a visible
   line once the ground behind it is a flat colour.

   Alpha ends on rgba(...,0) rather than `transparent` so the interpolation is
   unambiguously toward this same warm dark, never toward transparent black. */
.dhero-scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    /* Top band: the nav is transparent and fixed, so it needs a floor to read
       against no matter how bright the frame behind it is. */
    linear-gradient(to bottom,
      rgba(var(--x-dark-rgb), 0.78) 0%,
      rgba(var(--x-dark-rgb), 0.61) 4%,
      rgba(var(--x-dark-rgb), 0.44) 8%,
      rgba(var(--x-dark-rgb), 0.287) 11.5%,
      rgba(var(--x-dark-rgb), 0.16) 15%,
      rgba(var(--x-dark-rgb), 0.105) 17%,
      rgba(var(--x-dark-rgb), 0.053) 19%,
      rgba(var(--x-dark-rgb), 0.015) 21%,
      rgba(var(--x-dark-rgb), 0) 23%),
    linear-gradient(to top,
      rgba(var(--x-dark-rgb), 0.88) 0%,
      rgba(var(--x-dark-rgb), 0.77) 11%,
      rgba(var(--x-dark-rgb), 0.66) 22%,
      rgba(var(--x-dark-rgb), 0.55) 33%,
      rgba(var(--x-dark-rgb), 0.42) 44%,
      rgba(var(--x-dark-rgb), 0.31) 50.5%,
      rgba(var(--x-dark-rgb), 0.17) 57%,
      rgba(var(--x-dark-rgb), 0.05) 63.5%,
      rgba(var(--x-dark-rgb), 0) 70%),
    linear-gradient(100deg,
      rgba(var(--x-dark-rgb), 0.70) 0%,
      rgba(var(--x-dark-rgb), 0.46) 24%,
      rgba(var(--x-dark-rgb), 0.22) 48%,
      rgba(var(--x-dark-rgb), 0.152) 54.5%,
      rgba(var(--x-dark-rgb), 0.08) 61%,
      rgba(var(--x-dark-rgb), 0.023) 67.5%,
      rgba(var(--x-dark-rgb), 0) 74%);
}

/* Dither. The banding is not in the gradients themselves, it is in the 8 bits
   per channel they have to land on: a long, low-contrast ramp gets fewer than
   one code value per several pixels, so the steps line up into contours. It is
   worst exactly where the frame is smooth — a defocused wall behind the fade
   has no texture of its own to hide them. The fix is the one print and film
   use: add noise on the order of one code value so the eye averages across it
   and the contour has nothing to follow.

   This has to be the last thing in the stage — above the media, the scrim, the
   grain and the dim at z-index 5 — because every one of those composites in 8
   bits too, and the dim in particular scales any dither underneath it down by
   exactly the amount it is dimming. Dithering the finished composite instead
   keeps the amplitude constant through the whole scroll.

   .dhero-grain cannot do this job: it blends `overlay`, which on a near-black
   ground collapses to a multiply and leaves the deep end of the ramp — where
   the contours actually are — untouched. This layer blends normally, so it
   perturbs every tone equally. One octave, so it is grain rather than clouds,
   and stitched, so the tile is seamless. feComponentTransfer stretches the
   turbulence hard about mid grey: raw fractalNoise clusters so tightly around
   0.5 that at any opacity low enough not to wash the picture out it lands as a
   flat lift with no usable variance — measured, a gentle curve moved the mean
   6 code values and the spread barely 1. Stretched instead, the mean barely
   moves and the spread lands near +/-4: past the step size, under the
   threshold where anyone reads it as texture. */
.dhero-stage::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 6;
  pointer-events: none;
  opacity: 0.05;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='d' x='0' y='0' width='100%25' height='100%25' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='1' stitchTiles='stitch'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='6' intercept='-2.5'/%3E%3CfeFuncG type='linear' slope='6' intercept='-2.5'/%3E%3CfeFuncB type='linear' slope='6' intercept='-2.5'/%3E%3CfeFuncA type='linear' slope='0' intercept='1'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23d)'/%3E%3C/svg%3E");
  background-size: 180px 180px;
}

.dhero-grain {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  opacity: 0.15;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
}

/* Content sits on the floor of the frame, as in the pinned version. */
.dhero-inner {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: flex;
  align-items: flex-end;
  padding-bottom: clamp(58px, 9vh, 104px);
}

.dhero-wrap {
  width: 100%;
  max-width: 1280px;
  margin: 0 auto;
  padding: 0 clamp(20px, 5vw, 64px);
}

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

.dhero-eyebrow {
  display: flex;
  align-items: center;
  gap: 14px;
  font-family: var(--x-sans);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: rgba(var(--x-paper-rgb), 0.74);
  margin-bottom: 22px;
}

.dhero-eyebrow::before {
  content: "";
  width: 46px;
  height: 1px;
  background: var(--x-brass);
}

.dhero-title {
  font-family: var(--x-display);
  font-weight: 300;
  font-size: clamp(2.4rem, 5vw, 4.6rem);
  line-height: 1.0;
  letter-spacing: -0.015em;
  color: var(--x-paper);
  margin: 0 0 22px;
}

.dhero-title em { font-style: italic; color: var(--x-brass); }

/* The 22px below the title is the gap to the buttons. On a hero that has no
   buttons — collections — it is not a gap, it is 22px of dead air between the
   headline and the floor of the frame, which reads as the block having
   slipped upward off its own baseline. Nothing follows, so nothing to space. */
.dhero-title:last-child { margin-bottom: 0; }

/* -------------------------------------------------------------- buttons -- */

.dhero-actions { display: flex; flex-wrap: wrap; gap: 13px; }

.d-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 15px 30px;
  font-family: var(--x-sans);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  text-decoration: none;
  /* Outline at rest, brass on hover — see .btn in style.css, which is this
     button shared out to every other page. On this near-black ground the
     label can be true --x-brass (5.63:1); on cream it has to deepen to
     --x-brass-ink, which is the only thing that differs between the two. */
  border: 1px solid var(--x-brass);
  color: var(--x-brass);
  background: transparent;
  overflow: hidden;
  transition: color 0.5s var(--x-ease), border-color 0.5s var(--x-ease);
}

.d-btn span { position: relative; z-index: 1; }
.d-btn svg  { position: relative; z-index: 1; width: 15px; height: 15px; transition: transform 0.5s var(--x-ease); }

/* Fill wipes up from the bottom rather than a flat colour swap. */
.d-btn::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--x-brass);
  transform: translate3d(0, 101%, 0);
  transition: transform 0.6s var(--x-ease);
  z-index: 0;
}

.d-btn:hover { color: var(--x-dark); }
.d-btn:hover::after { transform: translate3d(0, 0, 0); }
.d-btn:hover svg    { transform: translate3d(4px, 0, 0); }

.d-btn--ghost {
  background: transparent;
  border-color: rgba(var(--x-paper-rgb), 0.42);
  color: var(--x-paper);
}

.d-btn--ghost:hover { color: var(--x-dark); border-color: var(--x-brass); }

/* ----------------------------------------------------------- entrance ---- */
/* The card that opens the site — .dveil — lives in css/style.css, because it
   can now open ANY page and style.css is the only stylesheet every page loads.
   What stays here is the half of the intro that only exists where there is a
   hero: the photograph's settle, and when the headline lands.

   The card lifts upward, so the bottom of the viewport is uncovered first —
   which is where the headline is, and why the type comes in halfway through
   the travel rather than at the end of it. The nav is at the top and is
   therefore uncovered last, so it has no entrance of its own any more: being
   revealed by the card is its entrance. */

/* The picture settles out of a crop behind the card. It starts before the
   lift and ends 1.3s after it, so the frame is still arriving once the card
   has gone — the part of the intro that is felt rather than watched.

   On .dhero-media, the plane, not on the images: the stills carry their own
   randomised drift on `transform`, and the two would overwrite each other.
   `backwards` rather than `both` so no transform is left held afterwards,
   which would keep the plane on a compositing layer for the whole session. */
.dhero-intro .dhero-media {
  animation: d-veil-settle 3.2s var(--x-ease) 0.9s backwards;
}

@keyframes d-veil-settle {
  from { transform: scale(1.08); }
  to   { transform: scale(1); }
}

/* The type lands halfway through the travel, by which point the card has
   cleared the bottom half of the screen and the block is in the open. Earlier
   and it settles behind the card; later and it trails the reveal. */
.dhero [data-in] {
  opacity: 0;
  transform: translate3d(0, 26px, 0);
  transition: opacity 1.2s var(--x-ease), transform 1.35s var(--x-ease);
  transition-delay: calc(var(--d-delay, 0ms) + 1850ms);
}

.dhero.is-ready [data-in] { opacity: 1; transform: none; }

/* Every load after the first in a session skips the card (see the gate in
   css/style.css). With nothing covering the frame there is nothing to wait
   for, so the settle goes and the headline arrives on its own short beat —
   the same words, without the ceremony in front of them. */
html.mc-intro-seen .dhero-intro .dhero-media { animation: none; }

html.mc-intro-seen .dhero [data-in] {
  transition: opacity 0.8s var(--x-ease), transform 0.9s var(--x-ease);
  transition-delay: calc(var(--d-delay, 0ms) + 120ms);
}

/* --------------------------------------------------------- responsive ---- */

@media (max-width: 900px) {
  .dhero-inner { padding-bottom: clamp(52px, 8vh, 84px); }
}

@media (max-width: 640px) {
  .dhero-actions .d-btn { padding: 13px 22px; font-size: 11px; }
}

@media (prefers-reduced-motion: reduce) {
  .dhero-stage, .dhero-intro .dhero-media { animation: none !important; }
  .dhero [data-in] { opacity: 1 !important; transform: none !important; transition: none !important; }
  .dhero-media video,
  .dhero-media img { transition: opacity 0.4s linear; }
  .dhero-media img,
  .dhero-media img.is-active { transform: none; }
  .dhero-media video.is-letterboxed { transform: scale(var(--d-lb, 1.05)); }
}
