/* =====================================================================
   STUDIO BENGUAR — TOP motion-only addendum (index-motion.html)
   Loaded AFTER css/style.css, which is otherwise untouched. Every rule
   here targets either a new [data-mo] attribute (added only in
   index-motion.html) or is scoped under body.page-home so it can never
   affect index.html or any other page. No layout, color or type rule
   from style.css is overridden — only opacity/transform/clip-path for
   the elements listed below.
   ===================================================================== */

/* Default (no-JS / JS not yet run): everything visible, nothing animates. */
[data-mo] { opacity: 1; }

/* ---------------------------------------------------------------------
   Hero — load-triggered (not scroll), quiet clip/opacity entrance.
   Runs once, right after paint; no continuous motion.
   --------------------------------------------------------------------- */
.js [data-mo="hero-en"],
.js [data-mo="hero-title"],
.js [data-mo="hero-sub"],
.js [data-mo="hero-note"] { opacity: 0; }

.js [data-mo="hero-en"] {
  animation: moFadeUpSoft .9s cubic-bezier(.22,.8,.3,1) .15s both;
}
.js [data-mo="hero-title"] {
  clip-path: inset(0 0 100% 0);
  animation: moTitleReveal 1.1s cubic-bezier(.22,.85,.28,1) .35s both;
}
.js [data-mo="hero-sub"] {
  animation: moFadeUpSoft .9s cubic-bezier(.22,.8,.3,1) .75s both;
}
.js [data-mo="hero-note"] {
  animation: moFadeSoft 1s ease .95s both;
}

