@charset "UTF-8";

/* =============================================================================
   HONDA × Onitsuka Tiger — LP stylesheet
   Phase 1 (static): this file owns layout, design tokens and every animation
   INITIAL state. Phase 2 (assets/js/app.js) owns the final values only.

   ---------------------------------------------------------------------------
   ANIMATION CONTRACT WITH assets/js/app.js  (Phase 2)
   ---------------------------------------------------------------------------
   1. `<html class="is-js">`
      Added by the INLINE SCRIPT in index.html's <head>, i.e. before the first
      paint — app.js runs after five CDN <script>s at the end of <body>, and
      arming there would let the loader overlay and the KV flash their static
      state first. app.js re-asserts it as its own first statement (idempotent)
      and REMOVES it when GSAP never arrived. That same head script also runs a
      5s failsafe: if `is-booted` (set at the top of app.js's boot) never lands,
      it strips `is-js` again, so a dead app.js can never lock the screen.
      Every "hidden until revealed" initial state in this file is gated behind
      `.is-js`, so with JS disabled / not yet loaded the page renders fully
      visible. Never author a bare `opacity: 0` outside an `.is-js` gate.

   2. `<html class="is-loaded">`
      app.js adds it when the opening sequence finishes (§11 — 2600ms; under
      reduced motion the sequence is skipped and this stays at ~100ms).
      KV children fade/slide in with staggered transition-delay (0.1 / 0.3 /
      0.5 / 0.7s) defined below.

   3. `.js-onscreen` + `.is-active`
      ScrollTrigger / IntersectionObserver adds `.is-active` when the element
      enters the viewport. Transition (not keyframes) resolves opacity+translate.
      Modifiers: `--wipe` (horizontal clip), `--left`, `--right`.

   3b. `.js-clip` + `.is-active`
      Image wipe. Sets clip-path ONLY (never opacity/transform), so it can be
      combined with a scrub parallax target on the same element. The open state
      keeps a -30px negative inset so offset box-shadows are not clipped away.

   3c. `.js-split` + `.is-active`
      app.js splits the element's text into `<span class="c-char">` (grouped by
      `<span class="c-word">` for non-CJK words so they cannot break mid-word)
      and writes `--char-i` on each. The stagger is CSS
      (`transition-delay: calc(var(--char-i) * 40ms)`). The original string is
      preserved on the element's `aria-label`; chars are `aria-hidden`.
      app.js must run the splitter BEFORE initReveal.

   4. `.js-loop`
      Pure CSS keyframe decorations (they animate `transform`, which outranks
      inline styles). app.js must NOT touch these — when a looping decoration
      also needs a scrub, the scrub goes on a dedicated PARENT wrapper
      (`.p-hxot-kv__mark-wrap`, `.p-hxot-shoes__stripe-wrap`,
      `.p-hxot-intro__bg-item-2 / -5 / -8`, `.p-hxot-shoes__tiger`,
      `.p-hxot-detail__tiger`, `.p-hxot-movie__tiger`).
      The two decorative marks are `.c-stripe` (inline svg, tinted through
      `fill: currentColor`) and `.c-tiger` (a CSS `mask-image` of
      assets/images/tiger_head.png, tinted through `background-color:
      currentColor`). Either way the host element only ever sets `color`.
      Placement rule: on the ink sections the mark is cream or yellow, on the
      light ones it is inked — and the two marks are mixed across the page
      (currently 6 stripes / 7 tigers, after #gallery's stripe was swapped for a
      tiger head on user request; it was 7 / 6).
      The MARQUEES are deliberately outside this system: they carry the two
      brand lockups (`.p-hxot-marquee__logo`) and nothing else.

   5. `.js-scroll`
      Anchor links. app.js hooks ScrollToPlugin with a --header-height offset.

   6. scrub parallax targets
      Their initial transform is authored here, gated by `.is-js` (e.g.
      `.is-js .p-hxot-intro__bg-item-1 { transform: translateY(40px) }`), so the
      static page is un-offset and JS arming is what introduces the start value.
      app.js only writes the FINAL value via
      `gsap.to(..., { scrub: 1, invalidateOnRefresh: true })`. Never `gsap.from`.
      Every scrub initial transform MUST also be reset inside the
      `prefers-reduced-motion: reduce` block (app.js registers no tween there,
      so an un-reset offset would be permanent).
      Full selector list: see the block comment at the bottom of this file.

   7. `.c-blend` (section background-color scrub)
      A masked strip pinned to a section's bottom padding, never overlapping
      content. app.js scrubs its `backgroundColor` towards the NEXT section's
      colour. `<body>` / the section itself are never recoloured.

   8. `.c-ghost` (oversized outline type) / `.c-badge` (rotating textPath)
      Decorative scrub targets. `.c-ghost` sweeps on x, `.c-badge__ring`
      rotates 360°. Both sit at z-index 0 behind `position: relative; z-index: 1`
      content wrappers.

   9. `.js-route` (#route — the scroll-drawn arrow road)
      The one place app.js generates DOM. It measures the stage, builds the
      zigzag svg from that width and writes the stage's height, the card
      top/left/width and the svg's viewBox — GEOMETRY only. Everything that
      MOVES still obeys the rules above:
        - the two drawn paths carry `pathLength` (app.js) so their dash space is
          normalised; this file owns `stroke-dasharray` + the start
          `stroke-dashoffset` and app.js scrubs only the final 0, per §6.
          The dash number is NOT 1: GSAP rounds px-unit CSS values to whole
          numbers, so 1 → 0 could only ever render "nothing" or "everything".
        - the arrow head and the rolling decorations are positioned with the SVG
          `transform` ATTRIBUTE, never a CSS transform, so the two can never
          fight over the same element.
        - nodes / chevrons / ticks / cards resolve on an `.is-hit` class plus a
          transition here, exactly like `.js-onscreen` (and, like it, `.is-hit`
          is never removed once set).
      The stage and the visually-hidden static `<ol>` are both gated behind
      `@media (prefers-reduced-motion: no-preference)`: under reduce app.js
      registers nothing at all and the plain list is what the section shows.

  10. `.js-movie` / `.js-vmodal` (#movie — the video modal)
      Triggers are `<button class="js-movie" data-video-id data-poster
      data-label>`. app.js fills `.js-vmodal-stage` on open and EMPTIES it on
      close, so the YouTube iframe is destroyed and playback always stops.
      A `data-video-id` starting with `PLACEHOLDER_` builds a styled poster
      instead of an iframe (the video is not decided yet).
      While open: app.js calls `lenis.stop()` AND puts `is-modal-open` on
      <html>; this file kills `overflow` on both <html> and <body> and pads
      <body> / `.l-header` by `--scrollbar-gap` (measured by app.js) so nothing
      jumps. Closing reverses both halves.
      The modal is NOT motion-gated: it opens under
      `prefers-reduced-motion: reduce` too — only its transitions are dropped
      there (see the reduce block below).

  11. `.c-loader` / `.js-loader` (the opening sequence)
      A full-screen #ffffff overlay, first element in <body>, above BOTH the
      header (100) and the video modal (200) at z-index 300. It is
      `display: none` by default and only `display: grid` under `.is-js`
      (contract §1), so JS-off never sees it.
      app.js ADDS one class per step and never removes one — the classes are
      cumulative, so each rule keeps applying once it has fired, and every
      rule below therefore has to be authored in step order:
        .is-honda    0ms     Honda wing SLAMS in: scale 2.5 → 0.955 → 1 with a
                             red shockwave ring and a 2px, 140ms jolt of the
                             stage at the impact, then a small float (860ms)
        .is-swap    1100ms   Honda fades out (250ms), so it is at 0 by 1350
                    1350ms   — 150ms of EMPTY overlay. The two lockups are
                             never on screen at the same time; step ② also has
                             to kill the slam animation or it would revive the
                             Honda logo, see the rule itself.
        .is-tiger   1500ms   Onitsuka Tiger fades + scales in  (400ms)
        .is-zoom    2250ms   the tiger logo scales 1 → 7 while the overlay
                             saturates to white and drops to opacity 0 (700ms)
        .is-done    2950ms   display:none + visibility:hidden + pointer-events:
                             none, and <html> gets `is-loaded` (§2)
      The timing is plain `setTimeout` class hops — NOT a gsap.timeline — so
      §6's scrub rules do not apply here; every transition lives in this file.
      Step ① is the one part built out of `@keyframes` rather than a transition
      (a slam with an overshoot is multi-stage by nature); the rest are plain
      transitions. Its keyframes END on exactly the declared `.is-honda` values,
      because a transition's before-change style ignores animation-derived
      values and any mismatch would show as a one-frame jump into `.is-swap`.
      Scroll is locked for the whole sequence with `lenis.stop()` (Lenis
      preventDefaults wheel/touch while stopped) plus a wheel/touchmove
      listener of app.js's own, because Lenis may not exist. No `overflow:
      hidden` lock like §10's: the scrollbar disappearing would shift the page
      underneath exactly as the overlay fades out.
      Under `prefers-reduced-motion: reduce` the overlay is `display: none`
      outright and app.js skips straight to `is-loaded`.
   ========================================================================== */

/* ---------------------------------------------------------------- 1. tokens */
:root {
  /* palette */
  --color-bg: #f4f1ec;
  --color-ink: #111111;
  --color-yellow: #f7b500;
  --color-red: #e60020;
  --color-white: #ffffff;
  --color-shadow: #111111;
  --color-line: rgba(17, 17, 17, 0.16);
  --color-muted: rgba(17, 17, 17, 0.62);

  /* type */
  --font-jp: "Zen Kaku Gothic New", "Hiragino Kaku Gothic ProN", "Hiragino Sans",
    "Yu Gothic", meiryo, sans-serif;
  --font-en: "Archivo Black", "Zen Kaku Gothic New", sans-serif;

  --fs-body: min(1.1111vw, 16px);
  --fs-body-sm: min(0.9722vw, 14px);
  --fs-lead: min(1.3888vw, 20px);
  --fs-heading-en: min(5.5555vw, 84px);
  --fs-heading-jp: min(1.6666vw, 24px);
  --fs-label: min(0.8333vw, 12px);

  --lh-body: 2;
  --lh-heading: 1.15;

  /* layout — PC design base 1440px */
  --header-height: 72px;
  --site-padding: min(6.25vw, 90px);
  --container: 1240px;
  --offset-shadow: 20px 20px 0 0 var(--color-shadow);
  --section-gap: min(11.1111vw, 160px);
}

@media (max-width: 767px) {
  :root {
    /* SP design base 375px */
    --fs-body: min(3.7333vw, 15px);
    --fs-body-sm: min(3.2vw, 13px);
    --fs-lead: min(4.2666vw, 17px);
    --fs-heading-en: min(9.6vw, 40px);
    --fs-heading-jp: min(3.7333vw, 15px);
    --fs-label: min(2.9333vw, 11px);
    --lh-body: 1.95;

    --header-height: 56px;
    --site-padding: min(6.4vw, 26px);
    --offset-shadow: 8px 8px 0 0 var(--color-shadow);
    --section-gap: min(21.3333vw, 90px);
  }
}

/* ------------------------------------------------------------------ 2. base */
*,
*::before,
*::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
}
/* Lenis writes the scroll position every frame; native smooth scrolling would
   re-interpolate each of those writes and lag permanently behind (Lenis
   requires this property to be off). Keep it only for the no-JS fallback,
   where anchor jumps have nothing else to smooth them. */
/* wrapped in the media query because `html:not(.is-js)` (0,1,1) would otherwise
   out-specify the `html { scroll-behavior: auto }` reduced-motion rule below. */
@media (prefers-reduced-motion: no-preference) {
  html:not(.is-js) {
    scroll-behavior: smooth;
  }
}

body {
  margin: 0;
  background-color: var(--color-bg);
  color: var(--color-ink);
  font-family: var(--font-jp);
  font-size: var(--fs-body);
  font-weight: 500;
  line-height: var(--lh-body);
  font-feature-settings: "palt";
  overflow-x: clip;
}

img { display: block; max-width: 100%; height: auto; }
a { color: inherit; text-decoration: none; }
ul, ol, dl, dd { margin: 0; padding: 0; list-style: none; }
h1, h2, h3, h4, p, figure { margin: 0; }
button { font: inherit; color: inherit; }

::selection { background: var(--color-yellow); color: var(--color-ink); }

