poster.html

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ポスター費用お見積もり | めいほう出版</title>
<link rel="preconnect" href="<https://fonts.googleapis.com>">
<link rel="preconnect" href="<https://fonts.gstatic.com>" crossorigin>
<link href="<https://fonts.googleapis.com/css2?family=Jost:wght@400;500;600;700&family=Zen+Kaku+Gothic+New:wght@400;500;700&display=swap>" rel="stylesheet">

<style>
  /* --- ベース設定 --- */
  :root {
    --font-jp: 'Zen Kaku Gothic New', "游ゴシック Medium", "游ゴシック体", "Yu Gothic Medium", YuGothic, "ヒラギノ角ゴ ProN", "Hiragino Kaku Gothic ProN", "メイリオ", Meiryo, "MS Pゴシック", "MS PGothic", sans-serif;
    --font-en: 'Jost', 'Zen Kaku Gothic New', "游ゴシック Medium", "游ゴシック体", "Yu Gothic Medium", YuGothic, "ヒラギノ角ゴ ProN", "Hiragino Kaku Gothic ProN", "メイリオ", Meiryo, "MS Pゴシック", "MS PGothic", sans-serif;

    /* カラーパレット */
    --bg-color: #faf9f7; 
    --text-main: #33322e; 
    --text-light: #7a7770;
    --border-color: #e2dfd8;
    --accent-color: #0092b4; 
    --active-bg: #f2f9fb;   
    --white: #ffffff;
  }

  body { 
    font-family: var(--font-en); 
    padding: 60px 20px; 
    background-color: var(--bg-color); 
    color: var(--text-main); 
    margin: 0;
    letter-spacing: 0.04em;
    line-height: 1.6;
  }

  /* メインコンテナ */
  .calculator { 
    max-width: 640px; 
    margin: auto; 
    background: var(--white); 
    padding: 48px 40px; 
    border-radius: 4px; 
    border: 1px solid var(--border-color);
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.02); 
  }

  h2 {
    text-align: center;
    font-size: 1.5rem;
    font-weight: 700;
    margin-top: 0;
    margin-bottom: 40px;
    letter-spacing: 0.1em;
    color: var(--text-main);
  }

  .section-title { 
    font-size: 1rem; 
    font-weight: 700; 
    color: var(--text-main); 
    margin-bottom: 12px; 
    padding-bottom: 8px;
    border-bottom: 1px solid var(--border-color);
  }

  .btn-group { 
    display: flex; 
    gap: 8px; 
    margin-bottom: 32px; 
    flex-wrap: wrap; 
  }

  /* 選択ボタン */
  .select-btn { 
    flex: 1; 
    min-width: calc(25% - 8px); 
    padding: 12px; 
    border: 1px solid var(--border-color); 
    background: var(--white); 
    cursor: pointer; 
    border-radius: 2px; 
    font-size: 0.95rem;
    font-family: var(--font-en);
    font-weight: 500;
    color: var(--text-light); 
    transition: all 0.3s ease; 
    text-align: center; 
  }
  .select-btn:hover { 
    background: var(--active-bg); 
    color: var(--text-main);
    border-color: #b3dfea; 
  }
  .select-btn.active { 
    background: var(--accent-color); 
    color: var(--white); 
    border-color: var(--accent-color); 
  }

  /* プルダウンのスタイル */
  .select-dropdown {
    width: 100%;
    padding: 14px 16px;
    border: 1px solid var(--border-color);
    border-radius: 2px;
    font-size: 0.95rem;
    font-family: var(--font-en);
    font-weight: 500;
    color: var(--text-main);
    background-color: var(--white);
    cursor: pointer;
    transition: all 0.3s;
    margin-bottom: 32px;
    appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='<http://www.w3.org/2000/svg>' fill='none' viewBox='0 0 24 24' stroke='%237a7770'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M19 9l-7 7-7-7'%3E%3C/path%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 16px center;
    background-size: 16px;
  }
  .select-dropdown:focus {
    outline: none;
    border-color: var(--accent-color);
    box-shadow: 0 0 0 2px rgba(0, 146, 180, 0.1); 
  }

  /* 部数コントロール */
  .qty-control { 
    display: inline-flex; 
    align-items: center; 
    border: 1px solid var(--border-color); 
    border-radius: 2px; 
    margin-bottom: 32px; 
    background: var(--white);
    transition: border-color 0.3s;
  }
  .qty-control:focus-within {
    border-color: var(--accent-color);
    box-shadow: 0 0 0 2px rgba(0, 146, 180, 0.1);
  }
  .qty-btn { 
    width: 48px; 
    height: 48px; 
    border: none; 
    background: transparent; 
    cursor: pointer; 
    font-size: 18px; 
    color: var(--text-light); 
    transition: all 0.2s; 
    display: flex; 
    align-items: center; 
    justify-content: center; 
  }
  .qty-btn:hover { 
    background: var(--active-bg); 
    color: var(--accent-color); 
  }
  #qty-val { 
    font-size: 1.1rem; 
    font-weight: 600;
    width: 100px; 
    text-align: center; 
    color: var(--text-main); 
  }

  /* 無効化(グレーアウト)時 */
  .print-options-wrapper {
    transition: opacity 0.4s ease;
  }
  .disabled-section {
    opacity: 0.3;
    pointer-events: none;
    user-select: none;
  }

  /* 金額表示エリア */
  .price-display-wrapper {
    margin-top: 40px;
    padding-top: 32px;
    border-top: 1px solid var(--border-color);
    text-align: center;
  }
  .price-label {
    font-size: 0.9rem;
    font-weight: 700;
    color: var(--text-light);
    margin-bottom: 8px;
    letter-spacing: 0.05em;
  }
  .price-display { 
    font-family: var(--font-en);
    font-size: 3.2rem; 
    font-weight: 600;
    color: var(--text-main); 
    margin: 0; 
    line-height: 1;
    letter-spacing: 0.02em;
    display: flex;
    align-items: baseline;
    justify-content: center;
  }
  .price-suffix {
    font-family: var(--font-jp);
    font-size: 1.6rem;
    font-weight: 500;
    color: var(--text-main);
    margin-left: 4px;
  }
  
  /* 割引オプション(チェックボックス)のスタイル */
  .discount-option {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background-color: var(--active-bg);
    padding: 12px 20px;
    margin-top: 16px;
    border-radius: 4px;
    border: 1px solid #b3dfea;
    cursor: pointer;
    font-family: var(--font-jp);
    font-size: 0.95rem;
    color: var(--text-main);
    transition: all 0.2s ease;
  }
  .discount-option:hover {
    background-color: #e5f4f8;
  }
  .discount-option input[type="checkbox"] {
    margin-right: 10px;
    width: 18px;
    height: 18px;
    accent-color: var(--accent-color);
    cursor: pointer;
  }
  .discount-option strong {
    color: var(--accent-color);
    font-size: 1.1rem;
    font-family: var(--font-en);
    margin-left: 6px;
    letter-spacing: 0.02em;
  }

  /* 注記のスタイル */
  .price-note {
    font-family: var(--font-jp);
    font-size: 0.75rem;
    color: var(--text-light);
    margin-top: 24px;
    line-height: 1.5;
    text-align: left;
    background-color: #f9f9f9;
    padding: 12px;
    border-radius: 4px;
  }

  /* スマホ対応 */
  @media (max-width: 480px) {
    .calculator { padding: 32px 20px; }
    .select-btn { min-width: calc(50% - 4px); }
    .price-display { font-size: 2.8rem; }
    .price-suffix { font-size: 1.4rem; }
    .discount-option { font-size: 0.85rem; padding: 10px 12px; width: 100%; box-sizing: border-box; }
  }
