/*!
 * asbsb-animations.css — ASB Smart Builder 出現アニメ語彙（共有カタログアセット）
 * 相方 = asbsb-animations.js。className で当てる（保存正規形＝WPの追加CSSクラスに残る）。
 *
 * 設計の柱:
 *  - 隠す初期状態は必ず `html.anim-on`（JSが付与）配下だけ＝JS無効/エディタでは中身が見える（プログレッシブ）。
 *  - 連続系（sway/parallax）と隠す系は `prefers-reduced-motion` で最終静止状態に落ちる＝
 *    measure は reduced-motion エミュレートで「静止状態」を測れる（静的==WP を壊さない）。
 *  - フロントのみ enqueue（エディタには入れない）。装飾色は decorations の CSS 変数で上書き。
 *
 * 語彙（className）:
 *  出現(スクロールで1回)  : anim-fade / anim-fade-up / anim-fade-down / anim-fade-left / anim-fade-right / anim-zoom
 *  画像カラーワイプ        : anim-wipe（色帯が走って画像が出る。色= --anim-wipe-color）
 *                           向き(M7-3)= 無印:左→右 / anim-wipe-left / anim-wipe-down / anim-wipe-up（単体でも anim-wipe 併用でも可）
 *  文字ワイプ(M7-3)        : anim-clip / anim-clip-left / anim-clip-down / anim-clip-up（マスク開き＝帯なし。文字にも画像にも可）
 *  ぼかし出現(M7-3)        : anim-blur（フェード＋blur→鮮明。強さ= --anim-blur）
 *  ポップ(M7-3)            : anim-pop（ぽんっとバウンス出現。開始倍率= --anim-pop-from）
 *  起き上がり(M7-3)        : anim-flip（下辺を軸に3D起き上がり。角度= --anim-flip-deg）
 *  ライン(M7-3)            : anim-line / anim-line-left / anim-line-down / anim-line-up（線が伸びる。仕切り線・下線に）
 *  数字カウント(M7-3)      : anim-count（JS。中身は数字テキストのみ・最終表示は元テキストと完全一致）
 *  遅延・スタッガ          : anim-delay-1..6 / 親に anim-stagger（子へJSが順番に遅延）
 *  連続                    : anim-sway（ゆらゆら）／ anim-bubbles（背景を幾何学の形がふわふわ上がる・CSSだけ）
 *  タイピング              : anim-type（JS。実テキストはDOMに残す）
 *  パララックス            : anim-parallax（速度= --anim-parallax-speed 既定0.15、負で逆）
 *  スティッキー            : anim-sticky（top= --anim-sticky-top 既定1.5rem。※transform/backdrop-filter祖先に注意）
 *
 * 方向サフィックスの規約（fade 系と同一）: サフィックス＝演出の進行方向。
 *  例) anim-wipe-left＝帯が右→左へ走る / anim-clip-up＝下→上へ開く / anim-line-down＝上→下へ伸びる。
 *
 * 調整用 CSS 変数（M7-1/M7-3。既定値＝従来のハードコード値と同一。運用モードの「アニメ調整」パネルが :root で上書き。
 * 制作フェーズで変えたい時は decorations.css の :root で宣言＝静的とWPで共有される）:
 *  --anim-duration(.7s) / --anim-distance(30px 縦) / --anim-distance-x(40px 横) / --anim-zoom-from(.9)
 *  --anim-delay-step(.08s) / --anim-wipe-duration(1.1s) / --anim-sway-duration(4.5s)
 *  --anim-sway-y(-10px) / --anim-sway-rot(-1.5deg) / --anim-type-speed(45 ms・JSが読む)
 *  --anim-clip-duration(.9s) / --anim-blur(12px) / --anim-pop-from(.6) / --anim-flip-deg(55deg)
 *  --anim-count-duration(1.2s・JSが読む)
 */

/* ---- 出現系（scroll reveal）：隠す初期状態は html.anim-on ＋ motion許可時のみ ---- */
@media (prefers-reduced-motion: no-preference) {
  html.anim-on :is(.anim-fade, .anim-fade-up, .anim-fade-down, .anim-fade-left, .anim-fade-right, .anim-zoom) {
    opacity: 0;
    will-change: opacity, transform;
    transition: opacity var(--anim-duration, .7s) cubic-bezier(.22, .61, .36, 1), transform var(--anim-duration, .7s) cubic-bezier(.22, .61, .36, 1);
    transition-delay: var(--anim-delay, 0s);
  }
  html.anim-on .anim-fade-up    { transform: translateY(var(--anim-distance, 30px)); }
  html.anim-on .anim-fade-down  { transform: translateY(calc(-1 * var(--anim-distance, 30px))); }
  html.anim-on .anim-fade-left  { transform: translateX(var(--anim-distance-x, 40px)); }  /* 右から入る */
  html.anim-on .anim-fade-right { transform: translateX(calc(-1 * var(--anim-distance-x, 40px))); } /* 左から入る */
  html.anim-on .anim-zoom       { transform: scale(var(--anim-zoom-from, .9)); }

  html.anim-on :is(.anim-fade, .anim-fade-up, .anim-fade-down, .anim-fade-left, .anim-fade-right, .anim-zoom).is-inview {
    opacity: 1;
    transform: none;
  }
}

