<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width,initial-scale=1" />
  <title>Mental Health Tracker (Download)</title>
  <style>
    html,body {
      height: 100%;
      margin: 0;
      font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial;
      background: linear-gradient(180deg, #1a0b1f 0%, #2a0d2e 100%);
      color: #fdf2f8;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      overflow-x: hidden;
    }
    h1, h2 { color: #fdf2f8; }
    h1 { font-size: 22px; margin-bottom: 10px; letter-spacing: -0.2px; }
    p { color: #c084fc; font-size: 15px; line-height: 1.5; }
    code { color: #ec4899; font-weight: 600; }

    .controls {
      display: flex;
      gap: 12px;
      margin-top: 18px;
      margin-bottom: 16px;
      flex-wrap: wrap;
    }

    button {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      gap: 8px;
      padding: 10px 16px;
      border-radius: 10px;
      border: none;
      cursor: pointer;
      font-weight: 600;
      background: linear-gradient(90deg, #ec4899, #8b5cf6);
      color: white;
      box-shadow: 0 6px 14px rgba(236, 72, 153, 0.25);
      transition: transform .08s ease, box-shadow .12s ease;
      white-space: nowrap;
    }
    button:hover {
      box-shadow: 0 8px 24px rgba(236, 72, 153, 0.35);
      transform: translateY(-1px);
    }
    button:active { transform: translateY(1px); }

    .note {
      color: #c084fc;
      font-size: 14px;
      background: rgba(139, 92, 246, 0.08);
      padding: 12px;
      border-radius: 12px;
      line-height: 1.5;
    }

    details {
      margin-top: 18px;
      background: rgba(255, 0, 128, 0.1);
      border-radius: 12px;
      padding: 10px 14px;
      box-shadow: 0 8px 24px rgba(236, 72, 153, 0.2);
    }
    summary {
      cursor: pointer;
      color: #ec4899;
      font-weight: 600;
    }

    textarea {
      width: 100%;
      height: 360px;
      font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, "Roboto Mono", "Courier New", monospace;
      margin-top: 10px;
      padding: 10px;
      border-radius: 10px;
      border: 1px solid rgba(139, 92, 246, 0.3);
      background: rgba(139, 92, 246, 0.1);
      color: #fdf2f8;
      resize: vertical;
      box-sizing: border-box;
    }

    #logConsole {
      background: #2a0d2e;
      color: #fdf2f8;
      font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, "Roboto Mono", "Courier New", monospace;
      padding: 12px;
      border-radius: 12px;
      height: 180px;
      overflow-y: auto;
      margin-top: 16px;
      white-space: pre-wrap;
      box-shadow: 0 6px 20px rgba(236, 72, 153, 0.2);
    }
    #logConsole .error { color: #ef4444; }
    #logConsole .warn { color: #f7d154; }
    #logConsole .info { color: #8b5cf6; }

    details[open] {
      background: rgba(139, 92, 246, 0.15);
    }

    @media (max-width: 600px) {
      button { flex: 1 1 100%; }
      textarea { height: 240px; }
    }
  </style>
</head>
<body>
  <h1>Merge the website files into single HTML</h1>

  <div class="controls">
    <button id="mergeDownloadBtn">Merge &amp; Download mental-health-tracking.html</button>
    <button id="mergePreviewBtn">Merge &amp; Open Preview</button>
    <button id="showMergedBtn">Show merged HTML (open panel)</button>
  </div>

  <div class="note">
    Important: This must be served from the <b>same origin</b> as <code>/website/</code>. Browser security (CORS / same-origin) prevents fetching files from another domain unless CORS is permitted.
  </div>

  <details style="margin-top:14px">
    <summary>Merged HTML output (editable)</summary>
    <textarea id="mergedOutput"></textarea>
  </details>

  <h2 style="margin-top:28px;">Console Output</h2>
  <div id="logConsole"></div>

<script>
  // ---------- Logging Utility ----------
  const logConsole = document.getElementById('logConsole');
  function logMessage(level, msg) {
    const time = new Date().toLocaleTimeString();
    const div = document.createElement('div');
    div.className = level;
    div.textContent = `[${time}] ${level.toUpperCase()}: ${msg}`;
    logConsole.appendChild(div);
    logConsole.scrollTop = logConsole.scrollHeight;
    console[level === 'error' ? 'error' : (level === 'warn' ? 'warn' : 'log')](msg);
  }
  const logInfo = msg => logMessage('info', msg);
  const logWarn = msg => logMessage('warn', msg);
  const logError = msg => logMessage('error', msg);

  // ---------- Helpers ----------
  function isAbsoluteOrProtocol(val) {
    if (!val) return false;
    return /^(https?:|\/\/|data:|mailto:|tel:|#|\/)/i.test(val);
  }

  function rewriteHtmlRelativeUrls(doc) {
    const attrs = ['src','href','poster','data-src'];
    const all = doc.querySelectorAll('*');
    for (const el of all) {
      for (const a of attrs) {
        if (!el.hasAttribute(a)) continue;
        const v = el.getAttribute(a);
        if (!v) continue;
        if (isAbsoluteOrProtocol(v)) continue;
        let newVal = v.startsWith('./') ? v.slice(2) : v;
        newVal = 'website/' + newVal;
        el.setAttribute(a, newVal);
      }
    }
  }

  function rewriteCssUrls(cssText) {
    return cssText.replace(/url\(\s*(['"]?)(?!data:|https?:|\/\/|\/)([^'")]+)\1\s*\)/gi,
      (m, q, path) => {
        if (path.startsWith('./')) path = path.slice(2);
        return `url(${q}website/${path}${q})`;
      });
  }

  async function fetchText(url) {
    try {
      logInfo(`Fetching: ${url}`);
      const res = await fetch(url, {cache: 'no-store'});
      if (!res.ok) throw new Error(`HTTP ${res.status} ${res.statusText}`);
      const text = await res.text();
      logInfo(`Fetched successfully: ${url}`);
      return text;
    } catch (err) {
      logError(`Failed to fetch ${url}: ${err.message}`);
      throw err;
    }
  }

// ---------- Core merge ----------
async function buildMergedHtml() {
  logInfo('Starting merge...');
  const base = './website/';
  try {
    const [indexHtmlText, cssTextMain, jsTextMain, guideHtmlText] = await Promise.all([
      fetchText(base + 'index.html'),
      fetchText(base + 'styles.css'),
      fetchText(base + 'scripts.js'),
      fetchText(base + 'guide.html')
    ]);

    const parser = new DOMParser();
    const doc = parser.parseFromString(indexHtmlText, 'text/html');

    // remove link tags replaced by inline CSS
    doc.querySelectorAll('link[rel="stylesheet"]').forEach(l => l.remove());

    const gdoc = parser.parseFromString(guideHtmlText, 'text/html');
    let cssText = cssTextMain;

    // inline CSS from guide page
    for (const l of gdoc.querySelectorAll('link[rel="stylesheet"]')) {
      const href = l.getAttribute('href') || '';
      if (!isAbsoluteOrProtocol(href)) {
        try {
          const fetchedCss = await fetchText(base + href.replace(/^\.\//, ''));
          cssText += `/* inlined from guide: ${href} */` + rewriteCssUrls(fetchedCss);
        } catch (e) { logWarn(`Failed to inline ${href}`); }
      }
      l.remove();
    }

    // inline JS from guide page
    let extraJsFromGuide = '';
    for (const s of gdoc.querySelectorAll('script[src]')) {
      const src = s.getAttribute('src') || '';
      if (!isAbsoluteOrProtocol(src)) {
        try {
          const fetchedJs = await fetchText(base + src.replace(/^\.\//, ''));
          extraJsFromGuide += fetchedJs;
        } catch (e) { logWarn(`Failed to inline ${src}`); }
      }
      s.remove();
    }

    const gInlineScripts = Array.from(gdoc.querySelectorAll('script:not([src])')).map(s => s.textContent);
    gdoc.querySelectorAll('script:not([src])').forEach(s => s.remove());
    rewriteHtmlRelativeUrls(gdoc);

    const styleEl = doc.createElement('style');
    styleEl.textContent = rewriteCssUrls(cssText);
    doc.head.appendChild(styleEl);

    doc.querySelectorAll('script[src]').forEach(s => s.remove());
    rewriteHtmlRelativeUrls(doc);

    const indexWrap = doc.createElement('div');
    indexWrap.dataset.page = 'index';
    while (doc.body.firstChild) indexWrap.appendChild(doc.body.firstChild);
    doc.body.appendChild(indexWrap);

    const gWrap = doc.createElement('div');
    gWrap.dataset.page = 'guide';
    gWrap.style.display = 'none';
    gWrap.innerHTML = gdoc.body.innerHTML.trim() || gdoc.documentElement.outerHTML;
    doc.body.appendChild(gWrap);

    const inlineScript = doc.createElement('script');
    inlineScript.textContent = jsTextMain;
    doc.body.appendChild(inlineScript);

    if (extraJsFromGuide || gInlineScripts.length) {
      const gScript = doc.createElement('script');
      gScript.textContent = extraJsFromGuide + '\n' + gInlineScripts.join('\n');
      doc.body.appendChild(gScript);
    }

    // ๐Ÿ”น Minimal page switcher (no nav bar)
    const pageSwitcher = doc.createElement('script');
    pageSwitcher.textContent = `
      (function(){
        function showPage(name){
          const pages = document.querySelectorAll('[data-page]');
          let found = false;
          pages.forEach(p=>{
            if(p.getAttribute('data-page')===name){p.style.display='';found=true;}
            else p.style.display='none';
          });
          return found;
        }
        function setFromHash(){
          const name = location.hash ? location.hash.slice(1) : 'index';
          if(!showPage(name)) showPage('index');
        }
        window.addEventListener('hashchange', setFromHash);
        document.addEventListener('DOMContentLoaded', setFromHash);
      })();
    `;
    doc.body.appendChild(pageSwitcher);

    const merged = '<!doctype html>\n' + doc.documentElement.outerHTML;
    logInfo('Merge completed successfully.');
    return merged;
  } catch (err) {
    logError('Error during merge: ' + err.message);
    throw err;
  }
}

  // ---------- UI Logic ----------
  const mergeDownloadBtn = document.getElementById('mergeDownloadBtn');
  const mergePreviewBtn = document.getElementById('mergePreviewBtn');
  const showMergedBtn = document.getElementById('showMergedBtn');
  const mergedOutput = document.getElementById('mergedOutput');

  async function tryBuildAndReturn() {
    try {
      mergeDownloadBtn.disabled = mergePreviewBtn.disabled = showMergedBtn.disabled = true;
      mergeDownloadBtn.textContent = 'Merging...';
      const merged = await buildMergedHtml();
      mergeDownloadBtn.textContent = 'Merge & Download mental-health-tracking.html';
      mergeDownloadBtn.disabled = mergePreviewBtn.disabled = showMergedBtn.disabled = false;
      return merged;
    } catch (err) {
      mergeDownloadBtn.textContent = 'Merge & Download mental-health-tracking.html';
      mergeDownloadBtn.disabled = mergePreviewBtn.disabled = showMergedBtn.disabled = false;
      logError('Build failed: ' + err.message);
      return null;
    }
  }

  mergeDownloadBtn.addEventListener('click', async () => {
    const merged = await tryBuildAndReturn();
    if (!merged) return;
    const blob = new Blob([merged], { type: 'text/html;charset=utf-8' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = 'mental-health-tracking.html';
    document.body.appendChild(a);
    a.click();
    a.remove();
    URL.revokeObjectURL(url);
    logInfo('Merged file downloaded.');
  });

  mergePreviewBtn.addEventListener('click', async () => {
    const merged = await tryBuildAndReturn();
    if (!merged) return;
    const blob = new Blob([merged], { type: 'text/html' });
    const url = URL.createObjectURL(blob);
    window.open(url, '_blank');
    setTimeout(() => URL.revokeObjectURL(url), 5000);
    logInfo('Preview opened in new tab.');
  });

  showMergedBtn.addEventListener('click', async () => {
    const merged = await tryBuildAndReturn();
    if (!merged) return;
    mergedOutput.value = merged;
    mergedOutput.scrollTop = 0;
    logInfo('Merged HTML displayed in textarea.');
  });
</script>
</body>
</html>
<!doctype html>
<html lang="en" data-theme="">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Personal Journal</title>
</head>
<body>
  <div style="max-width:1100px;margin:24px auto;padding:0 18px;">
    <div class="app card" id="root">
      <header>
        <div>
          <h1>Local Journal</h1>
          <div class="sub">Private, local-only tracking โ€” entries saved to your browser.</div>
        </div>
        <div class="row">
            <button class="btn btn-ghost" id="btnGuide">User Guide โ†’</button>
          <button class="btn btn-secondary" id="openSettings">Settings</button>
        </div>
      </header>

      <!-- Left column -->
      <div class="controls">
        <div class="card">
          <div style="display:flex;justify-content:space-between;align-items:center;">
            <div>
              <strong>Quick Actions</strong>
              <div class="small muted">Add an entry, manage types, or quick-log.</div>
            </div>
          </div>

          <div class="row">
            <button class="btn btn-primary btn-large" id="btnAddEntry">+ Add Entry</button>
            <button class="btn btn-secondary" id="btnQuickLog">Quick Log</button>
          </div>

          <div class="row">
            <button class="btn btn-ghost" id="btnManageTypes">Manage Event Types</button>
            <button class="btn btn-ghost" id="btnReminders">Reminders</button>
            <button class="btn btn-ghost" id="btnExport">Export</button>
          </div>

          <div style="border-top:1px dashed var(--glass-2);padding-top:10px" class="small muted">
            <div><strong id="totalCount">0</strong> total entries</div>
            <div id="overviewText" style="margin-top:6px;">No entries yet โ€” add one to get started.</div>
          </div>
        </div>

        <div class="card">
          <div style="display:flex;align-items:center;justify-content:space-between">
            <div>
              <strong>Event Types</strong>
              <div class="small muted">Manage categories used when logging entries.</div>
            </div>
            <button class="btn btn-secondary" id="btnManageTypes2">Edit</button>
          </div>
          <div id="typesPreview" style="margin-top:12px;display:flex;flex-wrap:wrap;gap:8px;"></div>
        </div>

        <div class="card">
          <div style="display:flex;align-items:center;justify-content:space-between">
            <div>
              <strong>Data</strong>
              <div class="small muted">Export, import, or clear all local data.</div>
            </div>
          </div>

          <div class="row">
            <button class="btn btn-secondary" id="btnExport2">Export CSV/JSON</button>
            <button class="btn btn-ghost" id="btnImport">Import JSON</button>
            <button class="btn btn-ghost danger" id="btnClearAll">Clear All</button>
          </div>
        </div>
      </div>

      <!-- Right column -->
      <div class="right">
        <div class="card chart-wrap">
          <canvas id="weekChart" aria-label="Weekly entries chart"></canvas>
          <div class="overview card" style="padding:12px;">
            <div style="display:flex;flex-direction:column;gap:8px;">
              <div><strong id="weekTotal">0</strong> entries in last 7 days</div>
              <div class="muted" id="topType">โ€”</div>
              <div class="muted" id="topMood">โ€”</div>
            </div>
          </div>
        </div>

        <div class="card">
          <div style="display:flex;align-items:center;justify-content:space-between">
            <strong>Entries</strong>
            <div class="row">
              <button class="btn btn-ghost" id="toggleCollapse">Collapse</button>
              <button class="btn btn-secondary" id="btnClearEntries">Clear</button>
            </div>
          </div>

          <div class="table-wrap">
            <table id="entriesTable">
              <thead>
                <tr>
                  <th style="width:160px">Date</th>
                  <th>Type</th>
                  <th class="col-mood">Mood</th>
                  <th class="col-sev">Severity</th>
                  <th>Duration</th>
                  <th>Notes</th>
                  <th class="actions-col">Actions</th>
                </tr>
              </thead>
              <tbody id="entriesBody">
                <!-- rows -->
              </tbody>
            </table>
          </div>
        </div>

        <footer class="muted">All data stays in your browser. Use Export to make backups.</footer>
      </div>
    </div>
  </div>

  <!-- Backdrop & Modals -->
  <div class="backdrop" id="backdrop" role="dialog" aria-hidden="true">
    <!-- Add Entry Modal -->
    <div class="modal card hidden" id="modalAddEntry">
      <div class="card">
        <h3 id="addEntryTitle">Add Entry</h3>
        <div class="row">
          <div style="flex:1">
            <label for="entryDate">Date & time</label>
            <input type="datetime-local" id="entryDate" />
          </div>
          <div style="width:200px">
            <label for="entryType">Type</label>
            <select id="entryType"></select>
          </div>
        </div>

        <div id="fieldMood" class="col">
          <label>Mood</label>
          <div style="display:flex;gap:8px;align-items:center;">
            <input type="text" id="entryMood" placeholder="Choose emoji or type" />
            <button class="btn btn-ghost" id="openEmojiPicker">๐Ÿ˜€</button>
          </div>
          <div id="emojiPicker" class="emoji-grid hidden" style="margin-top:8px;"></div>
        </div>

        <div id="fieldSeverity" class="col">
          <label>Severity (1-10)</label>
          <input type="number" id="entrySeverity" min="1" max="10" />
        </div>

        <div class="col">
          <label>Duration (minutes)</label>
          <input type="number" id="entryDuration" min="0" />
        </div>

        <div class="col">
          <label>Notes</label>
          <textarea id="entryNotes" placeholder="Optional notes..."></textarea>
        </div>

        <div class="actions">
          <button class="btn btn-secondary" id="btnClearEntry">Clear</button>
          <button class="btn btn-ghost" id="btnCancelEntry">Cancel</button>
          <button class="btn btn-primary" id="btnSaveEntry">Save</button>
        </div>
      </div>
    </div>

    <!-- Quick Log Modal -->
    <div class="modal card hidden" id="modalQuickLog">
      <div class="card">
        <h3>Quick Log</h3>
        <div class="row">
          <div style="flex:1">
            <label>Time</label>
            <input type="datetime-local" id="quickDate" />
          </div>
          <div style="width:200px">
            <label>Type</label>
            <select id="quickType"></select>
          </div>
        </div>

        <div id="quickMoodWrap" class="col">
          <label>Mood</label>
          <input type="text" id="quickMood" />
        </div>

        <div class="actions">
          <button class="btn btn-ghost" id="btnCancelQuick">Cancel</button>
          <button class="btn btn-primary" id="btnSaveQuick">Save</button>
        </div>
      </div>
    </div>

    <!-- Manage Types Modal -->
    <div class="modal card hidden" id="modalManageTypes">
      <div class="card">
        <h3>Manage Event Types</h3>
        <div class="type-list" id="typeList"></div>

        <div style="display:flex;gap:8px;margin-top:12px;align-items:center;">
          <input type="text" id="newTypeName" placeholder="New type name" />
          <label style="display:flex;align-items:center;gap:8px;"><input type="checkbox" id="newTypeAction" /> action</label>
          <button class="btn btn-primary" id="btnAddType">Add</button>
        </div>

        <div class="actions">
          <button class="btn btn-ghost" id="btnCloseTypes">Close</button>
        </div>
      </div>
    </div>

    <!-- Reminders Modal -->
    <div class="modal card hidden" id="modalReminders">
      <div class="card">
        <h3>Daily Reminder</h3>
        <div class="col">
          <label>Reminder time</label>
          <input type="time" id="reminderTime" />
        </div>

        <div class="row" style="align-items:center">
          <label style="margin-right:8px;">Enable reminders</label>
          <input type="checkbox" id="enableReminders" />
        </div>

        <div class="small muted" id="reminderStatus"></div>

        <div class="actions">
          <button class="btn btn-ghost" id="btnCancelReminders">Close</button>
          <button class="btn btn-primary" id="btnSaveReminders">Save</button>
        </div>
      </div>
    </div>

    <!-- Settings Modal -->
    <div class="modal card hidden" id="modalSettings">
      <div class="card">
        <h3>Settings</h3>
        <div class="col">
          <label><input type="checkbox" id="settingMood" /> Enable Mood field</label>
          <label><input type="checkbox" id="settingSeverity" /> Enable Severity field</label>
          <label><input type="checkbox" id="settingReminders" /> Enable Reminders feature</label>
          <label><input type="checkbox" id="settingExport" /> Enable Export/Import</label>
          <label><input type="checkbox" id="settingCompact" /> Compact UI</label>
        </div>

        <div style="margin-top:10px" class="small muted">Changes apply immediately and persist in localStorage.</div>

        <div class="actions">
          <button class="btn btn-ghost" id="btnCloseSettings">Close</button>
        </div>
      </div>
    </div>

    <!-- Export Modal -->
    <div class="modal card hidden" id="modalExport">
      <div class="card">
        <h3>Export</h3>
        <div class="col">
          <label>Export format</label>
          <div class="row">
            <button class="btn btn-secondary" id="exportCSV">Download CSV</button>
            <button class="btn btn-secondary" id="exportJSON">Download JSON</button>
            <button class="btn btn-ghost" id="openImportFile">Import JSON</button>
            <input type="file" id="importFile" accept="application/json" class="hidden" />
          </div>
        </div>

        <div class="actions">
          <button class="btn btn-ghost" id="btnCloseExport">Close</button>
        </div>
      </div>
    </div>

    <!-- View Entry Modal -->
    <div class="modal card hidden" id="modalViewEntry">
      <div class="card">
        <h3>View Entry</h3>
        <div id="viewEntryBody" class="col"></div>
        <div class="actions">
          <button class="btn btn-ghost" id="btnCloseView">Close</button>
          <button class="btn btn-secondary" id="btnDeleteEntry">Delete</button>
        </div>
      </div>
    </div>
  </div>

  <!-- ๐Ÿ”น Simple script to handle the page switch -->
  <script>
    document.getElementById('btnGuide').addEventListener('click', () => {
      location.hash = 'guide';
    });
  </script>

</body>
</html>
/* =========================
   VERSIONED STORAGE KEYS
   ========================= */
const APP_VERSION = 'v1';
const KEYS = {
  // ENTRIES will be stored in IndexedDB now (KEYS.ENTRIES retained for backwards compat where needed)
  ENTRIES: `LOCALJOURNAL_${APP_VERSION}_ENTRIES`,
  TYPES: `LOCALJOURNAL_${APP_VERSION}_TYPES`,
  REMINDER: `LOCALJOURNAL_${APP_VERSION}_REMINDER`,
  SETTINGS: `LOCALJOURNAL_${APP_VERSION}_SETTINGS`
};

/* =========================
   DEFAULTS
   ========================= */
const defaultTypes = [
  { id: 'nssi_action', name: 'NSSI โ€” action', action: true },
  { id: 'nssi_ideation', name: 'NSSI โ€” ideation', action: false },
  { id: 'depressive', name: 'Depressive episode', action: false },
  { id: 'suicidal_ideation', name: 'Suicidal ideation', action: false },
  { id: 'suicidal_action', name: 'Suicidal โ€” action', action: true }
];

const DEFAULT_SETTINGS = {
  enableMood: true,
  enableSeverity: true,
  enableReminders: false,
  enableExport: true,
  compactUI: false
};

const DEFAULT_REMINDER = { time: null, enabled: false };

/* =========================
   Persistence helpers (localStorage for small things)
   ========================= */
function loadJSON(key, fallback) {
  try {
    const raw = localStorage.getItem(key);
    if (!raw) return fallback;
    return JSON.parse(raw);
  } catch (e) {
    console.warn('Failed to parse localStorage key', key, e);
    return fallback;
  }
}
function saveJSON(key, value) {
  try {
    localStorage.setItem(key, JSON.stringify(value));
  } catch (e) {
    console.error('Failed to save', key, e);
  }
}

/* =========================
   IndexedDB wrapper for entries
   ========================= */
const DB_NAME = 'LocalJournalDB';
const DB_VERSION = 1;
const STORE_ENTRIES = 'entries';

let dbPromise = null;

function openDB() {
  if (dbPromise) return dbPromise;
  dbPromise = new Promise((resolve, reject) => {
    const req = indexedDB.open(DB_NAME, DB_VERSION);
    req.onupgradeneeded = (e) => {
      const db = e.target.result;
      if (!db.objectStoreNames.contains(STORE_ENTRIES)) {
        const store = db.createObjectStore(STORE_ENTRIES, { keyPath: 'id' });
        store.createIndex('timestamp', 'timestamp', { unique: false });
        store.createIndex('type', 'type', { unique: false });
        // mood or other indexes could be added here if needed
      }
    };
    req.onsuccess = (e) => resolve(e.target.result);
    req.onerror = (e) => reject(e.target.error);
  });
  return dbPromise;
}

function promisifyRequest(req) {
  return new Promise((resolve, reject) => {
    req.onsuccess = () => resolve(req.result);
    req.onerror = () => reject(req.error);
  });
}

async function dbPutEntry(entry) {
  const db = await openDB();
  return new Promise((resolve, reject) => {
    const tx = db.transaction(STORE_ENTRIES, 'readwrite');
    const store = tx.objectStore(STORE_ENTRIES);
    const req = store.put(entry);
    req.onsuccess = () => resolve(req.result);
    req.onerror = () => reject(req.error);
  });
}

async function dbGetAllEntries() {
  const db = await openDB();
  return new Promise((resolve, reject) => {
    const tx = db.transaction(STORE_ENTRIES, 'readonly');
    const store = tx.objectStore(STORE_ENTRIES);
    const req = store.getAll();
    req.onsuccess = () => resolve(req.result || []);
    req.onerror = () => reject(req.error);
  });
}

async function dbDeleteEntry(id) {
  const db = await openDB();
  return new Promise((resolve, reject) => {
    const tx = db.transaction(STORE_ENTRIES, 'readwrite');
    const store = tx.objectStore(STORE_ENTRIES);
    const req = store.delete(id);
    req.onsuccess = () => resolve();
    req.onerror = () => reject(req.error);
  });
}

async function dbClearEntries() {
  const db = await openDB();
  return new Promise((resolve, reject) => {
    const tx = db.transaction(STORE_ENTRIES, 'readwrite');
    const store = tx.objectStore(STORE_ENTRIES);
    const req = store.clear();
    req.onsuccess = () => resolve();
    req.onerror = () => reject(req.error);
  });
}

async function dbBulkPut(entriesArray) {
  const db = await openDB();
  return new Promise((resolve, reject) => {
    const tx = db.transaction(STORE_ENTRIES, 'readwrite');
    const store = tx.objectStore(STORE_ENTRIES);
    let count = 0;
    for (const entry of entriesArray) {
      const req = store.put(entry);
      req.onsuccess = () => {
        count++;
        // if last, resolve โ€” but can't easily know last synchronously; instead wait for tx.oncomplete
      };
      req.onerror = () => {
        // ignore single failure? reject
        console.error('dbBulkPut item failed', req.error);
      };
    }
    tx.oncomplete = () => resolve();
    tx.onerror = () => reject(tx.error);
    tx.onabort = () => reject(tx.error);
  });
}

/* =========================
   Utilities
   ========================= */
function esc(s){ // safe HTML insertion
  if (s === null || s === undefined) return '';
  return String(s)
    .replaceAll('&','&amp;')
    .replaceAll('<','&lt;')
    .replaceAll('>','&gt;')
    .replaceAll('"','&quot;')
    .replaceAll("'", '&#39;');
}
function isoDate(ts){ return (new Date(ts)).toISOString(); }
function formatShort(ts){
  const d = new Date(ts);
  return d.toLocaleString([], {month:'short', day:'numeric', hour:'2-digit', minute:'2-digit'});
}
function friendlyDateTime(ts){
  const d = new Date(ts);
  return d.toLocaleString();
}
function pad(n){ return String(n).padStart(2,'0'); }
function downloadBlob(filename, blob){
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = filename;
  document.body.appendChild(a);
  a.click();
  a.remove();
  setTimeout(()=> URL.revokeObjectURL(url), 5000);
}
function isActionType(typeId){
  const t = types.find(x => x.id === typeId);
  return !!(t && t.action);
}

/* =========================
   App state
   - entries moved to IndexedDB; keep in-memory cache 'entries' for UI responsiveness
   ========================= */
let entries = []; // will be populated from IndexedDB during init
let types = loadJSON(KEYS.TYPES, defaultTypes);
let settings = loadJSON(KEYS.SETTINGS, DEFAULT_SETTINGS);
let reminder = loadJSON(KEYS.REMINDER, DEFAULT_REMINDER);
let reminderInterval = null;

/* =========================
   DOM refs
   ========================= */
const rootEl = document.getElementById('root');
const weekCanvas = document.getElementById('weekChart');
const entriesBody = document.getElementById('entriesBody');
const totalCountEl = document.getElementById('totalCount');
const overviewText = document.getElementById('overviewText');
const typesPreview = document.getElementById('typesPreview');
const weekTotalEl = document.getElementById('weekTotal');
const topTypeEl = document.getElementById('topType');
const topMoodEl = document.getElementById('topMood');
const backdrop = document.getElementById('backdrop');

/* Modal nodes */
const modalAddEntry = document.getElementById('modalAddEntry');
const modalQuickLog = document.getElementById('modalQuickLog');
const modalManageTypes = document.getElementById('modalManageTypes');
const modalReminders = document.getElementById('modalReminders');
const modalSettings = document.getElementById('modalSettings');
const modalExport = document.getElementById('modalExport');
const modalViewEntry = document.getElementById('modalViewEntry');

/* inputs */
const entryDate = document.getElementById('entryDate');
const entryType = document.getElementById('entryType');
const entryMood = document.getElementById('entryMood');
const entrySeverity = document.getElementById('entrySeverity');
const entryDuration = document.getElementById('entryDuration');
const entryNotes = document.getElementById('entryNotes');
const emojiPicker = document.getElementById('emojiPicker');

const quickDate = document.getElementById('quickDate');
const quickType = document.getElementById('quickType');
const quickMood = document.getElementById('quickMood');

const typeList = document.getElementById('typeList');
const newTypeName = document.getElementById('newTypeName');
const newTypeAction = document.getElementById('newTypeAction');

const reminderTime = document.getElementById('reminderTime');
const enableRemindersInput = document.getElementById('enableReminders');
const reminderStatus = document.getElementById('reminderStatus');

const settingMood = document.getElementById('settingMood');
const settingSeverity = document.getElementById('settingSeverity');
const settingReminders = document.getElementById('settingReminders');
const settingExport = document.getElementById('settingExport');
const settingCompact = document.getElementById('settingCompact');

const entriesTable = document.getElementById('entriesTable');

let isListCollapsed = false;
let currentViewEntryId = null;

/* =========================
   Initial setup (async to load entries from DB)
   ========================= */
async function init(){
  // load entries from IndexedDB
  try {
    entries = await dbGetAllEntries();
    // sort desc by timestamp
    entries.sort((a,b)=> new Date(b.timestamp) - new Date(a.timestamp));
  } catch (err) {
    console.error('Failed to load entries from IndexedDB', err);
    entries = [];
  }

  // apply settings UI
  applySettingsToForm();
  applySettings();
  // wire up UI buttons
  wireUI();
  // draw initial UI
  renderTypeSelectors();
  renderTypesPreview();
  renderEntries();
  drawWeekChart();
  setupEmojiPicker();
  scheduleReminderLoop();
}

/* =========================
   Settings apply
   ========================= */
function applySettingsToForm(){
  settingMood.checked = !!settings.enableMood;
  settingSeverity.checked = !!settings.enableSeverity;
  settingReminders.checked = !!settings.enableReminders;
  settingExport.checked = !!settings.enableExport;
  settingCompact.checked = !!settings.compactUI;
  // apply reminder form
  reminderTime.value = reminder.time || '';
  enableRemindersInput.checked = !!(reminder.enabled);
}

function applySettings(){
  // Show/hide mood & severity fields in Add Entry modal and Quick Log
  const fieldMood = document.getElementById('fieldMood');
  const fieldSeverity = document.getElementById('fieldSeverity');
  const quickMoodWrap = document.getElementById('quickMoodWrap');

  if (settings.enableMood) { fieldMood.classList.remove('hidden'); quickMoodWrap.classList.remove('hidden'); }
  else { fieldMood.classList.add('hidden'); quickMoodWrap.classList.add('hidden'); }

  if (settings.enableSeverity) fieldSeverity.classList.remove('hidden'); else fieldSeverity.classList.add('hidden');

  // Export/Import availability
  if (settings.enableExport) {
    document.getElementById('btnExport').classList.remove('hidden');
    document.getElementById('btnExport2').classList.remove('hidden');
  } else {
    document.getElementById('btnExport').classList.add('hidden');
    document.getElementById('btnExport2').classList.add('hidden');
  }

  // Reminders
  if (settings.enableReminders) {
    document.getElementById('btnReminders').classList.remove('hidden');
  } else {
    document.getElementById('btnReminders').classList.add('hidden');
  }

  // compact UI
  if (settings.compactUI) document.body.classList.add('compact'); else document.body.classList.remove('compact');

  // columns in table
  document.querySelectorAll('.col-mood').forEach(n => n.style.display = settings.enableMood ? '' : 'none');
  document.querySelectorAll('.col-sev').forEach(n => n.style.display = settings.enableSeverity ? '' : 'none');
}

/* =========================
   Event wiring
   ========================= */
function wireUI(){
  document.getElementById('btnAddEntry').addEventListener('click', openAddEntry);
  document.getElementById('btnQuickLog').addEventListener('click', openQuickLog);
  document.getElementById('btnManageTypes').addEventListener('click', openManageTypes);
  document.getElementById('btnManageTypes2').addEventListener('click', openManageTypes);
  document.getElementById('btnReminders').addEventListener('click', openReminders);
  document.getElementById('btnExport').addEventListener('click', openExport);
  document.getElementById('btnExport2').addEventListener('click', openExport);
  document.getElementById('btnImport').addEventListener('click', ()=> document.getElementById('importFile').click());
  document.getElementById('importFile').addEventListener('change', handleImportFile);
  document.getElementById('btnClearAll').addEventListener('click', clearAllData);

  document.getElementById('btnClearEntries').addEventListener('click', clearEntries);
  document.getElementById('toggleCollapse').addEventListener('click', toggleCollapse);

  document.getElementById('btnSaveEntry').addEventListener('click', saveEntryFromModal);
  document.getElementById('btnCancelEntry').addEventListener('click', hideBackdrop);

  document.getElementById('btnSaveQuick').addEventListener('click', saveQuickLog);
  document.getElementById('btnCancelQuick').addEventListener('click', hideBackdrop);

  document.getElementById('btnAddType').addEventListener('click', addTypeFromInput);
  document.getElementById('btnCloseTypes').addEventListener('click', hideBackdrop);

  document.getElementById('btnSaveReminders').addEventListener('click', saveReminderSettings);
  document.getElementById('btnCancelReminders').addEventListener('click', hideBackdrop);

  document.getElementById('openSettings').addEventListener('click', openSettings);
  document.getElementById('btnCloseSettings').addEventListener('click', hideBackdrop);

  // settings toggles
  settingMood.addEventListener('change', ()=> { settings.enableMood = settingMood.checked; saveJSON(KEYS.SETTINGS, settings); applySettings(); });
  settingSeverity.addEventListener('change', ()=> { settings.enableSeverity = settingSeverity.checked; saveJSON(KEYS.SETTINGS, settings); applySettings(); });
  settingReminders.addEventListener('change', ()=> { settings.enableReminders = settingReminders.checked; saveJSON(KEYS.SETTINGS, settings); applySettings(); scheduleReminderLoop(); });
  settingExport.addEventListener('change', ()=> { settings.enableExport = settingExport.checked; saveJSON(KEYS.SETTINGS, settings); applySettings(); });
  settingCompact.addEventListener('change', ()=> { settings.compactUI = settingCompact.checked; saveJSON(KEYS.SETTINGS, settings); applySettings(); });

  // emoji
  document.getElementById('openEmojiPicker').addEventListener('click', ()=> emojiPicker.classList.toggle('hidden'));

  // export modal
  document.getElementById('exportCSV').addEventListener('click', exportCSV);
  document.getElementById('exportJSON').addEventListener('click', exportJSON);
  document.getElementById('openImportFile').addEventListener('click', ()=> document.getElementById('importFile').click());
  document.getElementById('btnCloseExport').addEventListener('click', hideBackdrop);

  // view modal
  document.getElementById('btnCloseView').addEventListener('click', hideBackdrop);
  document.getElementById('btnDeleteEntry').addEventListener('click', deleteViewedEntry);

  // backdrop click closes
  backdrop.addEventListener('click', (e) => {
    if (e.target === backdrop) hideBackdrop();
  });
}

/* =========================
   UI: Modals open/close
   ========================= */
function showBackdrop(){
  backdrop.classList.add('show');
  // set first modal's aria
  backdrop.setAttribute('aria-hidden','false');
}
function hideBackdrop(){
  backdrop.classList.remove('show');
  // hide all modals
  document.querySelectorAll('.modal').forEach(m=>m.classList.add('hidden'));
  backdrop.setAttribute('aria-hidden','true');
}

/* =========================
   Add / Quick entries (async DB-backed)
   ========================= */
function openAddEntry(){
  // prefill
  entryDate.value = (new Date()).toISOString().slice(0,16);
  entryType.innerHTML = '';
  renderTypeSelectors(); // fill select
  entrySeverity.value = '';
  entryDuration.value = '';
  entryMood.value = '';
  entryNotes.value = '';
  document.getElementById('addEntryTitle').textContent = 'Add Entry';
  document.querySelectorAll('.modal').forEach(m=>m.classList.add('hidden'));
  modalAddEntry.classList.remove('hidden');
  showBackdrop();
}

async function saveEntryFromModal(){
  const ts = entryDate.value ? new Date(entryDate.value).toISOString() : new Date().toISOString();
  const t = entryType.value;
  const moodVal = settings.enableMood ? (entryMood.value || '') : '';
  const sevVal = settings.enableSeverity ? (entrySeverity.value ? Number(entrySeverity.value) : null) : null;
  const dur = entryDuration.value ? Number(entryDuration.value) : null;
  const notesVal = entryNotes.value || '';

  const entry = {
    id: 'e_' + Date.now(),
    timestamp: ts,
    type: t,
    mood: moodVal,
    severity: sevVal,
    duration: dur,
    notes: notesVal
  };

  try {
    await dbPutEntry(entry);
    // keep in-memory list in sync (most recent first)
    entries.unshift(entry);
    // keep sorted
    entries.sort((a,b)=> new Date(b.timestamp) - new Date(a.timestamp));
    renderEntries();
    drawWeekChart();
    hideBackdrop();
  } catch (err) {
    console.error('Failed to save entry to IndexedDB', err);
    alert('Failed to save entry. See console for details.');
  }
}

function openQuickLog(){
  quickDate.value = (new Date()).toISOString().slice(0,16);
  quickType.innerHTML = '';
  renderTypeSelectors(true);
  quickMood.value = '';
  document.querySelectorAll('.modal').forEach(m=>m.classList.add('hidden'));
  modalQuickLog.classList.remove('hidden');
  showBackdrop();
}

async function saveQuickLog(){
  const ts = quickDate.value ? new Date(quickDate.value).toISOString() : new Date().toISOString();
  const t = quickType.value;
  const moodVal = settings.enableMood ? (quickMood.value || '') : '';
  const entry = {
    id: 'e_' + Date.now(),
    timestamp: ts,
    type: t,
    mood: moodVal,
    severity: null, duration: null, notes: ''
  };
  try {
    await dbPutEntry(entry);
    entries.unshift(entry);
    entries.sort((a,b)=> new Date(b.timestamp) - new Date(a.timestamp));
    renderEntries();
    drawWeekChart();
    hideBackdrop();
  } catch (err) {
    console.error('Failed to save quick entry', err);
    alert('Failed to save entry. See console for details.');
  }
}

/* =========================
   Render types selectors & preview
   ========================= */
function renderTypeSelectors(quick=false){
  // fill both selects
  const selects = quick ? [quickType] : [entryType, quickType];
  selects.forEach(sel => {
    if (!sel) return;
    sel.innerHTML = '';
    types.forEach(t => {
      const opt = document.createElement('option');
      opt.value = t.id;
      opt.textContent = t.name + (t.action ? ' (action)' : '');
      sel.appendChild(opt);
    });
  });
}

function renderTypesPreview(){
  typesPreview.innerHTML = '';
  types.slice(0,8).forEach(t => {
    const d = document.createElement('div');
    d.className = 'pill';
    d.textContent = t.name;
    typesPreview.appendChild(d);
  });
}

/* =========================
   Manage types
   ========================= */
function openManageTypes(){
  typeList.innerHTML = '';
  types.forEach(t => {
    const row = document.createElement('div');
    row.className = 'type-item';
    row.innerHTML = `
      <div style="flex:1">
        <input type="text" data-id="${esc(t.id)}" class="typeNameInput" value="${esc(t.name)}" />
      </div>
      <label style="display:flex;align-items:center;gap:6px;">
        <input type="checkbox" class="typeActionInput" ${t.action ? 'checked' : ''} />
        action
      </label>
      <button class="btn btn-ghost btn-sm typeRename" data-id="${esc(t.id)}">Save</button>
      <button class="btn btn-ghost danger typeDelete" data-id="${esc(t.id)}">Delete</button>
    `;
    typeList.appendChild(row);

    // wire inside
    row.querySelector('.typeRename').addEventListener('click', ()=>{
      const input = row.querySelector('.typeNameInput');
      const chk = row.querySelector('.typeActionInput');
      const id = input.getAttribute('data-id');
      const idx = types.findIndex(x => x.id === id);
      if (idx >= 0){
        types[idx].name = input.value.trim() || types[idx].name;
        types[idx].action = chk.checked;
        saveJSON(KEYS.TYPES, types);
        renderTypeSelectors();
        renderTypesPreview();
        renderEntries();
      }
    });
    row.querySelector('.typeDelete').addEventListener('click', ()=>{
      const id = row.querySelector('.typeNameInput').getAttribute('data-id');
      if (!confirm('Delete type "' + types.find(x=>x.id===id).name + '"? Existing entries will keep their type id.')) return;
      types = types.filter(x=>x.id !== id);
      saveJSON(KEYS.TYPES, types);
      renderTypeSelectors();
      renderTypesPreview();
      renderEntries();
      openManageTypes();
    });
  });

  // prepare new-type inputs
  newTypeName.value = '';
  newTypeAction.checked = false;

  document.querySelectorAll('.modal').forEach(m=>m.classList.add('hidden'));
  modalManageTypes.classList.remove('hidden');
  showBackdrop();
}

function addTypeFromInput(){
  const nm = newTypeName.value.trim();
  if (!nm) return alert('Please provide a type name.');
  const id = nm.toLowerCase().replace(/\s+/g,'_').replace(/[^\w\-]/g,'') + '_' + Date.now().toString(36);
  const obj = { id, name: nm, action: !!newTypeAction.checked };
  types.push(obj);
  saveJSON(KEYS.TYPES, types);
  renderTypeSelectors();
  renderTypesPreview();
  addTypeFromInputClear();
  openManageTypes(); // refresh
}
function addTypeFromInputClear(){ newTypeName.value=''; newTypeAction.checked=false; }

/* =========================
   Entries rendering & actions
   ========================= */
function renderEntries(){
  // entries is the in-memory cache of DB entries (already sorted where appropriate)
  entries.sort((a,b)=> new Date(b.timestamp) - new Date(a.timestamp));
  entriesBody.innerHTML = '';
  entries.forEach(e => {
    const tr = document.createElement('tr');
    const typeObj = types.find(t=>t.id===e.type) || { name: e.type || 'Unknown', action: false };

    const dateTd = document.createElement('td');
    dateTd.innerHTML = `<div style="font-weight:700">${esc(formatShort(e.timestamp))}</div><div class="small muted">${esc(new Date(e.timestamp).toLocaleString())}</div>`;

    const typeTd = document.createElement('td');
    typeTd.innerHTML = `<div>${esc(typeObj.name)}</div>`;

    const moodTd = document.createElement('td');
    moodTd.className = 'col-mood';
    moodTd.textContent = settings.enableMood ? (e.mood || '') : '';

    const sevTd = document.createElement('td');
    sevTd.className = 'col-sev';
    sevTd.textContent = (settings.enableSeverity && isActionType(e.type) && e.severity) ? String(e.severity) : (isActionType(e.type) ? 'โ€”' : '');

    const durTd = document.createElement('td');
    durTd.textContent = e.duration != null ? (String(e.duration) + ' min') : 'โ€”';

    const notesTd = document.createElement('td');
    notesTd.className = 'notes-cell';
    notesTd.textContent = e.notes && e.notes.trim() ? e.notes : 'โ€”';

    // Actions cell: use classes that keep buttons in a single row and prevent stretching
    const actTd = document.createElement('td');
    actTd.className = 'actions-cell actions-col';
    actTd.innerHTML = `
      <button class="btn btn-ghost" data-id="${esc(e.id)}" data-action="view" title="View">View</button>
      <button class="btn btn-ghost danger" data-id="${esc(e.id)}" data-action="delete" title="Delete">Delete</button>
    `;

    tr.appendChild(dateTd);
    tr.appendChild(typeTd);
    tr.appendChild(moodTd);
    tr.appendChild(sevTd);
    tr.appendChild(durTd);
    tr.appendChild(notesTd);
    tr.appendChild(actTd);
    entriesBody.appendChild(tr);

    // wire actions (use async handler for delete)
    actTd.querySelectorAll('button').forEach(btn => {
      btn.addEventListener('click', async (ev)=>{
        const id = btn.getAttribute('data-id');
        const action = btn.getAttribute('data-action');
        if (action === 'view') viewEntry(id);
        if (action === 'delete') {
          if (!confirm('Delete this entry?')) return;
          try {
            await dbDeleteEntry(id);
            entries = entries.filter(x=>x.id !== id);
            renderEntries();
            drawWeekChart();
          } catch (err) {
            console.error('Failed to delete entry', err);
            alert('Failed to delete entry. See console for details.');
          }
        }
      });
    });
  });

  totalCountEl.textContent = entries.length;
  overviewText.textContent = entries.length ? `Most recent: ${entries.length? formatShort(entries[0].timestamp) : 'โ€”'}` : 'No entries yet โ€” add one to get started.';
  renderTypesPreview();
}

/* =========================
   View Entry modal
   ========================= */
function viewEntry(id){
  const ent = entries.find(x => x.id === id);
  if (!ent) return alert('Entry not found.');
  currentViewEntryId = id;
  const typeObj = types.find(t => t.id === ent.type) || { name: ent.type || 'Unknown', action:false };
  const wrap = document.getElementById('viewEntryBody');
  wrap.innerHTML = `
    <div><strong>Date</strong><div class="small muted">${esc(friendlyDateTime(ent.timestamp))}</div></div>
    <div style="margin-top:8px"><strong>Type</strong><div class="small muted">${esc(typeObj.name)}</div></div>
    ${settings.enableMood ? `<div style="margin-top:8px"><strong>Mood</strong><div class="small muted">${esc(ent.mood||'โ€”')}</div></div>` : ''}
    ${settings.enableSeverity && typeObj.action ? `<div style="margin-top:8px"><strong>Severity</strong><div class="small muted">${esc(ent.severity||'โ€”')}</div></div>` : ''}
    <div style="margin-top:8px"><strong>Duration</strong><div class="small muted">${ent.duration != null ? esc(String(ent.duration) + ' min') : 'โ€”'}</div></div>
    <div style="margin-top:8px"><strong>Notes</strong><div class="small muted">${ent.notes ? esc(ent.notes) : 'โ€”'}</div></div>
  `;
  document.querySelectorAll('.modal').forEach(m=>m.classList.add('hidden'));
  modalViewEntry.classList.remove('hidden');
  showBackdrop();
}

async function deleteViewedEntry(){
  if (!currentViewEntryId) return;
  if (!confirm('Delete this entry?')) return;
  try {
    await dbDeleteEntry(currentViewEntryId);
    entries = entries.filter(x => x.id !== currentViewEntryId);
    currentViewEntryId = null;
    renderEntries();
    drawWeekChart();
    hideBackdrop();
  } catch (err) {
    console.error('Failed to delete viewed entry', err);
    alert('Failed to delete entry. See console for details.');
  }
}

/* =========================
   Chart: weekly bar chart
   ========================= */
function drawWeekChart(){
  const ctx = weekCanvas.getContext('2d');
  const DPR = window.devicePixelRatio || 1;
  const W = weekCanvas.clientWidth;
  const H = weekCanvas.clientHeight;
  weekCanvas.width = Math.floor(W * DPR);
  weekCanvas.height = Math.floor(H * DPR);
  ctx.scale(DPR, DPR);

  // compute last 7 days (including today)
  const counts = [];
  const labels = [];
  const today = new Date();
  for (let i = 6; i >= 0; i--){
    const d = new Date(today);
    d.setDate(today.getDate() - i);
    const start = new Date(d.getFullYear(), d.getMonth(), d.getDate(), 0,0,0,0);
    const end = new Date(d.getFullYear(), d.getMonth(), d.getDate(), 23,59,59,999);
    const c = entries.filter(e => {
      const t = new Date(e.timestamp);
      return t >= start && t <= end;
    }).length;
    counts.push(c);
    labels.push(d.toLocaleDateString([], {weekday:'short'}).slice(0,3));
  }

  // clear
  ctx.clearRect(0,0,W,H);

  // visual params
  const padding = 18;
  const barGap = 10;
  const maxVal = Math.max(1, ...counts);
  const barAreaW = W - padding*2;
  const barW = (barAreaW - (counts.length - 1)*barGap) / counts.length;
  const chartH = H - padding*2;

  // colors from CSS variables
  const barColor = getComputedStyle(document.documentElement).getPropertyValue('--accent').trim() || '#2563eb';
  const barColor2 = getComputedStyle(document.documentElement).getPropertyValue('--accent-2').trim() || '#10b981';
  const textColor = getComputedStyle(document.documentElement).getPropertyValue('--muted').trim() || '#6b7280';

  // draw grid lines
  ctx.strokeStyle = 'rgba(0,0,0,0.06)';
  ctx.lineWidth = 1;
  ctx.beginPath();
  for (let row=0; row<=3; row++){
    const y = padding + (chartH * row / 3);
    ctx.moveTo(padding, y);
    ctx.lineTo(W - padding, y);
  }
  ctx.stroke();

  // draw bars
  counts.forEach((val, i) => {
    const x = padding + i * (barW + barGap);
    const h = (val / maxVal) * (chartH - 20);
    const y = padding + (chartH - h) - 6;
    // gradient
    const grad = ctx.createLinearGradient(x, y, x, y + h);
    grad.addColorStop(0, barColor);
    grad.addColorStop(1, barColor2);
    ctx.fillStyle = grad;
    // rounded rect
    const r = 6;
    roundRect(ctx, x, y, barW, h, r);
    ctx.fill();

    // label (count)
    ctx.fillStyle = textColor;
    ctx.font = '600 12px system-ui, sans-serif';
    ctx.textAlign = 'center';
    ctx.fillText(String(val), x + barW / 2, y - 8);

    // day label
    ctx.font = '12px system-ui, sans-serif';
    ctx.fillText(labels[i], x + barW / 2, padding + chartH + 14);
  });

  // summary stats
  const last7 = counts.reduce((a,b)=>a+b,0);
  weekTotalEl.textContent = last7;
  // top type
  const since = new Date();
  since.setDate(since.getDate() - 6);
  const recent = entries.filter(e => new Date(e.timestamp) >= new Date(since.getFullYear(), since.getMonth(), since.getDate(),0,0,0));
  const typeCounts = {};
  recent.forEach(r => typeCounts[r.type] = (typeCounts[r.type] || 0) + 1);
  let topType = 'โ€”';
  if (Object.keys(typeCounts).length){
    const topId = Object.keys(typeCounts).sort((a,b)=> typeCounts[b]-typeCounts[a])[0];
    const tObj = types.find(t=>t.id===topId);
    topType = tObj ? `${tObj.name} (${typeCounts[topId]})` : `${topId} (${typeCounts[topId]})`;
  }
  topTypeEl.textContent = topType;
  // top mood
  const moodCounts = {};
  recent.forEach(r => { if (r.mood) moodCounts[r.mood] = (moodCounts[r.mood]||0)+1; });
  let topMood = 'โ€”';
  if (Object.keys(moodCounts).length){
    const m = Object.keys(moodCounts).sort((a,b)=> moodCounts[b]-moodCounts[a])[0];
    topMood = `${m} (${moodCounts[m]})`;
  }
  topMoodEl.textContent = topMood;
}

function roundRect(ctx, x, y, w, h, r){
  const radius = Math.min(r, w/2, h/2);
  ctx.beginPath();
  ctx.moveTo(x + radius, y);
  ctx.arcTo(x + w, y, x + w, y + h, radius);
  ctx.arcTo(x + w, y + h, x, y + h, radius);
  ctx.arcTo(x, y + h, x, y, radius);
  ctx.arcTo(x, y, x + w, y, radius);
  ctx.closePath();
}

/* =========================
   Reminders (settings still in localStorage)
   ========================= */
function openReminders(){
  reminderTime.value = reminder.time || '';
  enableRemindersInput.checked = !!reminder.enabled;
  reminderStatus.textContent = `Current saved: ${reminder.time || 'none'} (enabled: ${reminder.enabled ? 'yes' : 'no'})`;
  document.querySelectorAll('.modal').forEach(m=>m.classList.add('hidden'));
  modalReminders.classList.remove('hidden');
  showBackdrop();
}

async function saveReminderSettings(){
  const t = reminderTime.value || null;
  const en = !!enableRemindersInput.checked;
  reminder.time = t;
  reminder.enabled = en;
  saveJSON(KEYS.REMINDER, reminder);
  settings.enableReminders = en;
  saveJSON(KEYS.SETTINGS, settings);
  applySettingsToForm();
  applySettings();
  scheduleReminderLoop();
  hideBackdrop();
  if (en){
    // request permission if necessary
    if (Notification && Notification.permission !== 'granted') {
      try {
        await Notification.requestPermission();
      } catch(e){}
    }
  }
}

function scheduleReminderLoop(){
  if (reminderInterval) {
    clearInterval(reminderInterval);
    reminderInterval = null;
  }
  // only run if feature is enabled in settings and reminder.enabled
  if (!settings.enableReminders || !reminder.enabled || !reminder.time) return;
  // Do a check every 60 seconds (aligned to minute)
  checkReminderNow(); // immediate check
  reminderInterval = setInterval(checkReminderNow, 60 * 1000);
}

let lastReminderTrigger = null;
function checkReminderNow(){
  if (!reminder.time || !reminder.enabled) return;
  const now = new Date();
  const hh = pad(now.getHours());
  const mm = pad(now.getMinutes());
  const cur = `${hh}:${mm}`;
  if (cur !== reminder.time) return;
  // avoid repeat triggers within the same minute
  if (lastReminderTrigger === cur) return;
  lastReminderTrigger = cur;
  // show notification if permission
  if (window.Notification && Notification.permission === 'granted') {
    new Notification('Reminder', { body: 'Time to log an entry', silent: false });
  } else {
    // fallback: small on-screen prompt
    alert('Reminder: time to log an entry.');
  }
}

/* =========================
   Export / Import (read from DB to ensure completeness)
   ========================= */
async function exportCSV(){
  if (!settings.enableExport) return alert('Export is disabled in Settings.');
  try {
    const all = await dbGetAllEntries();
    const header = ['timestamp','type','mood','severity','duration','notes'];
    const rows = all.map(e => [e.timestamp, e.type, e.mood || '', e.severity ?? '', e.duration ?? '', e.notes || '']);
    const csv = [header.join(',')].concat(rows.map(r => r.map(csvEscape).join(','))).join('\n');
    const blob = new Blob([csv], { type: 'text/csv;charset=utf-8' });
    downloadBlob('local-journal-export.csv', blob);
  } catch (err) {
    console.error('Failed to export CSV', err);
    alert('Export failed. See console for details.');
  }
}

async function exportJSON(){
  if (!settings.enableExport) return alert('Export is disabled in Settings.');
  try {
    const all = await dbGetAllEntries();
    const blob = new Blob([JSON.stringify(all, null, 2)], { type: 'application/json;charset=utf-8' });
    downloadBlob('local-journal-export.json', blob);
  } catch (err) {
    console.error('Failed to export JSON', err);
    alert('Export failed. See console for details.');
  }
}

function csvEscape(val){
  if (val === null || val === undefined) return '';
  const s = String(val).replace(/\r?\n/g,' ');
  if (s.includes(',') || s.includes('"')) {
    return '"' + s.replaceAll('"','""') + '"';
  }
  return s;
}

function handleImportFile(e){
  const file = e.target.files && e.target.files[0];
  if (!file) return;
  const reader = new FileReader();
  reader.onload = async (ev) => {
    try{
      const parsed = JSON.parse(ev.target.result);
      if (!Array.isArray(parsed)) return alert('Invalid JSON: expected an array of entries.');
      // basic validation
      const good = parsed.filter(p => p.timestamp && p.type);
      if (!good.length) return alert('No valid entries found.');
      // ask user whether to append or replace
      if (!confirm(`Import ${good.length} entries. Click OK to append to existing entries.`)) return;
      // ensure ids
      const normalized = good.map(x=>{
        return {
          id: x.id || ('e_' + Date.now().toString(36) + '_' + Math.random().toString(36).slice(2,8)),
          timestamp: x.timestamp,
          type: x.type,
          mood: x.mood || '',
          severity: x.severity ?? null,
          duration: x.duration ?? null,
          notes: x.notes || ''
        };
      });
      // bulk write to DB
      await dbBulkPut(normalized);
      // refresh in-memory cache
      entries = await dbGetAllEntries();
      entries.sort((a,b)=> new Date(b.timestamp) - new Date(a.timestamp));
      renderEntries();
      drawWeekChart();
      alert('Import complete.');
    }catch(err){
      console.error(err);
      alert('Failed to import JSON: ' + err.message);
    } finally {
      e.target.value = '';
    }
  };
  reader.readAsText(file);
}

/* =========================
   Clearing
   ========================= */
async function clearAllData(){
  if (!confirm('Clear all app data (entries, types, settings, reminders)? This cannot be undone.')) return;
  try {
    await dbClearEntries();
    localStorage.removeItem(KEYS.TYPES);
    localStorage.removeItem(KEYS.SETTINGS);
    localStorage.removeItem(KEYS.REMINDER);
    entries = [];
    types = defaultTypes.slice();
    settings = DEFAULT_SETTINGS;
    reminder = DEFAULT_REMINDER;
    applySettingsToForm();
    applySettings();
    renderTypeSelectors();
    renderEntries();
    drawWeekChart();
    alert('All data cleared.');
  } catch (err) {
    console.error('Failed to clear data', err);
    alert('Failed to clear data. See console for details.');
  }
}

async function clearEntries(){
  if (!confirm('Clear all saved entries?')) return;
  try {
    await dbClearEntries();
    entries = [];
    renderEntries();
    drawWeekChart();
  } catch (err) {
    console.error('Failed to clear entries', err);
    alert('Failed to clear entries. See console for details.');
  }
}

/* =========================
   Export modal & import
   ========================= */
function openExport(){
  if (!settings.enableExport) return alert('Export is disabled in settings.');
  document.querySelectorAll('.modal').forEach(m=>m.classList.add('hidden'));
  modalExport.classList.remove('hidden');
  showBackdrop();
}

/* =========================
   Settings modal
   ========================= */
function openSettings(){
  applySettingsToForm();
  document.querySelectorAll('.modal').forEach(m=>m.classList.add('hidden'));
  modalSettings.classList.remove('hidden');
  showBackdrop();
}

/* =========================
   Emoji picker
   ========================= */
const EMOJIS = [
  // Saddest / Negative
  '๐Ÿ˜ญ','๐Ÿ˜ข','๐Ÿ˜ž','๐Ÿ˜Ÿ','๐Ÿ™','โ˜น๏ธ',
  '๐Ÿ˜ฃ','๐Ÿ˜–','๐Ÿ˜ซ','๐Ÿ˜ฉ',
  '๐Ÿ˜ ','๐Ÿ˜ก','๐Ÿคฌ',

  // Worried / Fearful
  '๐Ÿ˜จ','๐Ÿ˜ฐ','๐Ÿ˜ฑ','๐Ÿ˜ง',

  // Neutral / Ambiguous
  '๐Ÿ˜ถ','๐Ÿ˜','๐Ÿ˜‘','๐Ÿ™„','๐Ÿ˜ฌ','๐Ÿค”','๐Ÿคจ',

  // Surprised / Shocked
  '๐Ÿ˜ฏ','๐Ÿ˜ฎ','๐Ÿ˜ฒ','๐Ÿ˜ณ','๐Ÿ˜ต','๐Ÿคฏ',

  // Slightly Positive
  '๐Ÿ™‚','๐Ÿ˜Š','๐Ÿ˜Œ','๐Ÿ˜‰',

  // Happy / Laughing
  '๐Ÿ˜ƒ','๐Ÿ˜„','๐Ÿ˜','๐Ÿ˜†','๐Ÿ˜‚','๐Ÿคฃ',

  // Playful / Excited
  '๐Ÿ˜‹','๐Ÿ˜œ','๐Ÿคช','๐Ÿ˜','๐Ÿคฉ','๐Ÿฅณ'
];

function setupEmojiPicker(){
  emojiPicker.innerHTML = '';
  EMOJIS.forEach(e=>{
    const b = document.createElement('button');
    b.className = 'emoji-btn';
    b.textContent = e;
    b.title = e;
    b.addEventListener('click', ()=> {
      entryMood.value = e;
      quickMood.value = e;
      emojiPicker.classList.add('hidden');
    });
    emojiPicker.appendChild(b);
  });
}

/* =========================
   Toggle collapse list
   ========================= */
function toggleCollapse(){
  isListCollapsed = !isListCollapsed;
  entriesBody.parentElement.style.display = isListCollapsed ? 'none' : '';
  document.getElementById('toggleCollapse').textContent = isListCollapsed ? 'Expand' : 'Collapse';
}

/* =========================
   Import/Export helpers in settings (text import)
   ========================= */
async function handleImportJsonText(jsonText){
  try{
    const parsed = JSON.parse(jsonText);
    if (!Array.isArray(parsed)) throw new Error('Expected array');
    const normalized = parsed.map(x => ({
      id: x.id || ('e_' + Date.now().toString(36) + Math.random().toString(36).slice(2,5)),
      timestamp: x.timestamp,
      type: x.type,
      mood: x.mood || '',
      severity: x.severity ?? null,
      duration: x.duration ?? null,
      notes: x.notes || ''
    }));
    await dbBulkPut(normalized);
    entries = await dbGetAllEntries();
    entries.sort((a,b)=> new Date(b.timestamp) - new Date(a.timestamp));
    renderEntries();
    drawWeekChart();
    alert('Imported ' + parsed.length + ' entries.');
  }catch(err){
    alert('Import failed: ' + err.message);
  }
}

/* =========================
   Init: ensure types set (persist small items in localStorage)
   ========================= */
if (!Array.isArray(types) || types.length === 0){
  types = defaultTypes.slice();
  saveJSON(KEYS.TYPES, types);
}
if (!settings || typeof settings !== 'object'){ settings = DEFAULT_SETTINGS; saveJSON(KEYS.SETTINGS, settings); }
if (!reminder || typeof reminder !== 'object'){ reminder = DEFAULT_REMINDER; saveJSON(KEYS.REMINDER, reminder); }

init().catch(err => {
  console.error('Initialization failed', err);
});

/* =========================
   Extra: Save settings watchers (only small things remain in localStorage)
   ========================= */
window.addEventListener('beforeunload', ()=> {
  // entries are persisted to IndexedDB on each operation โ€” no need to write them here
  saveJSON(KEYS.TYPES, types);
  saveJSON(KEYS.SETTINGS, settings);
  saveJSON(KEYS.REMINDER, reminder);
});

/* =========================
   Other UI wiring for convenience
   ========================= */
document.getElementById('btnExport2').addEventListener('click', openExport);
document.getElementById('btnExport').addEventListener('click', openExport);
document.getElementById('btnQuickLog').addEventListener('click', openQuickLog);

/* === Handle imported file from sidebar input === */
document.getElementById('importFile').addEventListener('change', handleImportFile);
  :root {
  --bg: #1a0b1f;             /* deep purple-black */
  --card: #2a0d2e;           /* darker pinkish-purple */
  --muted: #c084fc;          /* muted lilac for secondary text */
  --text: #fdf2f8;           /* light pink-white for primary text */
  --accent: #ec4899;         /* hot pink */
  --accent-2: #8b5cf6;       /* vibrant purple */
  --danger: #ef4444;         /* strong red for errors/danger */
  --glass: rgba(255, 0, 128, 0.15); /* pink glow */
  --glass-2: rgba(139, 92, 246, 0.15); /* purple glow */
  --shadow: 0 8px 24px rgba(236, 72, 153, 0.3); /* pink shadow */
  --radius: 12px;
  --grid-gap: 18px;
  --card-padding: 14px;
  --compact-gap: 8px;
  --ui-gap: 10px;
  --small-radius: 8px;
  --mono: ui-monospace, SFMono-Regular, Menlo, Monaco, "Roboto Mono", "Courier New", monospace;
  --ui-font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial;
}

html,body {
  height: 100%;
  margin: 0;
  font-family: var(--ui-font);
  background: linear-gradient(180deg, var(--bg) 0%, #2a0d2e 100%);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* prevent accidental page-level horizontal scrolling caused by tiny rounding differences */
html, body {
  overflow-x: hidden;
}

.app {
  max-width: 1100px;
  margin: 28px auto;
  padding: 18px;
  display: grid;
  grid-template-columns: 360px 1fr;
  gap: var(--grid-gap);
}

.compact .app { gap: var(--compact-gap); }
.compact .card { padding: 8px; border-radius: 8px; }

header {
  grid-column: 1/-1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 6px;
}
h1 {
  font-size: 18px;
  margin: 0;
  letter-spacing: -0.2px;
}
.sub {
  color: var(--muted);
  font-size: 13px;
}

.card {
  background: var(--card);
  box-shadow: var(--shadow);
  border-radius: var(--radius);
  padding: var(--card-padding);
}

.controls {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 8px 12px;
  border-radius: 10px;
  border: none;
  cursor: pointer;
  font-weight: 600;
  background: transparent;
  transition: transform .08s ease, box-shadow .12s ease;
  white-space: nowrap; /* prevent text inside buttons from wrapping */
}
.btn:active { transform: translateY(1px); }

.btn-primary {
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
  color: white;
  box-shadow: 0 6px 14px rgba(236, 72, 153, 0.25);
}
.btn-secondary {
  background: transparent;
  border: 1px solid var(--glass-2);
  color: var(--text);
}
.btn-ghost {
  background: transparent;
  color: var(--text);
  opacity: 0.95;
}
.btn-large { padding: 12px 16px; font-size: 15px; border-radius: 12px; }

.row { display: flex; gap: 10px; align-items: center; }
.col { display: flex; flex-direction: column; gap: 8px; }

label { font-size: 13px; color: var(--muted); display: block; }
input[type="text"], input[type="time"], input[type="number"], select, textarea {
  width: 100%;
  padding: 8px 10px;
  border-radius: 8px;
  border: 1px solid var(--glass-2);
  background: transparent;
  color: var(--text);
  box-sizing: border-box;
  font-size: 14px;
}
textarea { min-height: 80px; resize: vertical; padding-top: 10px; }

.right {
  display: flex;
  flex-direction: column;
  gap: var(--grid-gap);
}

.chart-wrap {
  display: grid;
  grid-template-columns: 1fr 160px;
  gap: 12px;
  align-items: center;
}
canvas {
  width: 100%; height: 140px; display: block;
  border-radius: 8px;
  background: linear-gradient(180deg, rgba(139,92,246,0.08), transparent);
}

.overview {
  padding: 12px;
  border-radius: 10px;
  background: linear-gradient(180deg, rgba(236,72,153,0.08), transparent);
  min-height: 80px;
}
.muted { color: var(--muted); font-size: 13px; }

.table-wrap {
  margin-top:10px;
  overflow:auto; /* only scroll when strictly necessary */
  -webkit-overflow-scrolling: touch;
}

/* Keep table flexible, allow browser to size columns sensibly */
table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
  table-layout: auto; /* changed from fixed so actions column isn't squeezed */
  word-break: break-word;
}
th,td {
  text-align: left;
  padding: 10px 8px;
  border-bottom: 1px solid var(--glass-2);
  vertical-align: top;
  overflow-wrap: anywhere;
}
th { 
  font-weight: 700; 
  color: var(--muted); 
  font-size: 12px; 
  text-transform: uppercase; 
  letter-spacing: 0.6px; 
}
tr:hover td { background: linear-gradient(90deg, rgba(236,72,153,0.05), transparent); }

td.notes-cell {
  white-space: pre-wrap;
  word-break: break-word;
}

.pill {
  display: inline-block;
  padding: 6px 8px;
  border-radius: 999px;
  background: var(--glass);
  font-weight: 600;
  font-size: 13px;
}

.backdrop {
  position: fixed;
  inset: 0;
  background: rgba(10, 0, 20, 0.75);
  display: none;
  align-items: center;
  justify-content: center;
  z-index: 9998;
  padding: 20px;
}
.backdrop.show { display: flex; }
.modal {
  width: min(720px, 98%);
  max-height: 90vh;
  overflow: auto;
  border-radius: 12px;
}
.modal .card { padding: 18px; }

.emoji-grid { display: grid; grid-template-columns: repeat(8,1fr); gap: 8px; }
.emoji-btn { font-size: 18px; padding: 8px; border-radius: 8px; background: var(--glass); border: none; cursor: pointer; }

.small { font-size: 13px; color: var(--muted); }

/* modal actions (kept intentionally separate from table action cell) */
.actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 12px; }

/* type list */
.type-item { display: flex; gap: 8px; align-items: center; padding: 8px; border-radius: 8px; background: var(--glass); }
.type-list { display: flex; flex-direction: column; gap: 8px; }

.hidden { display: none !important; }

.controls .card { display: flex; flex-direction: column; gap: 12px; }

.flex { display: flex; gap: 8px; align-items: center; }
.spacer { flex: 1; }

.danger { color: var(--danger); font-weight: 700; }

/* ===========================================
   ACTIONS CELL: keep buttons horizontally aligned
   =========================================== */

/* A dedicated class applied to the <td> that contains action buttons.
   Keeps buttons on a single row and prevents them from expanding to full width. */
.actions-cell {
  display: inline-flex;
  align-items: center;
  justify-content: flex-end; /* keep to the right of the cell */
  gap: 8px;
  white-space: nowrap;       /* prevent internal text wrapping */
  flex-wrap: nowrap;         /* prevent button wrapping to a new line */
  padding: 8px;              /* consistent padding with other cells */
  box-sizing: border-box;
}

/* Prevent buttons inside the actions cell from stretching */
.actions-cell .btn {
  flex: 0 0 auto;            /* don't grow or shrink; keep intrinsic size */
  padding: 6px 8px;
  min-width: 40px;           /* keeps buttons comfortably tappable on touch screens */
  font-size: 13px;
}

/* Apply a modest fixed width to the Actions column so two buttons usually fit.
   Adjust the width to taste (increase if your labels are longer). */
.actions-col {
  width: 160px;
  min-width: 120px;
  max-width: 240px;
  vertical-align: middle;
  overflow: visible;
}

/* Make sure header cell follows same sizing */
th.actions-col { width: 160px; min-width: 120px; }

/* Responsive behavior:
   - The table container already has overflow:auto โ€” if viewport is very narrow,
     the table will scroll horizontally instead of wrapping the action buttons.
   - On very narrow screens we tighten spacing so buttons remain side-by-side when possible.
*/
@media (max-width: 420px) {
  /* Keep the action buttons side-by-side, but reduce spacing */
  .actions-cell { gap: 6px; }
  .actions-cell .btn { padding: 5px 6px; min-width: 36px; font-size: 13px; }
  /* If you want icons only on tiny screens you can swap text to icons in JS/rendering */
}

/* responsive layout rules */
@media (max-width:960px) {
  .app { grid-template-columns: 1fr; padding: 12px; }
  .chart-wrap{ grid-template-columns: 1fr; }
}

footer {
  grid-column: 1/-1;
  text-align: center;
  color: var(--muted);
  margin-top: 10px;
  font-size: 12px;
}
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <title>Inspirational Quotes</title>
  <!-- Main site CSS -->
  <link rel="stylesheet" href="./styles.css" />
  <!-- Minimal page-specific styles -->
  <style>
    /* Quotes container styling */
    .quotes {
      max-width: 800px;
      margin: 40px auto;
      padding: 20px;
      border-radius: 10px;
      background: var(--glass, rgba(255,255,255,0.1));
      box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    }

    /* Individual quotes */
    .quote {
      font-style: italic;
      margin: 12px 0;
      border-left: 3px solid var(--accent, #ec4899);
      padding-left: 12px;
    }

    #btnBack {
      margin-top: 20px;
    }
  </style>
</head>

<body>
  <div class="quotes card">
    <h1>Daily Quote</h1>
    <h2>w.i.p.</h2>
    <p class="quote" id="quoteText"></p>
    <button class="btn btn-secondary" id="btnBack">โ† Back to Journal</button>
  </div>

  <script>
    // Array of quotes
    const quotes = [
      "โ€œThe best way to predict the future is to create it.โ€ โ€” Peter Drucker"
    ];

    // Select a random quote
    const randomQuote = quotes[Math.floor(Math.random() * quotes.length)];

    // Display it on the page
    document.getElementById('quoteText').textContent = randomQuote;

    // Navigate back to the main journal page
    document.getElementById('btnBack').addEventListener('click', () => {
      location.hash = 'index';
    });
  </script>
</body>
</html>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Personal Journal โ€” User Guide</title>
<style>
  body {margin:0;font-family:system-ui,sans-serif;background:#07121d;color:#e6eef8;line-height:1.5;}
  .wrap{max-width:800px;margin:28px auto;padding:20px;}
  h1,h2,h3{margin-top:1em;margin-bottom:.5em;}
  .card{background:rgba(255,255,255,0.02);border-radius:10px;padding:16px;margin-top:16px;}
  a.btn{padding:8px 10px;border-radius:8px;background:#7c3aed;color:white;text-decoration:none;font-weight:600;margin-right:6px;}
  .muted{color:#94a3b8;font-size:0.9em;}
  ul{margin:0 0 1em 20px;}
  ol{margin:0 0 1em 20px;}
  .warn{color:#fecaca;}
  .ok{color:#bbf7d0;}
</style>
</head>
<body>
  <div class="wrap">
    <header>
      <h1>Local Journal โ€” User Guide</h1>
      <div class="muted">A practical walkthrough of your appโ€™s main features.</div>
    </header>

    <div class="card">
      <h2>Quick Start โ€” Common Tasks</h2>
      <ol>
        <li><strong>Add a new entry</strong>
          <ul>
            <li>Click <strong>Add Entry</strong>.</li>
            <li>Fill in the date, type, mood, severity, duration, and notes.</li>
            <li>Click <strong>Save</strong>.</li>
          </ul>
        </li>
        <li><strong>Quick Log</strong>
          <ul>
            <li>Click <strong>Quick Log</strong> to add a minimal entry (time, type, optional mood).</li>
            <li>Click <strong>Save</strong>.</li>
          </ul>
        </li>
        <li><strong>View or delete entries</strong>
          <ul>
            <li>Click <strong>View</strong> or <strong>Delete</strong> on any entry.</li>
          </ul>
        </li>
        <li><strong>Export / Import</strong>
          <ul>
            <li>Use Export to save your entries as CSV or JSON files.</li>
            <li>Use Import to load entries from a JSON file.</li>
          </ul>
        </li>
      </ol>
    </div>

    <div class="card">
      <h2>UI Overview</h2>
      <ul>
        <li><strong>Add Entry</strong> โ€” Opens form for new journal entries.</li>
        <li><strong>Quick Log</strong> โ€” Adds minimal entries quickly.</li>
        <li><strong>Reminders</strong> โ€” Enable notifications at set times.</li>
        <li><strong>Export / Import</strong> โ€” Save or load your journal entries.</li>
        <li><strong>Charts</strong> โ€” Weekly summaries of your logged data.</li>
        <li><strong>Entries Table</strong> โ€” Lists all saved entries with view/delete options.</li>
      </ul>
    </div>

    <div class="card">
      <h2>Tips & Troubleshooting</h2>
      <ul>
        <li>Ensure your browser allows local storage; otherwise, entries may not save.</li>
        <li>Notifications only work when the tab is open and permission is granted.</li>
        <li>If imported JSON fails, check it has the correct format with timestamps and type for each entry.</li>
        <li>Severity will only display for entries marked as action types.</li>
        <li><span class="warn">Sensitive content alert:</span> Some default categories include self-harm types. Make sure to use responsibly and seek professional help if needed.</li>
      </ul>
    </div>

    <div class="card">
      <h2>Data Safety</h2>
      <p class="muted">All your data is stored locally in your browser. Export files to back up or transfer entries. Clearing the app or browser data will erase entries unless previously exported.</p>
    </div>

    <footer class="muted">
      <p>Simple user guide for Local Journal. Focused on using the app safely and effectively. No developer knowledge required.</p>
    </footer>
  </div>
</body>
</html>