/* ============================================================
   GrowthSurvey モーション層（公開ページ）v24
   ------------------------------------------------------------
   置き場所: app/css/motion.css
   読み込み: 25 枚すべてで tokens.css → neumorphism.css → motion.css の順。
             （後勝ちで部品の静止時の指定に動きを上乗せするため、必ず最後）

   なぜ要るか
     v21 でニューモフィズムを撤廃したとき、動きを担っていた手段（影とグラデーション）を
     機械で消したが、代わりの語彙を用意しなかった。結果、公開ページの動きは
     「色が変わる」だけになった（2026-09-06 に本番を計測。234 要素中 遷移ありは 29、
     ページ内の @keyframes は 2、動きを伴うホバーは 5 で、その 5 つは全て影を消す指定）。

   立て直しの原則 ── 構造は静止させ、状態を動かす
     構造（静止しているとき）は面と 1px 罫線だけで作る。ここは一切変えない。
     影・グラデーション・光は、状態が変わった瞬間と、注目させたい一箇所にだけ使う。
     「面の分離に影を使わない」という決まりは、そのまま守られている。

   守っていること
     - 色は一つも直書きしない。透明度は color-mix(in srgb, var(--gs-X) N%, transparent)
     - 面にグラデーションを敷かない。文字の中（background-clip: text）と
       枠だけ（mask で 2px に限る）にとどめる
     - 止まらない動きは 1 画面に 1 箇所まで
     - 動きを減らす設定では、位置と大きさの変化を止め、色と形で状態を伝える
     - 教材を解いている最中の画面・図表の中・数字そのものには置かない
   ============================================================ */

@property --gs-a { syntax: '<angle>'; initial-value: 0deg; inherits: false; }

/* ============================================================
   1. 全体の遷移 ── 部品が「色以外」でも動けるようにする
   ------------------------------------------------------------
   これまでの --neo-transition は background-color / border-color / color の
   三つだけだった。仕組みとして色以外の動き方を持てなかったのは、ここが原因。
   ============================================================ */

.neo-card,
.neo-stat-card,
.neo-btn,
.neo-nav-link,
.neo-sidebar-link,
.neo-hamburger,
.neo-tab,
.neo-modal-close {
  transition:
    background-color var(--gs-dur-state) var(--gs-ease-standard),
    border-color     var(--gs-dur-state) var(--gs-ease-standard),
    color            var(--gs-dur-state) var(--gs-ease-standard),
    box-shadow       var(--gs-dur-state) var(--gs-ease-out),
    transform        var(--gs-dur-state) var(--gs-ease-out);
}

