{% extends 'base.html' %}
{% load i18n %}
{% load markdown_extras %}
{% load static %}

{% block extra_css %}
<link rel="stylesheet" href="{% static 'css/markdown.css' %}">
<style>
  /* ============================================================
     Apple-inspired design system — Post detail page
     Mirrors the home page: #f5f5f7 canvas, SF typography, soft
     shadows, pill buttons, generous rounded cards.
     ============================================================ */
  :root {
    --apple-bg: #f5f5f7;
    --apple-text: #1d1d1f;
    --apple-gray: #6e6e73;
    --apple-blue: #0071e3;
    --apple-blue-hover: #0077ed;
    --apple-red: #ff3b30;
    --apple-green: #1e7b34;
    --apple-purple: #8944ab;
    --apple-separator: rgba(0, 0, 0, 0.06);
    --apple-ease: cubic-bezier(0.28, 0.11, 0.32, 1);
    --apple-radius-lg: 28px;
    --apple-radius-md: 22px;
    --apple-radius-sm: 14px;
    --apple-shadow-card: 0 4px 24px rgba(0, 0, 0, 0.05);
    --apple-shadow-lift: 0 18px 44px rgba(0, 0, 0, 0.10);

    /* Reader surface (cards) — follows theme */
    --reader-surface: #ffffff;
    --reader-surface-2: #fafafa;
    --reader-control: #f5f5f7;
    --reader-hover: rgba(0, 0, 0, 0.05);
    --reader-progress: linear-gradient(90deg, #0071e3 0%, #7c3aed 100%);
    --reader-font-size: 17px;
    --reader-line-height: 1.85;
  }

  /* ============================================================
     Reader themes (微信读书-style): light / paper / green / night
     Overrides the --apple-* + --md-* design tokens so the whole
     page (cards, TOC, tables, code, quotes) re-skins together.
     ============================================================ */
  body.reader-paper {
    --apple-bg: #ece5d5;
    --apple-text: #40392e;
    --apple-gray: #8a8272;
    --apple-separator: rgba(64, 57, 46, 0.10);
    --reader-surface: #faf6ec;
    --reader-surface-2: #f3ede0;
    --reader-control: #efe8d8;
    --reader-hover: rgba(64, 57, 46, 0.07);
    --reader-progress: linear-gradient(90deg, #b8860b 0%, #8a6d1f 100%);
    --md-text: #40392e;
    --md-muted: #8a8272;
    --md-heading: #332d23;
    --md-border: #ddd4c0;
    --md-accent: #9a6b1f;
    --md-accent-soft: rgba(154, 107, 31, 0.12);
    --md-table-head-bg: #efe8d8;
    --md-table-zebra: rgba(154, 130, 60, 0.05);
    --md-code-bg: #f0e9da;
    --md-code-text: #4a4234;
    --md-pre-bg: #3d362a;
    --md-pre-text: #e8e0cd;
    --md-quote-bg: rgba(154, 130, 60, 0.07);
    --md-hr: #ddd4c0;
  }
  body.reader-green {
    --apple-bg: #dde8da;
    --apple-text: #26342a;
    --apple-gray: #5f7163;
    --apple-separator: rgba(38, 52, 42, 0.10);
    --reader-surface: #eef5ec;
    --reader-surface-2: #e3eee0;
    --reader-control: #dde8da;
    --reader-hover: rgba(38, 52, 42, 0.06);
    --reader-progress: linear-gradient(90deg, #2e8b57 0%, #1e6b3c 100%);
    --md-text: #26342a;
    --md-muted: #5f7163;
    --md-heading: #1d2a20;
    --md-border: #c9dac4;
    --md-accent: #1e7b34;
    --md-accent-soft: rgba(30, 123, 52, 0.10);
    --md-table-head-bg: #e3eee0;
    --md-table-zebra: rgba(46, 139, 87, 0.05);
    --md-code-bg: #e3eee0;
    --md-code-text: #2c3a30;
    --md-pre-bg: #22301f;
    --md-pre-text: #dce8d9;
    --md-quote-bg: rgba(46, 139, 87, 0.06);
    --md-hr: #c9dac4;
  }
  body.reader-night {
    --apple-bg: #131316;
    --apple-text: #d4d4dc;
    --apple-gray: #8b8b96;
    --apple-blue: #4d9fff;
    --apple-blue-hover: #66aeff;
    --apple-green: #4caf7d;
    --apple-purple: #c58af9;
    --apple-red: #ff6b61;
    --apple-separator: rgba(255, 255, 255, 0.10);
    --reader-surface: #1c1c22;
    --reader-surface-2: #232329;
    --reader-control: #26262e;
    --reader-hover: rgba(255, 255, 255, 0.07);
    --reader-progress: linear-gradient(90deg, #4d9fff 0%, #c58af9 100%);
    --apple-shadow-card: 0 4px 24px rgba(0, 0, 0, 0.35);
    --apple-shadow-lift: 0 18px 44px rgba(0, 0, 0, 0.55);
    --md-text: #c4c4cf;
    --md-muted: #8b8b96;
    --md-heading: #ececf2;
    --md-border: #33333c;
    --md-accent: #7db4ff;
    --md-accent-soft: rgba(77, 159, 255, 0.14);
    --md-table-head-bg: #26262e;
    --md-table-zebra: rgba(255, 255, 255, 0.03);
    --md-code-bg: #2a2a33;
    --md-code-text: #e0e0e8;
    --md-pre-bg: #0d0d10;
    --md-pre-text: #c8c8d4;
    --md-quote-bg: rgba(255, 255, 255, 0.04);
    --md-hr: #2c2c34;
  }

  body {
    background-color: var(--apple-bg) !important;
    font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
      "Helvetica Neue", "Segoe UI", Roboto, Arial, sans-serif;
    color: var(--apple-text);
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
    transition: background-color 0.4s var(--apple-ease), color 0.4s var(--apple-ease);
  }

  .apple-card {
    background: var(--reader-surface);
    border-radius: var(--apple-radius-lg);
    border: 1px solid rgba(0, 0, 0, 0.04);
    box-shadow: var(--apple-shadow-card);
  }

  .apple-btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 0.45rem;
    min-height: 44px; padding: 0.6rem 1.4rem; border-radius: 980px;
    font-weight: 600; font-size: 0.95rem; border: none; cursor: pointer; text-decoration: none;
    transition: background 0.3s var(--apple-ease), transform 0.3s var(--apple-ease), box-shadow 0.3s var(--apple-ease);
  }
  .apple-btn:active { transform: scale(0.97); }
  .apple-btn-primary { background: var(--apple-blue); color: #fff; box-shadow: 0 6px 18px rgba(0, 113, 227, 0.28); }
  .apple-btn-primary:hover { background: var(--apple-blue-hover); color: #fff; }
  .apple-btn-secondary { background: var(--apple-bg); color: var(--apple-text); border: 1px solid rgba(0, 0, 0, 0.10); }
  .apple-btn-secondary:hover { background: #ececef; }
  .apple-btn-danger { background: transparent; color: var(--apple-red); border: 1px solid rgba(255, 59, 48, 0.4); }
  .apple-btn-danger:hover { background: rgba(255, 59, 48, 0.08); }

  /* ---------- Soft pill action buttons (Listen / Edit / Share / Delete) ---------- */
  .action-btn {
    display: inline-flex; align-items: center; gap: 0.4rem;
    padding: 0.5rem 1rem; border-radius: 980px;
    font-size: 0.85rem; font-weight: 600; border: none; cursor: pointer;
    text-decoration: none; white-space: nowrap;
    transition: background 0.25s var(--apple-ease), color 0.25s var(--apple-ease), transform 0.2s var(--apple-ease);
  }
  .action-btn:active { transform: scale(0.96); }
  .action-btn svg { width: 1rem; height: 1rem; }
  .action-btn-purple { background: rgba(191, 90, 242, 0.12); color: var(--apple-purple); }
  .action-btn-purple:hover { background: rgba(191, 90, 242, 0.20); }
  .action-btn-blue { background: rgba(0, 113, 227, 0.10); color: var(--apple-blue); }
  .action-btn-blue:hover { background: rgba(0, 113, 227, 0.18); }
  .action-btn-green { background: rgba(48, 209, 88, 0.14); color: var(--apple-green); }
  .action-btn-green:hover { background: rgba(48, 209, 88, 0.22); }
  .action-btn-red { background: rgba(255, 59, 48, 0.10); color: var(--apple-red); }
  .action-btn-red:hover { background: rgba(255, 59, 48, 0.18); }
  .action-btn:disabled { opacity: 0.55; cursor: default; }
  .action-icon-btn {
    display: inline-flex; align-items: center; justify-content: center;
    width: 34px; height: 34px; border-radius: 50%; border: none; background: transparent;
    color: var(--apple-gray); cursor: pointer; transition: background 0.25s ease, color 0.25s ease;
  }
  .action-icon-btn:hover { background: rgba(255, 59, 48, 0.10); color: var(--apple-red); }
  .action-icon-btn:disabled { opacity: 0.5; cursor: default; }
  .action-icon-btn svg { width: 1rem; height: 1rem; }

  /* ---------- Modal ---------- */
  .modal {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    width: 100vw;
    height: 100vh;
    background-color: rgba(0, 0, 0, 0.45);
    z-index: 50;
    align-items: center;
    justify-content: center;
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
  }
  .modal.show {
    display: flex;
  }
  .modal-content {
    background: var(--reader-surface);
    border-radius: var(--apple-radius-md);
    width: 100%;
    max-width: 26rem;
    margin: 1rem;
    box-shadow: var(--apple-shadow-lift);
    border: 1px solid rgba(0, 0, 0, 0.04);
  }

  /* Think Panel Styles */
  .think-panel {
    border: 1px solid var(--apple-separator);
    border-radius: var(--apple-radius-sm);
    margin: 1rem 0;
    overflow: hidden;
    background-color: #fff;
  }

  .think-header {
    background-color: var(--apple-bg);
    padding: 1rem;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-size: 1rem;
    color: var(--apple-text);
  }

  .think-header:hover {
    background-color: #ececef;
  }

  .think-content {
    padding: 0;
    max-height: 0;
    overflow: hidden;
    transition: max-height 0.3s ease-out, padding 0.3s ease-out;
  }

  .think-content.expanded {
    padding: 1rem;
    max-height: 2000px; /* Adjust based on your needs */
    transition: max-height 0.5s ease-in, padding 0.3s ease-in;
  }

  .think-icon {
    transition: transform 0.3s ease;
  }

  .think-icon.expanded {
    transform: rotate(180deg);
  }

  /* Task List Styles */
  .task-item {
    list-style: none;
    padding-left: 0;
  }

  .task-checkbox {
    margin-right: 0.5rem;
    cursor: pointer;
    width: 1.1em;
    height: 1.1em;
    vertical-align: middle;
  }

  .task-checkbox:hover {
    opacity: 0.7;
  }

  /* Enhanced Audio Player Styles */
  .audio-player {
    background: linear-gradient(145deg, #fafafa 0%, #eef0f3 100%);
    border: 1px solid rgba(0, 0, 0, 0.06);
    border-radius: var(--apple-radius-md);
    box-shadow: var(--apple-shadow-card);
    padding: 1.25rem;
  }

    .audio-controls {
        display: flex;
        align-items: center;
        gap: 12px;
    }

    .play-pause-btn {
        width: 48px;
        height: 48px;
        background: linear-gradient(145deg, #1e293b 0%, #0f172a 100%);
        border: none;
        border-radius: 50%;
        color: white;
        display: flex;
        align-items: center;
        justify-content: center;
        cursor: pointer;
        transition: all 0.2s ease;
        box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
    }

    .play-pause-btn:hover {
        background: linear-gradient(145deg, #334155 0%, #1e293b 100%);
        transform: translateY(-1px);
        box-shadow: 0 6px 12px rgba(0, 0, 0, 0.25);
    }

    .play-pause-btn:active {
        transform: translateY(0);
        box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
    }

    .play-pause-btn:disabled {
        background: #94a3b8;
        cursor: not-allowed;
        transform: none;
        box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
    }

    .stop-btn {
        width: 36px;
        height: 36px;
        background: linear-gradient(145deg, #dc2626 0%, #991b1b 100%);
        border: none;
        border-radius: 50%;
        color: white;
        display: flex;
        align-items: center;
        justify-content: center;
        cursor: pointer;
        transition: all 0.2s ease;
        box-shadow: 0 3px 6px rgba(220, 38, 38, 0.3);
    }

    .stop-btn:hover {
        background: linear-gradient(145deg, #ef4444 0%, #dc2626 100%);
        transform: translateY(-1px);
        box-shadow: 0 4px 8px rgba(220, 38, 38, 0.4);
    }

    .stop-btn:active {
        transform: translateY(0);
        box-shadow: 0 2px 4px rgba(220, 38, 38, 0.3);
    }

    .speed-btn {
        width: 44px;
        height: 32px;
        background: linear-gradient(145deg, #059669 0%, #047857 100%);
        border: none;
        border-radius: 16px;
        color: white;
        display: flex;
        align-items: center;
        justify-content: center;
        cursor: pointer;
        transition: all 0.2s ease;
        box-shadow: 0 2px 4px rgba(5, 150, 105, 0.3);
        font-size: 11px;
        font-weight: 700;
        font-family: 'Monaco', 'Menlo', monospace;
    }

    .speed-btn:hover {
        background: linear-gradient(145deg, #10b981 0%, #059669 100%);
        transform: translateY(-1px);
        box-shadow: 0 3px 6px rgba(5, 150, 105, 0.4);
    }

    .speed-btn:active {
        transform: translateY(0);
        box-shadow: 0 2px 4px rgba(5, 150, 105, 0.3);
    }

    .progress-container {
        position: relative;
        height: 8px;
        background: #e2e8f0;
        border-radius: 4px;
        overflow: hidden;
        box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1);
    }

    .progress-bar {
        height: 100%;
        background: linear-gradient(90deg, #7c3aed 0%, #a855f7 100%);
        border-radius: 4px;
        transition: width 0.1s ease;
        box-shadow: 0 1px 3px rgba(124, 58, 237, 0.3);
    }

    .seek-slider {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        opacity: 0;
        cursor: pointer;
        margin: 0;
    }

    .seek-slider::-webkit-slider-thumb {
        appearance: none;
        width: 16px;
        height: 16px;
        background: #7c3aed;
        border-radius: 50%;
        cursor: pointer;
        box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
    }

    .audio-time {
        font-family: 'Monaco', 'Menlo', monospace;
        font-size: 14px;
        font-weight: 600;
        color: #475569;
        background: #f1f5f9;
        padding: 4px 8px;
        border-radius: 6px;
        border: 1px solid #e2e8f0;
    }

    .audio-status {
        font-size: 12px;
        font-weight: 600;
        padding: 4px 8px;
        border-radius: 6px;
        text-transform: uppercase;
        letter-spacing: 0.05em;
    }

    .status-ready { background: #ddd6fe; color: #7c3aed; }
    .status-generating { background: #fef3c7; color: #d97706; }
    .status-playing { background: #dcfce7; color: #16a34a; }
    .status-paused { background: #fed7aa; color: #ea580c; }
    .status-stopped { background: #f3f4f6; color: #6b7280; }
    .status-finished { background: #dbeafe; color: #2563eb; }
    .status-error { background: #fecaca; color: #dc2626; }

    /* Voice Selection Styles */
    .voice-select-compact {
        min-width: 180px;
        max-width: 220px;
        padding: 0.5rem;
        border: 2px solid #e5e7eb;
        border-radius: 6px;
        font-size: 12px;
        line-height: 1.4;
        background-color: white;
        cursor: pointer;
        transition: border-color 0.2s ease;
        flex-shrink: 0;
    }

    .voice-select-compact:focus {
        outline: none;
        border-color: #7c3aed;
        box-shadow: 0 0 0 3px rgba(124, 58, 237, 0.1);
    }

    .custom-voice-input {
        width: 100%;
        padding: 0.5rem;
        border: 2px solid #e5e7eb;
        border-radius: 6px;
        font-size: 12px;
        line-height: 1.4;
        transition: border-color 0.2s ease;
    }

    .custom-voice-input:focus {
        outline: none;
        border-color: #7c3aed;
        box-shadow: 0 0 0 3px rgba(124, 58, 237, 0.1);
    }

    .voice-controls {
        display: flex;
        align-items: center;
        gap: 0.75rem;
        margin-bottom: 1rem;
        padding: 1rem;
        background: rgba(255, 255, 255, 0.6);
        border-radius: var(--apple-radius-sm);
        border: 1px solid rgba(0, 0, 0, 0.06);
    }

    .voice-label {
        font-size: 12px;
        font-weight: 600;
        color: var(--apple-text);
        white-space: nowrap;
    }
    .main-content {
      background: var(--reader-surface);
      border-radius: var(--apple-radius-lg);
      border: 1px solid rgba(0, 0, 0, 0.04);
      box-shadow: var(--apple-shadow-card);
      padding: clamp(1.25rem, 4vw, 2.5rem);
      transition: background-color 0.4s var(--apple-ease), border-color 0.4s var(--apple-ease);
    }

    /* ===== Table of Contents Layout ===== */
    #post-toc-layout {
        max-width: 80rem;   /* max-w-6xl equivalent */
        margin: 0.5rem auto;
        padding: 0.5rem;
    }
    .post-header-row { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: 0.85rem; margin-bottom: 1.1rem; }
    .post-title { font-size: clamp(1.5rem, 3.4vw, 2.1rem); font-weight: 700; letter-spacing: -0.02em; line-height: 1.2; flex: 1 1 16rem; min-width: 0; color: var(--apple-text); }
    .post-actions { display: flex; align-items: center; gap: 0.5rem; flex-shrink: 0; flex-wrap: wrap; max-width: 100%; }
    .post-meta { display: flex; flex-direction: column; gap: 0.85rem; margin-bottom: 1.25rem; }
    .post-summary { position: relative; padding-left: 1rem; border-left: 3px solid rgba(0, 113, 227, 0.35); }
    .post-summary p { font-size: 1.02rem; color: var(--apple-gray); font-style: normal; margin: 0; line-height: 1.7; }
    .post-tags { display: flex; flex-wrap: wrap; gap: 0.5rem; }
    .post-timestamps { display: flex; flex-wrap: wrap; align-items: center; gap: 1.5rem; font-size: 0.85rem; color: var(--apple-gray); background: var(--apple-bg); border-radius: 980px; padding: 0.6rem 1.1rem; }
    .post-timestamps .timestamp-item { display: flex; align-items: center; }
    .post-timestamps svg { width: 1rem; height: 1rem; margin-right: 0.4rem; color: #a1a1a6; }
    .post-timestamps .timestamp-label { font-weight: 600; color: var(--apple-text); margin-right: 0.25rem; }
    .post-article { margin-top: 1.5rem; }
    .append-section { margin-top: 2.25rem; border-top: 1px solid var(--apple-separator); padding-top: 1.5rem; }
    .append-title { font-size: 0.85rem; font-weight: 600; color: var(--apple-text); margin-bottom: 0.75rem; }
    .append-textarea {
        width: 100%; min-height: 200px; padding: 0.85rem 1rem; font-size: 0.9rem;
        font-family: 'SF Mono', 'Monaco', 'Menlo', monospace; color: var(--apple-text);
        background: var(--apple-bg); border: 1px solid rgba(0, 0, 0, 0.08);
        border-radius: var(--apple-radius-sm); resize: vertical;
        transition: border-color 0.25s ease, box-shadow 0.25s ease, background 0.25s ease;
    }
    .append-textarea:focus {
        outline: none; background: #fff;
        border-color: rgba(0, 113, 227, 0.5);
        box-shadow: 0 0 0 4px rgba(0, 113, 227, 0.14);
    }
    .append-footer { display: flex; align-items: center; justify-content: space-between; margin-top: 0.75rem; }
    .append-status { font-size: 0.78rem; color: var(--apple-gray); }
    #toc-sidebar {
        display: none;  /* hidden by default (mobile) */
    }
    @media (min-width: 1024px) {
        #post-toc-layout {
            display: flex;
            align-items: stretch;   /* sidebar stretches to match content height — required for sticky */
            gap: 1.5rem;
        }
        #toc-sidebar {
            display: block;
            width: 16rem;
            flex-shrink: 0;
        }
        #toc-sidebar-inner {
            position: sticky;
            top: 5rem;              /* sits just below fixed navbar (~64px) */
            max-height: calc(100vh - 5.5rem);
            overflow-y: auto;
        }
        #post-main-content {
            flex: 1 1 0%;
            min-width: 0;
        }
        #toc-mobile-btn {
            display: none !important;
        }
    }
    #toc-sidebar-inner > div {
      background: var(--reader-surface);
      border: 1px solid rgba(0, 0, 0, 0.04);
      border-radius: var(--apple-radius-md);
      box-shadow: var(--apple-shadow-card);
      padding: 1.25rem;
      transition: background-color 0.4s var(--apple-ease), border-color 0.4s var(--apple-ease);
    }
    .toc-card-label {
        font-size: 0.7rem; font-weight: 600; color: var(--apple-gray);
        text-transform: uppercase; letter-spacing: 0.09em; margin-bottom: 0.75rem; user-select: none;
    }

    #toc-sidebar .toc-link {
        display: block;
        font-size: 0.8rem;
        line-height: 1.6;
        color: var(--apple-gray);
        text-decoration: none;
        padding: 0.2rem 0.5rem;
        border-left: 2px solid transparent;
        transition: color 0.15s, border-color 0.15s, background-color 0.15s;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        max-width: 100%;
        border-radius: 0 8px 8px 0;
    }
    #toc-sidebar .toc-link:hover { color: var(--apple-blue); background-color: rgba(0, 113, 227, 0.08); }
    #toc-sidebar .toc-link.toc-active {
        color: var(--apple-blue);
        border-left-color: var(--apple-blue);
        font-weight: 500;
        background-color: rgba(0, 113, 227, 0.08);
    }
    #toc-sidebar .toc-h2 { font-weight: 500; color: var(--apple-text); }
    #toc-sidebar .toc-h3,
    #toc-sidebar .toc-h4 { font-size: 0.775rem; }

    /* Mobile TOC button */
    #toc-mobile-btn {
        position: fixed;
        bottom: 1.5rem;
        right: 1.5rem;
        z-index: 40;
        background: var(--apple-blue);
        color: #fff;
        border: none;
        border-radius: 9999px;
        width: 3rem;
        height: 3rem;
        box-shadow: 0 12px 28px rgba(0, 113, 227, 0.32);
        display: flex;
        align-items: center;
        justify-content: center;
        cursor: pointer;
        transition: background-color 0.2s ease, transform 0.2s var(--apple-ease);
    }
    #toc-mobile-btn:hover { background: var(--apple-blue-hover); transform: translateY(-1px); }

    /* Mobile drawer */
    #toc-mobile-backdrop {
        display: none;
        position: fixed;
        inset: 0;
        background: rgba(0, 0, 0, 0.45);
        -webkit-backdrop-filter: blur(4px);
        backdrop-filter: blur(4px);
        z-index: 40;
    }
    #toc-mobile-drawer {
        position: fixed;
        top: 0;
        left: 0;
        height: 100%;
        width: 18rem;
        max-width: 80vw;
        background: #fff;
        z-index: 50;
        box-shadow: var(--apple-shadow-lift);
        border-radius: 0 var(--apple-radius-md) var(--apple-radius-md) 0;
        overflow-y: auto;
        transform: translateX(-100%);
        transition: transform 0.35s var(--apple-ease);
    }
    #toc-nav-mobile .toc-link {
        display: block;
        font-size: 0.875rem;
        line-height: 1.7;
        color: var(--apple-text);
        text-decoration: none;
        padding: 0.3rem 0.5rem;
        border-left: 2px solid transparent;
        transition: color 0.15s, border-color 0.15s;
        border-radius: 0 8px 8px 0;
    }
    #toc-nav-mobile .toc-link:hover { color: var(--apple-blue); background-color: rgba(0, 113, 227, 0.08); }
    #toc-nav-mobile .toc-link.toc-active { color: var(--apple-blue); border-left-color: var(--apple-blue); font-weight: 500; }

    /* ============================================================
       Reader typography — 微信读书-style reading experience
       ============================================================ */
    /* Comfortable measure: ~68-75 chars per line */
    .post-article {
      font-size: var(--reader-font-size, 17px);
      line-height: var(--reader-line-height, 1.85);
      max-width: 46rem;
      margin-left: auto;
      margin-right: auto;
      transition: font-size 0.25s var(--apple-ease), line-height 0.25s var(--apple-ease);
    }
    .post-article * { font-family: var(--reader-font-family, inherit); }
    .post-article code, .post-article pre, .post-article code * {
      font-family: 'SF Mono', 'Monaco', 'Menlo', 'Cascadia Code', 'JetBrains Mono', Consolas, monospace !important;
    }
    .post-article h1, .post-article h2, .post-article h3, .post-article h4 {
      font-family: var(--reader-font-family, inherit);
      scroll-margin-top: 5.5rem;
    }
    .post-article table { font-size: 0.92em; }

    /* Font families */
    .reader-font-system  { --reader-font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "PingFang SC", "Noto Sans SC", "Microsoft YaHei", "Segoe UI", sans-serif; }
    .reader-font-serif   { --reader-font-family: "Songti SC", "Noto Serif SC", "Source Han Serif SC", "STSong", "SimSun", Georgia, "Times New Roman", serif; }
    .reader-font-hei     { --reader-font-family: "PingFang SC", "Noto Sans SC", "Source Han Sans SC", "Microsoft YaHei", "Heiti SC", "SimHei", sans-serif; }
    .reader-font-kai     { --reader-font-family: "Kaiti SC", "KaiTi", "STKaiti", "Noto Serif SC", "Songti SC", serif; }
    .reader-font-mono    { --reader-font-family: "SF Mono", "Menlo", "Monaco", "Cascadia Code", "JetBrains Mono", Consolas, monospace; }

    /* ============================================================
       Reading progress bar (top of viewport, below navbar)
       ============================================================ */
    #reading-progress {
      position: fixed;
      top: 0; left: 0;
      height: 3px;
      width: 0%;
      background: var(--reader-progress);
      border-radius: 0 3px 3px 0;
      z-index: 100;
      box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
      transition: width 0.12s linear;
      pointer-events: none;
    }

    /* ============================================================
       Aa reading toolbar
       ============================================================ */
    .reader-toolbar-btn {
      display: inline-flex; align-items: center; justify-content: center;
      width: 36px; height: 36px; border-radius: 50%;
      border: none; cursor: pointer;
      background: var(--reader-control);
      color: var(--apple-text);
      font-size: 0.95rem; font-weight: 700; letter-spacing: 0.02em;
      transition: background 0.25s ease, transform 0.2s var(--apple-ease), box-shadow 0.25s ease;
      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
    }
    .reader-toolbar-btn:hover { background: var(--reader-hover); transform: translateY(-1px); }
    .reader-toolbar-btn:active { transform: scale(0.94); }
    .reader-toolbar-btn.active { background: var(--apple-blue); color: #fff; }

    #reader-panel {
      position: fixed;
      right: 1.25rem;
      bottom: 5.75rem;
      z-index: 90;
      width: min(21rem, calc(100vw - 2rem));
      background: var(--reader-surface);
      border: 1px solid rgba(0, 0, 0, 0.07);
      border-radius: var(--apple-radius-md);
      box-shadow: var(--apple-shadow-lift);
      padding: 1.1rem 1.2rem 1.2rem;
      opacity: 0;
      transform: translateY(12px) scale(0.98);
      pointer-events: none;
      transition: opacity 0.28s var(--apple-ease), transform 0.28s var(--apple-ease);
    }
    #reader-panel.open {
      opacity: 1;
      transform: translateY(0) scale(1);
      pointer-events: auto;
    }
    .rp-section { margin-bottom: 1rem; }
    .rp-section:last-child { margin-bottom: 0; }
    .rp-label {
      font-size: 0.68rem; font-weight: 700; color: var(--apple-gray);
      text-transform: uppercase; letter-spacing: 0.1em; margin-bottom: 0.5rem;
    }
    /* Theme swatches */
    .rp-themes { display: flex; gap: 0.75rem; }
    .rp-swatch {
      width: 34px; height: 34px; border-radius: 50%;
      border: 2px solid transparent; cursor: pointer;
      position: relative; transition: transform 0.2s var(--apple-ease), border-color 0.2s ease;
    }
    .rp-swatch:hover { transform: scale(1.1); }
    .rp-swatch.active { border-color: var(--apple-blue); box-shadow: 0 0 0 3px rgba(0, 113, 227, 0.18); }
    .rp-swatch svg { position: absolute; inset: 0; margin: auto; width: 14px; height: 14px; color: #fff; opacity: 0; transition: opacity 0.2s; }
    .rp-swatch.active svg { opacity: 1; }
    .rp-swatch-light { background: #ffffff; border-color: #d1d1d6; }
    .rp-swatch-paper { background: #faf6ec; border-color: #ddd4c0; }
    .rp-swatch-green { background: #eef5ec; border-color: #c9dac4; }
    .rp-swatch-night { background: #1c1c22; border-color: #44444e; }
    /* Font chips */
    .rp-fonts { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.45rem; }
    .rp-font-chip {
      padding: 0.45rem 0.3rem; border-radius: var(--apple-radius-sm);
      border: 1px solid rgba(0, 0, 0, 0.08); background: var(--reader-surface-2);
      cursor: pointer; text-align: center; color: var(--apple-text);
      transition: border-color 0.2s, background 0.2s;
    }
    .rp-font-chip:hover { background: var(--reader-hover); }
    .rp-font-chip.active { border-color: var(--apple-blue); background: rgba(0, 113, 227, 0.08); }
    .rp-font-chip .rp-font-name { display: block; font-size: 1rem; line-height: 1.3; }
    .rp-font-chip .rp-font-meta { display: block; font-size: 0.62rem; color: var(--apple-gray); margin-top: 0.15rem; }
    .rp-font-chip[data-font="system"] .rp-font-name { font-family: -apple-system, "PingFang SC", sans-serif; }
    .rp-font-chip[data-font="serif"] .rp-font-name { font-family: "Songti SC", "Noto Serif SC", serif; }
    .rp-font-chip[data-font="hei"] .rp-font-name { font-family: "PingFang SC", "Heiti SC", "Microsoft YaHei", sans-serif; }
    .rp-font-chip[data-font="kai"] .rp-font-name { font-family: "Kaiti SC", "KaiTi", "STKaiti", serif; }
    .rp-font-chip[data-font="mono"] .rp-font-name { font-family: "SF Mono", Menlo, Consolas, monospace; }
    /* Size & spacing */
    .rp-row { display: flex; align-items: center; gap: 0.6rem; }
    .rp-size-btn {
      width: 38px; height: 38px; border-radius: 50%;
      border: 1px solid rgba(0, 0, 0, 0.1); background: var(--reader-surface-2);
      color: var(--apple-text); font-weight: 700; cursor: pointer;
      display: inline-flex; align-items: center; justify-content: center;
      transition: background 0.2s, transform 0.15s var(--apple-ease);
    }
    .rp-size-btn:hover { background: var(--reader-hover); }
    .rp-size-btn:active { transform: scale(0.92); }
    .rp-size-btn[data-action="dec"] { font-size: 0.85rem; }
    .rp-size-btn[data-action="inc"] { font-size: 1.15rem; }
    .rp-size-val { flex: 1; text-align: center; font-size: 0.85rem; color: var(--apple-gray); font-variant-numeric: tabular-nums; }
    .rp-spacing { display: flex; gap: 0.45rem; }
    .rp-spacing-btn {
      flex: 1; padding: 0.45rem 0; border-radius: var(--apple-radius-sm);
      border: 1px solid rgba(0, 0, 0, 0.08); background: var(--reader-surface-2);
      color: var(--apple-text); font-size: 0.75rem; cursor: pointer; text-align: center;
      transition: border-color 0.2s, background 0.2s;
    }
    .rp-spacing-btn:hover { background: var(--reader-hover); }
    .rp-spacing-btn.active { border-color: var(--apple-blue); background: rgba(0, 113, 227, 0.08); }
    .rp-reset {
      width: 100%; margin-top: 0.9rem; padding: 0.5rem;
      border-radius: var(--apple-radius-sm); border: 1px dashed rgba(0, 0, 0, 0.15);
      background: transparent; color: var(--apple-gray); font-size: 0.75rem; cursor: pointer;
      transition: color 0.2s, border-color 0.2s;
    }
    .rp-reset:hover { color: var(--apple-text); border-color: var(--apple-blue); }
    /* Backdrop for closing panel on outside click (invisible) */
    #reader-panel-backdrop {
      position: fixed; inset: 0; z-index: 85; display: none;
    }
    #reader-panel.open ~ #reader-panel-backdrop { display: block; }

    /* Aa button placement: inline in actions row (desktop) + floating (mobile) */
    .reader-toolbar-wrap { display: inline-flex; align-items: center; }
    #reader-fab {
      display: none;
      position: fixed;
      bottom: 5.75rem; right: 1.5rem;
      z-index: 41;
      width: 3rem; height: 3rem;
      border-radius: 9999px;
      background: var(--apple-blue); color: #fff;
      border: none; cursor: pointer;
      font-size: 1.1rem; font-weight: 800;
      box-shadow: 0 12px 28px rgba(0, 113, 227, 0.32);
      align-items: center; justify-content: center;
      transition: background-color 0.2s ease, transform 0.2s var(--apple-ease);
    }
    #reader-fab:hover { transform: translateY(-1px); }
    @media (max-width: 1023px) {
      #reader-fab { display: flex; }
      #reader-panel {
        bottom: 9.25rem;
        right: 1.25rem;
      }
    }
    @media (max-width: 640px) {
      #reader-panel {
        left: 1rem;
        right: 1rem;
        width: auto;
        bottom: 9.4rem;
      }
    }
    /* Scroll-to-top mini button */
    #back-to-top {
      display: none;
      position: fixed;
      bottom: 1.5rem; left: 1.5rem;
      z-index: 41;
      width: 2.75rem; height: 2.75rem;
      border-radius: 9999px;
      border: 1px solid rgba(0, 0, 0, 0.08);
      background: var(--reader-surface);
      color: var(--apple-gray);
      box-shadow: var(--apple-shadow-card);
      cursor: pointer;
      align-items: center; justify-content: center;
      transition: opacity 0.3s ease, transform 0.2s var(--apple-ease), color 0.2s;
    }
    #back-to-top:hover { color: var(--apple-blue); transform: translateY(-1px); }
    #back-to-top.visible { display: flex; }
    @media (min-width: 1024px) {
      #back-to-top { display: none !important; }
    }
    /* Night theme tweaks for controls */
    body.reader-night .rp-size-btn,
    body.reader-night .rp-spacing-btn,
    body.reader-night .rp-font-chip {
      background: var(--reader-control);
    }
    body.reader-night .action-btn-secondary { background: var(--reader-control); }
    body.reader-night .apple-btn-secondary { background: var(--reader-control); color: var(--apple-text); }
    body.reader-night .post-timestamps { background: var(--reader-control); }
    body.reader-night .post-summary { border-left-color: rgba(77, 159, 255, 0.4); }
    body.reader-night .think-header { background: var(--reader-control); }
    body.reader-night .think-header:hover { background: var(--reader-hover); }
    body.reader-night .think-panel { background: var(--reader-surface); }
    body.reader-night .append-textarea { background: var(--reader-control); color: var(--apple-text); }
    body.reader-night .append-textarea:focus { background: var(--reader-surface-2); }
    body.reader-night .audio-player { background: var(--reader-surface-2); }
    body.reader-night .voice-controls { background: var(--reader-surface-2); }
    body.reader-night .voice-select-compact,
    body.reader-night .custom-voice-input { background: var(--reader-control); color: var(--apple-text); }
    body.reader-night .toc-mobile-btn-back { background: var(--reader-control); }
    body.reader-night #toc-sidebar .toc-h3,
    body.reader-night #toc-sidebar .toc-h4,
    body.reader-night #toc-nav-mobile .toc-h3,
    body.reader-night #toc-nav-mobile .toc-h4 { color: #a5a5b0; }
    body.reader-night .post-summary p { color: #a5a5b0; }
    body.reader-night .prose blockquote { color: #a9a9b4; }
    /* Reveal animation on load */
    @keyframes readerFadeIn {
      from { opacity: 0; transform: translateY(10px); }
      to   { opacity: 1; transform: translateY(0); }
    }
    .main-content { animation: readerFadeIn 0.5s var(--apple-ease) both; }

</style>
{% endblock %}

{% block content %}
<!-- Reading progress bar -->
<div id="reading-progress" aria-hidden="true"></div>

<!-- Delete Confirmation Modal -->
<div id="deleteModal" class="modal" aria-labelledby="modal-title" role="dialog" aria-modal="true">
    <div class="modal-content">
        <div class="p-6">
            <h3 class="text-lg font-semibold" style="color: var(--apple-text);" id="modal-title">
                {% trans "Delete Post" %}
            </h3>
            <p class="mt-2 text-sm" style="color: var(--apple-gray);">
                {% trans "Are you sure you want to delete this post? This action cannot be undone." %}
            </p>
            <div class="mt-6 flex gap-3">
                <form method="post" action="{% url 'post-delete' post.pk %}">
                    {% csrf_token %}
                    <button type="submit" class="apple-btn" style="background: var(--apple-red); color: #fff; box-shadow: 0 6px 18px rgba(255, 59, 48, 0.28);">
                        {% trans "Delete" %}
                    </button>
                </form>
                <button type="button"
                        onclick="closeDeleteModal()"
                        class="apple-btn apple-btn-secondary">
                    {% trans "Cancel" %}
                </button>
            </div>
        </div>
    </div>
</div>



<!-- Two-column layout: sticky TOC sidebar + main content -->
<div id="post-toc-layout">

    <!-- TOC Sidebar (desktop only, sticky, populated by JS) -->
    <aside id="toc-sidebar">
        <div id="toc-sidebar-inner">
            <div>
                <p class="toc-card-label">{% trans "Contents" %}</p>
                <nav id="toc-nav"></nav>
            </div>
        </div>
    </aside>

    <!-- Main Content -->
    <div class="main-content" id="post-main-content">
    <!-- Title and Actions -->
    <div class="post-header-row">
        <h1 class="post-title">{{ post.title }}</h1>

        <!-- Action Buttons -->
        <div class="post-actions">
                    <div class="reader-toolbar-wrap">
                        <button id="reader-toolbar-btn" onclick="toggleReaderPanel()" class="reader-toolbar-btn"
                                title="{% trans 'Reading settings' %}" aria-label="{% trans 'Reading settings' %}">Aa</button>
                    </div>
                    <button onclick="toggleTTS()" class="action-btn action-btn-purple">
                        <svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
                                  d="M15.536 8.464a5 5 0 010 7.072m2.828-9.9a9 9 0 010 14.142M9 9v6l4-3-4-3z"/>
                        </svg>
                        <span id="tts-button-text">{% trans "Listen" %}</span>
                    </button>
                    <a href="{% url 'post-update' post.pk %}" class="action-btn action-btn-blue">
                        <svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
                                  d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/>
                        </svg>
                        {% trans "Edit" %}
                    </a>
                    <!-- Share widget -->
                    <div x-data="shareWidget()" x-init="init()" class="relative">
                      <!-- Not yet shared -->
                      <button x-show="!isPublic" @click="enableShare()"
                              :disabled="busy"
                              class="action-btn action-btn-green">
                        <svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
                          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
                            d="M8.684 13.342C8.886 12.938 9 12.482 9 12c0-.482-.114-.938-.316-1.342m0 2.684a3 3 0 110-2.684m0 2.684l6.632 3.316m-6.632-6l6.632-3.316m0 0a3 3 0 105.367-2.684 3 3 0 00-5.367 2.684zm0 9.316a3 3 0 105.368 2.684 3 3 0 00-5.368-2.684z"/>
                        </svg>
                        {% trans "Share" %}
                      </button>
                      <!-- Already shared: copy + revoke -->
                      <div x-show="isPublic" class="flex items-center gap-1">
                        <button @click="copyUrl()" class="action-btn action-btn-green">
                          <svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
                              d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1"/>
                          </svg>
                          <span x-text="copied ? '{% trans "Copied!" %}' : '{% trans "Shared" %}'"></span>
                        </button>
                        <button @click="revokeShare()" :disabled="busy"
                                title="{% trans 'Revoke public access' %}"
                                class="action-icon-btn">
                          <svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
                          </svg>
                        </button>
                      </div>
                    </div>
                    <button onclick="openDeleteModal()" class="action-btn action-btn-red">
                        <svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
                                  d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/>
                        </svg>
                        {% trans "Delete" %}
                    </button>
                </div>
            </div>

            <!-- Metadata -->
            <div class="post-meta">

                {% if post.summary %}
                <div class="post-summary">
                    <p>{{ post.summary }}</p>
                </div>
                {% endif %}

                <!-- Tags -->
                {% if post.tags.exists %}
                <div class="post-tags">
                    {% for tag in post.tags.all %}
                    {% with number=forloop.counter %}
                    <a href="{% url 'tag-detail' tag.slug %}"
                       class="inline-flex items-center px-3 py-1 rounded-full text-xs font-medium transition duration-150 {% if number|divisibleby:10 %}tag-10{% elif number|divisibleby:9 %}tag-9{% elif number|divisibleby:8 %}tag-8{% elif number|divisibleby:7 %}tag-7{% elif number|divisibleby:6 %}tag-6{% elif number|divisibleby:5 %}tag-5{% elif number|divisibleby:4 %}tag-4{% elif number|divisibleby:3 %}tag-3{% elif number|divisibleby:2 %}tag-2{% else %}tag-1{% endif %}">
                        {{ tag.name }}
                    </a>
                    {% endwith %}
                    {% endfor %}
                </div>
                {% endif %}

                <!-- Timestamps -->
                <div class="post-timestamps">
                    <div class="timestamp-item">
                        <svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
                                  d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"/>
                        </svg>
                        <span class="timestamp-label">{% trans "Created" %}:</span>
                        <time datetime="{{ post.created_at|date:'Y-m-d H:i' }}">{{ post.created_at|date:"Y-m-d H:i" }}</time>
                    </div>
                    <div class="timestamp-item">
                        <svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
                                  d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/>
                        </svg>
                        <span class="timestamp-label">{% trans "Updated" %}:</span>
                        <time datetime="{{ post.updated_at|date:'Y-m-d H:i' }}">{{ post.updated_at|date:"Y-m-d H:i" }}</time>
                    </div>
                </div>
            </div>

            <!-- TTS Audio Player - Initially Hidden -->
            <div id="tts-player" class="mt-4 audio-player hidden">
                <div class="flex items-center justify-between mb-3">
                    <h4 class="text-sm font-medium" style="color: var(--apple-text);">{% trans "Audio Player" %}</h4>
                    <div id="tts-status" class="audio-status status-ready">{% trans "Ready" %}</div>
                </div>

                <!-- Voice Selection Controls -->
                <div class="voice-controls">
                    <span class="voice-label">{% trans "Voice:" %}</span>
                    <select id="post-voice-select" class="voice-select-compact" onchange="handlePostVoiceChange()">
                        <option value="zh-CN-XiaoxiaoNeural">Xiaoxiao (Female)</option>
                        <option value="zh-CN-YunxiNeural">Yunxi (Male)</option>
                        <option value="zh-CN-YunjianNeural">Yunjian (Male)</option>
                        <option value="zh-CN-XiaoyiNeural">Xiaoyi (Female)</option>
                        <option value="zh-CN-YunyangNeural">Yunyang (Male)</option>
                        <option value="zh-CN-XiaochenNeural">Xiaochen (Female)</option>
                        <option value="zh-CN-XiaohanNeural">Xiaohan (Female)</option>
                        <option value="zh-CN-XiaomengNeural" selected>Xiaomeng (Female)</option>
                        <option value="zh-CN-XiaomoNeural">Xiaomo (Female)</option>
                        <option value="zh-CN-XiaoqiuNeural">Xiaoqiu (Female)</option>
                        <option value="zh-CN-XiaorouNeural">Xiaorou (Female)</option>
                        <option value="zh-CN-YunyeNeural">Yunye (Male)</option>
                        <option value="zh-CN-XiaoshuangNeural">Xiaoshuang (Female, Child)</option>
                        <option value="en-US-EmmaNeural">Emma (Female)</option>
                        <option value="en-US-AndrewNeural">Andrew (Male)</option>
                        <option value="custom">{% trans "Custom" %}</option>
                    </select>
                    <button onclick="regenerateWithVoice()" id="regenerate-btn"
                            class="action-btn action-btn-purple"
                            disabled>
                        {% trans "Apply Voice" %}
                    </button>
                </div>

                <!-- Custom Voice Input (hidden by default) -->
                <div id="post-custom-voice-container" class="mb-3" style="display: none;">
                    <input
                        type="text"
                        id="post-custom-voice-input"
                        class="custom-voice-input"
                        placeholder="{% trans 'e.g., zh-CN-XiaoxiaoNeural' %}"
                        maxlength="100">
                    <div class="text-xs mt-1" style="color: var(--apple-gray);">
                        {% trans "Enter the voice code you want to use" %}
                    </div>
                </div>

                <!-- Audio Controls -->
                <div class="space-y-4">
                    <audio id="tts-audio" class="hidden" preload="none">
                        Your browser does not support the audio element.
                    </audio>

                    <!-- Progress Bar -->
                    <div class="progress-container">
                        <div id="progress-bar" class="progress-bar" style="width: 0%"></div>
                        <input id="seek-slider" type="range" min="0" max="100" value="0" class="seek-slider">
                    </div>

                    <!-- Control Buttons and Time -->
                    <div class="flex items-center justify-between">
                        <div class="audio-controls">
                            <button id="play-pause-btn" onclick="togglePlayPause()"
                                    class="play-pause-btn"
                                    disabled>
                                <svg id="play-icon" class="w-6 h-6" fill="currentColor" viewBox="0 0 20 20">
                                    <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z" clip-rule="evenodd"/>
                                </svg>
                                <svg id="pause-icon" class="w-6 h-6 hidden" fill="currentColor" viewBox="0 0 20 20">
                                    <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zM7 8a1 1 0 012 0v4a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v4a1 1 0 102 0V8a1 1 0 00-1-1z" clip-rule="evenodd"/>
                                </svg>
                            </button>

                            <button onclick="stopAudio()" class="stop-btn">
                                <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
                                    <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8 7a1 1 0 00-1 1v4a1 1 0 001 1h4a1 1 0 001-1V8a1 1 0 00-1-1H8z" clip-rule="evenodd"/>
                                </svg>
                            </button>

                            <button id="speed-btn" onclick="toggleSpeed()" class="speed-btn" title="{% trans 'Playback Speed' %}">
                                1x
                            </button>
                        </div>

                        <div class="audio-time">
                            <span id="current-time">0:00</span> / <span id="total-time">0:00</span>
                        </div>
                    </div>
                </div>
            </div>

    <!-- Content Section -->
    <article id="post-article" class="prose max-w-none prose-lg post-article">
        {% markdown_with_tasks post.content post.task_states %}
    </article>

    <!-- Append Content Section -->
    <div class="append-section">
        <h3 class="append-title">{% trans "Append Content" %}</h3>
        <textarea id="append-content-input"
            class="append-textarea"
            placeholder="{% trans 'Write markdown to append...' %}"></textarea>
        <div class="append-footer">
            <span id="append-status" class="append-status"></span>
            <button id="append-btn" onclick="appendContent()" class="apple-btn apple-btn-primary">
                {% trans "Append" %}
            </button>
        </div>
    </div><!-- end post-main-content -->
</div><!-- end post-toc-layout -->

<!-- Mobile TOC floating button -->
<button id="toc-mobile-btn" title="Table of Contents" aria-label="Table of Contents">
    <svg width="20" height="20" fill="none" stroke="currentColor" viewBox="0 0 24 24">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h7"/>
    </svg>
</button>

<!-- Mobile Aa floating button -->
<button id="reader-fab" onclick="toggleReaderPanel()" title="{% trans 'Reading settings' %}" aria-label="{% trans 'Reading settings' %}">Aa</button>

<!-- Reader settings panel -->
<div id="reader-panel" role="dialog" aria-label="{% trans 'Reading settings' %}">
    <div class="rp-section">
        <p class="rp-label">{% trans "Theme" %}</p>
        <div class="rp-themes">
            <button class="rp-swatch rp-swatch-light" data-theme="light" onclick="setReaderTheme('light')" title="{% trans 'Light' %}">
                <svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M5 13l4 4L19 7"/></svg>
            </button>
            <button class="rp-swatch rp-swatch-paper" data-theme="paper" onclick="setReaderTheme('paper')" title="{% trans 'Paper' %}">
                <svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M5 13l4 4L19 7"/></svg>
            </button>
            <button class="rp-swatch rp-swatch-green" data-theme="green" onclick="setReaderTheme('green')" title="{% trans 'Green' %}">
                <svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M5 13l4 4L19 7"/></svg>
            </button>
            <button class="rp-swatch rp-swatch-night" data-theme="night" onclick="setReaderTheme('night')" title="{% trans 'Night' %}">
                <svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M5 13l4 4L19 7"/></svg>
            </button>
        </div>
    </div>

    <div class="rp-section">
        <p class="rp-label">{% trans "Font" %}</p>
        <div class="rp-fonts">
            <button class="rp-font-chip" data-font="system" onclick="setReaderFont('system')">
                <span class="rp-font-name">系统</span><span class="rp-font-meta">System</span>
            </button>
            <button class="rp-font-chip" data-font="serif" onclick="setReaderFont('serif')">
                <span class="rp-font-name">宋体</span><span class="rp-font-meta">Serif</span>
            </button>
            <button class="rp-font-chip" data-font="hei" onclick="setReaderFont('hei')">
                <span class="rp-font-name">黑体</span><span class="rp-font-meta">Sans</span>
            </button>
            <button class="rp-font-chip" data-font="kai" onclick="setReaderFont('kai')">
                <span class="rp-font-name">楷体</span><span class="rp-font-meta">Kai</span>
            </button>
            <button class="rp-font-chip" data-font="mono" onclick="setReaderFont('mono')">
                <span class="rp-font-name">等宽</span><span class="rp-font-meta">Mono</span>
            </button>
        </div>
    </div>

    <div class="rp-section">
        <p class="rp-label">{% trans "Size" %}</p>
        <div class="rp-row">
            <button class="rp-size-btn" data-action="dec" onclick="changeReaderSize(-1)" aria-label="{% trans 'Smaller' %}">A−</button>
            <span class="rp-size-val" id="rp-size-val">17px</span>
            <button class="rp-size-btn" data-action="inc" onclick="changeReaderSize(1)" aria-label="{% trans 'Larger' %}">A+</button>
        </div>
    </div>

    <div class="rp-section">
        <p class="rp-label">{% trans "Spacing" %}</p>
        <div class="rp-spacing">
            <button class="rp-spacing-btn" data-spacing="1.6" onclick="setReaderSpacing(1.6)">{% trans "Compact" %}</button>
            <button class="rp-spacing-btn" data-spacing="1.85" onclick="setReaderSpacing(1.85)">{% trans "Cozy" %}</button>
            <button class="rp-spacing-btn" data-spacing="2.15" onclick="setReaderSpacing(2.15)">{% trans "Relaxed" %}</button>
        </div>
    </div>

    <button class="rp-reset" onclick="resetReaderPrefs()">↺ {% trans "Reset to defaults" %}</button>
</div>
<div id="reader-panel-backdrop" onclick="closeReaderPanel()"></div>

<!-- Back to top -->
<button id="back-to-top" onclick="window.scrollTo({top: 0, behavior: 'smooth'})" aria-label="{% trans 'Back to top' %}">
    <svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M5 15l7-7 7 7"/>
    </svg>
</button>

<!-- Mobile TOC backdrop -->
<div id="toc-mobile-backdrop" aria-hidden="true"></div>

<!-- Mobile TOC drawer -->
<div id="toc-mobile-drawer">
    <div style="padding:1.25rem;">
        <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:1rem;padding-bottom:0.75rem;border-bottom:1px solid var(--apple-separator);">
            <p style="font-weight:600;color:var(--apple-text);margin:0;">{% trans "Contents" %}</p>
            <button id="toc-mobile-close" class="action-icon-btn" style="color: var(--apple-gray);" aria-label="Close">
                <svg width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
                </svg>
            </button>
        </div>
        <nav id="toc-nav-mobile"></nav>
    </div>
</div>
{% endblock %}

{% block extra_js %}
<script>
function shareWidget() {
    return {
        isPublic: {{ post.is_public|yesno:"true,false" }},
        publicUrl: '{{ request.build_absolute_uri }}' .replace('/ui/posts/{{ post.pk }}/', '/public/posts/{{ post.pk }}/'),
        busy: false,
        copied: false,
        init() {
            // Compute the actual public URL from the current origin
            this.publicUrl = window.location.origin + '{% url "public-post" post.pk %}';
        },
        async _toggle(enable) {
            this.busy = true;
            try {
                const resp = await fetch('{% url "post-share" post.pk %}', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'X-CSRFToken': document.cookie.match(/csrftoken=([^;]+)/)?.[1] || '',
                    },
                    body: JSON.stringify({ enable }),
                });
                const data = await resp.json();
                this.isPublic = data.is_public;
                if (data.url) this.publicUrl = data.url;
            } finally {
                this.busy = false;
            }
        },
        enableShare() { this._toggle(true); },
        revokeShare() { this._toggle(false); },
        async copyUrl() {
            try {
                await navigator.clipboard.writeText(this.publicUrl);
                this.copied = true;
                setTimeout(() => { this.copied = false; }, 2000);
            } catch(e) {
                window.open(this.publicUrl, '_blank');
            }
        },
    };
}

</script>
<script>
function openDeleteModal() {
    document.getElementById('deleteModal').classList.add('show');
    document.body.style.overflow = 'hidden';
}

function closeDeleteModal() {
    document.getElementById('deleteModal').classList.remove('show');
    document.body.style.overflow = 'auto';
}

// Close modal when clicking outside
document.getElementById('deleteModal').addEventListener('click', function(e) {
    if (e.target === this) {
        closeDeleteModal();
    }
});

// Close modal on escape key
document.addEventListener('keydown', function(e) {
    if (e.key === 'Escape') {
        closeDeleteModal();
    }
});

// Think Panel functionality
document.addEventListener('DOMContentLoaded', function() {
    document.querySelectorAll('.think-header').forEach(header => {
        header.addEventListener('click', function() {
            const panel = this.parentElement;
            const content = panel.querySelector('.think-content');
            const icon = panel.querySelector('.think-icon');

            content.classList.toggle('expanded');
            icon.classList.toggle('expanded');
        });
    });

    // Task checkbox functionality
    document.querySelectorAll('.task-checkbox').forEach(checkbox => {
        checkbox.addEventListener('change', async function(e) {
            const taskHash = this.getAttribute('data-hash');
            const postId = {{ post.id }};

            try {
                const response = await fetch(`/api/posts/${postId}/toggle_task/`, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    body: JSON.stringify({ task_hash: taskHash })
                });

                if (!response.ok) {
                    // Revert checkbox if request failed
                    this.checked = !this.checked;
                    console.error('Failed to update task state');
                }
            } catch (error) {
                // Revert checkbox if request failed
                this.checked = !this.checked;
                console.error('Error updating task:', error);
            }
        });
    });

    // Initialize voice selection event listeners
    const customVoiceInput = document.getElementById('post-custom-voice-input');
    const regenerateBtn = document.getElementById('regenerate-btn');

    if (customVoiceInput && regenerateBtn) {
        customVoiceInput.addEventListener('input', function() {
            const voiceSelect = document.getElementById('post-voice-select');
            if (voiceSelect.value === 'custom') {
                regenerateBtn.disabled = !this.value.trim();
            }
        });
    }
});

// TTS Functionality
let currentAudio = null;
let isLoading = false;
let playbackSpeeds = [1, 1.25, 1.5, 2];
let currentSpeedIndex = 0;

function toggleTTS() {
    const player = document.getElementById('tts-player');
    const buttonText = document.getElementById('tts-button-text');

    if (player.classList.contains('hidden')) {
        player.classList.remove('hidden');
        buttonText.textContent = '{% trans "Hide" %}';

        if (!currentAudio) {
            loadTTSAudio();
        }
    } else {
        player.classList.add('hidden');
        buttonText.textContent = '{% trans "Listen" %}';

        if (currentAudio) {
            currentAudio.pause();
        }
    }
}

function loadTTSAudio(voiceOverride = null) {
    if (isLoading) return;

    isLoading = true;
    const status = document.getElementById('tts-status');
    const playBtn = document.getElementById('play-pause-btn');

    status.textContent = '{% trans "Generating..." %}';
    status.className = 'audio-status status-generating';
    playBtn.disabled = true;

    // Get voice parameter
    let voice = voiceOverride;
    if (!voice) {
        const voiceSelect = document.getElementById('post-voice-select');
        if (voiceSelect.value === 'custom') {
            const customInput = document.getElementById('post-custom-voice-input');
            voice = customInput.value.trim();
        } else {
            voice = voiceSelect.value;
        }
    }

    const requestBody = voice ? JSON.stringify({ voice: voice }) : null;

    fetch('{% url "post-tts" post.pk %}', {
        method: 'POST',
        headers: {
            'X-CSRFToken': '{{ csrf_token }}',
            'Content-Type': 'application/json',
        },
        body: requestBody
    })
    .then(response => {
        if (!response.ok) {
            throw new Error('TTS generation failed');
        }
        return response.blob();
    })
    .then(blob => {
        const audioUrl = URL.createObjectURL(blob);
        const audio = document.getElementById('tts-audio');

        audio.src = audioUrl;
        currentAudio = audio;

        audio.addEventListener('loadedmetadata', function() {
            status.textContent = '{% trans "Ready" %}';
            status.className = 'audio-status status-ready';
            playBtn.disabled = false;
            updateTotalTime();
            setupAudioEvents();
        });

        audio.addEventListener('error', function() {
            status.textContent = '{% trans "Error" %}';
            status.className = 'audio-status status-error';
            playBtn.disabled = true;
        });

        audio.load();
    })
    .catch(error => {
        console.error('TTS Error:', error);
        status.textContent = '{% trans "Failed" %}';
        status.className = 'audio-status status-error';
        playBtn.disabled = true;
    })
    .finally(() => {
        isLoading = false;
    });
}

function setupAudioEvents() {
    if (!currentAudio) return;

    currentAudio.addEventListener('timeupdate', updateProgress);
    currentAudio.addEventListener('ended', onAudioEnded);

    // Set initial playback rate
    currentAudio.playbackRate = playbackSpeeds[currentSpeedIndex];

    // Seek functionality
    const seekSlider = document.getElementById('seek-slider');
    seekSlider.addEventListener('input', function() {
        if (currentAudio) {
            const seekTime = (this.value / 100) * currentAudio.duration;
            currentAudio.currentTime = seekTime;
        }
    });
}

function togglePlayPause() {
    if (!currentAudio) return;

    const playIcon = document.getElementById('play-icon');
    const pauseIcon = document.getElementById('pause-icon');
    const status = document.getElementById('tts-status');

    if (currentAudio.paused) {
        currentAudio.play();
        playIcon.classList.add('hidden');
        pauseIcon.classList.remove('hidden');
        status.textContent = '{% trans "Playing" %}';
        status.className = 'audio-status status-playing';
    } else {
        currentAudio.pause();
        playIcon.classList.remove('hidden');
        pauseIcon.classList.add('hidden');
        status.textContent = '{% trans "Paused" %}';
        status.className = 'audio-status status-paused';
    }
}

function stopAudio() {
    if (!currentAudio) return;

    currentAudio.pause();
    currentAudio.currentTime = 0;

    const playIcon = document.getElementById('play-icon');
    const pauseIcon = document.getElementById('pause-icon');
    const status = document.getElementById('tts-status');

    playIcon.classList.remove('hidden');
    pauseIcon.classList.add('hidden');
    status.textContent = '{% trans "Stopped" %}';
    status.className = 'audio-status status-stopped';

    updateProgress();
}

function toggleSpeed() {
    if (!currentAudio) return;

    // Cycle through speeds
    currentSpeedIndex = (currentSpeedIndex + 1) % playbackSpeeds.length;
    const newSpeed = playbackSpeeds[currentSpeedIndex];

    // Update audio playback rate
    currentAudio.playbackRate = newSpeed;

    // Update button text
    const speedBtn = document.getElementById('speed-btn');
    speedBtn.textContent = newSpeed + 'x';

    // Visual feedback
    speedBtn.style.transform = 'scale(1.1)';
    setTimeout(() => {
        speedBtn.style.transform = '';
    }, 150);
}

function updateProgress() {
    if (!currentAudio) return;

    const progress = (currentAudio.currentTime / currentAudio.duration) * 100;
    document.getElementById('progress-bar').style.width = progress + '%';
    document.getElementById('seek-slider').value = progress;

    document.getElementById('current-time').textContent = formatTime(currentAudio.currentTime);
}

function updateTotalTime() {
    if (!currentAudio) return;

    document.getElementById('total-time').textContent = formatTime(currentAudio.duration);
}

function onAudioEnded() {
    const playIcon = document.getElementById('play-icon');
    const pauseIcon = document.getElementById('pause-icon');
    const status = document.getElementById('tts-status');

    playIcon.classList.remove('hidden');
    pauseIcon.classList.add('hidden');
    status.textContent = '{% trans "Finished" %}';
    status.className = 'audio-status status-finished';

    // Reset speed to 1x when audio ends
    currentSpeedIndex = 0;
    const speedBtn = document.getElementById('speed-btn');
    speedBtn.textContent = '1x';
    if (currentAudio) {
        currentAudio.playbackRate = 1;
    }
}

function formatTime(seconds) {
    if (isNaN(seconds)) return '0:00';

    const mins = Math.floor(seconds / 60);
    const secs = Math.floor(seconds % 60);
    return mins + ':' + (secs < 10 ? '0' : '') + secs;
}

// Voice selection handling functions
function handlePostVoiceChange() {
    const voiceSelect = document.getElementById('post-voice-select');
    const customContainer = document.getElementById('post-custom-voice-container');
    const customInput = document.getElementById('post-custom-voice-input');
    const regenerateBtn = document.getElementById('regenerate-btn');

    if (voiceSelect.value === 'custom') {
        customContainer.style.display = 'block';
        customInput.focus();

        // Enable regenerate button only if custom input has value
        regenerateBtn.disabled = !customInput.value.trim();
    } else {
        customContainer.style.display = 'none';
        // Enable regenerate button for predefined voices
        regenerateBtn.disabled = false;
    }
}

async function appendContent() {
    const input = document.getElementById('append-content-input');
    const btn = document.getElementById('append-btn');
    const status = document.getElementById('append-status');
    const extra = input.value.trim();

    if (!extra) return;

    btn.disabled = true;
    status.textContent = '{% trans "Saving..." %}';

    try {
        const response = await fetch(`/api/posts/{{ post.id }}/append_content`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ content: extra })
        });

        if (response.ok) {
            window.location.reload();
        } else {
            const err = await response.json();
            status.textContent = '{% trans "Error: " %}' + (err.error || err.detail || JSON.stringify(err));
            btn.disabled = false;
        }
    } catch (e) {
        status.textContent = '{% trans "Network error" %}';
        btn.disabled = false;
    }
}

function regenerateWithVoice() {
    const voiceSelect = document.getElementById('post-voice-select');
    const customInput = document.getElementById('post-custom-voice-input');
    const regenerateBtn = document.getElementById('regenerate-btn');

    let voice;
    if (voiceSelect.value === 'custom') {
        voice = customInput.value.trim();
        if (!voice) {
            alert('{% trans "Please enter a custom voice" %}');
            return;
        }
    } else {
        voice = voiceSelect.value;
    }

    // Disable the regenerate button temporarily
    const originalText = regenerateBtn.textContent;
    regenerateBtn.disabled = true;
    regenerateBtn.textContent = '{% trans "Applying..." %}';

    // Stop current audio if playing
    if (currentAudio && !currentAudio.paused) {
        currentAudio.pause();
    }

    // Clear current audio
    currentAudio = null;

    // Load new audio with selected voice
    loadTTSAudio(voice);

    // Re-enable and reset button after a delay
    setTimeout(() => {
        regenerateBtn.disabled = true; // Keep disabled until next voice change
        regenerateBtn.textContent = originalText;
    }, 2000);
}

// ============================================================
// Table of Contents
// ============================================================
(function() {
    function buildTOC() {
        const article = document.querySelector('article.prose');
        if (!article) return;

        const headings = article.querySelectorAll('h2, h3, h4');
        if (headings.length < 2) {
            // Not enough headings - hide TOC sidebar and mobile button
            const sidebar = document.getElementById('toc-sidebar');
            const mobileBtn = document.getElementById('toc-mobile-btn');
            if (sidebar) sidebar.style.display = 'none';
            if (mobileBtn) mobileBtn.style.display = 'none';
            return;
        }

        function createLinks(navEl) {
            navEl.innerHTML = '';
            headings.forEach(function(heading) {
                // Ensure heading has an id (toc extension adds these, but fallback just in case)
                if (!heading.id) {
                    heading.id = heading.textContent.trim()
                        .toLowerCase()
                        .replace(/[^\w\s-]/g, '')
                        .replace(/\s+/g, '-')
                        .replace(/-+/g, '-');
                }
                const level = parseInt(heading.tagName[1]); // 2, 3, or 4
                const link = document.createElement('a');
                link.href = '#' + heading.id;
                link.textContent = heading.textContent;
                link.classList.add('toc-link', 'toc-h' + level);
                link.setAttribute('data-heading-id', heading.id);

                // Visual indentation by heading level
                link.style.paddingLeft = ((level - 2) * 12 + 8) + 'px';

                link.addEventListener('click', function(e) {
                    e.preventDefault();
                    closeMobileDrawer();
                    const target = document.getElementById(heading.id);
                    if (target) {
                        const nav = document.getElementById('main-nav');
                        const navH = nav ? nav.offsetHeight : 70;
                        const y = target.getBoundingClientRect().top + window.scrollY - navH - 16;
                        window.scrollTo({ top: y, behavior: 'smooth' });
                    }
                });
                navEl.appendChild(link);
            });
        }

        const tocNav = document.getElementById('toc-nav');
        const tocNavMobile = document.getElementById('toc-nav-mobile');
        if (tocNav) createLinks(tocNav);
        if (tocNavMobile) createLinks(tocNavMobile);

        // Scroll-spy: find the heading whose top is closest above the viewport threshold
        var _rafPending = false;
        function onScroll() {
            if (_rafPending) return;
            _rafPending = true;
            requestAnimationFrame(function() {
                _rafPending = false;
                var nav = document.getElementById('main-nav');
                var navH = nav ? nav.offsetHeight : 64;
                var threshold = navH + 24; // a bit below the navbar
                var activeId = null;
                // Walk headings in reverse: pick the last one whose top <= threshold
                for (var i = headings.length - 1; i >= 0; i--) {
                    var rect = headings[i].getBoundingClientRect();
                    if (rect.top <= threshold) {
                        activeId = headings[i].id;
                        break;
                    }
                }
                // If none is above threshold, highlight the first heading
                if (!activeId && headings.length > 0) activeId = headings[0].id;
                highlightTOC(activeId);
                // Auto-scroll the active TOC link into view within the sidebar
                var activeLinkInSidebar = document.querySelector('#toc-nav .toc-link.toc-active');
                if (activeLinkInSidebar) {
                    var sidebarInner = document.getElementById('toc-sidebar-inner');
                    if (sidebarInner) {
                        var linkTop = activeLinkInSidebar.offsetTop;
                        var linkH = activeLinkInSidebar.offsetHeight;
                        var scrollTop = sidebarInner.scrollTop;
                        var sidebarH = sidebarInner.clientHeight;
                        if (linkTop < scrollTop) {
                            sidebarInner.scrollTop = linkTop - 8;
                        } else if (linkTop + linkH > scrollTop + sidebarH) {
                            sidebarInner.scrollTop = linkTop + linkH - sidebarH + 8;
                        }
                    }
                }
            });
        }
        window.addEventListener('scroll', onScroll, { passive: true });
        onScroll(); // run once on load

        function highlightTOC(id) {
            document.querySelectorAll('.toc-link').forEach(function(a) {
                if (id && a.getAttribute('data-heading-id') === id) {
                    a.classList.add('toc-active');
                } else {
                    a.classList.remove('toc-active');
                }
            });
        }
    }

    function openMobileDrawer() {
        const drawer = document.getElementById('toc-mobile-drawer');
        const backdrop = document.getElementById('toc-mobile-backdrop');
        if (drawer) drawer.style.transform = 'translateX(0)';
        if (backdrop) backdrop.classList.remove('hidden');
        document.body.style.overflow = 'hidden';
    }

    function closeMobileDrawer() {
        const drawer = document.getElementById('toc-mobile-drawer');
        const backdrop = document.getElementById('toc-mobile-backdrop');
        if (drawer) drawer.style.transform = 'translateX(-100%)';
        if (backdrop) backdrop.classList.add('hidden');
        document.body.style.overflow = '';
    }

    document.addEventListener('DOMContentLoaded', function() {
        buildTOC();
        const mobileBtn = document.getElementById('toc-mobile-btn');
        const mobileClose = document.getElementById('toc-mobile-close');
        const backdrop = document.getElementById('toc-mobile-backdrop');
        if (mobileBtn) mobileBtn.addEventListener('click', openMobileDrawer);
        if (mobileClose) mobileClose.addEventListener('click', closeMobileDrawer);
        if (backdrop) backdrop.addEventListener('click', closeMobileDrawer);
    });
})();

// ============================================================
// Reader preferences — 微信读书-style reading experience
// ============================================================
(function() {
    var STORAGE_KEY = 'links-reader-prefs-v1';
    var DEFAULTS = { theme: 'light', font: 'system', size: 17, spacing: 1.85 };

    var prefs = Object.assign({}, DEFAULTS);
    try {
        var saved = JSON.parse(localStorage.getItem(STORAGE_KEY) || '{}');
        Object.assign(prefs, saved);
    } catch (e) { /* ignore corrupt prefs */ }

    function clampSize(v) { return Math.min(24, Math.max(13, v)); }
    function clampSpacing(v) { return Math.min(2.3, Math.max(1.4, v)); }

    function save() {
        try { localStorage.setItem(STORAGE_KEY, JSON.stringify(prefs)); } catch (e) {}
    }

    function apply() {
        var body = document.body;
        // Theme
        ['light', 'paper', 'green', 'night'].forEach(function(t) {
            body.classList.toggle('reader-' + t, t === prefs.theme);
        });
        // Font
        ['system', 'serif', 'hei', 'kai', 'mono'].forEach(function(f) {
            body.classList.toggle('reader-font-' + f, f === prefs.font);
        });
        // Size + spacing on the article
        var article = document.getElementById('post-article');
        if (article) {
            article.style.setProperty('--reader-font-size', prefs.size + 'px');
            article.style.setProperty('--reader-line-height', prefs.spacing);
        }
        // Panel UI state
        document.querySelectorAll('.rp-swatch').forEach(function(el) {
            el.classList.toggle('active', el.getAttribute('data-theme') === prefs.theme);
        });
        document.querySelectorAll('.rp-font-chip').forEach(function(el) {
            el.classList.toggle('active', el.getAttribute('data-font') === prefs.font);
        });
        document.querySelectorAll('.rp-spacing-btn').forEach(function(el) {
            el.classList.toggle('active', parseFloat(el.getAttribute('data-spacing')) === prefs.spacing);
        });
        var sizeVal = document.getElementById('rp-size-val');
        if (sizeVal) sizeVal.textContent = prefs.size + 'px';
    }

    // Reading progress bar + back-to-top visibility
    var progressBar = document.getElementById('reading-progress');
    var backToTop = document.getElementById('back-to-top');
    var scrollTicking = false;
    function onScroll() {
        if (scrollTicking) return;
        scrollTicking = true;
        requestAnimationFrame(function() {
            scrollTicking = false;
            var doc = document.documentElement;
            var total = doc.scrollHeight - window.innerHeight;
            var pct = total > 0 ? (window.scrollY / total) * 100 : 0;
            if (progressBar) progressBar.style.width = pct + '%';
            if (backToTop) backToTop.classList.toggle('visible', window.scrollY > 600);
        });
    }
    window.addEventListener('scroll', onScroll, { passive: true });
    onScroll();

    // Expose panel controls globally (used by inline onclick)
    window.toggleReaderPanel = function() {
        var panel = document.getElementById('reader-panel');
        if (!panel) return;
        var open = panel.classList.toggle('open');
        syncReaderTriggers(open);
    };
    window.closeReaderPanel = function() {
        var panel = document.getElementById('reader-panel');
        if (panel) panel.classList.remove('open');
        syncReaderTriggers(false);
    };
    function syncReaderTriggers(open) {
        ['reader-toolbar-btn', 'reader-fab'].forEach(function(id) {
            var el = document.getElementById(id);
            if (el) el.classList.toggle('active', open);
        });
    }
    window.setReaderTheme = function(t) {
        prefs.theme = t; save(); apply();
    };
    window.setReaderFont = function(f) {
        prefs.font = f; save(); apply();
    };
    window.changeReaderSize = function(delta) {
        prefs.size = clampSize(prefs.size + delta); save(); apply();
    };
    window.setReaderSpacing = function(s) {
        prefs.spacing = clampSpacing(s); save(); apply();
    };
    window.resetReaderPrefs = function() {
        prefs = Object.assign({}, DEFAULTS); save(); apply();
    };

    // Close panel on Escape
    document.addEventListener('keydown', function(e) {
        if (e.key === 'Escape') closeReaderPanel();
    });

    document.addEventListener('DOMContentLoaded', function() {
        apply();
    });
})();
</script>
{% endblock %}