</style>
</head>
<body>

<div class="calculator">

    <h2>お見積もりシミュレーション</h2>

    <div class="section-title">ご依頼内容</div>
    <select id="service-type" class="select-dropdown" onchange="updateServiceType()">
        <option value="design_print">デザイン制作 + 印刷</option>
        <option value="design_only">デザイン制作のみ</option>
    </select>
    
    <div class="section-title">ポスターサイズ</div>
    <div class="btn-group" id="size-selector">
        <button class="select-btn active" onclick="updateState('size', 'A3')">A3</button>
        <button class="select-btn" onclick="updateState('size', 'A2')">A2</button>
        <button class="select-btn" onclick="updateState('size', 'A1')">A1</button>
        <button class="select-btn" onclick="updateState('size', 'A0')">A0</button>
        <button class="select-btn" onclick="updateState('size', 'B3')">B3</button>
        <button class="select-btn" onclick="updateState('size', 'B2')">B2</button>
        <button class="select-btn" onclick="updateState('size', 'B1')">B1</button>
        <button class="select-btn" onclick="updateState('size', 'B0')">B0</button>
    </div>

    <div id="print-options-wrapper" class="print-options-wrapper">
        <div class="section-title">用紙(135kg)</div>
        <div class="btn-group" id="paper-selector">
            <button class="select-btn active" onclick="updateState('paper', 'coat')">コート紙</button>
            <button class="select-btn" onclick="updateState('paper', 'matte')">マットコート紙</button>
            <button class="select-btn" onclick="updateState('paper', 'fine')">上質紙</button>
        </div>

        <div class="section-title">印刷部数</div>
        <div class="qty-control">
            <button class="qty-btn" onclick="stepQuantity(-1)">−</button>
            <span id="qty-val">10部</span>
            <button class="qty-btn" onclick="stepQuantity(1)">+</button>
        </div>
    </div>

    <div class="section-title">データ納品オプション</div>
    <select id="data-delivery" class="select-dropdown" onchange="updateDataOption()">
        <option value="none">希望しない(印刷物のみ納品)</option>
        <option value="pdf">印刷用PDFデータをお渡し (+5,000円)</option>
        <option value="ai">Illustratorデータ(アウトライン済) (+15,000円)</option>
        <option value="ai_edit">Illustratorデータ(編集可能) (+30,000円)</option>
    </select>

    <div class="price-display-wrapper">
        <div class="price-label">概算費用(税込)</div>
        <div class="price-display">
            ¥<span id="final-price" style="font-size: inherit; color: inherit; font-family: inherit; margin-left: 0; font-weight: inherit;">0</span><span class="price-suffix">〜</span>
        </div>
        
        <label class="discount-option">
            <input type="checkbox" id="local-discount" onchange="toggleLocalDiscount()">
            地域おこし・地方活性化の取り組みなら<strong>-20%</strong>
        </label>

        <div class="price-note">
            ※その他、用紙・加工・特急・工数などの要因により変動する場合がございます。詳細はお問い合わせ後に改めてご案内いたします。
        </div>
    </div>