.u-sr-only {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.u-pc { display: block; }
.u-sp { display: none; }
@media (max-width: 767px) {
  .u-pc { display: none; }
  .u-sp { display: block; }
}

/* sprite host for the Onitsuka stripe mark */
.u-svg-sprite { position: absolute; width: 0; height: 0; overflow: hidden; }

.c-stripe {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1563.73 / 654.11;
  fill: currentColor;
}

/* Onitsuka tiger-head mark. The PNG (assets/images/tiger_head.png, 310×327,
   unmultiplied from materials/logos/tiger_head.png) is used as an ALPHA MASK,
   not as an image: the visible colour is `background-color`, which defaults to
   `currentColor` here so a host element tints it with plain `color` — exactly
   like `.c-stripe` does through `fill: currentColor`. That is what lets the
   same asset read black on the cream sections and cream/yellow on the ink ones.
   Longhands (not the `mask` shorthand) so the -webkit- prefixed set stays in
   step property by property. */
.c-tiger {
  display: block;
  width: 100%;
  aspect-ratio: 310 / 327;
  background-color: currentColor;
  -webkit-mask-image: url(../images/tiger_head.png);
  mask-image: url(../images/tiger_head.png);
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
}

/* play button on a video card. Its `transform` is the centring translate plus a
   hover scale — it is NEVER a scrub target, so this cannot collide with §6. */
.c-play {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  display: grid;
  place-items: center;
  width: min(6.94vw, 100px);
  height: min(6.94vw, 100px);
  background: var(--color-white);
  border: 2px solid var(--color-ink);
  border-radius: 50%;
  pointer-events: none;
  transition: transform 0.38s cubic-bezier(0.16, 1, 0.3, 1), background-color 0.3s ease;
}
.c-play__tri {
  width: 0;
  height: 0;
  margin-left: 18%;
  border-left: min(1.66vw, 24px) solid var(--color-ink);
  border-top: min(1.11vw, 16px) solid transparent;
  border-bottom: min(1.11vw, 16px) solid transparent;
}
.c-play--sm { width: min(3.61vw, 52px); height: min(3.61vw, 52px); border-width: 2px; }
.c-play--sm .c-play__tri {
  border-left-width: min(0.9vw, 13px);
  border-top-width: min(0.62vw, 9px);
  border-bottom-width: min(0.62vw, 9px);
}

/* duration chip on a video card (dummy values — see the note in the section) */
.c-chip {
  position: absolute;
  right: min(0.83vw, 12px);
  bottom: min(0.83vw, 12px);
  padding: 3px min(0.69vw, 10px);
  background: var(--color-yellow);
  border: 2px solid var(--color-ink);
  color: var(--color-ink);
  font-family: var(--font-en);
  font-size: var(--fs-label);
  line-height: 1.5;
  letter-spacing: 0.08em;
  pointer-events: none;
}
.c-chip--sm { right: min(0.41vw, 6px); bottom: min(0.41vw, 6px); padding: 2px min(0.55vw, 8px); }

/* grid items must not blow out their track on long unbreakable English words */
.p-hxot-about__grid > *,
.p-hxot-bike__grid > *,
.p-hxot-shoes__grid > *,
.p-hxot-detail__visual > *,
.p-hxot-detail__list > *,
.p-hxot-spec__grid > * { min-width: 0; }

.l-container {
  width: 100%;
  max-width: calc(var(--container) + var(--site-padding) * 2);
  margin-inline: auto;
  padding-inline: var(--site-padding);
}

/* ------------------------------------------------- 3. animation base states */

/* Reveal-on-scroll. Visible by default; `.is-js` (added by app.js) arms the
   hidden initial state, `.is-active` (added by ScrollTrigger) resolves it. */
.js-onscreen {
  transition:
    opacity 0.9s cubic-bezier(0.33, 1, 0.68, 1),
    transform 0.9s cubic-bezier(0.33, 1, 0.68, 1);
}
.is-js .js-onscreen { opacity: 0; transform: translateY(48px); }
.is-js .js-onscreen.is-active { opacity: 1; transform: translateY(0); }

.is-js .js-onscreen--wipe { opacity: 1; transform: none; clip-path: inset(0 100% 0 0); transition: clip-path 1s cubic-bezier(0.215, 0.61, 0.355, 1); }
.is-js .js-onscreen--wipe.is-active { clip-path: inset(0 0 0 0); }

.is-js .js-onscreen--left { transform: translateX(-64px); }
.is-js .js-onscreen--left.is-active { transform: translateX(0); }

.is-js .js-onscreen--right { transform: translateX(64px); }
.is-js .js-onscreen--right.is-active { transform: translateX(0); }

/* clip-path wipe. Touches clip-path ONLY, so an element can be a scrub parallax
   target at the same time. The -30px negative insets keep offset box-shadows
   inside the clip region. */
.js-clip { transition: clip-path 1.15s cubic-bezier(0.76, 0, 0.24, 1); }
.is-js .js-clip { clip-path: inset(0 -30px 100% -30px); }
.is-js .js-clip.is-active { clip-path: inset(0 -30px -30px -30px); }

/* per-character heading stagger (spans are generated by app.js) */
.c-word { display: inline-block; white-space: nowrap; }
.js-split .c-char { display: inline-block; }
.is-js .js-split .c-char {
  opacity: 0;
  transform: translateY(0.42em) rotate(5deg);
  transition:
    opacity 0.62s cubic-bezier(0.33, 1, 0.68, 1),
    transform 0.72s cubic-bezier(0.16, 1, 0.3, 1);
  transition-delay: calc(var(--char-i, 0) * 40ms);
}
.is-js .js-split.is-active .c-char { opacity: 1; transform: translateY(0) rotate(0deg); }

/* CSS-only loop decorations (no jQuery, no GSAP) */
.js-loop { animation: floatY 4s ease-in-out infinite; }
.js-loop--swing { animation: swing 3.2s ease-in-out infinite alternate; }
.js-loop--spin { animation: spin 22s linear infinite; }
.js-loop--slow { animation-duration: 6s; }

@keyframes marquee {
  from { transform: translateX(0); }
  to { transform: translateX(-100%); }
}
@keyframes marquee-reverse {
  from { transform: translateX(-100%); }
  to { transform: translateX(0); }
}
@keyframes floatY {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-18px); }
}
@keyframes swing {
  from { transform: rotate(-5deg); }
  to { transform: rotate(5deg); }
}
@keyframes spin {
  from { transform: rotate(0); }
  to { transform: rotate(360deg); }
}
@keyframes scrollCue {
  0% { transform: scaleY(0); transform-origin: top; }
  45% { transform: scaleY(1); transform-origin: top; }
  55% { transform: scaleY(1); transform-origin: bottom; }
  100% { transform: scaleY(0); transform-origin: bottom; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .p-hxot-marquee__item,
  .js-loop,
  .p-hxot-kv__scroll-bar {
    animation: none !important;
  }
  .is-js .js-onscreen,
  .is-js .js-clip {
    opacity: 1 !important;
    transform: none !important;
    clip-path: none !important;
    transition: none !important;
  }
  .is-js .js-split .c-char {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
  .p-hxot-kv__anim { opacity: 1 !important; transform: none !important; transition: none !important; }

  /* The opening sequence (contract §11) is motion, whole and entire: there is
     no reduced version of it. app.js skips every step and goes straight to
     `is-loaded`, and the overlay never renders. */
  .c-loader,
  .is-js .c-loader { display: none !important; }

  /* app.js registers ZERO scrub tweens under reduce (both matchMedia queries
     carry `prefers-reduced-motion: no-preference`), so every `.is-js` scrub
     start offset has to be neutralised here or it would stick forever. */
  .is-js .p-hxot-kv__media-shift,
  .is-js .p-hxot-kv__mark-wrap,
  .is-js .p-hxot-kv__inner,
  .is-js .p-hxot-intro__bg-item,
  .is-js .p-hxot-about__img-main,
  .is-js .p-hxot-about__img-sub,
  .is-js .p-hxot-bike__hero,
  .is-js .p-hxot-bike__card,
  .is-js .p-hxot-bike__badge,
  .is-js .p-hxot-shoes__figure--01,
  .is-js .p-hxot-shoes__figure--02,
  .is-js .p-hxot-shoes__stripe-wrap,
  .is-js .p-hxot-shoes__tiger,
  .is-js .p-hxot-detail__img--wide,
  .is-js .p-hxot-detail__img--tall,
  .is-js .p-hxot-detail__deco,
  .is-js .p-hxot-detail__tiger,
  .is-js .p-hxot-movie__tiger,
  .is-js .p-hxot-movie__stripe,
  .is-js .p-hxot-gallery__tiger,
  .is-js .p-hxot-spec__panel-logo,
  .is-js .p-hxot-route__card-in,
  .is-js .p-hxot-route__node,
  .is-js .c-ghost {
    transform: none !important;
  }
  .is-js .p-hxot-route__card-in,
  .is-js .p-hxot-route__node { opacity: 1 !important; transition: none !important; }
  .c-ghost, .c-badge { display: none !important; }

  /* The video modal still OPENS under reduce (contract §10) — only its motion
     is switched off, never the modal itself. */
  .c-vmodal,
  .c-vmodal__close,
  .c-play,
  .p-hxot-movie__main-img,
  .p-hxot-movie__veil { transition: none !important; }
  .c-vmodal { opacity: 1 !important; }

  /* #route needs nothing here: app.js bails out of initRoute before creating a
     single ScrollTrigger, and both the stage's `display: block` and the static
     list's visually-hidden rule are gated behind `no-preference`, so this
     section falls back to its plain `<ol>` on its own. */
}

/* ---------------------------------------------------------------- 4. header */
.l-header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 100;
  height: var(--header-height);
  display: flex;
  align-items: center;
  background: rgba(244, 241, 236, 0.86);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--color-line);
}

.l-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  width: 100%;
}

.l-header__logo {
  display: flex;
  align-items: center;
  gap: min(0.83vw, 12px);
  font-family: var(--font-en);
  font-size: var(--fs-label);
  letter-spacing: 0.08em;
  white-space: nowrap;
}
.l-header__logo-img {
  display: block;
  width: auto;
  object-fit: contain;
}
/* 実寸は 522x420 / 582x375。ウイングは線的で軽く、鬼塚は面で重いため高さを振り分けて視覚量を揃える */
.l-header__logo-img--honda { height: 40px; }
.l-header__logo-img--onitsuka { height: 34px; }
.l-header__logo-x { color: var(--color-red); }

.l-header__nav { display: block; }
.l-header__nav-list { display: flex; align-items: center; gap: min(2.36vw, 34px); }
.l-header__nav-link {
  position: relative;
  font-family: var(--font-en);
  font-size: var(--fs-label);
  letter-spacing: 0.14em;
  padding-block: 6px;
}
.l-header__nav-link::after {
  content: "";
  position: absolute;
  left: 0; bottom: 0;
  width: 100%; height: 2px;
  background: var(--color-yellow);
  transform: scaleX(0);
  transform-origin: right center;
  transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}
@media (hover: hover) and (pointer: fine) {
  .l-header__nav-link:hover::after { transform: scaleX(1); transform-origin: left center; }
}

@media (max-width: 767px) {
  .l-header__nav { display: none; }
  .l-header__logo-img--honda { height: 30px; }
  .l-header__logo-img--onitsuka { height: 26px; }
}

.l-main { display: block; padding-top: var(--header-height); }

/* -------------------------------------------------------- 5. shared parts */
.p-hxot-heading { display: flex; flex-direction: column; gap: min(0.55vw, 8px); }
.p-hxot-heading__label {
  font-family: var(--font-en);
  font-size: var(--fs-label);
  letter-spacing: 0.24em;
  color: var(--color-muted);
}
.p-hxot-heading__main {
  font-family: var(--font-en);
  font-size: var(--fs-heading-en);
  line-height: var(--lh-heading);
  letter-spacing: -0.01em;
  text-transform: uppercase;
}
.p-hxot-heading__jp {
  display: inline-block;
  font-size: var(--fs-heading-jp);
  font-weight: 700;
  letter-spacing: 0.08em;
}
.p-hxot-heading__rule {
  display: block;
  width: min(8.33vw, 120px);
  height: 6px;
  margin-top: min(0.83vw, 12px);
  background: var(--color-yellow);
}
@media (max-width: 767px) {
  .p-hxot-heading__rule { width: min(21.33vw, 80px); height: 4px; }
}

.c-button {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  min-width: min(20.8vw, 300px);
  padding: min(1.38vw, 20px) min(2.7vw, 40px);
  background: var(--color-yellow);
  border: 2px solid var(--color-ink);
  box-shadow: 8px 8px 0 0 var(--color-shadow);
  font-family: var(--font-en);
  font-size: var(--fs-body);
  letter-spacing: 0.1em;
  line-height: 1.2;
  transition: transform 0.25s ease, box-shadow 0.25s ease;
}
.c-button__arrow { width: 22px; height: 10px; flex: none; }
@media (hover: hover) and (pointer: fine) {
  .c-button:hover { transform: translate(6px, 6px); box-shadow: 2px 2px 0 0 var(--color-shadow); }
}
@media (max-width: 767px) {
  .c-button { min-width: min(72vw, 300px); box-shadow: 5px 5px 0 0 var(--color-shadow); }
}

/* oversized outline type that sweeps across the section on scrub. Lives at
   z-index 0; every section that hosts one gives its content wrapper z-index 1
   and keeps `overflow: hidden` so the sweep never widens the document. */
.c-ghost {
  position: absolute;
  z-index: 0;
  font-family: var(--font-en);
  font-size: min(11.1vw, 160px);
  line-height: 0.86;
  letter-spacing: -0.02em;
  white-space: nowrap;
  color: transparent;
  pointer-events: none;
  user-select: none;
}

/* circular textPath badge — the ring rotates on scrub, the core stays put */
.c-badge {
  position: absolute;
  z-index: 3;
  display: grid;
  place-items: center;
  width: min(9.7vw, 140px);
  height: min(9.7vw, 140px);
  pointer-events: none;
}
.c-badge__ring { grid-area: 1 / 1; width: 100%; height: 100%; overflow: visible; }
.c-badge__text {
  font-family: var(--font-en);
  font-size: 14px;
  letter-spacing: 0.04em;
  fill: currentColor;
}
.c-badge__core {
  grid-area: 1 / 1;
  font-family: var(--font-en);
  font-size: min(0.83vw, 12px);
  line-height: 1.2;
  letter-spacing: 0.04em;
  text-align: center;
}

/* section-to-section background-color scrub strip. Sits inside the host
   section's BOTTOM PADDING only (height === --section-gap) so it can never
   darken text, and fades in from the top through a mask. */
.c-blend {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 0;
  height: var(--section-gap);
  pointer-events: none;
  -webkit-mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 1) 68%);
  mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 1) 68%);
}

/* --------------------------------------------- 5b. video modal (contract §10)
   Markup is static at the end of <body>; app.js only fills / empties
   `.js-vmodal-stage` and toggles `hidden` + `.is-open`. Closing empties the
   stage synchronously, so the iframe is destroyed and playback stops — there is
   deliberately no fade-OUT that would let audio run on. */