/* 押した瞬間の反応だけは速くする。ここが遅いと「効いていない」と感じる。 */
.neo-btn, .neo-tab, .neo-nav-link, .neo-sidebar-link, .neo-hamburger {
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
.neo-btn:active:not(:disabled),
.neo-tab:active,
.neo-hamburger:active { transform: scale(var(--gs-press-scale)); }

/* ============================================================
   2. 浮き上がり ── 触れたことを、面が答える
   ------------------------------------------------------------
   静止時の影は 0 のまま。影は状態の材料としてだけ使う。
   ============================================================ */

/* 浮かせるのは「押せる面」だけにする。読むための面は動かさない。
   理由は二つある。
     1. 浮き上がりは「押せる」という合図なので、押せない面が浮くと嘘になる。
     2. transform を持つ面は、その中の絶対位置の子にとって基準の箱になる。
        読むための面を一律に浮かせたところ、中に操作部品を並べた面で、
        触れたときに中身が 24px 横へ動いた（2026-09-06。見切れの検査で見つけた。
        375px 幅の組織レポートで、絞り込みの選択欄が画面の左端まで寄り、
        焦点の輪が 5px 切れていた）。
   押せない面には、罫線の濃さの変化だけを残す。 */
.neo-card:hover,
.neo-stat-card:hover { border-color: var(--gs-rule-strong); }

a > .neo-card:hover,
button.neo-card:hover,
.neo-card[role="button"]:hover,
.neo-card[tabindex]:hover,
.neo-card[onclick]:hover,
a > .neo-stat-card:hover,
.neo-stat-card[role="button"]:hover,
.neo-stat-card[tabindex]:hover,
.neo-stat-card[onclick]:hover,
.gs-m-lift:hover {
  transform: translateY(var(--gs-lift));
  border-color: var(--gs-rule-strong);
  box-shadow: var(--gs-glow-soft);
}

/* ボタンは持ち上げない（2026-09-06）。
   1px の持ち上がりのために transform を持たせると、その要素は
   中の絶対位置の子にとって基準の箱になり、並びによっては行ごと横へ動く。
   375px 幅の組織レポートで、絞り込みの行が画面の左端まで 24px 寄り、
   焦点の輪が 5px 切れていた（見切れの検査が拾った）。
   ボタンの表情は、淡い光と走る光の二つで足りる。位置は動かさない。
   押した瞬間の縮み（:active）は一瞬で戻るので残す。 */
.neo-btn-primary:hover:not(:disabled),
.neo-btn-secondary:hover:not(:disabled) { box-shadow: var(--gs-glow-soft); }

/* 表の行は浮かせない。行が動くと、隣の行との対応が読み取りにくくなる。 */
.neo-table tbody tr:hover { background: var(--gs-surface-1); }

/* ============================================================
   3. 走る光 ── 押せるものだと、一目で分かる
   ------------------------------------------------------------
   一度だけ横切る。繰り返さないので、うるさくならない。
   ============================================================ */

.neo-btn-primary,
.neo-btn-secondary,
.gs-m-sheen { position: relative; overflow: hidden; isolation: isolate; }

/* 静止しているときの ::after は、空の箱でしかない。
   帯（グラデーション）はホバーの中でだけ生やす。
   こうしておくと「面にグラデーションを敷いていない」を、
   透明度への言い訳なしに、そのまま満たせる。 */
.neo-btn-primary::after,
.neo-btn-secondary::after,
.gs-m-sheen::after {
  content: ''; position: absolute; inset: 0; z-index: 1;
  pointer-events: none;
  transform: translateX(-130%);
  opacity: 0;
}

.neo-btn-primary:hover:not(:disabled)::after,
.neo-btn-secondary:hover:not(:disabled)::after,
.neo-btn-primary:focus-visible::after,
.neo-btn-secondary:focus-visible::after,
.gs-m-sheen:hover::after,
.gs-m-sheen:focus-visible::after {
  /* 塗りの上を通る帯。地の色を薄く重ねるだけで、色は足していない。 */
  background: linear-gradient(112deg,
    transparent 38%,
    color-mix(in srgb, var(--gs-ground) 78%, transparent) 50%,
    transparent 62%);
  animation: gs-sheen var(--gs-dur-sheen) var(--gs-ease-out);
}

/* 白い面の上を走らせるときは、地の色では見えないので基調色の帯にする。 */
.gs-m-sheen.on-light:hover::after,
.gs-m-sheen.on-light:focus-visible::after {
  background: linear-gradient(112deg,
    transparent 38%,
    color-mix(in srgb, var(--gs-primary) 20%, transparent) 50%,
    transparent 62%);
}

@keyframes gs-sheen {
  0%   { transform: translateX(-130%); opacity: 0; }
  12%  { opacity: 1; }
  100% { transform: translateX(130%);  opacity: 0; }
}

/* ============================================================
   4. 文字を流れる光 ── 見出しの中を、色がゆっくり動く
   ------------------------------------------------------------
   名指しで付ける（.gs-m-flow）。1 画面に 1 箇所まで。
   使う色は --gs-primary-strong（対白 7.02:1）と --gs-secondary（4.63:1）だけなので、
   流れのどの瞬間でも AA を下回らない。
   ============================================================ */

/* 対応していない環境では、この単色で出る。グラデーションは一切敷かない。 */
.gs-m-flow { color: var(--gs-primary-strong); }

/* グラデーションと background-clip: text は、必ず同じ塊に置く。
   離して書くと「面に敷いたグラデーション」と区別できなくなり、
   検査からも、読む人からも、文字の中の色だと分からなくなる。 */
@supports (background-clip: text) or (-webkit-background-clip: text) {
  .gs-m-flow {
    background-image: linear-gradient(100deg,
      var(--gs-primary-strong) 0%,
      var(--gs-primary-strong) 34%,
      var(--gs-secondary)      46%,
      var(--gs-primary-strong) 58%,
      var(--gs-primary-strong) 100%);
    background-size: 280% 100%;
    background-position: 100% 0;
    -webkit-background-clip: text;
            background-clip: text;
    color: transparent;
    animation: gs-flow var(--gs-dur-ambient) linear infinite;
  }
}

@keyframes gs-flow { to { background-position: -180% 0; } }

/* ============================================================
   5. 周りを回る光 ── 見てほしい一枚にだけ
   ------------------------------------------------------------
   mask で枠の 2px 分だけ残す。面の上には一切かからない。
   1 画面に 1 箇所まで。増やすと、どれも目立たなくなる。
   ============================================================ */

.gs-m-orbit { position: relative; }

.gs-m-orbit::before {
  content: ''; position: absolute; inset: -1px;
  border-radius: inherit; padding: 2px;
  pointer-events: none;
  background: conic-gradient(from var(--gs-a),
    transparent 0turn,
    transparent .58turn,
    color-mix(in srgb, var(--gs-primary)   90%, transparent) .74turn,
    color-mix(in srgb, var(--gs-secondary) 90%, transparent) .84turn,
    transparent 1turn);
  /* 切り抜きは色ではなく不透明度で効く。純黒を書かずに currentColor を使う
     （どんな色でも不透明であれば同じに切り抜ける。色の直書きも純黒も要らない）。 */
  -webkit-mask: linear-gradient(currentColor 0 0) content-box, linear-gradient(currentColor 0 0);
          mask: linear-gradient(currentColor 0 0) content-box, linear-gradient(currentColor 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  animation: gs-orbit var(--gs-dur-orbit) linear infinite;
}

@keyframes gs-orbit { to { --gs-a: 360deg; } }

/* ============================================================
   6. 段差で現れる ── 一覧が、順番に置かれる
   ------------------------------------------------------------
   止まった状態が既定。読み込みが終わった時点で全部見えており、動きは上乗せ。
   親に .gs-m-stagger、子に --i を 0 から振る。
   ============================================================ */

.gs-m-stagger > * {
  animation: gs-rise var(--gs-dur-enter) var(--gs-ease-out) both;
  animation-delay: calc(var(--i, 0) * var(--gs-stagger));
}

@keyframes gs-rise {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

/* ============================================================
   7. 押した手応え ── 選んだことが、身体で分かる
   ------------------------------------------------------------
   学習基盤の motion.css に既にあるものと同じ値・同じ名前。
   ============================================================ */

.gs-m-commit.is-on { animation: gs-commit 380ms var(--gs-ease-commit); }

@keyframes gs-commit {
  0%   { transform: scale(1); }
  38%  { transform: scale(1.09); }
  100% { transform: scale(1); }
}

/* ============================================================
   8. 動きを減らす設定
   ------------------------------------------------------------
   位置と大きさの変化を止め、色と形だけで状態を伝える。
   状態が変わったことは伝えたまま、動きによる負担を取り除く。
   ============================================================ */

@media (prefers-reduced-motion: reduce) {
  a > .neo-card:hover, button.neo-card:hover,
  .neo-card[role="button"]:hover, .neo-card[tabindex]:hover, .neo-card[onclick]:hover,
  a > .neo-stat-card:hover, .neo-stat-card[role="button"]:hover,
  .neo-stat-card[tabindex]:hover, .neo-stat-card[onclick]:hover,
  .gs-m-lift:hover,
  .neo-btn-primary:hover:not(:disabled),
  .neo-btn-secondary:hover:not(:disabled) {
    transform: none;
    box-shadow: none;
  }
  .neo-btn:active:not(:disabled),
  .neo-tab:active,
  .neo-hamburger:active { transform: none; }

  .neo-btn-primary::after,
  .neo-btn-secondary::after,
  .gs-m-sheen::after { display: none; }

  .gs-m-flow { animation: none; background-position: 40% 0; }

  .gs-m-orbit::before { animation: none; --gs-a: 270deg; }

  .gs-m-stagger > * { animation: none; }

  .gs-m-commit.is-on { animation: none; }
}

/* ============================================================
   9. 訴求ページ（top.html）と料金の部品
   ------------------------------------------------------------
   top.html は Tailwind で組まれており、部品を .lp-* という別の名前で持っている。
   値は --lp-* から --gs-* へ通してあるので、動きの規則だけをここで合わせる。
   ============================================================ */

.lp-card, .lp-card-sm, .lp-btn, .lp-btn-accent, .lp-dark-btn, .plan-card {
  transition:
    background-color var(--gs-dur-state) var(--gs-ease-standard),
    border-color     var(--gs-dur-state) var(--gs-ease-standard),
    color            var(--gs-dur-state) var(--gs-ease-standard),
    box-shadow       var(--gs-dur-state) var(--gs-ease-out),
    transform        var(--gs-dur-state) var(--gs-ease-out);
}

.lp-btn, .lp-btn-accent, .lp-dark-btn {
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
.lp-btn:active, .lp-btn-accent:active, .lp-dark-btn:active { transform: scale(var(--gs-press-scale)); }

/* 訴求ページと料金の面は、どれも押せる面（中に主要な導線がある）ので浮かせてよい。
   ただし中の操作部品に触れている間は動かさない。 */
.lp-card:hover:not(:has(input:hover, select:hover, textarea:hover)),
.lp-card-sm:hover:not(:has(input:hover, select:hover, textarea:hover)),
.plan-card:hover:not(:has(input:hover, select:hover, textarea:hover)) {
  transform: translateY(var(--gs-lift));
  border-color: var(--gs-rule-strong);
  box-shadow: var(--gs-glow-soft);
}

/* 一番押してほしいボタンにだけ、光を走らせる。 */
.lp-btn-accent { position: relative; overflow: hidden; isolation: isolate; }
.lp-btn-accent::after {
  content: ''; position: absolute; inset: 0; z-index: 1;
  pointer-events: none; transform: translateX(-130%); opacity: 0;
}
.lp-btn-accent:hover::after,
.lp-btn-accent:focus-visible::after {
  background: linear-gradient(112deg,
    transparent 38%,
    color-mix(in srgb, var(--gs-ground) 78%, transparent) 50%,
    transparent 62%);
  animation: gs-sheen var(--gs-dur-sheen) var(--gs-ease-out);
}
.lp-btn-accent:hover { box-shadow: var(--gs-glow-firm); }

/* おすすめのプランの枠を、光が一周する。
   1 画面に 1 箇所という決まりを、部品の側で守らせている
   （おすすめのプランは、どちらの画面にも一枚しかない）。 */
.lp-plan-popular, .plan-card.popular { position: relative; }
.lp-plan-popular::before,
.plan-card.popular::before {
  content: ''; position: absolute; inset: -1px;
  border-radius: inherit; padding: 2px;
  pointer-events: none;
  background: conic-gradient(from var(--gs-a),
    transparent 0turn,
    transparent .58turn,
    color-mix(in srgb, var(--gs-primary)   90%, transparent) .74turn,
    color-mix(in srgb, var(--gs-secondary) 90%, transparent) .84turn,
    transparent 1turn);
  /* 切り抜きは色ではなく不透明度で効く。純黒を書かずに currentColor を使う
     （どんな色でも不透明であれば同じに切り抜ける。色の直書きも純黒も要らない）。 */
  -webkit-mask: linear-gradient(currentColor 0 0) content-box, linear-gradient(currentColor 0 0);
          mask: linear-gradient(currentColor 0 0) content-box, linear-gradient(currentColor 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  animation: gs-orbit var(--gs-dur-orbit) linear infinite;
}

@media (prefers-reduced-motion: reduce) {
  .lp-card:hover, .lp-card-sm:hover, .plan-card:hover,
  .neo-card:hover, .neo-stat-card:hover,
  .lp-btn-accent:hover { transform: none; box-shadow: none; }
  .lp-btn:active, .lp-btn-accent:active, .lp-dark-btn:active { transform: none; }
  .lp-btn-accent::after { display: none; }
  .lp-plan-popular::before, .plan-card.popular::before { animation: none; --gs-a: 270deg; }
}

/* 色を強制する設定（Windows のハイコントラスト等）では、
   background-clip: text の下地が塗られず、文字が消えることがある。
   透明にした文字色を、必ず実体のある色へ戻す。 */
@media (forced-colors: active) {
  .gs-m-flow {
    background-image: none;
    -webkit-background-clip: border-box;
            background-clip: border-box;
    color: CanvasText;
    animation: none;
  }
  .gs-m-orbit::before,
  .lp-plan-popular::before,
  .plan-card.popular::before { display: none; }
}