</div>

<script>
    const CONFIG = {
        PAPER_SURCHARGE: 1650, 
        DATA_FEES: {
            none: 0,
            pdf: 5000,
            ai: 15000,
            ai_edit: 30000
        }
    };

    const DESIGN_PRICE = {
        A3: 25000, A2: 30000, A1: 40000, A0: 50000,
        B3: 25000, B2: 35000, B1: 45000, B0: 60000
    };

    const PRICE_DATA = {
        A3: { 10: 31770, 50: 33180, 90: 34590, 100: 36290, 500: 38010, 1000: 40180, 3000: 50740 },
        A2: { 10: 42540, 50: 43340, 100: 44320, 300: 45590, 3000: 69950 },
        A1: { 10: 52410, 50: 53820, 100: 55590, 300: 57770, 3000: 100160 },
        A0: { 10: 159020, 100: 176580, 1000: 229530 },
        B3: { 10: 39460, 50: 40060, 100: 40800, 300: 41790, 3000: 60210 },
        B2: { 10: 46840, 50: 47890, 100: 49220, 300: 50890, 3000: 82700 },
        B1: { 10: 63470, 50: 65560, 100: 68190, 300: 71430, 3000: 128420 },
        B0: { 10: 220940, 100: 247200, 1000: 326290 }
    };

    let state = {
        serviceType: 'design_print',
        size: 'A3',
        paper: 'coat', 
        qty: 10,       
        dataDelivery: 'none',
        isLocalDiscount: false // 割引チェック状態
    };

    let currentDisplayPrice = 0;
    let animationId = null;

    function updateServiceType() {
        state.serviceType = document.getElementById('service-type').value;
        const printOptionsWrapper = document.getElementById('print-options-wrapper');
        const dataDeliverySelect = document.getElementById('data-delivery');

        if (state.serviceType === 'design_only') {
            printOptionsWrapper.classList.add('disabled-section');
            if (state.dataDelivery === 'none') {
                dataDeliverySelect.value = 'pdf';
                state.dataDelivery = 'pdf';
            }
            dataDeliverySelect.options[0].disabled = true;
        } else {
            printOptionsWrapper.classList.remove('disabled-section');
            dataDeliverySelect.options[0].disabled = false;
        }
        calculate();
    }

    function updateState(key, val) {
        state[key] = val;
        
        if (key === 'size') {
            const maxQty = (state.size === 'A0' || state.size === 'B0') ? 1000 : 3000;
            if (state.qty > maxQty) {
                state.qty = maxQty;
                updateQtyUI();
            }
        }
        updateButtonActiveStates();
        calculate();
    }

    function updateButtonActiveStates() {
        const sizeBtns = document.getElementById('size-selector').querySelectorAll('.select-btn');
        sizeBtns.forEach(b => {
            b.classList.toggle('active', b.innerText === state.size);
        });
        
        const paperMap = { 'coat': 'コート紙', 'matte': 'マットコート紙', 'fine': '上質紙' };
        const paperBtns = document.getElementById('paper-selector').querySelectorAll('.select-btn');
        paperBtns.forEach(b => {
            b.classList.toggle('active', b.innerText === paperMap[state.paper]);
        });
    }

    function updateDataOption() {
        state.dataDelivery = document.getElementById('data-delivery').value;
        calculate();
    }

    // 割引チェックボックスの切り替え
    function toggleLocalDiscount() {
        state.isLocalDiscount = document.getElementById('local-discount').checked;
        calculate();
    }

    function stepQuantity(direction) {
        let step = 10;
        if (state.qty >= 100 && direction > 0) step = 100;
        if (state.qty > 100 && direction < 0) step = 100;

        let next = state.qty + (direction * step);
        if (next < 10) next = 10;
        
        const max = (state.size === 'A0' || state.size === 'B0') ? 1000 : 3000;
        if (next > max) next = max;

        state.qty = next;
        updateQtyUI();
    }

    function updateQtyUI() {
        document.getElementById('qty-val').innerHTML = `${state.qty.toLocaleString()}部`;
        calculate();
    }

    function interpolate(table, qty) {
        const points = Object.keys(table).map(Number).sort((a, b) => a - b);
        if (table[qty]) return table[qty];
        if (qty <= points[0]) return table[points[0]];
        if (qty >= points[points.length - 1]) return table[points[points.length - 1]];

        let lower = points[0], upper = points[points.length - 1];
        for (let i = 0; i < points.length - 1; i++) {
            if (qty > points[i] && qty < points[i+1]) {
                lower = points[i];
                upper = points[i+1];
                break;
            }
        }
        const ratio = (qty - lower) / (upper - lower);
        return table[lower] + (table[upper] - table[lower]) * ratio;
    }

    function calculate() {
        let base = 0;

        if (state.serviceType === 'design_only') {
            base = DESIGN_PRICE[state.size];
        } else {
            const table = PRICE_DATA[state.size];
            base = interpolate(table, state.qty);
            if (state.paper !== 'coat') {
                base += CONFIG.PAPER_SURCHARGE;
            }
        }

        base += CONFIG.DATA_FEES[state.dataDelivery];

        // ▼ 地域活性化割引の適用(20%オフ)
        if (state.isLocalDiscount) {
            base = base * 0.8;
        }

        // 10円単位で切り上げ
        const final = Math.ceil(base / 10) * 10;
        animatePrice(final, 400);
    }

    function animatePrice(targetPrice, duration) {
        const el = document.getElementById('final-price');
        const startPrice = currentDisplayPrice;
        const startTime = performance.now();
        if (animationId) cancelAnimationFrame(animationId);

        function update(currentTime) {
            const elapsed = currentTime - startTime;
            const progress = Math.min(elapsed / duration, 1);
            
            const ease = progress === 1 ? 1 : 1 - Math.pow(2, -10 * progress);
            
            const current = Math.floor(startPrice + (targetPrice - startPrice) * ease);
            el.innerText = current.toLocaleString();
            currentDisplayPrice = current;
            if (progress < 1) {
                animationId = requestAnimationFrame(update);
            } else {
                el.innerText = targetPrice.toLocaleString();
            }
        }
        animationId = requestAnimationFrame(update);
    }

    // 初期化実行
    updateServiceType();
    updateButtonActiveStates();
    updateQtyUI();