@keyframes moTitleReveal {
  from { opacity: 0; clip-path: inset(0 0 100% 0); }
  to   { opacity: 1; clip-path: inset(0 0 0% 0); }
}
@keyframes moFadeUpSoft {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes moFadeSoft {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* Hero photo: intentionally no entrance rule here. The hero <img> keeps
   only style.css's own original ambient zoom, exactly as on the current
   production TOP — this version previously added a clip-path iris-open
   on the wrapper and that has been removed per feedback ("Heroの写真演出
   は元のBENGUAR TOPと同じ状態に戻す"). Hero text above is unchanged. */

/* ---------------------------------------------------------------------
   Scroll-triggered reveal variants (IntersectionObserver adds
   .is-mo on the element — see js/motion.js). threshold is kept at 0
   deliberately: a non-zero threshold combined with clip-path on the
   observed element itself makes Chromium report intersectionRatio 0
   forever (clip-path is applied before the ratio is computed), which
   never crosses a >0 threshold and the element never reveals.
   --------------------------------------------------------------------- */

/* English labels / headings: quiet left-to-right clip reveal, no shift. */
.js [data-mo="mask-en"],
.js [data-mo="mask-en-2"] {
  opacity: 0;
  clip-path: inset(0 100% 0 0);
  transition: opacity .7s ease, clip-path .7s cubic-bezier(.22,.8,.3,1);
}
.js [data-mo="mask-en-2"] { transition-delay: .12s; }
.js [data-mo="mask-en"].is-mo,
.js [data-mo="mask-en-2"].is-mo {
  opacity: 1;
  clip-path: inset(0 0% 0 0);
}

/* Japanese headings: readability first — opacity + a small vertical
   settle only, no masking, and a touch later than the English above. */
.js [data-mo="fade-jp"] {
  opacity: 0;
  transform: translateY(12px);
  transition: opacity .9s ease .2s, transform .9s cubic-bezier(.22,.8,.3,1) .2s;
}
.js [data-mo="fade-jp"].is-mo { opacity: 1; transform: translateY(0); }

/* Long-form body copy: opacity only, slow, no translate — it should
   read as "settling into place", not moving. */
.js [data-mo="body"] {
  opacity: 0;
  transition: opacity 1.1s ease;
}
.js [data-mo="body"].is-mo { opacity: 1; }

/* Link / CTA affordance: brief, small lift — distinct from the quiet
   body fade so links still read as interactive elements. */
.js [data-mo="link"] {
  opacity: 0;
  transform: translateY(8px);
  transition: opacity .5s ease, transform .5s cubic-bezier(.22,.8,.3,1);
}
.js [data-mo="link"].is-mo { opacity: 1; transform: translateY(0); }

/* Plain opacity-only fade for a photo that should stay quiet — no
   slide, no crop, no scale. Used for PHOTO18 (the full-bleed photo +
   overlay copy section): that photo is already visually strong on its
   own, so per feedback it gets the same restrained treatment as the
   text instead of an entrance effect. */
.js [data-mo="fade"] {
  opacity: 0;
  transition: opacity 1.1s ease;
}
.js [data-mo="fade"].is-mo { opacity: 1; }

/* ---------------------------------------------------------------------
   Stagger lists (.spec, .svc-list) — each item gets its own small,
   alternating-direction slide + an incremental delay, so a list never
   reveals as one uniform fade-up block.
   --------------------------------------------------------------------- */
.js [data-mo="stagger"] > li {
  opacity: 0;
  transform: translateX(-14px);
  transition: opacity .7s ease, transform .7s cubic-bezier(.22,.8,.3,1);
}
.js [data-mo="stagger"] > li:nth-child(even) { transform: translateX(14px); }
.js [data-mo="stagger"].is-mo > li { opacity: 1; transform: translateX(0); }

.js [data-mo="stagger"].is-mo > li:nth-child(1) { transition-delay: 0s; }
.js [data-mo="stagger"].is-mo > li:nth-child(2) { transition-delay: .08s; }
.js [data-mo="stagger"].is-mo > li:nth-child(3) { transition-delay: .16s; }
.js [data-mo="stagger"].is-mo > li:nth-child(4) { transition-delay: .24s; }
.js [data-mo="stagger"].is-mo > li:nth-child(5) { transition-delay: .32s; }
.js [data-mo="stagger"].is-mo > li:nth-child(6) { transition-delay: .4s; }

/* ---------------------------------------------------------------------
   Photo entrances that get image-load gating in js/motion.js
   (showPhoto()) instead of firing purely off scroll position — each is
   a single, single-axis transform + opacity transition, nothing else,
   and nothing writes to their transform again after it lands:

   [data-mo="photo"]    — Studio figure itself: translateX only (horizontal).
   [data-mo="photo-up"] — PHOTO16: a thin wrapper div around the <img>
                           inside .ed16__frame (NOT the <img> itself —
                           see below), translateY only (vertical).

   Deliberately different axes from each other on purpose (per
   feedback: PHOTO16 must not repeat control-room-b.jpg's horizontal
   slide). Both used to carry extra effects (scale, clip-path crop
   reveal, continuous scroll-linked pan) that could end up visibly
   overlapping on a real connection — read as the photo arriving
   diagonally, or stalling mid-transform while still loading. Each now
   has exactly one moving property besides opacity, and js/motion.js
   starts the transition only once the specific <img> is actually
   loaded (img.complete, or its load/error event, with a fallback
   timer), not on scroll timing — see showPhoto() there.

   PHOTO16's entrance sits on a wrapper, not the <img>, because the
   <img> itself is already spoken for on two fronts that must stay
   untouched: style.css gives it its own `transform` at <=767px
   (absolute + 108% height + translateY(-50%), for the "overscanned,
   centred" mobile crop), and js/motion.js's phoneBreathe (below) used
   to additionally write an inline transform to it every scroll tick on
   phones. Putting this entrance's transform on the SAME element as
   either would mean one of them wins outright (same property, same
   element) rather than combining — which is exactly the kind of
   conflict this whole fix is about removing. The wrapper needs
   width/height 100% (see .ed16__photo-up below) so the <img>'s own
   percentage-based sizing/positioning keeps resolving correctly
   against it. .ed16__frame img was also removed from the phoneBreathe
   call entirely (PHOTO17/18 keep it, unchanged) — per feedback PHOTO16
   must have no scroll-linked or rAF-driven transform at any width. */
.ed16__photo-up { display: block; width: 100%; height: 100%; }

.js [data-mo="photo"] {
  opacity: 0;
  transform: translateX(-60px);
  transition: opacity .85s ease, transform .85s cubic-bezier(.19,1,.22,1);
}
.js [data-mo="photo"].is-mo {
  opacity: 1;
  transform: translateX(0);
}
.js [data-mo="photo-up"] {
  opacity: 0;
  transform: translateY(50px);
  transition: opacity .85s ease, transform .85s cubic-bezier(.19,1,.22,1);
}
.js [data-mo="photo-up"].is-mo {
  opacity: 1;
  transform: translateY(0);
}

/* ---------------------------------------------------------------------
   Editorial photo PHOTO17 — additive crop-reveal only, layered on top
   of the EXISTING style.css reveal (.ed-photo fade-up +
   .ed17__frame lift), which is left completely untouched. clip-path is
   a property style.css never sets on this exact element, so nothing
   here overrides or fights the current behaviour — it only adds a
   crop-opening motion that style.css's plain fade/lift doesn't have.
   Transform is intentionally left alone on PHOTO17's <img> — it already
   carries its own transform at some width (parallax >=768px, phone
   "breathing" <=767px) and adding another transform rule here would
   simply replace, not combine with, theirs.
   PHOTO16 no longer uses [data-clip] (see [data-mo="photo-up"] above);
   PHOTO18 doesn't either — per feedback its photo is already strong
   full-bleed and stays quiet, using the plain [data-mo="fade"]
   opacity-only variant above instead.
   [data-clip] is triggered by the SAME .is-inview class js/motion.js
   already adds to the parent .ed-photo section (unchanged logic) — no
   new JS needed.
   --------------------------------------------------------------------- */
.js [data-clip="v-center"] {
  clip-path: inset(40% 0 40% 0);
  opacity: 0;
  transition: clip-path 1.1s cubic-bezier(.19,1,.22,1) .1s, opacity 1.1s ease .1s;
}
.js .ed-photo.is-inview [data-clip="v-center"] {
  clip-path: inset(0 0 0 0%);
  opacity: 1;
}

/* ---------------------------------------------------------------------
   Reduced motion: everything visible immediately, no animation of any
   kind. js/motion.js also skips the scroll listeners entirely in this
   case, but the CSS fallback here holds regardless of JS.
   --------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  [data-mo],
  [data-clip] {
    opacity: 1 !important;
    transform: none !important;
    clip-path: none !important;
    animation: none !important;
    transition: none !important;
  }
}