.c-vmodal {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: max(var(--site-padding), 20px);
  opacity: 0;
  transition: opacity 0.32s ease;
}
.c-vmodal[hidden] { display: none; }
.c-vmodal.is-open { opacity: 1; }
.c-vmodal__bg { position: absolute; inset: 0; background: rgba(0, 0, 0, 0.9); cursor: pointer; }
.c-vmodal__panel { position: relative; z-index: 1; width: min(100%, 1100px); }
.c-vmodal__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: min(1.66vw, 24px);
  margin-bottom: min(0.83vw, 12px);
}
.c-vmodal__title {
  font-family: var(--font-en);
  font-size: var(--fs-label);
  letter-spacing: 0.2em;
  line-height: 1.6;
  color: rgba(244, 241, 236, 0.78);
}
.c-vmodal__close {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px min(1.11vw, 16px);
  background: transparent;
  border: 2px solid rgba(244, 241, 236, 0.6);
  color: var(--color-bg);
  font-family: var(--font-en);
  font-size: var(--fs-label);
  letter-spacing: 0.16em;
  line-height: 1;
  cursor: pointer;
  transition: background-color 0.25s ease, color 0.25s ease, border-color 0.25s ease;
}
.c-vmodal__close-x { font-size: 1.4em; line-height: 1; }
@media (hover: hover) and (pointer: fine) {
  .c-vmodal__close:hover { background: var(--color-yellow); border-color: var(--color-yellow); color: var(--color-ink); }
}
.c-vmodal__close:focus-visible { outline: 3px solid var(--color-yellow); outline-offset: 3px; }
.c-vmodal__stage {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  max-height: calc(100svh - var(--header-height) - 80px);
  margin-inline: auto;
  background: #000000;
  border: 2px solid var(--color-bg);
  overflow: hidden;
}
.c-vmodal__stage iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
/* placeholder poster: shown instead of an iframe while `data-video-id` still
   starts with "PLACEHOLDER_" */
.c-vmodal__poster { position: absolute; inset: 0; display: grid; place-items: center; }
.c-vmodal__poster img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0.3; }
.c-vmodal__poster-note {
  position: relative;
  z-index: 1;
  padding: min(2.22vw, 32px);
  text-align: center;
  color: var(--color-bg);
}
.c-vmodal__poster-title {
  display: block;
  font-family: var(--font-en);
  font-size: min(2.22vw, 32px);
  letter-spacing: 0.08em;
  line-height: 1.2;
  color: var(--color-yellow);
  margin-bottom: min(1.11vw, 16px);
}
.c-vmodal__poster-text { display: block; font-size: var(--fs-body-sm); line-height: 2; }
.c-vmodal__poster-sub {
  display: inline-block;
  margin-top: min(1.11vw, 16px);
  padding: 4px 12px;
  border: 1px solid rgba(244, 241, 236, 0.45);
  font-family: var(--font-en);
  font-size: var(--fs-label);
  letter-spacing: 0.14em;
  color: rgba(244, 241, 236, 0.8);
}

/* Scroll lock while the modal is open. app.js also calls `lenis.stop()`, but
   Lenis is not registered under reduced motion — the modal still opens there,
   so the lock has to hold on its own. `--scrollbar-gap` is measured by app.js
   and pads the two elements that would otherwise jump when the bar disappears. */
.is-modal-open { overflow: hidden; }
.is-modal-open body { overflow: hidden; padding-right: var(--scrollbar-gap, 0px); }
.is-modal-open .l-header { padding-right: var(--scrollbar-gap, 0px); }
@media (max-width: 767px) {
  .c-vmodal { padding: 16px; }
  .c-vmodal__poster-title { font-size: min(6.4vw, 26px); }
  .c-vmodal__close { padding: 7px 12px; }
}

/* ----------------------------------------- 5c. opening loader (contract §11)
   Honda 単体 → Onitsuka Tiger 単体 → OT ロゴがズームしながらホワイトアウト
   → KV。app.js は `.is-honda` / `.is-swap` / `.is-tiger` / `.is-zoom` /
   `.is-done` を「足すだけ」なので、後段のルールほど下に書く必要がある。
   `display: none` が既定値で、`.is-js` が付いたときだけ出る＝ JS 無効なら
   そもそも表示されない（契約 §1・白画面ロック回避）。 */
.c-loader { display: none; }

.is-js .c-loader {
  position: fixed;
  inset: 0;
  z-index: 300; /* > .l-header (100) / > .c-vmodal (200) */
  display: grid;
  place-items: center;
  background: var(--color-white);
  opacity: 1;
  /* ホワイトアウト。ease-in なので白がしばらく残ってから一気に抜ける */
  transition: opacity 0.7s cubic-bezier(0.5, 0, 0.75, 0);
}

/* 2枚を同じグリッドセルに重ねる＝入れ替わりで単体表示される */
.c-loader__stage {
  position: relative;
  display: grid;
  place-items: center;
  transform-origin: 50% 50%;
}

/* 着地の衝撃：Honda 赤のリングが一度だけ広がって消える。グリッドの外
   （position: absolute）に置いてセルの寸法に一切関与させない。
   中央寄せは `translate` 単体プロパティなので、`transform` のスケールと
   取り合いにならない。 */
.c-loader__shock {
  position: absolute;
  left: 50%;
  top: 50%;
  translate: -50% -50%;
  width: min(24vw, 250px);
  aspect-ratio: 1;
  border: 3px solid var(--color-red);
  border-radius: 50%;
  opacity: 0;
  pointer-events: none;
}
.c-loader__logo {
  grid-area: 1 / 1;
  width: auto;
  height: clamp(96px, 10.4vw, 150px);
  max-width: 74vw;
  object-fit: contain;
  opacity: 0;
  transform: scale(0.9);
  transform-origin: 50% 50%;
  transition: opacity 0.4s ease, transform 0.4s cubic-bezier(0.33, 1, 0.68, 1);
}
/* ワードマークは同じ高さだと翼マークより大きく見えるので少し詰める */
.c-loader__logo--tiger { height: clamp(78px, 8.4vw, 122px); }

/* ① 0ms — Honda 単体。ここだけ transition ではなく keyframes：
   「2.5 倍から叩き込まれて 0.955 まで潰れ、跳ね返って着地」という多段の緩急は
   1本の transition では書けない。宣言値（opacity 1 / scale 1）は残してあり、
   loaderSlam の 100% もそれと同一 — CSS Transitions の before-change style は
   アニメーション由来の値を含まないので、1100ms の `.is-swap` へ渡るときに
   ここが食い違うと 1 フレームだけ跳ねる。 */
.is-js .c-loader.is-honda .c-loader__logo--honda {
  opacity: 1;
  transform: scale(1);
  transition-duration: 0.18s; /* opacity は transition 側の担当（下記） */
  animation: loaderSlam 0.86s linear both;
}
/* 着地に合わせた 140ms の微振動（2px）。fill は none なので、終わったあとの
   ステージには transform が一切残らない＝後段のズームに影響しない。 */
.is-js .c-loader.is-honda .c-loader__stage {
  animation: loaderShake 0.14s linear 0.235s;
}
.is-js .c-loader.is-honda .c-loader__shock {
  animation: loaderShock 0.62s cubic-bezier(0.16, 0.7, 0.3, 1) 0.225s both;
}

/* 860ms。% は ms に読み替えて: 0 / 103 / 241 / 361 / 464 / 550 / 705 / 860。
   0 → 12% は「大きいまま浮かんで見えている」時間をわざと作る区間で、そこから
   103 → 241ms の 138ms で 2.05 → 0.955 まで一気に落ちる＝これが叩き込み。
   最初のイージングを前詰めにしすぎると 100ms でほぼ着地してしまい、大きい絵が
   1 フレームも読めない（実測で確認して差し替えた）。 */
/* transform だけを動かす。`opacity` を絶対にここへ入れないこと: 満了後も
   `both` で効き続けるプロパティに対して Chrome は transition を開始しないので、
   1100ms の `.is-swap` で 250ms かけて消えるはずの Honda が 1 フレームで
   パチンと消える（実測: 1.000 @1051ms → 0.000 @1102ms）。
   opacity は `.is-honda` / `.is-swap` の transition が持つ。 */
@keyframes loaderSlam {
  0% {
    transform: translateY(0) scale(2.6);
    animation-timing-function: cubic-bezier(0.3, 0, 0.6, 1);
  }
  12% {
    transform: translateY(0) scale(2.05);
    animation-timing-function: cubic-bezier(0.55, 0.02, 0.18, 1); /* 突っ込む */
  }
  28% {
    transform: translateY(0) scale(0.955); /* 着地 — 1 を通り越して潰れる */
    animation-timing-function: cubic-bezier(0.34, 1.3, 0.64, 1);
  }
  42% { transform: translateY(0) scale(1.03); }
  54% { transform: translateY(0) scale(0.993); }
  64% { transform: translateY(0) scale(1); }
  82% { transform: translateY(-4px) scale(1.004); } /* 着地後にわずかに浮く */
  100% { transform: translateY(0) scale(1); }
}
@keyframes loaderShake {
  0%, 100% { transform: translate(0, 0); }
  20% { transform: translate(-2px, 1px); }
  40% { transform: translate(2px, -2px); }
  60% { transform: translate(-2px, -1px); }
  80% { transform: translate(1px, 2px); }
}
/* 開始スケールはロゴとほぼ同径（250px × 0.85 ≒ 212px）から。0.28 で始めると
   着地フレームではまだロゴの内側に隠れていて、肝心の「当たった瞬間」に
   衝撃が見えない（実測フレームで確認して直した）。 */
@keyframes loaderShock {
  0% { opacity: 0; transform: scale(0.85); border-width: 8px; }
  10% { opacity: 0.9; }
  100% { opacity: 0; transform: scale(2.7); border-width: 1px; }
}
/* ② 1100ms — Honda が抜ける（入りより速く）。
   `animation: none` は必須。loaderSlam は `both` で満了値を保持し続けるので、
   これを外さないと 250ms の transition が「終わった瞬間」に transition の寄与が
   消え、カスケード上でアニメーション（100% フレーム = opacity 1）が宣言値の
   opacity 0 に勝って Honda が復活する — Onitsuka Tiger と二重に見える原因。
   loaderSlam の 100% は宣言値と同一なので、ここで切っても跳ねない。 */
.is-js .c-loader.is-swap .c-loader__logo--honda {
  animation: none;
  opacity: 0;
  transition-duration: 0.25s;
}
/* ③ 1500ms — Onitsuka Tiger 単体。② の完了（1350ms）から 150ms 空ける */
.is-js .c-loader.is-tiger .c-loader__logo--tiger { opacity: 1; transform: scale(1); }
/* ④ 2250ms — OT ロゴにズームインしながらホワイトアウト。ロゴと白い面が同じ
   0.7s / 同じ ease-in で薄くなるので、ロゴは「大きくなりながら白へ飛ぶ」。
   opacity をロゴだけ先に 0 にすると、まだ 2.7 倍程度のうちに消えてしまって
   ズームがまったく効かない（実測で確認済み）。 */
.is-js .c-loader.is-zoom { opacity: 0; }
.is-js .c-loader.is-zoom .c-loader__logo--tiger {
  opacity: 0;
  transform: scale(7);
  transition:
    transform 0.7s cubic-bezier(0.55, 0, 1, 0.45),
    opacity 0.7s cubic-bezier(0.5, 0, 0.75, 0);
}
/* ⑤ 2950ms — 完全に退場。クリックを一切拾わない */
.is-js .c-loader.is-done {
  display: none;
  visibility: hidden;
  pointer-events: none;
}

/* --------------------------------------------------------------- 6. #kv */
.p-hxot-kv {
  position: relative;
  height: clamp(560px, calc(100svh - var(--header-height)), 840px);
  overflow: hidden;
  background: #e8e4dd;
}
.p-hxot-kv__media { position: absolute; inset: 0; }
/* Scrub target — and the "引き → 寄り" stage.
   `object-fit: cover` fits this photo BY HEIGHT, so the box height is what sets
   the on-screen zoom. 1.5% over-size (the old value was 15%) is as far back as
   cover can go: the drawn image is barely taller than the section, so the whole
   frame — model, bike, both shoes — is on screen at rest.
   Pulling back alone could never clear the shoe, though: the shoe sits at ~70%
   of the photo's height and the copy used to start at ~51% of the section, so
   the copy block was moved out of its way instead (narrow left-hand lockup,
   `width: fit-content` below). The pull-back is what makes that composition
   breathe.
   The scroll-out stays covered because the scrub grows `scale` alongside `y`:
   with origin 62% down the box the top edge sits at -12.4 - 36.3p px
   (p = progress) — negative for every p, so it can never uncover the top edge.
   See the target list at the bottom of this file. */
.p-hxot-kv__media-shift { position: absolute; inset: -1.5% 0; transform-origin: 48% 62%; }
/* scrub start value, per contract §6 — app.js writes only the final y/scale */
.is-js .p-hxot-kv__media-shift { transform: scale(1); }
.p-hxot-kv__media img { width: 100%; height: 100%; object-fit: cover; object-position: center 42%; }
/* Two-axis scrim. The copy now lives in a narrow left-hand column, so the
   legibility wash is mostly HORIZONTAL — that keeps the right-hand side, where
   the bike and the yellow shoes are, unwashed. The bottom gradient is only
   there to settle the block into the frame. */
.p-hxot-kv__scrim {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to right, rgba(244, 241, 236, 0.9) 0%, rgba(244, 241, 236, 0.66) 30%, rgba(244, 241, 236, 0) 58%),
    linear-gradient(to top, rgba(244, 241, 236, 0.58) 0%, rgba(244, 241, 236, 0) 42%);
  pointer-events: none;
}
.p-hxot-kv__inner {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  height: 100%;
  padding-bottom: min(3.33vw, 48px);
}
/* Every copy element hugs its own text (`fit-content`). Without this each one
   is a full-container-width block, so its bounding box would run straight
   through the shoes on the right even though no glyph goes near them — and
   "the boxes must not intersect" is the acceptance test for this KV. */