</script>

</body>
</html>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ポスター費用お見積もり | めいほう出版</title>
<link rel="preconnect" href="<https://fonts.googleapis.com>">
<link rel="preconnect" href="<https://fonts.gstatic.com>" crossorigin>
<link href="<https://fonts.googleapis.com/css2?family=Jost:wght@400;500;600;700&family=Zen+Kaku+Gothic+New:wght@400;500;700&display=swap>" rel="stylesheet">

<style>
  /* --- ベース設定 --- */
  :root {
    --font-jp: 'Zen Kaku Gothic New', "游ゴシック Medium", "游ゴシック体", "Yu Gothic Medium", YuGothic, "ヒラギノ角ゴ ProN", "Hiragino Kaku Gothic ProN", "メイリオ", Meiryo, "MS Pゴシック", "MS PGothic", sans-serif;
    --font-en: 'Jost', 'Zen Kaku Gothic New', "游ゴシック Medium", "游ゴシック体", "Yu Gothic Medium", YuGothic, "ヒラギノ角ゴ ProN", "Hiragino Kaku Gothic ProN", "メイリオ", Meiryo, "MS Pゴシック", "MS PGothic", sans-serif;

    /* カラーパレット */
    --bg-color: #faf9f7; 
    --text-main: #33322e; 
    --text-light: #7a7770;
    --border-color: #e2dfd8;
    --accent-color: #0092b4; 
    --active-bg: #f2f9fb;   
    --white: #ffffff;
  }

  body { 
    font-family: var(--font-en); 
    padding: 60px 20px; 
    background-color: var(--bg-color); 
    color: var(--text-main); 
    margin: 0;
    letter-spacing: 0.04em;
    line-height: 1.6;
  }

  /* メインコンテナ */
  .calculator { 
    max-width: 640px; 
    margin: auto; 
    background: var(--white); 
    padding: 48px 40px; 
    border-radius: 4px; 
    border: 1px solid var(--border-color);
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.02); 
  }

  h2 {
    text-align: center;
    font-size: 1.5rem;
    font-weight: 700;
    margin-top: 0;
    margin-bottom: 40px;
    letter-spacing: 0.1em;
    color: var(--text-main);
  }

  .section-title { 
    font-size: 1rem; 
    font-weight: 700; 
    color: var(--text-main); 
    margin-bottom: 12px; 
    padding-bottom: 8px;
    border-bottom: 1px solid var(--border-color);
  }

  .btn-group { 
    display: flex; 
    gap: 8px; 
    margin-bottom: 32px; 
    flex-wrap: wrap; 
  }

  /* 選択ボタン */
  .select-btn { 
    flex: 1; 
    min-width: calc(25% - 8px); 
    padding: 12px; 
    border: 1px solid var(--border-color); 
    background: var(--white); 
    cursor: pointer; 
    border-radius: 2px; 
    font-size: 0.95rem;
    font-family: var(--font-en);
    font-weight: 500;
    color: var(--text-light); 
    transition: all 0.3s ease; 
    text-align: center; 
  }
  .select-btn:hover { 
    background: var(--active-bg); 
    color: var(--text-main);
    border-color: #b3dfea; 
  }
  .select-btn.active { 
    background: var(--accent-color); 
    color: var(--white); 
    border-color: var(--accent-color); 
  }

  /* プルダウンのスタイル */
  .select-dropdown {
    width: 100%;
    padding: 14px 16px;
    border: 1px solid var(--border-color);
    border-radius: 2px;
    font-size: 0.95rem;
    font-family: var(--font-en);
    font-weight: 500;
    color: var(--text-main);
    background-color: var(--white);
    cursor: pointer;
    transition: all 0.3s;
    margin-bottom: 32px;
    appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='<http://www.w3.org/2000/svg>' fill='none' viewBox='0 0 24 24' stroke='%237a7770'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M19 9l-7 7-7-7'%3E%3C/path%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 16px center;
    background-size: 16px;
  }
  .select-dropdown:focus {
    outline: none;
    border-color: var(--accent-color);
    box-shadow: 0 0 0 2px rgba(0, 146, 180, 0.1); 
  }

  /* 部数コントロール */
  .qty-control { 
    display: inline-flex; 
    align-items: center; 
    border: 1px solid var(--border-color); 
    border-radius: 2px; 
    margin-bottom: 32px; 
    background: var(--white);
    transition: border-color 0.3s;
  }
  .qty-control:focus-within {
    border-color: var(--accent-color);
    box-shadow: 0 0 0 2px rgba(0, 146, 180, 0.1);
  }
  .qty-btn { 
    width: 48px; 
    height: 48px; 
    border: none; 
    background: transparent; 
    cursor: pointer; 
    font-size: 18px; 
    color: var(--text-light); 
    transition: all 0.2s; 
    display: flex; 
    align-items: center; 
    justify-content: center; 
  }
  .qty-btn:hover { 
    background: var(--active-bg); 
    color: var(--accent-color); 
  }
  #qty-val { 
    font-size: 1.1rem; 
    font-weight: 600;
    width: 100px; 
    text-align: center; 
    color: var(--text-main); 
  }

  /* 無効化(グレーアウト)時 */
  .print-options-wrapper {
    transition: opacity 0.4s ease;
  }
  .disabled-section {
    opacity: 0.3;
    pointer-events: none;
    user-select: none;
  }

  /* 金額表示エリア */
  .price-display-wrapper {
    margin-top: 40px;
    padding-top: 32px;
    border-top: 1px solid var(--border-color);
    text-align: center;
  }
  .price-label {
    font-size: 0.9rem;
    font-weight: 700;
    color: var(--text-light);
    margin-bottom: 8px;
    letter-spacing: 0.05em;
  }
  .price-display { 
    font-family: var(--font-en);
    font-size: 3.2rem; 
    font-weight: 600;
    color: var(--text-main); 
    margin: 0; 
    line-height: 1;
    letter-spacing: 0.02em;
    display: flex;
    align-items: baseline;
    justify-content: center;
  }
  .price-suffix {
    font-family: var(--font-jp);
    font-size: 1.6rem;
    font-weight: 500;
    color: var(--text-main);
    margin-left: 4px;
  }
  
  /* 割引オプション(チェックボックス)のスタイル */
  .discount-option {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background-color: var(--active-bg);
    padding: 12px 20px;
    margin-top: 16px;
    border-radius: 4px;
    border: 1px solid #b3dfea;
    cursor: pointer;
    font-family: var(--font-jp);
    font-size: 0.95rem;
    color: var(--text-main);
    transition: all 0.2s ease;
  }
  .discount-option:hover {
    background-color: #e5f4f8;
  }
  .discount-option input[type="checkbox"] {
    margin-right: 10px;
    width: 18px;
    height: 18px;
    accent-color: var(--accent-color);
    cursor: pointer;
  }
  .discount-option strong {
    color: var(--accent-color);
    font-size: 1.1rem;
    font-family: var(--font-en);
    margin-left: 6px;
    letter-spacing: 0.02em;
  }

  /* 注記のスタイル */
  .price-note {
    font-family: var(--font-jp);
    font-size: 0.75rem;
    color: var(--text-light);
    margin-top: 24px;
    line-height: 1.5;
    text-align: left;
    background-color: #f9f9f9;
    padding: 12px;
    border-radius: 4px;
  }

  /* スマホ対応 */
  @media (max-width: 480px) {
    .calculator { padding: 32px 20px; }
    .select-btn { min-width: calc(50% - 4px); }
    .price-display { font-size: 2.8rem; }
    .price-suffix { font-size: 1.4rem; }
    .discount-option { font-size: 0.85rem; padding: 10px 12px; width: 100%; box-sizing: border-box; }
  }
