/**
 * Hero Slide Styles v2.0.0
 * ヒーロースライド用CSSスタイル
 * 
 * 機能:
 * - Ken Burnsエフェクト（ズーム/パン）
 * - テキストアニメーション用ヘルパークラス
 * - レスポンシブ対応
 * - Swiperカスタマイズ
 * - テキスト位置をmax-w-7xlコンテナに合わせる（ヘッダーと同じ位置）
 * 
 * 依存:
 * - Swiper.js v12+
 * - Animate.css v4.1.1+
 * 
 * @version 2.0.0
 */


/* ========================================
   Hero Slide Container
   ======================================== */

.hero-slide-container {
    position: relative;
    width: 100%;
    height: 85vh;
    min-height: 500px;
    max-height: 900px;
    overflow: hidden;
    background-color: #0f172a;
    /* ========== 変更: 表示速度の改善（LCP）— JS の準備を待たずに表示する ==========
       以前は opacity: 0 で隠しておき、HeroSlide.razor.js が Swiper の初期化後に .hero-slide-ready を
       付けてフェードインさせていた。スマホでは blazor.web.js → JS Initializer → HeroSlide.razor.js → Swiper の
       読み込みと実行が終わるまでヒーロー画像（ページで最も大きな要素）が見えず、LCP が大きく遅れていた。
       フェードイン（0.5秒）は CSS アニメーションで残し、最初の描画からすぐに始める。
       - JS の準備前は下の「Fallback / No JS」の .no-js の指定で1枚目のスライドだけを表示する
       - Ken Burns の開始位置は「Ken Burns の開始位置」で最初から合わせているため、Swiper の初期化時に画像は動かない
       - .hero-slide-ready は引き続き HeroSlide.razor.js が初期化完了の目印として付けるが、表示には使っていない ========== */
    animation: hero-slide-fade-in 0.5s ease-out both;
}

/* フェードインは opacity: 0 ではなく 0.01（見た目では区別できない）から始める。
   Chrome は opacity: 0 の状態で描かれた画像を LCP の対象から外し、opacity のアニメーションは再描画を伴わないため、
   キャッシュ済みの画像が最初のフレームで描かれると、Swiper の初期化で再描画されるまで LCP が記録されない
   （2026-10-30 の計測で確認。2回目の訪問で LCP が JS の準備完了まで遅れた） */
@keyframes hero-slide-fade-in {
    from {
        opacity: 0.01;
    }

    to {
        opacity: 1;
    }
}

/* スライドが無いときの代わりの表示は、以前どおりフェードインせずにすぐ表示する */
.hero-slide-container.hero-slide-fallback {
    animation: none;
}

@media (max-width: 768px) {
    .hero-slide-container {
        height: 70vh;
        min-height: 400px;
    }
}


/* ========================================
   Swiper Customization
   ======================================== */

.hero-slide-container .swiper {
    width: 100% !important;
    height: 100% !important;
    overflow: visible !important;
}

.hero-slide-container .swiper-wrapper {
    display: flex !important;
    width: 100% !important;
    height: 100% !important;
    transition-property: transform !important;
}

.hero-slide-container .swiper-slide {
    position: relative !important;
    overflow: hidden !important;
    width: 100% !important;
    height: 100% !important;
    flex-shrink: 0 !important;
    /* ========== スタッキングコンテキスト修正 ========== */
    /* Swiper fadeエフェクトでは全スライドが重なるが、初回ロード時に
       Swiperが非アクティブスライドにz-indexを設定しない場合がある。
       その場合、子要素の z-index: 20（.hero-slide-content）が親の
       スタッキングコンテキストに漏れ、最後のスライドのテキスト領域が
       全スライドの上に来てしまう。z-index: 0 を設定することで全スライドに
       スタッキングコンテキストを作成し、子要素のz-indexをスライド内に限定する。
       Swiperのインラインスタイル（z-index: 1等）が適用されればCSSを上書きするため、
       アクティブスライドの重なり順序には影響しない */
    z-index: 0;
}

/* ========== Fadeモード: 非アクティブスライドのポインターイベント完全無効化 ========== */
/* z-indexの修正に加え、非アクティブスライドの全子要素のポインターイベントも無効化。
   .hero-slide-text に pointer-events: auto が明示設定されているため、
   親の pointer-events: none だけでは子要素のイベント捕捉を防げない。
   全子孫要素を対象にすることで確実に無効化する */
.hero-slide-container .swiper-slide:not(.swiper-slide-active) {
    pointer-events: none !important;
}