/* 遅延（スタッガ用。親 anim-stagger は JS が子に --anim-delay を振る。1歩= --anim-delay-step） */
html.anim-on .anim-delay-1 { --anim-delay: calc(1 * var(--anim-delay-step, .08s)); }
html.anim-on .anim-delay-2 { --anim-delay: calc(2 * var(--anim-delay-step, .08s)); }
html.anim-on .anim-delay-3 { --anim-delay: calc(3 * var(--anim-delay-step, .08s)); }
html.anim-on .anim-delay-4 { --anim-delay: calc(4 * var(--anim-delay-step, .08s)); }
html.anim-on .anim-delay-5 { --anim-delay: calc(5 * var(--anim-delay-step, .08s)); }
html.anim-on .anim-delay-6 { --anim-delay: calc(6 * var(--anim-delay-step, .08s)); }

/* ---- 画像カラーワイプ（kihan-tohoku 風：色帯が走って画像が出現）----
   向き（M7-3）: 無印=左→右。anim-wipe-left / anim-wipe-down / anim-wipe-up は単体でも anim-wipe 併用でも可
   （方向クラス自体が語彙＝:is() で本体機構に含める。上書きは「後勝ち」＝方向ルールを本体ルールの後に置く） */
:is(.anim-wipe, .anim-wipe-left, .anim-wipe-down, .anim-wipe-up) { overflow: hidden; }
/* position は :where()（詳細度0）で既定だけ与える＝絶対配置コラージュ（.c-cphoto 等の position:absolute）を
   読み込み順（このCSSは site.css の後）で潰さない。絶対配置でも ::after の基準になるので帯は正しく載る */
:where(.anim-wipe, .anim-wipe-left, .anim-wipe-down, .anim-wipe-up) { position: relative; }
:is(.anim-wipe, .anim-wipe-left, .anim-wipe-down, .anim-wipe-up)::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  background: var(--anim-wipe-color, currentColor);
  transform: scaleX(0);
  transform-origin: left center;
  pointer-events: none;
}
.anim-wipe-left::after { transform-origin: right center; }
.anim-wipe-down::after { transform: scaleY(0); transform-origin: center top; }
.anim-wipe-up::after   { transform: scaleY(0); transform-origin: center bottom; }
/* 下地モディファイア: 重ねコラージュで、出現待ちの間に下の写真が透けて見えるのを防ぐ（使う時だけ anim-wipe に併用）。
   色は --anim-wipe-bg（既定 #fff）。html.anim-on 配下だけ＝JS無効/エディタ/reduced-motion では付かない（measure 不変） */
