// ページ設定
// 表示可能なページのリスト（ファイル名の順序）
const AVAILABLE_PAGES = [
    'front_cover',  // 表紙
    'content',       // 目次
    '1', '2', '3', '4', '5', '6', '7', '8', '9', '10',
    '11', '12', '13', '14', '15', '16', '17', '18', '19', '20',
    '21', '22', '23', '24', '25', '26', '27', '28', '29', '30',
    '31', '32',      // 書籍ページ 1-32
    'poster',        // ポスター
    'back_cover'     // 裏表紙
];
const TOTAL_PAGES = AVAILABLE_PAGES.length;
const PAGE_BASE_PATH = 'pages/';

// ファイル名から表示ラベルへのマッピング
const pageLabels = {
    'front_cover': '表紙',
    'content': '目次',
    'poster': 'ポスター',
    'back_cover': '裏表紙'
    // 数値ページ（'1', '2', ... '32'）はそのまま表示
};

// ページ番号を実際のファイル名に変換する関数
function getActualPageNumber(displayPageNum) {
    if (displayPageNum < 1 || displayPageNum > AVAILABLE_PAGES.length) {
        return null;
    }
    return AVAILABLE_PAGES[displayPageNum - 1];
}

// 実際のファイル名を表示ページ番号に変換する関数
function getDisplayPageNumber(fileName) {
    const index = AVAILABLE_PAGES.indexOf(fileName);
    return index !== -1 ? index + 1 : null;
}

// 現在のページにテキストがあるかチェックする関数
function hasTextAvailable() {
    let hasText = false;
    
    if (isSpreadMode && !isMobile && currentPage !== 1 && currentPage !== TOTAL_PAGES) {
        // 見開きモードの場合：左右両方のページをチェック
        let leftDisplayPageNum, rightDisplayPageNum;
        
        if (currentPage % 2 === 0) {
            leftDisplayPageNum = currentPage;
            rightDisplayPageNum = currentPage + 1;
        } else {
            leftDisplayPageNum = currentPage - 1;
            rightDisplayPageNum = currentPage;
        }
        
        // 左ページが1ページ目の場合は単独チェック
        if (leftDisplayPageNum === 1) {
            const actualPageNum = getActualPageNumber(1);
            hasText = actualPageNum && pageTexts[actualPageNum] && pageTexts[actualPageNum].trim().length > 0;
        } else {
            // 左右どちらかにテキストがあればOK
            const leftActualPageNum = getActualPageNumber(leftDisplayPageNum);
            const rightActualPageNum = getActualPageNumber(rightDisplayPageNum);
            
            const leftHasText = leftActualPageNum && pageTexts[leftActualPageNum] && pageTexts[leftActualPageNum].trim().length > 0;
            const rightHasText = rightActualPageNum && pageTexts[rightActualPageNum] && pageTexts[rightActualPageNum].trim().length > 0;
            
            hasText = leftHasText || rightHasText;
        }
    } else {
        // 単一ページモードの場合：現在のページのみチェック
        const actualPageNum = getActualPageNumber(currentPage);
        hasText = actualPageNum && pageTexts[actualPageNum] && pageTexts[actualPageNum].trim().length > 0;
    }
    
    return hasText;
}

// 音声ボタンの状態を更新する関数
function updateAudioButtonState() {
    if (!audioBtn) return;
    
    const textAvailable = hasTextAvailable();
    
    if (textAvailable) {
        audioBtn.disabled = false;
        audioBtn.title = '音声読み上げ';
        audioBtn.setAttribute('aria-label', '音声読み上げ');
    } else {
        audioBtn.disabled = true;
        audioBtn.title = 'このページにはテキストがありません';
        audioBtn.setAttribute('aria-label', 'このページにはテキストがありません');
        
        // 再生中なら停止
        if (isPlaying) {
            stopAudio();
        }
    }
}

// ファイル名から表示ラベルを取得する関数
function getPageLabel(fileName) {
    // ファイル名がnullまたはundefinedの場合は現在のページ番号を返す
    if (!fileName) {
        return String(currentPage);
    }
    
    // 文字列に変換し、拡張子を除去（念のため）
    const cleanFileName = String(fileName).replace(/\.xhtml$/i, '').trim();
    
    // ラベルマップに存在する場合はラベルを返す
    if (pageLabels.hasOwnProperty(cleanFileName)) {
        return pageLabels[cleanFileName];
    }
    
    // 数値ページの場合はそのまま返す
    return cleanFileName;
}

// 書籍ページ番号（数値）を表示ページ番号に変換する関数
function bookPageToDisplayPage(bookPageNum) {
    // 書籍ページ番号はファイル名として文字列に変換
    const fileName = String(bookPageNum);
    return getDisplayPageNumber(fileName);
}

// 現在のページ番号（1から開始、表示ページ番号）
let currentPage = 1;
let isSpreadMode = true; // 見開きモード
let isMobile = window.innerWidth <= 1024;
let isPortrait = window.innerHeight > window.innerWidth;
let isTabletOrMobile = window.innerWidth <= 1024;

// ページサイズ定数
const PAGE_WIDTH = 595;
const PAGE_HEIGHT = 842;
const SPREAD_WIDTH = PAGE_WIDTH * 2; // 1190px

// 目次データ（ページ2の目次から取得）
// page: 内部表示ページ番号, bookPage: 書籍に印刷されているページ番号
const tableOfContents = [
    { number: '', title: '表紙', page: 1, bookPage: '表紙' },
    { number: '', title: '目次', page: 2, bookPage: '目次' },
    { number: '①', title: 'はてな？ なぜこんなにごみがあるの？', page: 3, bookPage: '1' },
    { number: '②', title: 'なぜだ！ どうしてごみを減らすの？', page: 4, bookPage: '2' },
    { number: '③', title: 'まずは！ みんなの家から！', page: 6, bookPage: '4' },
    { number: '④', title: 'わかる！ 燃やすごみの流れ', page: 14, bookPage: '12' },
    { number: '⑤', title: 'めぐる！ 資源物が生まれ変わるまで', page: 22, bookPage: '20' },
    { number: '⑥', title: 'できる！ ごみを減らす魔法の言葉3Rを覚えよう！', page: 26, bookPage: '24' },
    { number: '⑦', title: 'もっと！ 家以外でできること', page: 30, bookPage: '28' },
    { number: '⑧', title: 'つなぐ！ 未来へ向けて', page: 34, bookPage: '32' },
    { number: '', title: 'ポスター', page: 35, bookPage: 'ポスター' },
    { number: '', title: '裏表紙', page: 36, bookPage: '裏表紙' }
];

// DOM要素
const bookViewer = document.getElementById('bookViewer');
const currentPageSpan = document.getElementById('currentPage');
const totalPagesSpan = document.getElementById('totalPages');
const prevBtn = document.getElementById('prevBtn');
const nextBtn = document.getElementById('nextBtn');
const toggleSpreadBtn = document.getElementById('toggleSpread');
const tocBtn = document.getElementById('tocBtn');
const tocModal = document.getElementById('tocModal');
const closeTocBtn = document.getElementById('closeTocBtn');
const tocList = document.getElementById('tocList');
const zoomInBtn = document.getElementById('zoomInBtn');
const zoomOutBtn = document.getElementById('zoomOutBtn');
const zoomLevelDisplay = document.getElementById('zoomLevelDisplay');
const audioBtn = document.getElementById('audioBtn');
const audioIcon = document.getElementById('audioIcon');

// ズーム設定
let zoomLevel = 1.0;
const MIN_ZOOM = 0.5;
const MAX_ZOOM = 2.0;
const ZOOM_STEP = 0.1;

// 音声読み上げ設定
const AUDIO_BASE_PATH = 'pages/audio/';
let currentAudio = null;
let audioQueue = [];
let isPlaying = false;