.p-hxot-kv__label,
.p-hxot-kv__title,
.p-hxot-kv__catch,
.p-hxot-kv__meta { width: fit-content; max-width: 100%; }
.p-hxot-kv__label {
  font-family: var(--font-en);
  font-size: var(--fs-label);
  letter-spacing: 0.3em;
  margin-bottom: min(1.1vw, 16px);
}
.p-hxot-kv__title {
  font-family: var(--font-en);
  font-size: min(6.45vw, 100px);
  line-height: 0.98;
  letter-spacing: -0.02em;
  margin-bottom: min(1.38vw, 20px);
}
.p-hxot-kv__title-x { color: var(--color-red); }
/* 3 lines on every breakpoint now: "HONDA × / Onitsuka / Tiger" is a tall,
   narrow lockup that leaves the right half of the frame to the bike and the
   shoes. The 2-line version was 810px wide and unavoidably ran into them. */
.p-hxot-kv__title-br { display: block; }
.p-hxot-kv__catch {
  font-size: min(2.5vw, 38px);
  font-weight: 900;
  line-height: 1.5;
  letter-spacing: 0.04em;
  margin-bottom: min(0.83vw, 12px);
}
.p-hxot-kv__meta {
  font-size: var(--fs-body-sm);
  letter-spacing: 0.12em;
  color: var(--color-muted);
  line-height: 1.8;
}
/* 3 nested layers so nothing fights: wrap = GSAP scrub, anim = load reveal
   transition, mark = CSS keyframe loop.
   The mark is the Onitsuka TIGER HEAD (it used to be the stripe): on a KV whose
   whole job is "two brands met", the head reads as a brand signature where the
   stripe read as decoration. Inked, not yellow — the studio backdrop behind it
   is near-white, so black is the legible choice and it echoes the header
   wordmark. */
.p-hxot-kv__mark-wrap {
  position: absolute;
  right: var(--site-padding);
  top: min(5.5vw, 80px);
  width: min(11.1vw, 160px);
  z-index: 2;
}
.p-hxot-kv__tiger {
  color: var(--color-ink);
  opacity: 0.92;
}
.p-hxot-kv__badge {
  right: var(--site-padding);
  bottom: min(9.7vw, 140px);
  color: var(--color-ink);
}
.p-hxot-kv__scroll {
  position: absolute;
  right: var(--site-padding);
  bottom: 0;
  z-index: 3;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  font-family: var(--font-en);
  font-size: 10px;
  letter-spacing: 0.24em;
}
.p-hxot-kv__scroll-bar {
  display: block;
  width: 1px;
  height: min(4.16vw, 60px);
  background: var(--color-ink);
  animation: scrollCue 2.4s ease-in-out infinite;
}

/* Loading sequence — visible by default; `.is-js` arms the hidden state and
   `.is-loaded` (added by app.js after the load timeout) reveals in stages. */
.p-hxot-kv__anim {
  transition:
    opacity 1s cubic-bezier(0.33, 1, 0.68, 1),
    transform 1s cubic-bezier(0.33, 1, 0.68, 1);
}
.is-js .p-hxot-kv__anim { opacity: 0; transform: translateY(40px); }
.is-js .p-hxot-kv__media { opacity: 0; transform: scale(1.06); transition: opacity 1.2s ease, transform 1.6s cubic-bezier(0.33, 1, 0.68, 1); }
.is-js.is-loaded .p-hxot-kv__media { opacity: 1; transform: scale(1); }
.is-js.is-loaded .p-hxot-kv__anim { opacity: 1; transform: translateY(0); }
.is-js.is-loaded .p-hxot-kv__label { transition-delay: 0.1s; }
.is-js.is-loaded .p-hxot-kv__title { transition-delay: 0.3s; }
.is-js.is-loaded .p-hxot-kv__catch { transition-delay: 0.5s; }
.is-js.is-loaded .p-hxot-kv__meta,
.is-js.is-loaded .p-hxot-kv__mark-anim { transition-delay: 0.7s; }

@media (max-width: 767px) {
  /* taller than the old 700px cap: the SP art is a PORTRAIT crop whose shoes
     live in the bottom ~7% of the frame, so the section needs the extra height
     to show them AND still leave the copy somewhere to sit above them */
  .p-hxot-kv { height: clamp(520px, calc(100svh - var(--header-height)), 760px); }
  .p-hxot-kv__media img { object-position: center 30%; }
  /* ~0 over-size: `cover` then fits the portrait BY HEIGHT, i.e. the whole
     photo top-to-bottom — feet included — is on screen at rest */
  .p-hxot-kv__media-shift { inset: -0.8% 0; }
  /* Portrait crop, portrait section: the wash is a BAND, not a bottom fade.
     It peaks behind the copy (roughly 17–46% up from the bottom) and releases
     again below 11%, which is exactly the strip the yellow shoes stand in — a
     plain bottom-up fade washed them to cream and threw the whole point of the
     shot away. */
  .p-hxot-kv__scrim {
    background:
      linear-gradient(to right, rgba(244, 241, 236, 0.6) 0%, rgba(244, 241, 236, 0.26) 52%, rgba(244, 241, 236, 0) 80%),
      linear-gradient(to top,
        rgba(244, 241, 236, 0) 0%,
        rgba(244, 241, 236, 0.04) 11%,
        rgba(244, 241, 236, 0.88) 17%,
        rgba(244, 241, 236, 0.88) 46%,
        rgba(244, 241, 236, 0) 64%);
  }
  .p-hxot-kv__title { font-size: min(11.4vw, 48px); }
  .p-hxot-kv__catch { font-size: min(5.86vw, 24px); }
  .p-hxot-kv__mark-wrap { width: min(24vw, 96px); top: min(7.4vw, 30px); }
  /* SP crops to the portrait art, where the top-right corner is the BLACK
     backdrop panel — an inked mark simply vanishes into it. Yellow reads on
     both the panel and the wall it straddles, and it picks up the shoes. */
  .p-hxot-kv__tiger { color: var(--color-yellow); opacity: 1; }
  /* the SP KV text block already owns the lower half — no room for the badge */
  .p-hxot-kv__badge { display: none; }
  .p-hxot-kv__scroll { display: none; }
  /* lifts the whole copy block clear of the shoes at the bottom of the crop
     AND out of the strip where the scrim band above releases back to 0 */
  .p-hxot-kv__inner { padding-bottom: min(32vw, 125px); }
}

/* ------------------------------------------------------------ 7. #intro */
.p-hxot-intro {
  position: relative;
  padding-block: var(--section-gap);
  overflow: hidden;
}
.p-hxot-intro__inner { position: relative; z-index: 2; max-width: min(52.7vw, 760px); }
.p-hxot-intro__heading {
  font-size: min(3.05vw, 44px);
  font-weight: 900;
  line-height: 1.5;
  letter-spacing: 0.02em;
  margin-bottom: min(2.2vw, 32px);
}
.p-hxot-intro__heading em { font-style: normal; background: linear-gradient(transparent 62%, var(--color-yellow) 62%); }
.p-hxot-intro__text + .p-hxot-intro__text { margin-top: 1.4em; }

.p-hxot-intro__bg { position: absolute; inset: 0; z-index: 1; pointer-events: none; }
.p-hxot-intro__bg-item { position: absolute; }
/* scrub parallax — initial transform lives here (armed by `.is-js`), app.js
   only writes the FINAL value. Without JS the layout stays un-offset. */
.p-hxot-intro__bg-item-1 { right: min(4.16vw, 60px); top: min(5.5vw, 80px); width: min(20.8vw, 300px); color: var(--color-yellow); }
.is-js .p-hxot-intro__bg-item-1 { transform: translateY(40px); }
/* wrapper is the scrub target; the `.js-loop` svg inside stays JS-free */
.p-hxot-intro__bg-item-2 { right: min(20.8vw, 300px); bottom: min(4.16vw, 60px); width: min(9.7vw, 140px); color: var(--color-ink); opacity: 0.08; }
.is-js .p-hxot-intro__bg-item-2 { transform: translateY(-30px); }
.p-hxot-intro__bg-item-3 {
  right: min(2.7vw, 40px); bottom: min(9.7vw, 140px);
  width: min(11.1vw, 160px);
  background: var(--color-white);
  border: 2px solid var(--color-ink);
  box-shadow: 10px 10px 0 0 var(--color-shadow);
  padding: min(1.1vw, 16px);
}
.is-js .p-hxot-intro__bg-item-3 { transform: translateY(60px); }
.p-hxot-intro__bg-item-4 {
  right: min(29vw, 420px); top: min(11.1vw, 160px);
  width: min(8.3vw, 120px);
  background: var(--color-white);
  border: 2px solid var(--color-ink);
  box-shadow: 8px 8px 0 0 var(--color-shadow);
  padding: min(0.83vw, 12px);
}
.is-js .p-hxot-intro__bg-item-4 { transform: translateY(-50px); }
/* wrapper is the scrub target; the `.js-loop` dot inside stays JS-free */
.p-hxot-intro__bg-item-5 {
  left: min(1.4vw, 20px); bottom: min(2.7vw, 40px);
  width: min(6.9vw, 100px); height: min(6.9vw, 100px);
}
.p-hxot-intro__dot {
  display: block;
  width: 100%; height: 100%;
  background: var(--color-yellow);
  border-radius: 50%;
}
.is-js .p-hxot-intro__bg-item-5 { transform: translateY(30px); }

.p-hxot-intro__bg-item-6 {
  left: min(2.7vw, 40px); top: min(2.7vw, 40px);
  width: min(8.3vw, 120px); height: min(8.3vw, 120px);
  border: 6px solid var(--color-ink);
  border-radius: 50%;
  opacity: 0.12;
}
.is-js .p-hxot-intro__bg-item-6 { transform: translateY(70px) scale(0.8); }
.p-hxot-intro__bg-item-7 {
  left: min(13.8vw, 200px); bottom: min(1.4vw, 20px);
  width: min(13.8vw, 200px);
  color: var(--color-red);
  opacity: 0.16;
}
.is-js .p-hxot-intro__bg-item-7 { transform: translateX(-120px) rotate(-12deg); }
/* wrapper is the scrub target; the `.js-loop` tiger inside stays JS-free */
.p-hxot-intro__bg-item-8 {
  right: min(6.9vw, 100px); bottom: min(15.2vw, 220px);
  width: min(6.94vw, 100px);
  color: var(--color-ink);
  opacity: 0.1;
}
.is-js .p-hxot-intro__bg-item-8 { transform: translateY(50px) rotate(8deg); }

@media (max-width: 767px) {
  .p-hxot-intro { padding-bottom: min(42.6vw, 180px); }
  .p-hxot-intro__inner { max-width: none; }
  .p-hxot-intro__heading { font-size: min(6.4vw, 27px); }
  .p-hxot-intro__bg-item-1 { width: min(42.6vw, 170px); right: min(-5.3vw, -20px); top: min(-2.6vw, -10px); opacity: 0.85; }
  .p-hxot-intro__bg-item-2 { display: none; }
  .p-hxot-intro__bg-item-3 { width: min(24vw, 96px); right: min(4vw, 16px); bottom: min(2.6vw, 10px); box-shadow: 5px 5px 0 0 var(--color-shadow); }
  .p-hxot-intro__bg-item-4 { display: none; }
  .p-hxot-intro__bg-item-5 { width: min(16vw, 64px); height: min(16vw, 64px); left: min(-4vw, -16px); bottom: min(21.3vw, 84px); }
  .p-hxot-intro__bg-item-6 { width: min(21.3vw, 84px); height: min(21.3vw, 84px); border-width: 4px; left: auto; right: min(4vw, 16px); top: min(37.3vw, 150px); }
  .is-js .p-hxot-intro__bg-item-6 { transform: translateY(50px) scale(0.85); }
  .p-hxot-intro__bg-item-7 { display: none; }
  .p-hxot-intro__bg-item-8 { display: none; }
}

/* ---------------------------------------------------------- 8. marquee */
.p-hxot-marquee {
  background: var(--color-ink);
  color: var(--color-bg);
  border-block: 2px solid var(--color-ink);
  overflow: hidden;
  user-select: none;
  pointer-events: none;
}
.p-hxot-marquee__inner { padding-block: min(0.83vw, 12px); overflow: hidden; }
.p-hxot-marquee__wrapper { display: flex; width: max-content; }
.p-hxot-marquee__item {
  flex: none;
  display: flex;
  align-items: center;
  gap: min(1.66vw, 24px);
  padding-right: min(1.66vw, 24px);
  font-family: var(--font-en);
  font-size: min(2.08vw, 30px);
  letter-spacing: 0.02em;
  white-space: nowrap;
  animation: marquee 30s linear infinite;
}
/* The belt carries the two BRAND LOCKUPS and nothing else — no stripe, no
   tiger head, no chips. Both marquees run on ink, and the Onitsuka Tiger box
   logo is solid black artwork, so each lockup sits on a white plate; that also
   keeps the two logos reading as a matched pair rather than one floating red
   wing and one invisible black box. */
.p-hxot-marquee__logo {
  flex: none;
  display: grid;
  place-items: center;
  height: min(2.63vw, 38px);
  min-width: min(4.44vw, 64px);
  padding-inline: min(0.83vw, 12px);
  background: var(--color-white);
  border-radius: 3px;
}
.p-hxot-marquee__logo img { width: auto; height: min(1.8vw, 26px); max-width: 100%; object-fit: contain; }
/* second marquee runs the other way AND faster, so the two bands never read as
   one synchronised belt */