.hero-slide-container .swiper-slide:not(.swiper-slide-active) * {
    pointer-events: none !important;
}


/* ========================================
   Slide Background
   ======================================== */

.hero-slide-bg {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    overflow: hidden;
}

.hero-slide-image {
    width: 100%;
    height: 100%;
    object-fit: cover;
    will-change: transform;
    transform-origin: center center;
}

.hero-slide-overlay {
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 5;
}


/* ========================================
   Video Background
   ======================================== */

.hero-slide-video {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* ========== 動画フィルタープリセット ========== */

.hero-slide__video--slight-blur {
    filter: blur(1px) contrast(1.05);
}

.hero-slide__video--medium-blur {
    filter: blur(2px) contrast(1.1);
}

.hero-slide__video--film-grain {
    position: relative;
}

/* フィルムグレイン: アニメーション付きノイズテクスチャオーバーレイ（::after疑似要素）
   SVGノイズテクスチャの位置をアニメーションでシフトさせ、
   動的なフィルムグレイン効果で階調不足やブロック感を目立たなくする */
.hero-slide-bg:has(.hero-slide__video--film-grain)::after {
    content: '';
    position: absolute;
    /* insetを負の値に拡張し、アニメーション時にテクスチャの端が見えないようにする */
    inset: -50%;
    width: 200%;
    height: 200%;
    z-index: 2;
    pointer-events: none;
    opacity: 0.18;
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E");
    background-repeat: repeat;
    background-size: 256px 256px;
    mix-blend-mode: overlay;
    animation: heroGrainShift 0.8s steps(6) infinite;
}

/* ========== 強めのグレイン: 低画質動画向け ==========
   blur(1.5px)でブロックノイズを平滑化 + contrast(1.15)で視覚的コントラストを補正 +
   高密度・高不透明度のアニメーショングレインで階調不足やブロック感を積極的にカバー */
.hero-slide__video--heavy-grain {
    filter: blur(1.5px) contrast(1.15);
}

.hero-slide-bg:has(.hero-slide__video--heavy-grain)::after {
    content: '';
    position: absolute;
    inset: -50%;
    width: 200%;
    height: 200%;
    z-index: 2;
    pointer-events: none;
    opacity: 0.35;
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.75' numOctaves='5' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E");
    background-repeat: repeat;
    background-size: 256px 256px;
    mix-blend-mode: overlay;
    animation: heroGrainShift 0.6s steps(8) infinite;
}

/* グレインアニメーション: ノイズテクスチャをランダム風にシフトさせることで
   静的なパターンに見えることを防ぎ、自然なフィルムグレイン感を演出する */
@keyframes heroGrainShift {
    0%, 100% { transform: translate(0, 0); }
    12.5% { transform: translate(-8%, -12%); }
    25% { transform: translate(6%, -18%); }
    37.5% { transform: translate(-14%, 8%); }
    50% { transform: translate(10%, -6%); }
    62.5% { transform: translate(-4%, 16%); }
    75% { transform: translate(12%, 4%); }
    87.5% { transform: translate(-10%, -8%); }
}

/* ========== ドットフィルター: radial-gradient網目ドットパターン ==========
   2つのradial-gradientを半グリッド分オフセットして重ねることで、
   網目状のドットパターンを生成。ドットが動画のブロックノイズや
   階調不足を視覚的に分断し、低解像度感を紛らわせる。
   参考: https://web-den.com/dot-filter-video */

/* ドットパターン（スタンダード）: 6pxグリッドの不透明ドットパターン */
.hero-slide-bg:has(.hero-slide__video--dot-filter)::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 2;
    pointer-events: none;
    background-color: rgba(0, 0, 0, 0.4);
    background-image:
        radial-gradient(black 20%, transparent 20%),
        radial-gradient(black 20%, transparent 20%);
    background-size: 6px 6px;
    background-position: 0 0, 3px 3px;
}

/* ドットパターン（ストロング）: 4pxグリッドのより密な不透明ドットパターン + blur(1px)
   ドットが細かくなることでより効果的にブロック感を隠蔽し、
   blur との併用でかなり低画質な動画にも対応 */
.hero-slide__video--heavy-dot-filter {
    filter: blur(1px);
}

.hero-slide-bg:has(.hero-slide__video--heavy-dot-filter)::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 2;
    pointer-events: none;
    background-color: rgba(0, 0, 0, 0.5);
    background-image:
        radial-gradient(black 25%, transparent 25%),
        radial-gradient(black 25%, transparent 25%);
    background-size: 4px 4px;
    background-position: 0 0, 2px 2px;
}

