住宅購入 資金計画書
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>住宅購入 資金計画書</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
  <script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js"></script>
  <script src="https://cdn.sheetjs.com/xlsx-0.20.3/package/dist/xlsx.full.min.js"></script>
  <style>
    body { font-family: 'Hiragino Kaku Gothic ProN', 'Hiragino Sans', Meiryo, sans-serif; }
    input[type=text]::-webkit-inner-spin-button { -webkit-appearance: none; }
    @media print {
      .no-print { display: none !important; }
      body { background: white; }
    }
  </style>
</head>
<body class="bg-slate-50">
  <div id="root"></div>

  <script type="text/babel">
    const { useState, useMemo } = React;

    function formatCurrency(value) {
      if (!value && value !== 0) return '¥0';
      return '¥' + Number(value).toLocaleString('ja-JP');
    }

    function toNum(strVal) {
      if (strVal === '' || strVal === null || strVal === undefined) return 0;
      const n = parseInt(String(strVal).replace(/,/g, ''), 10);
      return isNaN(n) ? 0 : n;
    }

    function toDisplayStr(rawDigits) {
      if (rawDigits === '') return '';
      const n = parseInt(rawDigits, 10);
      if (isNaN(n)) return '';
      return n.toLocaleString('ja-JP');
    }

    /* ── 入力フィールド ── */
    function InputField({ label, note, value, onChange, disabled }) {
      return (
        <div className={`mb-4 ${disabled ? 'opacity-40 pointer-events-none' : ''}`}>
          <label className="flex items-baseline gap-2 text-sm font-medium text-slate-700 mb-1.5">
            {label}
            {note && <span className="text-xs font-normal text-slate-400">{note}</span>}
          </label>
          <div className="relative">
            <span className="absolute left-3 top-1/2 -translate-y-1/2 text-slate-400 text-sm select-none">¥</span>
            <input
              type="text"
              inputMode="numeric"
              value={value}
              onChange={onChange}
              disabled={disabled}
              placeholder="0"
              className="w-full pl-7 pr-3 py-2.5 border border-slate-200 rounded-xl bg-white
                         text-right text-slate-800 text-sm
                         focus:outline-none focus:ring-2 focus:ring-blue-400 focus:border-transparent
                         transition-shadow placeholder:text-slate-300"
            />
          </div>
        </div>
      );
    }

    /* ── 費用フィールド(金額+支払先) ── */
    function FeeField({ label, note, value, onChange, payee, onPayeeChange }) {
      return (
        <div className="mb-4">
          <label className="flex items-baseline gap-2 text-sm font-medium text-slate-700 mb-1.5">
            {label}
            {note && <span className="text-xs font-normal text-slate-400">{note}</span>}
          </label>
          <div className="relative">
            <span className="absolute left-3 top-1/2 -translate-y-1/2 text-slate-400 text-sm select-none">¥</span>
            <input
              type="text"
              inputMode="numeric"
              value={value}
              onChange={onChange}
              placeholder="0"
              className="w-full pl-7 pr-3 py-2.5 border border-slate-200 rounded-xl bg-white
                         text-right text-slate-800 text-sm
                         focus:outline-none focus:ring-2 focus:ring-blue-400 focus:border-transparent
                         transition-shadow placeholder:text-slate-300"
            />
          </div>
          <input
            type="text"
            value={payee}
            onChange={onPayeeChange}
            placeholder="支払先"
            className="mt-1.5 w-full px-3 py-1.5 border border-slate-100 rounded-lg bg-slate-50
                       text-slate-600 text-xs
                       focus:outline-none focus:ring-1 focus:ring-blue-300 focus:border-transparent
                       transition-shadow placeholder:text-slate-300"
          />
        </div>
      );
    }

    /* ── 結果カード ── */
    function ResultCard({ label, sub, value, variant = 'blue' }) {
      const s = {
        blue:   { card: 'bg-blue-600 border-blue-600',     label: 'text-blue-100',   sub: 'text-blue-200',   val: 'text-white' },
        teal:   { card: 'bg-teal-600 border-teal-600',     label: 'text-teal-100',   sub: 'text-teal-200',   val: 'text-white' },
        indigo: { card: 'bg-indigo-700 border-indigo-700', label: 'text-indigo-100', sub: 'text-indigo-200', val: 'text-white' },
        violet: { card: 'bg-violet-600 border-violet-600', label: 'text-violet-100', sub: 'text-violet-200', val: 'text-white' },
      }[variant];
      return (
        <div className={`rounded-xl p-4 border ${s.card}`}>
          <p className={`text-xs font-semibold tracking-wide mb-0.5 ${s.label}`}>{label}</p>
          {sub && <p className={`text-xs mb-1 ${s.sub}`}>{sub}</p>}
          <p className={`text-xl font-bold tabular-nums ${s.val}`}>{formatCurrency(value)}</p>
        </div>
      );
    }

    /* ── 資金計画表の行 ── */
    function TR({ label, value, level, total }) {
      const labelCls = level === 'header'
        ? 'py-2 px-4 text-xs font-semibold text-slate-400 uppercase tracking-wider bg-slate-50'
        : level === 'total'
        ? 'py-2.5 px-4 text-sm font-bold text-slate-800 bg-blue-50'
        : level === 'sub'
        ? 'py-2 pl-8 pr-4 text-sm text-slate-500'
        : level === 'note'
        ? 'py-1.5 pl-8 pr-4 text-xs text-slate-400 italic border-b border-slate-100'
        : 'py-2 px-4 text-sm text-slate-700';

      const valueCls = level === 'header'
        ? 'py-2 px-4 text-xs bg-slate-50'
        : level === 'total'
        ? 'py-2.5 px-4 text-sm font-bold text-blue-700 text-right bg-blue-50 tabular-nums'
        : 'py-2 px-4 text-sm text-slate-700 text-right tabular-nums';

      if (level === 'header' || level === 'note') {
        return (
          <tr>
            <td colSpan={2} className={labelCls}>{label}</td>
          </tr>
        );
      }
      return (
        <tr className="border-b border-slate-100">
          <td className={labelCls}>{label}</td>
          <td className={valueCls}>{formatCurrency(value)}</td>
        </tr>
      );
    }

    /* ── テキスト入力フィールド ── */
    function TextField({ label, value, onChange, placeholder }) {
      return (
        <div className="mb-4">
          <label className="block text-sm font-medium text-slate-700 mb-1.5">{label}</label>
          <input
            type="text"
            value={value}
            onChange={onChange}
            placeholder={placeholder}
            className="w-full px-3 py-2.5 border border-slate-200 rounded-xl bg-white
                       text-slate-800 text-sm
                       focus:outline-none focus:ring-2 focus:ring-blue-400 focus:border-transparent
                       transition-shadow placeholder:text-slate-300"
          />
        </div>
      );
    }

    /* ── メインアプリ ── */
    function App() {
      const [type, setType] = useState('house'); // 'house' | 'mansion'
      const [customerName, setCustomerName] = useState('');
      const [propertyName, setPropertyName] = useState('');
      const [staffName, setStaffName] = useState('');
      const [payees, setPayees] = useState({
        agencyFeePayee: '', registrationFeePayee: '', stampDutyPayee: '',
        officeFeePayee: '', fireInsurancePayee: '', propertyTaxPayee: '',
        bankGuaranteeFeePayee: '', managementFeePayee: '', repairFundPayee: '',
      });
      const [f, setF] = useState({
        purchasePrice: '',
        downPayment: '',
        agencyFee: '',
        registrationFee: '',
        stampDuty: '',
        officeFee: '',
        fireInsurance: '',
        propertyTax: '',
        bankGuaranteeFee: '',
        managementFee: '',
        repairFund: '',
      });

      const handleChange = (key) => (e) => {
        const raw = e.target.value.replace(/[^0-9]/g, '');
        setF(prev => ({ ...prev, [key]: toDisplayStr(raw) }));
      };

      const handlePayeeChange = (key) => (e) => {
        setPayees(prev => ({ ...prev, [key]: e.target.value }));
      };

      const v = useMemo(() => {
        const result = {};
        for (const k of Object.keys(f)) result[k] = toNum(f[k]);
        return result;
      }, [f]);

      const calc = useMemo(() => {
        const miscCostsWithoutGuarantee =
          v.agencyFee + v.registrationFee + v.stampDuty + v.officeFee + v.fireInsurance + v.propertyTax;
        const miscCosts = miscCostsWithoutGuarantee + v.bankGuaranteeFee;
        const remaining = Math.max(0, v.purchasePrice - v.downPayment);
        const monthlyCosts = type === 'mansion' ? v.managementFee + v.repairFund : 0;
        const settlementAmount = remaining + miscCosts;
        const totalPayment = v.purchasePrice + miscCosts;
        const suggestedBankGuarantee = Math.round((v.purchasePrice + miscCostsWithoutGuarantee) * 0.022 + 55000);
        return { miscCosts, remaining, monthlyCosts, settlementAmount, totalPayment, suggestedBankGuarantee };
      }, [v, type]);

      const reset = () => {
        setType('house');
        setCustomerName('');
        setPropertyName('');
        setStaffName('');
        setPayees({
          agencyFeePayee: '', registrationFeePayee: '', stampDutyPayee: '',
          officeFeePayee: '', fireInsurancePayee: '', propertyTaxPayee: '',
          bankGuaranteeFeePayee: '', managementFeePayee: '', repairFundPayee: '',
        });
        setF({
          purchasePrice: '',
          downPayment: '',
          agencyFee: '',
          registrationFee: '',
          stampDuty: '',
          officeFee: '',
          fireInsurance: '',
          propertyTax: '',
          bankGuaranteeFee: '',
          managementFee: '',
          repairFund: '',
        });
      };

      const isMansion = type === 'mansion';

      const downloadPDF = () => {
        const el = document.getElementById('pdf-area');
        const name = customerName ? `資金計画書_${customerName}` : (propertyName ? `資金計画書_${propertyName}` : '資金計画書');
        // A4 1枚に収めるため、PDF非表示要素を一時的に隠す
        const noPdfEls = el.querySelectorAll('[data-no-pdf]');
        noPdfEls.forEach(e => { e._prevDisplay = e.style.display; e.style.display = 'none'; });
        html2pdf().set({
          margin: [8, 8, 8, 8],
          filename: `${name}.pdf`,
          image: { type: 'jpeg', quality: 0.98 },
          html2canvas: { scale: 2, useCORS: true, logging: false },
          jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' },
        }).from(el).save().then(() => {
          noPdfEls.forEach(e => { e.style.display = e._prevDisplay; });
        });
      };

      const downloadExcel = () => {
        const today = new Date().toLocaleDateString('ja-JP', { year: 'numeric', month: '2-digit', day: '2-digit' });
        const bdr = () => ({
          top:    { style: 'thin', color: { rgb: 'BBBBBB' } },
          bottom: { style: 'thin', color: { rgb: 'BBBBBB' } },
          left:   { style: 'thin', color: { rgb: 'BBBBBB' } },
          right:  { style: 'thin', color: { rgb: 'BBBBBB' } },
        });
        const S = {
          companyTitle: { font: { bold: true, sz: 14, color: { rgb: 'FFFFFF' } }, fill: { fgColor: { rgb: '3B4F6B' }, patternType: 'solid' }, alignment: { horizontal: 'center', vertical: 'center' }, border: bdr() },
          companyInfo:  { font: { sz: 9, color: { rgb: '555555' } }, fill: { fgColor: { rgb: 'EEE9E0' }, patternType: 'solid' }, alignment: { horizontal: 'center', vertical: 'center' }, border: bdr() },
          docTitle:     { font: { bold: true, sz: 15 }, alignment: { horizontal: 'center', vertical: 'center' } },
          infoLabel:    { font: { bold: true, sz: 10 }, fill: { fgColor: { rgb: 'F5F5F0' }, patternType: 'solid' }, border: bdr() },
          infoValue:    { font: { sz: 10 }, border: bdr() },
          infoDate:     { font: { sz: 10 }, border: bdr(), alignment: { horizontal: 'right' } },
          colHeader:    { font: { bold: true, sz: 10, color: { rgb: 'FFFFFF' } }, fill: { fgColor: { rgb: '4A6FA5' }, patternType: 'solid' }, alignment: { horizontal: 'center', vertical: 'center' }, border: bdr() },
          section:      { font: { bold: true, sz: 10, color: { rgb: '2E4D7B' } }, fill: { fgColor: { rgb: 'E0E8F5' }, patternType: 'solid' }, border: bdr() },
          item:         { font: { sz: 10 }, border: bdr() },
          itemSub:      { font: { sz: 10, color: { rgb: '555555' } }, border: bdr() },
          payee:        { font: { sz: 10 }, border: bdr(), alignment: { horizontal: 'center', vertical: 'center', wrapText: true } },
          amount:       { font: { sz: 10 }, border: bdr(), alignment: { horizontal: 'right' } },
          subAmount:    { font: { sz: 10, color: { rgb: '555555' } }, border: bdr(), alignment: { horizontal: 'right' } },
          total:        { font: { bold: true, sz: 10 }, fill: { fgColor: { rgb: 'DBE9FF' }, patternType: 'solid' }, border: bdr() },
          totalAmt:     { font: { bold: true, sz: 10 }, fill: { fgColor: { rgb: 'DBE9FF' }, patternType: 'solid' }, border: bdr(), alignment: { horizontal: 'right' } },
          grandTotal:   { font: { bold: true, sz: 11, color: { rgb: 'FFFFFF' } }, fill: { fgColor: { rgb: '2B5BA8' }, patternType: 'solid' }, border: bdr() },
          grandTotalAmt:{ font: { bold: true, sz: 11, color: { rgb: 'FFFFFF' } }, fill: { fgColor: { rgb: '2B5BA8' }, patternType: 'solid' }, border: bdr(), alignment: { horizontal: 'right' } },
          empty:        {},
        };
        const wb = XLSX.utils.book_new();
        const ws = {};
        const merges = [];
        const fmt = '¥#,##0';
        const setC = (r, c, v, s, isNum) => {
          const addr = XLSX.utils.encode_cell({ r, c });
          ws[addr] = { v: v ?? '', s: s || S.empty, t: isNum ? 'n' : 's' };
          if (isNum) ws[addr].z = fmt;
        };
        const setN = (r, c, v, s) => setC(r, c, v, s, true);
        const setT = (r, c, v, s) => setC(r, c, v, s, false);
        const mg   = (r1,c1,r2,c2) => merges.push({ s:{r:r1,c:c1}, e:{r:r2,c:c2} });

        setT(0,0,'センチュリー21 えびす不動産',S.companyTitle); setT(0,1,'',S.companyTitle); setT(0,2,'',S.companyTitle); mg(0,0,0,2);
        setT(1,0,'〒596-0053 大阪府岸和田市沼町30番8号 TEL:072-437-1521 MAIL:info@21-ebisu.com',S.companyInfo); setT(1,1,'',S.companyInfo); setT(1,2,'',S.companyInfo); mg(1,0,1,2);
        setT(3,0,'住 宅 購 入 資 金 計 画 書',S.docTitle); setT(3,1,'',S.docTitle); setT(3,2,'',S.docTitle); mg(3,0,3,2);
        setT(5,0,'お客様名',S.infoLabel); setT(5,1,customerName||'',S.infoValue); setT(5,2,`作成日:${today}`,S.infoDate);
        setT(6,0,'物件名',  S.infoLabel); setT(6,1,propertyName||'',S.infoValue); setT(6,2,'',S.infoValue);
        setT(7,0,'担当者',  S.infoLabel); setT(7,1,staffName||'',   S.infoValue); setT(7,2,type==='mansion'?'マンション':type==='land'?'土地':'戸建て',S.infoDate);
        // 列ヘッダー:項目 | 金額 | 支払先
        setT(9,0,'項 目',S.colHeader); setT(9,1,'金 額',S.colHeader); setT(9,2,'支 払 先',S.colHeader);

        let r = 10;
        setT(r,0,'■ 物件費用',S.section); setT(r,1,'',S.section); setT(r,2,'',S.section); mg(r,0,r,2); r++;
        setT(r,0,'売買代金',S.item);               setN(r,1,v.purchasePrice,S.amount);  setT(r,2,'',S.payee); r++;
        setT(r,0,' 手付金',S.itemSub);             setN(r,1,v.downPayment,S.subAmount); setT(r,2,'',S.payee); r++;
        setT(r,0,' 残代金(引渡し時)',S.itemSub); setN(r,1,calc.remaining,S.subAmount); setT(r,2,'',S.payee); r++;

        setT(r,0,'■ 諸費用',S.section); setT(r,1,'',S.section); setT(r,2,'',S.section); mg(r,0,r,2); r++;
        [
          [' 仲介手数料',      v.agencyFee,        payees.agencyFeePayee],
          [' 登記費用',        v.registrationFee,  payees.registrationFeePayee],
          [' 印紙代',          v.stampDuty,        payees.stampDutyPayee],
          [' ローン事務手数料', v.officeFee,        payees.officeFeePayee],
          [' 火災保険料',      v.fireInsurance,    payees.fireInsurancePayee],
          [' 固定資産税',      v.propertyTax,      payees.propertyTaxPayee],
          [' 銀行保証料',      v.bankGuaranteeFee, payees.bankGuaranteeFeePayee],
        ].forEach(([lbl,amt,pee]) => { setT(r,0,lbl,S.itemSub); setN(r,1,amt,S.subAmount); setT(r,2,pee||'',S.payee); r++; });
        setT(r,0,'諸費用合計',S.total); setN(r,1,calc.miscCosts,S.totalAmt); setT(r,2,'',S.total); r++;

        if (isMansion) {
          setT(r,0,'■ 月額費用(マンション)',S.section); setT(r,1,'',S.section); setT(r,2,'',S.section); mg(r,0,r,2); r++;
          setT(r,0,' 管理費(月額)',    S.itemSub); setN(r,1,v.managementFee,S.subAmount); setT(r,2,payees.managementFeePayee||'',S.payee); r++;
          setT(r,0,' 修繕積立金(月額)',S.itemSub); setN(r,1,v.repairFund,S.subAmount);    setT(r,2,payees.repairFundPayee||'',S.payee); r++;
          setT(r,0,'月額費用合計',S.total); setN(r,1,calc.monthlyCosts,S.totalAmt); setT(r,2,'',S.total); r++;
        }

        r++;
        setT(r,0,'決済時の支払額(手付金以外の費用)',S.grandTotal);    setN(r,1,calc.settlementAmount,S.grandTotalAmt); setT(r,2,'',S.grandTotal); r++;
        r++;
        setT(r,0,'総支払い額(物件代金+諸費用+保証料)',S.grandTotal); setN(r,1,calc.totalPayment,S.grandTotalAmt);    setT(r,2,'',S.grandTotal);

        ws['!ref'] = XLSX.utils.encode_range({ s:{r:0,c:0}, e:{r:r,c:2} });
        ws['!merges'] = merges;
        ws['!cols'] = [{ wch: 30 }, { wch: 16 }, { wch: 20 }];
        ws['!rows'] = [{ hpt: 30 }, { hpt: 16 }, { hpt: 10 }, { hpt: 26 }, { hpt: 10 }];
        ws['!pageSetup'] = { paperSize: 9, orientation: 'portrait', fitToPage: true, fitToWidth: 1, fitToHeight: 1 };
        ws['!margins'] = { left: 0.55, right: 0.55, top: 0.75, bottom: 0.75, header: 0.3, footer: 0.3 };

        XLSX.utils.book_append_sheet(wb, ws, '資金計画書');
        const name = customerName ? `資金計画書_${customerName}` : (propertyName ? `資金計画書_${propertyName}` : '資金計画書');
        XLSX.writeFile(wb, `${name}.xlsx`);
      };

      return (
        <div className="min-h-screen bg-slate-50 pb-0">
          {/* ヘッダー */}
          <header className="bg-white border-b border-slate-200 shadow-sm">
            <div className="max-w-5xl mx-auto px-4 py-5 flex items-center gap-3">
              <div className="w-8 h-8 rounded-lg bg-blue-600 flex items-center justify-center flex-shrink-0">
                <svg className="w-5 h-5 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
                  <path strokeLinecap="round" strokeLinejoin="round" d="M3 9l9-7 9 7v11a2 2 0 01-2 2H5a2 2 0 01-2-2z" />
                  <polyline strokeLinecap="round" strokeLinejoin="round" points="9 22 9 12 15 12 15 22" />
                </svg>
              </div>
              <div>
                <h1 className="text-xl font-bold text-slate-800 leading-tight">住宅購入 資金計画書</h1>
                <p className="text-xs text-slate-400 mt-0.5">必要事項を入力すると費用が自動計算されます</p>
              </div>
            </div>
          </header>

          <div className="max-w-5xl mx-auto px-4 pt-6 grid grid-cols-1 lg:grid-cols-5 gap-6">

            {/* ── 左カラム:入力フォーム ── */}
            <section className="lg:col-span-2 no-print">
              <div className="bg-white rounded-2xl border border-slate-200 shadow-sm p-6">
                <h2 className="text-base font-bold text-slate-700 mb-5 pb-3 border-b border-slate-100">
                  入力フォーム
                </h2>

                {/* お客様名・担当者 */}
                <div className="mb-2">
                  <p className="text-xs font-semibold text-slate-400 uppercase tracking-wider mb-3">基本情報</p>
                </div>
                <TextField
                  label="お客様名"
                  value={customerName}
                  onChange={e => setCustomerName(e.target.value)}
                  placeholder="例:山田 太郎 様"
                />
                <TextField
                  label="物件名"
                  value={propertyName}
                  onChange={e => setPropertyName(e.target.value)}
                  placeholder="例:〇〇マンション101号室"
                />
                <TextField
                  label="担当者"
                  value={staffName}
                  onChange={e => setStaffName(e.target.value)}
                  placeholder="例:鈴木 花子"
                />

                {/* 物件種別 */}
                <div className="mb-6">
                  <p className="text-sm font-medium text-slate-700 mb-2">物件種別</p>
                  <div className="grid grid-cols-3 gap-2 p-1 bg-slate-100 rounded-xl">
                    {[
                      { value: 'house',   label: '戸建て' },
                      { value: 'land',    label: '土地' },
                      { value: 'mansion', label: 'マンション' },
                    ].map(opt => (
                      <button
                        key={opt.value}
                        onClick={() => setType(opt.value)}
                        className={`py-2 text-sm font-semibold rounded-lg transition-all ${
                          type === opt.value
                            ? 'bg-white text-blue-600 shadow-sm'
                            : 'text-slate-500 hover:text-slate-700'
                        }`}
                      >
                        {opt.label}
                      </button>
                    ))}
                  </div>
                </div>

                {/* 物件費用 */}
                <div className="mb-2">
                  <p className="text-xs font-semibold text-slate-400 uppercase tracking-wider mb-3">物件費用</p>
                </div>
                <InputField label="売買代金" value={f.purchasePrice} onChange={handleChange('purchasePrice')} />
                <InputField label="手付金" value={f.downPayment} onChange={handleChange('downPayment')} />

                {/* 諸費用 */}
                <div className="mt-5 mb-2">
                  <p className="text-xs font-semibold text-slate-400 uppercase tracking-wider mb-3">諸費用</p>
                </div>
                <FeeField label="仲介手数料" value={f.agencyFee} onChange={handleChange('agencyFee')} payee={payees.agencyFeePayee} onPayeeChange={handlePayeeChange('agencyFeePayee')} />
                <FeeField label="登記費用" value={f.registrationFee} onChange={handleChange('registrationFee')} payee={payees.registrationFeePayee} onPayeeChange={handlePayeeChange('registrationFeePayee')} />
                <FeeField label="印紙代" value={f.stampDuty} onChange={handleChange('stampDuty')} payee={payees.stampDutyPayee} onPayeeChange={handlePayeeChange('stampDutyPayee')} />
                <FeeField label="ローン事務手数料" value={f.officeFee} onChange={handleChange('officeFee')} payee={payees.officeFeePayee} onPayeeChange={handlePayeeChange('officeFeePayee')} />
                <FeeField label="火災保険料" value={f.fireInsurance} onChange={handleChange('fireInsurance')} payee={payees.fireInsurancePayee} onPayeeChange={handlePayeeChange('fireInsurancePayee')} />
                <FeeField label="固定資産税" value={f.propertyTax} onChange={handleChange('propertyTax')} payee={payees.propertyTaxPayee} onPayeeChange={handlePayeeChange('propertyTaxPayee')} />
                <p className="text-xs text-slate-400 italic -mt-2 mb-4 pl-1">
                  4/1〜3/31までの日割精算
                </p>

                {/* マンション専用:月額費用 */}
                {isMansion && (
                  <>
                    <div className="mt-5 mb-2">
                      <p className="text-xs font-semibold text-blue-400 uppercase tracking-wider mb-3">月額費用(マンション)</p>
                    </div>
                    <FeeField label="管理費" note="月額" value={f.managementFee} onChange={handleChange('managementFee')} payee={payees.managementFeePayee} onPayeeChange={handlePayeeChange('managementFeePayee')} />
                    <FeeField label="修繕積立金" note="月額" value={f.repairFund} onChange={handleChange('repairFund')} payee={payees.repairFundPayee} onPayeeChange={handlePayeeChange('repairFundPayee')} />
                  </>
                )}

                {/* 銀行保証料(最後) */}
                <div className="mt-5 mb-2">
                  <p className="text-xs font-semibold text-slate-400 uppercase tracking-wider mb-3">銀行保証料</p>
                </div>
                <FeeField label="銀行保証料" value={f.bankGuaranteeFee} onChange={handleChange('bankGuaranteeFee')} payee={payees.bankGuaranteeFeePayee} onPayeeChange={handlePayeeChange('bankGuaranteeFeePayee')} />
                <p className="text-xs text-blue-400 -mt-2 mb-4 pl-1 leading-relaxed">
                  参考: {formatCurrency(calc.suggestedBankGuarantee)}<br />
                  (売買代金+諸費用の2.2%+¥55,000)
                </p>

                <button
                  onClick={reset}
                  className="w-full mt-5 py-2.5 border-2 border-slate-200 text-slate-500 text-sm font-semibold
                             rounded-xl hover:bg-slate-50 hover:border-slate-300 active:scale-95 transition-all"
                >
                  リセット
                </button>
              </div>
            </section>

            {/* ── 右カラム:結果 ── */}
            <div className="lg:col-span-3 space-y-5">

              {/* ダウンロードボタン */}
              <div className="no-print flex gap-2 justify-end flex-wrap">
                <button
                  onClick={downloadExcel}
                  className="flex items-center gap-1.5 px-4 py-2 rounded-xl border-2 border-emerald-500 text-emerald-600 text-sm font-semibold hover:bg-emerald-50 active:scale-95 transition-all"
                >
                  <svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}><path strokeLinecap="round" strokeLinejoin="round" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" /></svg>
                  Excelダウンロード
                </button>
                <button
                  onClick={downloadPDF}
                  className="flex items-center gap-1.5 px-4 py-2 rounded-xl border-2 border-blue-500 text-blue-600 text-sm font-semibold hover:bg-blue-50 active:scale-95 transition-all"
                >
                  <svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}><path strokeLinecap="round" strokeLinejoin="round" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" /></svg>
                  PDFダウンロード
                </button>
              </div>

              {/* PDF / 印刷エリア ここから */}
              <div id="pdf-area" className="space-y-4">

              {/* PDF ヘッダー:顧客情報 */}
              <div className="bg-white rounded-2xl border border-slate-200 shadow-sm px-5 py-3">
                <div className="flex justify-between items-center mb-2 pb-2 border-b border-slate-100">
                  <h2 className="text-sm font-bold text-slate-800 tracking-wide">住宅購入 資金計画書</h2>
                  <p className="text-xs text-slate-400">{new Date().toLocaleDateString('ja-JP', {year:'numeric',month:'2-digit',day:'2-digit'})}</p>
                </div>
                <div className="grid grid-cols-2 gap-x-6 gap-y-2">
                  <div className="flex items-center gap-2">
                    <span className="text-xs text-slate-400 w-16 flex-shrink-0">お客様名</span>
                    <span className="text-sm font-bold text-slate-800">{customerName || '―'}</span>
                  </div>
                  <div className="flex items-center gap-2">
                    <span className="text-xs text-slate-400 w-16 flex-shrink-0">担当者</span>
                    <span className="text-sm font-semibold text-slate-700">{staffName || '―'}</span>
                  </div>
                  <div className="flex items-center gap-2 col-span-2">
                    <span className="text-xs text-slate-400 w-16 flex-shrink-0">物件名</span>
                    <span className="text-sm font-semibold text-slate-700">{propertyName || '―'}</span>
                  </div>
                </div>
              </div>

              {/* 計算結果カード群(画面表示のみ・PDF非表示) */}
              <section data-no-pdf="true">
                <h2 className="text-base font-bold text-slate-700 mb-3">計算結果</h2>
                <div className="grid grid-cols-2 gap-3">
                  <ResultCard label="物件代金" sub="手付金+残代金" value={v.purchasePrice} variant="blue" />
                  <ResultCard label="諸費用合計" sub="仲介・登記・保険ほか" value={calc.miscCosts} variant="blue" />
                  {isMansion && (
                    <ResultCard label="月額費用" sub="管理費+修繕積立金" value={calc.monthlyCosts} variant="violet" />
                  )}
                  <ResultCard label="決済時の支払額" sub="手付金以外の費用" value={calc.settlementAmount} variant="teal" />
                  <ResultCard label="総支払い額" sub="物件代金+諸費用+保証料" value={calc.totalPayment} variant="indigo" />
                </div>
              </section>

              {/* 資金計画表 */}
              <section>
                <h2 className="text-base font-bold text-slate-700 mb-3">資金計画表</h2>
                <div className="bg-white rounded-2xl border border-slate-200 shadow-sm overflow-hidden">
                  <table className="w-full border-collapse">
                    <tbody>
                      <TR label="物件費用" level="header" />
                      <TR label="売買代金" value={v.purchasePrice} />
                      <TR label="手付金" value={v.downPayment} level="sub" />
                      <TR label="残代金(引渡し時)" value={calc.remaining} level="sub" />

                      <TR label="諸費用" level="header" />
                      <TR label="仲介手数料" value={v.agencyFee} level="sub" />
                      <TR label="登記費用" value={v.registrationFee} level="sub" />
                      <TR label="印紙代" value={v.stampDuty} level="sub" />
                      <TR label="ローン事務手数料" value={v.officeFee} level="sub" />
                      <TR label="火災保険料" value={v.fireInsurance} level="sub" />
                      <TR label="固定資産税" value={v.propertyTax} level="sub" />
                      <TR label="銀行保証料" value={v.bankGuaranteeFee} level="sub" />
                      <TR label="諸費用合計" value={calc.miscCosts} level="total" />

                      {isMansion && (
                        <>
                          <TR label="月額費用(マンション)" level="header" />
                          <TR label="管理費" value={v.managementFee} level="sub" />
                          <TR label="修繕積立金" value={v.repairFund} level="sub" />
                          <TR label="月額費用合計" value={calc.monthlyCosts} level="total" />
                        </>
                      )}

                      <TR label="決済時の支払額" level="header" />
                      <TR label="決済時の支払額(手付金以外の費用)" value={calc.settlementAmount} level="total" />
                      <TR label="総支払い額(物件代金+諸費用+保証料)" value={calc.totalPayment} level="total" />
                    </tbody>
                  </table>
                </div>
              </section>


              </div>{/* /pdf-area */}
            </div>
          </div>

          {/* フッター */}
          <footer className="bg-[#BEAF88] mt-12">
            <div className="max-w-5xl mx-auto px-4 py-5 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2">
              <div className="text-slate-800">
                <p className="text-sm font-bold tracking-wide">センチュリー21 えびす不動産</p>
                <p className="text-xs text-slate-700 mt-0.5">〒596-0053 大阪府岸和田市沼町30番8号</p>
              </div>
              <div className="flex flex-col sm:items-end text-xs text-slate-700 gap-0.5">
                <span>TEL:072-437-1521</span>
                <span>MAIL:info@21-ebisu.com</span>
                <a href="https://www.21-ebisu.jp" target="_blank" rel="noopener noreferrer"
                   className="text-blue-800 hover:text-blue-900 underline underline-offset-2">
                  https://www.21-ebisu.jp
                </a>
              </div>
            </div>
          </footer>
        </div>
      );
    }

    ReactDOM.createRoot(document.getElementById('root')).render(<App />);
  </script>
</body>
</html>