// 各ページの読み上げテキスト（ファイル名をキーとする）
// 各ページのテキストをここに追加してください
const pageTexts = {
    'front_cover': "",
    'content': "SDGs目標4に、教育を通して持続可能な開発に必要な知識や技能を得られるようにすることが挙げられているよ。ごみの処理を学んでSDGsの目標達成につなげていこう！（SDGsのことは３ページを見てね）みんなが大人になったときにも良い環境を残していけるよう、できることから取り組んでいこう！横浜市では、「ヨコハマ プラ5.3計画」をつくり、ごみの量を減らすことはもちろん、地球温暖化の原因の一つである温室効果ガスの削減に向けたプラスチック対策やSDGsの目標の一つである食品ロスの削減などに取り組んでいるよ。将来のみんなに良い環境を残していけるよう、できることから一緒に取り組んでいこう！",
    '1': "①はてな？なぜこんなにごみがあるの？多くの人々が生活し、働いている横浜市では、毎日たくさんのごみが出されているよ。なんでこんなにごみが出るのかな？その理由をみんなで考えてみよう！",
    '2': "②なぜだ！どうしてごみを減らすの？ものはすべて限りある資源からできている。みんなが使う紙は木からできている。プラスチックは石油からできている。このようにみんなの身の回りにあるものは、すべて限りある資源から作られているよ。ものを長く大切に使ったり、いらなくなった紙やプラスチックなどを集めてリサイクルしたりすれば、資源が節約できるんだ。プラスチックごみを減らして地球の温暖化をふせごう！石油でできているプラスチックを燃やすと、二酸化炭素（CO2）が発生するんだ。二酸化炭素は、地球から熱をにがさない性質を持つため、温室効果ガスと呼ばれているよ。温室効果ガスがふえすぎると、地球がだんだんと温められていく。これを「地球温暖化」というんだ。地球温暖化が進むと、災害級の猛暑やかんばつ、集中ごう雨などの異常気象がふえ、わたしたち人間をふくむ、たくさんの動植物が住みづらくなるんだ。2024年には、7～8月における横浜市内の平均気温が最高値を更新するなど地球温暖化の影響は身近に表れているよ。たくさんのプラスチックごみを燃やせば、二酸化炭素もたくさん出てしまう。だからプラスチックごみを減らすことが、とても大事なんだ。",
    '3': "SDGsとごみの処理。だれひとり取り残されることなく、すべての人が安心してこの地球で暮らし続けることができるように、ＳＤＧｓ(持続可能な開発目標)が全世界共通の目標になっているよ。17の目標にはごみの処理そのものの目標はないけれど、SDGsのいろいろなところに関係しているよ。ここでは12「つくる責任つかう責任」と17「パートナーシップで目標を達成しよう」を見てみよう。目標12ではごみが大気や水、土じょうへ広がっていかないように管理すること、ごみ自体を減らしていくことが、一人ひとりの責任として求められているよ。目標17ではさまざまな団体のパートナーシップを進めることが求められていて、それはごみの処理も同じなんだ。収集する人や工場で働く人だけでなく、市民のみなさんやさまざまな会社の人たちが、協力しあいながら取り組んでいるよ。2050年までに「温室効果ガス」をゼロに!横浜市は、2050年までに温室効果ガスの排出量を実質ゼロにすることを目標としているよ。温室効果ガスを減らすことは、わたしたちがこれからも地球に住み続けるためにとても重要なことなんだよ。プラスチックごみを減らすこと、電気を使いすぎないこと、太陽光や風力など自然の力を使った「再生可能エネルギー」を使うこと。目標の達成には、一人ひとりの取り組みが大切なんだよ。みんなでできることを考えてみよう!",
    '4': "③まずは！ごみと資源物をきちんと分けてみよう！みんなの家から必要なくなったものはごみとして出さなくてはいけないよね。でも、すべてをごみとするのではなく、ごみと資源物（リサイクルできるもの）をきちんと分けて出せば、資源物はまた新しいものとして生まれ変わることができるんだ。リサイクルするためには、このきちんと分けるということ、「分別」がとても大切なんだ。みんなは分別ルールを知っているかな?次のページでチェックしてみよう!横浜市のごみと資源物の出し方ルール。それぞれのごみの収集日当日の朝８時までに、決められた集積場所に出そう！中身がわかる透明または半透明の袋で出してね。「ミクショナリー」でらくらく検索。みんなはごみを出すときにきちんと分別ができるかな？分別方法がわからないものはインターネットで調べてみよう！出したいものの名前を入れてボタンを押せば、すぐに分かるよ！インターネットを使うときは、先生や家族の人といっしょに使ってね。",
    '5': "やってみよう。分別チェックにトライ！横浜市では家から出るごみと資源物を、下の1～10の10のグループに分けるルールにしているんだ。次のア〜コのごみと資源物は何に分別するんだろう。線で結んでみよう！資源物の分別はいつから？2003年に「なんでも燃やすのではなく、ごみと資源物の分別を進めていこう」ということで、ごみの分別品目を拡大したんだ。多くのみなさんに協力してもらえたおかげで、ごみの量が大きく減って、２つの焼却工場を廃止して、最終処分場も長く使えるようになったんだ。2025年４月からは横浜市全域でプラスチック資源の分別も始まったよ。",
    '6': "燃やすごみについて知ろう。2024年度に家庭から出された「燃やすごみ」の中身を見てみよう。2024年度の燃やすごみのうち、一番多かったのが「生ごみ」で31％だったんだ。重さにすると、約15万3千トンにもなるよ。また、分別してリサイクルできるものが、まだまだたくさん燃やすごみの中に入っているんだ。みんなも資源物を正しく分別してね。生ごみの80%は水分!生ごみの80％は水分が占めていて、腐ったり臭いが出てしまったりする主な原因になっているんだ。水分をよく切れば臭いが防げるだけでなく、軽くなってごみ出しも楽になるね。また、ごみが軽くなると、集めるごみの量も減って、収集車が使う燃料も減るから、温室効果ガスの発生量も抑えられるね。それに、水分の少ないごみは燃えやすくなるから、焼却工場の発電量を増やすことにもつながるよ。",
    '7': "やってみよう。生ごみを土と混ぜて分解させてみよう！生ごみは、プランターや庭の土と混ぜて、微生物のはたらきで分解させることができるよ。分解されてできた土は栄養豊富な土に変わり、花や野菜などを育てるのに活用できるんだ。夏休みの自由研究などでやってみてね。缶・びん・ペットボトルの出し方。中をゆすいでから、缶はつぶさず、ペットボトルはつぶして出そう！ペットボトルのラベルとキャップは外して、プラスチック資源として出してね。店頭回収に参加してみよう。コンビニエンスストアやスーパーマーケットではペットボトルを回収しているところがあるよ。回収したペットボトルは新たなペットボトルに生まれ変わっているんだ。スーパーマーケットではほかにも食品トレイ、紙パックなどを回収しているところがあるね。店頭回収には収集曜日以外の日でも、お買い物やお出かけのついでに出すことができるし、とても環境に優しい取り組みなんだ。近くのスーパーマーケットでも回収していたら、ぜひ参加してみよう！",
    '8': "プラスチック資源の出し方。プラマークのついているものやプラスチックのみで出来ている製品は「プラスチック資源」の収集日に出してね。横浜市では、少しよごれが残っていてもプラスチック資源で回収しているよ。食べ物などのよごれがついているものは、軽くよごれをふきとるか、すすいでね。マヨネーズや歯みがき粉などのチューブ類はできる限り使い切ってから出そう！プラスチックの分別方法が変わったよ！プラスチックを燃やすと温室効果ガスが発生してしまうんだ。その温室効果ガスの発生を減らしていくために、今まで「燃やすごみ」として回収していたプラスチックのみでできているものも「プラスチック製容器包装」と一緒に回収してリサイクルしていくよ！",
    '9': "海のプラスチックごみ問題を解決するために。プラスチックは生活のあらゆる場面で使われているけど、ポイすてなどで街から海に流れ出たプラスチックごみが原因で、海の環境が悪くなり、生き物たちにも悪い影響を与えていて、世界中で問題になっているよ。",
    '10': "小さな金属類の出し方。やかんやなべなどは袋に入れずに出そう！はさみやカッターの刃などの危険なものは袋ではなく厚紙などで包み、品名を書いて出してね。電池類・スプレー缶の出し方。中身がわかる袋に入れて出してね。充電式電池やボタン電池は、電気屋さんなどにある専用のリサイクルボックスに出してね。スプレー缶は、中のガスは必ず出しきろうね。スプレー缶に穴は開けなくていいんだよ。燃えないごみの出し方。ガラスや食器、電球などのことだよ。買ったときの箱や新聞紙、厚紙などで包んで、品名を書いて出そう。古布の出し方。古布として集めているものは、ズボンやシャツなどの服やシーツなどだよ。古布は濡れるとカビが生えてリユースやリサイクルができなくなるので、雨の日には出さないでね。",
    '11': "古紙の出し方。「新聞」や「雑誌」はひもで十字にしばって出そう。「紙パック」は洗って、開いて、乾かしてから、大きさをそろえて、ひもでしばって出そう。内側が銀色のものはリサイクルできないので「燃やすごみ」として出してね。「段ボール」は折りたたんで、ひもでしばって出そう!「その他の紙」はお菓子などの紙箱やレシート、メモ用紙などのことだよ。紙袋(ない場合は透明または半透明の袋)に入れて、ひもでしばって中身が出ないようにして出そうね。リサイクルできない紙がある？アイスクリーム、ヨーグルト、カップめんの紙製容器などはリサイクルできないので、燃やすごみとして出してね！粗大ごみの出し方。みんなの家で使われなくなった「たんす」や「つくえ」のような大きいものを「粗大ごみ」というんだ。粗大ごみを出すときは、お金(手数料)がかかるんだよ。LINE、チャット、インターネットや電話で、粗大ごみ受付センターに申し込んでから、粗大ごみ処理券を買い、粗大ごみにはって取りに来てもらうんだ。粗大ごみ処理券は銀行やコンビニエンスストアで買うことができるよ。",
    '12': "④わかる！燃やすごみの流れ。収集車が集めるんだよ。みんなの家から集積場所に出された「燃やすごみ」は収集車が順序よく回って集めているよ。分別されていないごみは取り残すんだ。分別されていないごみは、シールをはって、集積場所に取り残すことで、ごみを出した人に注意をよびかけているんだよ。取り残されたごみは、袋の中身を調べて、出した人に直接注意をすることもあるんだ。みんなが分別を守らないと、ごみを減らすことはできないからね。分別ルールをしっかり守ろうね！充電式電池の出し方に注意！充電式電池や、充電式電池を内蔵した小型家電が「燃やすごみ」として出されると、収集車の火災につながることがあるよ。「燃やすごみ」には絶対に混ぜないようにしてね！",
    '13': "収集車のひみつ。収集車は1台で最大2トン積むことができるんだ。燃やすごみなどは、収集車の後ろからメインのボックスに、燃えないごみやスプレー缶などは側面にあるポケットに入れられるんだ。だから燃やすごみと燃えないごみなどを一度に集められるんだよ。まとめて運ぶことで収集車の燃料を減らすことができるんだ。収集車のごみがいっぱいになると、焼却工場に運んで収集車を空にしてから、また別の集積場所へ向かうんだ。横浜市には、ごみを集める車両が全部で約700台あって、その中には、二酸化炭素の発生が少ないハイブリッド収集車が、約90台あるんだ。（2025年4月現在）",
    '14': "焼却工場の中を見てみよう！運ばれた燃やすごみは、番号の順番に処理されるよ！❶投入ステージ。収集車が集めたごみは、投入ステージでごみピットに落とすんだ。1つの工場に１日に来る収集車の数は250～600台にもなるんだよ。❷ごみピット。集めたごみは、ごみピットにためておくよ。ごみは１日に400～1000トン入ってくるんだ。❸ごみクレーン。ごみピットにたまったごみを、少しずつごみクレーンで焼却炉に入れているよ。クレーンは１回に約3～6トンのごみをつかむことができるよ。6トンのごみは、収集車３～４台分だよ。❹焼却炉。ごみを燃やして灰にするところだよ。１つの工場には１日に180～400トンのごみを燃やせる焼却炉が３つあるよ。燃やす時の温度は800～950度にもなるんだ。高温で長い時間燃やすことで、有害な物質であるダイオキシンの発生をおさえるんだ。❺ボイラー。ごみを燃やした時に出る熱を利用して、水を蒸気にかえるところだよ。蒸気で電気を作ったり、福祉施設のお風呂や冷暖房、温水プールなどに使ったりするんだよ。",
    '15': "❻バグフィルタ。ごみを燃やした時に発生する、有害な物質をフィルタで取りのぞいて、きれいな排ガスにしているんだ。❼灰コンベア・灰ピット。ごみを燃やした後の灰をコンベアを使って灰ピットに運んでいるんだよ。ごみを燃やすことで大きさは約40分の１に、重さは約７分の１になるんだ。❽灰クレーン。ごみを燃やした後の灰をトラックにのせるためのクレーンだよ。灰は最終処分場でうめ立てられるんだ。煙突。煙突はきれいな排ガスを外に出すところだよ。高さは100～130メートル、太さは10メートル以上あるよ。中央管制室。ここは、焼却炉がきちんと動いているか見ているところなんだ。工場は24時間動いているから、職員は交代しながら働いているよ。タービン発電機。ここでは、ボイラーでできた蒸気を使って電気を作っているんだよ。",
    '16': "ごみを燃やした時に出る熱や電気を有効に利用する。焼却工場のボイラーでできた蒸気は、となりにある余熱利用施設の温水プールやお風呂、冷暖房に利用しているよ。それから、蒸気の力でタービンを回して電気を作り、焼却工場などで利用するほかに、電力会社の電線を使って遠くにある市役所に電気を送っているよ。さらに電力会社にも売っていて、令和5年度からは横浜市営地下鉄「グリーンライン」でもこの電気を活用しているんだ。焼却工場で生まれる電気は、地球を温める二酸化炭素を発生させない「環境にやさしい電気」だよ。横浜市の焼却工場で１年間に作られる電気は、約8万軒（横浜市内にある家の数の22分の１）の家が１年間で使う電気量と同じくらいなんだ。灰は最終処分場へ。ごみを燃やした後の灰は2017年に完成した南本牧第5ブロック廃棄物最終処分場でうめ立てているんだ。灰の一部は再利用しているよ。いま横浜市内で灰をうめ立てできるのは、ここだけなんだ。今のペースでうめ立てていくと、約30年でいっぱいになっちゃうよ。この最終処分場をなるべく長く使えるように、ひとりひとりがごみの量を減らすことがとても大切なんだ。",
    '17': "最終処分場のしくみ。最終処分場の構造は大きく分けて3つだよ。最終処分場と海を仕切る遮水護岸、廃棄物を広くうすくうめ立てるための浮桟橋、最終処分場から出る水をきれいにする排水処理施設でできているよ。",
    '18': "昔のごみ処理はどうだった？横浜市がごみの収集を始めたのは1918年だよ。そのころはそれぞれの家にあるごみ箱からごみを回収して、船にのせて海に捨てていたんだ。消毒もしていなかったからとても不衛生だったんだって。焼却工場を作ってごみを燃やすっていう計画はあったんだけど、焼却工場を建てるのに近くに住んでいる人たちの反対も大きくてなかなか進まなかったんだ。1930年ごろにようやく初めての焼却工場ができたんだ。この時代でもごみを燃やした時に出る熱を利用して電気を作っていたよ。でも、この後に起きた戦争のせいで焼却工場が使えなくなっちゃったから、1950年ごろは回収したごみをそのままうめたてていたよ。そのままだとにおいや虫が出ちゃうから薬をまいて、その上に土をかぶせていたよ。このころは12世帯に１つの割合で道にごみ箱を置いて、３～７日ごとに回収していたよ。手車や自動車でごみを運んでいたんだ。",
    '19': "1960年ごろになると、ごみ箱を道に置くのはやめて、集積場所にごみを集めて決まった日に収集するようになったよ。これは今の収集方法と同じだね。このころからプラスチック製品が生活の中で使われ出したから、プラスチックごみの量もちょっとずつ増えてきたよ。新しい焼却工場の建設もどんどん行われるようになったよ。1970年ごろになると、人口が増えて、その分ごみの量もものすごく増えたんだ。このころから粗大ごみの対応が必要になったんだ。1968年から1978年の10年間で、粗大ごみの量は10倍以上になったんだ。今はごみを分別してリサイクルするなど、ごみを減らすこともしているけど、みんなに分別を協力してもらうようになった2000年ごろまではごみの量がどんどん増えていたよ。",
    '20': "⑤めぐる！資源物が生まれ変わるまで。古紙と古布とプラスチック資源、リサイクルの旅。みんなが分別してくれた資源物は、リサイクルされて原料になったり、リユースされたりと、役に立っているんだ。",
    '21': "資源集団回収ってなあに？資源のリサイクルを進めるために、みんなの住んでいるまちの自治会・町内会、子ども会、PTAなどの人たちが、回収業者とあらかじめ決めた日にち・場所で、新聞・雑誌・ダンボールなどの紙や布、アルミ缶などを集める活動を「資源集団回収」とよんでいるんだ。みんなの家から出る紙や布、缶などをリサイクルするために、資源集団回収に協力しよう！プラスチックの大変化。プラスチック資源は、プラスチック製品の他にも色々なものに生まれ変わるよ。たとえば、燃やさずに分解する特別な技術を使って、アンモニアを精製して、かゆみ止めの薬などの原材料を作り出すことができるんだ！小型家電のリサイクル。小型家電の中には、鉄や銅、金など資源になるものが含まれているんだよ。家で使わなくなった小型家電はないかな？横浜市では、区役所や大型スーパーなどに回収ボックスを設置しているんだ。ボックスの投入口（30㎝×15㎝）に入る、長さ30㎝未満の電気や電池で動く製品は、ぜひ回収ボックスに入れてリサイクルに協力してね！",
    '22': "缶・びん・ペットボトル リサイクルの旅。みんなが飲んだジュースの缶やペットボトルがどうなるのか見てみよう！",
    '23': "",
    '24': "⑥できる！ごみを減らす魔法の言葉３Ｒを覚えよう！「3R」ってなんだろう？ごみを減らすためには３つの方法があるんだ。Reduceリデュース、Reuseリユース、Recycleリサイクル。1「ごみそのものを減らす」こと、2「何回もくり返し使う」こと、3「資源物を新しい製品に作り変える」こと。英語で書くと、頭文字がみんな「R」なので3Rとよんでいるよ。このRのついた3つの言葉は、それぞれごみを減らすためになくてはならないことなんだ。これを環境にやさしい順番にならべると、リデュース・リユース・リサイクルになるんだよ。なぜなら、使わなくなったものをリサイクルするのにもエネルギーが必要だからなんだ。だから「ごみそのものを減らす(リデュース)」が、一番エネルギーを使わずにすむ方法になるんだね。やってみよう。「３つのマイ」でリデュース！！出かける時は、「マイバッグ」「マイボトル」「マイはし」を持っていこう。お気に入りの3点セットで楽しくリデュースしちゃおうね。",
    '25': "3Rと「もったいない」という心でごみを減らそう！みんなは「もったいない」という言葉を知っているかな?「もったいない」は「環境にやさしい社会をつくる」ということを一言で表す、すばらしい言葉なんだ。たとえば、お店でもらえるスプーンやストローのように一度使ってすててしまうものを受け取ることや、直せば使えるものをすててしまうのは、とても「もったいない」よね。使いすてを減らして、ものを長く大切に使うことは❶の「リデュース」につながるよ。みんなが小さいときに着ていた洋服や読み終わった本はどうしているかな?弟や妹にあげたり、フリーマーケットで買ってもらったり、古本屋さんに売ったりして、その人の役に立ててもらえるとうれしいよね。これが❷の「リユース」なんだ。こういった「もったいない」の心を毎日の行動にすることが「3R」なんだよ。3Rの中で、みんなにやってほしいのが4ページから学習した「ごみの分別」と、これから学習する「生ごみをださないようにすること」、とくに「食品ロス」を減らすことなんだよ。",
    '26': "「食品ロス」ってなんだろう。6ページで、燃やすごみの中で生ごみが最も多いことを学んだね。生ごみの中には、本当は食べられるのにすてているものがあるんだ。食べられるのにすてられているものを「食品ロス」と言うよ。下の写真は燃やすごみの中から見つかった食品ロスだよ。家庭から出る食品ロスは、横浜市で１年間に約6万4千トンも出されているんだよ。これを市民一人あたりで考えると17kg、おにぎり170個分になるんだって。地球上には、食べ物に困っている国もあって、世界人口のおよそ11人に１人が飢えに苦しんでいるんだ。そうした国へ食べ物の援助をしているんだけど、世界全体で援助している食べ物の量よりも、日本で出された食品ロスの方が多いんだ。食べ物を大切にして、食品ロスを減らしていこうね。",
    '27': "食品ロスを減らすために、できることを考えよう。では、食品ロスを減らすにはどうしたらいいだろう。たとえば、残さず食べるようにすれば、「食べ残されたもの」がなくなるね。また、冷蔵庫の中を整理しておくと、何があるか見やすくなって、必要なものだけを買うことができるね。このほかにもできることはないかな。みんなも考えて、下に書いてみよう！フードドライブ　〜食べ物の「もったいない」を「ありがとう」へ!〜。フードドライブとは、まだ食べられるけど、食べないままお家で眠っている食品を集める活動だよ。ドライブには、「寄附」という意味があって、集まった食品は、食べ物を必要としている人のもとに届けられるんだ。横浜市では、区役所や収集事務所、スーパーなどみんなの身近な場所でフードドライブがおこなわれているよ。「賞味期限と消費期限の違いって？」食品ロスを減らすために、賞味期限と消費期限の違いを知ろう！賞味期限…おいしく食べることができる期限。缶詰やスナック菓子など比較的長く保存ができる食べ物だよ。この日にちがすぎたからと言って、すぐに食べられないということではないよ。消費期限…日にちがすぎたら食べない方がいい期限。生のお魚やお弁当など長くは保存できない食べ物だよ。食べわすれがないか冷蔵庫をチェックして食品ロスを減らそう！",
    '28': "⑦もっと！家以外でできること。どこでもみんなで！分別＆リサイクル。みんなが給食で飲む牛乳のパックは、洗って、開いて、かわかしているよね。その後はリサイクル工場に運ばれて、紙としてリサイクルされているんだ。このように、学校やお出かけ先でもきちんと分別すればリサイクルすることができるものがあるんだ。外に出かけたときも、家や学校と同じように紙やプラスチックを分別してリサイクルに協力してね。地域の清掃活動に参加してみよう。みんなは外へ遊びに行ったときに食べたり飲んだりしてごみが出たら、持ち帰っているよね。ところが、まちをよく見てみると、ペットボトルや空き缶、ストロー、おかしの袋、たばこのすいがらなどが散らかっているよね。こうしたごみは、海のプラスチックごみ問題にもつながるんだ(9ページ)。下のコラムの環境事業推進委員さんのようにまちをきれいにするために、ごみ拾いの活動をがんばっている人たちがいるよ。みんなも地域の清掃活動に参加してみよう。環境事業推進委員が活やくしているよ。環境事業推進委員は、地域でごみの減量化や３R行動を進めている、ボランティアリーダーだよ。ごみ集積場所へのごみと資源物の分け方・出し方を説明したり、区役所の人と一緒にポイ捨て防止に取り組んだり、地域の清掃活動をしたりしているんだ。みんなもルールを守って、環境事業推進委員さんと一緒にきれいなまちにしようね。",
    '29': "食べきり協力店をさがしてみよう。飲食店では食べ残しによるごみもたくさんあるんだよ。おいしい料理を残してしまうのは、もったいないよね。横浜市では、小盛りメニューや残った料理の持ち帰りなどの取り組みに協力してもらえるお店を「食べきり協力店」としているよ。さがしてみてね。災害時の資源とごみの分け方・出し方。地震などの大きな災害が起きたときの資源とごみの分け方・出し方も決められているよ。トイレパックを用意しておこう！トイレパックとは、水道がこわれたりして家のトイレの水が流せなくなったときでも、水を使わずにおしっこ・うんちができるトイレのことだよ。凝固剤で袋の中のおしっこやうんちを固めて、燃やすごみとして出すことができるんだ。いつくるかわからない地震などの災害に備えて、家に最低３日分のトイレパックを用意しておこう。１人あたり１日５回トイレに行くとすると、１日５回×３日分（できれば１週間分）×人数分のトイレパックが必要だよ。",
    '30': "収集現場で働く人。収集現場で働く人にお話を聞いてみたよ!まず、1日のスケジュールを教えてください。8時ごろから収集作業をはじめ、16時ごろに事務所に戻って、洗車や車両整備をします。また、高齢者の方のお宅へ伺うふれあい収集なども行っています。お仕事をしていて、気をつけていることは何ですか?せまい道路や交通量の多い道路などどんなところへも行くので、交通事故を起こさないように気をつけています。たいへんだと思うことは何ですか?分別されずに出されたごみにガラスや刃物、注射器が入っていると、けがをすることがあります。それとスプレー缶や電池、特に最近は充電式電池が原因で車両火災が発生することがあります。充電式電池は回収ボックスへ入れてください。集積場所や収集の順番はどうやって決めているんですか?集積場所は利用する皆さんで相談して決めてもらいます。決まった後に収集事務所に申しこみをしてもらうと、ごみの収集が始まります。収集の順番は効率的になるように収集車に積める量や予想されるごみの量から決めています。ただ道路工事などの影響で順番が変わることがあります。ごみ収集をやっていてやりがいを感じるときはどういうときですか？毎日の収集作業が、きれいなまちを保つことに役立てていると思うと、日々やりがいを感じます。また収集作業中に「雨の日も風の日もお疲れ様です」とねぎらいの言葉をかけてもらえたときは、「毎日がんばろう」という活力につながっています。小学校にうかがって、皆さんと環境のことやごみの分別のお話をさせていただく活動もしています。横浜が環境にやさしいまちになるように、皆さんと一緒に取り組んでいきたいです。",
    '31': "焼却工場で働く人。焼却工場で働く職員の人にお話を聞いてみたよ！焼却工場では、どんなお仕事をしているんですか。工場で働く職員は、焼却炉のメンテナンスを行う係と運転操作する係に分かれます。メンテナンスを行う係は、ごみを燃やす計画をたてたり、工場の運転に必要な工事を発注したり、点検や修理、薬品などの管理をしています。一方、運転操作する係は、焼却炉が24時間休まず動いているので、日勤と夜勤の交代で、ごみクレーンの操作や焼却炉の監視を行っています。お仕事をしていて、気をつけていることは何ですか。焼却炉の運転は、ごみの性質や状態に大きく影響されます。ごみの分別がしっかりされていないと焼却炉の故障につながるため、安定した運転ができるよう、搬入ごみの監視や焼却炉の点検・整備をこまめに行っています。また、機械を点検する場所は危険なところが多いので、ヘルメットやマスクなどの保護具を身に着け、安全にはいつも気をつけています。",
    '32': "⑧つなぐ！未来へ向けて。「ヨコハマ プラ5.3計画」の取り組みへ。横浜市では2002年度から「ヨコハマはＧ30」という取り組みで分別とリサイクルを進め、2010年度からは「ヨコハマ３Ｒ夢」という取り組みでマイバッグを使うなどの「リデュース」を進めてきたよ。これらのおかげで、今では2001年度の半分の量までごみが減っているんだ。2024年１月から「ヨコハマ プラ5.3計画」という取り組みを新しく始めたよ。この計画では、地球温暖化を防いでいくため、燃やすごみの中のプラスチックごみを2030年度までに２万トン（１人あたり5.3kg）減らすことを目指しているんだ。いま、世界では、地球の環境を守っていくために、ごみを出さない仕組みである「循環経済」（英語でサーキュラーエコノミー）が大事だと言われていて、横浜市でも色々な取り組みが始まっているよ。",
    'poster': "",
    'back_cover': ""
};

