{"id":5798,"date":"2026-08-01T20:01:51","date_gmt":"2026-08-01T11:01:51","guid":{"rendered":"https:\/\/nk-ts.net\/?p=5798"},"modified":"2026-08-01T20:02:00","modified_gmt":"2026-08-01T11:02:00","slug":"%e3%83%a1%e3%83%a2%e7%94%a8%e7%b4%99%e7%ae%a1%e7%90%86%e3%82%a2%e3%83%97%e3%83%aa","status":"publish","type":"post","link":"https:\/\/nk-ts.net\/?p=5798","title":{"rendered":"\u30e1\u30e2\u7528\u7d19\u7ba1\u7406\u30a2\u30d7\u30ea"},"content":{"rendered":"\n<!DOCTYPE html>\n<html lang=\"ja\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <title>\u53d7\u691c\u8005\u30fb\u8a66\u9a13\u5225\u30e1\u30e2\u56de\u53ce\u7ba1\u7406<\/title>\n  <style>\n    :root {\n      --primary: #4f46e5;\n      --primary-dark: #3730a3;\n      --success: #15803d;\n      --success-soft: #dcfce7;\n      --danger: #dc2626;\n      --danger-dark: #991b1b;\n      --danger-soft: #fee2e2;\n      --warning: #c2410c;\n      --warning-soft: #ffedd5;\n      --paper: #0f766e;\n      --paper-soft: #ccfbf1;\n      --line: #d9e2ef;\n      --bg: #eef2ff;\n      --panel: #ffffff;\n      --soft: #f8fafc;\n      --text: #172033;\n      --muted: #64748b;\n      --shadow: 0 18px 48px rgba(30, 41, 59, 0.14);\n    }\n\n    * { box-sizing: border-box; }\n    html { scroll-behavior: smooth; }\n\n    body {\n      margin: 0;\n      min-height: 100vh;\n      color: var(--text);\n      background: linear-gradient(135deg, #e0e7ff 0%, #f8fafc 52%, #ccfbf1 100%);\n      font-family: \"Segoe UI\", \"Meiryo\", system-ui, -apple-system, BlinkMacSystemFont, sans-serif;\n    }\n\n    button, input, select { font: inherit; }\n    button { touch-action: manipulation; }\n\n    .app {\n      width: min(1540px, calc(100% - 22px));\n      margin: 12px auto 28px;\n      background: var(--panel);\n      border: 1px solid rgba(255,255,255,.9);\n      border-radius: 20px;\n      overflow: hidden;\n      box-shadow: var(--shadow);\n    }\n\n    .header {\n      color: #fff;\n      background: linear-gradient(135deg, var(--primary) 0%, #6d28d9 58%, var(--paper) 100%);\n      padding: 18px 22px;\n    }\n\n    .header-row {\n      display: flex;\n      align-items: center;\n      justify-content: space-between;\n      gap: 18px;\n      flex-wrap: wrap;\n    }\n\n    .title h1 {\n      margin: 0;\n      font-size: clamp(22px, 2.7vw, 34px);\n      line-height: 1.2;\n    }\n\n    .title p {\n      margin: 7px 0 0;\n      font-size: 13px;\n      opacity: .94;\n    }\n\n    .header-actions {\n      display: flex;\n      align-items: center;\n      gap: 8px;\n      flex-wrap: wrap;\n    }\n\n    .date-field,\n    .header-btn {\n      min-height: 42px;\n      border-radius: 10px;\n      font-weight: 800;\n    }\n\n    .date-field {\n      padding: 8px 11px;\n      color: #172033;\n      background: #fff;\n      border: 1px solid rgba(255,255,255,.65);\n    }\n\n    .header-btn {\n      padding: 9px 13px;\n      color: #fff;\n      background: rgba(255,255,255,.14);\n      border: 1px solid rgba(255,255,255,.52);\n      cursor: pointer;\n    }\n\n    .header-btn:hover { background: rgba(255,255,255,.24); }\n\n    .storage-status {\n      min-height: 34px;\n      display: inline-flex;\n      align-items: center;\n      gap: 7px;\n      padding: 7px 11px;\n      border-radius: 999px;\n      border: 1px solid rgba(255,255,255,.44);\n      background: rgba(15,23,42,.18);\n      color: #fff;\n      font-size: 12px;\n      font-weight: 900;\n      white-space: nowrap;\n    }\n\n    .storage-status::before {\n      content: '';\n      width: 9px;\n      height: 9px;\n      border-radius: 50%;\n      background: #fde68a;\n      box-shadow: 0 0 0 3px rgba(253,230,138,.18);\n    }\n\n    .storage-status.saved::before {\n      background: #86efac;\n      box-shadow: 0 0 0 3px rgba(134,239,172,.18);\n    }\n\n    .storage-status.error::before {\n      background: #fca5a5;\n      box-shadow: 0 0 0 3px rgba(252,165,165,.18);\n    }\n\n    .summary {\n      display: grid;\n      grid-template-columns: repeat(5, minmax(0, 1fr));\n      gap: 10px;\n      padding: 13px 16px;\n      background: #f8fafc;\n      border-bottom: 1px solid var(--line);\n    }\n\n    .summary-card {\n      min-height: 76px;\n      padding: 11px 13px;\n      background: #fff;\n      border: 1px solid var(--line);\n      border-radius: 13px;\n      box-shadow: 0 4px 12px rgba(15,23,42,.045);\n    }\n\n    .summary-label {\n      color: var(--muted);\n      font-size: 12px;\n      font-weight: 800;\n    }\n\n    .summary-value {\n      margin-top: 5px;\n      font-size: 27px;\n      line-height: 1;\n      font-weight: 900;\n      color: var(--primary-dark);\n    }\n\n    .summary-card.warning .summary-value { color: var(--danger); }\n    .summary-card.success .summary-value { color: var(--success); }\n    .summary-card.paper .summary-value { color: var(--paper); }\n    .summary-card.exam .summary-value { color: var(--warning); }\n\n    .toolbar {\n      position: sticky;\n      top: 0;\n      z-index: 30;\n      display: flex;\n      align-items: end;\n      justify-content: space-between;\n      gap: 12px;\n      flex-wrap: wrap;\n      padding: 11px 16px;\n      background: rgba(255,255,255,.97);\n      border-bottom: 1px solid var(--line);\n      backdrop-filter: blur(8px);\n    }\n\n    .tool-cluster {\n      display: flex;\n      align-items: end;\n      gap: 10px;\n      flex-wrap: wrap;\n    }\n\n    .tool-group label {\n      display: block;\n      margin-bottom: 5px;\n      color: #334155;\n      font-size: 11px;\n      font-weight: 900;\n    }\n\n    .field,\n    .select,\n    .tool-btn {\n      min-height: 40px;\n      border-radius: 9px;\n    }\n\n    .field,\n    .select {\n      padding: 8px 10px;\n      color: var(--text);\n      background: #fff;\n      border: 2px solid var(--line);\n      outline: none;\n    }\n\n    .field:focus,\n    .select:focus {\n      border-color: var(--primary);\n      box-shadow: 0 0 0 3px rgba(79,70,229,.12);\n    }\n\n    .jump-input { width: 118px; }\n    .select { min-width: 165px; }\n\n    .tool-btn {\n      padding: 8px 13px;\n      color: #fff;\n      background: var(--primary);\n      border: none;\n      cursor: pointer;\n      font-weight: 900;\n    }\n\n    .tool-btn.secondary {\n      color: #334155;\n      background: #eef2f7;\n      border: 1px solid var(--line);\n    }\n\n    .list-info {\n      color: var(--muted);\n      font-size: 12px;\n      font-weight: 800;\n    }\n\n    .table-wrap {\n      overflow-x: auto;\n      background: #fff;\n    }\n\n    table {\n      width: 100%;\n      min-width: 1050px;\n      border-collapse: separate;\n      border-spacing: 0;\n    }\n\n    thead th {\n      position: sticky;\n      top: 63px;\n      z-index: 15;\n      padding: 10px 11px;\n      color: #334155;\n      background: #eaf0fb;\n      border-bottom: 2px solid #cbd5e1;\n      text-align: left;\n      font-size: 12px;\n      letter-spacing: .02em;\n    }\n\n    tbody td {\n      padding: 7px 10px;\n      background: #fff;\n      border-bottom: 1px solid #e8edf4;\n      vertical-align: middle;\n    }\n\n    tbody tr:hover td { background: #fafbff; }\n    tbody tr.uncollected-row td { background: #fff8f8; }\n    tbody tr.uncollected-row:hover td { background: #fff1f1; }\n    tbody tr.jump-highlight td { animation: rowFlash 1.4s ease; }\n\n    @keyframes rowFlash {\n      0%, 100% { background: inherit; }\n      20%, 70% { background: #fef08a; }\n    }\n\n    .candidate-cell {\n      width: 205px;\n      white-space: nowrap;\n    }\n\n    .candidate-line {\n      display: flex;\n      align-items: center;\n      gap: 7px;\n    }\n\n    .candidate-no {\n      display: inline-flex;\n      align-items: center;\n      justify-content: center;\n      min-width: 88px;\n      min-height: 36px;\n      padding: 6px 9px;\n      color: #1e293b;\n      background: #eef2ff;\n      border: 1px solid #c7d2fe;\n      border-radius: 9px;\n      font-size: 14px;\n      font-weight: 900;\n    }\n\n    .exam-count {\n      min-width: 45px;\n      text-align: center;\n      color: var(--warning);\n      font-size: 15px;\n      font-weight: 900;\n    }\n\n    .square-btn {\n      width: 36px;\n      height: 36px;\n      padding: 0;\n      border: none;\n      border-radius: 9px;\n      color: #fff;\n      cursor: pointer;\n      font-size: 21px;\n      line-height: 1;\n      font-weight: 900;\n    }\n\n    .exam-minus { background: #64748b; }\n    .exam-plus { background: linear-gradient(135deg, #f97316, #c2410c); }\n    .square-btn:disabled { opacity: .33; cursor: not-allowed; }\n\n    .sessions-cell { min-width: 640px; }\n\n    .session-list {\n      display: flex;\n      align-items: stretch;\n      gap: 7px;\n      flex-wrap: wrap;\n    }\n\n    .session-card {\n      display: grid;\n      grid-template-columns: auto auto auto auto;\n      align-items: center;\n      gap: 6px;\n      min-height: 48px;\n      padding: 6px 7px;\n      background: #f8fafc;\n      border: 1px solid var(--line);\n      border-radius: 11px;\n    }\n\n    .session-card.uncollected {\n      background: var(--danger-soft);\n      border-color: #fca5a5;\n      box-shadow: inset 4px 0 0 var(--danger);\n    }\n\n    .session-card.collected {\n      background: var(--success-soft);\n      border-color: #86efac;\n      box-shadow: inset 4px 0 0 var(--success);\n    }\n\n    .session-no {\n      min-width: 33px;\n      text-align: center;\n      color: #fff;\n      background: var(--primary);\n      border-radius: 8px;\n      padding: 7px 5px;\n      font-size: 13px;\n      font-weight: 900;\n    }\n\n    .paper-counter {\n      display: flex;\n      align-items: center;\n      gap: 4px;\n    }\n\n    .paper-btn {\n      width: 32px;\n      height: 32px;\n      padding: 0;\n      color: #fff;\n      background: var(--paper);\n      border: none;\n      border-radius: 8px;\n      cursor: pointer;\n      font-size: 18px;\n      font-weight: 900;\n    }\n\n    .paper-btn.minus { background: #64748b; }\n    .paper-btn:disabled { opacity: .32; cursor: not-allowed; }\n\n    .paper-value {\n      min-width: 49px;\n      text-align: center;\n      color: var(--paper);\n      font-size: 14px;\n      font-weight: 900;\n    }\n\n    .collect-btn {\n      min-width: 90px;\n      min-height: 34px;\n      padding: 6px 9px;\n      border: none;\n      border-radius: 8px;\n      cursor: pointer;\n      font-size: 12px;\n      font-weight: 900;\n      white-space: nowrap;\n    }\n\n    .collect-btn.none {\n      color: #475569;\n      background: #e2e8f0;\n      cursor: default;\n    }\n\n    .collect-btn.pending {\n      color: #fff;\n      background: var(--danger);\n    }\n\n    .collect-btn.done {\n      color: #fff;\n      background: var(--success);\n    }\n\n    .status-cell {\n      width: 145px;\n      text-align: center;\n      white-space: nowrap;\n    }\n\n    .status-badge {\n      display: inline-flex;\n      align-items: center;\n      justify-content: center;\n      min-width: 112px;\n      min-height: 34px;\n      padding: 6px 9px;\n      border-radius: 999px;\n      font-size: 12px;\n      font-weight: 900;\n    }\n\n    .status-badge.pending { color: var(--danger-dark); background: var(--danger-soft); }\n    .status-badge.done { color: #166534; background: var(--success-soft); }\n    .status-badge.none { color: #475569; background: #e2e8f0; }\n\n    .empty-message {\n      padding: 42px 20px;\n      color: var(--muted);\n      text-align: center;\n      font-weight: 800;\n    }\n\n    .end-section {\n      padding: 28px 18px 32px;\n      text-align: center;\n      background: #f8fafc;\n      border-top: 1px solid var(--line);\n    }\n\n    .end-section h2 {\n      margin: 0 0 7px;\n      font-size: 21px;\n    }\n\n    .end-section p {\n      margin: 0 0 16px;\n      color: var(--muted);\n      font-size: 13px;\n    }\n\n    .reset-btn {\n      min-width: 250px;\n      min-height: 50px;\n      padding: 12px 22px;\n      color: #fff;\n      background: var(--danger);\n      border: none;\n      border-radius: 12px;\n      cursor: pointer;\n      font-size: 17px;\n      font-weight: 900;\n    }\n\n    .reset-btn:hover { background: #b91c1c; }\n\n    .modal {\n      position: fixed;\n      inset: 0;\n      z-index: 1000;\n      display: none;\n      align-items: center;\n      justify-content: center;\n      padding: 18px;\n      background: rgba(15,23,42,.78);\n      backdrop-filter: blur(5px);\n    }\n\n    .modal.open { display: flex; }\n\n    .modal-card {\n      width: min(560px, 100%);\n      padding: 24px;\n      background: #fff;\n      border-radius: 18px;\n      box-shadow: 0 24px 70px rgba(0,0,0,.34);\n    }\n\n    .modal-card h2 {\n      margin: 0;\n      font-size: 25px;\n    }\n\n    .modal-card p {\n      margin: 9px 0 17px;\n      color: var(--muted);\n      font-size: 14px;\n      line-height: 1.65;\n    }\n\n    .setup-count {\n      width: 100%;\n      min-height: 52px;\n      padding: 10px 13px;\n      border: 2px solid var(--line);\n      border-radius: 11px;\n      outline: none;\n      font-size: 20px;\n      font-weight: 900;\n    }\n\n    .setup-count:focus {\n      border-color: var(--primary);\n      box-shadow: 0 0 0 3px rgba(79,70,229,.12);\n    }\n\n    .preset-row {\n      display: grid;\n      grid-template-columns: repeat(5, 1fr);\n      gap: 7px;\n      margin-top: 11px;\n    }\n\n    .preset-btn {\n      min-height: 42px;\n      padding: 7px;\n      color: #334155;\n      background: #eef2f7;\n      border: 1px solid var(--line);\n      border-radius: 9px;\n      cursor: pointer;\n      font-weight: 900;\n    }\n\n    .modal-warning {\n      display: none;\n      margin: 13px 0 0;\n      padding: 11px 12px;\n      color: var(--danger-dark);\n      background: var(--danger-soft);\n      border: 1px solid #fca5a5;\n      border-radius: 10px;\n      font-size: 13px;\n      font-weight: 900;\n    }\n\n    .modal-warning.show { display: block; }\n\n    .modal-actions {\n      display: flex;\n      justify-content: flex-end;\n      gap: 9px;\n      margin-top: 20px;\n    }\n\n    .modal-action {\n      min-width: 130px;\n      min-height: 46px;\n      padding: 10px 17px;\n      border-radius: 10px;\n      cursor: pointer;\n      font-size: 15px;\n      font-weight: 900;\n    }\n\n    .modal-action.cancel {\n      color: #334155;\n      background: #eef2f7;\n      border: 1px solid var(--line);\n    }\n\n    .modal-action.apply {\n      color: #fff;\n      background: var(--primary);\n      border: none;\n    }\n\n    .modal-action.erase {\n      color: #fff;\n      background: var(--danger);\n      border: none;\n    }\n\n    .toast {\n      position: fixed;\n      right: 18px;\n      bottom: 18px;\n      z-index: 1200;\n      max-width: min(390px, calc(100% - 36px));\n      padding: 12px 16px;\n      color: #fff;\n      background: #172033;\n      border-radius: 10px;\n      box-shadow: 0 12px 30px rgba(15,23,42,.28);\n      font-size: 13px;\n      font-weight: 800;\n      animation: toastIn .22s ease;\n    }\n\n    @keyframes toastIn {\n      from { transform: translateY(18px); opacity: 0; }\n      to { transform: translateY(0); opacity: 1; }\n    }\n\n    @media (max-width: 1050px) {\n      .summary { grid-template-columns: repeat(3, minmax(0, 1fr)); }\n      thead th { top: 109px; }\n    }\n\n    @media (max-width: 720px) {\n      .app { width: calc(100% - 10px); margin: 5px auto 16px; border-radius: 14px; }\n      .header { padding: 15px 14px; }\n      .summary { grid-template-columns: repeat(2, minmax(0, 1fr)); padding: 10px; }\n      .toolbar { padding: 10px; }\n      .tool-cluster { width: 100%; }\n      .tool-group { flex: 1; min-width: 135px; }\n      .field, .select, .tool-btn { width: 100%; }\n      .jump-input { width: 100%; }\n      thead th { top: 156px; }\n      .preset-row { grid-template-columns: repeat(3, 1fr); }\n      .modal-actions { flex-direction: column-reverse; }\n      .modal-action { width: 100%; }\n    }\n  <\/style>\n<\/head>\n<body>\n  <main class=\"app\">\n    <header class=\"header\">\n      <div class=\"header-row\">\n        <div class=\"title\">\n          <h1>\u53d7\u691c\u8005\u30fb\u8a66\u9a13\u5225\u30e1\u30e2\u56de\u53ce\u7ba1\u7406<\/h1>\n          <p>\u5404\u53d7\u691c\u8005\u306e\u7b2c1\u8a66\u9a13\u30fb\u7b2c2\u8a66\u9a13\u3054\u3068\u306b\u3001\u30e1\u30e2\u7528\u7d19\u306e\u914d\u5e03\u679a\u6570\u3068\u56de\u53ce\u72b6\u6cc1\u3092\u78ba\u8a8d\u3057\u307e\u3059\u3002<\/p>\n        <\/div>\n        <div class=\"header-actions\">\n          <span id=\"storage-status\" class=\"storage-status\" aria-live=\"polite\">DB\u8aad\u8fbc\u4e2d<\/span>\n          <input type=\"date\" id=\"event-date\" class=\"date-field\" aria-label=\"\u958b\u50ac\u65e5\">\n          <button type=\"button\" id=\"change-count-btn\" class=\"header-btn\">\u53d7\u691c\u8005\u6570\u3092\u5909\u66f4<\/button>\n        <\/div>\n      <\/div>\n    <\/header>\n\n    <section class=\"summary\" aria-label=\"\u672c\u65e5\u306e\u96c6\u8a08\">\n      <div class=\"summary-card\">\n        <div class=\"summary-label\">\u53d7\u691c\u8005\u6570<\/div>\n        <div class=\"summary-value\"><span id=\"summary-candidates\">0<\/span>\u540d<\/div>\n      <\/div>\n      <div class=\"summary-card exam\">\n        <div class=\"summary-label\">\u8ffd\u52a0\u8a66\u9a13<\/div>\n        <div class=\"summary-value\"><span id=\"summary-extra-exams\">0<\/span>\u56de<\/div>\n      <\/div>\n      <div class=\"summary-card paper\">\n        <div class=\"summary-label\">\u30e1\u30e2\u7528\u7d19\u914d\u5e03<\/div>\n        <div class=\"summary-value\"><span id=\"summary-papers\">0<\/span>\u679a<\/div>\n      <\/div>\n      <div class=\"summary-card success\">\n        <div class=\"summary-label\">\u56de\u53ce\u6e08\u307f\u8a66\u9a13<\/div>\n        <div class=\"summary-value\"><span id=\"summary-collected\">0<\/span>\u4ef6<\/div>\n      <\/div>\n      <div class=\"summary-card warning\">\n        <div class=\"summary-label\">\u672a\u56de\u53ce\u306e\u8a66\u9a13<\/div>\n        <div class=\"summary-value\"><span id=\"summary-uncollected\">0<\/span>\u4ef6<\/div>\n      <\/div>\n    <\/section>\n\n    <section class=\"toolbar\">\n      <div class=\"tool-cluster\">\n        <div class=\"tool-group\">\n          <label for=\"jump-no\">\u53d7\u691c\u8005No.\u3078\u79fb\u52d5<\/label>\n          <div style=\"display:flex;gap:6px;\">\n            <input id=\"jump-no\" class=\"field jump-input\" type=\"number\" min=\"1\" max=\"200\" placeholder=\"\u4f8b\uff1a128\">\n            <button type=\"button\" id=\"jump-btn\" class=\"tool-btn\">\u79fb\u52d5<\/button>\n          <\/div>\n        <\/div>\n        <div class=\"tool-group\">\n          <label for=\"filter-select\">\u4e00\u89a7\u306e\u7d5e\u308a\u8fbc\u307f<\/label>\n          <select id=\"filter-select\" class=\"select\">\n            <option value=\"all\">\u3059\u3079\u3066\u8868\u793a<\/option>\n            <option value=\"uncollected\">\u672a\u56de\u53ce\u3042\u308a<\/option>\n            <option value=\"extra\">\u8ffd\u52a0\u8a66\u9a13\u3042\u308a<\/option>\n            <option value=\"paper\">\u30e1\u30e2\u7528\u7d19\u3042\u308a<\/option>\n            <option value=\"complete\">\u56de\u53ce\u78ba\u8a8d\u6e08\u307f<\/option>\n          <\/select>\n        <\/div>\n      <\/div>\n      <div id=\"list-info\" class=\"list-info\">0\u540d\u3092\u8868\u793a\u4e2d<\/div>\n    <\/section>\n\n    <div class=\"table-wrap\">\n      <table>\n        <thead>\n          <tr>\n            <th>\u53d7\u691c\u8005\u30fb\u8a66\u9a13\u56de\u6570<\/th>\n            <th>\u8a66\u9a13\u3054\u3068\u306e\u30e1\u30e2\u7528\u7d19\uff0f\u56de\u53ce\u78ba\u8a8d<\/th>\n            <th>\u56de\u53ce\u72b6\u6cc1<\/th>\n          <\/tr>\n        <\/thead>\n        <tbody id=\"candidate-body\"><\/tbody>\n      <\/table>\n    <\/div>\n\n    <section class=\"end-section\">\n      <h2>\u672c\u65e5\u306e\u958b\u50ac\u7d42\u4e86<\/h2>\n      <p>\u30ea\u30bb\u30c3\u30c8\u3059\u308b\u3068\u3001\u53d7\u691c\u8005\u6570\u30fb\u8ffd\u52a0\u8a66\u9a13\u30fb\u30e1\u30e2\u7528\u7d19\u679a\u6570\u30fb\u56de\u53ce\u72b6\u6cc1\u304c\u3059\u3079\u3066\u524a\u9664\u3055\u308c\u307e\u3059\u3002<\/p>\n      <button type=\"button\" id=\"reset-all-btn\" class=\"reset-btn\">\u3059\u3079\u3066\u30ea\u30bb\u30c3\u30c8<\/button>\n    <\/section>\n  <\/main>\n\n  <div id=\"setup-modal\" class=\"modal\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"setup-title\">\n    <div class=\"modal-card\">\n      <h2 id=\"setup-title\">\u672c\u65e5\u306e\u53d7\u691c\u8005\u6570<\/h2>\n      <p id=\"setup-description\">\u5f53\u65e5\u306e\u53d7\u691c\u8005\u6570\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u300213\u540d\u306a\u308913\u540d\u3060\u3051\u3001200\u540d\u306a\u3089200\u540d\u3059\u3079\u3066\u3092\u4e00\u89a7\u8868\u793a\u3057\u307e\u3059\u3002<\/p>\n      <input id=\"candidate-count-input\" class=\"setup-count\" type=\"number\" min=\"1\" max=\"200\" value=\"13\" inputmode=\"numeric\">\n      <div class=\"preset-row\">\n        <button type=\"button\" class=\"preset-btn\" data-count=\"13\">13\u540d<\/button>\n        <button type=\"button\" class=\"preset-btn\" data-count=\"25\">25\u540d<\/button>\n        <button type=\"button\" class=\"preset-btn\" data-count=\"50\">50\u540d<\/button>\n        <button type=\"button\" class=\"preset-btn\" data-count=\"100\">100\u540d<\/button>\n        <button type=\"button\" class=\"preset-btn\" data-count=\"200\">200\u540d<\/button>\n      <\/div>\n      <div class=\"modal-actions\">\n        <button type=\"button\" id=\"setup-cancel-btn\" class=\"modal-action cancel\">\u30ad\u30e3\u30f3\u30bb\u30eb<\/button>\n        <button type=\"button\" id=\"setup-apply-btn\" class=\"modal-action apply\">\u3053\u306e\u4eba\u6570\u3067\u958b\u59cb<\/button>\n      <\/div>\n    <\/div>\n  <\/div>\n\n  <div id=\"reset-modal\" class=\"modal\" role=\"alertdialog\" aria-modal=\"true\" aria-labelledby=\"reset-title\">\n    <div class=\"modal-card\">\n      <h2 id=\"reset-title\">\u672c\u5f53\u306b\u3059\u3079\u3066\u30ea\u30bb\u30c3\u30c8\u3057\u307e\u3059\u304b\uff1f<\/h2>\n      <p>\u672c\u65e5\u306e\u53d7\u691c\u8005\u60c5\u5831\u3001\u8a66\u9a13\u56de\u6570\u3001\u30e1\u30e2\u7528\u7d19\u679a\u6570\u3001\u56de\u53ce\u78ba\u8a8d\u3092\u3059\u3079\u3066\u524a\u9664\u3057\u307e\u3059\u3002\u3053\u306e\u64cd\u4f5c\u306f\u5143\u306b\u623b\u305b\u307e\u305b\u3093\u3002<\/p>\n      <div id=\"reset-warning\" class=\"modal-warning\"><\/div>\n      <div class=\"modal-actions\">\n        <button type=\"button\" id=\"reset-cancel-btn\" class=\"modal-action cancel\">\u6d88\u3055\u306a\u3044<\/button>\n        <button type=\"button\" id=\"reset-confirm-btn\" class=\"modal-action erase\">\u6d88\u3059<\/button>\n      <\/div>\n    <\/div>\n  <\/div>\n\n  <script>\n    (() => {\n      'use strict';\n\n      const STORAGE_KEY = 'examMemoCollectionManagerV1';\n      const BACKUP_KEY = `${STORAGE_KEY}_backup`;\n      const DB_NAME = 'ExamMemoCollectionDB';\n      const DB_VERSION = 1;\n      const STORE_NAME = 'appState';\n      const STATE_ID = 'current';\n      const MAX_CANDIDATES = 200;\n      const MAX_EXAMS = 9;\n      const MAX_PAPERS = 9;\n\n      const elements = {\n        body: document.getElementById('candidate-body'),\n        storageStatus: document.getElementById('storage-status'),\n        eventDate: document.getElementById('event-date'),\n        changeCountBtn: document.getElementById('change-count-btn'),\n        jumpNo: document.getElementById('jump-no'),\n        jumpBtn: document.getElementById('jump-btn'),\n        filterSelect: document.getElementById('filter-select'),\n        listInfo: document.getElementById('list-info'),\n        summaryCandidates: document.getElementById('summary-candidates'),\n        summaryExtraExams: document.getElementById('summary-extra-exams'),\n        summaryPapers: document.getElementById('summary-papers'),\n        summaryCollected: document.getElementById('summary-collected'),\n        summaryUncollected: document.getElementById('summary-uncollected'),\n        setupModal: document.getElementById('setup-modal'),\n        setupTitle: document.getElementById('setup-title'),\n        setupDescription: document.getElementById('setup-description'),\n        countInput: document.getElementById('candidate-count-input'),\n        setupCancelBtn: document.getElementById('setup-cancel-btn'),\n        setupApplyBtn: document.getElementById('setup-apply-btn'),\n        resetAllBtn: document.getElementById('reset-all-btn'),\n        resetModal: document.getElementById('reset-modal'),\n        resetWarning: document.getElementById('reset-warning'),\n        resetCancelBtn: document.getElementById('reset-cancel-btn'),\n        resetConfirmBtn: document.getElementById('reset-confirm-btn')\n      };\n\n      let state = null;\n      let currentFilter = 'all';\n      let setupMode = 'initial';\n      let jumpHighlightNo = null;\n      let dbPromise = null;\n      let saveQueue = Promise.resolve();\n\n      function todayString() {\n        const now = new Date();\n        const year = now.getFullYear();\n        const month = String(now.getMonth() + 1).padStart(2, '0');\n        const day = String(now.getDate()).padStart(2, '0');\n        return `${year}-${month}-${day}`;\n      }\n\n      function defaultSession() {\n        return { papers: 0, collected: false };\n      }\n\n      function defaultCandidate(no) {\n        return { no, sessions: [defaultSession()] };\n      }\n\n      function createState(count) {\n        return {\n          eventDate: todayString(),\n          candidateCount: count,\n          records: Array.from({ length: count }, (_, index) => defaultCandidate(index + 1))\n        };\n      }\n\n      function clamp(value, min, max) {\n        return Math.min(max, Math.max(min, value));\n      }\n\n      function normalizeSession(session) {\n        const papers = clamp(Number(session?.papers) || 0, 0, MAX_PAPERS);\n        return {\n          papers,\n          collected: papers > 0 ? Boolean(session?.collected) : false\n        };\n      }\n\n      function updateStorageStatus(type, message) {\n        if (!elements.storageStatus) return;\n        elements.storageStatus.className = `storage-status ${type || ''}`.trim();\n        elements.storageStatus.textContent = message;\n      }\n\n      function normalizeState(saved) {\n        if (!saved || !Number.isInteger(saved.candidateCount) || saved.candidateCount < 1 || saved.candidateCount > MAX_CANDIDATES || !Array.isArray(saved.records)) {\n          return null;\n        }\n\n        const records = Array.from({ length: saved.candidateCount }, (_, index) => {\n          const raw = saved.records[index];\n          const sessions = Array.isArray(raw?.sessions) && raw.sessions.length > 0\n            ? raw.sessions.slice(0, MAX_EXAMS).map(normalizeSession)\n            : [defaultSession()];\n          return { no: index + 1, sessions };\n        });\n\n        return {\n          eventDate: typeof saved.eventDate === 'string' ? saved.eventDate : todayString(),\n          candidateCount: saved.candidateCount,\n          records\n        };\n      }\n\n      function cloneState(value) {\n        if (typeof structuredClone === 'function') {\n          return structuredClone(value);\n        }\n        return JSON.parse(JSON.stringify(value));\n      }\n\n      function openDatabase() {\n        if (dbPromise) return dbPromise;\n\n        dbPromise = new Promise((resolve, reject) => {\n          if (!('indexedDB' in window)) {\n            reject(new Error('\u3053\u306e\u30d6\u30e9\u30a6\u30b6\u30fc\u306fIndexedDB\u306b\u5bfe\u5fdc\u3057\u3066\u3044\u307e\u305b\u3093\u3002'));\n            return;\n          }\n\n          const request = indexedDB.open(DB_NAME, DB_VERSION);\n\n          request.onupgradeneeded = event => {\n            const database = event.target.result;\n            if (!database.objectStoreNames.contains(STORE_NAME)) {\n              database.createObjectStore(STORE_NAME, { keyPath: 'id' });\n            }\n          };\n\n          request.onsuccess = () => {\n            const database = request.result;\n            database.onversionchange = () => database.close();\n            resolve(database);\n          };\n\n          request.onerror = () => {\n            dbPromise = null;\n            reject(request.error || new Error('IndexedDB\u3092\u958b\u3051\u307e\u305b\u3093\u3067\u3057\u305f\u3002'));\n          };\n\n          request.onblocked = () => {\n            updateStorageStatus('error', 'DB\u66f4\u65b0\u5f85\u3061');\n          };\n        });\n\n        return dbPromise;\n      }\n\n      async function readStateFromDatabase() {\n        const database = await openDatabase();\n        return new Promise((resolve, reject) => {\n          const transaction = database.transaction(STORE_NAME, 'readonly');\n          const request = transaction.objectStore(STORE_NAME).get(STATE_ID);\n\n          request.onsuccess = () => resolve(request.result?.data || null);\n          request.onerror = () => reject(request.error || new Error('\u4fdd\u5b58\u30c7\u30fc\u30bf\u3092\u8aad\u307f\u8fbc\u3081\u307e\u305b\u3093\u3067\u3057\u305f\u3002'));\n          transaction.onerror = () => reject(transaction.error || new Error('DB\u8aad\u8fbc\u51e6\u7406\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002'));\n        });\n      }\n\n      async function writeStateToDatabase(snapshot) {\n        const database = await openDatabase();\n        return new Promise((resolve, reject) => {\n          const transaction = database.transaction(STORE_NAME, 'readwrite');\n          transaction.objectStore(STORE_NAME).put({\n            id: STATE_ID,\n            data: snapshot,\n            updatedAt: new Date().toISOString()\n          });\n\n          transaction.oncomplete = () => resolve();\n          transaction.onerror = () => reject(transaction.error || new Error('DB\u4fdd\u5b58\u51e6\u7406\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002'));\n          transaction.onabort = () => reject(transaction.error || new Error('DB\u4fdd\u5b58\u51e6\u7406\u304c\u4e2d\u65ad\u3055\u308c\u307e\u3057\u305f\u3002'));\n        });\n      }\n\n      async function deleteStateFromDatabase() {\n        const database = await openDatabase();\n        return new Promise((resolve, reject) => {\n          const transaction = database.transaction(STORE_NAME, 'readwrite');\n          transaction.objectStore(STORE_NAME).delete(STATE_ID);\n          transaction.oncomplete = () => resolve();\n          transaction.onerror = () => reject(transaction.error || new Error('DB\u524a\u9664\u51e6\u7406\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002'));\n          transaction.onabort = () => reject(transaction.error || new Error('DB\u524a\u9664\u51e6\u7406\u304c\u4e2d\u65ad\u3055\u308c\u307e\u3057\u305f\u3002'));\n        });\n      }\n\n      function readBackupState() {\n        const keys = [BACKUP_KEY, STORAGE_KEY];\n        for (const key of keys) {\n          try {\n            const raw = localStorage.getItem(key);\n            if (!raw) continue;\n            const normalized = normalizeState(JSON.parse(raw));\n            if (normalized) return normalized;\n          } catch (error) {\n            console.warn(`\u4e88\u5099\u4fdd\u5b58\u30c7\u30fc\u30bf\uff08${key}\uff09\u3092\u8aad\u307f\u8fbc\u3081\u307e\u305b\u3093\u3067\u3057\u305f\u3002`, error);\n          }\n        }\n        return null;\n      }\n\n      async function loadState() {\n        updateStorageStatus('', 'DB\u8aad\u8fbc\u4e2d');\n\n        try {\n          const saved = normalizeState(await readStateFromDatabase());\n          if (saved) {\n            updateStorageStatus('saved', 'DB\u4fdd\u5b58\u6e08\u307f');\n            return saved;\n          }\n        } catch (error) {\n          console.error('IndexedDB\u306e\u8aad\u8fbc\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002', error);\n        }\n\n        const backup = readBackupState();\n        if (backup) {\n          try {\n            await writeStateToDatabase(cloneState(backup));\n            localStorage.setItem(BACKUP_KEY, JSON.stringify(backup));\n            localStorage.removeItem(STORAGE_KEY);\n            updateStorageStatus('saved', 'DB\u3078\u5fa9\u5143\u6e08\u307f');\n          } catch (error) {\n            console.error('\u4e88\u5099\u4fdd\u5b58\u304b\u3089DB\u3078\u306e\u5fa9\u5143\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002', error);\n            updateStorageStatus('error', '\u4e88\u5099\u4fdd\u5b58\u3067\u5fa9\u5143');\n          }\n          return backup;\n        }\n\n        updateStorageStatus('saved', 'DB\u6e96\u5099\u5b8c\u4e86');\n        return null;\n      }\n\n      function saveState() {\n        if (!state) return Promise.resolve();\n\n        const snapshot = cloneState(state);\n        updateStorageStatus('', '\u81ea\u52d5\u4fdd\u5b58\u4e2d');\n\n        try {\n          localStorage.setItem(BACKUP_KEY, JSON.stringify(snapshot));\n        } catch (error) {\n          console.warn('\u4e88\u5099\u4fdd\u5b58\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002', error);\n        }\n\n        saveQueue = saveQueue\n          .catch(() => undefined)\n          .then(() => writeStateToDatabase(snapshot))\n          .then(() => {\n            updateStorageStatus('saved', 'DB\u4fdd\u5b58\u6e08\u307f');\n          })\n          .catch(error => {\n            console.error('IndexedDB\u3078\u306e\u4fdd\u5b58\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002', error);\n            updateStorageStatus('error', '\u4e88\u5099\u4fdd\u5b58\u306e\u307f');\n          });\n\n        return saveQueue;\n      }\n\n      function getCandidate(no) {\n        return state?.records.find(record => record.no === no) || null;\n      }\n\n      function candidateStats(record) {\n        const paperSessions = record.sessions.filter(session => session.papers > 0);\n        const uncollected = paperSessions.filter(session => !session.collected).length;\n        const collected = paperSessions.filter(session => session.collected).length;\n        const papers = record.sessions.reduce((sum, session) => sum + session.papers, 0);\n        return { paperSessions: paperSessions.length, uncollected, collected, papers };\n      }\n\n      function getFilteredRecords() {\n        if (!state) return [];\n        switch (currentFilter) {\n          case 'uncollected':\n            return state.records.filter(record => candidateStats(record).uncollected > 0);\n          case 'extra':\n            return state.records.filter(record => record.sessions.length > 1);\n          case 'paper':\n            return state.records.filter(record => candidateStats(record).papers > 0);\n          case 'complete':\n            return state.records.filter(record => {\n              const stats = candidateStats(record);\n              return stats.paperSessions > 0 && stats.uncollected === 0;\n            });\n          default:\n            return state.records;\n        }\n      }\n\n      function render() {\n        if (!state) return;\n        elements.eventDate.value = state.eventDate;\n        elements.filterSelect.value = currentFilter;\n\n        const records = getFilteredRecords();\n        elements.listInfo.textContent = `${records.length}\u540d\u3092\u8868\u793a\u4e2d\uff08\u5168${state.candidateCount}\u540d\uff09`;\n\n        if (records.length === 0) {\n          elements.body.innerHTML = '<tr><td colspan=\"3\" class=\"empty-message\">\u6761\u4ef6\u306b\u8a72\u5f53\u3059\u308b\u53d7\u691c\u8005\u306f\u3044\u307e\u305b\u3093\u3002<\/td><\/tr>';\n        } else {\n          elements.body.innerHTML = records.map(record => renderCandidateRow(record)).join('');\n        }\n\n        updateSummary();\n        requestAnimationFrame(() => {\n          if (jumpHighlightNo !== null) {\n            const row = elements.body.querySelector(`tr[data-candidate-no=\"${jumpHighlightNo}\"]`);\n            if (row) {\n              row.scrollIntoView({ behavior: 'smooth', block: 'center' });\n              setTimeout(() => row.classList.remove('jump-highlight'), 1500);\n            }\n            jumpHighlightNo = null;\n          }\n        });\n      }\n\n      function renderCandidateRow(record) {\n        const stats = candidateStats(record);\n        const rowClass = stats.uncollected > 0 ? 'uncollected-row' : '';\n        const highlighted = jumpHighlightNo === record.no ? 'jump-highlight' : '';\n        const status = getStatusMarkup(stats);\n\n        const sessionCards = record.sessions.map((session, index) => {\n          const sessionClass = session.papers === 0 ? '' : (session.collected ? 'collected' : 'uncollected');\n          const buttonClass = session.papers === 0 ? 'none' : (session.collected ? 'done' : 'pending');\n          const buttonText = session.papers === 0 ? '\u30e1\u30e2\u306a\u3057' : (session.collected ? '\u2713 \u56de\u53ce\u6e08' : '\u672a\u56de\u53ce');\n          const disabled = session.papers === 0 ? 'disabled' : '';\n          return `\n            <div class=\"session-card ${sessionClass}\">\n              <span class=\"session-no\">\u7b2c${index + 1}<\/span>\n              <div class=\"paper-counter\">\n                <button type=\"button\" class=\"paper-btn minus\" data-action=\"paper-minus\" data-session-index=\"${index}\" ${session.papers <= 0 ? 'disabled' : ''} aria-label=\"\u7b2c${index + 1}\u8a66\u9a13\u306e\u30e1\u30e2\u7528\u7d19\u30921\u679a\u6e1b\u3089\u3059\">\uff0d<\/button>\n                <span class=\"paper-value\">${session.papers}\u679a<\/span>\n                <button type=\"button\" class=\"paper-btn\" data-action=\"paper-plus\" data-session-index=\"${index}\" ${session.papers >= MAX_PAPERS ? 'disabled' : ''} aria-label=\"\u7b2c${index + 1}\u8a66\u9a13\u306e\u30e1\u30e2\u7528\u7d19\u30921\u679a\u5897\u3084\u3059\">\uff0b<\/button>\n              <\/div>\n              <button type=\"button\" class=\"collect-btn ${buttonClass}\" data-action=\"toggle-collected\" data-session-index=\"${index}\" ${disabled}>${buttonText}<\/button>\n            <\/div>\n          `;\n        }).join('');\n\n        return `\n          <tr data-candidate-no=\"${record.no}\" class=\"${rowClass} ${highlighted}\">\n            <td class=\"candidate-cell\">\n              <div class=\"candidate-line\">\n                <span class=\"candidate-no\">No.${record.no}<\/span>\n                <button type=\"button\" class=\"square-btn exam-minus\" data-action=\"exam-minus\" ${record.sessions.length <= 1 ? 'disabled' : ''} aria-label=\"\u53d7\u691c\u8005No.${record.no}\u306e\u6700\u7d42\u8a66\u9a13\u3092\u524a\u9664\">\uff0d<\/button>\n                <span class=\"exam-count\">${record.sessions.length}\u56de<\/span>\n                <button type=\"button\" class=\"square-btn exam-plus\" data-action=\"exam-plus\" ${record.sessions.length >= MAX_EXAMS ? 'disabled' : ''} aria-label=\"\u53d7\u691c\u8005No.${record.no}\u306e\u8a66\u9a13\u3092\u8ffd\u52a0\">\uff0b<\/button>\n              <\/div>\n            <\/td>\n            <td class=\"sessions-cell\"><div class=\"session-list\">${sessionCards}<\/div><\/td>\n            <td class=\"status-cell\">${status}<\/td>\n          <\/tr>\n        `;\n      }\n\n      function getStatusMarkup(stats) {\n        if (stats.uncollected > 0) {\n          return `<span class=\"status-badge pending\">\u672a\u56de\u53ce ${stats.uncollected}\u4ef6<\/span>`;\n        }\n        if (stats.paperSessions > 0) {\n          return '<span class=\"status-badge done\">\u2713 \u3059\u3079\u3066\u56de\u53ce\u6e08<\/span>';\n        }\n        return '<span class=\"status-badge none\">\u30e1\u30e2\u5229\u7528\u306a\u3057<\/span>';\n      }\n\n      function updateSummary() {\n        const totals = state.records.reduce((acc, record) => {\n          const stats = candidateStats(record);\n          acc.extraExams += Math.max(0, record.sessions.length - 1);\n          acc.papers += stats.papers;\n          acc.collected += stats.collected;\n          acc.uncollected += stats.uncollected;\n          return acc;\n        }, { extraExams: 0, papers: 0, collected: 0, uncollected: 0 });\n\n        elements.summaryCandidates.textContent = String(state.candidateCount);\n        elements.summaryExtraExams.textContent = String(totals.extraExams);\n        elements.summaryPapers.textContent = String(totals.papers);\n        elements.summaryCollected.textContent = String(totals.collected);\n        elements.summaryUncollected.textContent = String(totals.uncollected);\n      }\n\n      function updateCandidate(candidateNo, action, sessionIndex) {\n        const record = getCandidate(candidateNo);\n        if (!record) return;\n\n        if (action === 'exam-plus') {\n          if (record.sessions.length >= MAX_EXAMS) return showToast('\u8a66\u9a13\u56de\u6570\u306f9\u56de\u304c\u4e0a\u9650\u3067\u3059\u3002');\n          record.sessions.push(defaultSession());\n          showToast(`\u53d7\u691c\u8005No.${candidateNo}\u306b\u7b2c${record.sessions.length}\u8a66\u9a13\u3092\u8ffd\u52a0\u3057\u307e\u3057\u305f\u3002`);\n        }\n\n        if (action === 'exam-minus') {\n          if (record.sessions.length <= 1) return showToast('\u7b2c1\u8a66\u9a13\u306f\u524a\u9664\u3067\u304d\u307e\u305b\u3093\u3002');\n          const lastSession = record.sessions[record.sessions.length - 1];\n          if (lastSession.papers > 0 && !lastSession.collected) {\n            const ok = window.confirm(`\u7b2c${record.sessions.length}\u8a66\u9a13\u306b\u672a\u56de\u53ce\u306e\u30e1\u30e2\u7528\u7d19\u304c\u3042\u308a\u307e\u3059\u3002\u6700\u7d42\u8a66\u9a13\u3092\u524a\u9664\u3057\u307e\u3059\u304b\uff1f`);\n            if (!ok) return;\n          }\n          record.sessions.pop();\n          showToast(`\u53d7\u691c\u8005No.${candidateNo}\u306e\u6700\u7d42\u8a66\u9a13\u3092\u524a\u9664\u3057\u307e\u3057\u305f\u3002`);\n        }\n\n        if (action === 'paper-plus') {\n          const session = record.sessions[sessionIndex];\n          if (!session || session.papers >= MAX_PAPERS) return;\n          session.papers += 1;\n          session.collected = false;\n        }\n\n        if (action === 'paper-minus') {\n          const session = record.sessions[sessionIndex];\n          if (!session || session.papers <= 0) return;\n          session.papers -= 1;\n          session.collected = false;\n        }\n\n        if (action === 'toggle-collected') {\n          const session = record.sessions[sessionIndex];\n          if (!session || session.papers === 0) return;\n          session.collected = !session.collected;\n        }\n\n        saveState();\n        render();\n      }\n\n      function setCandidateCount(count, resetExisting = false) {\n        const normalized = clamp(Number(count) || 0, 1, MAX_CANDIDATES);\n\n        if (!state || resetExisting) {\n          state = createState(normalized);\n        } else if (normalized > state.candidateCount) {\n          for (let no = state.candidateCount + 1; no <= normalized; no += 1) {\n            state.records.push(defaultCandidate(no));\n          }\n          state.candidateCount = normalized;\n        } else if (normalized < state.candidateCount) {\n          const removed = state.records.slice(normalized);\n          const hasData = removed.some(record => {\n            const stats = candidateStats(record);\n            return record.sessions.length > 1 || stats.papers > 0;\n          });\n          if (hasData) {\n            const ok = window.confirm(`No.${normalized + 1}\u4ee5\u964d\u306b\u5165\u529b\u6e08\u307f\u30c7\u30fc\u30bf\u304c\u3042\u308a\u307e\u3059\u3002\u524a\u9664\u3057\u3066${normalized}\u540d\u306b\u5909\u66f4\u3057\u307e\u3059\u304b\uff1f`);\n            if (!ok) return false;\n          }\n          state.records = state.records.slice(0, normalized);\n          state.candidateCount = normalized;\n        }\n\n        saveState();\n        render();\n        return true;\n      }\n\n      function openSetupModal(mode) {\n        setupMode = mode;\n        const initial = mode === 'initial';\n        elements.setupTitle.textContent = initial ? '\u672c\u65e5\u306e\u53d7\u691c\u8005\u6570' : '\u53d7\u691c\u8005\u6570\u3092\u5909\u66f4';\n        elements.setupDescription.textContent = initial\n          ? '\u5f53\u65e5\u306e\u53d7\u691c\u8005\u6570\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002\u5165\u529b\u3057\u305f\u4eba\u6570\u3092\u3059\u3079\u3066\u7e26\u4e00\u89a7\u3067\u8868\u793a\u3057\u307e\u3059\u3002'\n          : '\u4eba\u6570\u3092\u5897\u3084\u3059\u3068\u53d7\u691c\u8005\u3092\u8ffd\u52a0\u3057\u307e\u3059\u3002\u4eba\u6570\u3092\u6e1b\u3089\u3059\u5834\u5408\u3001\u5bfe\u8c61\u7bc4\u56f2\u306e\u5165\u529b\u30c7\u30fc\u30bf\u306f\u524a\u9664\u3055\u308c\u307e\u3059\u3002';\n        elements.countInput.value = state?.candidateCount || 13;\n        elements.setupCancelBtn.style.display = initial ? 'none' : 'inline-block';\n        elements.setupModal.classList.add('open');\n        setTimeout(() => elements.countInput.focus(), 50);\n      }\n\n      function closeSetupModal() {\n        if (setupMode === 'initial' && !state) return;\n        elements.setupModal.classList.remove('open');\n      }\n\n      function applySetup() {\n        const count = Number(elements.countInput.value);\n        if (!Number.isInteger(count) || count < 1 || count > MAX_CANDIDATES) {\n          return showToast('\u53d7\u691c\u8005\u6570\u306f1\uff5e200\u540d\u3067\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002');\n        }\n        const changed = setCandidateCount(count, setupMode === 'initial');\n        if (changed !== false) elements.setupModal.classList.remove('open');\n      }\n\n      function jumpToCandidate() {\n        if (!state) return;\n        const no = Number(elements.jumpNo.value);\n        if (!Number.isInteger(no) || no < 1 || no > state.candidateCount) {\n          return showToast(`\u53d7\u691c\u8005No.\u306f1\uff5e${state.candidateCount}\u3067\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002`);\n        }\n        currentFilter = 'all';\n        jumpHighlightNo = no;\n        render();\n      }\n\n      function openResetModal() {\n        const uncollected = state.records.reduce((sum, record) => sum + candidateStats(record).uncollected, 0);\n        if (uncollected > 0) {\n          elements.resetWarning.textContent = `\u6ce8\u610f\uff1a\u672a\u56de\u53ce\u306e\u8a66\u9a13\u304c${uncollected}\u4ef6\u6b8b\u3063\u3066\u3044\u307e\u3059\u3002\u56de\u53ce\u78ba\u8a8d\u524d\u306b\u6d88\u3057\u3066\u3088\u3044\u304b\u3001\u5fc5\u305a\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044\u3002`;\n          elements.resetWarning.classList.add('show');\n        } else {\n          elements.resetWarning.textContent = '';\n          elements.resetWarning.classList.remove('show');\n        }\n        elements.resetModal.classList.add('open');\n        setTimeout(() => elements.resetCancelBtn.focus(), 50);\n      }\n\n      async function resetAll() {\n        elements.resetConfirmBtn.disabled = true;\n        elements.resetCancelBtn.disabled = true;\n        updateStorageStatus('', 'DB\u524a\u9664\u4e2d');\n\n        try {\n          await saveQueue.catch(() => undefined);\n          await deleteStateFromDatabase();\n          localStorage.removeItem(BACKUP_KEY);\n          localStorage.removeItem(STORAGE_KEY);\n          state = null;\n          currentFilter = 'all';\n          elements.resetModal.classList.remove('open');\n          updateStorageStatus('saved', 'DB\u30ea\u30bb\u30c3\u30c8\u6e08\u307f');\n          openSetupModal('initial');\n          showToast('\u672c\u65e5\u306e\u30c7\u30fc\u30bf\u3092\u3059\u3079\u3066\u524a\u9664\u3057\u307e\u3057\u305f\u3002');\n        } catch (error) {\n          console.error('\u4fdd\u5b58\u30c7\u30fc\u30bf\u3092\u524a\u9664\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002', error);\n          updateStorageStatus('error', 'DB\u524a\u9664\u5931\u6557');\n          showToast('\u30c7\u30fc\u30bf\u3092\u524a\u9664\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u3082\u3046\u4e00\u5ea6\u304a\u8a66\u3057\u304f\u3060\u3055\u3044\u3002');\n        } finally {\n          elements.resetConfirmBtn.disabled = false;\n          elements.resetCancelBtn.disabled = false;\n        }\n      }\n\n      function showToast(message) {\n        document.querySelectorAll('.toast').forEach(toast => toast.remove());\n        const toast = document.createElement('div');\n        toast.className = 'toast';\n        toast.textContent = message;\n        document.body.appendChild(toast);\n        setTimeout(() => toast.remove(), 2800);\n      }\n\n      elements.body.addEventListener('click', event => {\n        const button = event.target.closest('button[data-action]');\n        if (!button) return;\n        const row = button.closest('tr[data-candidate-no]');\n        if (!row) return;\n        const candidateNo = Number(row.dataset.candidateNo);\n        const sessionIndex = Number(button.dataset.sessionIndex);\n        updateCandidate(candidateNo, button.dataset.action, sessionIndex);\n      });\n\n      elements.eventDate.addEventListener('change', () => {\n        if (!state) return;\n        state.eventDate = elements.eventDate.value || todayString();\n        saveState();\n      });\n\n      elements.changeCountBtn.addEventListener('click', () => openSetupModal('resize'));\n      elements.setupCancelBtn.addEventListener('click', closeSetupModal);\n      elements.setupApplyBtn.addEventListener('click', applySetup);\n      elements.jumpBtn.addEventListener('click', jumpToCandidate);\n      elements.jumpNo.addEventListener('keydown', event => {\n        if (event.key === 'Enter') jumpToCandidate();\n      });\n      elements.filterSelect.addEventListener('change', () => {\n        currentFilter = elements.filterSelect.value;\n        render();\n      });\n      elements.resetAllBtn.addEventListener('click', openResetModal);\n      elements.resetCancelBtn.addEventListener('click', () => elements.resetModal.classList.remove('open'));\n      elements.resetConfirmBtn.addEventListener('click', resetAll);\n\n      document.querySelectorAll('.preset-btn').forEach(button => {\n        button.addEventListener('click', () => {\n          elements.countInput.value = button.dataset.count;\n        });\n      });\n\n      document.addEventListener('keydown', event => {\n        if (event.key !== 'Escape') return;\n        if (elements.resetModal.classList.contains('open')) {\n          elements.resetModal.classList.remove('open');\n        } else if (elements.setupModal.classList.contains('open')) {\n          closeSetupModal();\n        }\n      });\n\n      document.addEventListener('visibilitychange', () => {\n        if (document.visibilityState === 'hidden' && state) {\n          saveState();\n        }\n      });\n\n      window.addEventListener('pagehide', () => {\n        if (state) saveState();\n      });\n\n      async function initializeApp() {\n        state = await loadState();\n        if (state) {\n          render();\n        } else {\n          openSetupModal('initial');\n        }\n      }\n\n      initializeApp().catch(error => {\n        console.error('\u30a2\u30d7\u30ea\u306e\u521d\u671f\u5316\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002', error);\n        updateStorageStatus('error', '\u521d\u671f\u5316\u5931\u6557');\n        state = readBackupState();\n        if (state) {\n          render();\n          showToast('DB\u3092\u958b\u3051\u306a\u304b\u3063\u305f\u305f\u3081\u3001\u4e88\u5099\u4fdd\u5b58\u30c7\u30fc\u30bf\u3092\u8868\u793a\u3057\u3066\u3044\u307e\u3059\u3002');\n        } else {\n          openSetupModal('initial');\n        }\n      });\n    })();\n  <\/script>\n<\/body>\n<\/html>\n","protected":false},"excerpt":{"rendered":"<p>\u53d7\u691c\u8005\u30fb\u8a66\u9a13\u5225\u30e1\u30e2\u56de\u53ce\u7ba1\u7406 \u53d7\u691c\u8005\u30fb\u8a66\u9a13\u5225\u30e1\u30e2\u56de\u53ce\u7ba1\u7406 \u5404\u53d7\u691c\u8005\u306e\u7b2c1\u8a66\u9a13\u30fb\u7b2c2\u8a66\u9a13\u3054\u3068\u306b\u3001\u30e1\u30e2\u7528\u7d19\u306e\u914d\u5e03\u679a\u6570\u3068\u56de\u53ce\u72b6\u6cc1\u3092\u78ba\u8a8d\u3057\u307e\u3059\u3002 DB\u8aad\u8fbc\u4e2d \u53d7\u691c\u8005\u6570\u3092\u5909\u66f4 \u53d7\u691c\u8005\u6570 0\u540d \u8ffd\u52a0\u8a66\u9a13 0\u56de \u30e1\u30e2\u7528\u7d19\u914d\u5e03 0\u679a \u56de\u53ce\u2026<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"templates\/page-no-sidebar.php","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-5798","post","type-post","status-publish","format-standard","hentry","category-1"],"featured_image_url":null,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/nk-ts.net\/index.php?rest_route=\/wp\/v2\/posts\/5798","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nk-ts.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nk-ts.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nk-ts.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nk-ts.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=5798"}],"version-history":[{"count":1,"href":"https:\/\/nk-ts.net\/index.php?rest_route=\/wp\/v2\/posts\/5798\/revisions"}],"predecessor-version":[{"id":5799,"href":"https:\/\/nk-ts.net\/index.php?rest_route=\/wp\/v2\/posts\/5798\/revisions\/5799"}],"wp:attachment":[{"href":"https:\/\/nk-ts.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=5798"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nk-ts.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=5798"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nk-ts.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=5798"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}