</style>
</head>
<body>

<div class="calculator">

    <h2>お見積もりシミュレーション</h2>

    <div class="section-title">ご依頼内容</div>
    <select id="service-type" class="select-dropdown" onchange="updateServiceType()">
        <option value="design_print">デザイン制作 + 印刷</option>
        <option value="design_only">デザイン制作のみ</option>
    </select>
    
    <div class="section-title">ポスターサイズ</div>
    <div class="btn-group" id="size-selector">
        <button class="select-btn active" onclick="updateState('size', 'A3')">A3</button>
        <button class="select-btn" onclick="updateState('size', 'A2')">A2</button>
        <button class="select-btn" onclick="updateState('size', 'A1')">A1</button>
        <button class="select-btn" onclick="updateState('size', 'A0')">A0</button>
        <button class="select-btn" onclick="updateState('size', 'B3')">B3</button>
        <button class="select-btn" onclick="updateState('size', 'B2')">B2</button>
        <button class="select-btn" onclick="updateState('size', 'B1')">B1</button>
        <button class="select-btn" onclick="updateState('size', 'B0')">B0</button>
    </div>

    <div id="print-options-wrapper" class="print-options-wrapper">
        <div class="section-title">用紙(135kg)</div>
        <div class="btn-group" id="paper-selector">
            <button class="select-btn active" onclick="updateState('paper', 'coat')">コート紙</button>
            <button class="select-btn" onclick="updateState('paper', 'matte')">マットコート紙</button>
            <button class="select-btn" onclick="updateState('paper', 'fine')">上質紙</button>
        </div>

        <div class="section-title">印刷部数</div>
        <div class="qty-control">
            <button class="qty-btn" onclick="stepQuantity(-1)">−</button>
            <span id="qty-val">10部</span>
            <button class="qty-btn" onclick="stepQuantity(1)">+</button>
        </div>
    </div>

    <div class="section-title">データ納品オプション</div>
    <select id="data-delivery" class="select-dropdown" onchange="updateDataOption()">
        <option value="none">希望しない(印刷物のみ納品)</option>
        <option value="pdf">印刷用PDFデータをお渡し (+5,000円)</option>
        <option value="ai">Illustratorデータ(アウトライン済) (+15,000円)</option>
        <option value="ai_edit">Illustratorデータ(編集可能) (+30,000円)</option>
    </select>

    <div class="price-display-wrapper">
        <div class="price-label">概算費用(税込)</div>
        <div class="price-display">
            ¥<span id="final-price" style="font-size: inherit; color: inherit; font-family: inherit; margin-left: 0; font-weight: inherit;">0</span><span class="price-suffix">〜</span>
        </div>
        
        <label class="discount-option">
            <input type="checkbox" id="local-discount" onchange="toggleLocalDiscount()">
            地域おこし・地方活性化の取り組みなら<strong>-20%</strong>
        </label>

        <div class="price-note">
            ※その他、用紙・加工・特急・工数などの要因により変動する場合がございます。詳細はお問い合わせ後に改めてご案内いたします。
        </div>
    </div>