// 目次番号 → ページ番号のマッピング（ページ2のもくじ用）
const inPageTocMap = {
    '①': 3,
    '②': 3,
    '③': 4,
    '④': 12,
    '⑤': 20,
    '⑥': 24,
    '⑦': 28,
    '⑧': 32
};

// 初期化
function init() {
    totalPagesSpan.textContent = TOTAL_PAGES;

    // 前回開いていたページをローカルストレージから復元
    try {
        const savedPage = parseInt(localStorage.getItem('currentPage'), 10);
        if (!isNaN(savedPage) && savedPage >= 1 && savedPage <= TOTAL_PAGES) {
            currentPage = savedPage;
        }
    } catch (e) {
        console.warn('ページ復元時のエラー:', e);
    }

    checkDeviceType();
    
    // 初期UI更新（ページ読み込み前にラベルを設定）
    updateUI();
    
    loadPage(currentPage);
    setupEventListeners();
    setupKeyboardNavigation();
    setupTableOfContents();
    setupMessageListener();
    setupAudio();
    // リロード時にズームを100%にリセット
    setZoom(1.0);
}

// デバイスタイプのチェック
function checkDeviceType() {
    const prevPortrait = isPortrait;
    const prevTabletOrMobile = isTabletOrMobile;
    
    isMobile = window.innerWidth <= 768;
    isTabletOrMobile = window.innerWidth <= 1024;
    isPortrait = window.innerHeight > window.innerWidth;
    
    if (isTabletOrMobile) {
        // タブレット・モバイル: 向きによってモード切替
        if (isPortrait) {
            isSpreadMode = false; // 縦向き = 単ページ
        } else {
            isSpreadMode = true; // 横向き = 見開き
        }
    }
    
    updateSpreadMode();
    
    // 向きが変わったらページを再読み込み
    if (isTabletOrMobile && prevPortrait !== isPortrait) {
        loadPage(currentPage);
    }
}