.p-hxot-marquee--bottom .p-hxot-marquee__item { animation-name: marquee-reverse; animation-duration: 21s; }

@media (max-width: 767px) {
  .p-hxot-marquee__item { font-size: min(5.33vw, 22px); gap: min(3.2vw, 14px); padding-right: min(3.2vw, 14px); }
  .p-hxot-marquee__logo {
    height: min(8vw, 32px);
    min-width: min(12.8vw, 50px);
    padding-inline: min(2.1vw, 8px);
  }
  .p-hxot-marquee__logo img { height: min(5.3vw, 21px); }
}

/* ------------------------------------------------------------ 9. #about */
.p-hxot-about { position: relative; padding-block: var(--section-gap); overflow: hidden; }
.p-hxot-about > .l-container { position: relative; z-index: 1; }
.p-hxot-about__blend { background-color: var(--color-bg); }
.p-hxot-about__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: min(5.5vw, 80px);
  align-items: start;
}
.p-hxot-about__media { position: relative; }
.p-hxot-about__img-main {
  width: 100%;
  border: 2px solid var(--color-ink);
  box-shadow: var(--offset-shadow);
}
/* scrub parallax target */
.is-js .p-hxot-about__img-main { transform: translateY(30px); }
.p-hxot-about__img-sub {
  position: absolute;
  right: min(-4.16vw, -60px);
  bottom: min(-5.5vw, -80px);
  width: min(20.8vw, 300px);
  border: 2px solid var(--color-ink);
  box-shadow: 12px 12px 0 0 var(--color-shadow);
}
/* scrub parallax target */
.is-js .p-hxot-about__img-sub { transform: translateY(50px); }
.p-hxot-about__body { padding-top: min(2.7vw, 40px); }
/* "Collaboration" is unbreakable and this heading lives in a half-width column */
.p-hxot-about .p-hxot-heading__main { font-size: min(4.16vw, 60px); }
.p-hxot-about__lead {
  font-size: min(1.94vw, 28px);
  font-weight: 900;
  line-height: 1.7;
  letter-spacing: 0.02em;
  margin-block: min(2.2vw, 32px) min(1.66vw, 24px);
}
.p-hxot-about__text + .p-hxot-about__text { margin-top: 1.4em; }
.p-hxot-about__note {
  display: flex;
  gap: min(1.66vw, 24px);
  margin-top: min(2.7vw, 40px);
  padding-top: min(1.66vw, 24px);
  border-top: 1px solid var(--color-line);
}
.p-hxot-about__note dt {
  flex: none;
  width: min(6.9vw, 100px);
  font-family: var(--font-en);
  font-size: var(--fs-label);
  letter-spacing: 0.16em;
  color: var(--color-muted);
  line-height: 2.4;
}
.p-hxot-about__note dd { font-size: var(--fs-body-sm); line-height: 2; }

@media (max-width: 767px) {
  .p-hxot-about__grid { grid-template-columns: 1fr; gap: min(16vw, 62px); }
  .p-hxot-about__img-sub { right: min(-4vw, -16px); bottom: min(-8vw, -32px); width: min(40vw, 150px); box-shadow: 6px 6px 0 0 var(--color-shadow); }
  .p-hxot-about__body { padding-top: 0; }
  .p-hxot-about__lead { font-size: min(5.33vw, 21px); }
  .p-hxot-about__note { flex-direction: column; gap: min(1.6vw, 6px); }
  .p-hxot-about__note dt { width: auto; line-height: 1.6; }
}

/* ------------------------------------------------------------- 10. #bike */
.p-hxot-bike { position: relative; padding-block: var(--section-gap); background: var(--color-ink); color: var(--color-bg); overflow: hidden; }
.p-hxot-bike > .l-container { position: relative; z-index: 1; }
.p-hxot-bike .p-hxot-heading__label { color: rgba(244, 241, 236, 0.6); }
.p-hxot-bike__blend { background-color: var(--color-ink); }

/* the ghost lives inside the section's TOP padding, above the heading */
.p-hxot-bike__ghost {
  left: 0;
  top: min(1.1vw, 16px);
  -webkit-text-stroke: 2px rgba(244, 241, 236, 0.26);
}
.is-js .p-hxot-bike__ghost { transform: translateX(-260px); }

.p-hxot-bike__lead {
  font-size: min(3.33vw, 48px);
  font-weight: 900;
  line-height: 1.4;
  letter-spacing: 0.02em;
  margin-top: min(2.7vw, 40px);
}
.p-hxot-bike__hero {
  margin-top: min(2.7vw, 40px);
  border: 2px solid var(--color-bg);
  box-shadow: 20px 20px 0 0 var(--color-yellow);
}
/* scrub parallax target */
.is-js .p-hxot-bike__hero { transform: translateY(40px); }
.p-hxot-bike__hero img { width: 100%; aspect-ratio: 16 / 7; object-fit: cover; object-position: center 45%; }
.p-hxot-bike__hero-caption {
  padding: min(0.83vw, 12px) min(1.38vw, 20px);
  border-top: 2px solid var(--color-bg);
  font-family: var(--font-en);
  font-size: var(--fs-label);
  letter-spacing: 0.2em;
  color: rgba(244, 241, 236, 0.75);
}

.p-hxot-bike__grid {
  display: grid;
  grid-template-columns: 1.15fr 1fr;
  gap: min(5.5vw, 80px);
  align-items: center;
  margin-top: min(3.33vw, 48px);
}
.p-hxot-bike__card {
  position: relative;
  background: var(--color-white);
  border: 2px solid var(--color-ink);
  box-shadow: 20px 20px 0 0 var(--color-yellow);
  padding: min(2.7vw, 40px);
}
/* scrub parallax target */
.is-js .p-hxot-bike__card { transform: translateX(-40px); }
.p-hxot-bike__card img { width: 100%; }
.p-hxot-bike__badge {
  position: absolute;
  /* the card image carries `.js-clip`, and a clip-path makes it a stacking
     context that would otherwise paint over this earlier-in-DOM sibling */
  z-index: 1;
  left: min(-1.66vw, -24px);
  top: min(-1.66vw, -24px);
  display: grid;
  place-items: center;
  width: min(8.33vw, 120px); height: min(8.33vw, 120px);
  background: var(--color-yellow);
  border: 2px solid var(--color-ink);
  border-radius: 50%;
  color: var(--color-ink);
  font-family: var(--font-en);
  font-size: min(1.11vw, 16px);
  line-height: 1.2;
  text-align: center;
}
/* scrub parallax target (rotates inside the card, which itself scrubs on x) */
.is-js .p-hxot-bike__badge { transform: rotate(-12deg); }
.p-hxot-bike__text { margin-bottom: min(1.66vw, 24px); }
.p-hxot-bike__spec { border-top: 1px solid rgba(244, 241, 236, 0.28); }
.p-hxot-bike__spec-row {
  display: flex;
  align-items: baseline;
  gap: min(1.66vw, 24px);
  padding-block: min(1.11vw, 16px);
  border-bottom: 1px solid rgba(244, 241, 236, 0.28);
}
.p-hxot-bike__spec-row dt {
  flex: none;
  width: min(13.8vw, 200px);
  font-size: var(--fs-body-sm);
  letter-spacing: 0.1em;
  color: rgba(244, 241, 236, 0.7);
}
.p-hxot-bike__spec-row dd { font-family: var(--font-en); font-size: min(1.66vw, 24px); letter-spacing: 0.02em; }
.p-hxot-bike__disclaimer { margin-top: min(1.11vw, 16px); font-size: var(--fs-label); color: rgba(244, 241, 236, 0.6); line-height: 1.8; }

@media (max-width: 767px) {
  .p-hxot-bike__ghost { font-size: min(16vw, 64px); top: min(4.2vw, 17px); }
  .is-js .p-hxot-bike__ghost { transform: translateX(-70px); }
  .p-hxot-bike__lead { font-size: min(8vw, 32px); margin-top: min(8.5vw, 34px); }
  .p-hxot-bike__hero { margin-top: min(8.5vw, 34px); box-shadow: 8px 8px 0 0 var(--color-yellow); }
  .p-hxot-bike__hero img { aspect-ratio: 4 / 3; }
  .is-js .p-hxot-bike__hero { transform: none; }
  .p-hxot-bike__grid { grid-template-columns: 1fr; gap: min(13.3vw, 52px); margin-top: min(13.3vw, 52px); }
  .p-hxot-bike__card { padding: min(6.4vw, 26px); box-shadow: 8px 8px 0 0 var(--color-yellow); }
  .is-js .p-hxot-bike__card { transform: none; }
  .is-js .p-hxot-bike__badge { transform: none; }
  .p-hxot-bike__badge { width: min(21.3vw, 84px); height: min(21.3vw, 84px); font-size: min(2.93vw, 12px); left: min(-2.6vw, -10px); top: min(-4vw, -16px); }
  .p-hxot-bike__spec-row { flex-direction: column; align-items: flex-start; gap: min(1.06vw, 4px); }
  .p-hxot-bike__spec-row dt { width: auto; line-height: 1.6; }
  .p-hxot-bike__spec-row dd { font-size: min(4.8vw, 19px); }
}

/* ------------------------------------------------------------ 11. #route */
/* Scroll-drawn arrow road. app.js measures `.p-hxot-route__stage`, generates the
   zigzag geometry from that width and writes it into the (empty in markup) svg.
   Everything animated here is a CLASS TOGGLE (`.is-hit`) resolved by a CSS
   transition — the only continuous values app.js writes are the two path
   `stroke-dashoffset` scrubs plus the imperative `transform` attribute on the
   arrow head / decorations (SVG attribute, not CSS, so nothing collides). */
.p-hxot-route {
  position: relative;
  padding-block: var(--section-gap);
  background: var(--color-bg);
  overflow: hidden;
}
/* ★ ユーザー指示により非表示 2026-08-06 ★
   `hidden` だけだと UA の `[hidden] { display: none }` が上の `.p-hxot-route`
   と同じカスケード段ではないため確実性に欠ける。明示的に伏せる。
   復活させるときは index.html の `hidden` 属性を外すだけでよい（この規則は
   属性セレクタなので自動的に効かなくなる）。 */
.p-hxot-route[hidden] { display: none !important; }
.p-hxot-route > .l-container { position: relative; z-index: 1; }
.p-hxot-route__blend { background-color: var(--color-bg); }

.p-hxot-route__lead {
  font-size: min(3.33vw, 48px);
  font-weight: 900;
  line-height: 1.4;
  letter-spacing: 0.02em;
  margin-top: min(2.7vw, 40px);
}
.p-hxot-route__text {
  max-width: min(41.6vw, 600px);
  margin-top: min(1.66vw, 24px);
  color: var(--color-muted);
}

/* The measured stage. Height is written by app.js (it comes out of the
   generated geometry), so with JS off there is nothing to lay out.
   It is revealed ONLY under `no-preference`, i.e. exactly when app.js actually
   builds it — the reduce block further up the file has the same specificity and
   sits EARLIER, so gating here beats fighting it with `!important`. */
.p-hxot-route__stage { display: none; }
@media (prefers-reduced-motion: no-preference) {
  .is-js .p-hxot-route__stage {
    display: block;
    position: relative;
    margin-top: min(4.16vw, 60px);
  }
}
/* 1:1 with the viewBox → getPointAtLength() returns screen px directly.
   `overflow: visible` lets the decorations roll out past the stage edge; the
   section's own `overflow: hidden` is what stops the document widening. */
.p-hxot-route__svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}

.p-hxot-route__track { fill: none; stroke: var(--color-ink); stroke-width: 1.5; opacity: 0.16; }
.p-hxot-route__glow { fill: none; stroke: var(--color-red); stroke-width: 11; opacity: 0.14; }
.p-hxot-route__line { fill: none; stroke: var(--color-red); stroke-width: 4; }
/* `pathLength="10000"` (written by app.js) normalises the dash space, so this
   initial state survives every geometry rebuild and app.js only ever writes the
   FINAL value (0) — contract §6.
   10000 and not 1: GSAP ROUNDS px-unit CSS values to whole numbers, so a 1 → 0
   tween can only ever render "undrawn" or "fully drawn". 10000 buys ~0.2px of
   resolution along the road. Both numbers must stay in step with the
   `pathLength` attribute app.js sets. */
.is-js .p-hxot-route__glow,
.is-js .p-hxot-route__line { stroke-dasharray: 10000; stroke-dashoffset: 10000; }

.p-hxot-route__tick {
  stroke: var(--color-red);
  stroke-width: 2;
  opacity: 0;
  transition: opacity 0.4s ease;
}
.p-hxot-route__tick.is-hit { opacity: 1; }

.p-hxot-route__chevron {
  fill: none;
  stroke: var(--color-red);
  stroke-width: 2.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0;
  transition: opacity 0.45s ease;
}
.p-hxot-route__chevron.is-hit { opacity: 1; }

/* triple diamond: outline / red fill / cream core */
.p-hxot-route__node {
  transform-box: fill-box;
  transform-origin: center;
  transition:
    opacity 0.3s ease,
    transform 0.55s cubic-bezier(0.16, 1, 0.3, 1);
}
.is-js .p-hxot-route__node { opacity: 0; transform: scale(0); }
.is-js .p-hxot-route__node.is-hit { opacity: 1; transform: scale(1); }
.p-hxot-route__node-ring { fill: none; stroke: var(--color-red); stroke-width: 2; opacity: 0.45; }
.p-hxot-route__node-fill { fill: var(--color-red); }
.p-hxot-route__node-core { fill: var(--color-bg); }