</div>

<script>
    const CONFIG = {
        PAPER_SURCHARGE: 1650, 
        DATA_FEES: {
            none: 0,
            pdf: 5000,
            ai: 15000,
            ai_edit: 30000
        }
    };

    const DESIGN_PRICE = {
        A3: 25000, A2: 30000, A1: 40000, A0: 50000,
        B3: 25000, B2: 35000, B1: 45000, B0: 60000
    };

    const PRICE_DATA = {
        A3: { 10: 31770, 50: 33180, 90: 34590, 100: 36290, 500: 38010, 1000: 40180, 3000: 50740 },
        A2: { 10: 42540, 50: 43340, 100: 44320, 300: 45590, 3000: 69950 },
        A1: { 10: 52410, 50: 53820, 100: 55590, 300: 57770, 3000: 100160 },
        A0: { 10: 159020, 100: 176580, 1000: 229530 },
        B3: { 10: 39460, 50: 40060, 100: 40800, 300: 41790, 3000: 60210 },
        B2: { 10: 46840, 50: 47890, 100: 49220, 300: 50890, 3000: 82700 },
        B1: { 10: 63470, 50: 65560, 100: 68190, 300: 71430, 3000: 128420 },
        B0: { 10: 220940, 100: 247200, 1000: 326290 }
    };

    let state = {
        serviceType: 'design_print',
        size: 'A3',
        paper: 'coat', 
        qty: 10,       
        dataDelivery: 'none',
        isLocalDiscount: false // 割引チェック状態
    };

    let currentDisplayPrice = 0;
    let animationId = null;

    function updateServiceType() {
        state.serviceType = document.getElementById('service-type').value;
        const printOptionsWrapper = document.getElementById('print-options-wrapper');
        const dataDeliverySelect = document.getElementById('data-delivery');

        if (state.serviceType === 'design_only') {
            printOptionsWrapper.classList.add('disabled-section');
            if (state.dataDelivery === 'none') {
                dataDeliverySelect.value = 'pdf';
                state.dataDelivery = 'pdf';
            }
            dataDeliverySelect.options[0].disabled = true;
        } else {
            printOptionsWrapper.classList.remove('disabled-section');
            dataDeliverySelect.options[0].disabled = false;
        }
        calculate();
    }

    function updateState(key, val) {
        state[key] = val;
        
        if (key === 'size') {
            const maxQty = (state.size === 'A0' || state.size === 'B0') ? 1000 : 3000;
            if (state.qty > maxQty) {
                state.qty = maxQty;
                updateQtyUI();
            }
        }
        updateButtonActiveStates();
        calculate();
    }

    function updateButtonActiveStates() {
        const sizeBtns = document.getElementById('size-selector').querySelectorAll('.select-btn');
        sizeBtns.forEach(b => {
            b.classList.toggle('active', b.innerText === state.size);
        });
        
        const paperMap = { 'coat': 'コート紙', 'matte': 'マットコート紙', 'fine': '上質紙' };
        const paperBtns = document.getElementById('paper-selector').querySelectorAll('.select-btn');
        paperBtns.forEach(b => {
            b.classList.toggle('active', b.innerText === paperMap[state.paper]);
        });
    }

    function updateDataOption() {
        state.dataDelivery = document.getElementById('data-delivery').value;
        calculate();
    }

    // 割引チェックボックスの切り替え
    function toggleLocalDiscount() {
        state.isLocalDiscount = document.getElementById('local-discount').checked;
        calculate();
    }

    function stepQuantity(direction) {
        let step = 10;
        if (state.qty >= 100 && direction > 0) step = 100;
        if (state.qty > 100 && direction < 0) step = 100;

        let next = state.qty + (direction * step);
        if (next < 10) next = 10;
        
        const max = (state.size === 'A0' || state.size === 'B0') ? 1000 : 3000;
        if (next > max) next = max;

        state.qty = next;
        updateQtyUI();
    }

    function updateQtyUI() {
        document.getElementById('qty-val').innerHTML = `${state.qty.toLocaleString()}部`;
        calculate();
    }

    function interpolate(table, qty) {
        const points = Object.keys(table).map(Number).sort((a, b) => a - b);
        if (table[qty]) return table[qty];
        if (qty <= points[0]) return table[points[0]];
        if (qty >= points[points.length - 1]) return table[points[points.length - 1]];

        let lower = points[0], upper = points[points.length - 1];
        for (let i = 0; i < points.length - 1; i++) {
            if (qty > points[i] && qty < points[i+1]) {
                lower = points[i];
                upper = points[i+1];
                break;
            }
        }
        const ratio = (qty - lower) / (upper - lower);
        return table[lower] + (table[upper] - table[lower]) * ratio;
    }

    function calculate() {
        let base = 0;

        if (state.serviceType === 'design_only') {
            base = DESIGN_PRICE[state.size];
        } else {
            const table = PRICE_DATA[state.size];
            base = interpolate(table, state.qty);
            if (state.paper !== 'coat') {
                base += CONFIG.PAPER_SURCHARGE;
            }
        }

        base += CONFIG.DATA_FEES[state.dataDelivery];

        // ▼ 地域活性化割引の適用(20%オフ)
        if (state.isLocalDiscount) {
            base = base * 0.8;
        }

        // 10円単位で切り上げ
        const final = Math.ceil(base / 10) * 10;
        animatePrice(final, 400);
    }

    function animatePrice(targetPrice, duration) {
        const el = document.getElementById('final-price');
        const startPrice = currentDisplayPrice;
        const startTime = performance.now();
        if (animationId) cancelAnimationFrame(animationId);

        function update(currentTime) {
            const elapsed = currentTime - startTime;
            const progress = Math.min(elapsed / duration, 1);
            
            const ease = progress === 1 ? 1 : 1 - Math.pow(2, -10 * progress);
            
            const current = Math.floor(startPrice + (targetPrice - startPrice) * ease);
            el.innerText = current.toLocaleString();
            currentDisplayPrice = current;
            if (progress < 1) {
                animationId = requestAnimationFrame(update);
            } else {
                el.innerText = targetPrice.toLocaleString();
            }
        }
        animationId = requestAnimationFrame(update);
    }

    // 初期化実行
    updateServiceType();
    updateButtonActiveStates();
    updateQtyUI();

</script>

</body>
</html>