// 自動ズーム計算（ビューポート幅に合わせる）
function calculateAutoZoom() {
    if (!isTabletOrMobile) return zoomLevel;
    
    const viewportWidth = window.innerWidth;
    const pageContainer = document.querySelector('.page-container');
    
    let contentWidth;
    if (isPortrait) {
        // 縦向き: 単ページ幅
        contentWidth = PAGE_WIDTH;
    } else {
        // 横向き: 実際の表示モードに応じて幅を決定
        if (pageContainer && pageContainer.classList.contains('single-page')) {
            // 単ページ表示
            contentWidth = PAGE_WIDTH;
        } else {
            // 見開き表示
            contentWidth = SPREAD_WIDTH;
        }
    }
    
    // ビューポート幅に完全にフィットするスケールを計算
    // book-viewerのpadding（左右各5px = 10px）を考慮
    const availableWidth = viewportWidth - 10;
    let scale = availableWidth / contentWidth;
    
    // 最小は30%（小さすぎないように）
    scale = Math.max(0.3, scale);
    
    // スケール後の幅がビューポートを超えないように調整
    const scaledWidth = contentWidth * scale;
    if (scaledWidth > availableWidth) {
        scale = availableWidth / contentWidth;
    }
    
    return scale;
}

// 自動ズームを適用
function applyAutoZoom() {
    if (!isTabletOrMobile) return;
    
    const scale = calculateAutoZoom();
    const pageContainer = document.querySelector('.page-container');
    const pages = document.querySelectorAll('.page');
    const iframes = document.querySelectorAll('.page iframe');
    const bookViewer = document.querySelector('.book-viewer');
    
    // book-viewerの設定
    if (bookViewer) {
        bookViewer.style.padding = '5px';
        bookViewer.style.justifyContent = 'center';
        bookViewer.style.alignItems = 'flex-start';
        bookViewer.style.overflowX = 'auto';
        bookViewer.style.overflowY = 'auto';
        bookViewer.style.maxWidth = '100vw';
        bookViewer.style.width = '100%';
    }
    
    if (pageContainer) {
        // コンテナのスケーリング - 上中央基点
        // 実際の表示モードに応じて幅を決定
        let contentWidth;
        if (isPortrait) {
            contentWidth = PAGE_WIDTH;
        } else {
            // 横向きの場合、実際の表示モードを確認
            if (pageContainer.classList.contains('single-page')) {
                contentWidth = PAGE_WIDTH;
            } else {
                contentWidth = SPREAD_WIDTH;
            }
        }
        
        pageContainer.style.width = `${contentWidth}px`;
        pageContainer.style.maxWidth = 'none';
        pageContainer.style.marginLeft = 'auto';
        pageContainer.style.marginRight = 'auto';
        pageContainer.style.marginTop = '0';
        pageContainer.style.transform = `scale(${scale})`;
        pageContainer.style.transformOrigin = 'top center';
        pageContainer.style.overflow = 'visible'; // クリップしない
        
        // スケール後の高さ調整（実際の表示高さに合わせる）
        const scaledHeight = PAGE_HEIGHT * scale;
        pageContainer.style.marginBottom = `${scaledHeight - PAGE_HEIGHT}px`;
    }
    
    // ページ要素のサイズ設定 - overflowをvisibleに
    pages.forEach(page => {
        page.style.width = `${PAGE_WIDTH}px`;
        page.style.minWidth = `${PAGE_WIDTH}px`;
        page.style.maxWidth = `${PAGE_WIDTH}px`;
        page.style.overflow = 'visible'; // クリップしない
    });
    
    // iframeのサイズ設定
    iframes.forEach(iframe => {
        iframe.style.width = `${PAGE_WIDTH}px`;
        iframe.style.minWidth = `${PAGE_WIDTH}px`;
        iframe.style.height = `${PAGE_HEIGHT}px`;
        iframe.style.overflow = 'hidden';
    });
    
}