/* `#stripe-mark` paints with `fill: currentColor`, so `color` is what tints it */
.p-hxot-route__deco { opacity: 0; }
.p-hxot-route__deco--stripe { color: var(--color-yellow); }
.p-hxot-route__deco--stripe-ink { color: var(--color-ink); }
.p-hxot-route__deco--star { fill: var(--color-red); }
.p-hxot-route__deco--star-yellow { fill: var(--color-yellow); }

/* barbed arrow head — app.js writes only its transform attribute + opacity */
.p-hxot-route__head-glow { fill: var(--color-red); opacity: 0.2; }
.p-hxot-route__head-body { fill: var(--color-red); }
.p-hxot-route__head-core { fill: var(--color-bg); opacity: 0.92; }

/* --- cards. app.js writes top / left / width / transform (measured geometry);
   the slam-in itself is this stylesheet's transition. --- */
.p-hxot-route__card { position: absolute; top: 0; left: 0; }
.p-hxot-route__card-in {
  transition:
    opacity 0.6s cubic-bezier(0.33, 1, 0.68, 1),
    transform 0.72s cubic-bezier(0.16, 1, 0.3, 1);
}
.is-js .p-hxot-route__card-in { opacity: 0; transform: translate(60px, 22px) skewX(-9deg); }
.is-js .p-hxot-route__card[data-side="left"] .p-hxot-route__card-in { transform: translate(-60px, 22px) skewX(9deg); }
.is-js .p-hxot-route__card.is-hit .p-hxot-route__card-in { opacity: 1; transform: translate(0, 0) skewX(0deg); }

.p-hxot-route__card-body {
  position: relative;
  transform: rotate(1.4deg);
  background: var(--color-ink);
  color: var(--color-bg);
  border: 2px solid var(--color-ink);
  box-shadow: 12px 12px 0 0 rgba(17, 17, 17, 0.14);
  padding: min(1.66vw, 24px);
}
.p-hxot-route__card[data-side="left"] .p-hxot-route__card-body { transform: rotate(-1.5deg); }
.p-hxot-route__card-edge {
  position: absolute;
  top: -2px;
  right: 14px;
  width: 46px;
  height: 4px;
  background: var(--color-red);
}
.p-hxot-route__card[data-side="left"] .p-hxot-route__card-edge { right: auto; left: 14px; }
.p-hxot-route__card-head {
  display: flex;
  align-items: baseline;
  gap: min(0.83vw, 12px);
  margin-bottom: min(0.55vw, 8px);
}
.p-hxot-route__num {
  font-family: var(--font-en);
  font-size: min(2.22vw, 32px);
  line-height: 1;
  color: transparent;
  -webkit-text-stroke: 1.6px var(--color-red);
}
.p-hxot-route__en {
  font-family: var(--font-en);
  font-size: var(--fs-label);
  letter-spacing: 0.24em;
  color: var(--color-red);
}
.p-hxot-route__card-title {
  font-size: min(1.38vw, 20px);
  font-weight: 900;
  line-height: 1.5;
  margin-bottom: min(0.55vw, 8px);
}
.p-hxot-route__card-text {
  font-size: var(--fs-body-sm);
  line-height: 1.85;
  color: rgba(244, 241, 236, 0.76);
}

/* --- static equivalent (JS off / reduced motion). Visible by default; the
   `.is-js` rule below only takes it out of the layout, never out of the
   accessibility tree — the animated stage is aria-hidden. --- */
.p-hxot-route__static {
  display: grid;
  gap: min(2.2vw, 32px);
  margin-top: min(3.33vw, 48px);
}
.p-hxot-route__static li {
  display: flex;
  gap: min(1.66vw, 24px);
  align-items: baseline;
  border-top: 2px solid var(--color-ink);
  padding-top: min(1.11vw, 16px);
}
.p-hxot-route__static-no {
  flex: none;
  font-family: var(--font-en);
  font-size: min(1.66vw, 24px);
  line-height: 1;
  color: transparent;
  -webkit-text-stroke: 1.4px var(--color-red);
}
.p-hxot-route__static strong {
  display: block;
  font-size: min(1.38vw, 20px);
  font-weight: 900;
  line-height: 1.5;
}
/* visually hidden but never removed from the accessibility tree — the animated
   stage is aria-hidden, so this list is the section's only exposed copy. Same
   `no-preference` gate as the stage: under reduce it simply stays visible. */
@media (prefers-reduced-motion: no-preference) {
  .is-js .p-hxot-route__static {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

@media (max-width: 767px) {
  .p-hxot-route__lead { font-size: min(8vw, 32px); margin-top: min(8.5vw, 34px); }
  .p-hxot-route__text { max-width: none; margin-top: min(4.2vw, 17px); }
  /* claw back the container padding: the SP layout puts the zigzag in a left
     band and the cards in the remaining column, so every px of width counts. */
  .is-js .p-hxot-route__stage {
    margin-top: min(10.6vw, 42px);
    margin-inline: calc(var(--site-padding) * -1 + 8px);
  }
  .p-hxot-route__card-body { padding: min(4.2vw, 17px); box-shadow: 6px 6px 0 0 rgba(17, 17, 17, 0.14); }
  .p-hxot-route__card-edge { width: 30px; height: 3px; }
  /* min(0.83vw, …) collapses to ~3px at 390px — the number would touch the
     English label */
  .p-hxot-route__card-head { gap: min(2.5vw, 10px); margin-bottom: min(1.6vw, 6px); }
  .p-hxot-route__num { font-size: min(6.4vw, 26px); }
  .p-hxot-route__card-title { font-size: min(4.26vw, 17px); }
  .p-hxot-route__static-no { font-size: min(6.4vw, 26px); }
  .p-hxot-route__static strong { font-size: min(4.8vw, 19px); }
  .p-hxot-route__static li { flex-direction: column; align-items: flex-start; gap: min(2.1vw, 8px); }
}

/* ------------------------------------------------ 12. #shoes (sticky重ね) */
.p-hxot-shoes { position: relative; background: var(--color-yellow); }
.p-hxot-shoes__body {
  position: sticky;
  top: 0;
  height: min(100vh, 860px);
  padding-top: var(--header-height);
  display: flex;
  align-items: center;
  overflow: hidden;
}
.p-hxot-shoes__body > .l-container { position: relative; z-index: 1; }
/* the shared rule is yellow, which is invisible on this yellow section */
.p-hxot-shoes .p-hxot-heading__rule { background: var(--color-ink); }
.p-hxot-shoes__ghost {
  right: 0;
  bottom: min(1.4vw, 20px);
  -webkit-text-stroke: 2px rgba(17, 17, 17, 0.18);
}
.is-js .p-hxot-shoes__ghost { transform: translateX(240px); }
/* wrapper is the scrub target; the `.js-loop` tiger inside stays JS-free.
   Yellow section → the mark is inked. */
.p-hxot-shoes__tiger {
  position: absolute;
  z-index: 0;
  left: min(2.7vw, 40px);
  top: min(5.5vw, 80px);
  display: block;
  width: min(8.33vw, 120px);
  color: var(--color-ink);
  opacity: 0.14;
  pointer-events: none;
}
.is-js .p-hxot-shoes__tiger { transform: translateY(60px) rotate(-6deg); }
/* empty spacer — gives ScrollTrigger 1 screen of scrub range (kuromi country方式) */
.p-hxot-shoes__space { height: min(100vh, 860px); pointer-events: none; }

.p-hxot-shoes__grid {
  display: grid;
  grid-template-columns: 1fr 1.1fr;
  gap: min(4.16vw, 60px);
  align-items: center;
  width: 100%;
}
.p-hxot-shoes__pair { display: grid; gap: min(1.66vw, 24px); }
.p-hxot-shoes__figure {
  background: var(--color-white);
  border: 2px solid var(--color-ink);
  box-shadow: 12px 12px 0 0 var(--color-shadow);
  padding: min(1.66vw, 24px);
}
.p-hxot-shoes__figure img { width: 100%; }
/* scrub parallax targets — offset in opposite directions */
.is-js .p-hxot-shoes__figure--01 { transform: translateY(28px); }
.is-js .p-hxot-shoes__figure--02 { transform: translateY(-28px); }
.p-hxot-shoes__caption {
  margin-top: min(0.83vw, 12px);
  font-family: var(--font-en);
  font-size: var(--fs-label);
  letter-spacing: 0.16em;
}
.p-hxot-shoes__lead {
  font-size: min(1.94vw, 28px);
  font-weight: 900;
  line-height: 1.7;
  margin-block: min(2.2vw, 32px) min(1.66vw, 24px);
}
.p-hxot-shoes__grid p + p { margin-top: 1.2em; }
/* wrapper is the scrub target; the `.js-loop` svg inside stays JS-free */
.p-hxot-shoes__stripe-wrap {
  width: min(11.1vw, 160px);
  margin-top: min(2.2vw, 32px);
}
.is-js .p-hxot-shoes__stripe-wrap { transform: translateX(-60px) rotate(-8deg); }
.p-hxot-shoes__stripe { color: var(--color-ink); }

@media (max-width: 767px) {
  /* `relative` (not `static`) cancels the sticky behaviour AND keeps this the
     containing block for `.p-hxot-shoes__ghost`, so the base `overflow: hidden`
     still clips it. With `static` the ghost escaped to `.p-hxot-shoes` (which
     must not be `overflow: hidden` or PC sticky breaks) and added 70px of
     horizontal scroll. */
  .p-hxot-shoes__body { height: auto; position: relative; padding-block: var(--section-gap); }
  .p-hxot-shoes__space { display: none; }
  .p-hxot-shoes__ghost { font-size: min(16vw, 64px); bottom: min(4.2vw, 17px); }
  .is-js .p-hxot-shoes__ghost { transform: translateX(70px); }
  .p-hxot-shoes__grid { grid-template-columns: 1fr; gap: min(10.6vw, 42px); }
  .p-hxot-shoes__figure { box-shadow: 6px 6px 0 0 var(--color-shadow); padding: min(4.2vw, 17px); }
  .is-js .p-hxot-shoes__figure--01,
  .is-js .p-hxot-shoes__figure--02 { transform: none; }
  .is-js .p-hxot-shoes__stripe-wrap { transform: none; }
  .p-hxot-shoes__lead { font-size: min(5.33vw, 21px); }
  .p-hxot-shoes__stripe-wrap { width: min(37.3vw, 150px); }
  .p-hxot-shoes__tiger { display: none; }
}

/* ----------------------------------------------------------- 13. #detail */
.p-hxot-detail { position: relative; padding-block: var(--section-gap); overflow: hidden; }
.p-hxot-detail > .l-container { position: relative; z-index: 1; }
.p-hxot-detail__blend { background-color: var(--color-bg); }
.p-hxot-detail__deco {
  position: absolute;
  z-index: 0;
  left: min(-4.16vw, -60px);
  top: min(27.7vw, 400px);
  width: min(16.6vw, 240px);
  color: var(--color-yellow);
  opacity: 0.55;
  pointer-events: none;
}
.is-js .p-hxot-detail__deco { transform: translateY(60px) rotate(-10deg); }
/* wrapper is the scrub target; the `.js-loop` tiger inside stays JS-free */
.p-hxot-detail__tiger {
  position: absolute;
  z-index: 0;
  right: min(-2.08vw, -30px);
  top: min(13.8vw, 200px);
  display: block;
  width: min(9.72vw, 140px);
  color: var(--color-ink);
  opacity: 0.09;
  pointer-events: none;
}
.is-js .p-hxot-detail__tiger { transform: translateY(-50px) rotate(7deg); }
.p-hxot-detail__visual {
  position: relative;
  margin-top: min(3.33vw, 48px);
  display: grid;
  grid-template-columns: 1.6fr 1fr;
  gap: min(2.2vw, 32px);
  align-items: end;
}
.p-hxot-detail__img {
  border: 2px solid var(--color-ink);
  width: 100%;
}
/* scrub parallax targets */
.is-js .p-hxot-detail__img--wide { transform: translateY(30px); will-change: transform; }
.is-js .p-hxot-detail__img--tall { transform: translateY(-30px); will-change: transform; }

.p-hxot-detail__list {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: min(2.7vw, 40px);
  margin-top: min(5.5vw, 80px);
}
.p-hxot-detail__item { border-top: 4px solid var(--color-ink); padding-top: min(1.66vw, 24px); }
.p-hxot-detail__num {
  font-family: var(--font-en);
  font-size: min(2.5vw, 36px);
  color: var(--color-yellow);
  -webkit-text-stroke: 1px var(--color-ink);
  line-height: 1;
}
.p-hxot-detail__item-title {
  font-size: min(1.38vw, 20px);
  font-weight: 900;
  line-height: 1.6;
  margin-block: min(0.83vw, 12px) min(0.55vw, 8px);
}
.p-hxot-detail__item-text { font-size: var(--fs-body-sm); }

@media (max-width: 767px) {
  .p-hxot-detail__deco { display: none; }
  .p-hxot-detail__tiger { display: none; }
  .p-hxot-detail__visual { grid-template-columns: 1fr; gap: min(4.2vw, 17px); }
  .is-js .p-hxot-detail__img--wide,
  .is-js .p-hxot-detail__img--tall { transform: none; }
  .p-hxot-detail__img--tall { width: 68%; margin-left: auto; }
  .p-hxot-detail__list { grid-template-columns: 1fr; gap: min(8.5vw, 34px); margin-top: min(13.3vw, 52px); }
  .p-hxot-detail__num { font-size: min(8.5vw, 34px); }
  .p-hxot-detail__item-title { font-size: min(4.8vw, 19px); }
}

/* ------------------------------------------------------------ 14. #movie */
/* Ink section sitting between the cream #detail and the ink #gallery, so the
   existing hand-off chain is unchanged: `.p-hxot-detail__blend` now warms up
   towards THIS section (same #f4f1ec → #111111 scrub, only the trigger moved
   from `.p-hxot-gallery` to `.p-hxot-movie`) and #movie → #gallery needs no
   blend because both are already ink. */
.p-hxot-movie {
  position: relative;
  padding-block: var(--section-gap);
  background: var(--color-ink);
  color: var(--color-bg);
  overflow: hidden;
  /* #movie and #gallery are both ink, so without this hairline the seam
     between them disappears and the two read as one endless black block */
  border-bottom: 1px solid rgba(244, 241, 236, 0.16);
}
.p-hxot-movie > .l-container { position: relative; z-index: 1; }
.p-hxot-movie .p-hxot-heading__label { color: rgba(244, 241, 236, 0.6); }
.p-hxot-movie__deco { position: absolute; inset: 0; z-index: 0; pointer-events: none; }
/* wrapper is the scrub target; the `.js-loop` tiger inside stays JS-free.
   Ink section → the mark is yellow. */
.p-hxot-movie__tiger {
  position: absolute;
  right: min(-2.08vw, -30px);
  top: min(4.16vw, 60px);
  display: block;
  width: min(18.05vw, 260px);
  color: var(--color-yellow);
  opacity: 0.16;
}
.is-js .p-hxot-movie__tiger { transform: translateY(70px) rotate(-9deg); }
.p-hxot-movie__stripe {
  position: absolute;
  left: min(-5.55vw, -80px);
  bottom: min(6.94vw, 100px);
  width: min(16.66vw, 240px);
  color: rgba(244, 241, 236, 0.12);
}
.is-js .p-hxot-movie__stripe { transform: translateX(-90px) rotate(10deg); }

.p-hxot-movie__lead {
  font-size: min(3.33vw, 48px);
  font-weight: 900;
  line-height: 1.4;
  letter-spacing: 0.02em;
  margin-top: min(2.7vw, 40px);
}
.p-hxot-movie__text {
  max-width: min(41.6vw, 600px);
  margin-top: min(1.66vw, 24px);
  color: rgba(244, 241, 236, 0.72);
}

/* main video card — a <button>, so keyboard activation is free */
.p-hxot-movie__main {
  position: relative;
  display: block;
  width: 100%;
  margin-top: min(3.33vw, 48px);
  padding: 0;
  background: #000000;
  border: 2px solid var(--color-bg);
  box-shadow: 20px 20px 0 0 var(--color-yellow);
  cursor: pointer;
  overflow: hidden;
  text-align: left;
}
.p-hxot-movie__main-img {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  object-position: center 45%;
  transition: transform 0.9s cubic-bezier(0.16, 1, 0.3, 1);
}
.p-hxot-movie__veil {
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.72) 0%, rgba(0, 0, 0, 0.14) 52%, rgba(0, 0, 0, 0.3) 100%);
  transition: opacity 0.4s ease;
  pointer-events: none;
}
.p-hxot-movie__main-cap {
  position: absolute;
  left: min(1.66vw, 24px);
  bottom: min(1.38vw, 20px);
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.p-hxot-movie__main-en {
  font-family: var(--font-en);
  font-size: var(--fs-label);
  letter-spacing: 0.24em;
  color: var(--color-yellow);
}
.p-hxot-movie__main-jp {
  font-size: min(1.38vw, 20px);
  font-weight: 900;
  line-height: 1.5;
  letter-spacing: 0.04em;
}
@media (hover: hover) and (pointer: fine) {
  .p-hxot-movie__main:hover .p-hxot-movie__main-img { transform: scale(1.035); }
  .p-hxot-movie__main:hover .p-hxot-movie__veil { opacity: 0.72; }
  .p-hxot-movie__main:hover .c-play { transform: translate(-50%, -50%) scale(1.12); background: var(--color-yellow); }
  .p-hxot-movie__thumb:hover .p-hxot-movie__veil { opacity: 0.6; }
  .p-hxot-movie__thumb:hover .c-play { transform: translate(-50%, -50%) scale(1.14); background: var(--color-yellow); }
}
.p-hxot-movie__main:focus-visible,
.p-hxot-movie__thumb:focus-visible { outline: 3px solid var(--color-yellow); outline-offset: 4px; }

/* thumbnail nav */
.p-hxot-movie__nav {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: min(1.66vw, 24px);
  margin-top: min(2.77vw, 40px);
}
.p-hxot-movie__nav-item { min-width: 0; }
.p-hxot-movie__thumb {
  position: relative;
  display: block;
  width: 100%;
  padding: 0;
  background: #000000;
  border: 2px solid rgba(244, 241, 236, 0.6);
  cursor: pointer;
  overflow: hidden;
  text-align: left;
  transition: border-color 0.3s ease;
}
.p-hxot-movie__thumb img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; }
.p-hxot-movie__thumb-cap {
  position: absolute;
  left: min(0.69vw, 10px);
  bottom: min(0.55vw, 8px);
  font-size: var(--fs-label);
  font-weight: 700;
  letter-spacing: 0.06em;
  line-height: 1.5;
}
@media (hover: hover) and (pointer: fine) {
  .p-hxot-movie__thumb:hover { border-color: var(--color-yellow); }
}
.p-hxot-movie__note {
  margin-top: min(1.66vw, 24px);
  font-size: var(--fs-label);
  line-height: 1.9;
  color: rgba(244, 241, 236, 0.6);
}