/* ========== ドットパターン（ライト）: 半透明ドット・5pxグリッド ==========
   ドットに透明度を持たせることで粒の存在感を抑え、
   動画の色味を活かしながら低解像度感を軽減する控えめな効果 */
.hero-slide-bg:has(.hero-slide__video--dot-filter-light)::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 2;
    pointer-events: none;
    background-color: rgba(0, 0, 0, 0.25);
    background-image:
        radial-gradient(rgba(0, 0, 0, 0.35) 15%, transparent 15%),
        radial-gradient(rgba(0, 0, 0, 0.35) 15%, transparent 15%);
    background-size: 5px 5px;
    background-position: 0 0, 2.5px 2.5px;
}

/* ========== ドットパターン（ソフト）: 半透明ドット・4pxグリッド ==========
   ライトより密度を上げつつ、半透明ドットにより自然な質感を維持。
   画質カバーと視覚的な自然さのバランスが良い */
.hero-slide-bg:has(.hero-slide__video--dot-filter-soft)::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 2;
    pointer-events: none;
    background-color: rgba(0, 0, 0, 0.3);
    background-image:
        radial-gradient(rgba(0, 0, 0, 0.45) 20%, transparent 20%),
        radial-gradient(rgba(0, 0, 0, 0.45) 20%, transparent 20%);
    background-size: 4px 4px;
    background-position: 0 0, 2px 2px;
}

/* ========== ドットパターン（デンス）: 半透明ドット・3pxグリッド ==========
   非常に高密度なドットパターンだが、半透明にすることで
   密度の割にドットが目立たず、効果的に低解像度感を分散する */
.hero-slide-bg:has(.hero-slide__video--dot-filter-dense)::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 2;
    pointer-events: none;
    background-color: rgba(0, 0, 0, 0.3);
    background-image:
        radial-gradient(rgba(0, 0, 0, 0.5) 22%, transparent 22%),
        radial-gradient(rgba(0, 0, 0, 0.5) 22%, transparent 22%);
    background-size: 3px 3px;
    background-position: 0 0, 1.5px 1.5px;
}

.hero-slide__video--cinematic {
    filter: blur(1px) brightness(0.9) contrast(1.1);
}

/* シネマティック: ビネット効果 */
.hero-slide-bg:has(.hero-slide__video--cinematic)::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 2;
    pointer-events: none;
    background: radial-gradient(ellipse at center, transparent 50%, rgba(0, 0, 0, 0.4) 100%);
}

/* ========== prefers-reduced-motion: 動画を停止しポスター画像をフォールバック表示 ========== */

@media (prefers-reduced-motion: reduce) {
    /* グレインアニメーションを停止（テクスチャは静的表示を維持） */
    .hero-slide-bg:has(.hero-slide__video--film-grain)::after,
    .hero-slide-bg:has(.hero-slide__video--heavy-grain)::after {
        animation: none;
    }

    .hero-slide-video {
        display: none;
    }

    /* ポスター画像のフォールバック表示
       Razor側で .hero-slide-bg に --poster-url CSS変数をインラインスタイルで設定済み
       CSS変数はvar()で参照されるまでリソースをダウンロードしないため、
       reduced-motion以外ではポスター画像の余分なダウンロードは発生しない */
    .hero-slide-bg {
        background-image: var(--poster-url, none);
        background-size: cover;
        background-position: center;
    }

    /* 動画フィルターのオーバーレイも非表示 */
    .hero-slide-bg:has(.hero-slide-video)::after {
        display: none;
    }
}

/* ========== 動画無効化: 低速回線/データセーバー時（JSで .hero-slide-video-disabled クラス付与） ========== */

.hero-slide-video-disabled .hero-slide-video {
    display: none;
}

.hero-slide-video-disabled .hero-slide-bg {
    background-image: var(--poster-url, none);
    background-size: cover;
    background-position: center;
}

.hero-slide-video-disabled .hero-slide-bg::after {
    display: none;
}


/* ========================================
   Ken Burns Effects
   ======================================== */

.hero-slide-image.kenburns-none {
    animation: none !important;
    transform: scale(1);
}

.hero-slide-image.kenburns-zoom-in {
    animation: kenburnsZoomIn var(--slide-duration, 7s) ease-out forwards !important;
}

