.related-articles-slider{padding:3rem 0;background:linear-gradient(180deg,#fffaf3 0%,#fff 100%);border-top:1px solid #eadfce;overflow:hidden}
.related-articles-slider__inner{position:relative}
.related-articles-slider__header{display:flex;align-items:flex-end;justify-content:space-between;gap:1rem;margin-bottom:1.25rem}
.related-articles-slider__title{position:relative;margin:0;padding-left:.85rem;font-size:1.35rem;font-weight:900;line-height:1.45;color:#17324d}
.related-articles-slider__title::before{content:'';position:absolute;left:0;top:.18em;width:4px;height:1.65em;border-radius:999px;background:linear-gradient(180deg,#167044,#f2a65a)}
.related-articles-slider__all{display:inline-flex;align-items:center;gap:.25rem;min-height:44px;padding:.25rem .15rem;font-size:13px;font-weight:900;color:#167044;white-space:nowrap;text-decoration:none}
.related-articles-slider__all:hover,.related-articles-slider__all:focus-visible{text-decoration:underline;text-underline-offset:4px;outline:2px solid rgba(22,112,68,.25);outline-offset:4px;border-radius:6px}
.related-articles-slider__viewport{position:relative;max-width:100%;overflow:hidden}
.related-articles-slider__track{--related-card-size:clamp(260px,31%,320px);display:flex;gap:18px;overflow-x:auto;overflow-y:hidden;scroll-snap-type:x mandatory;scroll-behavior:smooth;scroll-padding-inline:2.75rem;padding:.25rem 2.75rem 1rem;-webkit-overflow-scrolling:touch;scrollbar-width:none;cursor:grab;touch-action:pan-x pan-y}
.related-articles-slider__track::-webkit-scrollbar{display:none}
.related-articles-slider__track::after{content:'';flex:0 0 max(0px,calc(100% - var(--related-card-size)))}
.related-articles-slider__track.is-dragging{cursor:grabbing;scroll-snap-type:none;user-select:none}
.related-articles-slider__track:focus-visible{outline:3px solid rgba(22,112,68,.28);outline-offset:4px;border-radius:14px}
.related-articles-slider__card{flex:0 0 var(--related-card-size);display:flex;flex-direction:column;min-height:312px;background:#fff;border:1px solid #e2ded6;border-radius:12px;overflow:hidden;box-shadow:0 8px 22px rgba(23,50,77,.08);scroll-snap-align:start;text-decoration:none;color:inherit;transition:transform .2s ease,border-color .2s ease,box-shadow .2s ease}
.related-articles-slider__card:hover,.related-articles-slider__card:focus-visible{transform:translateY(-3px);border-color:#f2a65a;box-shadow:0 14px 28px rgba(23,50,77,.12);outline:none}
.related-articles-slider__thumb{display:block;aspect-ratio:16/9;background:#f5f0e8;overflow:hidden}
.related-articles-slider__thumb img{width:100%;height:100%;object-fit:cover;transition:transform .25s ease}
.related-articles-slider__card:hover .related-articles-slider__thumb img,.related-articles-slider__card:focus-visible .related-articles-slider__thumb img{transform:scale(1.035)}
.related-articles-slider__body{display:flex;flex-direction:column;gap:.55rem;padding:.9rem .95rem 1rem;min-height:0}
.related-articles-slider__meta{display:flex;align-items:center;justify-content:space-between;gap:.5rem}
.related-articles-slider__category{display:inline-flex;align-items:center;border-radius:999px;background:#eef7f0;color:#167044;font-size:11px;font-weight:900;line-height:1;padding:.32rem .55rem;max-width:56%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.related-articles-slider__date{font-size:11px;font-weight:700;color:#7b8794;white-space:nowrap}
.related-articles-slider__card-title{display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;font-size:.94rem;font-weight:900;line-height:1.58;color:#17324d}
.related-articles-slider__arrow{position:absolute;top:50%;z-index:2;display:grid;place-items:center;width:44px;height:44px;border:1px solid #e2ded6;border-radius:999px;background:rgba(255,255,255,.96);box-shadow:0 8px 18px rgba(23,50,77,.14);color:#167044;cursor:pointer;transform:translateY(-55%);transition:background .2s ease,border-color .2s ease,box-shadow .2s ease,opacity .2s ease}
.related-articles-slider__arrow:hover,.related-articles-slider__arrow:focus-visible{background:#fff7ec;border-color:#f2a65a;box-shadow:0 10px 22px rgba(23,50,77,.18);outline:2px solid rgba(242,166,90,.35);outline-offset:3px}
.related-articles-slider__arrow[disabled]{opacity:0;pointer-events:none}
.related-articles-slider__arrow--prev{left:.35rem}
.related-articles-slider__arrow--next{right:.35rem}
.related-articles-slider__footer{display:grid;gap:.7rem;justify-items:center;margin-top:.25rem}
.related-articles-slider__dots{display:flex;align-items:center;justify-content:center;gap:.48rem;min-height:20px}
.related-articles-slider__dot{width:8px;height:8px;border:0;border-radius:999px;background:#d8d8d8;cursor:pointer;padding:0;transition:width .2s ease,background .2s ease}
.related-articles-slider__dot[aria-current="true"]{width:18px;background:#167044}
.related-articles-slider__dot:focus-visible{outline:2px solid rgba(22,112,68,.35);outline-offset:4px}
.related-articles-slider__hint{display:none;align-items:center;gap:.45rem;margin:0;font-size:12px;font-weight:900;color:#65758a;line-height:1.4}
.related-articles-slider__hint svg{width:16px;height:16px;color:#f2a65a;flex:0 0 auto}
@media(min-width:1200px){.related-articles-slider__track{--related-card-size:calc((100% - 36px)/3)}}
@media(min-width:768px) and (max-width:1199px){.related-articles-slider__track{--related-card-size:calc((100% - 18px)/2)}}
@media(max-width:767px){.related-articles-slider{padding:2.35rem 0}.related-articles-slider__header{align-items:flex-start;margin-bottom:.85rem}.related-articles-slider__title{font-size:1.08rem;line-height:1.55}.related-articles-slider__all{font-size:12px;min-height:38px}.related-articles-slider__viewport{margin-right:-1rem}.related-articles-slider__track{--related-card-size:min(82vw,330px);gap:13px;padding:.2rem 1rem .85rem .05rem;scroll-padding-inline:.05rem}.related-articles-slider__card{min-height:268px;border-radius:11px}.related-articles-slider__body{padding:.75rem .8rem .85rem;gap:.45rem}.related-articles-slider__category{font-size:10px;padding:.28rem .5rem}.related-articles-slider__date{font-size:10px}.related-articles-slider__card-title{font-size:.86rem;line-height:1.55;-webkit-line-clamp:3}.related-articles-slider__arrow{display:none}.related-articles-slider__hint{display:inline-flex}.related-articles-slider__dot{width:7px;height:7px}.related-articles-slider__dot[aria-current="true"]{width:16px}}
@media(max-width:420px){.related-articles-slider__header{display:grid;gap:.4rem}.related-articles-slider__all{justify-self:start}.related-articles-slider__track{--related-card-size:83vw}}
@media(prefers-reduced-motion:reduce){.related-articles-slider__track{scroll-behavior:auto}.related-articles-slider__card,.related-articles-slider__thumb img,.related-articles-slider__dot,.related-articles-slider__arrow{transition:none}}
.related-articles{padding:3.25rem 1rem;background:#f8fbff;border-top:1px solid #dbeafe}
.related-articles__eyebrow{text-align:center;font-size:13px;font-weight:900;color:#2563eb;letter-spacing:.08em;margin-bottom:.75rem}
.related-articles__title{text-align:center;font-size:1.5rem;font-weight:900;color:#1e3a8a;margin-bottom:.75rem}
.related-articles__lead{text-align:center;font-size:14px;font-weight:700;color:#475569;line-height:1.9;margin:0 auto 2rem;max-width:42rem}
.related-articles__grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:1rem}
.related-article-card{display:flex;flex-direction:column;gap:.75rem;background:#fff;border:1px solid #dbeafe;border-radius:8px;padding:1.25rem;text-decoration:none;box-shadow:0 2px 10px rgba(37,99,235,.06);transition:transform .2s,border-color .2s,box-shadow .2s}
.related-article-card:hover,.related-article-card:focus-visible{transform:translateY(-2px);border-color:#93c5fd;box-shadow:0 10px 20px rgba(37,99,235,.12);outline:none}
.related-article-card__meta{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem}
.related-article-card__pill{display:inline-flex;align-items:center;border-radius:9999px;background:#eff6ff;color:#2563eb;font-size:11px;font-weight:900;padding:.25rem .625rem}
.related-article-card__time{font-size:11px;font-weight:700;color:#64748b}
.related-article-card__title{font-size:1rem;font-weight:900;color:#1e3a8a;line-height:1.5}
.related-article-card__desc{font-size:13px;font-weight:700;color:#475569;line-height:1.8}
.related-article-card__link{display:inline-flex;align-items:center;gap:.35rem;font-size:13px;font-weight:900;color:#2563eb}
.related-symptoms{padding:3.25rem 1rem;background:#fff;border-top:1px solid #dfe4dc}
.related-symptoms__eyebrow{text-align:center;font-size:12px;font-weight:900;color:#356b2f;letter-spacing:.1em;margin:0 0 .7rem}
.related-symptoms__title{text-align:center;font-size:1.45rem;font-weight:900;color:#223b2d;line-height:1.55;margin:0 0 .75rem}
.related-symptoms__lead{text-align:center;font-size:14px;font-weight:700;color:#59635d;line-height:1.9;margin:0 auto 2rem;max-width:42rem}
.related-symptoms__grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:.9rem}
.related-symptom-card{position:relative;display:flex;flex-direction:column;gap:.55rem;min-height:118px;background:#fff;border:1px solid #dfe4dc;border-radius:8px;padding:1rem 3.25rem 1rem 1rem;text-decoration:none;transition:transform .2s,border-color .2s,background .2s,box-shadow .2s}
.related-symptom-card:hover,.related-symptom-card:focus-visible{transform:translateY(-2px);background:#fafcf8;border-color:#9bb596;box-shadow:0 8px 18px rgba(35,77,36,.09);outline:3px solid rgba(53,107,47,.16);outline-offset:2px}
.related-symptom-card__label{font-size:1rem;font-weight:900;color:#234d24;line-height:1.5}
.related-symptom-card__description{font-size:13px;font-weight:700;color:#59635d;line-height:1.75}
.related-symptom-card__arrow{position:absolute;right:1rem;top:50%;transform:translateY(-50%);width:34px;height:34px;border-radius:50%;display:grid;place-items:center;background:#f6f9f3;border:1px solid #cbd8c6;color:#356b2f;font-size:22px;font-weight:900;line-height:1;transition:background .2s ease,color .2s ease,border-color .2s ease,transform .2s ease}
.related-symptom-card:hover .related-symptom-card__arrow,.related-symptom-card:focus-visible .related-symptom-card__arrow{background:#356b2f;border-color:#356b2f;color:#fff;transform:translateY(-50%) translateX(2px)}
.related-symptoms__all{display:flex;justify-content:center;margin-top:1.35rem}
.related-symptoms__all-link{display:inline-flex;align-items:center;justify-content:center;gap:.45rem;min-height:44px;border-bottom:1px solid #8aa384;color:#234d24;font-size:14px;font-weight:900;text-decoration:none}
.related-symptoms__all-link:hover,.related-symptoms__all-link:focus-visible{color:#356b2f;border-color:#356b2f;outline:3px solid rgba(53,107,47,.16);outline-offset:5px}
@media(max-width:640px){.related-symptoms{padding:2.75rem 1rem}.related-symptoms__grid{grid-template-columns:1fr}.related-symptom-card{min-height:104px;padding-right:3rem}.related-symptom-card__arrow{right:.85rem;width:30px;height:30px;font-size:20px}}
.symptom-mid-cta{padding:2.75rem 1rem;background:#fff;border-top:1px solid #e2e8f0;border-bottom:1px solid #e2e8f0}
.symptom-mid-cta__inner{display:grid;gap:1.25rem;align-items:center;background:#f8fbff;border:1px solid #bfdbfe;border-radius:8px;padding:1.5rem}
.symptom-mid-cta__eyebrow{font-size:12px;font-weight:900;color:#2563eb;letter-spacing:.08em;margin:0 0 .5rem}
.symptom-mid-cta__title{font-size:1.25rem;font-weight:900;color:#1e3a8a;line-height:1.55;margin:0 0 .5rem}
.symptom-mid-cta__text{font-size:14px;font-weight:700;color:#475569;line-height:1.9;margin:0}
.symptom-mid-cta__actions{display:flex;flex-wrap:wrap;gap:.75rem}
.symptom-mid-cta__btn{display:inline-flex;align-items:center;justify-content:center;gap:.4rem;border-radius:8px;padding:.85rem 1.15rem;font-size:14px;font-weight:900;text-decoration:none;transition:transform .2s,background .2s,border-color .2s}
.symptom-mid-cta__btn--line{background:#06C755;color:#fff}
.symptom-mid-cta__btn--tel{background:#fff;color:#1e3a8a;border:1px solid #bfdbfe}
.symptom-mid-cta__btn:hover,.symptom-mid-cta__btn:focus-visible{transform:translateY(-1px);outline:2px solid #93c5fd;outline-offset:3px}
.symptom-voices{padding:3.25rem 1rem;background:#f8fafc;border-top:1px solid #e2e8f0}
.symptom-voices__eyebrow{text-align:center;font-size:12px;font-weight:900;color:#2563eb;letter-spacing:.1em;margin:0 0 .7rem}
.symptom-voices__title{text-align:center;font-size:1.45rem;font-weight:900;color:#1e3a8a;line-height:1.55;margin:0 0 .75rem}
.symptom-voices__lead{text-align:center;font-size:14px;font-weight:700;color:#475569;line-height:1.9;margin:0 auto 2rem;max-width:42rem}
.symptom-voices__grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,320px),600px));justify-content:center;gap:2rem}
.symptom-voice-card{background:#fff;border:1px solid #dbeafe;border-radius:8px;overflow:hidden;box-shadow:0 16px 36px rgba(15,23,42,.09)}
.symptom-voice-card__image-link{display:block;background:#f1f5f9}
.symptom-voice-card__image{display:block;width:100%;height:auto}
.symptom-voice-card__body{padding:1.25rem}
.symptom-voice-card__label{font-size:11px;font-weight:900;color:#2563eb;letter-spacing:.08em;margin:0 0 .5rem}
.symptom-voice-card__rows{display:grid;gap:.75rem;margin:.85rem 0 0}
.symptom-voice-card__row{display:grid;gap:.3rem;border-top:1px solid #e2e8f0;padding-top:.75rem}
.symptom-voice-card__key{font-size:12px;font-weight:900;color:#2563eb;letter-spacing:.08em}
.symptom-voice-card__value{font-size:14px;font-weight:700;color:#334155;line-height:1.8}
.symptom-voices__note{font-size:11px;font-weight:700;color:#64748b;line-height:1.8;text-align:right;margin:1rem 0 0}
.symptom-footer{background:#0f172a;color:#cbd5e1;padding:3rem 1rem 2rem;text-align:center}
.symptom-footer__inner{max-width:860px;margin:0 auto}
.symptom-footer__logo{display:inline-block;background:#fff;border-radius:8px;padding:.7rem 1.35rem;margin-bottom:.8rem}
.symptom-footer__logo span{font-size:1.2rem;font-weight:900;color:#1e293b}
.symptom-footer__tagline{font-size:14px;font-weight:700;line-height:1.8;margin:0 0 1.4rem}
.symptom-footer__links{display:flex;flex-wrap:wrap;justify-content:center;gap:.65rem 1rem;list-style:none;margin:0 0 1.4rem;padding:0}
.symptom-footer__links a{font-size:13px;font-weight:700;color:#94a3b8;text-decoration:none;transition:color .2s}
.symptom-footer__links a:hover,.symptom-footer__links a:focus-visible{color:#60a5fa;outline:none;text-decoration:underline;text-underline-offset:4px}
.symptom-footer__note{font-size:10px;color:#64748b;font-weight:700;line-height:2;margin:0}
@media(min-width:768px){.related-articles__title{font-size:1.75rem}}
@media(min-width:768px){.symptom-mid-cta__inner{grid-template-columns:minmax(0,1fr) auto;padding:1.75rem 2rem}.symptom-mid-cta__title{font-size:1.45rem}}
@media(max-width:640px){.symptom-mid-cta__actions{flex-direction:column}.symptom-mid-cta__btn{width:100%}.symptom-voices__grid{gap:1rem}.symptom-voice-card__body{padding:1rem}.symptom-voices__note{text-align:left}}
`.trim();

const relatedArticleSliderScript = `
  <!-- RELATED_ARTICLES_SLIDER_SCRIPT_START -->
  <script>
    (() => {
      const slider = document.querySelector('[data-related-article-slider]');
      if (!slider) return;

      const track = slider.querySelector('[data-related-track]');
      const prev = slider.querySelector('[data-related-prev]');
      const next = slider.querySelector('[data-related-next]');
      const dotsRoot = slider.querySelector('[data-related-dots]');
      const cards = Array.from(slider.querySelectorAll('.related-articles-slider__card'));
      const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
      if (!track || !cards.length) return;

      const getCardStep = () => {
        const first = cards[0];
        const second = cards[1];
        if (!first) return track.clientWidth;
        if (second) return second.offsetLeft - first.offsetLeft;
        return first.getBoundingClientRect().width;
      };

      const getActiveIndex = () => {
        const target = track.scrollLeft;
        let activeIndex = 0;
        let closest = Number.POSITIVE_INFINITY;
        cards.forEach((card, index) => {
          const distance = Math.abs(card.offsetLeft - cards[0].offsetLeft - target);
          if (distance < closest) {
            closest = distance;
            activeIndex = index;
          }
        });
        return activeIndex;
      };

      const scrollToCard = (index) => {
        const card = cards[Math.max(0, Math.min(index, cards.length - 1))];
        if (!card) return;
        track.scrollTo({
          left: card.offsetLeft - cards[0].offsetLeft,
          behavior: reducedMotion ? 'auto' : 'smooth',
        });
      };

      const dots = cards.map((_, index) => {
        const dot = document.createElement('button');
        dot.type = 'button';
        dot.className = 'related-articles-slider__dot';
        dot.setAttribute('aria-label', String(index + 1) + '番目の記事へ移動');
        dot.addEventListener('click', () => scrollToCard(index));
        dotsRoot?.appendChild(dot);
        return dot;
      });

      const updateControls = () => {
        const maxScroll = Math.max(0, track.scrollWidth - track.clientWidth - 2);
        const hasOverflow = maxScroll > 1;
        const activeIndex = getActiveIndex();

        if (prev) {
          prev.disabled = !hasOverflow || track.scrollLeft <= 2;
          prev.hidden = !hasOverflow;
        }
        if (next) {
          next.disabled = !hasOverflow || track.scrollLeft >= maxScroll;
          next.hidden = !hasOverflow;
        }
        if (dotsRoot) dotsRoot.hidden = !hasOverflow || cards.length < 2;
        dots.forEach((dot, index) => {
          dot.setAttribute('aria-current', index === activeIndex ? 'true' : 'false');
        });
      };

      let scrollFrame = 0;
      track.addEventListener('scroll', () => {
        window.cancelAnimationFrame(scrollFrame);
        scrollFrame = window.requestAnimationFrame(updateControls);
      }, { passive: true });

      prev?.addEventListener('click', () => {
        track.scrollBy({ left: -getCardStep(), behavior: reducedMotion ? 'auto' : 'smooth' });
      });
      next?.addEventListener('click', () => {
        track.scrollBy({ left: getCardStep(), behavior: reducedMotion ? 'auto' : 'smooth' });
      });

      track.addEventListener('keydown', (event) => {
        if (event.key !== 'ArrowLeft' && event.key !== 'ArrowRight') return;
        event.preventDefault();
        const direction = event.key === 'ArrowRight' ? 1 : -1;
        track.scrollBy({ left: direction * getCardStep(), behavior: reducedMotion ? 'auto' : 'smooth' });
      });

      let isDragging = false;
      let dragStartX = 0;
      let dragStartScroll = 0;
      let suppressClick = false;

      track.addEventListener('pointerdown', (event) => {
        if (event.pointerType === 'touch' || event.button !== 0) return;
        isDragging = true;
        suppressClick = false;
        dragStartX = event.clientX;
        dragStartScroll = track.scrollLeft;
        track.classList.add('is-dragging');
        track.setPointerCapture(event.pointerId);
      });

      track.addEventListener('pointermove', (event) => {
        if (!isDragging) return;
        const delta = event.clientX - dragStartX;
        if (Math.abs(delta) > 6) suppressClick = true;
        track.scrollLeft = dragStartScroll - delta;
      });

      const stopDragging = (event) => {
        if (!isDragging) return;
        isDragging = false;
        track.classList.remove('is-dragging');
        if (event.pointerId && track.hasPointerCapture(event.pointerId)) {
          track.releasePointerCapture(event.pointerId);
        }
        window.setTimeout(() => {
          suppressClick = false;
        }, 0);
      };

      track.addEventListener('pointerup', stopDragging);
      track.addEventListener('pointercancel', stopDragging);
      track.addEventListener('pointerleave', stopDragging);
      track.addEventListener('click', (event) => {
        if (!suppressClick) return;
        event.preventDefault();
        event.stopPropagation();
      }, true);

      window.addEventListener('resize', updateControls);
      updateControls();
    })();
  </script>
  <!-- RELATED_ARTICLES_SLIDER_SCRIPT_END -->
`.trim();

export async function buildBlog() {
  const [rawData, indexTemplate, postTemplate] = await Promise.all([
    fs.readFile(dataPath, "utf8"),
    fs.readFile(path.join(templatesDir, "blog-index-template.html"), "utf8"),
    fs.readFile(path.join(templatesDir, "blog-post-template.html"), "utf8")
  ]);

  const blogData = JSON.parse(rawData);
  validateBlogData(blogData);

  const categoryMap = new Map(blogData.categories.map((category) => [category.slug, category]));
  const posts = [...blogData.posts]
    .map((post) => normalizePost(post, blogData.site, categoryMap))
    .sort((a, b) => b.date.localeCompare(a.date));

  const indexHtml = renderTemplate(indexTemplate, {
    SEO_HEAD: buildIndexSeo(blogData.site),
    CSS_PATH: "assets/blog.css",
    HOME_PATH: "/",
    BLOG_PATH: "./",
    ACCESS_PATH: "/access.html",
    CONTACT_PATH: "/#access",
    PHONE: blogData.site.phone,
    PHONE_HREF: `tel:${blogData.site.phone.replace(/-/g, "")}`,
    SITE_NAME: blogData.site.name,
    SITE_SUBTITLE: blogData.site.subtitle,
    PAGE_CONTENT: buildIndexContent(blogData.site, posts, categoryMap)
  });

  await replaceDirectoryAtomically(postsDir, async (stagingDir) => {
    await fs.writeFile(path.join(stagingDir, ".gitkeep"), "", "utf8");

    for (const post of posts) {
      const postDir = path.join(stagingDir, post.slug);
      await fs.mkdir(postDir, { recursive: true });
      const relatedPosts = posts.filter((item) => item.slug !== post.slug && item.category.slug === post.category.slug).slice(0, 2);
      const postHtml = renderTemplate(postTemplate, {
        SEO_HEAD: buildPostSeo(blogData.site, post),
        CSS_PATH: "../../assets/blog.css",
        HOME_PATH: "/",
        BLOG_PATH: "../../",
        ACCESS_PATH: "/access.html",
        CONTACT_PATH: "/#access",
        PHONE: blogData.site.phone,
        PHONE_HREF: `tel:${blogData.site.phone.replace(/-/g, "")}`,
        SITE_NAME: blogData.site.name,
        SITE_SUBTITLE: blogData.site.subtitle,
        PAGE_CONTENT: buildPostContent(blogData.site, post, relatedPosts)
      });
      await fs.writeFile(path.join(postDir, "index.html"), cleanGeneratedText(postHtml), "utf8");
    }
  });

  await fs.writeFile(path.join(blogDir, "index.html"), cleanGeneratedText(indexHtml), "utf8");

  await updateSymptomPages(blogData.site, posts);
  await updateSymptomsDirectoryPage();

  await fs.writeFile(path.join(rootDir, "blog.html"), cleanGeneratedText(buildBlogRedirectHtml()), "utf8");
  await fs.writeFile(path.join(rootDir, "blog-detail.html"), cleanGeneratedText(buildLegacyDetailRedirectHtml()), "utf8");
  await updateSitemap(blogData.site, posts);

  console.log(`Generated ${posts.length} static blog post(s), updated symptom related articles, and regenerated sitemap.xml.`);
}

export async function replaceDirectoryAtomically(targetDir, populateDirectory) {
  const parentDir = path.dirname(targetDir);
  const dirName = path.basename(targetDir);
  const nonce = `${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2, 10)}`;
  const stagingDir = path.join(parentDir, `${dirName}.__staging__${nonce}`);
  const backupDir = path.join(parentDir, `${dirName}.__backup__${nonce}`);
  let backupCreated = false;

  await fs.mkdir(parentDir, { recursive: true });

  try {
    await fs.mkdir(stagingDir, { recursive: true });
    await populateDirectory(stagingDir);

    try {
      await fs.rename(targetDir, backupDir);
      backupCreated = true;
    } catch (error) {
      if (error?.code !== "ENOENT") throw error;
    }

    try {
      await fs.rename(stagingDir, targetDir);
    } catch (error) {
      if (backupCreated) {
        try {
          await fs.rename(backupDir, targetDir);
          backupCreated = false;
        } catch {
          // Preserve the backup directory on disk if rollback fails.
        }
      }
      throw error;
    }

    if (backupCreated) {
      await fs.rm(backupDir, { recursive: true, force: true });
      backupCreated = false;
    }
  } catch (error) {
    await fs.rm(stagingDir, { recursive: true, force: true }).catch(() => {});
    throw error;
  }
}

async function updateSymptomPages(site, posts) {
  const symptomFiles = await fs.readdir(symptomsDir);
  for (const fileName of symptomFiles) {
    if (!fileName.endsWith(".html")) continue;
    const baseConfig = symptomConfigs[fileName];
    const config = baseConfig ? { ...baseConfig, fileName } : null;
    if (!config) continue;

    const fullPath = path.join(symptomsDir, fileName);
    let html = await fs.readFile(fullPath, "utf8");
    html = upsertRelatedStyles(html);
    html = upsertDetailedSymptomContent(html, config);
    html = upsertSymptomPatientVoices(html, config);
    html = upsertSymptomMidCta(html, site);
    if (NOINDEX_SYMPTOM_FILES.has(fileName)) {
      html = ensureNoindexFollow(html);
    }

    const relatedPostLimit = isRelatedArticleSliderPage(fileName) ? 5 : 4;
    const matchedPosts = selectRelatedPosts(config, posts).slice(0, relatedPostLimit);
    const sectionHtml = matchedPosts.length ? buildRelatedArticlesSection(site, config, matchedPosts) : "";
    html = replaceRelatedSection(html, sectionHtml);
    html = upsertRelatedArticleSliderScript(html, config);
    html = normalizeSymptomPageDesign(html, site, config);

    await fs.writeFile(fullPath, cleanGeneratedText(html), "utf8");
  }
}

const symptomsDirectoryStyles = `
    *, *::before, *::after { box-sizing: border-box; }
    body { margin: 0; font-family: "BIZ UDPGothic", "Noto Sans JP", system-ui, sans-serif; line-height: 1.8; color: #263b34; background: #fff; }
    a { color: inherit; }
    .page { min-height: 100vh; padding: 88px 18px 72px; background: #fff; }
    .symptom-directory-hero { width: min(960px, 100%); margin: 0 auto; padding: clamp(34px, 6vw, 64px) 0 clamp(48px, 7vw, 76px); border-bottom: 1px solid #dfe4dc; }
    .symptom-directory-hero__label { margin: 0 0 12px; color: #356b2f; font-size: .82rem; font-weight: 900; letter-spacing: .08em; }
    .symptom-directory-hero h1 { position: relative; margin: 0 0 26px; padding-bottom: 18px; color: #223b2d; font-size: clamp(2rem, 5vw, 3.2rem); line-height: 1.35; letter-spacing: 0; }
    .symptom-directory-hero h1::after { content: ""; position: absolute; left: 0; bottom: 0; width: 52px; height: 3px; background: #356b2f; }
    .symptom-directory-hero__lead { max-width: 720px; margin: 0; color: #59635d; font-size: clamp(1rem, 2vw, 1.12rem); font-weight: 700; line-height: 1.9; }
    .symptom-directory-hero__actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 28px; }
    .symptom-directory-hero__button { display: inline-flex; align-items: center; justify-content: center; min-height: 46px; padding: 11px 18px; border: 1px solid #356b2f; border-radius: 8px; background: #356b2f; color: #fff; font-size: .94rem; font-weight: 900; text-decoration: none; }
    .symptom-directory-hero__button--secondary { background: #fff; color: #234d24; }
    .symptom-directory-hero__button:hover, .symptom-directory-hero__button:focus-visible { outline: 3px solid rgba(53,107,47,.18); outline-offset: 3px; }
    .symptom-directory { width: min(960px, 100%); margin: 0 auto; padding: clamp(58px, 8vw, 92px) 0 0; }
    .symptom-directory__heading { margin-bottom: clamp(34px, 5vw, 52px); }
    .symptom-directory__heading h2 { position: relative; margin: 0 0 18px; padding-bottom: 15px; color: #223b2d; font-size: clamp(1.65rem, 3vw, 2.2rem); line-height: 1.45; letter-spacing: 0; }
    .symptom-directory__heading h2::after { content: ""; position: absolute; left: 0; bottom: 0; width: 46px; height: 3px; background: #356b2f; }
    .symptom-directory__heading p { margin: 0; color: #59635d; font-size: .98rem; font-weight: 700; line-height: 1.85; }
    .symptom-directory__groups { columns: 2; column-gap: clamp(44px, 6vw, 72px); }
    .symptom-directory__group { display: inline-block; width: 100%; min-width: 0; margin-bottom: 34px; padding: 34px 0 6px; border-top: 1px solid #dfe4dc; break-inside: avoid; }
    .symptom-directory__group-header { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 14px; align-items: start; margin-bottom: 19px; }
    .symptom-directory__group-icon { display: grid; place-items: center; width: 42px; height: 42px; border: 1px solid #aebfa8; border-radius: 50%; color: #356b2f; }
    .symptom-directory__group-icon svg { width: 20px; height: 20px; stroke-width: 1.8; }
    .symptom-directory__group h3 { margin: 0 0 5px; color: #223b2d; font-size: 1.24rem; line-height: 1.45; }
    .symptom-directory__group-description { margin: 0; color: #69736c; font-size: .84rem; font-weight: 700; line-height: 1.7; }
    .symptom-directory__links { display: grid; gap: 0; border-top: 1px solid #e5e9e2; }
    .symptom-directory__link { position: relative; display: grid; gap: 4px; min-height: 76px; padding: 14px 46px 14px 4px; border-bottom: 1px solid #e5e9e2; text-decoration: none; }
    .symptom-directory__link-title { color: #234d24; font-size: .98rem; font-weight: 900; line-height: 1.5; }
    .symptom-directory__link-description { color: #69736c; font-size: .79rem; font-weight: 700; line-height: 1.65; }
    .symptom-directory__link-arrow { position: absolute; right: 4px; top: 50%; display: grid; place-items: center; width: 32px; height: 32px; border: 1px solid #cbd8c6; border-radius: 50%; color: #356b2f; font-size: 20px; font-weight: 900; line-height: 1; transform: translateY(-50%); transition: background .2s, color .2s, transform .2s; }
    .symptom-directory__link:hover, .symptom-directory__link:focus-visible { background: #fafcf8; outline: 3px solid rgba(53,107,47,.15); outline-offset: 2px; }
    .symptom-directory__link:hover .symptom-directory__link-arrow, .symptom-directory__link:focus-visible .symptom-directory__link-arrow { background: #356b2f; color: #fff; transform: translateY(-50%) translateX(2px); }
    @media (max-width: 767px) {
      .page { padding: 60px 16px 94px; }
      .symptom-directory-hero { padding-top: 30px; padding-bottom: 52px; }
      .symptom-directory-hero__actions { display: grid; }
      .symptom-directory-hero__button { width: 100%; }
      .symptom-directory__groups { columns: 1; }
      .symptom-directory__group { margin-bottom: 24px; padding-top: 30px; }
      .symptom-directory__group-header { gap: 12px; }
      .symptom-directory__link { min-height: 72px; }
    }
.symptom-page-toc {
  padding: 1.75rem 0;
  background: #fffaf3;
  border-top: 1px solid #eadfce;
  border-bottom: 1px solid #eadfce;
}

.symptom-page-toc__inner {
  display: grid;
  grid-template-columns: minmax(150px, .35fr) minmax(0, 1fr);
  align-items: start;
  gap: 1.5rem;
}

.symptom-page-toc__heading {
  margin: 0;
  color: #223b2d;
  font-size: 1rem;
  font-weight: 900;
  line-height: 1.5;
}

.symptom-page-toc__heading::before {
  display: inline-block;
  width: 4px;
  height: 1.2em;
  margin-right: .6rem;
  border-radius: 999px;
  background: #356b2f;
  content: "";
  vertical-align: -.15em;
}

.symptom-page-toc__list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: .55rem 1rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.symptom-page-toc__link {
  display: flex;
  align-items: flex-start;
  gap: .45rem;
  min-height: 44px;
  padding: .55rem .7rem;
  border-bottom: 1px solid #ded8cc;
  color: #365047;
  font-size: .84rem;
  font-weight: 700;
  line-height: 1.55;
  text-decoration: none;
}

.symptom-page-toc__link::before {
  flex: 0 0 auto;
  color: #d58b40;
  content: "›";
  font-size: 1.1rem;
  font-weight: 900;
  line-height: 1.2;
}

.symptom-page-toc__link:hover,
.symptom-page-toc__link:focus-visible {
  border-color: #8aa384;
  color: #234d24;
  outline: 2px solid rgba(53, 107, 47, .18);
  outline-offset: 2px;
}

@media (max-width: 767px) {
  .symptom-page-toc {
    padding: 1.35rem 0;
  }

  .symptom-page-toc__inner {
    grid-template-columns: 1fr;
    gap: .65rem;
  }

  .symptom-page-toc__list {
    grid-template-columns: 1fr;
    gap: 0;
  }

  .symptom-page-toc__link {
    padding: .48rem .35rem;
    font-size: .82rem;
  }
}

.symptom-trust {
  padding: clamp(4rem, 8vw, 6rem) 1rem;
  border-top: 1px solid #e3e6df;
  background: #fbfaf6;
}

.symptom-trust__inner {
  display: grid;
  gap: clamp(2rem, 5vw, 3.5rem);
}

.symptom-major-guide {
  padding: clamp(1.5rem, 4vw, 2.25rem);
  border-left: 4px solid #d58b40;
  background: #fff;
}

.symptom-major-guide__eyebrow,
.symptom-trust__eyebrow,
.symptom-trust__review-label {
  margin: 0 0 .55rem;
  color: #356b2f;
  font-size: .75rem;
  font-weight: 900;
  letter-spacing: .08em;
}

.symptom-major-guide h2,
.symptom-trust__heading h2 {
  margin: 0;
  color: #203a30;
  font-size: clamp(1.35rem, 3vw, 1.9rem);
  font-weight: 900;
  line-height: 1.55;
  letter-spacing: 0;
}

.symptom-major-guide > p:not(.symptom-major-guide__eyebrow),
.symptom-trust__heading > p:last-child {
  margin: 1rem 0 0;
  color: #52615a;
  font-size: .96rem;
  font-weight: 700;
  line-height: 1.9;
}

.symptom-major-guide ul {
  display: grid;
  gap: .65rem;
  margin: 1.15rem 0 0;
  padding: 0;
  list-style: none;
}

.symptom-major-guide li {
  position: relative;
  padding-left: 1.35rem;
  color: #52615a;
  font-size: .9rem;
  font-weight: 700;
  line-height: 1.75;
}

.symptom-major-guide li::before {
  position: absolute;
  left: 0;
  color: #d58b40;
  content: "●";
  font-size: .55rem;
  top: .55em;
}

.symptom-trust__heading {
  max-width: 760px;
}

.symptom-trust__levels {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  border-top: 1px solid #d9ded7;
  border-bottom: 1px solid #d9ded7;
}

.symptom-trust__level {
  min-width: 0;
  padding: 1.75rem;
  background: #fff;
}

.symptom-trust__level + .symptom-trust__level {
  border-left: 1px solid #d9ded7;
}

.symptom-trust__level-heading {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: .8rem;
  align-items: start;
}

.symptom-trust__level-icon {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border: 1px solid #b9c7bd;
  border-radius: 50%;
  color: #356b2f;
}

.symptom-trust__level--urgent .symptom-trust__level-icon {
  border-color: #c9a77c;
  color: #8a572e;
}

.symptom-trust__level-icon svg {
  width: 19px;
  height: 19px;
  stroke-width: 1.8;
}

.symptom-trust__level h3 {
  margin: 0;
  color: #263b34;
  font-size: 1.02rem;
  font-weight: 900;
  line-height: 1.55;
}

.symptom-trust__level-heading p {
  margin: .45rem 0 0;
  color: #69736e;
  font-size: .78rem;
  font-weight: 700;
  line-height: 1.65;
}

.symptom-trust__level ul {
  display: grid;
  gap: .7rem;
  margin: 1.15rem 0 0;
  padding: 0;
  list-style: none;
}

.symptom-trust__level li {
  position: relative;
  padding-left: 1.15rem;
  color: #4e5d56;
  font-size: .84rem;
  font-weight: 700;
  line-height: 1.7;
}

.symptom-trust__level li::before {
  position: absolute;
  left: 0;
  top: .6em;
  width: 6px;
  height: 6px;
  border: 1px solid #6e8f79;
  border-radius: 50%;
  content: "";
}

.symptom-trust__review {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 2rem;
  padding-top: .25rem;
}

.symptom-trust__reviewer,
.symptom-trust__references {
  padding-top: 1.2rem;
  border-top: 1px solid #cdd5ce;
}

.symptom-trust__review-name {
  margin: 0;
  color: #263b34;
  font-size: 1rem;
  font-weight: 900;
  line-height: 1.65;
}

.symptom-trust__review-name span {
  display: block;
  color: #5f6c66;
  font-size: .82rem;
  font-weight: 700;
}

.symptom-trust__review-date {
  margin: .55rem 0 0;
  color: #6a746f;
  font-size: .78rem;
  font-weight: 700;
}

.symptom-trust__reviewer-link,
.symptom-trust__reference {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: #245b44;
  font-size: .84rem;
  font-weight: 900;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.symptom-trust__references ul {
  display: grid;
  gap: .25rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.symptom-trust__disclaimer {
  margin: 0;
  padding: 1rem 1.15rem;
  border-left: 3px solid #92a68e;
  background: #f1f4ef;
  color: #5a665f;
  font-size: .78rem;
  font-weight: 700;
  line-height: 1.75;
}

@media (max-width: 767px) {
  .symptom-trust {
    padding: 4rem 1rem;
  }

  .symptom-trust__levels,
  .symptom-trust__review {
    grid-template-columns: 1fr;
  }

  .symptom-trust__level {
    padding: 1.35rem 1rem;
  }

  .symptom-trust__level + .symptom-trust__level {
    border-top: 1px solid #d9ded7;
    border-left: 0;
  }

  .symptom-trust__review {
    gap: 1.25rem;
  }
}