@media (max-width: 767px) {
  .p-hxot-movie__lead { font-size: min(8vw, 32px); margin-top: min(8.5vw, 34px); }
  .p-hxot-movie__text { max-width: none; margin-top: min(4.2vw, 17px); }
  .p-hxot-movie__tiger { width: min(37.3vw, 150px); right: min(-8vw, -32px); top: min(2.6vw, 10px); }
  .p-hxot-movie__stripe { width: min(45.3vw, 180px); left: min(-10.6vw, -42px); bottom: min(10.6vw, 42px); }
  .is-js .p-hxot-movie__tiger { transform: translateY(50px) rotate(-9deg); }
  .is-js .p-hxot-movie__stripe { transform: translateX(-50px) rotate(10deg); }
  .p-hxot-movie__main { margin-top: min(8.5vw, 34px); box-shadow: 8px 8px 0 0 var(--color-yellow); }
  .p-hxot-movie__main-jp { font-size: min(4.26vw, 17px); }
  .p-hxot-movie__main-cap { left: min(4.2vw, 17px); bottom: min(3.2vw, 13px); }
  .p-hxot-movie__nav { grid-template-columns: repeat(2, 1fr); gap: min(3.2vw, 13px); margin-top: min(8.5vw, 34px); }
  .p-hxot-movie__note { margin-top: min(6.4vw, 26px); }
  .c-play { width: min(16vw, 64px); height: min(16vw, 64px); }
  .c-play__tri { border-left-width: min(4.2vw, 17px); border-top-width: min(2.9vw, 12px); border-bottom-width: min(2.9vw, 12px); }
  .c-play--sm { width: min(9.6vw, 40px); height: min(9.6vw, 40px); }
  .c-play--sm .c-play__tri { border-left-width: min(2.6vw, 11px); border-top-width: min(1.8vw, 8px); border-bottom-width: min(1.8vw, 8px); }
}

/* ---------------------------------------------------------- 15. #gallery */
.p-hxot-gallery { position: relative; padding-block: var(--section-gap); background: var(--color-ink); color: var(--color-bg); overflow: hidden; }
.p-hxot-gallery > .l-container { position: relative; z-index: 1; }
.p-hxot-gallery .p-hxot-heading__label { color: rgba(244, 241, 236, 0.6); }
/* ストライプ → タイガーヘッド（ユーザー指示）。ink セクションなので契約 §4 の
   出し分けどおり黄で、#movie のタイガー（yellow / .16）と同じ扱いに揃える。
   幅は 300px → 190px：ストライプは 2.39:1 の横長、タイガーは 0.95:1 のほぼ
   正方形なので、同じ幅だと面積が 2.5 倍になって背景装飾の域を出る。 */
.p-hxot-gallery__tiger {
  position: absolute;
  z-index: 0;
  right: min(-2.7vw, -40px);
  top: min(2.7vw, 40px);
  display: block;
  width: min(13.19vw, 190px);
  color: var(--color-yellow);
  opacity: 0.16;
  pointer-events: none;
}
.is-js .p-hxot-gallery__tiger { transform: translateX(90px) rotate(8deg); }
.p-hxot-gallery__slider {
  margin-top: min(3.33vw, 48px);
  /* Static fallback: a scroll-snap row. app.js replaces it with Swiper and the
     `.is-js` rule below hands overflow control back to Swiper. */
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
}
.is-js .p-hxot-gallery__slider { overflow: hidden; scroll-snap-type: none; }
.p-hxot-gallery__wrapper { display: flex; gap: min(1.66vw, 24px); }
.is-js .p-hxot-gallery__wrapper { gap: 0; }
.p-hxot-gallery__slide {
  flex: none;
  width: min(31.9vw, 460px);
  scroll-snap-align: center;
}
.is-js .p-hxot-gallery__slide { width: auto; }
.p-hxot-gallery__slide img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border: 2px solid var(--color-bg);
}
.p-hxot-gallery__caption {
  margin-top: min(0.83vw, 12px);
  font-family: var(--font-en);
  font-size: var(--fs-label);
  letter-spacing: 0.16em;
  color: rgba(244, 241, 236, 0.7);
}
.p-hxot-gallery__nav { display: flex; gap: min(0.83vw, 12px); margin-top: min(2.2vw, 32px); }
.p-hxot-gallery__nav-btn {
  display: grid;
  place-items: center;
  width: min(4.16vw, 60px); height: min(4.16vw, 60px);
  background: transparent;
  border: 2px solid var(--color-bg);
  border-radius: 50%;
  cursor: pointer;
  transition: background 0.3s ease, color 0.3s ease;
}
.p-hxot-gallery__nav-btn svg { width: 40%; height: auto; }
@media (hover: hover) and (pointer: fine) {
  .p-hxot-gallery__nav-btn:hover { background: var(--color-yellow); color: var(--color-ink); border-color: var(--color-yellow); }
}
@media (max-width: 767px) {
  /* PC と同じ理由で 190px → 122px（横長のストライプと同じ面積に揃える）。
     48vw のままだと画面幅の半分を占めて、背景装飾ではなく主役になる。 */
  .p-hxot-gallery__tiger { width: min(31vw, 122px); top: min(4.2vw, 17px); }
  .is-js .p-hxot-gallery__tiger { transform: translateX(50px) rotate(8deg); }
  .p-hxot-gallery__slide { width: min(74.6vw, 300px); }
  .p-hxot-gallery__nav-btn { width: min(12.8vw, 50px); height: min(12.8vw, 50px); }
}

/* ------------------------------------------------------------- 16. #spec */
.p-hxot-spec { padding-block: var(--section-gap); }
.p-hxot-spec__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: min(5.5vw, 80px);
  align-items: start;
  margin-top: min(3.33vw, 48px);
}
.p-hxot-spec__list { border-top: 4px solid var(--color-ink); }
.p-hxot-spec__row {
  display: flex;
  align-items: baseline;
  gap: min(1.66vw, 24px);
  padding-block: min(1.38vw, 20px);
  border-bottom: 1px solid var(--color-line);
}
.p-hxot-spec__row dt {
  flex: none;
  width: min(11.1vw, 160px);
  font-family: var(--font-en);
  font-size: var(--fs-label);
  letter-spacing: 0.16em;
  color: var(--color-muted);
}
.p-hxot-spec__row dd { font-size: var(--fs-body); font-weight: 700; }
.p-hxot-spec__panel {
  position: relative;
  background: var(--color-white);
  border: 2px solid var(--color-ink);
  box-shadow: var(--offset-shadow);
  padding: min(2.7vw, 40px);
  text-align: center;
}
.p-hxot-spec__badge {
  right: min(-2.7vw, -40px);
  top: min(-2.7vw, -40px);
  width: min(8.3vw, 120px);
  height: min(8.3vw, 120px);
  background: var(--color-yellow);
  border: 2px solid var(--color-ink);
  border-radius: 50%;
  color: var(--color-ink);
}
.p-hxot-spec__badge .c-badge__text { font-size: 13px; }
/* Honda のウイングマーク。ここは Honda がホストであることを示す面なので、
   ストライプではなくブランドロゴを置く（ストライプ分の装飾ウェイトは
   タイガーヘッドの配分で吸収）。ロゴなので回転は控えめに振る。 */
.p-hxot-spec__panel-logo {
  width: min(9.72vw, 140px);
  height: auto;
  margin: 0 auto min(1.66vw, 24px);
  object-fit: contain;
}
/* scrub parallax target */
.is-js .p-hxot-spec__panel-logo { transform: rotate(-3deg) scale(0.92); }
.p-hxot-spec__panel-title {
  font-family: var(--font-en);
  font-size: min(2.22vw, 32px);
  line-height: 1.2;
  margin-bottom: min(0.83vw, 12px);
}
.p-hxot-spec__panel-text { font-size: var(--fs-body-sm); margin-bottom: min(2.2vw, 32px); }
.p-hxot-spec__mock {
  margin-top: min(1.38vw, 20px);
  font-size: var(--fs-label);
  color: var(--color-muted);
  line-height: 1.8;
}

@media (max-width: 767px) {
  .p-hxot-spec__grid { grid-template-columns: 1fr; gap: min(13.3vw, 52px); margin-top: min(8.5vw, 34px); }
  .p-hxot-spec__row dt { width: min(26.6vw, 102px); }
  .p-hxot-spec__panel { padding: min(6.4vw, 26px); }
  .p-hxot-spec__panel-title { font-size: min(6.4vw, 26px); }
  .p-hxot-spec__panel-logo { width: min(29.3vw, 118px); }
  .p-hxot-spec__badge { width: min(21.3vw, 84px); height: min(21.3vw, 84px); right: min(-3.2vw, -13px); top: min(-4.2vw, -17px); }
  .p-hxot-spec__badge .c-badge__text { font-size: 15px; }
  .c-badge__core { font-size: min(2.4vw, 10px); }
}