@keyframes kenburnsZoomIn {
    0% { transform: scale(1); }
    100% { transform: scale(1.15); }
}

.hero-slide-image.kenburns-zoom-out {
    animation: kenburnsZoomOut var(--slide-duration, 7s) ease-out forwards !important;
}

@keyframes kenburnsZoomOut {
    0% { transform: scale(1.15); }
    100% { transform: scale(1); }
}

.hero-slide-image.kenburns-pan-left {
    animation: kenburnsPanLeft var(--slide-duration, 7s) ease-out forwards !important;
}

@keyframes kenburnsPanLeft {
    0% { transform: scale(1.1) translateX(5%); }
    100% { transform: scale(1.1) translateX(-5%); }
}

.hero-slide-image.kenburns-pan-right {
    animation: kenburnsPanRight var(--slide-duration, 7s) ease-out forwards !important;
}

@keyframes kenburnsPanRight {
    0% { transform: scale(1.1) translateX(-5%); }
    100% { transform: scale(1.1) translateX(5%); }
}

.hero-slide-image.kenburns-pan-up {
    animation: kenburnsPanUp var(--slide-duration, 7s) ease-out forwards !important;
}

@keyframes kenburnsPanUp {
    0% { transform: scale(1.1) translateY(5%); }
    100% { transform: scale(1.1) translateY(-5%); }
}

.hero-slide-image.kenburns-pan-down {
    animation: kenburnsPanDown var(--slide-duration, 7s) ease-out forwards !important;
}

@keyframes kenburnsPanDown {
    0% { transform: scale(1.1) translateY(-5%); }
    100% { transform: scale(1.1) translateY(5%); }
}

/* ========== 追加: Ken Burns の開始位置（JS の準備前からヒーローを表示するための対応） ==========
   各効果の開始位置（上の各 @keyframes の 0%）を最初から当てておく。これが無いと、JS の準備前は
   拡大・移動していない状態で表示され、HeroSlide.razor.js が効果を始めた瞬間に画像が開始位置へ跳ねて見える
   （以前はヒーロー全体を JS の準備まで隠していたため見えなかった）。
   data-kenburns は HeroSlide.razor がスライドごとに出力する（静止・動画のスライドは空のため対象外）。
   - 効果の実行中はアニメーションの値が優先される
   - 効果の停止後（stopKenBurns）は開始位置に戻るため、次にそのスライドへ切り替わったときも跳ねない
   - @keyframes の 0% を変えるときは、ここも同じ値に揃えること ========== */
.swiper-slide[data-kenburns="kenburns-zoom-out"] .hero-slide-image {
    transform: scale(1.15);
}

.swiper-slide[data-kenburns="kenburns-pan-left"] .hero-slide-image {
    transform: scale(1.1) translateX(5%);
}

.swiper-slide[data-kenburns="kenburns-pan-right"] .hero-slide-image {
    transform: scale(1.1) translateX(-5%);
}

.swiper-slide[data-kenburns="kenburns-pan-up"] .hero-slide-image {
    transform: scale(1.1) translateY(5%);
}

.swiper-slide[data-kenburns="kenburns-pan-down"] .hero-slide-image {
    transform: scale(1.1) translateY(-5%);
}


/* ========================================
   Text Content Layer
   ヘッダーと同じ max-w-7xl mx-auto px-4 sm:px-6 に合わせる
   ======================================== */

.hero-slide-content {
    position: absolute;
    inset: 0;
    z-index: 20;
    display: flex;
    pointer-events: none;
    padding-top: 2rem;
    padding-bottom: 2rem;
}

@media (min-width: 768px) {
    .hero-slide-content {
        padding-top: 4rem;
        padding-bottom: 4rem;
    }
}

.hero-slide-text {
    width: 100%;
    max-width: 1280px;
    margin-left: auto;
    margin-right: auto;
    padding-left: 1rem;
    padding-right: 1rem;
    pointer-events: auto;
    box-sizing: border-box;
}

@media (min-width: 640px) {
    .hero-slide-text {
        padding-left: 1.5rem;
        padding-right: 1.5rem;
    }
}


/* ========== 上段 ========== */

.hero-slide-content.text-top-left {
    align-items: flex-start;
}

.hero-slide-content.text-top-left .hero-slide-text {
    text-align: left;
}

.hero-slide-content.text-top-center {
    align-items: flex-start;
}

.hero-slide-content.text-top-center .hero-slide-text {
    text-align: center;
}

.hero-slide-content.text-top-right {
    align-items: flex-start;
}