// モバイル: ビューアの横スクロールを中央にスナップ（未使用・必要なら呼び出しを復活）
function centerBookViewerScroll() {
    if (!isTabletOrMobile) return;
    const viewer = document.getElementById('bookViewer');
    const pageContainer = document.querySelector('.page-container');
    if (!viewer || !pageContainer) return;
    const run = () => {
        const cw = viewer.clientWidth;
        const sw = viewer.scrollWidth;
        if (sw <= cw) return;
        const contentCenter = pageContainer.offsetLeft + pageContainer.offsetWidth / 2;
        const viewCenter = cw / 2;
        const targetScrollLeft = contentCenter - viewCenter;
        viewer.scrollLeft = Math.max(0, Math.min(targetScrollLeft, sw - cw));
    };
    requestAnimationFrame(() => requestAnimationFrame(run));
}

// イベントリスナーの設定
function setupEventListeners() {
    prevBtn.addEventListener('click', () => {
        const prevPage = isSpreadMode && !isMobile ? getPrevPageInSpreadMode(currentPage) : currentPage - 1;
        goToPage(prevPage);
    });
    nextBtn.addEventListener('click', () => {
        const nextPage = isSpreadMode && !isMobile ? getNextPageInSpreadMode(currentPage) : currentPage + 1;
        goToPage(nextPage);
    });
    toggleSpreadBtn.addEventListener('click', toggleSpreadMode);
    tocBtn.addEventListener('click', openTableOfContents);
    closeTocBtn.addEventListener('click', closeTableOfContents);
    
    // モーダル外をクリックで閉じる
    tocModal.addEventListener('click', (e) => {
        if (e.target === tocModal) {
            closeTableOfContents();
        }
    });

    // ズームボタン
    if (zoomInBtn && zoomOutBtn) {
        zoomInBtn.addEventListener('click', () => {
            setZoom(zoomLevel + ZOOM_STEP);
        });
        zoomOutBtn.addEventListener('click', () => {
            setZoom(zoomLevel - ZOOM_STEP);
        });
    }
    
    // リサイズ時の処理（モバイルでは再スケールしない＝ブラウザズームで拡大縮小したままにする）
    window.addEventListener('resize', () => {
        checkDeviceType();
        if (!isTabletOrMobile) {
            applyZoomToCurrentPage();
        }
    });
    
    // 向き変更時の処理（モバイル・タブレット用）
    window.addEventListener('orientationchange', () => {
        setTimeout(() => {
            checkDeviceType();
            loadPage(currentPage);
        }, 100); // 向き変更が完了するまで少し待つ
    });
    
    // タッチイベント（スワイプ）- iOS対応を強化
    let touchStartX = 0;
    let touchStartY = 0;
    let touchEndX = 0;
    let touchEndY = 0;
    let isSwiping = false;
    let touchStartTime = 0;
    
    // documentレベルでもリスナーを追加（iOSでより確実に動作）
    const handleDocumentTouchStart = (e) => {
        // book-viewerまたはその子要素でのみ有効
        if (!bookViewer.contains(e.target) && !e.target.closest('.book-viewer')) {
            return;
        }
        touchStartX = e.touches[0].clientX;
        touchStartY = e.touches[0].clientY;
        touchStartTime = Date.now();
        isSwiping = false;
    };
    
    const handleDocumentTouchMove = (e) => {
        if (!touchStartX) return;
        
        const currentX = e.touches[0].clientX;
        const currentY = e.touches[0].clientY;
        const diffX = Math.abs(currentX - touchStartX);
        const diffY = Math.abs(currentY - touchStartY);
        
        // 横方向のスワイプが縦方向より大きい場合のみスワイプと判定
        if (diffX > diffY && diffX > 15) {
            isSwiping = true;
            // 横スクロールを防ぐ（縦スクロールは許可）
            if (diffX > 25) {
                e.preventDefault();
            }
        }
    };
    
    const handleDocumentTouchEnd = (e) => {
        if (!touchStartX) return;
        
        touchEndX = e.changedTouches[0].clientX;
        touchEndY = e.changedTouches[0].clientY;
        handleSwipe();
        
        // リセット
        touchStartX = 0;
        touchStartY = 0;
        isSwiping = false;
        touchStartTime = 0;
    };
    
    const handleDocumentTouchCancel = () => {
        touchStartX = 0;
        touchStartY = 0;
        isSwiping = false;
        touchStartTime = 0;
    };
    
    // documentレベルでリスナーを追加（iOSでより確実）
    document.addEventListener('touchstart', handleDocumentTouchStart, { passive: true });
    document.addEventListener('touchmove', handleDocumentTouchMove, { passive: false });
    document.addEventListener('touchend', handleDocumentTouchEnd, { passive: true });
    document.addEventListener('touchcancel', handleDocumentTouchCancel, { passive: true });
    
    // book-viewerにも追加（二重に確実に）
    bookViewer.addEventListener('touchstart', handleDocumentTouchStart, { passive: true });
    bookViewer.addEventListener('touchmove', handleDocumentTouchMove, { passive: false });
    bookViewer.addEventListener('touchend', handleDocumentTouchEnd, { passive: true });
    bookViewer.addEventListener('touchcancel', handleDocumentTouchCancel, { passive: true });
    
    function handleSwipe() {
        // モバイルではスワイプによるページ送りを無効化
        if (isTabletOrMobile) return;
        const swipeThreshold = 50;
        const diffX = touchStartX - touchEndX;
        const diffY = Math.abs(touchStartY - touchEndY);
        const swipeTime = Date.now() - touchStartTime;
        
        // 横方向の移動が縦方向より大きく、閾値を超えた場合のみスワイプと判定
        // また、スワイプ時間が500ms以内（素早いスワイプ）であることも確認
        if (Math.abs(diffX) > swipeThreshold && Math.abs(diffX) > diffY && swipeTime < 500) {
            if (diffX > 0) {
                // 左スワイプ = 次のページ
                const nextPage = isSpreadMode && !isMobile ? getNextPageInSpreadMode(currentPage) : currentPage + 1;
                goToPage(nextPage);
            } else {
                // 右スワイプ = 前のページ
                const prevPage = isSpreadMode && !isMobile ? getPrevPageInSpreadMode(currentPage) : currentPage - 1;
                goToPage(prevPage);
            }
        }
    }
}