/* ----------------------------------------------------------- 17. #bottom */
.p-hxot-footer { position: relative; padding-block: min(5.5vw, 80px) min(2.7vw, 40px); background: var(--color-bg); overflow: hidden; }
.p-hxot-footer > .l-container { position: relative; z-index: 1; }
/* static watermark (no scrub, no loop) — the footer is the one place the mark
   is allowed to sit still */
.p-hxot-footer__tiger {
  position: absolute;
  z-index: 0;
  left: min(4.16vw, 60px);
  bottom: min(-2.08vw, -30px);
  display: block;
  width: min(11.11vw, 160px);
  color: var(--color-ink);
  opacity: 0.07;
  pointer-events: none;
}
.p-hxot-footer__logos {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: min(4.16vw, 60px);
  flex-wrap: wrap;
}
.p-hxot-footer__logo {
  display: grid;
  place-items: center;
  width: min(13.8vw, 200px);
  height: min(8.3vw, 120px);
  background: var(--color-white);
  border: 2px solid var(--color-ink);
  box-shadow: 10px 10px 0 0 var(--color-shadow);
  padding: min(1.38vw, 20px);
}
.p-hxot-footer__logo img { width: auto; height: min(4.16vw, 60px); max-width: 100%; object-fit: contain; }
.p-hxot-footer__x { font-family: var(--font-en); font-size: min(2.22vw, 32px); color: var(--color-red); }
.p-hxot-footer__title {
  margin-top: min(4.16vw, 60px);
  text-align: center;
  font-family: var(--font-jp);
  font-weight: 900;
  font-size: min(3.33vw, 48px);
  letter-spacing: 0.04em;
  line-height: 1.4;
}
.p-hxot-footer__nav {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: min(2.2vw, 32px);
  margin-top: min(2.7vw, 40px);
  padding-top: min(2.7vw, 40px);
  border-top: 1px solid var(--color-line);
}
.p-hxot-footer__nav a { font-family: var(--font-en); font-size: var(--fs-label); letter-spacing: 0.16em; }
.p-hxot-footer__meta { margin-top: min(2.2vw, 32px); text-align: center; }
.p-hxot-footer__copyright { font-size: var(--fs-label); color: var(--color-muted); letter-spacing: 0.06em; }
.p-hxot-footer__mock {
  margin-top: min(0.83vw, 12px);
  font-size: var(--fs-label);
  line-height: 1.9;
  color: var(--color-muted);
}
.p-hxot-footer__mock strong { font-family: var(--font-en); font-weight: 400; letter-spacing: 0.1em; color: var(--color-ink); }

@media (max-width: 767px) {
  .p-hxot-footer__logo { width: min(37.3vw, 150px); height: min(24vw, 96px); box-shadow: 5px 5px 0 0 var(--color-shadow); padding: min(3.2vw, 13px); }
  .p-hxot-footer__logo img { height: min(12.8vw, 50px); }
  .p-hxot-footer__x { font-size: min(6.4vw, 26px); }
  .p-hxot-footer__title { font-size: min(7.46vw, 30px); margin-top: min(10.6vw, 42px); }
  .p-hxot-footer__nav { gap: min(4.2vw, 17px); }
  .p-hxot-footer__tiger { width: min(26.6vw, 102px); left: min(-2.6vw, -10px); bottom: min(-2.6vw, -10px); }
}

/* =============================================================================
   PHASE 2 — scrub parallax / ScrollTrigger target list (for app.js)
   -----------------------------------------------------------------------------
   Every entry below is one `gsap.to()` + `scrub: 1` + `invalidateOnRefresh`.
   "PC" = (min-width: 768px), "SP" = (max-width: 767px); the two matchMedia
   queries are exclusive and both carry `prefers-reduced-motion: no-preference`.
   "start → final": start comes from the `.is-js` rule in this file, final is the
   only thing app.js writes.

   --- #kv  (trigger .p-hxot-kv, "top top" → "bottom top") -------------------
   .p-hxot-kv__media-shift      y 0 → 80 (PC) / 50 (SP) AND scale 1 → 1.16 (PC)
                                / 1.14 (SP), transform-origin 48% 62%.
                                引き → 寄り: the box is only 5% (PC) / 6% (SP)
                                over-sized, which is what pulls the framing
                                back far enough that the shoe clears the title
                                at rest; the scale then pushes in on scroll.
                                Both values ride ONE tween — and they have to,
                                because the growing scale is what keeps the box
                                covering the section as `y` pushes it down
                                (top edge = -41 - 10.4p px at 1440, negative for
                                every progress p).
   .p-hxot-kv__inner            y 0 → -170 + opacity .06   fast layer, shorter
                                                           range ("top top" →
                                                           "72% top")
   .p-hxot-kv__mark-wrap        y 0 → -260, rotation 26    (SP: -140 / 18)
                                (hosts the TIGER HEAD `.c-tiger`, not the
                                stripe — WRAPPER, `.js-loop` mark inside)
   .p-hxot-kv__badge .c-badge__ring   rotation 0 → 360     PC only (hidden on SP)

   --- #intro (trigger .p-hxot-intro, "top bottom" → "bottom top") -----------
   .p-hxot-intro__bg-item-1     y 40 → -40, rotation -14
   .p-hxot-intro__bg-item-2     y -30 → 30, rotation 18    PC only (SP hidden)
   .p-hxot-intro__bg-item-3     y 60 → -60, rotation 6
   .p-hxot-intro__bg-item-4     y -50 → 50, rotation -8    PC only (SP hidden)
   .p-hxot-intro__bg-item-5     y 30 → -30, scale 1 → 1.3
   .p-hxot-intro__bg-item-6     y 70/50 → -70/-40, scale .8 → 1.15
   .p-hxot-intro__bg-item-7     x -120 → 120, rotation -12 → 10   PC only
   .p-hxot-intro__bg-item-8     y 50 → -50, rotation 8 → -8       PC only
                                (tiger head; SP hides it like 2/4/7)
   NOTE items 2, 5 and 8 are WRAPPERS; the `.js-loop` element lives inside them.

   --- #about ---------------------------------------------------------------
   .p-hxot-about__img-main      y 30 → -30      (trigger .p-hxot-about)
   .p-hxot-about__img-sub       y 50 → -50, rotation 0 → 4
   .p-hxot-about__blend         backgroundColor #f4f1ec → #111111
                                (trigger .p-hxot-bike, "top bottom" → "top 45%")

   --- #bike ----------------------------------------------------------------
   .p-hxot-bike__ghost          x -260 → 260 (PC) / -70 → 70 (SP)
                                (trigger .p-hxot-bike, "top bottom"→"bottom top")
   .p-hxot-bike__hero           y 40 → -40      PC only
   .p-hxot-bike__card           x -40 → 0       PC only
   .p-hxot-bike__badge          rotation -12 → 10   PC only
   .p-hxot-bike__blend          backgroundColor #111111 → #f7b500
                                (trigger .p-hxot-shoes, "top bottom"→"top 45%")
                                ★ was → #f4f1ec on .p-hxot-route until #route
                                was hidden (2026-08-06); the ink now hands over
                                directly to the yellow #shoes.

   --- #route  ★ HIDDEN 2026-08-06 (ユーザー指示) ★ --------------------------
   The section carries `hidden` + `.p-hxot-route[hidden] { display: none }`, and
   app.js no longer boots initRoute, so NONE of the three scrubs below is
   registered any more. Kept verbatim for the day it comes back.
   (trigger .p-hxot-route__stage, "top 80%" → "bottom 80%")
   Three scrubs share that one range so the ink, the head and the thresholds
   stay on the same clock. All three are `ease: "none"` — scrubTo() otherwise
   inherits GSAP's default power1.out, which would bend the drawn length away
   from the linear node fractions.
   .p-hxot-route__line          strokeDashoffset 10000 → 0   (PC + SP)
   .p-hxot-route__glow          strokeDashoffset 10000 → 0   (PC + SP)
   (proxy object)               p 0 → 1  — the progress clock. Its onUpdate
                                parks the arrow head with getPointAtLength(),
                                rolls the decorations out along the path normal
                                and flips `.is-hit` on nodes / chevrons / ticks
                                / cards. NOT `invalidateOnRefresh`: 0 → 1 owns
                                no layout, and re-reading it mid-scroll on a
                                refresh would rewrite the tween's start value.
   .p-hxot-route__blend         backgroundColor #f4f1ec → #f7b500
                                (trigger .p-hxot-shoes, "top bottom"→"top 45%")
                                ★ commented out in app.js while #route is hidden
   Geometry is rebuilt on a ResizeObserver width change (then
   ScrollTrigger.refresh()); the PC/SP layout mode comes from gsap.matchMedia,
   NOT from the measured width — at a 768px viewport the container is only
   ~672px wide and would otherwise pick the SP layout.

   --- #shoes (sticky; scrub range = .p-hxot-shoes__space, PC only) ----------
   .p-hxot-shoes__figure--01    y 28 → -28      PC only
   .p-hxot-shoes__figure--02    y -28 → 28      PC only
   .p-hxot-shoes__stripe-wrap   x -60 → 60, rotation -8 → 12   PC only
                                (WRAPPER — the `.js-loop` svg is its child)
   .p-hxot-shoes__ghost         x 240 → -240 (PC) / 70 → -70 (SP)
                                (trigger .p-hxot-shoes)
   .p-hxot-shoes__tiger         y 60 → -60, rotation -6 → 8   PC only
                                (trigger .p-hxot-shoes; WRAPPER, `.js-loop`
                                tiger inside. SP hides it)

   --- #detail --------------------------------------------------------------
   .p-hxot-detail__img--wide    y 30 → -30      PC only
   .p-hxot-detail__img--tall    y -30 → 30      PC only
   .p-hxot-detail__deco         y 60 → -60, rotation -10 → 18   PC only
   .p-hxot-detail__tiger        y -50 → 50, rotation 7 → -9     PC only
                                (WRAPPER, `.js-loop` tiger inside. SP hides it)
   .p-hxot-detail__blend        backgroundColor #f4f1ec → #111111
                                (trigger .p-hxot-movie, "top bottom"→"top 45%")
                                — retargeted from .p-hxot-gallery when #movie
                                was inserted; the colours are unchanged because
                                #movie is ink too.

   --- #movie (trigger .p-hxot-movie, "top bottom" → "bottom top") -----------
   .p-hxot-movie__tiger         y 70 → -70 (PC) / 50 → -50 (SP), rotation -9→11
                                (WRAPPER — the `.js-loop` tiger is its child)
   .p-hxot-movie__stripe        x -90 → 90 (PC) / -50 → 50 (SP), rotation 10→-8
   #movie → #gallery carries NO blend: both sections are already #111111.

   --- #gallery / #spec -----------------------------------------------------
   .p-hxot-gallery__tiger       x 90 → -120 (PC) / 50 → -60 (SP), rotation 8 → -8
                                (was `.p-hxot-gallery__stripe`: the stripe mark
                                was swapped for the tiger head on user request.
                                Direct scrub target, NOT a wrapper — this one
                                never carried a `.js-loop`.)
   .p-hxot-spec__panel-logo     rotation -3 → 4, scale .92 → 1.08 (PC) / 1.06 (SP)
                                (Honda wing mark — replaced the stripe svg that
                                used to sit here; a logo takes a gentler swing)
   .p-hxot-spec__badge .c-badge__ring   rotation 0 → 360   (PC + SP)

   --- non-scrub hooks ------------------------------------------------------
   loader   .js-loader   → the opening sequence; see contract §11 at the top.
                          setTimeout class hops (.is-honda / .is-swap /
                          .is-tiger / .is-zoom / .is-done), zero tweens, and
                          `is-loaded` lands at its end instead of at +100ms.
                          Motion-gated: nothing of it runs under reduce.
   reveal   .js-onscreen (+ --wipe / --left / --right) → add .is-active
   wipe     .js-clip     → add .is-active (clip-path only, transform-safe)
   split    .js-split    → app.js injects .c-word/.c-char + --char-i, then
                           .is-active drives the CSS stagger
   loop     .js-loop (+ --swing / --spin / --slow) → CSS only, never touched;
                           scrub the parent wrapper instead
   anchors  a.js-scroll  → ScrollToPlugin, offsetY = var(--header-height)
   swiper   .js-gallery-slider / .js-gallery-prev / .js-gallery-next
   route    .js-route    → app.js measures it, generates the svg inside it and
                           positions the cards; see contract §9 at the top
   movie    .js-movie / .js-vmodal / .js-vmodal-stage / .js-vmodal-close
                        → the video modal; see contract §10 at the top. NOT a
                          scrub and NOT motion-gated: it works under reduce.

   Totals (measured in Chrome via
   `ScrollTrigger.getAll().filter(st => st.vars.scrub).length`):
     >=768px : 35 scrub tweens   <=767px : 19 scrub tweens
     reduce  :  0 scrub tweens, 0 ScrollTriggers at all
   How it got here: 34 / 21 at the end of the previous round
     +5 PC / +2 SP  new decorations (intro-8, shoes tiger, detail tiger,
                    movie tiger, movie stripe — the last two on SP too)
     -4 PC / -4 SP  #route hidden (line + glow + progress proxy +
                    .p-hxot-route__blend stop being registered)
   The KV scale rides the EXISTING media-shift tween, so the 引き→寄り zoom
   costs zero extra ScrollTriggers.
   The 767/768 sets are exclusive — the count is never 54.
   Anything added here must ALSO be listed in the
   `prefers-reduced-motion: reduce` transform reset near the top.
   ========================================================================== */
