My name is Anna Möller and these are some of my photo projects.

Sorry, but nothing was found. Please try a search with different keywords.

Sorry, but nothing was found. Please try a search with different keywords.

Sorry, but nothing was found. Please try a search with different keywords.

Sorry, but nothing was found. Please try a search with different keywords.

Sorry, but nothing was found. Please try a search with different keywords.


Twenty Twenty-Five

email@example.com
+1 555 349 1806

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>WWS CALI 0.1 — Vault</title>
  <style>
    :root{
      --bg:#0d0f14; --card:#121623; --ink:#e9eef7; --muted:#aab3c5;
      --line:#26304a; --soft:#0f1320; --btn:#1a2240; --btn2:#15203a;
      --danger:#4a1f1f; --ok:#1f4a2b; --warn:#4a3b1f;
      font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
    }
    body{ margin:0; background:var(--bg); color:var(--ink); }
    header{ padding:16px 18px; border-bottom:1px solid var(--line); }
    h1{ margin:0 0 6px; font-size:18px; letter-spacing:.3px; }
    .sub{ margin:0; font-size:13px; color:var(--muted); }
    main{ max-width:1200px; margin:0 auto; padding:16px 18px 40px; }
    .tabs{ display:flex; gap:8px; flex-wrap:wrap; margin:12px 0 14px; }
    .tabbtn{
      border:1px solid var(--line); background:var(--btn2); color:var(--ink);
      padding:10px 12px; border-radius:12px; cursor:pointer; font-weight:650;
    }
    .tabbtn.active{ background:var(--btn); }
    .grid{ display:grid; grid-template-columns:1fr; gap:12px; }
    @media(min-width:980px){ .grid{ grid-template-columns:420px 1fr; } }
    .card{
      background:var(--card); border:1px solid var(--line);
      border-radius:16px; padding:14px; box-shadow:0 10px 28px rgba(0,0,0,.25);
    }
    h2{ margin:0 0 10px; font-size:15px; }
    label{ display:block; font-size:12px; color:var(--muted); margin:10px 0 6px; }
    input, textarea, select{
      width:100%; box-sizing:border-box; padding:10px;
      border-radius:12px; border:1px solid var(--line);
      background:var(--soft); color:var(--ink); outline:none;
    }
    textarea{ min-height:84px; resize:vertical; }
    .row{ display:grid; grid-template-columns:1fr 1fr; gap:10px; }
    .row3{ display:grid; grid-template-columns:1fr 1fr 1fr; gap:10px; }
    .btnbar{ display:flex; gap:10px; flex-wrap:wrap; margin-top:12px; }
    button{
      border:1px solid var(--line); background:var(--btn2); color:var(--ink);
      padding:10px 12px; border-radius:12px; cursor:pointer; font-weight:650;
    }
    button.primary{ background:var(--btn); }
    button.danger{ background:var(--danger); border-color:#6a2e2e; }
    button.ok{ background:var(--ok); border-color:#2c6a3d; }
    button.warn{ background:var(--warn); border-color:#6a542c; }
    hr{ border:0; border-top:1px solid var(--line); margin:14px 0; }
    .muted{ color:var(--muted); font-size:12px; }
    .pill{ display:inline-block; padding:4px 10px; border-radius:999px; border:1px solid var(--line); background:rgba(255,255,255,.03); font-size:12px; color:var(--muted); }
    table{ width:100%; border-collapse:collapse; }
    th,td{ text-align:left; padding:10px 8px; border-bottom:1px solid var(--line); vertical-align:top; }
    th{ color:var(--muted); font-size:12px; font-weight:650; }
    tr:hover{ background:rgba(255,255,255,.03); }
    .right{ text-align:right; }
    .small{ font-size:12px; color:var(--muted); }
    .hidden{ display:none; }
    .mono{ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
    .twoColNotes{ display:grid; grid-template-columns:1fr; gap:10px; }
    @media(min-width:980px){ .twoColNotes{ grid-template-columns:1fr 1fr; } }
    .checkgrid{ display:grid; grid-template-columns:1fr 1fr; gap:10px; }
    .checkline{ display:flex; align-items:center; gap:10px; padding:8px 10px; border:1px solid var(--line); border-radius:12px; background:rgba(255,255,255,.02); }
    .checkline input{ width:auto; }
  </style>
</head>
<body>
<header>
  <h1>WWS CALI 0.1 — Vault</h1>
  <p class="sub">Offline-first calendar, routine log, and WWS publishing rhythm. Export JSON to move devices. Optional server sync later.</p>
</header>

<main>
  <div class="tabs">
    <button class="tabbtn active" data-tab="today">Today</button>
    <button class="tabbtn" data-tab="calendar">Calendar</button>
    <button class="tabbtn" data-tab="wws">WWS Weekly</button>
    <button class="tabbtn" data-tab="export">Export / Import</button>
    <button class="tabbtn" data-tab="sync">Sync (optional)</button>
  </div>

  <!-- TODAY -->
  <section id="tab-today">
    <div class="grid">
      <div class="card">
        <h2>Daily Page</h2>

        <div class="row">
          <div>
            <label>Date</label>
            <input id="d_date" type="date" />
          </div>
          <div>
            <label>Wake time</label>
            <input id="d_wake" type="time" />
          </div>
        </div>

        <div class="row">
          <div>
            <label>Sleep time (night before)</label>
            <input id="d_sleep" type="time" />
          </div>
          <div>
            <label>One word for inner weather</label>
            <input id="d_weather" placeholder="e.g., clear / heavy / sharp" />
          </div>
        </div>

        <hr />

        <h2>Foundation Completed</h2>
        <div class="checkgrid">
          <label class="checkline"><input type="checkbox" id="d_med" /> Meditation (20–30 mins)</label>
          <label class="checkline"><input type="checkbox" id="d_move" /> Movement (yoga / weights)</label>
          <label class="checkline"><input type="checkbox" id="d_ski" /> Ski walk & training (60–90 mins)</label>
          <label class="checkline"><input type="checkbox" id="d_house" /> House baseline (kitchen / toilets / quick vacuum)</label>
          <label class="checkline"><input type="checkbox" id="d_admin" /> Emails + 3 priorities chosen</label>
          <label class="checkline"><input type="checkbox" id="d_balance" /> Balance kept (no overload)</label>
        </div>

        <hr />

        <h2>Direction</h2>
        <label>The one thing that matters today</label>
        <input id="d_one" placeholder="One clean sentence." />

        <div class="row">
          <div>
            <label>Support action 1</label>
            <input id="d_sup1" />
          </div>
          <div>
            <label>Support action 2</label>
            <input id="d_sup2" />
          </div>
        </div>

        <hr />

        <h2>Energy & Nourishment</h2>
        <div class="row">
          <div>
            <label>Feeding window honoured (3–6pm)</label>
            <select id="d_feed">
              <option value="">Select</option>
              <option>Yes</option>
              <option>No</option>
            </select>
          </div>
          <div>
            <label>Minerals taken</label>
            <select id="d_mins">
              <option value="">Select</option>
              <option>Yes</option>
              <option>No</option>
            </select>
          </div>
        </div>

        <label>Supplements today</label>
        <div class="checkgrid">
          <label class="checkline"><input type="checkbox" id="d_algae" /> Algae (every other day)</label>
          <label class="checkline"><input type="checkbox" id="d_camu" /> Camu camu</label>
          <label class="checkline"><input type="checkbox" id="d_thistle" /> Milk thistle</label>
          <label class="checkline"><input type="checkbox" id="d_clove" /> Clove water</label>
        </div>

        <label>Body response after food</label>
        <select id="d_bodyresp">
          <option value="">Select</option>
          <option>Light</option>
          <option>Neutral</option>
          <option>Heavy</option>
          <option>Inflamed</option>
        </select>

        <hr />

        <div class="twoColNotes">
          <div>
            <h2>Shadow Check</h2>
            <label>Where did I notice resistance today</label>
            <textarea id="d_shadow"></textarea>
            <label>What story tried to run me</label>
            <textarea id="d_story"></textarea>
          </div>
          <div>
            <h2>Record</h2>
            <label>What actually moved today</label>
            <textarea id="d_moved"></textarea>
            <label>What stayed unresolved (leave it here)</label>
            <textarea id="d_unres"></textarea>
            <label>One thing I did well (fact, not praise)</label>
            <textarea id="d_well"></textarea>
          </div>
        </div>

        <div class="btnbar">
          <button class="primary" id="saveDaily">Save Daily</button>
          <button id="loadDaily">Load</button>
          <button class="warn" id="resetDaily">Reset fields</button>
        </div>

        <div class="muted" style="margin-top:10px;">
          This page is a record, not a judgement.
        </div>
      </div>

      <div class="card">
        <h2>Next 30 days (Red-line first)</h2>

        <div class="row3">
          <div>
            <label>Filter</label>
            <select id="f_cat">
              <option value="All" selected>All</option>
              <option>High Court</option>
              <option>District Court</option>
              <option>Legal Admin</option>
              <option>WWS Publishing</option>
              <option>Income / Organic Road Show</option>
              <option>Family / Care</option>
              <option>Utilities / Civil Bills</option>
              <option>Other</option>
            </select>
          </div>
          <div>
            <label>Priority</label>
            <select id="f_pri">
              <option value="All" selected>All</option>
              <option>Red-line</option>
              <option>High</option>
              <option>Normal</option>
              <option>Low</option>
            </select>
          </div>
          <div>
            <label>Search</label>
            <input id="f_q" placeholder="title, tags..." />
          </div>
        </div>

        <div class="btnbar">
          <button class="ok" id="seedCore">Seed Feb 2026 court dates</button>
        </div>

        <div style="overflow:auto; margin-top:10px;">
          <table>
            <thead>
              <tr>
                <th style="min-width:110px;">Date</th>
                <th style="min-width:120px;">Category</th>
                <th>Title</th>
                <th style="min-width:90px;">Priority</th>
              </tr>
            </thead>
            <tbody id="nextRows"></tbody>
          </table>
        </div>
        <div class="small" id="nextCount"></div>
      </div>
    </div>
  </section>

  <!-- CALENDAR -->
  <section id="tab-calendar" class="hidden">
    <div class="grid">
      <div class="card">
        <h2>Add / Edit Event</h2>

        <label>Title</label>
        <input id="e_title" placeholder="e.g., High Court — injunction hearing" />

        <div class="row">
          <div>
            <label>Date</label>
            <input id="e_date" type="date" />
          </div>
          <div>
            <label>Time (optional)</label>
            <input id="e_time" type="time" />
          </div>
        </div>

        <div class="row">
          <div>
            <label>Category</label>
            <select id="e_cat">
              <option>High Court</option>
              <option>District Court</option>
              <option>Legal Admin</option>
              <option>WWS Publishing</option>
              <option>Income / Organic Road Show</option>
              <option>Family / Care</option>
              <option>Utilities / Civil Bills</option>
              <option>Other</option>
            </select>
          </div>
          <div>
            <label>Priority</label>
            <select id="e_pri">
              <option>Red-line</option>
              <option>High</option>
              <option selected>Normal</option>
              <option>Low</option>
            </select>
          </div>
        </div>

        <label>Tags (comma separated)</label>
        <input id="e_tags" placeholder="Pepper, affidavit, service, WWS, outreach" />

        <label>Notes / Strategy</label>
        <textarea id="e_notes" placeholder="Key objective, prep requirements, what must happen before the date."></textarea>

        <div class="row">
          <div>
            <label>Reminder days before (optional)</label>
            <input id="e_rem" type="number" min="0" placeholder="e.g., 14" />
          </div>
          <div>
            <label>Event ID</label>
            <input id="e_id" disabled class="mono" />
          </div>
        </div>

        <div class="btnbar">
          <button class="primary" id="saveEvent">Save Event</button>
          <button id="clearEvent">Clear</button>
        </div>

        <div class="muted" style="margin-top:10px;">
          Tip: Use Priority = Red-line for anything that could end in eviction or custody loss of home, or jail risk.
        </div>
      </div>

      <div class="card">
        <h2>All Events</h2>

        <div class="row3">
          <div>
            <label>Filter category</label>
            <select id="c_cat">
              <option value="All" selected>All</option>
              <option>High Court</option>
              <option>District Court</option>
              <option>Legal Admin</option>
              <option>WWS Publishing</option>
              <option>Income / Organic Road Show</option>
              <option>Family / Care</option>
              <option>Utilities / Civil Bills</option>
              <option>Other</option>
            </select>
          </div>
          <div>
            <label>Priority</label>
            <select id="c_pri">
              <option value="All" selected>All</option>
              <option>Red-line</option>
              <option>High</option>
              <option>Normal</option>
              <option>Low</option>
            </select>
          </div>
          <div>
            <label>Search</label>
            <input id="c_q" placeholder="search..." />
          </div>
        </div>

        <div style="overflow:auto; margin-top:10px;">
          <table>
            <thead>
              <tr>
                <th style="min-width:110px;">Date</th>
                <th style="min-width:120px;">Category</th>
                <th>Title</th>
                <th style="min-width:90px;">Priority</th>
                <th style="min-width:120px;" class="right">Actions</th>
              </tr>
            </thead>
            <tbody id="allRows"></tbody>
          </table>
        </div>
        <div class="small" id="allCount"></div>
      </div>
    </div>
  </section>

  <!-- WWS -->
  <section id="tab-wws" class="hidden">
    <div class="grid">
      <div class="card">
        <h2>WWS Weekly (Mon → Sun)</h2>
        <div class="muted">This is your publishing engine. Keep it simple. Keep it moving.</div>

        <hr />

        <label>Week starting (Monday)</label>
        <input id="w_monday" type="date" />

        <label>Book title / working title</label>
        <input id="w_title" placeholder="e.g., Working With Shadow — Volume X" />

        <label>One sentence intent</label>
        <input id="w_intent" placeholder="This week’s book says..." />

        <hr />

        <h2>Weekly steps</h2>
        <div class="checkgrid">
          <label class="checkline"><input type="checkbox" id="w_mon" /> Monday: intent + outline</label>
          <label class="checkline"><input type="checkbox" id="w_tue" /> Tuesday: writing</label>
          <label class="checkline"><input type="checkbox" id="w_wed" /> Wednesday: writing</label>
          <label class="checkline"><input type="checkbox" id="w_thu" /> Thursday: edit + tighten</label>
          <label class="checkline"><input type="checkbox" id="w_fri" /> Friday: format + metadata</label>
          <label class="checkline"><input type="checkbox" id="w_sat" /> Saturday: publish + site update</label>
          <label class="checkline"><input type="checkbox" id="w_sun" /> Sunday: review + next theme</label>
        </div>

        <label>Notes</label>
        <textarea id="w_notes"></textarea>

        <div class="btnbar">
          <button class="primary" id="saveWeek">Save Week</button>
          <button id="loadWeek">Load</button>
          <button class="warn" id="resetWeek">Reset</button>
        </div>
      </div>

      <div class="card">
        <h2>Weekly minerals check (Sunday)</h2>
        <div class="muted">Ten minutes. Objective. No drama.</div>

        <hr />

        <label>Week ending (Sunday)</label>
        <input id="m_sunday" type="date" />

        <div class="checkgrid">
          <label class="checkline"><input type="checkbox" id="m_hyd" /> Hydration consistent</label>
          <label class="checkline"><input type="checkbox" id="m_dig" /> Digestion steady</label>
          <label class="checkline"><input type="checkbox" id="m_energy" /> Energy stable</label>
          <label class="checkline"><input type="checkbox" id="m_sleep" /> Sleep respected</label>
        </div>

        <label>Algae cadence used (Mon/Wed/Fri/Sun)</label>
        <select id="m_algae">
          <option value="">Select</option>
          <option>Yes</option>
          <option>No</option>
          <option>Mixed</option>
        </select>

        <label>Notes (what worked / what did not)</label>
        <textarea id="m_notes"></textarea>

        <div class="btnbar">
          <button class="primary" id="saveMinerals">Save Minerals</button>
          <button id="loadMinerals">Load</button>
        </div>
      </div>
    </div>
  </section>

  <!-- EXPORT -->
  <section id="tab-export" class="hidden">
    <div class="card">
      <h2>Export / Import JSON</h2>
      <div class="muted">Use export/import to move your vault between devices without a server.</div>

      <div class="btnbar">
        <button class="primary" id="doExport">Export</button>
        <button id="doImport">Import</button>
        <button class="danger" id="wipeAll">Wipe local vault</button>
      </div>

      <label>JSON</label>
      <textarea id="jsonBox" class="mono" placeholder="Export appears here. Paste JSON here to import."></textarea>
    </div>
  </section>

  <!-- SYNC -->
  <section id="tab-sync" class="hidden">
    <div class="card">
      <h2>Optional Sync (server storage)</h2>
      <div class="muted">
        If you want access anywhere on any device, you need a small endpoint on your private domain.
        This UI can push/pull JSON to that endpoint. You can add the endpoint later.
      </div>

      <hr />

      <label>Endpoint URL</label>
      <input id="s_url" placeholder="e.g., https://yourdomain.com/cali-sync.php" />

      <label>Access token (simple shared secret)</label>
      <input id="s_token" placeholder="A long random token" />

      <div class="btnbar">
        <button class="ok" id="pushServer">Push vault to server</button>
        <button class="primary" id="pullServer">Pull vault from server</button>
      </div>

      <div class="muted" style="margin-top:10px;">
        Notes: This is basic. For stronger security, you would use real authentication and HTTPS only.
      </div>
    </div>
  </section>
</main>

<script>
/* ---------------------------
   Storage and data model
----------------------------*/
const KEY = "wws_cali_v01";

const state = {
  version: "0.1",
  events: [],
  daily: {},      // daily[YYYY-MM-DD] = {fields...}
  wwsWeeks: {},   // wwsWeeks[YYYY-MM-DD Monday] = {fields...}
  mineralsWeeks: {}, // mineralsWeeks[YYYY-MM-DD Sunday] = {fields...}
  sync: { url: "", token: "" }
};

function loadState(){
  const raw = localStorage.getItem(KEY);
  if (!raw) return;
  try{
    const obj = JSON.parse(raw);
    Object.assign(state, obj);
  }catch(e){}
}
function saveState(){
  localStorage.setItem(KEY, JSON.stringify(state));
}
function uid(){
  return "e_" + Math.random().toString(16).slice(2) + "_" + Date.now().toString(16);
}
function tagsParse(s){
  return (s||"").split(",").map(x=>x.trim()).filter(Boolean);
}
function priWeight(p){
  return ({ "Red-line":0, "High":1, "Normal":2, "Low":3 }[p] ?? 9);
}
function sortEvents(list){
  return [...list].sort((a,b)=>{
    const aw=priWeight(a.priority), bw=priWeight(b.priority);
    if (aw!==bw) return aw-bw;
    const ad=(a.date||"") + (a.time||"");
    const bd=(b.date||"") + (b.time||"");
    return ad.localeCompare(bd);
  });
}
function todayISO(){
  const d = new Date();
  const yyyy = d.getFullYear();
  const mm = String(d.getMonth()+1).padStart(2,"0");
  const dd = String(d.getDate()).padStart(2,"0");
  return `${yyyy}-${mm}-${dd}`;
}
function $(id){ return document.getElementById(id); }

/* ---------------------------
   Tabs
----------------------------*/
document.querySelectorAll(".tabbtn").forEach(btn=>{
  btn.addEventListener("click", ()=>{
    document.querySelectorAll(".tabbtn").forEach(b=>b.classList.remove("active"));
    btn.classList.add("active");
    const tab = btn.dataset.tab;
    document.querySelectorAll("main section[id^='tab-']").forEach(s=>s.classList.add("hidden"));
    $("tab-"+tab).classList.remove("hidden");
    renderAll();
  });
});

/* ---------------------------
   Daily page
----------------------------*/
function dailyCollect(){
  const date = $("d_date").value;
  if(!date) return null;
  return {
    date,
    wake: $("d_wake").value,
    sleep: $("d_sleep").value,
    weather: $("d_weather").value.trim(),
    foundation: {
      med: $("d_med").checked,
      move: $("d_move").checked,
      ski: $("d_ski").checked,
      house: $("d_house").checked,
      admin: $("d_admin").checked,
      balance: $("d_balance").checked
    },
    direction: {
      one: $("d_one").value.trim(),
      sup1: $("d_sup1").value.trim(),
      sup2: $("d_sup2").value.trim()
    },
    nourish: {
      feed: $("d_feed").value,
      minerals: $("d_mins").value,
      algae: $("d_algae").checked,
      camu: $("d_camu").checked,
      thistle: $("d_thistle").checked,
      clove: $("d_clove").checked,
      bodyresp: $("d_bodyresp").value
    },
    shadow: $("d_shadow").value.trim(),
    story: $("d_story").value.trim(),
    moved: $("d_moved").value.trim(),
    unresolved: $("d_unres").value.trim(),
    didwell: $("d_well").value.trim(),
    updatedAt: new Date().toISOString()
  };
}

function dailyFill(obj){
  $("d_date").value = obj.date || "";
  $("d_wake").value = obj.wake || "";
  $("d_sleep").value = obj.sleep || "";
  $("d_weather").value = obj.weather || "";
  $("d_med").checked = !!obj.foundation?.med;
  $("d_move").checked = !!obj.foundation?.move;
  $("d_ski").checked = !!obj.foundation?.ski;
  $("d_house").checked = !!obj.foundation?.house;
  $("d_admin").checked = !!obj.foundation?.admin;
  $("d_balance").checked = !!obj.foundation?.balance;
  $("d_one").value = obj.direction?.one || "";
  $("d_sup1").value = obj.direction?.sup1 || "";
  $("d_sup2").value = obj.direction?.sup2 || "";
  $("d_feed").value = obj.nourish?.feed || "";
  $("d_mins").value = obj.nourish?.minerals || "";
  $("d_algae").checked = !!obj.nourish?.algae;
  $("d_camu").checked = !!obj.nourish?.camu;
  $("d_thistle").checked = !!obj.nourish?.thistle;
  $("d_clove").checked = !!obj.nourish?.clove;
  $("d_bodyresp").value = obj.nourish?.bodyresp || "";
  $("d_shadow").value = obj.shadow || "";
  $("d_story").value = obj.story || "";
  $("d_moved").value = obj.moved || "";
  $("d_unres").value = obj.unresolved || "";
  $("d_well").value = obj.didwell || "";
}

$("saveDaily").addEventListener("click", ()=>{
  const obj = dailyCollect();
  if(!obj){ alert("Choose a date first."); return; }
  state.daily[obj.date] = obj;
  saveState();
  alert("Saved.");
});
$("loadDaily").addEventListener("click", ()=>{
  const date = $("d_date").value;
  if(!date){ alert("Choose a date first."); return; }
  const obj = state.daily[date];
  if(!obj){ alert("No saved daily page for that date."); return; }
  dailyFill(obj);
});
$("resetDaily").addEventListener("click", ()=>{
  const d = $("d_date").value;
  dailyFill({date:d});
});

/* ---------------------------
   Events
----------------------------*/
function eventCollect(){
  const title = $("e_title").value.trim();
  const date = $("e_date").value;
  if(!title || !date) return null;
  const existingId = $("e_id").value.trim();
  const id = existingId || uid();
  return {
    id,
    title,
    date,
    time: $("e_time").value,
    category: $("e_cat").value,
    priority: $("e_pri").value,
    tags: tagsParse($("e_tags").value),
    notes: $("e_notes").value.trim(),
    reminderDays: $("e_rem").value ? Number($("e_rem").value) : "",
    updatedAt: new Date().toISOString(),
    createdAt: existingId ? (state.events.find(x=>x.id===id)?.createdAt || new Date().toISOString()) : new Date().toISOString()
  };
}
function eventFill(e){
  $("e_title").value = e.title || "";
  $("e_date").value = e.date || "";
  $("e_time").value = e.time || "";
  $("e_cat").value = e.category || "Other";
  $("e_pri").value = e.priority || "Normal";
  $("e_tags").value = (e.tags||[]).join(", ");
  $("e_notes").value = e.notes || "";
  $("e_rem").value = (e.reminderDays === "" || e.reminderDays == null) ? "" : String(e.reminderDays);
  $("e_id").value = e.id || "";
}
$("saveEvent").addEventListener("click", ()=>{
  const e = eventCollect();
  if(!e){ alert("Title + Date are required."); return; }
  const idx = state.events.findIndex(x=>x.id===e.id);
  if(idx >= 0) state.events[idx] = e; else state.events.push(e);
  saveState();
  eventFill({});
  renderAll();
});
$("clearEvent").addEventListener("click", ()=> eventFill({}));

function seedCoreDates(){
  const seeds = [
    {
      title:"District Court — burglary charge",
      date:"2026-02-16",
      time:"",
      category:"District Court",
      priority:"Red-line",
      tags:["Bray","appearance","defence"],
      notes:"Red-line. Pack documents day before. Short morning. No heavy decisions after court.",
      reminderDays:14
    },
    {
      title:"High Court — eviction injunction",
      date:"2026-02-17",
      time:"",
      category:"High Court",
      priority:"Red-line",
      tags:["injunction","eviction","affidavit"],
      notes:"Red-line. Preserve position. Keep points prepared and short. Track affidavit service date.",
      reminderDays:14
    }
  ];
  for(const s of seeds){
    // avoid duplicates by title+date
    const exists = state.events.some(e=>e.title===s.title && e.date===s.date);
    if(!exists) state.events.push({ id:uid(), createdAt:new Date().toISOString(), updatedAt:new Date().toISOString(), ...s });
  }
  saveState();
  renderAll();
}
$("seedCore").addEventListener("click", seedCoreDates);

/* ---------------------------
   WWS weekly + minerals weekly
----------------------------*/
function weekCollect(){
  const monday = $("w_monday").value;
  if(!monday) return null;
  return {
    monday,
    title: $("w_title").value.trim(),
    intent: $("w_intent").value.trim(),
    checks: {
      mon:$("w_mon").checked, tue:$("w_tue").checked, wed:$("w_wed").checked,
      thu:$("w_thu").checked, fri:$("w_fri").checked, sat:$("w_sat").checked, sun:$("w_sun").checked
    },
    notes: $("w_notes").value.trim(),
    updatedAt: new Date().toISOString()
  };
}
function weekFill(w){
  $("w_monday").value = w.monday || "";
  $("w_title").value = w.title || "";
  $("w_intent").value = w.intent || "";
  $("w_mon").checked = !!w.checks?.mon;
  $("w_tue").checked = !!w.checks?.tue;
  $("w_wed").checked = !!w.checks?.wed;
  $("w_thu").checked = !!w.checks?.thu;
  $("w_fri").checked = !!w.checks?.fri;
  $("w_sat").checked = !!w.checks?.sat;
  $("w_sun").checked = !!w.checks?.sun;
  $("w_notes").value = w.notes || "";
}
$("saveWeek").addEventListener("click", ()=>{
  const w = weekCollect();
  if(!w){ alert("Choose the Monday date."); return; }
  state.wwsWeeks[w.monday] = w;
  saveState();
  alert("Saved.");
});
$("loadWeek").addEventListener("click", ()=>{
  const monday = $("w_monday").value;
  if(!monday){ alert("Choose the Monday date."); return; }
  const w = state.wwsWeeks[monday];
  if(!w){ alert("No saved week for that Monday."); return; }
  weekFill(w);
});
$("resetWeek").addEventListener("click", ()=>{
  const m = $("w_monday").value;
  weekFill({monday:m});
});

function mineralsCollect(){
  const sunday = $("m_sunday").value;
  if(!sunday) return null;
  return {
    sunday,
    hyd: $("m_hyd").checked,
    dig: $("m_dig").checked,
    energy: $("m_energy").checked,
    sleep: $("m_sleep").checked,
    algae: $("m_algae").value,
    notes: $("m_notes").value.trim(),
    updatedAt: new Date().toISOString()
  };
}
function mineralsFill(m){
  $("m_sunday").value = m.sunday || "";
  $("m_hyd").checked = !!m.hyd;
  $("m_dig").checked = !!m.dig;
  $("m_energy").checked = !!m.energy;
  $("m_sleep").checked = !!m.sleep;
  $("m_algae").value = m.algae || "";
  $("m_notes").value = m.notes || "";
}
$("saveMinerals").addEventListener("click", ()=>{
  const m = mineralsCollect();
  if(!m){ alert("Choose the Sunday date."); return; }
  state.mineralsWeeks[m.sunday] = m;
  saveState();
  alert("Saved.");
});
$("loadMinerals").addEventListener("click", ()=>{
  const sunday = $("m_sunday").value;
  if(!sunday){ alert("Choose the Sunday date."); return; }
  const m = state.mineralsWeeks[sunday];
  if(!m){ alert("No saved minerals week for that Sunday."); return; }
  mineralsFill(m);
});

/* ---------------------------
   Export / Import
----------------------------*/
$("doExport").addEventListener("click", ()=>{
  $("jsonBox").value = JSON.stringify({ exportedAt:new Date().toISOString(), ...state }, null, 2);
});
$("doImport").addEventListener("click", ()=>{
  try{
    const obj = JSON.parse($("jsonBox").value);
    if(!obj || !obj.version || !obj.events) throw new Error("Bad format");
    // keep only known keys
    state.version = obj.version;
    state.events = Array.isArray(obj.events) ? obj.events : [];
    state.daily = obj.daily || {};
    state.wwsWeeks = obj.wwsWeeks || {};
    state.mineralsWeeks = obj.mineralsWeeks || {};
    state.sync = obj.sync || state.sync;
    saveState();
    renderAll();
    alert("Imported.");
  }catch(e){
    alert("Import failed: " + e.message);
  }
});
$("wipeAll").addEventListener("click", ()=>{
  if(!confirm("Wipe local vault? This cannot be undone.")) return;
  localStorage.removeItem(KEY);
  location.reload();
});

/* ---------------------------
   Sync (optional endpoint)
   Server expects:
   - GET returns JSON state
   - POST stores JSON state
   Header: X-Token: <token>
----------------------------*/
function syncFill(){
  $("s_url").value = state.sync.url || "";
  $("s_token").value = state.sync.token || "";
}
$("pushServer").addEventListener("click", async ()=>{
  state.sync.url = $("s_url").value.trim();
  state.sync.token = $("s_token").value.trim();
  saveState();
  if(!state.sync.url || !state.sync.token){ alert("Set URL + token."); return; }

  try{
    const res = await fetch(state.sync.url, {
      method:"POST",
      headers:{
        "Content-Type":"application/json",
        "X-Token": state.sync.token
      },
      body: JSON.stringify(state)
    });
    if(!res.ok) throw new Error("HTTP " + res.status);
    alert("Pushed to server.");
  }catch(e){
    alert("Push failed: " + e.message);
  }
});
$("pullServer").addEventListener("click", async ()=>{
  state.sync.url = $("s_url").value.trim();
  state.sync.token = $("s_token").value.trim();
  saveState();
  if(!state.sync.url || !state.sync.token){ alert("Set URL + token."); return; }

  try{
    const res = await fetch(state.sync.url, {
      method:"GET",
      headers:{ "X-Token": state.sync.token }
    });
    if(!res.ok) throw new Error("HTTP " + res.status);
    const obj = await res.json();
    if(!obj || !obj.version || !obj.events) throw new Error("Bad data from server");
    state.version = obj.version;
    state.events = Array.isArray(obj.events) ? obj.events : [];
    state.daily = obj.daily || {};
    state.wwsWeeks = obj.wwsWeeks || {};
    state.mineralsWeeks = obj.mineralsWeeks || {};
    // keep sync settings
    saveState();
    renderAll();
    alert("Pulled from server.");
  }catch(e){
    alert("Pull failed: " + e.message);
  }
});

/* ---------------------------
   Rendering tables
----------------------------*/
function renderNext30(){
  const cat = $("f_cat")?.value || "All";
  const pri = $("f_pri")?.value || "All";
  const q = ($("f_q")?.value || "").toLowerCase();

  const now = new Date();
  const max = new Date(); max.setDate(max.getDate() + 30);

  let list = state.events.filter(e=>{
    if(!e.date) return false;
    const d = new Date(e.date + "T00:00:00");
    return d >= new Date(now.toDateString()) && d <= max;
  });

  if(cat !== "All") list = list.filter(e=>e.category===cat);
  if(pri !== "All") list = list.filter(e=>e.priority===pri);
  if(q) list = list.filter(e=> (e.title + " " + (e.tags||[]).join(" ")).toLowerCase().includes(q));

  list = sortEvents(list);

  const tb = $("nextRows");
  tb.innerHTML = "";
  for(const e of list){
    const tr = document.createElement("tr");
    tr.innerHTML = `
      <td>${e.date}${e.time ? " " + e.time : ""}</td>
      <td>${e.category}</td>
      <td><div style="font-weight:700;">${escapeHtml(e.title)}</div><div class="small">${escapeHtml((e.tags||[]).join(", "))}</div></td>
      <td>${e.priority}</td>
    `;
    tb.appendChild(tr);
  }
  $("nextCount").textContent = `${list.length} shown`;
}

function renderAllEvents(){
  const cat = $("c_cat")?.value || "All";
  const pri = $("c_pri")?.value || "All";
  const q = ($("c_q")?.value || "").toLowerCase();

  let list = [...state.events];
  if(cat !== "All") list = list.filter(e=>e.category===cat);
  if(pri !== "All") list = list.filter(e=>e.priority===pri);
  if(q) list = list.filter(e=>{
    const blob = (e.title + " " + e.category + " " + e.priority + " " + (e.tags||[]).join(" ") + " " + (e.notes||"")).toLowerCase();
    return blob.includes(q);
  });

  list = sortEvents(list);

  const tb = $("allRows");
  tb.innerHTML = "";
  for(const e of list){
    const tr = document.createElement("tr");
    tr.innerHTML = `
      <td>${e.date}${e.time ? " " + e.time : ""}</td>
      <td>${e.category}</td>
      <td><div style="font-weight:700;">${escapeHtml(e.title)}</div><div class="small">${escapeHtml((e.tags||[]).join(", "))}</div></td>
      <td>${e.priority}</td>
      <td class="right">
        <button data-act="edit" data-id="${e.id}">Edit</button>
        <button data-act="del" data-id="${e.id}" class="danger">Del</button>
      </td>
    `;
    tb.appendChild(tr);
  }
  $("allCount").textContent = `${list.length} shown / ${state.events.length} total`;

  tb.addEventListener("click", (ev)=>{
    const btn = ev.target.closest("button");
    if(!btn) return;
    const id = btn.getAttribute("data-id");
    const act = btn.getAttribute("data-act");
    const idx = state.events.findIndex(x=>x.id===id);
    if(idx < 0) return;

    if(act==="edit"){
      eventFill(state.events[idx]);
      // switch to calendar tab (form is there)
      document.querySelectorAll(".tabbtn").forEach(b=>b.classList.remove("active"));
      document.querySelector(".tabbtn[data-tab='calendar']").classList.add("active");
      document.querySelectorAll("main section[id^='tab-']").forEach(s=>s.classList.add("hidden"));
      $("tab-calendar").classList.remove("hidden");
      window.scrollTo({top:0, behavior:"smooth"});
    }
    if(act==="del"){
      if(!confirm("Delete this event?")) return;
      state.events.splice(idx,1);
      saveState();
      renderAll();
    }
  }, { once:true });
}

function escapeHtml(s){
  return (s||"").replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;");
}

function renderAll(){
  if(!$("d_date").value) $("d_date").value = todayISO();
  if(!$("w_monday").value) $("w_monday").value = "";
  if(!$("m_sunday").value) $("m_sunday").value = "";
  renderNext30();
  renderAllEvents();
  syncFill();
}

$("f_cat").addEventListener("change", renderNext30);
$("f_pri").addEventListener("change", renderNext30);
$("f_q").addEventListener("input", renderNext30);
$("c_cat").addEventListener("change", renderAllEvents);
$("c_pri").addEventListener("change", renderAllEvents);
$("c_q").addEventListener("input", renderAllEvents);

/* ---------------------------
   Boot
----------------------------*/
loadState();
$("d_date").value = todayISO();
renderAll();
</script>
</body>
</html>