// ページコンテナにスワイプイベントを設定（iOS対応強化）
// モバイルではスワイプによるページ送りを無効化するため、リスナーを追加しない
function setupSwipeOnContainer(container) {
    if (!container || isTabletOrMobile) return;
    
    let touchStartX = 0;
    let touchStartY = 0;
    let touchStartTime = 0;
    let isSwiping = false;
    
    const handleTouchStart = (e) => {
        touchStartX = e.touches[0].clientX;
        touchStartY = e.touches[0].clientY;
        touchStartTime = Date.now();
        isSwiping = false;
    };
    
    const handleTouchMove = (e) => {
        if (!touchStartX) return;
        
        const currentX = e.touches[0].clientX;
        const currentY = e.touches[0].clientY;
        const diffX = Math.abs(currentX - touchStartX);
        const diffY = Math.abs(currentY - touchStartY);
        
        // 横方向のスワイプが縦方向より大きい場合のみスワイプと判定
        if (diffX > diffY && diffX > 15) {
            isSwiping = true;
            // 横スクロールを防ぐ（縦スクロールは許可）
            if (diffX > 25) {
                e.preventDefault();
            }
        }
    };
    
    const handleTouchEnd = (e) => {
        if (!touchStartX) return;
        
        const touchEndX = e.changedTouches[0].clientX;
        const touchEndY = e.changedTouches[0].clientY;
        const diffX = touchStartX - touchEndX;
        const diffY = Math.abs(touchStartY - touchEndY);
        const swipeThreshold = 50;
        const swipeTime = Date.now() - touchStartTime;
        
        // 横方向の移動が縦方向より大きく、閾値を超えた場合のみスワイプと判定
        // また、スワイプ時間が500ms以内（素早いスワイプ）であることも確認
        if (Math.abs(diffX) > swipeThreshold && Math.abs(diffX) > diffY && swipeTime < 500) {
            if (diffX > 0) {
                // 左スワイプ = 次のページ
                const nextPage = isSpreadMode && !isMobile ? getNextPageInSpreadMode(currentPage) : currentPage + 1;
                goToPage(nextPage);
            } else {
                // 右スワイプ = 前のページ
                const prevPage = isSpreadMode && !isMobile ? getPrevPageInSpreadMode(currentPage) : currentPage - 1;
                goToPage(prevPage);
            }
        }
        
        // リセット
        touchStartX = 0;
        touchStartY = 0;
        isSwiping = false;
        touchStartTime = 0;
    };
    
    const handleTouchCancel = () => {
        touchStartX = 0;
        touchStartY = 0;
        isSwiping = false;
        touchStartTime = 0;
    };
    
    container.addEventListener('touchstart', handleTouchStart, { passive: true });
    container.addEventListener('touchmove', handleTouchMove, { passive: false });
    container.addEventListener('touchend', handleTouchEnd, { passive: true });
    container.addEventListener('touchcancel', handleTouchCancel, { passive: true });
    
    // ページ内のiframeにも対応（pointer-eventsを調整）
    const pages = container.querySelectorAll('.page');
    pages.forEach(page => {
        const iframe = page.querySelector('iframe');
        if (iframe) {
            // iframe上でもタッチイベントが検出できるように
            iframe.style.pointerEvents = 'auto';
        }
    });
}

// キーボードナビゲーション
function setupKeyboardNavigation() {
    document.addEventListener('keydown', (e) => {
        if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') {
            e.preventDefault();
            const prevPage = isSpreadMode && !isMobile ? getPrevPageInSpreadMode(currentPage) : currentPage - 1;
            goToPage(prevPage);
        } else if (e.key === 'ArrowRight' || e.key === 'ArrowDown') {
            e.preventDefault();
            const nextPage = isSpreadMode && !isMobile ? getNextPageInSpreadMode(currentPage) : currentPage + 1;
            goToPage(nextPage);
        } else if (e.key === 'Home') {
            e.preventDefault();
            goToPage(1);
        } else if (e.key === 'End') {
            e.preventDefault();
            goToPage(TOTAL_PAGES);
        }
    });
}

// ページ読み込み
function loadPage(pageNum) {
    if (pageNum < 1 || pageNum > TOTAL_PAGES) {
        return;
    }
    
    currentPage = pageNum;
    updateUI();
    
    // 表示ページ番号を実際のページ番号に変換
    const actualPageNum = getActualPageNumber(pageNum);
    if (!actualPageNum) {
        return;
    }
    
    // タブレット・モバイルは向きで判定、PCはisSpreadModeで判定
    const showSinglePage = isTabletOrMobile ? isPortrait : !isSpreadMode;
    
    if (showSinglePage) {
        // 単ページ表示
        loadSinglePage(pageNum);
    } else {
        // 見開き表示
        loadSpreadPages(pageNum, actualPageNum);
    }
}

// 単ページ読み込み
function loadSinglePage(displayPageNum) {
    const pageContainer = document.createElement('div');
    pageContainer.className = 'page-container single-page';
    // 読み込み中は非表示
    pageContainer.style.opacity = '0';
    pageContainer.style.visibility = 'hidden';
    
    const fileName = getActualPageNumber(displayPageNum);
    if (!fileName) {
        return;
    }
    
    const page = createPageElement(fileName);
    pageContainer.appendChild(page);
    
    bookViewer.innerHTML = '';
    bookViewer.appendChild(pageContainer);
    
    // ページコンテナにもスワイプイベントを追加（より確実に動作するように）
    setupSwipeOnContainer(pageContainer);
    
    // ページ読み込み後に自動スケールを適用してから表示
    setTimeout(() => {
        applyZoomToCurrentPage();
        // スケーリング完了後に表示
        setTimeout(() => {
            pageContainer.style.opacity = '1';
            pageContainer.style.visibility = 'visible';
        }, 50);
    }, 100);
}

// 見開きページ読み込み
function loadSpreadPages(displayPageNum, actualPageNum) {
    const pageContainer = document.createElement('div');
    // 読み込み中は非表示
    pageContainer.style.opacity = '0';
    pageContainer.style.visibility = 'hidden';
    
    // 見開き表示: 表示ページ番号から左右のページを計算
    let leftDisplayPageNum, rightDisplayPageNum;
    
    if (displayPageNum === 1 || actualPageNum === 'front_cover') {
        // 最初のページ（表紙）は単独表示
        pageContainer.className = 'page-container single-page';
        leftDisplayPageNum = 1;
        rightDisplayPageNum = null;
    } else if (displayPageNum === TOTAL_PAGES || actualPageNum === 'back_cover') {
        // 最後のページ（裏表紙）は単独表示
        pageContainer.className = 'page-container single-page';
        leftDisplayPageNum = TOTAL_PAGES;
        rightDisplayPageNum = null;
    } else {
        // 2ページ目以降は見開き
        pageContainer.className = 'page-container spread';
        // 現在のページが左側（偶数）か右側（奇数）かを判定
        if (displayPageNum % 2 === 0) {
            // 偶数ページ = 左ページ
            leftDisplayPageNum = displayPageNum;
            rightDisplayPageNum = displayPageNum + 1;
        } else {
            // 奇数ページ = 右ページ
            leftDisplayPageNum = displayPageNum - 1;
            rightDisplayPageNum = displayPageNum;
        }
        
        // 左ページが1ページ目（表紙）の場合は、単独表示
        if (leftDisplayPageNum === 1) {
            pageContainer.className = 'page-container single-page';
            leftDisplayPageNum = 1;
            rightDisplayPageNum = null;
        }
        
        // 右ページが最後のページ（裏表紙）の場合は、単独表示
        if (rightDisplayPageNum === TOTAL_PAGES) {
            pageContainer.className = 'page-container single-page';
            leftDisplayPageNum = TOTAL_PAGES;
            rightDisplayPageNum = null;
        }
    }
    
    // 表示ページ番号を実際のファイル名に変換
    const leftFileName = leftDisplayPageNum ? getActualPageNumber(leftDisplayPageNum) : null;
    const rightFileName = rightDisplayPageNum ? getActualPageNumber(rightDisplayPageNum) : null;
    
    // 左ページを追加
    if (leftFileName) {
        const leftPage = createPageElement(leftFileName);
        pageContainer.appendChild(leftPage);
    }
    
    // 右ページを追加
    if (rightFileName) {
        const rightPage = createPageElement(rightFileName);
        pageContainer.appendChild(rightPage);
    }
    
    bookViewer.innerHTML = '';
    bookViewer.appendChild(pageContainer);
    
    // ページコンテナにもスワイプイベントを追加（より確実に動作するように）
    setupSwipeOnContainer(pageContainer);
    
    // ページ読み込み後に自動スケールを適用してから表示
    setTimeout(() => {
        applyZoomToCurrentPage();
        // スケーリング完了後に表示
        setTimeout(() => {
            pageContainer.style.opacity = '1';
            pageContainer.style.visibility = 'visible';
        }, 50);
    }, 100);
}