html.anim-on .anim-wipe-bg { background: var(--anim-wipe-bg, #fff); }
@media (prefers-reduced-motion: no-preference) {
  html.anim-on :is(.anim-wipe, .anim-wipe-left, .anim-wipe-down, .anim-wipe-up) :is(img, .wp-block-cover__image-background) { opacity: 0; }
  html.anim-on :is(.anim-wipe, .anim-wipe-left, .anim-wipe-down, .anim-wipe-up).is-inview::after {
    animation: anim-wipe-sweep var(--anim-wipe-duration, 1.1s) cubic-bezier(.77, 0, .18, 1) forwards;
    animation-delay: var(--anim-delay, 0s); /* anim-delay-* / anim-stagger の遅延に追従 */
  }
  html.anim-on .anim-wipe-left.is-inview::after { animation-name: anim-wipe-sweep-left; }
  html.anim-on .anim-wipe-down.is-inview::after { animation-name: anim-wipe-sweep-down; }
  html.anim-on .anim-wipe-up.is-inview::after   { animation-name: anim-wipe-sweep-up; }
  html.anim-on :is(.anim-wipe, .anim-wipe-left, .anim-wipe-down, .anim-wipe-up).is-inview :is(img, .wp-block-cover__image-background) {
    opacity: 1;
    /* 帯が覆っている間（掃引の中間点≒45.5%）に画像を出す。遅延に追従。.455*1.1s=.5005s＝従来の .5s と同値 */
    transition: opacity .01s calc(var(--anim-wipe-duration, 1.1s) * .455 + var(--anim-delay, 0s));
  }
}
/* 掃引: 伸びる原点＝進行方向の後ろ端 → 縮む原点＝進行方向の前端（先端が走り抜けて見える） */
@keyframes anim-wipe-sweep {
  0%     { transform: scaleX(0); transform-origin: left center; }
  48%    { transform: scaleX(1); transform-origin: left center; }
  52%    { transform: scaleX(1); transform-origin: right center; }
  100%   { transform: scaleX(0); transform-origin: right center; }
}
@keyframes anim-wipe-sweep-left {
  0%     { transform: scaleX(0); transform-origin: right center; }
  48%    { transform: scaleX(1); transform-origin: right center; }
  52%    { transform: scaleX(1); transform-origin: left center; }
  100%   { transform: scaleX(0); transform-origin: left center; }
}
@keyframes anim-wipe-sweep-down {
  0%     { transform: scaleY(0); transform-origin: center top; }
  48%    { transform: scaleY(1); transform-origin: center top; }
  52%    { transform: scaleY(1); transform-origin: center bottom; }
  100%   { transform: scaleY(0); transform-origin: center bottom; }
}
@keyframes anim-wipe-sweep-up {
  0%     { transform: scaleY(0); transform-origin: center bottom; }
  48%    { transform: scaleY(1); transform-origin: center bottom; }
  52%    { transform: scaleY(1); transform-origin: center top; }
  100%   { transform: scaleY(0); transform-origin: center top; }
}

/* ---- 文字ワイプ（M7-3・マスク開き）: 帯なしで拭き出すように出現。見出し・段落向け、画像にも可 ----
   方向は初期 inset の切り方だけ＝最終状態は inset(0)（measure は reduced-motion で clip 無し） */
@media (prefers-reduced-motion: no-preference) {
  html.anim-on :is(.anim-clip, .anim-clip-left, .anim-clip-down, .anim-clip-up) {
    transition: clip-path var(--anim-clip-duration, .9s) cubic-bezier(.22, .61, .36, 1);
    transition-delay: var(--anim-delay, 0s);
  }
  html.anim-on .anim-clip      { clip-path: inset(0 100% 0 0); } /* 左→右 */
  html.anim-on .anim-clip-left { clip-path: inset(0 0 0 100%); } /* 右→左 */
  html.anim-on .anim-clip-down { clip-path: inset(0 0 100% 0); } /* 上→下 */
  html.anim-on .anim-clip-up   { clip-path: inset(100% 0 0 0); } /* 下→上 */
  html.anim-on :is(.anim-clip, .anim-clip-left, .anim-clip-down, .anim-clip-up).is-inview { clip-path: inset(0 0 0 0); }
}

/* ---- ぼかし出現（M7-3）: ピンぼけ→鮮明＋フェード。写真・大見出し向け ---- */
@media (prefers-reduced-motion: no-preference) {
  html.anim-on .anim-blur {
    opacity: 0;
    filter: blur(var(--anim-blur, 12px));
    will-change: opacity, filter;
    transition: opacity var(--anim-duration, .7s) cubic-bezier(.22, .61, .36, 1), filter var(--anim-duration, .7s) cubic-bezier(.22, .61, .36, 1);
    transition-delay: var(--anim-delay, 0s);
  }
  html.anim-on .anim-blur.is-inview { opacity: 1; filter: none; }
}

/* ---- ポップ（M7-3）: ぽんっと弾んで出現（オーバーシュートは easeOutBack 系ベジェで表現）。アイコン・数字・ボタン向け ---- */
@media (prefers-reduced-motion: no-preference) {
  html.anim-on .anim-pop {
    opacity: 0;
    transform: scale(var(--anim-pop-from, .6));
    will-change: opacity, transform;
    transition: opacity calc(var(--anim-duration, .7s) * .6) cubic-bezier(.22, .61, .36, 1), transform var(--anim-duration, .7s) cubic-bezier(.34, 1.56, .64, 1);
    transition-delay: var(--anim-delay, 0s);
  }
  html.anim-on .anim-pop.is-inview { opacity: 1; transform: none; }
}

/* ---- 起き上がり（M7-3）: 下辺を軸に3Dで立ち上がる。カード・画像向け ---- */
@media (prefers-reduced-motion: no-preference) {
  html.anim-on .anim-flip {
    opacity: 0;
    transform: perspective(900px) rotateX(calc(-1 * var(--anim-flip-deg, 55deg)));
    transform-origin: 50% 100%;
    will-change: opacity, transform;
    transition: opacity var(--anim-duration, .7s) cubic-bezier(.22, .61, .36, 1), transform var(--anim-duration, .7s) cubic-bezier(.22, .61, .36, 1);
    transition-delay: var(--anim-delay, 0s);
  }
  html.anim-on .anim-flip.is-inview { opacity: 1; transform: none; }
}

/* ---- ライン（M7-3）: 線が伸びる（仕切り線・下線・separator に）。scale なので最終レイアウト不変 ---- */
@media (prefers-reduced-motion: no-preference) {
  html.anim-on :is(.anim-line, .anim-line-left, .anim-line-down, .anim-line-up) {
    will-change: transform;
    transition: transform var(--anim-duration, .7s) cubic-bezier(.77, 0, .18, 1);
    transition-delay: var(--anim-delay, 0s);
  }
  html.anim-on .anim-line      { transform: scaleX(0); transform-origin: left center; }
  html.anim-on .anim-line-left { transform: scaleX(0); transform-origin: right center; }
  html.anim-on .anim-line-down { transform: scaleY(0); transform-origin: center top; }
  html.anim-on .anim-line-up   { transform: scaleY(0); transform-origin: center bottom; }
  html.anim-on :is(.anim-line, .anim-line-left, .anim-line-down, .anim-line-up).is-inview { transform: none; }
}

/* ---- 連続：ゆらゆら ---- */
@media (prefers-reduced-motion: no-preference) {
  .anim-sway { animation: anim-sway var(--anim-sway-duration, 4.5s) ease-in-out infinite; will-change: transform; }
}
@keyframes anim-sway {
  0%, 100% { transform: translateY(0) rotate(0deg); }
  50%      { transform: translateY(var(--anim-sway-y, -10px)) rotate(var(--anim-sway-rot, -1.5deg)); }
}

/* ---- タイピング（JS駆動。キャレットのみCSS）---- */
.anim-type { }
.anim-type .anim-caret {
  display: inline-block;
  width: .08em;
  transform: translateY(.05em);
  background: currentColor;
  margin-left: .04em;
  animation: anim-caret-blink 1s steps(1) infinite;
}
@keyframes anim-caret-blink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }

/* ---- パララックス（JSがtransformを流す。willChangeだけCSS）---- */
.anim-parallax { will-change: transform; }

/* ---- スティッキー ---- */
.anim-sticky { position: sticky; top: var(--anim-sticky-top, 1.5rem); align-self: start; }

/* ---- SVG線描き→カラー（anim-draw・JS）: 白い線が描かれてからカラーの塗りが現れる。ロゴ・アイコン・線画向け ----
   対象=インラインSVG、または .svg を指す <img>（JS が実行時にインライン化＝保存正規形は wp:image のまま）。
   線色=--anim-draw-color(既定#fff)/太さ=--anim-draw-width(既定2・non-scaling＝拡縮で太さ不変)/
   描画=--anim-draw-dur(既定1.2s)/曲線=--anim-draw-ease(既定ease。手描き感はlinear＝easeは序盤が速く「描いて見えない」)/
   順番=--anim-draw-order(既定sequential＝1本ずつ順に描く。parallel=旧挙動＝全パス同時＝完成した絵が薄く浮かぶだけ)/
   塗り出し=--anim-draw-fill-dur(既定.5s)/線消し=--anim-draw-fade(既定.4s)。
   塗りは SVG 自身の色（内部 .st0 等の fill）が戻ることで出す＝1つのSVGで線と色を兼ねる。 */
@media (prefers-reduced-motion: no-preference) {
  /* transition は JS が3プロパティまとめて設定（stroke-dashoffset＋fill＋stroke-opacity）＝
     インラインで stroke-dashoffset だけ指定すると fill/stroke-opacity の transition を消してしまい
     「線が見えないまま一瞬でカラー」になる罠を回避（M?） */
  html.anim-on .anim-draw svg path {
    stroke: var(--anim-draw-color, #fff);
    stroke-width: var(--anim-draw-width, 2);
    vector-effect: non-scaling-stroke;
  }
  /* 描画前＝塗りを消し白線だけ（SVG内 fill を上書き。JSが各pathへ dash を設定して線を隠す） */
  html.anim-on .anim-draw:not(.is-inview) svg path { fill: transparent; }
  /* 描画後＝塗りが戻り(:not外れる)、白線はフェードアウト */
  html.anim-on .anim-draw.is-inview svg path { stroke-opacity: 0; }
}

/* ============================================================================
 * M17 追加語彙（GSAP 相当の演出を CSS＋IntersectionObserver で。ライブラリは足さない）
 *  文字   : anim-split（1字ずつ立ち上げ＝SplitText 相当）/ anim-mask（行ごとマスク）/ anim-scramble（文字が確定する）
 *  装飾   : anim-marquee（無限に流れる帯）/ anim-gradient（見出しに色が流れる）/ anim-bar（数値バーが伸びる）
 *  スクロール連動: anim-scrub（進むほど拡大・回転・移動）/ anim-pin（固定して中身だけ進む）/ anim-hscroll（横に流れる）
 * すべて html.anim-on 配下＝JS無効/エディタでは素の状態。reduce は最終静止状態（末尾の reduce ブロック）。
 * ============================================================================ */

/* ---- 1字ずつ立ち上げ（anim-split・JSが1字=1spanへ分割。--i が字番号）----
   ★実テキストは DOM に残る（span で包むだけ・textContent は不変）＝SEO/顧客編集/measure 安全。
   語単位は anim-split-word（英文向け。和文は字単位＝無印でよい）。 */
@media (prefers-reduced-motion: no-preference) {
  html.anim-on :is(.anim-split, .anim-split-word) .anim-sp {
    display: inline-block;
    opacity: 0;
    transform: translateY(var(--anim-split-distance, .8em)) rotate(var(--anim-split-rot, 0deg));
    will-change: opacity, transform;
    transition: opacity var(--anim-split-duration, .6s) cubic-bezier(.22, .61, .36, 1),
                transform var(--anim-split-duration, .6s) cubic-bezier(.22, .61, .36, 1);
    transition-delay: calc(var(--anim-delay, 0s) + var(--i, 0) * var(--anim-split-step, .035s));
  }
  html.anim-on :is(.anim-split, .anim-split-word).is-inview .anim-sp { opacity: 1; transform: none; }
}

/* ---- 行ごとマスク（anim-mask・JSが「実際に折り返した行」で包む）----
   帯を使わず、行の下から立ち上がる＝見出しの王道。折り返し位置は実測なので原稿を変えても崩れない。 */
@media (prefers-reduced-motion: no-preference) {
  html.anim-on .anim-mask .anim-ml { display: block; overflow: hidden; }
  html.anim-on .anim-mask .anim-ml-i {
    display: inline-block;
    transform: translateY(105%);
    will-change: transform;
    transition: transform var(--anim-mask-duration, .9s) cubic-bezier(.22, .61, .36, 1);
    transition-delay: calc(var(--anim-delay, 0s) + var(--i, 0) * var(--anim-mask-step, .12s));
  }
  html.anim-on .anim-mask.is-inview .anim-ml-i { transform: none; }
}

/* ---- 文字が確定する（anim-scramble・JS。CSSは等幅寄せだけ）----
   ★幅が踊らないよう字送りを固定（font-variant-numeric）。実テキストは最後に完全復元。 */
.anim-scramble { font-variant-numeric: tabular-nums; }

/* ---- 無限に流れる帯（anim-marquee・JSが中身を2つ並べる）----
   速さ= --anim-marquee-duration（既定24s）。逆向き= anim-marquee-rev。マウスを乗せると止まる。 */
:is(.anim-marquee, .anim-marquee-rev) { overflow: hidden; }
html.anim-on :is(.anim-marquee, .anim-marquee-rev) .anim-mq-track {
  display: flex;
  width: max-content;
  gap: var(--anim-marquee-gap, 2.5rem);
  will-change: transform;
}
@media (prefers-reduced-motion: no-preference) {
  html.anim-on :is(.anim-marquee, .anim-marquee-rev) .anim-mq-track {
    animation: anim-marquee-flow var(--anim-marquee-duration, 24s) linear infinite;
  }
  html.anim-on .anim-marquee-rev .anim-mq-track { animation-direction: reverse; }
  html.anim-on :is(.anim-marquee, .anim-marquee-rev):hover .anim-mq-track { animation-play-state: paused; }
}
/* 2つ並べて -50% まで動かす＝継ぎ目が出ない（gap も含めて半分ちょうどになるよう JS が同じ中身を複製する） */
@keyframes anim-marquee-flow {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(calc(-50% - var(--anim-marquee-gap, 2.5rem) / 2), 0, 0); }
}

/* ---- 見出しに色が流れる（anim-gradient・CSSのみ）----
   色= --anim-gradient-from / --anim-gradient-to（既定はサイトのアクセント色）。速さ= --anim-gradient-duration。 */
.anim-gradient {
  background-image: linear-gradient(100deg,
    var(--anim-gradient-from, var(--c-accent, #ee7500)) 0%,
    var(--anim-gradient-to, #ffce9c) 35%,
    var(--anim-gradient-from, var(--c-accent, #ee7500)) 70%);
  background-size: 260% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
@media (prefers-reduced-motion: no-preference) {
  .anim-gradient { animation: anim-gradient-flow var(--anim-gradient-duration, 7s) linear infinite; }
}
@keyframes anim-gradient-flow {
  from { background-position: 0% 50%; }
  to   { background-position: -260% 50%; }
}

/* ---- 数値バー（anim-bar・JSが数字を読んでバーを足す）----
   中身の数字が満たす割合を棒で見せる。上限= --anim-bar-max（既定100）。anim-count と併用すると数字も動く。 */
/* ★バーは要素の【すぐ後ろの兄弟】として JS が足す（中に入れない）。anim-count は textContent を
   書き換えるので、中に入れたバーは併用した瞬間に消えるため（実装上の必然）。 */
.anim-bar-track {
  display: block;
  margin-top: var(--anim-bar-gap, .5rem);
  height: var(--anim-bar-height, 6px);
  border-radius: var(--anim-bar-radius, 999px);
  background: var(--anim-bar-bg, rgba(0, 0, 0, .1));
  overflow: hidden;
}
.anim-bar-fill {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: var(--anim-bar-color, var(--c-accent, #ee7500));
  width: var(--anim-bar-to, 0%);
}
@media (prefers-reduced-motion: no-preference) {
  html.anim-on .anim-bar + .anim-bar-track .anim-bar-fill {
    width: 0%;
    will-change: width;
    transition: width var(--anim-bar-duration, 1.2s) cubic-bezier(.22, .61, .36, 1);
    transition-delay: var(--anim-delay, 0s);
  }
  html.anim-on .anim-bar.is-inview + .anim-bar-track .anim-bar-fill { width: var(--anim-bar-to, 0%); }
}

/* ---- スクロール連動（anim-scrub・JSが 0→1 の進み具合を --p に流す）----
   無印は --p を配るだけ（decorations.css から自由に使える）。よく使う3つは修飾クラスで用意:
   anim-scrub-zoom（進むほど拡大）/ anim-scrub-rot（回る）/ anim-scrub-x（横に流れる）。 */
.anim-scrub { will-change: transform; }
@media (prefers-reduced-motion: no-preference) {
  html.anim-on .anim-scrub-zoom { transform: scale(calc(1 + var(--p, 0) * var(--anim-scrub-zoom-amount, .18))); }
  html.anim-on .anim-scrub-rot  { transform: rotate(calc(var(--p, 0) * var(--anim-scrub-rot-amount, 10deg))); }
  html.anim-on .anim-scrub-x    { transform: translate3d(calc((var(--p, 0) - .5) * var(--anim-scrub-x-amount, 140px)), 0, 0); }
}

/* ---- 固定して中身だけ進む（anim-pin）／横に流れる（anim-hscroll）----
   ★JS が外側に track（背の高い箱）を作り、本体を sticky にする＝reduce/JS無効では素の1画面のまま（何も起きない）。
   ★sticky は transform / filter / backdrop-filter を持つ祖先の下では効かない（anim-sticky と同じ制約）。
   ★キャッシュ系プラグインの「遅延描画（content-visibility）」が当たったセクションでも崩れる＝除外設定が要る。 */
.anim-pin-track, .anim-hscroll-track { position: relative; }
html.anim-on .anim-pin-track { height: var(--anim-pin-length, 220vh); }
/* ★「JS が箱を作った時だけ」効かせる（子セレクタで箱を要求する）。
   素の .anim-hscroll に固定＋overflow:hidden を当てると、JS が作らない場面
   ——狭い画面（768px未満）・reduced-motion・JS無効——で【中身が切り取られて見えなくなる】。
   実測: 幅390pxで6枚のカードのうち2枚しか出ず、残りは overflow に隠れて到達不能だった。 */
html.anim-on .anim-pin-track > .anim-pin {
  position: sticky;
  top: var(--anim-pin-top, 0px);
  min-height: var(--anim-pin-height, 100vh);
  display: flex;
  flex-direction: column;
  justify-content: center;
}
html.anim-on .anim-hscroll-track > .anim-hscroll {
  position: sticky;
  top: var(--anim-hscroll-top, 0px);
  height: var(--anim-hscroll-height, 100vh);
  overflow: hidden;
  display: flex;
  align-items: center;
}
html.anim-on .anim-hscroll-track > .anim-hscroll .anim-hs-row {
  display: flex;
  align-items: stretch;
  gap: var(--anim-hscroll-gap, 2rem);
  width: max-content;
  will-change: transform;
  transform: translate3d(calc(-1 * var(--p, 0) * var(--anim-hs-distance, 0px)), 0, 0);
}
html.anim-on .anim-hscroll-track > .anim-hscroll .anim-hs-row > * { flex: 0 0 auto; margin-top: 0; margin-bottom: 0; }

/* ---- 背景を幾何学の形がふわふわ上がる（anim-bubbles・CSSだけ・M20）----
   ヒーローや帯に付けると、地の上を四角・三角・丸・十字・六角の細い輪郭がゆっくり昇っていく。
   ★JS で形を作らない（DOM に要素を1つも増やさない）＝保存正規形も measure の要素数も動かない。
   ★形は **mask** で敷く（background-image に SVG を置くと色を CSS 変数で変えられない＝
     サイトごとの当て分けができなくなる）。SVG の線は**白**＝alpha でも luminance でも出る。
   仕組み: ::after に 5 層のタイルを敷き、mask-position を「その層のタイルの整数倍」だけ動かす
   ＝1周してもつなぎ目が出ない。
   ★**1層＝1つの格子**なので、素直に作ると「碁盤」に見えて演出にならない（2026-09-08 実測）。
     ①層ごとにタイルを**縦横比の違う長方形**にする ②大きさを互いに割り切れない比にする — の2つで、
     見かけの繰り返しが画面よりずっと大きくなり**ばらけて見える**。形は手前ほど大きく速い＝奥行き。
   ★SVG は既定の `xMidYMid meet` でタイルに収まる＝**長方形タイルでも形は歪まない**（1単位＝短辺/100）。
     線の太さは層ごとに割り戻して**見かけの太さを揃えて**ある。
   ★中身が形の下に隠れないよう直下の子を1段上げる。cover の写真と暗幕だけは最背面のまま
   （形は「写真の上・文字の下」に居るのが正しい）。
   調整= --anim-bubbles-color / -size（いちばん大きい形のタイル）/ -duration / -opacity */
.anim-bubbles { position: relative; }
.anim-bubbles > :not(.wp-block-cover__image-background):not(.wp-block-cover__background) {
  position: relative;
  z-index: 1;
}
.anim-bubbles > .wp-block-cover__background { z-index: 0; }
.anim-bubbles::after {
  --anim-bubbles-tile: var(--anim-bubbles-size, 560px);
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: var(--anim-bubbles-opacity, .5);
  background-color: var(--anim-bubbles-color, #fff);
  -webkit-mask-repeat: repeat;
          mask-repeat: repeat;
  -webkit-mask-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Crect x='12.50' y='58.50' width='9.00' height='9.00' fill='none' stroke='%23fff' stroke-width='0.24'/%3E%3C/svg%3E"),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Cpath d='M61.00 17.75L64.91 25.06L57.09 25.06Z' stroke-linejoin='round' fill='none' stroke='%23fff' stroke-width='0.28'/%3E%3C/svg%3E"),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Ccircle cx='33.00' cy='78.00' r='4.50' fill='none' stroke='%23fff' stroke-width='0.42'/%3E%3C/svg%3E"),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Cpath d='M82.00 36.75V45.25M77.75 41.00H86.25' stroke-linecap='round' fill='none' stroke='%23fff' stroke-width='0.45'/%3E%3C/svg%3E"),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Cpath d='M16.11 63.62L16.11 68.38L12.00 70.75L7.89 68.38L7.89 63.62L12.00 61.25Z' stroke-linejoin='round' fill='none' stroke='%23fff' stroke-width='0.54'/%3E%3C/svg%3E");
          mask-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Crect x='12.50' y='58.50' width='9.00' height='9.00' fill='none' stroke='%23fff' stroke-width='0.24'/%3E%3C/svg%3E"),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Cpath d='M61.00 17.75L64.91 25.06L57.09 25.06Z' stroke-linejoin='round' fill='none' stroke='%23fff' stroke-width='0.28'/%3E%3C/svg%3E"),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Ccircle cx='33.00' cy='78.00' r='4.50' fill='none' stroke='%23fff' stroke-width='0.42'/%3E%3C/svg%3E"),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Cpath d='M82.00 36.75V45.25M77.75 41.00H86.25' stroke-linecap='round' fill='none' stroke='%23fff' stroke-width='0.45'/%3E%3C/svg%3E"),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Cpath d='M16.11 63.62L16.11 68.38L12.00 70.75L7.89 68.38L7.89 63.62L12.00 61.25Z' stroke-linejoin='round' fill='none' stroke='%23fff' stroke-width='0.54'/%3E%3C/svg%3E");
  -webkit-mask-size:
    var(--anim-bubbles-tile) calc(var(--anim-bubbles-tile) * .83),
    calc(var(--anim-bubbles-tile) * .71) calc(var(--anim-bubbles-tile) * .94),
    calc(var(--anim-bubbles-tile) * .58) calc(var(--anim-bubbles-tile) * .47),
    calc(var(--anim-bubbles-tile) * .44) calc(var(--anim-bubbles-tile) * .67),
    calc(var(--anim-bubbles-tile) * .37) calc(var(--anim-bubbles-tile) * .52);
          mask-size:
    var(--anim-bubbles-tile) calc(var(--anim-bubbles-tile) * .83),
    calc(var(--anim-bubbles-tile) * .71) calc(var(--anim-bubbles-tile) * .94),
    calc(var(--anim-bubbles-tile) * .58) calc(var(--anim-bubbles-tile) * .47),
    calc(var(--anim-bubbles-tile) * .44) calc(var(--anim-bubbles-tile) * .67),
    calc(var(--anim-bubbles-tile) * .37) calc(var(--anim-bubbles-tile) * .52);
  animation: anim-bubbles-rise var(--anim-bubbles-duration, 26s) linear infinite;
}
@keyframes anim-bubbles-rise {
  from { -webkit-mask-position: 0 0, 0 0, 0 0, 0 0, 0 0; mask-position: 0 0, 0 0, 0 0, 0 0, 0 0; }
  to {
    -webkit-mask-position:
      calc(var(--anim-bubbles-tile) * 0.0) calc(var(--anim-bubbles-tile) * -2.49),
      calc(var(--anim-bubbles-tile) * 0.71) calc(var(--anim-bubbles-tile) * -2.82),
      calc(var(--anim-bubbles-tile) * -0.58) calc(var(--anim-bubbles-tile) * -0.94),
      calc(var(--anim-bubbles-tile) * 0.44) calc(var(--anim-bubbles-tile) * -1.34),
      calc(var(--anim-bubbles-tile) * 0.0) calc(var(--anim-bubbles-tile) * -1.04);
    mask-position:
      calc(var(--anim-bubbles-tile) * 0.0) calc(var(--anim-bubbles-tile) * -2.49),
      calc(var(--anim-bubbles-tile) * 0.71) calc(var(--anim-bubbles-tile) * -2.82),
      calc(var(--anim-bubbles-tile) * -0.58) calc(var(--anim-bubbles-tile) * -0.94),
      calc(var(--anim-bubbles-tile) * 0.44) calc(var(--anim-bubbles-tile) * -1.34),
      calc(var(--anim-bubbles-tile) * 0.0) calc(var(--anim-bubbles-tile) * -1.04);
  }
}

/* ---- reduced-motion：すべて最終静止状態（measure はこの状態を測る）---- */
@media (prefers-reduced-motion: reduce) {
  .anim-fade, .anim-fade-up, .anim-fade-down, .anim-fade-left, .anim-fade-right, .anim-zoom,
  .anim-pop, .anim-flip { opacity: 1 !important; transform: none !important; }
  .anim-blur { opacity: 1 !important; filter: none !important; }
  .anim-clip, .anim-clip-left, .anim-clip-down, .anim-clip-up { clip-path: none !important; }
  /* line は opacity を触らない（site.css 側で意図した半透明の線を reduce で潰さない） */
  .anim-line, .anim-line-left, .anim-line-down, .anim-line-up { transform: none !important; }
  .anim-sway, .anim-parallax { animation: none !important; transform: none !important; }
  /* 粒は消さず「止める」（reduce の約束＝最終静止状態。消すと地の見え方まで変わる） */
  .anim-bubbles::after { animation: none !important; }
  :is(.anim-wipe, .anim-wipe-left, .anim-wipe-down, .anim-wipe-up)::after { display: none !important; }
  :is(.anim-wipe, .anim-wipe-left, .anim-wipe-down, .anim-wipe-up) :is(img, .wp-block-cover__image-background) { opacity: 1 !important; }
  .anim-type .anim-caret { display: none !important; }
  /* anim-draw は JS がインライン化しない＝<img>のカラーロゴのまま。手動インラインSVGがあれば塗りだけ見せ線は出さない */
  .anim-draw svg path { stroke: none !important; }
  /* ---- M17 追加語彙 ---- */
  /* split / mask / scramble / marquee / bar / pin / hscroll は JS が動かない＝素のテキスト・素の箱のまま。
     ここで打ち消すのは「CSSだけで動く」ものと、JSが走った後に reduce へ切り替わった時の保険。 */
  :is(.anim-split, .anim-split-word) .anim-sp { opacity: 1 !important; transform: none !important; }
  .anim-mask .anim-ml { overflow: visible !important; }
  .anim-mask .anim-ml-i { transform: none !important; }
  .anim-marquee .anim-mq-track, .anim-marquee-rev .anim-mq-track { animation: none !important; transform: none !important; }
  .anim-gradient { animation: none !important; }
  .anim-bar-track .anim-bar-fill { transition: none !important; width: var(--anim-bar-to, 0%) !important; }
  .anim-scrub, .anim-scrub-zoom, .anim-scrub-rot, .anim-scrub-x { transform: none !important; }
  /* pin/hscroll は track ごと JS 産＝reduce では作られない。念のため sticky も解除しておく */
  .anim-pin, .anim-hscroll { position: static !important; height: auto !important; min-height: 0 !important; overflow: visible !important; }
  .anim-hscroll .anim-hs-row { transform: none !important; flex-wrap: wrap !important; width: auto !important; }
}

/* ===== anim-first（M20b・2026-09-20）: 画面の一番上に来る要素は「透明にして隠す」をやめる ==========
 *
 * ★なぜ要るか（実測・asobit.jp /service）: 出現アニメは中身を `opacity: 0` で隠す。ブラウザは
 *   透明な要素を「まだ描いていない」と数えるので、**画面でいちばん大きい絵が演出の後まで描かれたことにならない**
 *   ＝ LCP が 556ms（演出を外すと 40ms）。**演出を消さずに**中身を描いたまま隠すのがこの層。
 * ★「上にアニメを置かない」という決まりは作らない（ユーザー決定 2026-09-20）。置き方の側を安全にする。
 * ★印は静的公開の工程が本文の先頭ひと塊へ自動で付ける（speed.firstScreenAnim）。手で `anim-first` と書けば
 *   どこでも効き、`anim-keep` と書けば自動では付かない（今までどおりの隠し方のまま）。
 *
 * 隠し方の置き換え:
 *   wipe 系 … 帯（::after）が**最初から覆っていて退く**（中身は最初から不透明）。見た目の signature は同じ。
 *   fade 系 … 透明にせず**動き（transform）だけ**。
 * ★覆いはブラウザの「描いたか」の判定に影響しない（遮蔽は考慮されない）＝中身を描いた時刻がそのまま記録される。
 *   Google の案内（中身を opacity でフェードインさせず transform で動かす）と同じ向きの作り。
 */
@media (prefers-reduced-motion: no-preference) {
  html.anim-on .anim-first:is(.anim-wipe, .anim-wipe-left, .anim-wipe-down, .anim-wipe-up) :is(img, .wp-block-cover__image-background) { opacity: 1; }
  html.anim-on .anim-first:is(.anim-wipe, .anim-wipe-left, .anim-wipe-down, .anim-wipe-up)::after { transform: scaleX(1); transform-origin: right center; }
  html.anim-on .anim-first.anim-wipe-left::after  { transform: scaleX(1); transform-origin: left center; }
  html.anim-on .anim-first.anim-wipe-down::after  { transform: scaleY(1); transform-origin: center bottom; }
  html.anim-on .anim-first.anim-wipe-up::after    { transform: scaleY(1); transform-origin: center top; }
  html.anim-on .anim-first:is(.anim-wipe, .anim-wipe-left, .anim-wipe-down, .anim-wipe-up).is-inview::after {
    animation-name: anim-first-wipe-x;
    animation-duration: calc(var(--anim-wipe-duration, 1.1s) * .55);   /* 走って戻る半分＝同じ手触り */
  }
  html.anim-on .anim-first:is(.anim-wipe-down, .anim-wipe-up).is-inview::after { animation-name: anim-first-wipe-y; }
  /* fade 系は透明にしない（動きだけ）。transform の初期値は元の規則のまま効く */
  html.anim-on .anim-first:is(.anim-fade, .anim-fade-up, .anim-fade-down, .anim-fade-left, .anim-fade-right, .anim-zoom, .anim-blur, .anim-pop, .anim-flip) { opacity: 1; }
  /* 文字を1字ずつ出す演出も、上に来た時は透明にしない（見出しが的になる） */
  html.anim-on .anim-first:is(.anim-split, .anim-split-word) .anim-sp { opacity: 1; }
}
@keyframes anim-first-wipe-x { from { transform: scaleX(1); } to { transform: scaleX(0); } }
@keyframes anim-first-wipe-y { from { transform: scaleY(1); } to { transform: scaleY(0); } }
