<script lang="ts">
  import { onMount } from 'svelte';
  import { page } from '$app/stores';
  import { goto } from '$app/navigation';
  import { api, type ApiError } from '$lib/api';
  import Skeleton from '$lib/components/ui/Skeleton.svelte';
  import EmptyState from '$lib/components/ui/EmptyState.svelte';
  import Button from '$lib/components/ui/Button.svelte';
  import { countryLabel } from '$lib/i18n/countries';

  type ArticleRef = { id: number; title: string | null };
  type Topic = {
    topic_rank: number;
    topic_label: string;
    summary: string;
    article_ids: number[];
    articles: ArticleRef[];
    article_count: number;
    importance_score: number;
    llm_fallback_used: boolean;
  };
  type Country = { country: string; topics: Topic[] };
  type Digest = {
    digest_date: string;
    total_articles: number;
    total_countries: number;
    total_topics: number;
    llm_calls: number;
    llm_failures: number;
    status: string;
    countries: Country[];
  };
  type DateSummary = {
    digest_date: string;
    total_topics: number;
    total_countries: number;
    total_articles: number;
    status: string;
  };

  let digest = $state<Digest | null>(null);
  let dates = $state<DateSummary[]>([]);
  let loading = $state(true);
  let error = $state<string | null>(null);
  let loadedDate = $state<string | null>(null); // 어떤 date 파라미터로 로드했는지 (중복 로드 방지)

  // URL = 단일 진실: ?date=, ?country=
  let urlDate = $derived($page.url.searchParams.get('date') ?? '');
  let urlCountry = $derived($page.url.searchParams.get('country') ?? '');

  async function loadDates() {
    try {
      dates = await api<DateSummary[]>('/digest/dates');
    } catch {
      dates = [];
    }
  }

  async function loadDigest(dateStr: string) {
    loading = true;
    error = null;
    try {
      const path = dateStr ? `/digest?date=${dateStr}` : '/digest/latest';
      digest = await api<Digest>(path);
    } catch (e) {
      const err = e as ApiError;
      if (err && err.status === 404) {
        digest = null;
        error = null;
      } else {
        error = err?.detail ?? (e as Error)?.message ?? '알 수 없는 오류';
      }
    } finally {
      loadedDate = dateStr;
      loading = false;
    }
  }

  // URL date 변경(최초 포함) → 로드
  $effect(() => {
    const d = urlDate;
    if (d !== loadedDate) loadDigest(d);
  });

  onMount(loadDates);

  // 현재 country: '' = ALL(전체). URL 우선, 데이터에 없는 코드면 ALL 로 graceful fallback.
  let activeCountry = $derived.by(() => {
    const list = digest?.countries ?? [];
    if (urlCountry === '') return '';
    if (list.some((c) => c.country === urlCountry)) return urlCountry;
    return ''; // ALL fallback
  });

  // 편집형 정렬 리스트(t): country 슬롯 매핑의 단일 소스.
  //  - ALL(''): 전 국가 topics flatten → importance desc, 동률 시 article_count desc
  //  - 특정 country: 그 국가 topics → topic_rank asc
  // 각 topic 에 country 코드를 동봉(렌더 시 칩 표기용).
  type SlotTopic = Topic & { country: string };
  let sortedTopics = $derived.by<SlotTopic[]>(() => {
    const list = digest?.countries ?? [];
    if (activeCountry === '') {
      const flat: SlotTopic[] = [];
      for (const c of list) for (const t of c.topics) flat.push({ ...t, country: c.country });
      flat.sort((a, b) => {
        if (b.importance_score !== a.importance_score) return b.importance_score - a.importance_score;
        return b.article_count - a.article_count;
      });
      return flat;
    }
    const c = list.find((x) => x.country === activeCountry);
    if (!c) return [];
    return [...c.topics]
      .sort((a, b) => a.topic_rank - b.topic_rank)
      .map((t) => ({ ...t, country: activeCountry }));
  });

  // 슬롯: lead=t[0], featured=t[1..2], sidebar=t[3..5], grid=t[6..]
  let lead = $derived<SlotTopic | undefined>(sortedTopics[0]);
  let featured = $derived<SlotTopic[]>(sortedTopics.slice(1, 3));
  let sidebar = $derived<SlotTopic[]>(sortedTopics.slice(3, 6));
  let grid = $derived<SlotTopic[]>(sortedTopics.slice(6));

  // 날짜 네비게이션 (dates = 최신 내림차순)
  let currentDate = $derived(digest?.digest_date ?? urlDate ?? '');
  let dateIdx = $derived(dates.findIndex((d) => d.digest_date === currentDate));
  let hasOlder = $derived(dateIdx >= 0 && dateIdx < dates.length - 1);
  let hasNewer = $derived(dateIdx > 0);

  function setParams(next: { date?: string | null; country?: string | null }) {
    const p = new URLSearchParams($page.url.searchParams);
    if ('date' in next) next.date ? p.set('date', next.date) : p.delete('date');
    if ('country' in next) next.country ? p.set('country', next.country) : p.delete('country');
    const qs = p.toString();
    goto(`/digest${qs ? '?' + qs : ''}`, { noScroll: true, keepFocus: true });
  }
  function pickDate(d: string) {
    setParams({ date: d });
  }
  function pickCountry(c: string) {
    setParams({ country: c }); // '' → ALL (delete)
  }
  function older() {
    if (hasOlder) pickDate(dates[dateIdx + 1].digest_date);
  }
  function newer() {
    if (hasNewer) pickDate(dates[dateIdx - 1].digest_date);
  }
  function onSelectDate(e: Event) {
    const v = (e.currentTarget as HTMLSelectElement).value;
    pickDate(v);
  }

  function title(a: ArticleRef): string {
    return a.title ?? '(제목 없음)';
  }
  function pct(imp: number): number {
    return Math.max(0, Math.min(100, Math.round(imp * 100)));
  }
  // 편집일 한국어 표기 (예: 2026년 6월 4일 목요일)
  let editionDateKo = $derived.by(() => {
    const ds = digest?.digest_date;
    if (!ds) return '';
    const [y, m, d] = ds.split('-').map((n) => parseInt(n, 10));
    if (!y || !m || !d) return ds;
    const wd = ['일', '월', '화', '수', '목', '금', '토'];
    const dt = new Date(Date.UTC(y, m - 1, d));
    return `${y}년 ${m}월 ${d}일 ${wd[dt.getUTCDay()]}요일`;
  });