// ページ要素の作成
function createPageElement(fileName) {
    const page = document.createElement('div');
    page.className = 'page';
    
    const iframe = document.createElement('iframe');
    iframe.src = `${PAGE_BASE_PATH}${fileName}.xhtml`;
    iframe.className = 'page-iframe';
    iframe.setAttribute('scrolling', 'auto');
    iframe.setAttribute('frameborder', '0');
    iframe.setAttribute('title', getPageLabel(fileName) || fileName);
    iframe.style.minHeight = '842px';
    
    iframe.onload = () => {
        // iframe内のコンテンツを調整
        try {
            const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
            const iframeBody = iframeDoc.body;
            const iframeHtml = iframeDoc.documentElement;
            
            if (iframeBody && iframeHtml) {
                // 元のスタイルを保持しつつ、レスポンシブ対応
                iframeBody.style.margin = '0';
                iframeBody.style.padding = '0';
                iframeBody.style.width = '100%';
                iframeBody.style.maxWidth = '100%';
                iframeBody.style.minHeight = '842px';
                iframeBody.style.overflowX = 'hidden';
                iframeBody.style.overflowY = 'visible';
                iframeBody.style.boxSizing = 'border-box';
                
                iframeHtml.style.margin = '0';
                iframeHtml.style.padding = '0';
                iframeHtml.style.overflowX = 'hidden';
                iframeHtml.style.overflowY = 'visible';
                iframeHtml.style.width = '100%';
                iframeHtml.style.maxWidth = '100%';
                iframeHtml.style.boxSizing = 'border-box';
                
                // モバイルの場合、page_bodyも100%幅にする
                if (isMobile) {
                    const pageBody = iframeDoc.querySelector('.page_body');
                    if (pageBody) {
                        pageBody.style.width = '100%';
                        pageBody.style.maxWidth = '100%';
                        pageBody.style.boxSizing = 'border-box';
                    }
                }
                
                // iframeの高さをコンテンツに合わせて調整
                const bodyHeight = Math.max(
                    iframeBody.scrollHeight,
                    iframeBody.offsetHeight,
                    iframeHtml.scrollHeight,
                    iframeHtml.offsetHeight,
                    842
                );
                iframe.style.height = bodyHeight + 'px';
                
                // 画像とコンテナ要素が横にはみ出さないようにする
                try {
                    const images = iframeDoc.querySelectorAll('img');
                    images.forEach(img => {
                        img.style.maxWidth = '100%';
                        img.style.height = 'auto';
                        img.style.boxSizing = 'border-box';
                    });
                    
                    // コンテナ要素（divなど）も横にはみ出さないようにする
                    const containers = iframeDoc.querySelectorAll('div[id^="_idContainer"]');
                    containers.forEach(container => {
                        // _idContainer678 は overflow-x: visible を保持するため除外
                        if (container.id === '_idContainer678') {
                            container.style.maxWidth = '100%';
                            container.style.boxSizing = 'border-box';
                            // overflow-x は既存のスタイルを尊重（visible のまま）
                        } else {
                            container.style.maxWidth = '100%';
                            container.style.boxSizing = 'border-box';
                            container.style.overflowX = 'hidden';
                        }
                    });
                } catch (e) {
                    console.warn('iframe内の要素スタイル調整エラー:', e);
                }

                // 目次ページ（content.xhtml）の行をクリック可能にする
                setupInPageTocInteractions(fileName, iframeDoc);
            }
        } catch (e) {
            console.log('Cross-origin iframe: スタイル調整をスキップ');
            // クロスオリジンの場合、デフォルトの高さを設定
            iframe.style.height = '842px';
        }
    };
    
    page.appendChild(iframe);
    return page;
}

// ページ移動
function goToPage(pageNum) {
    if (pageNum < 1) {
        pageNum = 1;
    } else if (pageNum > TOTAL_PAGES) {
        pageNum = TOTAL_PAGES;
    }
    
    // ページ変更時に音声を停止
    stopAudio();
    
    loadPage(pageNum);

    // 現在のページを保存（リロード時に同じページから再開できるように）
    try {
        localStorage.setItem('currentPage', String(pageNum));
    } catch (e) {
        console.warn('ページ保存時のエラー:', e);
    }
    
    // ページトップにスクロール
    bookViewer.scrollTop = 0;
    bookViewer.scrollLeft = 0;
}

// ズームレベルの設定
function setZoom(newZoom) {
    zoomLevel = Math.max(MIN_ZOOM, Math.min(MAX_ZOOM, newZoom));
    applyZoomToCurrentPage();
    updateZoomUI();
}

// 現在のページにズームを適用
function applyZoomToCurrentPage() {
    const container = bookViewer.querySelector('.page-container');
    if (!container) return;

    // タブレット・モバイルの場合: 自動ズームを適用
    if (isTabletOrMobile) {
        applyAutoZoom();
        return;
    }

    // PC: 画面幅に合わせて自動スケールを計算
    const windowWidth = window.innerWidth;
    const toolbarHeight = document.querySelector('.toolbar').offsetHeight || 0;
    const availableWidth = windowWidth - 40; // padding分を考慮
    
    let targetWidth;
    if (isSpreadMode) {
        // 見開きモード: 1190px
        targetWidth = 1190;
    } else {
        // 単一ページモード: 595px
        targetWidth = 595;
    }
    
    // 幅に合わせてスケールを計算
    const calculatedScale = availableWidth / targetWidth;
    
    // 計算されたスケールと手動ズームレベルの両方を適用
    const finalScale = calculatedScale * zoomLevel;
    
    container.style.transformOrigin = 'top center';
    container.style.transform = `scale(${finalScale})`;
    // PCでは元の幅を維持
    container.style.width = '';
    container.style.maxWidth = '';
}

// ズームUIの更新
function updateZoomUI() {
    if (zoomLevelDisplay) {
        if (isTabletOrMobile) {
            // タブレット・モバイル: 自動ズームレベルを表示
            const autoZoom = calculateAutoZoom();
            zoomLevelDisplay.textContent = Math.round(autoZoom * 100);
        } else {
            // PC: 実際のスケール（自動スケール × 手動ズーム）を表示
            const container = bookViewer.querySelector('.page-container');
            if (container) {
                const windowWidth = window.innerWidth;
                const availableWidth = windowWidth - 40;
                let targetWidth;
                if (isSpreadMode) {
                    targetWidth = 1190;
                } else {
                    targetWidth = 595;
                }
                const calculatedScale = availableWidth / targetWidth;
                const actualScale = calculatedScale * zoomLevel;
                zoomLevelDisplay.textContent = Math.round(actualScale * 100);
            } else {
                zoomLevelDisplay.textContent = Math.round(zoomLevel * 100);
            }
        }
    }

    if (zoomInBtn) {
        zoomInBtn.disabled = zoomLevel >= MAX_ZOOM - 0.01;
    }
    if (zoomOutBtn) {
        zoomOutBtn.disabled = zoomLevel <= MIN_ZOOM + 0.01;
    }
}

