{
  "version": 3,
  "sources": ["fresh-hint.js"],
  "sourcesContent": ["// ─────────────────────────────────────────────────────────────────────────\n// What a page does when swr() (datacache.js) hands it a fresher copy of data it\n// already painted from the cache.\n//\n// The cache paints first and revalidates behind the page. Until this existed only\n// the dashboard listened for the fresh copy, so everywhere else a reload showed the\n// old data and the new data waited for the NEXT reload — a crawl mid-build needed\n// two. Each page now takes one of two routes, chosen per page:\n//\n//   applyFresh(rerender)  the page's render is safe to run again. It runs, in\n//                         place, keeping the scroll position — but only while the\n//                         reader has not touched the page yet (no click, tap, key\n//                         or typing since it loaded), so an open panel, a half-typed\n//                         note or a chosen filter is never swept away. Once they\n//                         have, it falls back to the hint below.\n//   showFreshHint()       the page's render is not safe to re-run (one-shot\n//                         setup, drafts, open overlays). A small pill offers a\n//                         refresh; swr() has already cached the fresh copy, so the\n//                         reload it triggers paints the new data at once.\n//\n// Nothing here throws into the caller: a failed re-render degrades to the hint.\n// ─────────────────────────────────────────────────────────────────────────\n\nlet touched = false;\nconst markTouched = () => { touched = true; };\ntry {\n  if (typeof addEventListener === \"function\") {\n    for (const ev of [\"pointerdown\", \"keydown\", \"input\", \"change\"]) {\n      addEventListener(ev, markTouched, { capture: true, passive: true });\n    }\n  }\n} catch { /* no window (tests) */ }\n\n// Whether the reader has interacted with the page since it loaded.\nexport const readerTouched = () => touched;\n\n// Test seam only.\nexport function _resetTouched() { touched = false; }\n\nexport function applyFresh(rerender, { canRerender } = {}) {\n  let ok = !touched;\n  if (ok && canRerender) { try { ok = !!canRerender(); } catch { ok = false; } }\n  if (ok) {\n    const x = typeof scrollX === \"number\" ? scrollX : 0;\n    const y = typeof scrollY === \"number\" ? scrollY : 0;\n    try {\n      rerender();\n      try { if (typeof scrollTo === \"function\" && (scrollX !== x || scrollY !== y)) scrollTo(x, y); } catch {}\n      return \"rerendered\";\n    } catch (e) {\n      try { console.warn(\"[fresh] re-render failed, offering a refresh instead:\", e); } catch {}\n    }\n  }\n  showFreshHint();\n  return \"hint\";\n}\n\nconst HINT_ID = \"rl-fresh-hint\";\nconst STYLE_ID = \"rl-fresh-hint-css\";\nconst CSS = `\n#${HINT_ID}{position:fixed;right:16px;bottom:16px;z-index:9000;display:flex;align-items:center;gap:10px;\n  padding:8px 8px 8px 14px;border-radius:999px;background:var(--bg-card,#1c1c24);color:var(--text-color,#fafafa);\n  border:1px solid var(--border-light,#3f3f46);box-shadow:0 6px 24px rgba(0,0,0,.28);\n  font-family:var(--mono,\"JetBrains Mono\",monospace);font-size:.74rem;line-height:1.2;max-width:calc(100vw - 32px)}\n#${HINT_ID} button{font:inherit;cursor:pointer;border-radius:999px}\n#${HINT_ID} .rl-fresh-hint__go{border:0;padding:6px 12px;background:var(--accent-fill,#c8ff00);color:var(--accent-ink,#09090b);font-weight:600}\n#${HINT_ID} .rl-fresh-hint__x{border:0;background:transparent;color:inherit;opacity:.6;padding:4px 6px}\n#${HINT_ID} .rl-fresh-hint__x:hover{opacity:1}\nbody.has-pbuy #${HINT_ID}{bottom:calc(var(--pbuy-h,0px) + 16px)}\nbody.has-qxl #${HINT_ID}{bottom:calc(var(--qxl-bar-h,88px) + 16px)}\n@media print{#${HINT_ID}{display:none!important}}`;\n\n// One pill per page, however many payloads come back changed.\nexport function showFreshHint({ message = \"Updated since this page opened\", action = \"Refresh\" } = {}) {\n  try {\n    if (typeof document === \"undefined\" || !document.body) return null;\n    const existing = document.getElementById(HINT_ID);\n    if (existing) return existing;\n    if (!document.getElementById(STYLE_ID)) {\n      const st = document.createElement(\"style\");\n      st.id = STYLE_ID;\n      st.textContent = CSS;\n      document.head.appendChild(st);\n    }\n    const el = document.createElement(\"div\");\n    el.id = HINT_ID;\n    el.setAttribute(\"role\", \"status\");\n    el.setAttribute(\"aria-live\", \"polite\");\n    const msg = document.createElement(\"span\");\n    msg.textContent = message;\n    const go = document.createElement(\"button\");\n    go.type = \"button\";\n    go.className = \"rl-fresh-hint__go\";\n    go.textContent = action;\n    go.addEventListener(\"click\", () => { try { location.reload(); } catch {} });\n    const x = document.createElement(\"button\");\n    x.type = \"button\";\n    x.className = \"rl-fresh-hint__x\";\n    x.setAttribute(\"aria-label\", \"Dismiss\");\n    x.textContent = \"×\";\n    x.addEventListener(\"click\", () => el.remove());\n    el.append(msg, go, x);\n    document.body.appendChild(el);\n    return el;\n  } catch { return null; }\n}\n"],
  "mappings": "AAuBA,IAAIA,EAAU,GACd,MAAMC,EAAc,IAAM,CAAED,EAAU,EAAM,EAC5C,GAAI,CACF,GAAI,OAAO,kBAAqB,WAC9B,UAAWE,IAAM,CAAC,cAAe,UAAW,QAAS,QAAQ,EAC3D,iBAAiBA,EAAID,EAAa,CAAE,QAAS,GAAM,QAAS,EAAK,CAAC,CAGxE,MAAQ,CAA0B,CAG3B,aAAM,cAAgB,IAAMD,EAG5B,gBAAS,eAAgB,CAAEA,EAAU,EAAO,CAE5C,gBAAS,WAAWG,EAAU,CAAE,YAAAC,CAAY,EAAI,CAAC,EAAG,CACzD,IAAIC,EAAK,CAACL,EACV,GAAIK,GAAMD,EAAe,GAAI,CAAEC,EAAK,CAAC,CAACD,EAAY,CAAG,MAAQ,CAAEC,EAAK,EAAO,CAC3E,GAAIA,EAAI,CACN,MAAMC,EAAI,OAAO,SAAY,SAAW,QAAU,EAC5CC,EAAI,OAAO,SAAY,SAAW,QAAU,EAClD,GAAI,CACFJ,EAAS,EACT,GAAI,CAAM,OAAO,UAAa,aAAe,UAAYG,GAAK,UAAYC,IAAI,SAASD,EAAGC,CAAC,CAAG,MAAQ,CAAC,CACvG,MAAO,YACT,OAASC,EAAG,CACV,GAAI,CAAE,QAAQ,KAAK,wDAAyDA,CAAC,CAAG,MAAQ,CAAC,CAC3F,CACF,CACA,qBAAc,EACP,MACT,CAEA,MAAMC,EAAU,gBACVC,EAAW,oBACXC,EAAM;AAAA,GACTF,CAAO;AAAA;AAAA;AAAA;AAAA,GAIPA,CAAO;AAAA,GACPA,CAAO;AAAA,GACPA,CAAO;AAAA,GACPA,CAAO;AAAA,iBACOA,CAAO;AAAA,gBACRA,CAAO;AAAA,gBACPA,CAAO,4BAGhB,gBAAS,cAAc,CAAE,QAAAG,EAAU,iCAAkC,OAAAC,EAAS,SAAU,EAAI,CAAC,EAAG,CACrG,GAAI,CACF,GAAI,OAAO,SAAa,KAAe,CAAC,SAAS,KAAM,OAAO,KAC9D,MAAMC,EAAW,SAAS,eAAeL,CAAO,EAChD,GAAIK,EAAU,OAAOA,EACrB,GAAI,CAAC,SAAS,eAAeJ,CAAQ,EAAG,CACtC,MAAMK,EAAK,SAAS,cAAc,OAAO,EACzCA,EAAG,GAAKL,EACRK,EAAG,YAAcJ,EACjB,SAAS,KAAK,YAAYI,CAAE,CAC9B,CACA,MAAMC,EAAK,SAAS,cAAc,KAAK,EACvCA,EAAG,GAAKP,EACRO,EAAG,aAAa,OAAQ,QAAQ,EAChCA,EAAG,aAAa,YAAa,QAAQ,EACrC,MAAMC,EAAM,SAAS,cAAc,MAAM,EACzCA,EAAI,YAAcL,EAClB,MAAMM,EAAK,SAAS,cAAc,QAAQ,EAC1CA,EAAG,KAAO,SACVA,EAAG,UAAY,oBACfA,EAAG,YAAcL,EACjBK,EAAG,iBAAiB,QAAS,IAAM,CAAE,GAAI,CAAE,SAAS,OAAO,CAAG,MAAQ,CAAC,CAAE,CAAC,EAC1E,MAAMZ,EAAI,SAAS,cAAc,QAAQ,EACzC,OAAAA,EAAE,KAAO,SACTA,EAAE,UAAY,mBACdA,EAAE,aAAa,aAAc,SAAS,EACtCA,EAAE,YAAc,IAChBA,EAAE,iBAAiB,QAAS,IAAMU,EAAG,OAAO,CAAC,EAC7CA,EAAG,OAAOC,EAAKC,EAAIZ,CAAC,EACpB,SAAS,KAAK,YAAYU,CAAE,EACrBA,CACT,MAAQ,CAAE,OAAO,IAAM,CACzB",
  "names": ["touched", "markTouched", "ev", "rerender", "canRerender", "ok", "x", "y", "e", "HINT_ID", "STYLE_ID", "CSS", "message", "action", "existing", "st", "el", "msg", "go"]
}