</script>

<div class="digest-page">
  <div class="app desktop">

    <!-- ── Masthead ── -->
    <header class="bar">
      <div class="mark">
        <span class="logo-chip">Digest</span>
        <h1>글로벌 뉴스 다이제스트</h1>
      </div>
      <div class="right">
        {#if digest}
          <div class="stat-group">
            <div class="stat-item">
              <span class="stat-val">{digest.total_articles.toLocaleString()}</span>
              <span class="stat-lbl">기사</span>
            </div>
            <div class="stat-item">
              <span class="stat-val">{digest.total_countries}</span>
              <span class="stat-lbl">국가</span>
            </div>
            <div class="stat-item">
              <span class="stat-val">{digest.total_topics}</span>
              <span class="stat-lbl">주제</span>
            </div>
          </div>
        {/if}

        <!-- 날짜 picker (URL ?date= 동기화) -->
        <div class="date-nav">
          <button
            type="button"
            class="date-btn"
            onclick={older}
            disabled={!hasOlder}
            aria-label="이전(과거) 날짜">‹</button>
          <select
            class="date-select"
            value={currentDate}
            onchange={onSelectDate}
            aria-label="다이제스트 날짜 선택">
            {#if dates.length === 0 && currentDate}
              <option value={currentDate}>{currentDate}</option>
            {/if}
            {#each dates as d (d.digest_date)}
              <option value={d.digest_date}>{d.digest_date} · {d.total_topics}주제 · {d.total_countries}국</option>
            {/each}
          </select>
          <button
            type="button"
            class="date-btn"
            onclick={newer}
            disabled={!hasNewer}
            aria-label="다음(최신) 날짜">›</button>
        </div>
      </div>
    </header>

    <!-- ── Country nav ── -->
    {#if digest && digest.countries.length > 0}
      <nav class="country-nav" aria-label="국가 필터">
        <button
          type="button"
          class="nav-item"
          class:active={activeCountry === ''}
          aria-current={activeCountry === '' ? 'true' : undefined}
          onclick={() => pickCountry('')}>
          <span class="cc-chip">ALL</span> 전체 <span class="topic-count">{digest.total_topics}</span>
        </button>
        {#each digest.countries as c (c.country)}
          {@const lbl = countryLabel(c.country)}
          <button
            type="button"
            class="nav-item"
            class:active={activeCountry === c.country}
            aria-current={activeCountry === c.country ? 'true' : undefined}
            onclick={() => pickCountry(c.country)}>
            <span class="cc-chip">{c.country}</span> {lbl.ko} <span class="topic-count">{c.topics.length}</span>
          </button>
        {/each}
      </nav>
    {/if}

    <!-- ── Body ── -->
    <div class="body">

      {#if loading}
        <Skeleton class="h-10 w-full" />
        <div style="height:16px"></div>
        <Skeleton class="h-40 w-full" />
        <div style="height:16px"></div>
        <Skeleton class="h-32 w-full" />
      {:else if error}
        <EmptyState title="불러올 수 없음" description={error}>
          <Button variant="ghost" size="sm" onclick={() => loadDigest(urlDate)}>다시 시도</Button>
        </EmptyState>
      {:else if !digest || digest.countries.length === 0}
        <EmptyState
          title="이 날짜의 digest 가 없습니다"
          description="다른 날짜를 선택하거나, 오늘 04:00 KST cron 실행을 기다려 주세요." />
      {:else if sortedTopics.length === 0}
        <EmptyState title="이 국가의 topic 이 없습니다" description="다른 country 탭을 확인해 주세요." />
      {:else}

        <!-- Edition dateline -->
        <div class="edition-line">
          <span class="edition-tag">Today's Front Page</span>
          <span class="edition-sep"></span>
          <span class="edition-date">{editionDateKo}</span>
          <span class="edition-sep"></span>
          <span class="edition-sub">
            {#if activeCountry === ''}
              중요도 상위 주제 우선 편집 · 전 {digest.total_countries}개국 수집
            {:else}
              {countryLabel(activeCountry).ko} · 주제 순위 편집
            {/if}
          </span>
        </div>

        <!-- ── LEAD ── -->
        {#if lead}
          {@const lbl = countryLabel(lead.country)}
          <div class="lead-block">
            <div class="lead-meta">
              <span class="priority-badge">Top Story</span>
              <span class="country-chip">
                <span class="cc">{lead.country}</span> {lbl.ko}
              </span>
              <span class="cnt-badge">
                관련기사 <strong>{lead.article_count}</strong>건&nbsp;·&nbsp;중요도 <strong>{lead.importance_score.toFixed(2)}</strong>
              </span>
            </div>
            <h2 class="lead-headline">{lead.topic_label}</h2>
            {#if lead.summary}
              <p class="lead-summary">{lead.summary}</p>
            {/if}
            {#if lead.articles.length > 0}
              <div class="lead-articles">
                {#each lead.articles as a (a.id)}
                  <div class="art-row">
                    <span class="art-bullet"></span>
                    <a href={`/documents/${a.id}`} title={title(a)}>{title(a)}</a>
                  </div>
                {/each}
              </div>
            {/if}
            <div class="lead-imp-bar">
              <span class="bar-label">중요도</span>
              <div class="bar-track">
                <div class="bar-fill" style="width:{pct(lead.importance_score)}%;"></div>
              </div>
              <span class="bar-val">{lead.importance_score.toFixed(2)}</span>
            </div>
          </div>
        {/if}

        <!-- ── 주요 뉴스 (featured 2 + sidebar 3) ── -->
        {#if featured.length > 0 || sidebar.length > 0}
          <div class="section-head">
            <span class="sh-label">주요 뉴스</span>
            <div class="sh-line"></div>
          </div>

          <div class="magazine-layout">
            {#each featured as t (t.country + ':' + t.topic_rank)}
              {@const lbl = countryLabel(t.country)}
              <div class="story-card featured">
                <div class="card-meta">
                  <span class="country-chip"><span class="cc">{t.country}</span> {lbl.ko}</span>
                  <span class="cnt-tag">기사 {t.article_count}건</span>
                </div>
                <h3 class="card-title">{t.topic_label}</h3>
                {#if t.summary}<p class="card-summary">{t.summary}</p>{/if}
                {#if t.articles.length > 0}
                  <div class="card-articles">
                    {#each t.articles.slice(0, 2) as a (a.id)}
                      <a href={`/documents/${a.id}`} title={title(a)}>{title(a)}</a>
                    {/each}
                  </div>
                {/if}
                <div class="card-imp">
                  <div class="imp-swatch imp-high" style="width:{pct(t.importance_score)}px;"></div>
                  <span class="imp-val">imp {t.importance_score.toFixed(2)}</span>
                </div>
              </div>
            {/each}

            {#if sidebar.length > 0}
              <div class="sidebar-stack">
                {#each sidebar as t (t.country + ':' + t.topic_rank)}
                  {@const lbl = countryLabel(t.country)}
                  <div class="sidebar-card">
                    <div class="sc-meta">
                      <span class="cc-only">{t.country}</span>
                      <span class="cc-name">{lbl.ko}</span>
                      <span class="sc-cnt">기사 {t.article_count}건</span>
                    </div>
                    <p class="s-title">{t.topic_label}</p>
                    {#if t.summary}<p class="s-summary">{t.summary}</p>{/if}
                    {#if t.articles.length > 0}
                      <a href={`/documents/${t.articles[0].id}`} class="s-link" title={title(t.articles[0])}>{title(t.articles[0])} &rarr;</a>
                    {/if}
                  </div>
                {/each}
              </div>
            {/if}
          </div>
        {/if}

        <!-- ── 심층 보도 (grid) ── -->
        {#if grid.length > 0}
          <div class="section-head">
            <span class="sh-label">심층 보도</span>
            <div class="sh-line"></div>
          </div>

          <div class="grid-3">
            {#each grid as t (t.country + ':' + t.topic_rank)}
              {@const lbl = countryLabel(t.country)}
              <div class="compact-card">
                <div class="c-meta">
                  <span class="c-cc">{t.country}</span>
                  <span class="c-ko">{lbl.ko}</span>
                  <span class="c-cnt">기사 {t.article_count}건</span>
                </div>
                <p class="c-title">{t.topic_label}</p>
                {#if t.summary}<p class="c-summary">{t.summary}</p>{/if}
                {#if t.articles.length > 0}
                  <a href={`/documents/${t.articles[0].id}`} class="c-link" title={title(t.articles[0])}>{title(t.articles[0])} &rarr;</a>
                {/if}
                <div class="c-imp-bar"><div class="c-imp-fill" style="width:{pct(t.importance_score)}%;"></div></div>
              </div>
            {/each}
          </div>
        {/if}

      {/if}
    </div><!-- /.body -->
  </div><!-- /.app.desktop -->
</div><!-- /.digest-page -->

<style>
  /* ── 세이지 팔레트 로컬 재정의 ──
     앱 :root 다크 토큰(--surface:#1a1d27, --accent:파랑 등)이 하위 var() 로 새지 않도록
     이 subtree 에서 세이지값으로 덮어쓴다. 하위 모든 var(--surface/--card/--line/--brand …)는
     여기서 해석된다. 검정(#000/#1f2024) 미사용. */
  .digest-page {
    --brand: #4f8a6b;
    --brand-d: #3d7256;
    --surface: #ecf0e8;
    --card: #fff;
    --ink: #23291f;
    --muted: #697061;
    --line: #dde3d6;
    font-family: 'Apple SD Gothic Neo', 'Noto Sans KR', 'Malgun Gothic', system-ui, sans-serif;
    color: #333a2d;
  }

  /* ── App shell ── */
  .app {
    max-width: 1680px;
    margin: 0 auto;
    background: var(--surface);
    min-height: 100vh;
    overflow-x: hidden;
  }

  /* ── Masthead ── */
  header.bar {
    background: #f4f7f1;
    border-bottom: 3px solid var(--brand);
    padding: 0 32px;
    display: flex;
    align-items: center;
    gap: 0;
    min-height: 56px;
    box-shadow: 0 1px 0 #dde3d6;
  }
  header.bar .mark {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-shrink: 0;
    white-space: nowrap;
  }
  header.bar .mark .logo-chip {
    background: var(--brand);
    color: #fff;
    font-size: 10px;
    font-weight: 800;
    letter-spacing: 0.1em;
    padding: 3px 8px;
    border-radius: 3px;
    text-transform: uppercase;
    flex-shrink: 0;
  }
  header.bar h1 {
    font-size: 15px;
    font-weight: 700;
    color: #333a2d;
    margin: 0;
    letter-spacing: -0.01em;
    white-space: nowrap;
    line-height: 1.4;
  }
  header.bar .right {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: 20px;
    flex-shrink: 0;
  }
  header.bar .stat-group {
    display: flex;
    gap: 16px;
  }
  header.bar .stat-item {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    line-height: 1.2;
  }
  header.bar .stat-val {
    font-size: 13px;
    font-weight: 700;
    color: #333a2d;
  }
  header.bar .stat-lbl {
    font-size: 10px;
    color: #9aa090;
    letter-spacing: 0.04em;
  }

  /* 날짜 nav (badge 자리를 select 로 대체) */
  .date-nav {
    display: flex;
    align-items: center;
    gap: 4px;
  }
  .date-btn {
    background: #ecf0e8;
    border: 1px solid #cfd7c6;
    border-radius: 4px;
    width: 26px;
    height: 28px;
    font-size: 14px;
    font-weight: 700;
    color: #4a5142;
    cursor: pointer;
    line-height: 1;
    transition: background 0.15s, color 0.15s;
  }
  .date-btn:hover:not(:disabled) {
    background: #e3ebdf;
    color: var(--brand-d);
  }
  .date-btn:disabled {
    opacity: 0.4;
    cursor: not-allowed;
  }
  .date-select {
    background: #ecf0e8;
    border: 1px solid #cfd7c6;
    border-radius: 4px;
    padding: 4px 8px;
    font-size: 12px;
    font-weight: 600;
    color: #4a5142;
    letter-spacing: 0.02em;
    max-width: 220px;
    cursor: pointer;
    font-family: inherit;
  }

  /* ── Country nav ── */
  .country-nav {
    background: #fff;
    border-bottom: 1px solid var(--line);
    padding: 0 32px;
    display: flex;
    align-items: center;
    gap: 0;
    overflow-x: auto;
    scrollbar-width: none;
  }
  .country-nav::-webkit-scrollbar { display: none; }
  .country-nav .nav-item {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 10px 14px;
    font-size: 12px;
    font-weight: 600;
    color: #697061;
    cursor: pointer;
    border: none;
    background: none;
    border-bottom: 2px solid transparent;
    white-space: nowrap;
    transition: color 0.15s, border-color 0.15s;
    font-family: inherit;
  }
  .country-nav .nav-item:hover {
    color: #333a2d;
    border-bottom-color: #cfd7c6;
  }
  .country-nav .nav-item.active {
    color: var(--brand);
    border-bottom-color: var(--brand);
  }
  .country-nav .cc-chip {
    display: inline-block;
    font-size: 9px;
    font-weight: 800;
    padding: 2px 5px;
    border-radius: 2px;
    letter-spacing: 0.05em;
    background: var(--surface);
    color: #697061;
  }
  .country-nav .nav-item.active .cc-chip {
    background: rgba(79, 138, 107, 0.15);
    color: var(--brand);
  }
  .country-nav .topic-count {
    font-size: 10px;
    font-weight: 400;
    color: #9aa090;
  }

  /* ── Body ── */
  .body {
    padding: 28px 32px 48px;
  }

  /* ── Edition dateline ── */
  .edition-line {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 20px;
    padding-bottom: 10px;
    border-bottom: 2px solid var(--brand);
    flex-wrap: wrap;
  }
  .edition-line .edition-tag {
    background: var(--brand);
    color: #fff;
    font-size: 9px;
    font-weight: 800;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    padding: 3px 8px;
    border-radius: 2px;
  }
  .edition-line .edition-date {
    font-size: 12px;
    font-weight: 600;
    color: #697061;
    letter-spacing: 0.04em;
  }
  .edition-line .edition-sep {
    width: 1px;
    height: 12px;
    background: var(--line);
  }
  .edition-line .edition-sub {
    font-size: 11px;
    color: #9aa090;
  }

  /* ── Lead story block ── */
  .lead-block {
    background: var(--card);
    border: 1px solid #cfd7c6;
    border-top: 4px solid var(--brand);
    border-radius: 4px;
    padding: 28px 32px 24px;
    margin-bottom: 24px;
    position: relative;
    overflow: hidden;
  }
  .lead-block::before {
    content: '';
    position: absolute;
    top: 0;
    right: 0;
    width: 200px;
    height: 100%;
    background: linear-gradient(to left, rgba(79, 138, 107, 0.05), transparent);
    pointer-events: none;
  }
  .lead-meta {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 14px;
    flex-wrap: wrap;
  }
  .lead-meta .priority-badge {
    background: var(--brand);
    color: #fff;
    font-size: 9px;
    font-weight: 800;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    padding: 3px 8px;
    border-radius: 2px;
  }
  .lead-meta .country-chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 11px;
    font-weight: 600;
    color: #333a2d;
    background: var(--surface);
    border: 1px solid #cfd7c6;
    padding: 3px 8px;
    border-radius: 3px;
  }
  .lead-meta .country-chip .cc {
    font-size: 9px;
    font-weight: 800;
    letter-spacing: 0.06em;
    background: var(--brand-d);
    color: #fff;
    padding: 1px 4px;
    border-radius: 2px;
  }
  .lead-meta .cnt-badge {
    font-size: 11px;
    color: #697061;
    display: flex;
    align-items: center;
    gap: 4px;
  }
  .lead-meta .cnt-badge strong {
    color: #333a2d;
    font-weight: 700;
  }
  .lead-headline {
    font-size: 28px;
    font-weight: 800;
    line-height: 1.25;
    color: #23291f;
    letter-spacing: -0.02em;
    margin: 0 0 14px;
  }
  .lead-summary {
    font-size: 14px;
    line-height: 1.75;
    color: #4a5142;
    margin: 0 0 20px;
    max-width: 680px;
  }
  .lead-articles {
    border-top: 1px solid var(--line);
    padding-top: 16px;
    display: flex;
    flex-direction: column;
    gap: 8px;
  }
  .lead-articles .art-row {
    display: flex;
    align-items: baseline;
    gap: 8px;
  }
  .lead-articles .art-bullet {
    width: 4px;
    height: 4px;
    border-radius: 50%;
    background: var(--brand);
    flex-shrink: 0;
    margin-top: 6px;
  }
  .lead-articles a {
    font-size: 13px;
    font-weight: 600;
    color: #333a2d;
    text-decoration: none;
    line-height: 1.45;
  }
  .lead-articles a:hover {
    color: var(--brand);
    text-decoration: underline;
  }
  .lead-imp-bar {
    margin-top: 16px;
    display: flex;
    align-items: center;
    gap: 10px;
  }
  .lead-imp-bar .bar-label {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: #9aa090;
    white-space: nowrap;
  }
  .lead-imp-bar .bar-track {
    flex: 1;
    height: 5px;
    background: var(--line);
    border-radius: 3px;
    overflow: hidden;
    max-width: 200px;
  }
  .lead-imp-bar .bar-fill {
    height: 100%;
    border-radius: 3px;
    background: var(--brand);
  }
  .lead-imp-bar .bar-val {
    font-size: 11px;
    font-weight: 700;
    color: var(--brand);
  }

  /* ── Section divider ── */
  .section-head {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 16px;
  }
  .section-head .sh-label {
    font-size: 10px;
    font-weight: 800;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: #9aa090;
    white-space: nowrap;
  }
  .section-head .sh-line {
    flex: 1;
    height: 1px;
    background: var(--line);
  }

  /* ── Magazine layout (2-col main + 1-col sidebar) ── */
  .magazine-layout {
    display: grid;
    grid-template-columns: 1fr 1fr 280px;
    gap: 16px;
    margin-bottom: 24px;
  }

  /* ── Story card ── */
  .story-card {
    background: var(--card);
    border: 1px solid #cfd7c6;
    border-radius: 4px;
    padding: 18px 20px 16px;
    display: flex;
    flex-direction: column;
    gap: 10px;
    transition: box-shadow 0.15s;
  }
  .story-card:hover {
    box-shadow: 0 2px 12px rgba(74, 81, 66, 0.09);
  }
  .story-card.featured {
    border-top: 3px solid var(--brand-d);
  }
  .card-meta {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
  }
  .card-meta .country-chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 10px;
    font-weight: 600;
    color: #333a2d;
    background: var(--surface);
    border: 1px solid #cfd7c6;
    padding: 2px 7px;
    border-radius: 3px;
  }
  .card-meta .country-chip .cc {
    font-size: 8px;
    font-weight: 800;
    letter-spacing: 0.06em;
    background: var(--brand-d);
    color: #fff;
    padding: 1px 3px;
    border-radius: 2px;
  }
  .card-meta .cnt-tag {
    font-size: 10px;
    color: #9aa090;
    margin-left: auto;
  }
  .card-title {
    font-size: 15px;
    font-weight: 700;
    line-height: 1.35;
    color: #23291f;
    letter-spacing: -0.01em;
    margin: 0;
  }
  .card-summary {
    font-size: 12px;
    line-height: 1.65;
    color: #4a5142;
    margin: 0;
    flex: 1;
  }
  .card-articles {
    display: flex;
    flex-direction: column;
    gap: 5px;
    border-top: 1px solid var(--line);
    padding-top: 10px;
  }
  .card-articles a {
    font-size: 11px;
    font-weight: 600;
    color: #333a2d;
    text-decoration: none;
    line-height: 1.4;
    display: flex;
    align-items: baseline;
    gap: 6px;
  }
  .card-articles a::before {
    content: '';
    display: inline-block;
    width: 3px;
    height: 3px;
    border-radius: 50%;
    background: #9aa090;
    flex-shrink: 0;
    margin-top: 5px;
  }
  .card-articles a:hover { color: var(--brand); }
  .card-articles a:hover::before { background: var(--brand); }
  .card-imp {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 2px;
  }
  .card-imp .imp-swatch {
    height: 3px;
    border-radius: 2px;
  }
  .card-imp .imp-val {
    font-size: 10px;
    font-weight: 600;
    color: #9aa090;
  }

  /* ── Sidebar stack ── */
  .sidebar-stack {
    display: flex;
    flex-direction: column;
    gap: 12px;
  }
  .sidebar-card {
    background: var(--card);
    border: 1px solid #cfd7c6;
    border-radius: 4px;
    padding: 14px 16px;
    display: flex;
    flex-direction: column;
    gap: 8px;
  }
  .sidebar-card .sc-meta {
    display: flex;
    align-items: center;
    gap: 6px;
  }
  .sidebar-card .cc-only {
    font-size: 9px;
    font-weight: 800;
    letter-spacing: 0.06em;
    background: var(--brand-d);
    color: #fff;
    padding: 2px 5px;
    border-radius: 2px;
  }
  .sidebar-card .cc-name {
    font-size: 10px;
    font-weight: 600;
    color: #697061;
  }
  .sidebar-card .sc-cnt {
    font-size: 10px;
    color: #9aa090;
    margin-left: auto;
  }
  .sidebar-card .s-title {
    font-size: 13px;
    font-weight: 700;
    line-height: 1.35;
    color: #23291f;
    margin: 0;
  }
  .sidebar-card .s-summary {
    font-size: 11px;
    line-height: 1.55;
    color: #4a5142;
    margin: 0;
  }
  .sidebar-card .s-link {
    font-size: 11px;
    color: var(--brand);
    font-weight: 600;
    text-decoration: none;
  }
  .sidebar-card .s-link:hover { text-decoration: underline; }

  /* ── 3-col grid (심층 보도) ── */
  .grid-3 {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 14px;
    margin-bottom: 24px;
  }
  .compact-card {
    background: var(--card);
    border: 1px solid #cfd7c6;
    border-radius: 4px;
    padding: 14px 16px;
    display: flex;
    flex-direction: column;
    gap: 8px;
  }
  .compact-card .c-meta {
    display: flex;
    align-items: center;
    gap: 6px;
  }
  .compact-card .c-cc {
    font-size: 8px;
    font-weight: 800;
    letter-spacing: 0.06em;
    background: var(--brand-d);
    color: #fff;
    padding: 2px 4px;
    border-radius: 2px;
  }
  .compact-card .c-ko {
    font-size: 10px;
    font-weight: 600;
    color: #697061;
  }
  .compact-card .c-cnt {
    font-size: 10px;
    color: #9aa090;
    margin-left: auto;
  }
  .compact-card .c-title {
    font-size: 13px;
    font-weight: 700;
    line-height: 1.35;
    color: #23291f;
    margin: 0;
  }
  .compact-card .c-summary {
    font-size: 11px;
    line-height: 1.55;
    color: #4a5142;
    margin: 0;
    flex: 1;
  }
  .compact-card .c-link {
    font-size: 11px;
    font-weight: 600;
    color: var(--brand);
    text-decoration: none;
  }
  .compact-card .c-link:hover { text-decoration: underline; }
  .compact-card .c-imp-bar {
    height: 2px;
    border-radius: 1px;
    background: var(--line);
    overflow: hidden;
  }
  .compact-card .c-imp-fill {
    height: 100%;
    border-radius: 1px;
    background: rgba(79, 138, 107, 0.6);
  }

  /* ── Importance swatches ── */
  .imp-high { background: rgba(79, 138, 107, 0.85); }

  /* 극단적 긴 무공백 토큰(연속 CJK·URL) 가로 오버플로 방어 */
  .lead-headline, .lead-summary, .card-title, .card-summary,
  .s-title, .s-summary, .c-title, .c-summary,
  .lead-articles a, .card-articles a, .sidebar-card .s-link, .compact-card .c-link {
    overflow-wrap: anywhere;
    word-break: break-word;
  }

  /* ── 반응형: 좁은 화면에서 가로 오버플로 방지 ── */
  @media (max-width: 880px) {
    .magazine-layout {
      grid-template-columns: 1fr;
    }
    .grid-3 {
      grid-template-columns: 1fr 1fr;
    }
  }
  @media (max-width: 560px) {
    .body { padding: 20px 16px 40px; }
    header.bar { padding: 0 16px; }
    .country-nav { padding: 0 16px; }
    .grid-3 { grid-template-columns: 1fr; }
    .lead-headline { font-size: 22px; }
    header.bar .stat-group { display: none; }
  }
</style>