// 目次ページ（content.xhtml）のテキストをクリックでページ遷移できるようにする
function setupInPageTocInteractions(fileName, iframeDoc) {
    if (fileName !== 'content') {
        return;
    }

    try {
        const script = iframeDoc.createElement('script');
        script.textContent = `
            (function() {
                const bookPageToDisplayPageMap = {
                    3: 5, 4: 6, 6: 8, 12: 14,
                    20: 22, 24: 26, 28: 30, 32: 34
                };
                const tocMap = {
                    '①': bookPageToDisplayPageMap[3] || 5,
                    '②': bookPageToDisplayPageMap[3] || 5,
                    '③': bookPageToDisplayPageMap[4] || 6,
                    '④': bookPageToDisplayPageMap[12] || 14,
                    '⑤': bookPageToDisplayPageMap[20] || 22,
                    '⑥': bookPageToDisplayPageMap[24] || 26,
                    '⑦': bookPageToDisplayPageMap[28] || 30,
                    '⑧': bookPageToDisplayPageMap[32] || 34
                };
                
                const container = document.getElementById('_idContainer012');
                if (!container) {
                    return;
                }
                
                container.querySelectorAll('p').forEach((p, index) => {
                    const spans = p.querySelectorAll('span');
                    let number = null;
                    for (let i = 0; i < spans.length; i++) {
                        const t = (spans[i].textContent || spans[i].innerText || '').trim();
                        if (/^[①②③④⑤⑥⑦⑧]$/.test(t)) {
                            number = t;
                            break;
                        }
                    }
                    const targetPage = number ? tocMap[number] : null;
                    if (!targetPage) {
                        return;
                    }
                    
                    p.style.cursor = 'pointer';
                    p.style.userSelect = 'none';
                    p.style.backgroundColor = 'rgba(255, 200, 0, 0.1)';
                    
                    p.addEventListener('click', function(e) {
                        e.preventDefault();
                        e.stopPropagation();
                        if (window.parent && window.parent !== window) {
                            window.parent.postMessage({
                                type: 'navigateToPage',
                                page: targetPage
                            }, '*');
                        }
                    });
                });
            })();
        `;
        iframeDoc.body.appendChild(script);
    } catch (e) {
        console.error('ページ内目次の設定中にエラー:', e);
    }
}

// 見開きモードでの次のページ計算
function getNextPageInSpreadMode(current) {
    if (!isSpreadMode || isMobile) {
        return current + 1;
    }
    
    // 見開きモードでは、2ページずつ進む（ただし最初と最後のページは除く）
    if (current === 1) {
        return 2; // 1ページ目から2ページ目へ
    }
    
    // 最後のページ（単独表示）への遷移
    if (current >= TOTAL_PAGES - 2) {
        return TOTAL_PAGES; // 最後のページへ
    }
    
    // 2ページ目以降は、2ページずつ進む
    return Math.min(current + 2, TOTAL_PAGES);
}

// 見開きモードでの前のページ計算
function getPrevPageInSpreadMode(current) {
    if (!isSpreadMode || isMobile) {
        return current - 1;
    }
    
    // 見開きモードでは、2ページずつ戻る（ただし最初と最後のページは除く）
    if (current <= 2) {
        return 1; // 2ページ目以下から1ページ目へ
    }
    
    // 最後のページ（単独表示）からの遷移
    if (current === TOTAL_PAGES) {
        return TOTAL_PAGES - 2; // 最後から2ページ前の見開きへ
    }
    
    // 3ページ目以降は、2ページずつ戻る
    return Math.max(current - 2, 1);
}

// UI更新
function updateUI() {
    if (!currentPageSpan) {
        return;
    }
    
    // 現在のページのファイル名を取得
    const fileName = getActualPageNumber(currentPage);
    
    // 表示ラベルを取得
    let label;
    if (fileName) {
        label = getPageLabel(fileName);
    } else {
        label = String(currentPage);
    }
    
    // ラベルを設定
    currentPageSpan.textContent = label;
    
    prevBtn.disabled = currentPage === 1;
    nextBtn.disabled = currentPage === TOTAL_PAGES;
    
    // 見開きモードの切り替えボタンの表示
    // タブレット・モバイルでは向きで自動切替するので非表示
    if (isTabletOrMobile) {
        toggleSpreadBtn.style.display = 'none';
    } else {
        toggleSpreadBtn.style.display = 'flex';
        var icon = toggleSpreadBtn.querySelector('#toggleSpreadIcon');
        if (icon) {
            icon.className = isSpreadMode ? 'fas fa-book-open' : 'fas fa-file-alt';
        }
    }
    
    // 音声ボタンの状態を更新
    updateAudioButtonState();
}

// 見開きモードの切り替え
function toggleSpreadMode() {
    // タブレット・モバイルでは向きで自動切替するので無効
    if (isTabletOrMobile) {
        return;
    }
    
    isSpreadMode = !isSpreadMode;
    loadPage(currentPage);
    updateUI();
}

// 見開きモードの更新
function updateSpreadMode() {
    // タブレット・モバイルは checkDeviceType() で制御
    if (!isTabletOrMobile && isMobile) {
        isSpreadMode = false;
    }
}

// 目次機能のセットアップ
function setupTableOfContents() {
    // 目次リストを生成
    tocList.innerHTML = '';
    
    tableOfContents.forEach(item => {
        const li = document.createElement('li');
        const a = document.createElement('a');
        a.href = '#';
        a.innerHTML = `
            <span class="toc-item-number">${item.number}</span>
            <span class="toc-item-title">${item.title}</span>
            <span style="float: right; color: #999; font-size: 16px;">${item.bookPage}</span>
        `;
        
        a.addEventListener('click', (e) => {
            e.preventDefault();
            // item.pageは表示ページ番号なので直接使用
            goToPage(item.page);
                closeTableOfContents();
        });
        
        li.appendChild(a);
        tocList.appendChild(li);
    });
}

// iframeからのメッセージを受け取るリスナーを設定
function setupMessageListener() {
    window.addEventListener('message', (event) => {
        if (event.data && event.data.type === 'navigateToPage') {
            const displayPageNum = event.data.page;
            if (displayPageNum >= 1 && displayPageNum <= TOTAL_PAGES) {
                goToPage(displayPageNum);
            }
        }
    });
}

// 目次を開く
function openTableOfContents() {
    tocModal.classList.add('active');
    document.body.style.overflow = 'hidden'; // 背景のスクロールを無効化
}

// 目次を閉じる
function closeTableOfContents() {
    tocModal.classList.remove('active');
    document.body.style.overflow = ''; // 背景のスクロールを有効化
}

// 音声読み上げ機能のセットアップ
function setupAudio() {
    if (!audioBtn || !audioIcon) {
        return;
    }
    
    audioBtn.addEventListener('click', toggleAudio);
    
    // ページが非表示になったら音声を停止
    document.addEventListener('visibilitychange', function() {
        if (document.hidden && isPlaying) {
            stopAudio();
        }
    });
    
    // ページが閉じられる前に音声を停止
    window.addEventListener('beforeunload', stopAudio);
}

// 音声の再生/停止を切り替え
function toggleAudio() {
    if (isPlaying) {
        stopAudio();
    } else {
        startAudio();
    }
}

// 音声を開始
function startAudio() {
    // 音声ファイルのキューを作成
    audioQueue = [];
    
    if (isSpreadMode && !isMobile && currentPage !== 1 && currentPage !== TOTAL_PAGES) {
        // 見開きモードの場合：左右両方のページの音声を取得
        let leftDisplayPageNum, rightDisplayPageNum;
        
        if (currentPage % 2 === 0) {
            leftDisplayPageNum = currentPage;
            rightDisplayPageNum = currentPage + 1;
        } else {
            leftDisplayPageNum = currentPage - 1;
            rightDisplayPageNum = currentPage;
        }
        
        if (leftDisplayPageNum === 1) {
            // 表紙は音声なし
        } else {
            const leftActualPageNum = getActualPageNumber(leftDisplayPageNum);
            const rightActualPageNum = getActualPageNumber(rightDisplayPageNum);
            
            if (leftActualPageNum && pageTexts[leftActualPageNum]) {
                audioQueue.push(leftActualPageNum);
            }
            if (rightActualPageNum && pageTexts[rightActualPageNum]) {
                audioQueue.push(rightActualPageNum);
            }
        }
    } else {
        // 単一ページモードの場合
        const actualPageNum = getActualPageNumber(currentPage);
        if (actualPageNum && pageTexts[actualPageNum]) {
            audioQueue.push(actualPageNum);
        }
    }
    
    if (audioQueue.length === 0) {
        return;
    }
    
    // 既存の音声を停止
    if (currentAudio) {
        currentAudio.pause();
        currentAudio = null;
    }
    
    // 再生状態を更新
    isPlaying = true;
    audioBtn.classList.add('playing');
    audioIcon.className = 'fas fa-stop';
    audioBtn.setAttribute('aria-label', '音声停止');
    
    // キューの最初の音声を再生
    playNextAudio();
}

// 次の音声を再生
function playNextAudio() {
    if (audioQueue.length === 0) {
        // キューが空になったら終了
        isPlaying = false;
        audioBtn.classList.remove('playing');
        audioIcon.className = 'fas fa-volume-up';
        audioBtn.setAttribute('aria-label', '音声読み上げ');
        return;
    }
    
    const pageNum = audioQueue.shift();
    const audioPath = AUDIO_BASE_PATH + pageNum + '.mp3';
    
    currentAudio = new Audio(audioPath);
    
    currentAudio.onended = function() {
        playNextAudio();
    };
    
    currentAudio.onerror = function(e) {
        console.error('音声ファイル読み込みエラー:', audioPath, e);
        playNextAudio(); // エラーでも次の音声を試す
    };
    
    currentAudio.play().catch(function(e) {
        console.error('音声再生エラー:', e);
        playNextAudio();
    });
}

// 音声を停止
function stopAudio() {
    // 音声キューをクリア
    audioQueue = [];
    
    // 現在再生中の音声を停止
    if (currentAudio) {
        currentAudio.pause();
        currentAudio = null;
    }
    
    isPlaying = false;
    if (audioBtn) {
        audioBtn.classList.remove('playing');
    }
    if (audioIcon) {
        audioIcon.className = 'fas fa-volume-up';
    }
    if (audioBtn) {
        audioBtn.setAttribute('aria-label', '音声読み上げ');
    }
}

// 初期化実行
init();