.hero-slide-content.text-top-right .hero-slide-text {
    text-align: right;
}


/* ========== 中段 ========== */

.hero-slide-content.text-center-left {
    align-items: center;
}

.hero-slide-content.text-center-left .hero-slide-text {
    text-align: left;
}

.hero-slide-content.text-center,
.hero-slide-content.text-center-center {
    align-items: center;
}

.hero-slide-content.text-center .hero-slide-text,
.hero-slide-content.text-center-center .hero-slide-text {
    text-align: center;
}

.hero-slide-content.text-center-right {
    align-items: center;
}

.hero-slide-content.text-center-right .hero-slide-text {
    text-align: right;
}


/* ========== 下段 ========== */

.hero-slide-content.text-bottom-left {
    align-items: flex-end;
}

.hero-slide-content.text-bottom-left .hero-slide-text {
    text-align: left;
}

.hero-slide-content.text-bottom-center {
    align-items: flex-end;
}

.hero-slide-content.text-bottom-center .hero-slide-text {
    text-align: center;
}

.hero-slide-content.text-bottom-right {
    align-items: flex-end;
}

.hero-slide-content.text-bottom-right .hero-slide-text {
    text-align: right;
}


/* ========================================
   Title & Description
   ======================================== */

.hero-slide-title {
    color: white;
    font-size: 1.8rem;
    line-height: 1.2;
    margin-bottom: 1rem;
    text-shadow: 0 2px 10px rgba(0, 0, 0, 0.5);
    opacity: 0;
    visibility: hidden;
}

@media (min-width: 768px) {
    .hero-slide-title {
        font-size: 2.1rem;
    }
}

@media (min-width: 1024px) {
    .hero-slide-title {
        font-size: 2.5rem;
    }
}

.hero-slide-description {
    color: rgba(255, 255, 255, 0.9);
    font-size: 1rem;
    line-height: 1.6;
    text-shadow: 0 1px 5px rgba(0, 0, 0, 0.3);
    opacity: 0;
    visibility: hidden;
    white-space: pre-line;
}

@media (min-width: 768px) {
    .hero-slide-description {
        font-size: 1.125rem;
    }
}

.hero-slide-custom {
    width: 100%;
    height: 100%;
    display: flex;
    pointer-events: auto;
}


/* ========================================
   Animation Helpers
   ======================================== */

.hero-animate-hidden {
    opacity: 0 !important;
    visibility: hidden !important;
}

.hero-animate-visible {
    visibility: visible !important;
}

.hero-slide-title.animate__animated,
.hero-slide-description.animate__animated {
    animation-fill-mode: forwards;
}


/* ========================================
   Swiper Navigation & Pagination
   ======================================== */

.hero-slide-container .swiper-button-prev,
.hero-slide-container .swiper-button-next {
    color: white;
    opacity: 0.7;
    transition: opacity 0.3s ease;
}

.hero-slide-container .swiper-button-prev:hover,
.hero-slide-container .swiper-button-next:hover {
    opacity: 1;
}

.hero-slide-container .swiper-button-prev::after,
.hero-slide-container .swiper-button-next::after {
    font-size: 1.5rem;
}

@media (max-width: 768px) {
    .hero-slide-container .swiper-button-prev,
    .hero-slide-container .swiper-button-next {
        display: none;
    }
}

.hero-slide-container .swiper-pagination {
    bottom: 1.5rem !important;
}

.hero-slide-container .swiper-pagination-bullet {
    width: 10px;
    height: 10px;
    background: white;
    opacity: 0.5;
    transition: opacity 0.3s ease, transform 0.3s ease;
}

.hero-slide-container .swiper-pagination-bullet-active {
    opacity: 1;
    transform: scale(1.2);
}


/* ========================================
   Link Wrapper
   ======================================== */

.hero-slide-link {
    display: block;
    width: 100%;
    height: 100%;
    text-decoration: none;
    color: inherit;
}


/* ========================================
   Fallback / No JS
   ======================================== */

.hero-slide-container.no-js .swiper-slide:not(:first-child) {
    display: none;
}

.hero-slide-container.no-js .swiper-slide:first-child .hero-slide-title,
.hero-slide-container.no-js .swiper-slide:first-child .hero-slide-description {
    opacity: 1;
    visibility: visible;
}

/* No-JS時: 動画スライドの最初の1枚は表示 */
.hero-slide-container.no-js .swiper-slide:first-child .hero-slide-video {
    display: block;
}
