Files
backlog/webapp/index-style-v2.html
T
Alexander Derevianko c2e9eaaa7b Add browser storage fallback for Firefox/Safari (#1)
IndexedDB-based storage backend with Storage Persistence API for browsers
without File System Access API support. Requests persistent storage on
first save to protect data from automatic eviction. Includes backup
rotation (last 10 saves) and appropriate UI banner.
2026-05-07 10:19:20 -04:00

6691 lines
357 KiB
HTML

<!doctype html>
<html lang="en" data-density="comfortable" data-show-ids="false" data-paper="true">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Personal Backlog</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
/* Personal Backlog — paper-like editor aesthetic */
:root {
--accent-hue: 35;
--accent: oklch(0.62 0.13 var(--accent-hue));
--accent-soft: oklch(0.62 0.13 var(--accent-hue) / 0.10);
--accent-edge: oklch(0.62 0.13 var(--accent-hue) / 0.35);
--accent-deep: oklch(0.48 0.14 var(--accent-hue));
--bg: oklch(0.985 0.005 80);
--bg-2: oklch(0.97 0.006 80);
--paper: oklch(0.99 0.004 80);
--ink: oklch(0.22 0.012 60);
--ink-2: oklch(0.42 0.012 60);
--ink-3: oklch(0.62 0.012 60);
--rule: oklch(0.91 0.008 70);
--rule-2: oklch(0.95 0.006 70);
--status-open: oklch(0.55 0.005 60);
--status-progress: oklch(0.55 0.13 220);
--status-blocked: oklch(0.58 0.16 25);
--status-postponed: oklch(0.68 0.15 60);
--status-done: oklch(0.55 0.12 145);
--status-cancelled: oklch(0.5 0.012 60);
--warn: oklch(0.7 0.13 80);
--warn-bg: oklch(0.94 0.05 85);
--ok: oklch(0.6 0.12 145);
--danger: oklch(0.58 0.16 25);
--danger-soft: oklch(0.58 0.16 25 / 0.08);
--font-sans: "Inter", system-ui, -apple-system, "Helvetica Neue", Helvetica, Arial, sans-serif;
--font-mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;
--radius: 6px;
--radius-lg: 10px;
--shadow-1: 0 1px 0 oklch(0.91 0.008 70);
--shadow-2: 0 1px 2px oklch(0.22 0.012 60 / 0.06), 0 4px 14px oklch(0.22 0.012 60 / 0.05);
--shadow-pop: 0 8px 24px oklch(0.22 0.012 60 / 0.14), 0 2px 6px oklch(0.22 0.012 60 / 0.08);
--row-h: 36px;
--row-pad-y: 7px;
}
html[data-density="compact"] { --row-h: 28px; --row-pad-y: 4px; }
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; height: 100%; }
body {
font-family: var(--font-sans);
color: var(--ink);
background: var(--bg);
font-size: 14px;
line-height: 1.45;
-webkit-font-smoothing: antialiased;
}
html[data-paper="true"] body {
background-image: radial-gradient(oklch(0.91 0.008 70 / 0.35) 1px, transparent 1px);
background-size: 22px 22px;
}
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }
button:focus-visible { outline: 2px solid var(--accent-edge); outline-offset: 2px; border-radius: 3px; }
button:disabled { cursor: not-allowed; opacity: 0.4; }
input { font: inherit; color: inherit; }
.mono { font-family: var(--font-mono); }
.small { font-size: 12px; }
.muted { color: var(--ink-3); }
/* ---------- App shell ---------- */
.app { min-height: 100vh; height: 100vh; display: flex; flex-direction: column; }
/* ---------- Header ---------- */
.header {
display: grid;
grid-template-columns: auto auto 1fr auto;
gap: 24px;
align-items: center;
padding: 14px 24px;
border-bottom: 1px solid var(--rule);
background: oklch(0.985 0.005 80 / 0.86);
backdrop-filter: saturate(1.4) blur(8px);
flex-shrink: 0;
z-index: 50;
}
.brand { display: flex; align-items: center; gap: 10px; }
.brand-glyph { display: inline-flex; align-items: center; color: var(--accent); }
.brand-name { font-weight: 600; font-size: 15px; letter-spacing: -0.01em; }
.brand-sub {
font-size: 12px; color: var(--ink-3);
padding-left: 10px; border-left: 1px solid var(--rule); margin-left: 4px;
}
.tabs { display: flex; gap: 2px; }
.tab {
display: inline-flex; align-items: center; gap: 6px;
padding: 6px 12px; border-radius: var(--radius);
font-size: 13px; color: var(--ink-2); font-weight: 500;
}
.tab:hover { background: var(--bg-2); color: var(--ink); }
.tab.active { background: var(--ink); color: var(--bg); }
.search-wrap {
display: flex; align-items: center; gap: 8px;
padding: 7px 12px;
background: var(--paper);
border: 1px solid var(--rule); border-radius: var(--radius);
color: var(--ink-3);
max-width: 480px; width: 100%; justify-self: start;
}
.search-wrap:focus-within {
border-color: var(--accent-edge);
box-shadow: 0 0 0 3px var(--accent-soft);
color: var(--ink);
}
.search-input { flex: 1; border: 0; background: transparent; outline: 0; color: var(--ink); font-size: 13px; }
.search-input::placeholder { color: var(--ink-3); }
.search-clear {
width: 18px; height: 18px;
display: grid; place-items: center;
border-radius: 50%; color: var(--ink-3); font-size: 14px; line-height: 1;
}
.search-clear:hover { background: var(--bg-2); color: var(--ink); }
.header-right { display: flex; align-items: center; gap: 14px; }
.header-btn {
display: inline-flex; align-items: center; gap: 6px;
padding: 6px 10px; border-radius: var(--radius);
font-size: 12.5px; color: var(--ink-2);
border: 1px solid var(--rule); background: var(--paper);
}
.header-btn:hover { background: var(--bg-2); color: var(--ink); }
.save-indicator { display: inline-flex; align-items: center; gap: 8px; font-size: 12px; color: var(--ink-3); font-family: var(--font-mono); }
.save-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--ok); }
.save-dot.saving { background: var(--accent); animation: pulse 1.2s ease-in-out infinite; }
@keyframes pulse { 50% { opacity: 0.4; } }
/* ---------- Banner ---------- */
.banner { display: flex; align-items: center; gap: 10px; padding: 9px 24px; font-size: 13px; border-bottom: 1px solid var(--rule); }
.banner.warn { background: var(--warn-bg); color: oklch(0.35 0.12 60); }
.banner.info { background: oklch(0.96 0.01 220); color: oklch(0.35 0.05 220); }
.banner-close { margin-left: auto; font-size: 12px; color: inherit; text-decoration: underline; text-underline-offset: 3px; }
/* ---------- Main layout ---------- */
.main { display: grid; grid-template-columns: 240px 1fr; flex: 1; min-height: 0; }
/* ---------- Filter panel ---------- */
.filter-panel {
border-right: 1px solid var(--rule);
padding: 22px 18px;
display: flex; flex-direction: column; gap: 22px;
overflow-y: auto;
overflow-x: hidden;
height: 100%;
}
.filter-section { display: flex; flex-direction: column; gap: 8px; }
.filter-label {
font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase;
color: var(--ink-3); font-weight: 600;
}
.filter-list { display: flex; flex-direction: column; gap: 2px; }
.filter-list-row { flex-direction: row; gap: 6px; }
.filter-list-row.wrap { flex-wrap: wrap; }
.filter-chip {
display: flex; align-items: center; gap: 8px;
padding: 5px 8px; border-radius: 5px;
font-size: 13px; color: var(--ink-2); text-align: left;
}
.filter-chip:hover { background: var(--bg-2); color: var(--ink); }
.filter-chip.active { background: var(--accent-soft); color: var(--accent-deep); }
.filter-chip .filter-name { flex: 1; }
.filter-chip .filter-count { font-family: var(--font-mono); font-size: 11px; color: var(--ink-3); }
.filter-chip.active .filter-count { color: var(--accent-deep); }
.filter-chip.mini {
padding: 4px 10px; font-family: var(--font-mono); font-size: 12px; font-weight: 500;
border: 1px solid var(--rule); background: var(--paper);
}
.filter-chip.mini.active { border-color: var(--accent); background: var(--accent); color: var(--bg); }
.filter-chip.mini.pri-P0.active { background: var(--accent-deep); border-color: var(--accent-deep); }
.tag-chip {
font-family: var(--font-mono); font-size: 11.5px;
padding: 3px 8px; border-radius: 99px;
background: var(--bg-2); color: var(--ink-2);
border: 1px solid var(--rule);
display: inline-flex; align-items: center; gap: 3px;
}
.tag-chip:hover { background: var(--paper); color: var(--ink); }
.tag-chip.active { background: var(--ink); color: var(--bg); border-color: var(--ink); }
.tag-chip .hl { color: var(--accent-deep); font-weight: 600; }
.tag-chip.active .hl { color: var(--bg); }
.tag-x { font-family: var(--font-sans); font-size: 13px; line-height: 1; opacity: 0.6; margin-left: 1px; }
.tag-chip:hover .tag-x { opacity: 1; }
.tag-total {
font-size: 10.5px; font-weight: 500;
color: var(--ink-3);
padding: 1px 6px; border-radius: 99px;
background: var(--bg-2); border: 1px solid var(--rule);
margin-left: 4px;
letter-spacing: 0;
}
.tag-selected { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 2px; }
.tag-search {
display: flex; align-items: center; gap: 6px;
padding: 6px 9px;
border: 1px solid var(--rule); border-radius: var(--radius);
background: var(--bg-2); color: var(--ink-3);
margin-bottom: 6px;
}
.tag-search.focused { border-color: var(--accent-edge); background: var(--paper); box-shadow: 0 0 0 3px var(--accent-soft); color: var(--ink); }
.tag-search-input { flex: 1; border: 0; background: transparent; outline: 0; font-size: 12.5px; color: var(--ink); padding: 0; min-width: 0; }
.tag-search-input::placeholder { color: var(--ink-3); }
.tag-search-clear { width: 16px; height: 16px; display: grid; place-items: center; border-radius: 50%; color: var(--ink-3); font-size: 14px; line-height: 1; flex-shrink: 0; }
.tag-search-clear:hover { background: var(--paper); color: var(--ink); }
.tag-results { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; max-height: 220px; overflow-y: auto; padding: 2px 0; }
.tag-empty { font-size: 11.5px; color: var(--ink-3); font-style: italic; padding: 4px 0; }
.tag-more { font-size: 10.5px; color: var(--ink-3); padding: 2px 4px; }
.clear-btn { padding: 6px 0; font-size: 12px; color: var(--accent-deep); text-align: left; text-decoration: underline; text-underline-offset: 3px; }
/* ---------- Content ---------- */
.content { min-width: 0; height: 100%; display: flex; flex-direction: column; overflow: hidden; }
.content-sticky {
flex-shrink: 0;
padding: 28px 32px 14px;
background: var(--bg);
border-bottom: 1px solid var(--rule-2);
}
.content-scroll {
flex: 1;
overflow-y: auto;
padding: 18px 32px 80px;
min-height: 0;
}
.content-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 24px; margin-bottom: 14px; }
.content-head-actions { display: flex; align-items: center; gap: 12px; }
.eyebrow { font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-3); font-weight: 600; margin-bottom: 4px; }
.content-title { font-size: 26px; font-weight: 600; letter-spacing: -0.015em; margin: 0; }
.btn-primary, .btn-secondary, .btn-danger {
display: inline-flex; align-items: center; gap: 6px;
padding: 8px 14px; border-radius: var(--radius);
font-size: 13px; font-weight: 500;
}
.btn-primary { background: var(--ink); color: var(--bg); }
.btn-primary:hover:not(:disabled) { background: oklch(0.15 0.012 60); }
.btn-secondary { background: var(--paper); color: var(--ink); border: 1px solid var(--rule); }
.btn-secondary:hover { background: var(--bg-2); }
.btn-danger { background: var(--danger); color: white; }
.btn-danger:hover { background: oklch(0.5 0.16 25); }
/* segmented control */
.seg { display: inline-flex; padding: 2px; background: var(--bg-2); border: 1px solid var(--rule); border-radius: var(--radius); }
.seg-mini { padding: 2px; }
.seg-btn {
padding: 5px 10px; border-radius: 4px;
font-size: 12px; color: var(--ink-2);
font-family: var(--font-mono); font-weight: 500;
transition: background 0.12s, color 0.12s;
}
.seg-btn:hover { color: var(--ink); }
.seg-btn.active { background: var(--paper); color: var(--ink); box-shadow: 0 1px 2px oklch(0.22 0.012 60 / 0.08); }
/* in dialogs the segmented control should fill the row + have a stronger active state */
.field .seg { width: 100%; height: 38px; padding: 3px; align-items: stretch; }
.field .seg .seg-btn { flex: 1; padding: 0 12px; display: inline-flex; align-items: center; justify-content: center; gap: 5px; }
.field .seg .seg-btn.active {
background: var(--paper);
color: var(--ink);
box-shadow: 0 0 0 1px var(--ink) inset, 0 1px 2px oklch(0.22 0.012 60 / 0.08);
font-weight: 600;
}
.field .seg .seg-btn.pri-P0.active {
background: var(--accent);
color: var(--bg);
box-shadow: 0 0 0 1px var(--accent) inset;
}
.field .seg .seg-btn.pri-P0.active .p0-dot { background: var(--bg); box-shadow: 0 0 0 2px oklch(0.62 0.13 var(--accent-hue) / 0.4); }
.legend {
display: flex; flex-wrap: wrap; align-items: center;
gap: 14px; padding: 10px 12px; margin-bottom: 0;
font-size: 12px; color: var(--ink-3);
border: 1px dashed var(--rule); border-radius: var(--radius);
background: var(--paper);
}
/* Saved view chips */
.view-chips {
display: flex; flex-wrap: wrap; gap: 4px;
margin: 12px 0 10px;
}
.view-chip {
padding: 6px 12px;
border-radius: 99px;
font-size: 12.5px; font-weight: 500;
color: var(--ink-2);
border: 1px solid var(--rule);
background: var(--paper);
transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.view-chip:hover { background: var(--bg-2); color: var(--ink); border-color: oklch(0.85 0.008 70); }
.view-chip.active {
background: var(--ink);
color: var(--bg);
border-color: var(--ink);
}
.legend-cap { font-weight: 600; color: var(--ink-2); letter-spacing: 0.04em; }
.legend-item { display: inline-flex; align-items: center; gap: 5px; color: var(--ink-2); }
.legend-sep { color: var(--rule); }
.legend-hint { margin-left: auto; }
.legend kbd {
font-family: var(--font-mono); font-size: 11px;
padding: 1px 6px;
border: 1px solid var(--rule); border-bottom-width: 2px; border-radius: 4px;
background: var(--paper); color: var(--ink-2);
}
/* ---------- Status icons (3 styles) ---------- */
.glyph-flat { display: inline-block; vertical-align: middle; }
.glyph-flat.status-open { color: var(--status-open); }
.glyph-flat.status-in-progress { color: var(--status-progress); }
.glyph-flat.status-blocked { color: var(--status-blocked); }
.glyph-flat.status-postponed { color: var(--status-postponed); }
.glyph-flat.status-done { color: var(--status-done); }
.glyph-flat.status-cancelled { color: var(--status-cancelled); }
.glyph-ascii {
font-family: var(--font-mono); font-size: 13px; font-weight: 500;
letter-spacing: -0.04em; display: inline-block; min-width: 26px; text-align: center;
}
.glyph-ascii.status-open { color: var(--status-open); }
.glyph-ascii.status-in-progress { color: var(--status-progress); font-weight: 600; }
.glyph-ascii.status-blocked { color: var(--status-blocked); font-weight: 600; }
.glyph-ascii.status-postponed { color: var(--status-postponed); }
.glyph-ascii.status-done { color: var(--status-done); }
.glyph-ascii.status-cancelled { color: var(--status-cancelled); text-decoration: line-through; text-decoration-thickness: 1px; }
.glyph-emoji {
display: inline-flex;
align-items: center;
justify-content: center;
vertical-align: middle;
line-height: 1;
font-family: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif;
/* normalize size of the variation-selector pictographs */
font-variant-emoji: emoji;
}
.glyph-color { display: inline-block; vertical-align: middle; }
.restore-warn {
display: flex; gap: 10px;
margin-top: 12px;
padding: 10px 12px;
border-radius: var(--radius);
border: 1px solid oklch(0.82 0.13 85 / 0.6);
background: oklch(0.97 0.05 85);
color: oklch(0.36 0.10 70);
}
.restore-warn svg { flex-shrink: 0; margin-top: 2px; color: oklch(0.62 0.16 70); }
.restore-warn-title { font-weight: 600; font-size: 12.5px; margin-bottom: 3px; color: oklch(0.32 0.08 70); }
.restore-warn-body { font-size: 12px; line-height: 1.45; color: oklch(0.40 0.06 70); }
.restore-warn-body code { background: oklch(1 0 0 / 0.55); padding: 0 4px; border-radius: 3px; }
/* ---------- Tree rows ---------- */
.tree {
background: var(--paper);
border: 1px solid var(--rule);
border-radius: var(--radius-lg);
overflow: hidden;
box-shadow: var(--shadow-2);
}
.row {
display: flex; align-items: center; gap: 10px;
padding: var(--row-pad-y) 16px;
min-height: var(--row-h);
border-bottom: 1px solid var(--rule-2);
position: relative;
font-size: 13.5px;
}
.row:last-child { border-bottom: 0; }
.row:hover { background: oklch(0.985 0.005 80 / 0.7); }
.row.dimmed { opacity: 0.45; }
.row.drop-target { box-shadow: inset 0 2px 0 var(--accent); background: var(--accent-soft); }
.row.p0 { background: linear-gradient(90deg, var(--accent-soft) 0%, transparent 60%); }
.row.p0::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 2px; background: var(--accent); }
.level-0 .title { font-weight: 600; font-size: 14.5px; }
.level-1 .title { font-weight: 500; }
.level-2 .title, .level-3 .title { color: var(--ink-2); }
.row-rail { align-self: stretch; flex-shrink: 0; }
.twisty { width: 16px; height: 16px; display: grid; place-items: center; color: var(--ink-3); border-radius: 3px; flex-shrink: 0; }
.twisty:hover { background: var(--bg-2); color: var(--ink); }
.twisty.empty { visibility: hidden; }
.drag-handle { width: 14px; color: oklch(0.85 0.005 60); cursor: grab; flex-shrink: 0; opacity: 0; transition: opacity 0.15s; }
.row:hover .drag-handle { opacity: 1; }
/* status button + popover */
.status-wrap { position: relative; display: inline-flex; }
.status-btn {
display: inline-flex; align-items: center; justify-content: center;
width: 24px; height: 24px;
border-radius: 5px;
flex-shrink: 0;
}
.status-btn:hover { background: var(--bg-2); }
.status-pop {
position: absolute; top: calc(100% + 4px); left: 0;
z-index: 30; min-width: 180px;
padding: 4px;
background: var(--paper); border: 1px solid var(--rule);
border-radius: var(--radius); box-shadow: var(--shadow-pop);
}
.status-pop-item {
width: 100%; display: flex; align-items: center; gap: 8px;
padding: 6px 8px; border-radius: 4px;
font-size: 13px; color: var(--ink); text-align: left;
}
.status-pop-item:hover { background: var(--bg-2); }
.status-pop-item.active { background: var(--accent-soft); color: var(--accent-deep); }
/* priority button + popover */
.pri-wrap { position: relative; display: inline-flex; }
.pri {
font-family: var(--font-mono);
font-size: 11px; font-weight: 600;
color: var(--ink-3); letter-spacing: 0.04em;
flex-shrink: 0;
display: inline-flex; align-items: center; gap: 4px;
padding: 3px 7px; border-radius: 4px;
border: 1px solid var(--rule); background: var(--paper);
}
.pri:hover { background: var(--bg-2); border-color: oklch(0.85 0.008 70); }
.pri-P0 { color: var(--accent-deep); border-color: var(--accent-edge); background: var(--accent-soft); }
.pri-P1 { color: var(--ink); }
.pri-P2 { color: var(--ink-2); }
.pri-P3 { color: var(--ink-3); }
.p0-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
.pri-pop {
position: absolute; top: calc(100% + 4px); left: 0;
z-index: 30; min-width: 160px; padding: 4px;
background: var(--paper); border: 1px solid var(--rule);
border-radius: var(--radius); box-shadow: var(--shadow-pop);
}
.pri-pop-item {
width: 100%;
display: grid; grid-template-columns: 14px 32px 1fr; align-items: center; gap: 8px;
padding: 6px 8px; border-radius: 4px;
font-family: var(--font-mono); font-size: 12px;
color: var(--ink); text-align: left;
}
.pri-pop-item:hover { background: var(--bg-2); }
.pri-pop-item.active { background: var(--accent-soft); color: var(--accent-deep); }
.pri-pop-item .p0-dot { grid-column: 1; }
.pri-pop-hint { font-family: var(--font-sans); font-size: 11.5px; color: var(--ink-3); justify-self: end; }
.title { flex-shrink: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; cursor: text; }
.title.done { color: var(--ink-3); text-decoration: line-through; text-decoration-thickness: 1px; }
.title .hl { background: var(--accent-soft); color: var(--accent-deep); padding: 0 1px; border-radius: 2px; }
/* ---------- Progress gauge ---------- */
.gauge {
display: inline-flex; align-items: center; gap: 4px;
flex-shrink: 0;
padding: 1px 6px 1px 4px;
border-radius: 99px;
background: var(--bg-2);
border: 1px solid var(--rule);
user-select: none;
line-height: 1;
}
.gauge-seg {
display: inline-block;
width: 4px; height: 8px;
border-radius: 1px;
background: oklch(0.88 0.005 60);
transition: background 0.12s;
}
.gauge-seg.on { background: var(--status-progress); }
.gauge-num {
font-family: var(--font-mono);
font-size: 10.5px;
font-variant-numeric: tabular-nums;
color: var(--ink-3);
padding-left: 3px;
min-width: 26px;
text-align: right;
}
/* state-coloring: 100 = green, 0 = neutral, mid = blue (default) */
.gauge.gauge-v-100 .gauge-seg.on { background: var(--status-done); }
.gauge.gauge-v-100 .gauge-num { color: var(--status-done); }
.gauge.gauge-v-0 { border-style: dashed; }
.gauge.gauge-v-0 .gauge-num { color: var(--ink-3); }
/* row gauge: hover-emphasize when interactive */
.gauge-interactive { cursor: pointer; transition: background 0.12s, border-color 0.12s; }
.gauge-interactive:hover { background: var(--paper); border-color: var(--accent-edge); }
.gauge-interactive:focus-visible { outline: 2px solid var(--accent-edge); outline-offset: 2px; }
/* larger size for dialog */
.gauge-md { padding: 4px 10px 4px 7px; gap: 5px; }
.gauge-md .gauge-seg { width: 5px; height: 12px; }
.gauge-md .gauge-num { font-size: 12px; min-width: 32px; padding-left: 4px; }
/* dialog progress field */
.progress-row { display: flex; align-items: center; gap: 12px; }
.progress-seg { flex: 1; }
.progress-seg .seg-btn { font-family: var(--font-mono); }
.progress-seg.locked { opacity: 0.55; }
/* row dim adjustment: lower opacity for blocked-ish stuck rows */
.row .gauge { margin-left: 2px; }
.due { font-family: var(--font-mono); font-size: 11.5px; color: var(--ink-3); padding: 1px 6px; border-radius: 99px; background: var(--bg-2); flex-shrink: 0; }
.due.overdue { color: oklch(0.95 0.005 60); background: var(--status-blocked); font-weight: 500; }
.tags { display: inline-flex; gap: 4px; flex-shrink: 0; }
.tag { font-family: var(--font-mono); font-size: 10.5px; color: var(--ink-2); padding: 1px 6px; border-radius: 99px; border: 1px solid var(--rule); background: var(--paper); }
.reason { font-style: italic; font-size: 12px; color: var(--status-blocked); flex-shrink: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 240px; }
.row-spacer { flex: 1; min-width: 0; }
/* row action toolbar — bigger, distinct, labeled on hover */
.row-actions { display: flex; gap: 2px; flex-shrink: 0; opacity: 0; transition: opacity 0.15s; align-items: center; }
.row:hover .row-actions, .row:focus-within .row-actions { opacity: 1; }
.action-sep { width: 1px; height: 16px; background: var(--rule); margin: 0 4px; }
/* custom tooltip on icon buttons (instant, branded) */
.icon-btn { position: relative; }
.icon-btn[data-tip]::after {
content: attr(data-tip);
position: absolute;
top: calc(100% + 6px);
left: 50%;
transform: translateX(-50%);
white-space: nowrap;
background: var(--ink);
color: var(--bg);
font-family: var(--font-sans);
font-size: 11.5px;
font-weight: 500;
padding: 4px 8px;
border-radius: 4px;
pointer-events: none;
opacity: 0;
transition: opacity 0.12s 0s;
z-index: 100;
box-shadow: 0 4px 12px oklch(0.22 0.012 60 / 0.2);
}
.icon-btn[data-tip]::before {
content: "";
position: absolute;
top: calc(100% + 1px);
left: 50%;
transform: translateX(-50%);
border: 4px solid transparent;
border-bottom-color: var(--ink);
pointer-events: none;
opacity: 0;
transition: opacity 0.12s 0s;
z-index: 100;
}
.icon-btn[data-tip]:hover::after,
.icon-btn[data-tip]:hover::before,
.icon-btn[data-tip]:focus-visible::after,
.icon-btn[data-tip]:focus-visible::before {
opacity: 1;
transition-delay: 0.35s;
}
.icon-btn {
width: 28px; height: 28px;
display: inline-grid; place-items: center;
border-radius: 5px;
color: var(--ink-2);
border: 1px solid transparent;
transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.icon-btn:hover:not(:disabled) {
background: var(--paper);
color: var(--ink);
border-color: var(--rule);
}
.icon-btn.danger:hover:not(:disabled) {
color: var(--danger);
background: var(--danger-soft);
border-color: oklch(0.58 0.16 25 / 0.3);
}
.empty-state { text-align: center; padding: 60px 20px; color: var(--ink-3); background: var(--paper); border: 1px dashed var(--rule); border-radius: var(--radius-lg); }
.empty-glyph { font-family: var(--font-mono); font-size: 36px; margin-bottom: 8px; color: var(--rule); }
/* ---------- Admin ---------- */
.admin { padding: 28px 32px 80px; max-width: 1280px; margin: 0 auto; width: 100%; overflow-y: auto; height: 100%; }
.admin-head { display: flex; align-items: flex-end; justify-content: space-between; margin-bottom: 24px; }
.admin-head h2 { font-size: 26px; font-weight: 600; letter-spacing: -0.015em; margin: 0; }
.admin-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
.card { background: var(--paper); border: 1px solid var(--rule); border-radius: var(--radius-lg); padding: 18px 20px; box-shadow: var(--shadow-2); }
.card.span-2 { grid-column: span 2; }
.card.span-3 { grid-column: span 3; }
.card-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; gap: 10px; }
.card-head h3 { font-size: 14px; font-weight: 600; margin: 0; letter-spacing: -0.005em; }
.card-sub { font-size: 11.5px; color: var(--ink-3); }
.pill { display: inline-flex; align-items: center; gap: 5px; font-family: var(--font-mono); font-size: 11px; font-weight: 500; padding: 2px 8px; border-radius: 99px; border: 1px solid var(--rule); }
.pill.mini { font-size: 10.5px; padding: 1px 6px; }
.pill.ok { color: var(--ok); border-color: var(--ok); background: oklch(0.95 0.04 145); }
.pill.warn { color: oklch(0.45 0.12 60); border-color: var(--warn); background: var(--warn-bg); }
.pill.neutral { color: var(--ink-2); background: var(--bg-2); }
.kv { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 16px; margin: 0; }
.kv > div { display: flex; flex-direction: column; gap: 1px; padding: 6px 0; border-top: 1px dashed var(--rule); }
.kv > div:first-child, .kv > div:nth-child(2) { border-top: 0; padding-top: 0; }
.kv dt { font-size: 11px; color: var(--ink-3); text-transform: uppercase; letter-spacing: 0.06em; margin: 0; }
.kv dd { margin: 0; font-size: 13px; color: var(--ink); }
.action-list { display: flex; flex-direction: column; gap: 6px; }
.action-btn { display: flex; align-items: flex-start; gap: 10px; padding: 10px 12px; border-radius: var(--radius); border: 1px solid var(--rule); background: var(--bg); font-size: 13px; text-align: left; line-height: 1.35; }
.action-btn:hover { background: var(--bg-2); border-color: oklch(0.85 0.008 70); }
.action-btn svg { flex-shrink: 0; margin-top: 2px; color: var(--ink-2); }
.action-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.action-label { font-weight: 500; color: var(--ink); font-size: 13px; }
.action-meta { font-family: var(--font-mono); font-size: 10.5px; color: var(--ink-3); letter-spacing: 0.01em; }
/* ---- Stats overview ---- */
.stats-card { display: flex; flex-direction: column; gap: 16px; }
.stats-head { flex-wrap: wrap; gap: 12px; }
.range-switch {
display: inline-flex; flex-wrap: wrap;
background: var(--bg);
border: 1px solid var(--rule);
border-radius: var(--radius);
padding: 2px;
gap: 1px;
}
.range-btn {
padding: 5px 10px;
font-size: 11.5px; font-weight: 500;
color: var(--ink-3);
border-radius: 4px;
white-space: nowrap;
transition: background 0.12s, color 0.12s;
}
.range-btn:hover { color: var(--ink-2); background: var(--bg-2); }
.range-btn.active { background: var(--ink); color: var(--bg); }
.kpi-grid {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 1px;
background: var(--rule);
border: 1px solid var(--rule);
border-radius: var(--radius);
overflow: hidden;
}
.kpi {
background: var(--paper);
padding: 12px 14px;
display: flex; flex-direction: column; gap: 6px;
min-width: 0;
}
.kpi-accent { background: oklch(from var(--accent) l c h / 0.04); }
.kpi-label { font-size: 10.5px; font-weight: 600; color: var(--ink-3); text-transform: uppercase; letter-spacing: 0.06em; }
.kpi-value { font-family: var(--font-mono); font-size: 24px; font-weight: 500; letter-spacing: -0.02em; line-height: 1; color: var(--ink); }
.kpi-unit { font-size: 13px; color: var(--ink-3); margin-left: 2px; font-weight: 400; }
.kpi-delta { font-family: var(--font-mono); font-size: 10.5px; display: flex; align-items: center; gap: 4px; }
.kpi-delta.up { color: oklch(0.55 0.13 145); }
.kpi-delta.down { color: oklch(0.58 0.16 30); }
.kpi-delta.flat { color: var(--ink-3); }
.kpi-arrow { font-size: 9px; }
.kpi-vs { color: var(--ink-3); font-weight: 400; }
.chart-head {
display: flex; justify-content: space-between; align-items: center;
gap: 12px; flex-wrap: wrap;
padding-top: 6px;
border-top: 1px dashed var(--rule);
padding-top: 14px;
}
.chart-legend { display: flex; flex-wrap: wrap; gap: 4px; }
.legend-chip {
display: inline-flex; align-items: center; gap: 6px;
padding: 3px 8px;
font-size: 11px; color: var(--ink-2);
border: 1px solid transparent;
border-radius: 99px;
transition: opacity 0.12s, border-color 0.12s;
}
.legend-chip:hover { border-color: var(--rule); }
.legend-chip.off { opacity: 0.4; }
.legend-chip.off .lg-swatch { filter: grayscale(0.8); }
.lg-swatch { display: inline-block; width: 9px; height: 9px; border-radius: 2px; }
.mode-switch {
display: inline-flex;
background: var(--bg);
border: 1px solid var(--rule);
border-radius: var(--radius);
padding: 2px;
gap: 1px;
}
.mode-btn {
display: inline-flex; align-items: center; gap: 5px;
padding: 4px 9px;
font-size: 11.5px; font-weight: 500;
color: var(--ink-3);
border-radius: 4px;
}
.mode-btn:hover { color: var(--ink-2); background: var(--bg-2); }
.mode-btn.active { background: var(--paper); color: var(--ink); box-shadow: 0 0 0 1px var(--rule); }
.mode-btn svg { color: currentColor; }
.stack-bars {
display: grid;
grid-auto-flow: column;
grid-auto-columns: 1fr;
gap: 4px;
align-items: end;
height: 160px;
padding: 0 2px;
}
.stack-col { display: flex; flex-direction: column; gap: 6px; height: 100%; min-width: 0; }
.stack-stack {
position: relative;
flex: 1;
min-height: 0;
border-radius: 3px 3px 0 0;
overflow: hidden;
align-self: stretch;
}
.stack-seg {
position: absolute;
left: 0; right: 0;
width: 100%;
min-height: 1px;
transition: height 0.25s ease, bottom 0.25s ease;
box-sizing: border-box;
}
/* round the topmost segment of each stack */
.stack-seg.top { border-radius: 3px 3px 0 0; }
.cumulative-stack { border-radius: 3px 3px 0 0; }
.stack-seg.cumulative {
background: var(--accent);
border-radius: 3px 3px 0 0;
box-shadow: none;
}
.legend-chip.static { cursor: default; opacity: 1; padding: 3px 8px; }
.stack-cap {
font-size: 10.5px; color: var(--ink-3);
font-family: var(--font-mono);
text-align: center;
display: flex; flex-direction: column; align-items: center; gap: 1px;
min-height: 16px;
line-height: 1;
}
.stack-total { font-size: 9.5px; color: var(--ink-3); opacity: 0.7; }
/* dense buckets — collapse columns to fit */
.stack-bars.buckets-30 { gap: 2px; }
.stack-bars.buckets-30 .stack-cap { font-size: 9.5px; }
/* legacy stat block styles kept for any external refs but no longer used */
.stats-row, .stat-block, .bar-row, .bar-col, .bar { /* retained */ }
.stat-block { padding: 12px 14px; border-radius: var(--radius); background: var(--bg); border: 1px solid var(--rule); }
.stat-num { font-family: var(--font-mono); font-size: 28px; font-weight: 500; letter-spacing: -0.03em; line-height: 1; }
.stat-num.small { font-family: var(--font-sans); font-size: 14px; font-weight: 600; }
.stat-unit { font-size: 14px; color: var(--ink-3); margin-left: 2px; }
.stat-cap { font-size: 11px; color: var(--ink-3); text-transform: uppercase; letter-spacing: 0.06em; margin-top: 6px; }
.bar-row { display: grid; grid-template-columns: repeat(7, 1fr); gap: 8px; align-items: end; padding-top: 16px; border-top: 1px dashed var(--rule); }
.bar-col { display: flex; flex-direction: column; align-items: center; gap: 4px; }
.bar { width: 100%; background: var(--accent); border-radius: 3px 3px 0 0; min-height: 4px; }
.bar-cap { font-size: 11px; color: var(--ink-3); }
.bar-num { font-family: var(--font-mono); font-size: 11px; color: var(--ink-2); }
.status-mix { display: flex; flex-direction: column; gap: 7px; }
.mix-row { display: grid; grid-template-columns: 30px 1fr 80px 30px; align-items: center; gap: 8px; font-size: 12.5px; }
.mix-label { color: var(--ink-2); }
.mix-bar { height: 6px; background: var(--bg-2); border-radius: 99px; overflow: hidden; }
.mix-fill { display: block; height: 100%; background: var(--ink-2); border-radius: 99px; }
.mix-num { font-family: var(--font-mono); font-size: 11.5px; text-align: right; color: var(--ink-2); }
.backup-table, .history-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.backup-table th, .history-table th { text-align: left; font-weight: 600; font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-3); padding: 6px 8px; border-bottom: 1px solid var(--rule); }
.backup-table td, .history-table td { padding: 9px 8px; border-bottom: 1px solid var(--rule-2); }
.backup-table tr.active { background: var(--accent-soft); }
.row-actions-cell { display: flex; gap: 4px; justify-content: flex-end; }
.row-btn { display: inline-flex; align-items: center; gap: 4px; padding: 4px 8px; border-radius: 4px; font-size: 11.5px; color: var(--ink-2); border: 1px solid var(--rule); background: var(--paper); }
.row-btn:hover { background: var(--bg-2); }
.row-btn.primary { background: var(--ink); color: var(--bg); border-color: var(--ink); }
.row-btn.primary:hover { background: oklch(0.15 0.012 60); }
.backup-preview { margin-top: 12px; border: 1px solid var(--rule); border-radius: var(--radius); background: var(--bg); overflow: hidden; }
.preview-head { display: flex; justify-content: space-between; align-items: center; padding: 8px 12px; border-bottom: 1px solid var(--rule); background: var(--bg-2); }
.preview-body { margin: 0; padding: 14px 16px; font-family: var(--font-mono); font-size: 11.5px; line-height: 1.55; color: var(--ink-2); white-space: pre-wrap; max-height: 320px; overflow: auto; }
/* ---------- Dialog system (centered, properly scrolled) ---------- */
.dlg-backdrop {
position: fixed; inset: 0;
display: flex; align-items: center; justify-content: center;
background: oklch(0.22 0.012 60 / 0.42);
backdrop-filter: blur(3px);
z-index: 200;
padding: 24px;
animation: dlg-fade 0.15s ease;
}
@keyframes dlg-fade { from { opacity: 0; } }
.dlg {
width: 100%;
max-height: calc(100vh - 48px);
background: var(--paper);
border: 1px solid var(--rule);
border-radius: 12px;
box-shadow: 0 30px 80px oklch(0.22 0.012 60 / 0.28), 0 4px 12px oklch(0.22 0.012 60 / 0.12);
display: flex; flex-direction: column;
overflow: hidden;
animation: dlg-pop 0.18s cubic-bezier(0.2, 0.9, 0.3, 1.1);
}
@keyframes dlg-pop { from { opacity: 0; transform: translateY(8px) scale(0.985); } }
.dlg form { display: contents; }
.dlg-head {
display: flex; align-items: flex-start; justify-content: space-between;
padding: 18px 22px 14px;
border-bottom: 1px solid var(--rule-2);
gap: 16px;
}
.dlg-title { font-size: 17px; font-weight: 600; letter-spacing: -0.01em; margin: 0; color: var(--ink); }
.dlg-close {
width: 28px; height: 28px;
display: grid; place-items: center;
border-radius: 6px;
color: var(--ink-3);
flex-shrink: 0;
}
.dlg-close:hover { background: var(--bg-2); color: var(--ink); }
.dlg-body {
padding: 18px 22px;
overflow-y: auto;
flex: 1;
min-height: 0;
}
.dlg-msg { font-size: 14px; color: var(--ink); margin: 0 0 8px; }
.dlg-detail { font-size: 12.5px; color: var(--ink-3); padding: 8px 12px; background: var(--bg-2); border: 1px dashed var(--rule); border-radius: 6px; }
.dlg-foot {
display: flex; align-items: center; justify-content: space-between;
gap: 12px;
padding: 14px 22px;
border-top: 1px solid var(--rule-2);
background: var(--bg-2);
}
.dlg-foot-actions { display: flex; gap: 8px; }
.dlg-hint { font-size: 11.5px; color: var(--ink-3); font-family: var(--font-mono); }
/* dialog form fields */
.field { display: flex; flex-direction: column; gap: 6px; margin-bottom: 16px; }
.field:last-child { margin-bottom: 0; }
.field-row { display: grid; grid-template-columns: 1.5fr 1fr; gap: 16px; margin-bottom: 16px; }
.field-row .field { margin-bottom: 0; }
.field-label {
font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase;
color: var(--ink-3); font-weight: 600;
display: flex; align-items: baseline; gap: 8px;
}
.field-hint {
font-size: 11px; letter-spacing: 0; text-transform: none;
font-weight: 400; color: var(--ink-3); font-style: italic;
}
.text-input {
width: 100%;
height: 38px;
padding: 0 12px;
font-size: 13.5px;
border: 1px solid var(--rule);
border-radius: var(--radius);
background: var(--bg);
color: var(--ink);
outline: 0;
transition: border-color 0.12s, box-shadow 0.12s;
}
.text-input[type="date"] { font-family: var(--font-mono); font-size: 13px; }
.text-input::placeholder { color: var(--ink-3); }
.text-input:focus { border-color: var(--accent-edge); box-shadow: 0 0 0 3px var(--accent-soft); background: var(--paper); }
/* status grid in dialog */
.status-grid {
display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px;
}
.status-card {
display: flex; align-items: center; gap: 8px;
padding: 9px 11px; border-radius: var(--radius);
border: 1px solid var(--rule); background: var(--bg);
font-size: 12.5px; color: var(--ink-2);
text-align: left;
transition: background 0.12s, border-color 0.12s;
}
.status-card:hover { background: var(--paper); color: var(--ink); }
.status-card.active { background: var(--paper); border-color: var(--ink); color: var(--ink); box-shadow: 0 0 0 1px var(--ink) inset; }
.status-card-icon { display: inline-flex; flex-shrink: 0; }
.status-card-label { font-weight: 500; }
/* tag input */
.tag-input {
display: flex; flex-wrap: wrap; gap: 4px;
padding: 6px 8px;
border: 1px solid var(--rule);
border-radius: var(--radius);
background: var(--bg);
min-height: 38px;
cursor: text;
}
.tag-input:hover { border-color: oklch(0.85 0.008 70); }
.tag-input:focus-within { border-color: var(--accent-edge); box-shadow: 0 0 0 3px var(--accent-soft); background: var(--paper); }
.tag-pill {
display: inline-flex; align-items: center; gap: 4px;
font-family: var(--font-mono); font-size: 11.5px;
padding: 2px 4px 2px 8px;
background: var(--paper); border: 1px solid var(--rule); border-radius: 99px;
color: var(--ink);
}
.tag-pill button {
width: 16px; height: 16px;
display: grid; place-items: center;
border-radius: 50%;
color: var(--ink-3);
font-size: 14px; line-height: 1;
}
.tag-pill button:hover { background: var(--bg-2); color: var(--danger); }
.tag-input-field { flex: 1; min-width: 80px; border: 0; outline: 0; background: transparent; padding: 4px; font-size: 13px; }
.tag-input-field::placeholder { color: var(--ink-3); }
.tag-suggest { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 8px; align-items: center; }
.tag-suggest-cap { font-size: 11px; color: var(--ink-3); text-transform: uppercase; letter-spacing: 0.06em; font-weight: 600; margin-right: 4px; }
.tag-suggest-chip {
font-family: var(--font-mono); font-size: 11px;
padding: 2px 8px; border-radius: 99px;
background: var(--bg); border: 1px dashed var(--rule); color: var(--ink-2);
}
.tag-suggest-chip:hover { background: var(--paper); color: var(--ink); border-style: solid; border-color: var(--accent-edge); }
/* Tag autocomplete dropdown */
.tag-ac { position: relative; }
.tag-ac-pop {
position: absolute;
top: calc(100% + 4px); left: 0; right: 0;
background: var(--paper);
border: 1px solid var(--rule);
border-radius: var(--radius);
box-shadow: var(--shadow-pop);
padding: 4px;
z-index: 50;
max-height: 280px;
overflow-y: auto;
}
.tag-ac-cap {
font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase;
color: var(--ink-3); font-weight: 600;
padding: 6px 8px 4px;
}
.tag-ac-item {
display: flex; align-items: center; gap: 6px;
width: 100%; text-align: left;
padding: 6px 9px; border-radius: 4px;
font-family: var(--font-mono); font-size: 12.5px;
color: var(--ink); background: transparent;
}
.tag-ac-item.highlighted { background: var(--accent-soft); color: var(--accent-deep); }
.tag-ac-item .hl { color: var(--accent-deep); font-weight: 600; }
.tag-ac-item.highlighted .hl { color: var(--accent-deep); background: oklch(0.62 0.13 var(--accent-hue) / 0.18); padding: 0 1px; border-radius: 2px; }
.tag-ac-item.create { color: var(--accent-deep); }
.tag-ac-item.create strong { font-weight: 600; }
.tag-ac-foot {
display: flex; gap: 12px; justify-content: flex-end;
padding: 6px 9px 4px;
border-top: 1px dashed var(--rule);
margin-top: 4px;
font-size: 10.5px; color: var(--ink-3);
}
.tag-ac-foot kbd {
font-family: var(--font-mono); font-size: 10px;
padding: 1px 4px; margin-right: 2px;
border: 1px solid var(--rule); border-bottom-width: 2px; border-radius: 3px;
background: var(--bg-2); color: var(--ink-2);
}
/* ---------- Import / Export dialog ---------- */
.ie-tabs { display: flex; gap: 4px; margin-bottom: 12px; border-bottom: 1px solid var(--rule); align-items: stretch; }
.ie-tab {
display: inline-flex; align-items: baseline; gap: 6px;
padding: 7px 14px;
font-size: 13px; font-weight: 500; color: var(--ink-3);
border-bottom: 2px solid transparent;
margin-bottom: -1px;
}
.ie-tab:hover { color: var(--ink); }
.ie-tab.active { color: var(--ink); border-bottom-color: var(--ink); }
.ie-tab-sub { font-family: var(--font-mono); font-size: 10.5px; color: var(--ink-3); }
.ie-copy-btn {
margin-left: auto;
display: inline-flex; align-items: center; gap: 5px;
padding: 5px 10px;
font-size: 12px; font-weight: 500; color: var(--ink-2);
border: 1px solid var(--rule); border-radius: var(--radius);
background: var(--paper);
align-self: center;
margin-bottom: 4px;
transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.ie-copy-btn:hover { background: var(--bg-2); color: var(--ink); border-color: oklch(0.85 0.008 70); }
.ie-copy-btn.copied { background: var(--ok); color: white; border-color: var(--ok); }
.export-pre {
background: var(--bg); border: 1px solid var(--rule); border-radius: var(--radius);
padding: 14px 16px;
font-family: var(--font-mono); font-size: 11.5px; line-height: 1.55;
color: var(--ink-2);
max-height: 360px; overflow: auto;
white-space: pre;
margin: 0;
}
/* ---------- Toast ---------- */
.toast {
position: fixed; bottom: 24px; left: 50%;
transform: translateX(-50%);
background: var(--ink); color: var(--bg);
padding: 9px 16px; border-radius: 99px;
font-size: 13px;
display: inline-flex; align-items: center; gap: 8px;
box-shadow: 0 10px 30px oklch(0.22 0.012 60 / 0.3);
z-index: 250;
animation: toast-in 0.2s ease;
}
@keyframes toast-in { from { opacity: 0; transform: translate(-50%, 8px); } }
@media (max-width: 900px) {
.main { grid-template-columns: 1fr; }
.filter-panel { position: static; max-height: none; border-right: 0; border-bottom: 1px solid var(--rule); }
.admin-grid { grid-template-columns: 1fr; }
.card.span-2, .card.span-3 { grid-column: span 1; }
.header { grid-template-columns: 1fr; gap: 10px; }
.stats-row { grid-template-columns: repeat(2, 1fr); }
.field-row { grid-template-columns: 1fr; }
.status-grid { grid-template-columns: repeat(2, 1fr); }
}
</style>
</head>
<body>
<template id="__bundler_thumbnail">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200">
<rect width="200" height="200" fill="#f7f3ec"/>
<g transform="translate(60,60)" stroke="#3a3530" stroke-width="3" fill="none" stroke-linecap="round">
<rect x="0" y="0" width="80" height="80" rx="4" fill="#ffffff"/>
<line x1="14" y1="22" x2="66" y2="22"/>
<line x1="14" y1="40" x2="56" y2="40"/>
<line x1="14" y1="58" x2="60" y2="58"/>
<circle cx="8" cy="22" r="2.5" fill="#3a3530"/>
<circle cx="8" cy="40" r="2.5" fill="#3a3530"/>
<circle cx="8" cy="58" r="2.5" fill="#3a3530"/>
</g>
</svg>
</template>
<div id="root"></div>
<script>
/**
* @license React
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
(function(){'use strict';(function(c,x){"object"===typeof exports&&"undefined"!==typeof module?x(exports):"function"===typeof define&&define.amd?define(["exports"],x):(c=c||self,x(c.React={}))})(this,function(c){function x(a){if(null===a||"object"!==typeof a)return null;a=V&&a[V]||a["@@iterator"];return"function"===typeof a?a:null}function w(a,b,e){this.props=a;this.context=b;this.refs=W;this.updater=e||X}function Y(){}function K(a,b,e){this.props=a;this.context=b;this.refs=W;this.updater=e||X}function Z(a,b,
e){var m,d={},c=null,h=null;if(null!=b)for(m in void 0!==b.ref&&(h=b.ref),void 0!==b.key&&(c=""+b.key),b)aa.call(b,m)&&!ba.hasOwnProperty(m)&&(d[m]=b[m]);var l=arguments.length-2;if(1===l)d.children=e;else if(1<l){for(var f=Array(l),k=0;k<l;k++)f[k]=arguments[k+2];d.children=f}if(a&&a.defaultProps)for(m in l=a.defaultProps,l)void 0===d[m]&&(d[m]=l[m]);return{$$typeof:y,type:a,key:c,ref:h,props:d,_owner:L.current}}function oa(a,b){return{$$typeof:y,type:a.type,key:b,ref:a.ref,props:a.props,_owner:a._owner}}
function M(a){return"object"===typeof a&&null!==a&&a.$$typeof===y}function pa(a){var b={"=":"=0",":":"=2"};return"$"+a.replace(/[=:]/g,function(a){return b[a]})}function N(a,b){return"object"===typeof a&&null!==a&&null!=a.key?pa(""+a.key):b.toString(36)}function B(a,b,e,m,d){var c=typeof a;if("undefined"===c||"boolean"===c)a=null;var h=!1;if(null===a)h=!0;else switch(c){case "string":case "number":h=!0;break;case "object":switch(a.$$typeof){case y:case qa:h=!0}}if(h)return h=a,d=d(h),a=""===m?"."+
N(h,0):m,ca(d)?(e="",null!=a&&(e=a.replace(da,"$&/")+"/"),B(d,b,e,"",function(a){return a})):null!=d&&(M(d)&&(d=oa(d,e+(!d.key||h&&h.key===d.key?"":(""+d.key).replace(da,"$&/")+"/")+a)),b.push(d)),1;h=0;m=""===m?".":m+":";if(ca(a))for(var l=0;l<a.length;l++){c=a[l];var f=m+N(c,l);h+=B(c,b,e,f,d)}else if(f=x(a),"function"===typeof f)for(a=f.call(a),l=0;!(c=a.next()).done;)c=c.value,f=m+N(c,l++),h+=B(c,b,e,f,d);else if("object"===c)throw b=String(a),Error("Objects are not valid as a React child (found: "+
("[object Object]"===b?"object with keys {"+Object.keys(a).join(", ")+"}":b)+"). If you meant to render a collection of children, use an array instead.");return h}function C(a,b,e){if(null==a)return a;var c=[],d=0;B(a,c,"","",function(a){return b.call(e,a,d++)});return c}function ra(a){if(-1===a._status){var b=a._result;b=b();b.then(function(b){if(0===a._status||-1===a._status)a._status=1,a._result=b},function(b){if(0===a._status||-1===a._status)a._status=2,a._result=b});-1===a._status&&(a._status=
0,a._result=b)}if(1===a._status)return a._result.default;throw a._result;}function O(a,b){var e=a.length;a.push(b);a:for(;0<e;){var c=e-1>>>1,d=a[c];if(0<D(d,b))a[c]=b,a[e]=d,e=c;else break a}}function p(a){return 0===a.length?null:a[0]}function E(a){if(0===a.length)return null;var b=a[0],e=a.pop();if(e!==b){a[0]=e;a:for(var c=0,d=a.length,k=d>>>1;c<k;){var h=2*(c+1)-1,l=a[h],f=h+1,g=a[f];if(0>D(l,e))f<d&&0>D(g,l)?(a[c]=g,a[f]=e,c=f):(a[c]=l,a[h]=e,c=h);else if(f<d&&0>D(g,e))a[c]=g,a[f]=e,c=f;else break a}}return b}
function D(a,b){var c=a.sortIndex-b.sortIndex;return 0!==c?c:a.id-b.id}function P(a){for(var b=p(r);null!==b;){if(null===b.callback)E(r);else if(b.startTime<=a)E(r),b.sortIndex=b.expirationTime,O(q,b);else break;b=p(r)}}function Q(a){z=!1;P(a);if(!u)if(null!==p(q))u=!0,R(S);else{var b=p(r);null!==b&&T(Q,b.startTime-a)}}function S(a,b){u=!1;z&&(z=!1,ea(A),A=-1);F=!0;var c=k;try{P(b);for(n=p(q);null!==n&&(!(n.expirationTime>b)||a&&!fa());){var m=n.callback;if("function"===typeof m){n.callback=null;
k=n.priorityLevel;var d=m(n.expirationTime<=b);b=v();"function"===typeof d?n.callback=d:n===p(q)&&E(q);P(b)}else E(q);n=p(q)}if(null!==n)var g=!0;else{var h=p(r);null!==h&&T(Q,h.startTime-b);g=!1}return g}finally{n=null,k=c,F=!1}}function fa(){return v()-ha<ia?!1:!0}function R(a){G=a;H||(H=!0,I())}function T(a,b){A=ja(function(){a(v())},b)}function ka(a){throw Error("act(...) is not supported in production builds of React.");}var y=Symbol.for("react.element"),qa=Symbol.for("react.portal"),sa=Symbol.for("react.fragment"),
ta=Symbol.for("react.strict_mode"),ua=Symbol.for("react.profiler"),va=Symbol.for("react.provider"),wa=Symbol.for("react.context"),xa=Symbol.for("react.forward_ref"),ya=Symbol.for("react.suspense"),za=Symbol.for("react.memo"),Aa=Symbol.for("react.lazy"),V=Symbol.iterator,X={isMounted:function(a){return!1},enqueueForceUpdate:function(a,b,c){},enqueueReplaceState:function(a,b,c,m){},enqueueSetState:function(a,b,c,m){}},la=Object.assign,W={};w.prototype.isReactComponent={};w.prototype.setState=function(a,
b){if("object"!==typeof a&&"function"!==typeof a&&null!=a)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,a,b,"setState")};w.prototype.forceUpdate=function(a){this.updater.enqueueForceUpdate(this,a,"forceUpdate")};Y.prototype=w.prototype;var t=K.prototype=new Y;t.constructor=K;la(t,w.prototype);t.isPureReactComponent=!0;var ca=Array.isArray,aa=Object.prototype.hasOwnProperty,L={current:null},
ba={key:!0,ref:!0,__self:!0,__source:!0},da=/\/+/g,g={current:null},J={transition:null};if("object"===typeof performance&&"function"===typeof performance.now){var Ba=performance;var v=function(){return Ba.now()}}else{var ma=Date,Ca=ma.now();v=function(){return ma.now()-Ca}}var q=[],r=[],Da=1,n=null,k=3,F=!1,u=!1,z=!1,ja="function"===typeof setTimeout?setTimeout:null,ea="function"===typeof clearTimeout?clearTimeout:null,na="undefined"!==typeof setImmediate?setImmediate:null;"undefined"!==typeof navigator&&
void 0!==navigator.scheduling&&void 0!==navigator.scheduling.isInputPending&&navigator.scheduling.isInputPending.bind(navigator.scheduling);var H=!1,G=null,A=-1,ia=5,ha=-1,U=function(){if(null!==G){var a=v();ha=a;var b=!0;try{b=G(!0,a)}finally{b?I():(H=!1,G=null)}}else H=!1};if("function"===typeof na)var I=function(){na(U)};else if("undefined"!==typeof MessageChannel){t=new MessageChannel;var Ea=t.port2;t.port1.onmessage=U;I=function(){Ea.postMessage(null)}}else I=function(){ja(U,0)};t={ReactCurrentDispatcher:g,
ReactCurrentOwner:L,ReactCurrentBatchConfig:J,Scheduler:{__proto__:null,unstable_ImmediatePriority:1,unstable_UserBlockingPriority:2,unstable_NormalPriority:3,unstable_IdlePriority:5,unstable_LowPriority:4,unstable_runWithPriority:function(a,b){switch(a){case 1:case 2:case 3:case 4:case 5:break;default:a=3}var c=k;k=a;try{return b()}finally{k=c}},unstable_next:function(a){switch(k){case 1:case 2:case 3:var b=3;break;default:b=k}var c=k;k=b;try{return a()}finally{k=c}},unstable_scheduleCallback:function(a,
b,c){var e=v();"object"===typeof c&&null!==c?(c=c.delay,c="number"===typeof c&&0<c?e+c:e):c=e;switch(a){case 1:var d=-1;break;case 2:d=250;break;case 5:d=1073741823;break;case 4:d=1E4;break;default:d=5E3}d=c+d;a={id:Da++,callback:b,priorityLevel:a,startTime:c,expirationTime:d,sortIndex:-1};c>e?(a.sortIndex=c,O(r,a),null===p(q)&&a===p(r)&&(z?(ea(A),A=-1):z=!0,T(Q,c-e))):(a.sortIndex=d,O(q,a),u||F||(u=!0,R(S)));return a},unstable_cancelCallback:function(a){a.callback=null},unstable_wrapCallback:function(a){var b=
k;return function(){var c=k;k=b;try{return a.apply(this,arguments)}finally{k=c}}},unstable_getCurrentPriorityLevel:function(){return k},unstable_shouldYield:fa,unstable_requestPaint:function(){},unstable_continueExecution:function(){u||F||(u=!0,R(S))},unstable_pauseExecution:function(){},unstable_getFirstCallbackNode:function(){return p(q)},get unstable_now(){return v},unstable_forceFrameRate:function(a){0>a||125<a?console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"):
ia=0<a?Math.floor(1E3/a):5},unstable_Profiling:null}};c.Children={map:C,forEach:function(a,b,c){C(a,function(){b.apply(this,arguments)},c)},count:function(a){var b=0;C(a,function(){b++});return b},toArray:function(a){return C(a,function(a){return a})||[]},only:function(a){if(!M(a))throw Error("React.Children.only expected to receive a single React element child.");return a}};c.Component=w;c.Fragment=sa;c.Profiler=ua;c.PureComponent=K;c.StrictMode=ta;c.Suspense=ya;c.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=
t;c.act=ka;c.cloneElement=function(a,b,c){if(null===a||void 0===a)throw Error("React.cloneElement(...): The argument must be a React element, but you passed "+a+".");var e=la({},a.props),d=a.key,k=a.ref,h=a._owner;if(null!=b){void 0!==b.ref&&(k=b.ref,h=L.current);void 0!==b.key&&(d=""+b.key);if(a.type&&a.type.defaultProps)var l=a.type.defaultProps;for(f in b)aa.call(b,f)&&!ba.hasOwnProperty(f)&&(e[f]=void 0===b[f]&&void 0!==l?l[f]:b[f])}var f=arguments.length-2;if(1===f)e.children=c;else if(1<f){l=
Array(f);for(var g=0;g<f;g++)l[g]=arguments[g+2];e.children=l}return{$$typeof:y,type:a.type,key:d,ref:k,props:e,_owner:h}};c.createContext=function(a){a={$$typeof:wa,_currentValue:a,_currentValue2:a,_threadCount:0,Provider:null,Consumer:null,_defaultValue:null,_globalName:null};a.Provider={$$typeof:va,_context:a};return a.Consumer=a};c.createElement=Z;c.createFactory=function(a){var b=Z.bind(null,a);b.type=a;return b};c.createRef=function(){return{current:null}};c.forwardRef=function(a){return{$$typeof:xa,
render:a}};c.isValidElement=M;c.lazy=function(a){return{$$typeof:Aa,_payload:{_status:-1,_result:a},_init:ra}};c.memo=function(a,b){return{$$typeof:za,type:a,compare:void 0===b?null:b}};c.startTransition=function(a,b){b=J.transition;J.transition={};try{a()}finally{J.transition=b}};c.unstable_act=ka;c.useCallback=function(a,b){return g.current.useCallback(a,b)};c.useContext=function(a){return g.current.useContext(a)};c.useDebugValue=function(a,b){};c.useDeferredValue=function(a){return g.current.useDeferredValue(a)};
c.useEffect=function(a,b){return g.current.useEffect(a,b)};c.useId=function(){return g.current.useId()};c.useImperativeHandle=function(a,b,c){return g.current.useImperativeHandle(a,b,c)};c.useInsertionEffect=function(a,b){return g.current.useInsertionEffect(a,b)};c.useLayoutEffect=function(a,b){return g.current.useLayoutEffect(a,b)};c.useMemo=function(a,b){return g.current.useMemo(a,b)};c.useReducer=function(a,b,c){return g.current.useReducer(a,b,c)};c.useRef=function(a){return g.current.useRef(a)};
c.useState=function(a){return g.current.useState(a)};c.useSyncExternalStore=function(a,b,c){return g.current.useSyncExternalStore(a,b,c)};c.useTransition=function(){return g.current.useTransition()};c.version="18.3.1"});
})();
</script>
<script>
/**
* @license React
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
(function(){/*
Modernizr 3.0.0pre (Custom Build) | MIT
*/
'use strict';(function(Q,zb){"object"===typeof exports&&"undefined"!==typeof module?zb(exports,require("react")):"function"===typeof define&&define.amd?define(["exports","react"],zb):(Q=Q||self,zb(Q.ReactDOM={},Q.React))})(this,function(Q,zb){function m(a){for(var b="https://reactjs.org/docs/error-decoder.html?invariant="+a,c=1;c<arguments.length;c++)b+="&args[]="+encodeURIComponent(arguments[c]);return"Minified React error #"+a+"; visit "+b+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}
function mb(a,b){Ab(a,b);Ab(a+"Capture",b)}function Ab(a,b){$b[a]=b;for(a=0;a<b.length;a++)cg.add(b[a])}function bj(a){if(Zd.call(dg,a))return!0;if(Zd.call(eg,a))return!1;if(cj.test(a))return dg[a]=!0;eg[a]=!0;return!1}function dj(a,b,c,d){if(null!==c&&0===c.type)return!1;switch(typeof b){case "function":case "symbol":return!0;case "boolean":if(d)return!1;if(null!==c)return!c.acceptsBooleans;a=a.toLowerCase().slice(0,5);return"data-"!==a&&"aria-"!==a;default:return!1}}function ej(a,b,c,d){if(null===
b||"undefined"===typeof b||dj(a,b,c,d))return!0;if(d)return!1;if(null!==c)switch(c.type){case 3:return!b;case 4:return!1===b;case 5:return isNaN(b);case 6:return isNaN(b)||1>b}return!1}function Y(a,b,c,d,e,f,g){this.acceptsBooleans=2===b||3===b||4===b;this.attributeName=d;this.attributeNamespace=e;this.mustUseProperty=c;this.propertyName=a;this.type=b;this.sanitizeURL=f;this.removeEmptyString=g}function $d(a,b,c,d){var e=R.hasOwnProperty(b)?R[b]:null;if(null!==e?0!==e.type:d||!(2<b.length)||"o"!==
b[0]&&"O"!==b[0]||"n"!==b[1]&&"N"!==b[1])ej(b,c,e,d)&&(c=null),d||null===e?bj(b)&&(null===c?a.removeAttribute(b):a.setAttribute(b,""+c)):e.mustUseProperty?a[e.propertyName]=null===c?3===e.type?!1:"":c:(b=e.attributeName,d=e.attributeNamespace,null===c?a.removeAttribute(b):(e=e.type,c=3===e||4===e&&!0===c?"":""+c,d?a.setAttributeNS(d,b,c):a.setAttribute(b,c)))}function ac(a){if(null===a||"object"!==typeof a)return null;a=fg&&a[fg]||a["@@iterator"];return"function"===typeof a?a:null}function bc(a,b,
c){if(void 0===ae)try{throw Error();}catch(d){ae=(b=d.stack.trim().match(/\n( *(at )?)/))&&b[1]||""}return"\n"+ae+a}function be(a,b){if(!a||ce)return"";ce=!0;var c=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{if(b)if(b=function(){throw Error();},Object.defineProperty(b.prototype,"props",{set:function(){throw Error();}}),"object"===typeof Reflect&&Reflect.construct){try{Reflect.construct(b,[])}catch(n){var d=n}Reflect.construct(a,[],b)}else{try{b.call()}catch(n){d=n}a.call(b.prototype)}else{try{throw Error();
}catch(n){d=n}a()}}catch(n){if(n&&d&&"string"===typeof n.stack){for(var e=n.stack.split("\n"),f=d.stack.split("\n"),g=e.length-1,h=f.length-1;1<=g&&0<=h&&e[g]!==f[h];)h--;for(;1<=g&&0<=h;g--,h--)if(e[g]!==f[h]){if(1!==g||1!==h){do if(g--,h--,0>h||e[g]!==f[h]){var k="\n"+e[g].replace(" at new "," at ");a.displayName&&k.includes("<anonymous>")&&(k=k.replace("<anonymous>",a.displayName));return k}while(1<=g&&0<=h)}break}}}finally{ce=!1,Error.prepareStackTrace=c}return(a=a?a.displayName||a.name:"")?bc(a):
""}function fj(a){switch(a.tag){case 5:return bc(a.type);case 16:return bc("Lazy");case 13:return bc("Suspense");case 19:return bc("SuspenseList");case 0:case 2:case 15:return a=be(a.type,!1),a;case 11:return a=be(a.type.render,!1),a;case 1:return a=be(a.type,!0),a;default:return""}}function de(a){if(null==a)return null;if("function"===typeof a)return a.displayName||a.name||null;if("string"===typeof a)return a;switch(a){case Bb:return"Fragment";case Cb:return"Portal";case ee:return"Profiler";case fe:return"StrictMode";
case ge:return"Suspense";case he:return"SuspenseList"}if("object"===typeof a)switch(a.$$typeof){case gg:return(a.displayName||"Context")+".Consumer";case hg:return(a._context.displayName||"Context")+".Provider";case ie:var b=a.render;a=a.displayName;a||(a=b.displayName||b.name||"",a=""!==a?"ForwardRef("+a+")":"ForwardRef");return a;case je:return b=a.displayName||null,null!==b?b:de(a.type)||"Memo";case Ta:b=a._payload;a=a._init;try{return de(a(b))}catch(c){}}return null}function gj(a){var b=a.type;
switch(a.tag){case 24:return"Cache";case 9:return(b.displayName||"Context")+".Consumer";case 10:return(b._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return a=b.render,a=a.displayName||a.name||"",b.displayName||(""!==a?"ForwardRef("+a+")":"ForwardRef");case 7:return"Fragment";case 5:return b;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return de(b);case 8:return b===fe?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";
case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if("function"===typeof b)return b.displayName||b.name||null;if("string"===typeof b)return b}return null}function Ua(a){switch(typeof a){case "boolean":case "number":case "string":case "undefined":return a;case "object":return a;default:return""}}function ig(a){var b=a.type;return(a=a.nodeName)&&"input"===a.toLowerCase()&&("checkbox"===b||"radio"===
b)}function hj(a){var b=ig(a)?"checked":"value",c=Object.getOwnPropertyDescriptor(a.constructor.prototype,b),d=""+a[b];if(!a.hasOwnProperty(b)&&"undefined"!==typeof c&&"function"===typeof c.get&&"function"===typeof c.set){var e=c.get,f=c.set;Object.defineProperty(a,b,{configurable:!0,get:function(){return e.call(this)},set:function(a){d=""+a;f.call(this,a)}});Object.defineProperty(a,b,{enumerable:c.enumerable});return{getValue:function(){return d},setValue:function(a){d=""+a},stopTracking:function(){a._valueTracker=
null;delete a[b]}}}}function Pc(a){a._valueTracker||(a._valueTracker=hj(a))}function jg(a){if(!a)return!1;var b=a._valueTracker;if(!b)return!0;var c=b.getValue();var d="";a&&(d=ig(a)?a.checked?"true":"false":a.value);a=d;return a!==c?(b.setValue(a),!0):!1}function Qc(a){a=a||("undefined"!==typeof document?document:void 0);if("undefined"===typeof a)return null;try{return a.activeElement||a.body}catch(b){return a.body}}function ke(a,b){var c=b.checked;return E({},b,{defaultChecked:void 0,defaultValue:void 0,
value:void 0,checked:null!=c?c:a._wrapperState.initialChecked})}function kg(a,b){var c=null==b.defaultValue?"":b.defaultValue,d=null!=b.checked?b.checked:b.defaultChecked;c=Ua(null!=b.value?b.value:c);a._wrapperState={initialChecked:d,initialValue:c,controlled:"checkbox"===b.type||"radio"===b.type?null!=b.checked:null!=b.value}}function lg(a,b){b=b.checked;null!=b&&$d(a,"checked",b,!1)}function le(a,b){lg(a,b);var c=Ua(b.value),d=b.type;if(null!=c)if("number"===d){if(0===c&&""===a.value||a.value!=
c)a.value=""+c}else a.value!==""+c&&(a.value=""+c);else if("submit"===d||"reset"===d){a.removeAttribute("value");return}b.hasOwnProperty("value")?me(a,b.type,c):b.hasOwnProperty("defaultValue")&&me(a,b.type,Ua(b.defaultValue));null==b.checked&&null!=b.defaultChecked&&(a.defaultChecked=!!b.defaultChecked)}function mg(a,b,c){if(b.hasOwnProperty("value")||b.hasOwnProperty("defaultValue")){var d=b.type;if(!("submit"!==d&&"reset"!==d||void 0!==b.value&&null!==b.value))return;b=""+a._wrapperState.initialValue;
c||b===a.value||(a.value=b);a.defaultValue=b}c=a.name;""!==c&&(a.name="");a.defaultChecked=!!a._wrapperState.initialChecked;""!==c&&(a.name=c)}function me(a,b,c){if("number"!==b||Qc(a.ownerDocument)!==a)null==c?a.defaultValue=""+a._wrapperState.initialValue:a.defaultValue!==""+c&&(a.defaultValue=""+c)}function Db(a,b,c,d){a=a.options;if(b){b={};for(var e=0;e<c.length;e++)b["$"+c[e]]=!0;for(c=0;c<a.length;c++)e=b.hasOwnProperty("$"+a[c].value),a[c].selected!==e&&(a[c].selected=e),e&&d&&(a[c].defaultSelected=
!0)}else{c=""+Ua(c);b=null;for(e=0;e<a.length;e++){if(a[e].value===c){a[e].selected=!0;d&&(a[e].defaultSelected=!0);return}null!==b||a[e].disabled||(b=a[e])}null!==b&&(b.selected=!0)}}function ne(a,b){if(null!=b.dangerouslySetInnerHTML)throw Error(m(91));return E({},b,{value:void 0,defaultValue:void 0,children:""+a._wrapperState.initialValue})}function ng(a,b){var c=b.value;if(null==c){c=b.children;b=b.defaultValue;if(null!=c){if(null!=b)throw Error(m(92));if(cc(c)){if(1<c.length)throw Error(m(93));
c=c[0]}b=c}null==b&&(b="");c=b}a._wrapperState={initialValue:Ua(c)}}function og(a,b){var c=Ua(b.value),d=Ua(b.defaultValue);null!=c&&(c=""+c,c!==a.value&&(a.value=c),null==b.defaultValue&&a.defaultValue!==c&&(a.defaultValue=c));null!=d&&(a.defaultValue=""+d)}function pg(a,b){b=a.textContent;b===a._wrapperState.initialValue&&""!==b&&null!==b&&(a.value=b)}function qg(a){switch(a){case "svg":return"http://www.w3.org/2000/svg";case "math":return"http://www.w3.org/1998/Math/MathML";default:return"http://www.w3.org/1999/xhtml"}}
function oe(a,b){return null==a||"http://www.w3.org/1999/xhtml"===a?qg(b):"http://www.w3.org/2000/svg"===a&&"foreignObject"===b?"http://www.w3.org/1999/xhtml":a}function rg(a,b,c){return null==b||"boolean"===typeof b||""===b?"":c||"number"!==typeof b||0===b||dc.hasOwnProperty(a)&&dc[a]?(""+b).trim():b+"px"}function sg(a,b){a=a.style;for(var c in b)if(b.hasOwnProperty(c)){var d=0===c.indexOf("--"),e=rg(c,b[c],d);"float"===c&&(c="cssFloat");d?a.setProperty(c,e):a[c]=e}}function pe(a,b){if(b){if(ij[a]&&
(null!=b.children||null!=b.dangerouslySetInnerHTML))throw Error(m(137,a));if(null!=b.dangerouslySetInnerHTML){if(null!=b.children)throw Error(m(60));if("object"!==typeof b.dangerouslySetInnerHTML||!("__html"in b.dangerouslySetInnerHTML))throw Error(m(61));}if(null!=b.style&&"object"!==typeof b.style)throw Error(m(62));}}function qe(a,b){if(-1===a.indexOf("-"))return"string"===typeof b.is;switch(a){case "annotation-xml":case "color-profile":case "font-face":case "font-face-src":case "font-face-uri":case "font-face-format":case "font-face-name":case "missing-glyph":return!1;
default:return!0}}function re(a){a=a.target||a.srcElement||window;a.correspondingUseElement&&(a=a.correspondingUseElement);return 3===a.nodeType?a.parentNode:a}function tg(a){if(a=ec(a)){if("function"!==typeof se)throw Error(m(280));var b=a.stateNode;b&&(b=Rc(b),se(a.stateNode,a.type,b))}}function ug(a){Eb?Fb?Fb.push(a):Fb=[a]:Eb=a}function vg(){if(Eb){var a=Eb,b=Fb;Fb=Eb=null;tg(a);if(b)for(a=0;a<b.length;a++)tg(b[a])}}function wg(a,b,c){if(te)return a(b,c);te=!0;try{return xg(a,b,c)}finally{if(te=
!1,null!==Eb||null!==Fb)yg(),vg()}}function fc(a,b){var c=a.stateNode;if(null===c)return null;var d=Rc(c);if(null===d)return null;c=d[b];a:switch(b){case "onClick":case "onClickCapture":case "onDoubleClick":case "onDoubleClickCapture":case "onMouseDown":case "onMouseDownCapture":case "onMouseMove":case "onMouseMoveCapture":case "onMouseUp":case "onMouseUpCapture":case "onMouseEnter":(d=!d.disabled)||(a=a.type,d=!("button"===a||"input"===a||"select"===a||"textarea"===a));a=!d;break a;default:a=!1}if(a)return null;
if(c&&"function"!==typeof c)throw Error(m(231,b,typeof c));return c}function jj(a,b,c,d,e,f,g,h,k){gc=!1;Sc=null;kj.apply(lj,arguments)}function mj(a,b,c,d,e,f,g,h,k){jj.apply(this,arguments);if(gc){if(gc){var n=Sc;gc=!1;Sc=null}else throw Error(m(198));Tc||(Tc=!0,ue=n)}}function nb(a){var b=a,c=a;if(a.alternate)for(;b.return;)b=b.return;else{a=b;do b=a,0!==(b.flags&4098)&&(c=b.return),a=b.return;while(a)}return 3===b.tag?c:null}function zg(a){if(13===a.tag){var b=a.memoizedState;null===b&&(a=a.alternate,
null!==a&&(b=a.memoizedState));if(null!==b)return b.dehydrated}return null}function Ag(a){if(nb(a)!==a)throw Error(m(188));}function nj(a){var b=a.alternate;if(!b){b=nb(a);if(null===b)throw Error(m(188));return b!==a?null:a}for(var c=a,d=b;;){var e=c.return;if(null===e)break;var f=e.alternate;if(null===f){d=e.return;if(null!==d){c=d;continue}break}if(e.child===f.child){for(f=e.child;f;){if(f===c)return Ag(e),a;if(f===d)return Ag(e),b;f=f.sibling}throw Error(m(188));}if(c.return!==d.return)c=e,d=f;
else{for(var g=!1,h=e.child;h;){if(h===c){g=!0;c=e;d=f;break}if(h===d){g=!0;d=e;c=f;break}h=h.sibling}if(!g){for(h=f.child;h;){if(h===c){g=!0;c=f;d=e;break}if(h===d){g=!0;d=f;c=e;break}h=h.sibling}if(!g)throw Error(m(189));}}if(c.alternate!==d)throw Error(m(190));}if(3!==c.tag)throw Error(m(188));return c.stateNode.current===c?a:b}function Bg(a){a=nj(a);return null!==a?Cg(a):null}function Cg(a){if(5===a.tag||6===a.tag)return a;for(a=a.child;null!==a;){var b=Cg(a);if(null!==b)return b;a=a.sibling}return null}
function oj(a,b){if(Ca&&"function"===typeof Ca.onCommitFiberRoot)try{Ca.onCommitFiberRoot(Uc,a,void 0,128===(a.current.flags&128))}catch(c){}}function pj(a){a>>>=0;return 0===a?32:31-(qj(a)/rj|0)|0}function hc(a){switch(a&-a){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return a&
4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return a&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return a}}function Vc(a,b){var c=a.pendingLanes;if(0===c)return 0;var d=0,e=a.suspendedLanes,f=a.pingedLanes,g=c&268435455;if(0!==g){var h=g&~e;0!==h?d=hc(h):(f&=g,0!==f&&(d=hc(f)))}else g=c&~e,0!==g?d=hc(g):0!==f&&(d=hc(f));if(0===d)return 0;if(0!==b&&b!==d&&0===(b&e)&&
(e=d&-d,f=b&-b,e>=f||16===e&&0!==(f&4194240)))return b;0!==(d&4)&&(d|=c&16);b=a.entangledLanes;if(0!==b)for(a=a.entanglements,b&=d;0<b;)c=31-ta(b),e=1<<c,d|=a[c],b&=~e;return d}function sj(a,b){switch(a){case 1:case 2:case 4:return b+250;case 8:case 16:case 32:case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return b+5E3;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return-1;
case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function tj(a,b){for(var c=a.suspendedLanes,d=a.pingedLanes,e=a.expirationTimes,f=a.pendingLanes;0<f;){var g=31-ta(f),h=1<<g,k=e[g];if(-1===k){if(0===(h&c)||0!==(h&d))e[g]=sj(h,b)}else k<=b&&(a.expiredLanes|=h);f&=~h}}function ve(a){a=a.pendingLanes&-1073741825;return 0!==a?a:a&1073741824?1073741824:0}function Dg(){var a=Wc;Wc<<=1;0===(Wc&4194240)&&(Wc=64);return a}function we(a){for(var b=[],c=0;31>c;c++)b.push(a);
return b}function ic(a,b,c){a.pendingLanes|=b;536870912!==b&&(a.suspendedLanes=0,a.pingedLanes=0);a=a.eventTimes;b=31-ta(b);a[b]=c}function uj(a,b){var c=a.pendingLanes&~b;a.pendingLanes=b;a.suspendedLanes=0;a.pingedLanes=0;a.expiredLanes&=b;a.mutableReadLanes&=b;a.entangledLanes&=b;b=a.entanglements;var d=a.eventTimes;for(a=a.expirationTimes;0<c;){var e=31-ta(c),f=1<<e;b[e]=0;d[e]=-1;a[e]=-1;c&=~f}}function xe(a,b){var c=a.entangledLanes|=b;for(a=a.entanglements;c;){var d=31-ta(c),e=1<<d;e&b|a[d]&
b&&(a[d]|=b);c&=~e}}function Eg(a){a&=-a;return 1<a?4<a?0!==(a&268435455)?16:536870912:4:1}function Fg(a,b){switch(a){case "focusin":case "focusout":Va=null;break;case "dragenter":case "dragleave":Wa=null;break;case "mouseover":case "mouseout":Xa=null;break;case "pointerover":case "pointerout":jc.delete(b.pointerId);break;case "gotpointercapture":case "lostpointercapture":kc.delete(b.pointerId)}}function lc(a,b,c,d,e,f){if(null===a||a.nativeEvent!==f)return a={blockedOn:b,domEventName:c,eventSystemFlags:d,
nativeEvent:f,targetContainers:[e]},null!==b&&(b=ec(b),null!==b&&Gg(b)),a;a.eventSystemFlags|=d;b=a.targetContainers;null!==e&&-1===b.indexOf(e)&&b.push(e);return a}function vj(a,b,c,d,e){switch(b){case "focusin":return Va=lc(Va,a,b,c,d,e),!0;case "dragenter":return Wa=lc(Wa,a,b,c,d,e),!0;case "mouseover":return Xa=lc(Xa,a,b,c,d,e),!0;case "pointerover":var f=e.pointerId;jc.set(f,lc(jc.get(f)||null,a,b,c,d,e));return!0;case "gotpointercapture":return f=e.pointerId,kc.set(f,lc(kc.get(f)||null,a,b,
c,d,e)),!0}return!1}function Hg(a){var b=ob(a.target);if(null!==b){var c=nb(b);if(null!==c)if(b=c.tag,13===b){if(b=zg(c),null!==b){a.blockedOn=b;wj(a.priority,function(){xj(c)});return}}else if(3===b&&c.stateNode.current.memoizedState.isDehydrated){a.blockedOn=3===c.tag?c.stateNode.containerInfo:null;return}}a.blockedOn=null}function Xc(a){if(null!==a.blockedOn)return!1;for(var b=a.targetContainers;0<b.length;){var c=ye(a.domEventName,a.eventSystemFlags,b[0],a.nativeEvent);if(null===c){c=a.nativeEvent;
var d=new c.constructor(c.type,c);ze=d;c.target.dispatchEvent(d);ze=null}else return b=ec(c),null!==b&&Gg(b),a.blockedOn=c,!1;b.shift()}return!0}function Ig(a,b,c){Xc(a)&&c.delete(b)}function yj(){Ae=!1;null!==Va&&Xc(Va)&&(Va=null);null!==Wa&&Xc(Wa)&&(Wa=null);null!==Xa&&Xc(Xa)&&(Xa=null);jc.forEach(Ig);kc.forEach(Ig)}function mc(a,b){a.blockedOn===b&&(a.blockedOn=null,Ae||(Ae=!0,Jg(Kg,yj)))}function nc(a){if(0<Yc.length){mc(Yc[0],a);for(var b=1;b<Yc.length;b++){var c=Yc[b];c.blockedOn===a&&(c.blockedOn=
null)}}null!==Va&&mc(Va,a);null!==Wa&&mc(Wa,a);null!==Xa&&mc(Xa,a);b=function(b){return mc(b,a)};jc.forEach(b);kc.forEach(b);for(b=0;b<Ya.length;b++)c=Ya[b],c.blockedOn===a&&(c.blockedOn=null);for(;0<Ya.length&&(b=Ya[0],null===b.blockedOn);)Hg(b),null===b.blockedOn&&Ya.shift()}function zj(a,b,c,d){var e=z,f=Gb.transition;Gb.transition=null;try{z=1,Be(a,b,c,d)}finally{z=e,Gb.transition=f}}function Aj(a,b,c,d){var e=z,f=Gb.transition;Gb.transition=null;try{z=4,Be(a,b,c,d)}finally{z=e,Gb.transition=
f}}function Be(a,b,c,d){if(Zc){var e=ye(a,b,c,d);if(null===e)Ce(a,b,d,$c,c),Fg(a,d);else if(vj(e,a,b,c,d))d.stopPropagation();else if(Fg(a,d),b&4&&-1<Bj.indexOf(a)){for(;null!==e;){var f=ec(e);null!==f&&Cj(f);f=ye(a,b,c,d);null===f&&Ce(a,b,d,$c,c);if(f===e)break;e=f}null!==e&&d.stopPropagation()}else Ce(a,b,d,null,c)}}function ye(a,b,c,d){$c=null;a=re(d);a=ob(a);if(null!==a)if(b=nb(a),null===b)a=null;else if(c=b.tag,13===c){a=zg(b);if(null!==a)return a;a=null}else if(3===c){if(b.stateNode.current.memoizedState.isDehydrated)return 3===
b.tag?b.stateNode.containerInfo:null;a=null}else b!==a&&(a=null);$c=a;return null}function Lg(a){switch(a){case "cancel":case "click":case "close":case "contextmenu":case "copy":case "cut":case "auxclick":case "dblclick":case "dragend":case "dragstart":case "drop":case "focusin":case "focusout":case "input":case "invalid":case "keydown":case "keypress":case "keyup":case "mousedown":case "mouseup":case "paste":case "pause":case "play":case "pointercancel":case "pointerdown":case "pointerup":case "ratechange":case "reset":case "resize":case "seeked":case "submit":case "touchcancel":case "touchend":case "touchstart":case "volumechange":case "change":case "selectionchange":case "textInput":case "compositionstart":case "compositionend":case "compositionupdate":case "beforeblur":case "afterblur":case "beforeinput":case "blur":case "fullscreenchange":case "focus":case "hashchange":case "popstate":case "select":case "selectstart":return 1;
case "drag":case "dragenter":case "dragexit":case "dragleave":case "dragover":case "mousemove":case "mouseout":case "mouseover":case "pointermove":case "pointerout":case "pointerover":case "scroll":case "toggle":case "touchmove":case "wheel":case "mouseenter":case "mouseleave":case "pointerenter":case "pointerleave":return 4;case "message":switch(Dj()){case De:return 1;case Mg:return 4;case ad:case Ej:return 16;case Ng:return 536870912;default:return 16}default:return 16}}function Og(){if(bd)return bd;
var a,b=Ee,c=b.length,d,e="value"in Za?Za.value:Za.textContent,f=e.length;for(a=0;a<c&&b[a]===e[a];a++);var g=c-a;for(d=1;d<=g&&b[c-d]===e[f-d];d++);return bd=e.slice(a,1<d?1-d:void 0)}function cd(a){var b=a.keyCode;"charCode"in a?(a=a.charCode,0===a&&13===b&&(a=13)):a=b;10===a&&(a=13);return 32<=a||13===a?a:0}function dd(){return!0}function Pg(){return!1}function ka(a){function b(b,d,e,f,g){this._reactName=b;this._targetInst=e;this.type=d;this.nativeEvent=f;this.target=g;this.currentTarget=null;
for(var c in a)a.hasOwnProperty(c)&&(b=a[c],this[c]=b?b(f):f[c]);this.isDefaultPrevented=(null!=f.defaultPrevented?f.defaultPrevented:!1===f.returnValue)?dd:Pg;this.isPropagationStopped=Pg;return this}E(b.prototype,{preventDefault:function(){this.defaultPrevented=!0;var a=this.nativeEvent;a&&(a.preventDefault?a.preventDefault():"unknown"!==typeof a.returnValue&&(a.returnValue=!1),this.isDefaultPrevented=dd)},stopPropagation:function(){var a=this.nativeEvent;a&&(a.stopPropagation?a.stopPropagation():
"unknown"!==typeof a.cancelBubble&&(a.cancelBubble=!0),this.isPropagationStopped=dd)},persist:function(){},isPersistent:dd});return b}function Fj(a){var b=this.nativeEvent;return b.getModifierState?b.getModifierState(a):(a=Gj[a])?!!b[a]:!1}function Fe(a){return Fj}function Qg(a,b){switch(a){case "keyup":return-1!==Hj.indexOf(b.keyCode);case "keydown":return 229!==b.keyCode;case "keypress":case "mousedown":case "focusout":return!0;default:return!1}}function Rg(a){a=a.detail;return"object"===typeof a&&
"data"in a?a.data:null}function Ij(a,b){switch(a){case "compositionend":return Rg(b);case "keypress":if(32!==b.which)return null;Sg=!0;return Tg;case "textInput":return a=b.data,a===Tg&&Sg?null:a;default:return null}}function Jj(a,b){if(Hb)return"compositionend"===a||!Ge&&Qg(a,b)?(a=Og(),bd=Ee=Za=null,Hb=!1,a):null;switch(a){case "paste":return null;case "keypress":if(!(b.ctrlKey||b.altKey||b.metaKey)||b.ctrlKey&&b.altKey){if(b.char&&1<b.char.length)return b.char;if(b.which)return String.fromCharCode(b.which)}return null;
case "compositionend":return Ug&&"ko"!==b.locale?null:b.data;default:return null}}function Vg(a){var b=a&&a.nodeName&&a.nodeName.toLowerCase();return"input"===b?!!Kj[a.type]:"textarea"===b?!0:!1}function Lj(a){if(!Ia)return!1;a="on"+a;var b=a in document;b||(b=document.createElement("div"),b.setAttribute(a,"return;"),b="function"===typeof b[a]);return b}function Wg(a,b,c,d){ug(d);b=ed(b,"onChange");0<b.length&&(c=new He("onChange","change",null,c,d),a.push({event:c,listeners:b}))}function Mj(a){Xg(a,
0)}function fd(a){var b=Ib(a);if(jg(b))return a}function Nj(a,b){if("change"===a)return b}function Yg(){oc&&(oc.detachEvent("onpropertychange",Zg),pc=oc=null)}function Zg(a){if("value"===a.propertyName&&fd(pc)){var b=[];Wg(b,pc,a,re(a));wg(Mj,b)}}function Oj(a,b,c){"focusin"===a?(Yg(),oc=b,pc=c,oc.attachEvent("onpropertychange",Zg)):"focusout"===a&&Yg()}function Pj(a,b){if("selectionchange"===a||"keyup"===a||"keydown"===a)return fd(pc)}function Qj(a,b){if("click"===a)return fd(b)}function Rj(a,b){if("input"===
a||"change"===a)return fd(b)}function Sj(a,b){return a===b&&(0!==a||1/a===1/b)||a!==a&&b!==b}function qc(a,b){if(ua(a,b))return!0;if("object"!==typeof a||null===a||"object"!==typeof b||null===b)return!1;var c=Object.keys(a),d=Object.keys(b);if(c.length!==d.length)return!1;for(d=0;d<c.length;d++){var e=c[d];if(!Zd.call(b,e)||!ua(a[e],b[e]))return!1}return!0}function $g(a){for(;a&&a.firstChild;)a=a.firstChild;return a}function ah(a,b){var c=$g(a);a=0;for(var d;c;){if(3===c.nodeType){d=a+c.textContent.length;
if(a<=b&&d>=b)return{node:c,offset:b-a};a=d}a:{for(;c;){if(c.nextSibling){c=c.nextSibling;break a}c=c.parentNode}c=void 0}c=$g(c)}}function bh(a,b){return a&&b?a===b?!0:a&&3===a.nodeType?!1:b&&3===b.nodeType?bh(a,b.parentNode):"contains"in a?a.contains(b):a.compareDocumentPosition?!!(a.compareDocumentPosition(b)&16):!1:!1}function ch(){for(var a=window,b=Qc();b instanceof a.HTMLIFrameElement;){try{var c="string"===typeof b.contentWindow.location.href}catch(d){c=!1}if(c)a=b.contentWindow;else break;
b=Qc(a.document)}return b}function Ie(a){var b=a&&a.nodeName&&a.nodeName.toLowerCase();return b&&("input"===b&&("text"===a.type||"search"===a.type||"tel"===a.type||"url"===a.type||"password"===a.type)||"textarea"===b||"true"===a.contentEditable)}function Tj(a){var b=ch(),c=a.focusedElem,d=a.selectionRange;if(b!==c&&c&&c.ownerDocument&&bh(c.ownerDocument.documentElement,c)){if(null!==d&&Ie(c))if(b=d.start,a=d.end,void 0===a&&(a=b),"selectionStart"in c)c.selectionStart=b,c.selectionEnd=Math.min(a,c.value.length);
else if(a=(b=c.ownerDocument||document)&&b.defaultView||window,a.getSelection){a=a.getSelection();var e=c.textContent.length,f=Math.min(d.start,e);d=void 0===d.end?f:Math.min(d.end,e);!a.extend&&f>d&&(e=d,d=f,f=e);e=ah(c,f);var g=ah(c,d);e&&g&&(1!==a.rangeCount||a.anchorNode!==e.node||a.anchorOffset!==e.offset||a.focusNode!==g.node||a.focusOffset!==g.offset)&&(b=b.createRange(),b.setStart(e.node,e.offset),a.removeAllRanges(),f>d?(a.addRange(b),a.extend(g.node,g.offset)):(b.setEnd(g.node,g.offset),
a.addRange(b)))}b=[];for(a=c;a=a.parentNode;)1===a.nodeType&&b.push({element:a,left:a.scrollLeft,top:a.scrollTop});"function"===typeof c.focus&&c.focus();for(c=0;c<b.length;c++)a=b[c],a.element.scrollLeft=a.left,a.element.scrollTop=a.top}}function dh(a,b,c){var d=c.window===c?c.document:9===c.nodeType?c:c.ownerDocument;Je||null==Jb||Jb!==Qc(d)||(d=Jb,"selectionStart"in d&&Ie(d)?d={start:d.selectionStart,end:d.selectionEnd}:(d=(d.ownerDocument&&d.ownerDocument.defaultView||window).getSelection(),d=
{anchorNode:d.anchorNode,anchorOffset:d.anchorOffset,focusNode:d.focusNode,focusOffset:d.focusOffset}),rc&&qc(rc,d)||(rc=d,d=ed(Ke,"onSelect"),0<d.length&&(b=new He("onSelect","select",null,b,c),a.push({event:b,listeners:d}),b.target=Jb)))}function gd(a,b){var c={};c[a.toLowerCase()]=b.toLowerCase();c["Webkit"+a]="webkit"+b;c["Moz"+a]="moz"+b;return c}function hd(a){if(Le[a])return Le[a];if(!Kb[a])return a;var b=Kb[a],c;for(c in b)if(b.hasOwnProperty(c)&&c in eh)return Le[a]=b[c];return a}function $a(a,
b){fh.set(a,b);mb(b,[a])}function gh(a,b,c){var d=a.type||"unknown-event";a.currentTarget=c;mj(d,b,void 0,a);a.currentTarget=null}function Xg(a,b){b=0!==(b&4);for(var c=0;c<a.length;c++){var d=a[c],e=d.event;d=d.listeners;a:{var f=void 0;if(b)for(var g=d.length-1;0<=g;g--){var h=d[g],k=h.instance,n=h.currentTarget;h=h.listener;if(k!==f&&e.isPropagationStopped())break a;gh(e,h,n);f=k}else for(g=0;g<d.length;g++){h=d[g];k=h.instance;n=h.currentTarget;h=h.listener;if(k!==f&&e.isPropagationStopped())break a;
gh(e,h,n);f=k}}}if(Tc)throw a=ue,Tc=!1,ue=null,a;}function B(a,b){var c=b[Me];void 0===c&&(c=b[Me]=new Set);var d=a+"__bubble";c.has(d)||(hh(b,a,2,!1),c.add(d))}function Ne(a,b,c){var d=0;b&&(d|=4);hh(c,a,d,b)}function sc(a){if(!a[id]){a[id]=!0;cg.forEach(function(b){"selectionchange"!==b&&(Uj.has(b)||Ne(b,!1,a),Ne(b,!0,a))});var b=9===a.nodeType?a:a.ownerDocument;null===b||b[id]||(b[id]=!0,Ne("selectionchange",!1,b))}}function hh(a,b,c,d,e){switch(Lg(b)){case 1:e=zj;break;case 4:e=Aj;break;default:e=
Be}c=e.bind(null,b,c,a);e=void 0;!Oe||"touchstart"!==b&&"touchmove"!==b&&"wheel"!==b||(e=!0);d?void 0!==e?a.addEventListener(b,c,{capture:!0,passive:e}):a.addEventListener(b,c,!0):void 0!==e?a.addEventListener(b,c,{passive:e}):a.addEventListener(b,c,!1)}function Ce(a,b,c,d,e){var f=d;if(0===(b&1)&&0===(b&2)&&null!==d)a:for(;;){if(null===d)return;var g=d.tag;if(3===g||4===g){var h=d.stateNode.containerInfo;if(h===e||8===h.nodeType&&h.parentNode===e)break;if(4===g)for(g=d.return;null!==g;){var k=g.tag;
if(3===k||4===k)if(k=g.stateNode.containerInfo,k===e||8===k.nodeType&&k.parentNode===e)return;g=g.return}for(;null!==h;){g=ob(h);if(null===g)return;k=g.tag;if(5===k||6===k){d=f=g;continue a}h=h.parentNode}}d=d.return}wg(function(){var d=f,e=re(c),g=[];a:{var h=fh.get(a);if(void 0!==h){var k=He,m=a;switch(a){case "keypress":if(0===cd(c))break a;case "keydown":case "keyup":k=Vj;break;case "focusin":m="focus";k=Pe;break;case "focusout":m="blur";k=Pe;break;case "beforeblur":case "afterblur":k=Pe;break;
case "click":if(2===c.button)break a;case "auxclick":case "dblclick":case "mousedown":case "mousemove":case "mouseup":case "mouseout":case "mouseover":case "contextmenu":k=ih;break;case "drag":case "dragend":case "dragenter":case "dragexit":case "dragleave":case "dragover":case "dragstart":case "drop":k=Wj;break;case "touchcancel":case "touchend":case "touchmove":case "touchstart":k=Xj;break;case jh:case kh:case lh:k=Yj;break;case mh:k=Zj;break;case "scroll":k=ak;break;case "wheel":k=bk;break;case "copy":case "cut":case "paste":k=
ck;break;case "gotpointercapture":case "lostpointercapture":case "pointercancel":case "pointerdown":case "pointermove":case "pointerout":case "pointerover":case "pointerup":k=nh}var l=0!==(b&4),p=!l&&"scroll"===a,w=l?null!==h?h+"Capture":null:h;l=[];for(var A=d,t;null!==A;){t=A;var M=t.stateNode;5===t.tag&&null!==M&&(t=M,null!==w&&(M=fc(A,w),null!=M&&l.push(tc(A,M,t))));if(p)break;A=A.return}0<l.length&&(h=new k(h,m,null,c,e),g.push({event:h,listeners:l}))}}if(0===(b&7)){a:{h="mouseover"===a||"pointerover"===
a;k="mouseout"===a||"pointerout"===a;if(h&&c!==ze&&(m=c.relatedTarget||c.fromElement)&&(ob(m)||m[Ja]))break a;if(k||h){h=e.window===e?e:(h=e.ownerDocument)?h.defaultView||h.parentWindow:window;if(k){if(m=c.relatedTarget||c.toElement,k=d,m=m?ob(m):null,null!==m&&(p=nb(m),m!==p||5!==m.tag&&6!==m.tag))m=null}else k=null,m=d;if(k!==m){l=ih;M="onMouseLeave";w="onMouseEnter";A="mouse";if("pointerout"===a||"pointerover"===a)l=nh,M="onPointerLeave",w="onPointerEnter",A="pointer";p=null==k?h:Ib(k);t=null==
m?h:Ib(m);h=new l(M,A+"leave",k,c,e);h.target=p;h.relatedTarget=t;M=null;ob(e)===d&&(l=new l(w,A+"enter",m,c,e),l.target=t,l.relatedTarget=p,M=l);p=M;if(k&&m)b:{l=k;w=m;A=0;for(t=l;t;t=Lb(t))A++;t=0;for(M=w;M;M=Lb(M))t++;for(;0<A-t;)l=Lb(l),A--;for(;0<t-A;)w=Lb(w),t--;for(;A--;){if(l===w||null!==w&&l===w.alternate)break b;l=Lb(l);w=Lb(w)}l=null}else l=null;null!==k&&oh(g,h,k,l,!1);null!==m&&null!==p&&oh(g,p,m,l,!0)}}}a:{h=d?Ib(d):window;k=h.nodeName&&h.nodeName.toLowerCase();if("select"===k||"input"===
k&&"file"===h.type)var ma=Nj;else if(Vg(h))if(ph)ma=Rj;else{ma=Pj;var va=Oj}else(k=h.nodeName)&&"input"===k.toLowerCase()&&("checkbox"===h.type||"radio"===h.type)&&(ma=Qj);if(ma&&(ma=ma(a,d))){Wg(g,ma,c,e);break a}va&&va(a,h,d);"focusout"===a&&(va=h._wrapperState)&&va.controlled&&"number"===h.type&&me(h,"number",h.value)}va=d?Ib(d):window;switch(a){case "focusin":if(Vg(va)||"true"===va.contentEditable)Jb=va,Ke=d,rc=null;break;case "focusout":rc=Ke=Jb=null;break;case "mousedown":Je=!0;break;case "contextmenu":case "mouseup":case "dragend":Je=
!1;dh(g,c,e);break;case "selectionchange":if(dk)break;case "keydown":case "keyup":dh(g,c,e)}var ab;if(Ge)b:{switch(a){case "compositionstart":var da="onCompositionStart";break b;case "compositionend":da="onCompositionEnd";break b;case "compositionupdate":da="onCompositionUpdate";break b}da=void 0}else Hb?Qg(a,c)&&(da="onCompositionEnd"):"keydown"===a&&229===c.keyCode&&(da="onCompositionStart");da&&(Ug&&"ko"!==c.locale&&(Hb||"onCompositionStart"!==da?"onCompositionEnd"===da&&Hb&&(ab=Og()):(Za=e,Ee=
"value"in Za?Za.value:Za.textContent,Hb=!0)),va=ed(d,da),0<va.length&&(da=new qh(da,a,null,c,e),g.push({event:da,listeners:va}),ab?da.data=ab:(ab=Rg(c),null!==ab&&(da.data=ab))));if(ab=ek?Ij(a,c):Jj(a,c))d=ed(d,"onBeforeInput"),0<d.length&&(e=new fk("onBeforeInput","beforeinput",null,c,e),g.push({event:e,listeners:d}),e.data=ab)}Xg(g,b)})}function tc(a,b,c){return{instance:a,listener:b,currentTarget:c}}function ed(a,b){for(var c=b+"Capture",d=[];null!==a;){var e=a,f=e.stateNode;5===e.tag&&null!==
f&&(e=f,f=fc(a,c),null!=f&&d.unshift(tc(a,f,e)),f=fc(a,b),null!=f&&d.push(tc(a,f,e)));a=a.return}return d}function Lb(a){if(null===a)return null;do a=a.return;while(a&&5!==a.tag);return a?a:null}function oh(a,b,c,d,e){for(var f=b._reactName,g=[];null!==c&&c!==d;){var h=c,k=h.alternate,n=h.stateNode;if(null!==k&&k===d)break;5===h.tag&&null!==n&&(h=n,e?(k=fc(c,f),null!=k&&g.unshift(tc(c,k,h))):e||(k=fc(c,f),null!=k&&g.push(tc(c,k,h))));c=c.return}0!==g.length&&a.push({event:b,listeners:g})}function rh(a){return("string"===
typeof a?a:""+a).replace(gk,"\n").replace(hk,"")}function jd(a,b,c,d){b=rh(b);if(rh(a)!==b&&c)throw Error(m(425));}function kd(){}function Qe(a,b){return"textarea"===a||"noscript"===a||"string"===typeof b.children||"number"===typeof b.children||"object"===typeof b.dangerouslySetInnerHTML&&null!==b.dangerouslySetInnerHTML&&null!=b.dangerouslySetInnerHTML.__html}function ik(a){setTimeout(function(){throw a;})}function Re(a,b){var c=b,d=0;do{var e=c.nextSibling;a.removeChild(c);if(e&&8===e.nodeType)if(c=
e.data,"/$"===c){if(0===d){a.removeChild(e);nc(b);return}d--}else"$"!==c&&"$?"!==c&&"$!"!==c||d++;c=e}while(c);nc(b)}function Ka(a){for(;null!=a;a=a.nextSibling){var b=a.nodeType;if(1===b||3===b)break;if(8===b){b=a.data;if("$"===b||"$!"===b||"$?"===b)break;if("/$"===b)return null}}return a}function sh(a){a=a.previousSibling;for(var b=0;a;){if(8===a.nodeType){var c=a.data;if("$"===c||"$!"===c||"$?"===c){if(0===b)return a;b--}else"/$"===c&&b++}a=a.previousSibling}return null}function ob(a){var b=a[Da];
if(b)return b;for(var c=a.parentNode;c;){if(b=c[Ja]||c[Da]){c=b.alternate;if(null!==b.child||null!==c&&null!==c.child)for(a=sh(a);null!==a;){if(c=a[Da])return c;a=sh(a)}return b}a=c;c=a.parentNode}return null}function ec(a){a=a[Da]||a[Ja];return!a||5!==a.tag&&6!==a.tag&&13!==a.tag&&3!==a.tag?null:a}function Ib(a){if(5===a.tag||6===a.tag)return a.stateNode;throw Error(m(33));}function Rc(a){return a[uc]||null}function bb(a){return{current:a}}function v(a,b){0>Mb||(a.current=Se[Mb],Se[Mb]=null,Mb--)}
function y(a,b,c){Mb++;Se[Mb]=a.current;a.current=b}function Nb(a,b){var c=a.type.contextTypes;if(!c)return cb;var d=a.stateNode;if(d&&d.__reactInternalMemoizedUnmaskedChildContext===b)return d.__reactInternalMemoizedMaskedChildContext;var e={},f;for(f in c)e[f]=b[f];d&&(a=a.stateNode,a.__reactInternalMemoizedUnmaskedChildContext=b,a.__reactInternalMemoizedMaskedChildContext=e);return e}function ea(a){a=a.childContextTypes;return null!==a&&void 0!==a}function th(a,b,c){if(J.current!==cb)throw Error(m(168));
y(J,b);y(S,c)}function uh(a,b,c){var d=a.stateNode;b=b.childContextTypes;if("function"!==typeof d.getChildContext)return c;d=d.getChildContext();for(var e in d)if(!(e in b))throw Error(m(108,gj(a)||"Unknown",e));return E({},c,d)}function ld(a){a=(a=a.stateNode)&&a.__reactInternalMemoizedMergedChildContext||cb;pb=J.current;y(J,a);y(S,S.current);return!0}function vh(a,b,c){var d=a.stateNode;if(!d)throw Error(m(169));c?(a=uh(a,b,pb),d.__reactInternalMemoizedMergedChildContext=a,v(S),v(J),y(J,a)):v(S);
y(S,c)}function wh(a){null===La?La=[a]:La.push(a)}function jk(a){md=!0;wh(a)}function db(){if(!Te&&null!==La){Te=!0;var a=0,b=z;try{var c=La;for(z=1;a<c.length;a++){var d=c[a];do d=d(!0);while(null!==d)}La=null;md=!1}catch(e){throw null!==La&&(La=La.slice(a+1)),xh(De,db),e;}finally{z=b,Te=!1}}return null}function qb(a,b){Ob[Pb++]=nd;Ob[Pb++]=od;od=a;nd=b}function yh(a,b,c){na[oa++]=Ma;na[oa++]=Na;na[oa++]=rb;rb=a;var d=Ma;a=Na;var e=32-ta(d)-1;d&=~(1<<e);c+=1;var f=32-ta(b)+e;if(30<f){var g=e-e%5;
f=(d&(1<<g)-1).toString(32);d>>=g;e-=g;Ma=1<<32-ta(b)+e|c<<e|d;Na=f+a}else Ma=1<<f|c<<e|d,Na=a}function Ue(a){null!==a.return&&(qb(a,1),yh(a,1,0))}function Ve(a){for(;a===od;)od=Ob[--Pb],Ob[Pb]=null,nd=Ob[--Pb],Ob[Pb]=null;for(;a===rb;)rb=na[--oa],na[oa]=null,Na=na[--oa],na[oa]=null,Ma=na[--oa],na[oa]=null}function zh(a,b){var c=pa(5,null,null,0);c.elementType="DELETED";c.stateNode=b;c.return=a;b=a.deletions;null===b?(a.deletions=[c],a.flags|=16):b.push(c)}function Ah(a,b){switch(a.tag){case 5:var c=
a.type;b=1!==b.nodeType||c.toLowerCase()!==b.nodeName.toLowerCase()?null:b;return null!==b?(a.stateNode=b,la=a,fa=Ka(b.firstChild),!0):!1;case 6:return b=""===a.pendingProps||3!==b.nodeType?null:b,null!==b?(a.stateNode=b,la=a,fa=null,!0):!1;case 13:return b=8!==b.nodeType?null:b,null!==b?(c=null!==rb?{id:Ma,overflow:Na}:null,a.memoizedState={dehydrated:b,treeContext:c,retryLane:1073741824},c=pa(18,null,null,0),c.stateNode=b,c.return=a,a.child=c,la=a,fa=null,!0):!1;default:return!1}}function We(a){return 0!==
(a.mode&1)&&0===(a.flags&128)}function Xe(a){if(D){var b=fa;if(b){var c=b;if(!Ah(a,b)){if(We(a))throw Error(m(418));b=Ka(c.nextSibling);var d=la;b&&Ah(a,b)?zh(d,c):(a.flags=a.flags&-4097|2,D=!1,la=a)}}else{if(We(a))throw Error(m(418));a.flags=a.flags&-4097|2;D=!1;la=a}}}function Bh(a){for(a=a.return;null!==a&&5!==a.tag&&3!==a.tag&&13!==a.tag;)a=a.return;la=a}function pd(a){if(a!==la)return!1;if(!D)return Bh(a),D=!0,!1;var b;(b=3!==a.tag)&&!(b=5!==a.tag)&&(b=a.type,b="head"!==b&&"body"!==b&&!Qe(a.type,
a.memoizedProps));if(b&&(b=fa)){if(We(a)){for(a=fa;a;)a=Ka(a.nextSibling);throw Error(m(418));}for(;b;)zh(a,b),b=Ka(b.nextSibling)}Bh(a);if(13===a.tag){a=a.memoizedState;a=null!==a?a.dehydrated:null;if(!a)throw Error(m(317));a:{a=a.nextSibling;for(b=0;a;){if(8===a.nodeType){var c=a.data;if("/$"===c){if(0===b){fa=Ka(a.nextSibling);break a}b--}else"$"!==c&&"$!"!==c&&"$?"!==c||b++}a=a.nextSibling}fa=null}}else fa=la?Ka(a.stateNode.nextSibling):null;return!0}function Qb(){fa=la=null;D=!1}function Ye(a){null===
wa?wa=[a]:wa.push(a)}function vc(a,b,c){a=c.ref;if(null!==a&&"function"!==typeof a&&"object"!==typeof a){if(c._owner){c=c._owner;if(c){if(1!==c.tag)throw Error(m(309));var d=c.stateNode}if(!d)throw Error(m(147,a));var e=d,f=""+a;if(null!==b&&null!==b.ref&&"function"===typeof b.ref&&b.ref._stringRef===f)return b.ref;b=function(a){var b=e.refs;null===a?delete b[f]:b[f]=a};b._stringRef=f;return b}if("string"!==typeof a)throw Error(m(284));if(!c._owner)throw Error(m(290,a));}return a}function qd(a,b){a=
Object.prototype.toString.call(b);throw Error(m(31,"[object Object]"===a?"object with keys {"+Object.keys(b).join(", ")+"}":a));}function Ch(a){var b=a._init;return b(a._payload)}function Dh(a){function b(b,c){if(a){var d=b.deletions;null===d?(b.deletions=[c],b.flags|=16):d.push(c)}}function c(c,d){if(!a)return null;for(;null!==d;)b(c,d),d=d.sibling;return null}function d(a,b){for(a=new Map;null!==b;)null!==b.key?a.set(b.key,b):a.set(b.index,b),b=b.sibling;return a}function e(a,b){a=eb(a,b);a.index=
0;a.sibling=null;return a}function f(b,c,d){b.index=d;if(!a)return b.flags|=1048576,c;d=b.alternate;if(null!==d)return d=d.index,d<c?(b.flags|=2,c):d;b.flags|=2;return c}function g(b){a&&null===b.alternate&&(b.flags|=2);return b}function h(a,b,c,d){if(null===b||6!==b.tag)return b=Ze(c,a.mode,d),b.return=a,b;b=e(b,c);b.return=a;return b}function k(a,b,c,d){var f=c.type;if(f===Bb)return l(a,b,c.props.children,d,c.key);if(null!==b&&(b.elementType===f||"object"===typeof f&&null!==f&&f.$$typeof===Ta&&
Ch(f)===b.type))return d=e(b,c.props),d.ref=vc(a,b,c),d.return=a,d;d=rd(c.type,c.key,c.props,null,a.mode,d);d.ref=vc(a,b,c);d.return=a;return d}function n(a,b,c,d){if(null===b||4!==b.tag||b.stateNode.containerInfo!==c.containerInfo||b.stateNode.implementation!==c.implementation)return b=$e(c,a.mode,d),b.return=a,b;b=e(b,c.children||[]);b.return=a;return b}function l(a,b,c,d,f){if(null===b||7!==b.tag)return b=sb(c,a.mode,d,f),b.return=a,b;b=e(b,c);b.return=a;return b}function u(a,b,c){if("string"===
typeof b&&""!==b||"number"===typeof b)return b=Ze(""+b,a.mode,c),b.return=a,b;if("object"===typeof b&&null!==b){switch(b.$$typeof){case sd:return c=rd(b.type,b.key,b.props,null,a.mode,c),c.ref=vc(a,null,b),c.return=a,c;case Cb:return b=$e(b,a.mode,c),b.return=a,b;case Ta:var d=b._init;return u(a,d(b._payload),c)}if(cc(b)||ac(b))return b=sb(b,a.mode,c,null),b.return=a,b;qd(a,b)}return null}function r(a,b,c,d){var e=null!==b?b.key:null;if("string"===typeof c&&""!==c||"number"===typeof c)return null!==
e?null:h(a,b,""+c,d);if("object"===typeof c&&null!==c){switch(c.$$typeof){case sd:return c.key===e?k(a,b,c,d):null;case Cb:return c.key===e?n(a,b,c,d):null;case Ta:return e=c._init,r(a,b,e(c._payload),d)}if(cc(c)||ac(c))return null!==e?null:l(a,b,c,d,null);qd(a,c)}return null}function p(a,b,c,d,e){if("string"===typeof d&&""!==d||"number"===typeof d)return a=a.get(c)||null,h(b,a,""+d,e);if("object"===typeof d&&null!==d){switch(d.$$typeof){case sd:return a=a.get(null===d.key?c:d.key)||null,k(b,a,d,
e);case Cb:return a=a.get(null===d.key?c:d.key)||null,n(b,a,d,e);case Ta:var f=d._init;return p(a,b,c,f(d._payload),e)}if(cc(d)||ac(d))return a=a.get(c)||null,l(b,a,d,e,null);qd(b,d)}return null}function x(e,g,h,k){for(var n=null,m=null,l=g,t=g=0,q=null;null!==l&&t<h.length;t++){l.index>t?(q=l,l=null):q=l.sibling;var A=r(e,l,h[t],k);if(null===A){null===l&&(l=q);break}a&&l&&null===A.alternate&&b(e,l);g=f(A,g,t);null===m?n=A:m.sibling=A;m=A;l=q}if(t===h.length)return c(e,l),D&&qb(e,t),n;if(null===l){for(;t<
h.length;t++)l=u(e,h[t],k),null!==l&&(g=f(l,g,t),null===m?n=l:m.sibling=l,m=l);D&&qb(e,t);return n}for(l=d(e,l);t<h.length;t++)q=p(l,e,t,h[t],k),null!==q&&(a&&null!==q.alternate&&l.delete(null===q.key?t:q.key),g=f(q,g,t),null===m?n=q:m.sibling=q,m=q);a&&l.forEach(function(a){return b(e,a)});D&&qb(e,t);return n}function I(e,g,h,k){var n=ac(h);if("function"!==typeof n)throw Error(m(150));h=n.call(h);if(null==h)throw Error(m(151));for(var l=n=null,q=g,t=g=0,A=null,w=h.next();null!==q&&!w.done;t++,w=
h.next()){q.index>t?(A=q,q=null):A=q.sibling;var x=r(e,q,w.value,k);if(null===x){null===q&&(q=A);break}a&&q&&null===x.alternate&&b(e,q);g=f(x,g,t);null===l?n=x:l.sibling=x;l=x;q=A}if(w.done)return c(e,q),D&&qb(e,t),n;if(null===q){for(;!w.done;t++,w=h.next())w=u(e,w.value,k),null!==w&&(g=f(w,g,t),null===l?n=w:l.sibling=w,l=w);D&&qb(e,t);return n}for(q=d(e,q);!w.done;t++,w=h.next())w=p(q,e,t,w.value,k),null!==w&&(a&&null!==w.alternate&&q.delete(null===w.key?t:w.key),g=f(w,g,t),null===l?n=w:l.sibling=
w,l=w);a&&q.forEach(function(a){return b(e,a)});D&&qb(e,t);return n}function v(a,d,f,h){"object"===typeof f&&null!==f&&f.type===Bb&&null===f.key&&(f=f.props.children);if("object"===typeof f&&null!==f){switch(f.$$typeof){case sd:a:{for(var k=f.key,n=d;null!==n;){if(n.key===k){k=f.type;if(k===Bb){if(7===n.tag){c(a,n.sibling);d=e(n,f.props.children);d.return=a;a=d;break a}}else if(n.elementType===k||"object"===typeof k&&null!==k&&k.$$typeof===Ta&&Ch(k)===n.type){c(a,n.sibling);d=e(n,f.props);d.ref=vc(a,
n,f);d.return=a;a=d;break a}c(a,n);break}else b(a,n);n=n.sibling}f.type===Bb?(d=sb(f.props.children,a.mode,h,f.key),d.return=a,a=d):(h=rd(f.type,f.key,f.props,null,a.mode,h),h.ref=vc(a,d,f),h.return=a,a=h)}return g(a);case Cb:a:{for(n=f.key;null!==d;){if(d.key===n)if(4===d.tag&&d.stateNode.containerInfo===f.containerInfo&&d.stateNode.implementation===f.implementation){c(a,d.sibling);d=e(d,f.children||[]);d.return=a;a=d;break a}else{c(a,d);break}else b(a,d);d=d.sibling}d=$e(f,a.mode,h);d.return=a;
a=d}return g(a);case Ta:return n=f._init,v(a,d,n(f._payload),h)}if(cc(f))return x(a,d,f,h);if(ac(f))return I(a,d,f,h);qd(a,f)}return"string"===typeof f&&""!==f||"number"===typeof f?(f=""+f,null!==d&&6===d.tag?(c(a,d.sibling),d=e(d,f),d.return=a,a=d):(c(a,d),d=Ze(f,a.mode,h),d.return=a,a=d),g(a)):c(a,d)}return v}function af(){bf=Rb=td=null}function cf(a,b){b=ud.current;v(ud);a._currentValue=b}function df(a,b,c){for(;null!==a;){var d=a.alternate;(a.childLanes&b)!==b?(a.childLanes|=b,null!==d&&(d.childLanes|=
b)):null!==d&&(d.childLanes&b)!==b&&(d.childLanes|=b);if(a===c)break;a=a.return}}function Sb(a,b){td=a;bf=Rb=null;a=a.dependencies;null!==a&&null!==a.firstContext&&(0!==(a.lanes&b)&&(ha=!0),a.firstContext=null)}function qa(a){var b=a._currentValue;if(bf!==a)if(a={context:a,memoizedValue:b,next:null},null===Rb){if(null===td)throw Error(m(308));Rb=a;td.dependencies={lanes:0,firstContext:a}}else Rb=Rb.next=a;return b}function ef(a){null===tb?tb=[a]:tb.push(a)}function Eh(a,b,c,d){var e=b.interleaved;
null===e?(c.next=c,ef(b)):(c.next=e.next,e.next=c);b.interleaved=c;return Oa(a,d)}function Oa(a,b){a.lanes|=b;var c=a.alternate;null!==c&&(c.lanes|=b);c=a;for(a=a.return;null!==a;)a.childLanes|=b,c=a.alternate,null!==c&&(c.childLanes|=b),c=a,a=a.return;return 3===c.tag?c.stateNode:null}function ff(a){a.updateQueue={baseState:a.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function Fh(a,b){a=a.updateQueue;b.updateQueue===a&&(b.updateQueue=
{baseState:a.baseState,firstBaseUpdate:a.firstBaseUpdate,lastBaseUpdate:a.lastBaseUpdate,shared:a.shared,effects:a.effects})}function Pa(a,b){return{eventTime:a,lane:b,tag:0,payload:null,callback:null,next:null}}function fb(a,b,c){var d=a.updateQueue;if(null===d)return null;d=d.shared;if(0!==(p&2)){var e=d.pending;null===e?b.next=b:(b.next=e.next,e.next=b);d.pending=b;return kk(a,c)}e=d.interleaved;null===e?(b.next=b,ef(d)):(b.next=e.next,e.next=b);d.interleaved=b;return Oa(a,c)}function vd(a,b,c){b=
b.updateQueue;if(null!==b&&(b=b.shared,0!==(c&4194240))){var d=b.lanes;d&=a.pendingLanes;c|=d;b.lanes=c;xe(a,c)}}function Gh(a,b){var c=a.updateQueue,d=a.alternate;if(null!==d&&(d=d.updateQueue,c===d)){var e=null,f=null;c=c.firstBaseUpdate;if(null!==c){do{var g={eventTime:c.eventTime,lane:c.lane,tag:c.tag,payload:c.payload,callback:c.callback,next:null};null===f?e=f=g:f=f.next=g;c=c.next}while(null!==c);null===f?e=f=b:f=f.next=b}else e=f=b;c={baseState:d.baseState,firstBaseUpdate:e,lastBaseUpdate:f,
shared:d.shared,effects:d.effects};a.updateQueue=c;return}a=c.lastBaseUpdate;null===a?c.firstBaseUpdate=b:a.next=b;c.lastBaseUpdate=b}function wd(a,b,c,d){var e=a.updateQueue;gb=!1;var f=e.firstBaseUpdate,g=e.lastBaseUpdate,h=e.shared.pending;if(null!==h){e.shared.pending=null;var k=h,n=k.next;k.next=null;null===g?f=n:g.next=n;g=k;var l=a.alternate;null!==l&&(l=l.updateQueue,h=l.lastBaseUpdate,h!==g&&(null===h?l.firstBaseUpdate=n:h.next=n,l.lastBaseUpdate=k))}if(null!==f){var m=e.baseState;g=0;l=
n=k=null;h=f;do{var r=h.lane,p=h.eventTime;if((d&r)===r){null!==l&&(l=l.next={eventTime:p,lane:0,tag:h.tag,payload:h.payload,callback:h.callback,next:null});a:{var x=a,v=h;r=b;p=c;switch(v.tag){case 1:x=v.payload;if("function"===typeof x){m=x.call(p,m,r);break a}m=x;break a;case 3:x.flags=x.flags&-65537|128;case 0:x=v.payload;r="function"===typeof x?x.call(p,m,r):x;if(null===r||void 0===r)break a;m=E({},m,r);break a;case 2:gb=!0}}null!==h.callback&&0!==h.lane&&(a.flags|=64,r=e.effects,null===r?e.effects=
[h]:r.push(h))}else p={eventTime:p,lane:r,tag:h.tag,payload:h.payload,callback:h.callback,next:null},null===l?(n=l=p,k=m):l=l.next=p,g|=r;h=h.next;if(null===h)if(h=e.shared.pending,null===h)break;else r=h,h=r.next,r.next=null,e.lastBaseUpdate=r,e.shared.pending=null}while(1);null===l&&(k=m);e.baseState=k;e.firstBaseUpdate=n;e.lastBaseUpdate=l;b=e.shared.interleaved;if(null!==b){e=b;do g|=e.lane,e=e.next;while(e!==b)}else null===f&&(e.shared.lanes=0);ra|=g;a.lanes=g;a.memoizedState=m}}function Hh(a,
b,c){a=b.effects;b.effects=null;if(null!==a)for(b=0;b<a.length;b++){var d=a[b],e=d.callback;if(null!==e){d.callback=null;d=c;if("function"!==typeof e)throw Error(m(191,e));e.call(d)}}}function ub(a){if(a===wc)throw Error(m(174));return a}function gf(a,b){y(xc,b);y(yc,a);y(Ea,wc);a=b.nodeType;switch(a){case 9:case 11:b=(b=b.documentElement)?b.namespaceURI:oe(null,"");break;default:a=8===a?b.parentNode:b,b=a.namespaceURI||null,a=a.tagName,b=oe(b,a)}v(Ea);y(Ea,b)}function Tb(a){v(Ea);v(yc);v(xc)}function Ih(a){ub(xc.current);
var b=ub(Ea.current);var c=oe(b,a.type);b!==c&&(y(yc,a),y(Ea,c))}function hf(a){yc.current===a&&(v(Ea),v(yc))}function xd(a){for(var b=a;null!==b;){if(13===b.tag){var c=b.memoizedState;if(null!==c&&(c=c.dehydrated,null===c||"$?"===c.data||"$!"===c.data))return b}else if(19===b.tag&&void 0!==b.memoizedProps.revealOrder){if(0!==(b.flags&128))return b}else if(null!==b.child){b.child.return=b;b=b.child;continue}if(b===a)break;for(;null===b.sibling;){if(null===b.return||b.return===a)return null;b=b.return}b.sibling.return=
b.return;b=b.sibling}return null}function jf(){for(var a=0;a<kf.length;a++)kf[a]._workInProgressVersionPrimary=null;kf.length=0}function V(){throw Error(m(321));}function lf(a,b){if(null===b)return!1;for(var c=0;c<b.length&&c<a.length;c++)if(!ua(a[c],b[c]))return!1;return!0}function mf(a,b,c,d,e,f){vb=f;C=b;b.memoizedState=null;b.updateQueue=null;b.lanes=0;yd.current=null===a||null===a.memoizedState?lk:mk;a=c(d,e);if(zc){f=0;do{zc=!1;Ac=0;if(25<=f)throw Error(m(301));f+=1;N=K=null;b.updateQueue=null;
yd.current=nk;a=c(d,e)}while(zc)}yd.current=zd;b=null!==K&&null!==K.next;vb=0;N=K=C=null;Ad=!1;if(b)throw Error(m(300));return a}function nf(){var a=0!==Ac;Ac=0;return a}function Fa(){var a={memoizedState:null,baseState:null,baseQueue:null,queue:null,next:null};null===N?C.memoizedState=N=a:N=N.next=a;return N}function sa(){if(null===K){var a=C.alternate;a=null!==a?a.memoizedState:null}else a=K.next;var b=null===N?C.memoizedState:N.next;if(null!==b)N=b,K=a;else{if(null===a)throw Error(m(310));K=a;
a={memoizedState:K.memoizedState,baseState:K.baseState,baseQueue:K.baseQueue,queue:K.queue,next:null};null===N?C.memoizedState=N=a:N=N.next=a}return N}function Bc(a,b){return"function"===typeof b?b(a):b}function of(a,b,c){b=sa();c=b.queue;if(null===c)throw Error(m(311));c.lastRenderedReducer=a;var d=K,e=d.baseQueue,f=c.pending;if(null!==f){if(null!==e){var g=e.next;e.next=f.next;f.next=g}d.baseQueue=e=f;c.pending=null}if(null!==e){f=e.next;d=d.baseState;var h=g=null,k=null,n=f;do{var l=n.lane;if((vb&
l)===l)null!==k&&(k=k.next={lane:0,action:n.action,hasEagerState:n.hasEagerState,eagerState:n.eagerState,next:null}),d=n.hasEagerState?n.eagerState:a(d,n.action);else{var u={lane:l,action:n.action,hasEagerState:n.hasEagerState,eagerState:n.eagerState,next:null};null===k?(h=k=u,g=d):k=k.next=u;C.lanes|=l;ra|=l}n=n.next}while(null!==n&&n!==f);null===k?g=d:k.next=h;ua(d,b.memoizedState)||(ha=!0);b.memoizedState=d;b.baseState=g;b.baseQueue=k;c.lastRenderedState=d}a=c.interleaved;if(null!==a){e=a;do f=
e.lane,C.lanes|=f,ra|=f,e=e.next;while(e!==a)}else null===e&&(c.lanes=0);return[b.memoizedState,c.dispatch]}function pf(a,b,c){b=sa();c=b.queue;if(null===c)throw Error(m(311));c.lastRenderedReducer=a;var d=c.dispatch,e=c.pending,f=b.memoizedState;if(null!==e){c.pending=null;var g=e=e.next;do f=a(f,g.action),g=g.next;while(g!==e);ua(f,b.memoizedState)||(ha=!0);b.memoizedState=f;null===b.baseQueue&&(b.baseState=f);c.lastRenderedState=f}return[f,d]}function Jh(a,b,c){}function Kh(a,b,c){c=C;var d=sa(),
e=b(),f=!ua(d.memoizedState,e);f&&(d.memoizedState=e,ha=!0);d=d.queue;qf(Lh.bind(null,c,d,a),[a]);if(d.getSnapshot!==b||f||null!==N&&N.memoizedState.tag&1){c.flags|=2048;Cc(9,Mh.bind(null,c,d,e,b),void 0,null);if(null===O)throw Error(m(349));0!==(vb&30)||Nh(c,b,e)}return e}function Nh(a,b,c){a.flags|=16384;a={getSnapshot:b,value:c};b=C.updateQueue;null===b?(b={lastEffect:null,stores:null},C.updateQueue=b,b.stores=[a]):(c=b.stores,null===c?b.stores=[a]:c.push(a))}function Mh(a,b,c,d){b.value=c;b.getSnapshot=
d;Oh(b)&&Ph(a)}function Lh(a,b,c){return c(function(){Oh(b)&&Ph(a)})}function Oh(a){var b=a.getSnapshot;a=a.value;try{var c=b();return!ua(a,c)}catch(d){return!0}}function Ph(a){var b=Oa(a,1);null!==b&&xa(b,a,1,-1)}function Qh(a){var b=Fa();"function"===typeof a&&(a=a());b.memoizedState=b.baseState=a;a={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:Bc,lastRenderedState:a};b.queue=a;a=a.dispatch=ok.bind(null,C,a);return[b.memoizedState,a]}function Cc(a,b,c,d){a={tag:a,create:b,
destroy:c,deps:d,next:null};b=C.updateQueue;null===b?(b={lastEffect:null,stores:null},C.updateQueue=b,b.lastEffect=a.next=a):(c=b.lastEffect,null===c?b.lastEffect=a.next=a:(d=c.next,c.next=a,a.next=d,b.lastEffect=a));return a}function Rh(a){return sa().memoizedState}function Bd(a,b,c,d){var e=Fa();C.flags|=a;e.memoizedState=Cc(1|b,c,void 0,void 0===d?null:d)}function Cd(a,b,c,d){var e=sa();d=void 0===d?null:d;var f=void 0;if(null!==K){var g=K.memoizedState;f=g.destroy;if(null!==d&&lf(d,g.deps)){e.memoizedState=
Cc(b,c,f,d);return}}C.flags|=a;e.memoizedState=Cc(1|b,c,f,d)}function Sh(a,b){return Bd(8390656,8,a,b)}function qf(a,b){return Cd(2048,8,a,b)}function Th(a,b){return Cd(4,2,a,b)}function Uh(a,b){return Cd(4,4,a,b)}function Vh(a,b){if("function"===typeof b)return a=a(),b(a),function(){b(null)};if(null!==b&&void 0!==b)return a=a(),b.current=a,function(){b.current=null}}function Wh(a,b,c){c=null!==c&&void 0!==c?c.concat([a]):null;return Cd(4,4,Vh.bind(null,b,a),c)}function rf(a,b){}function Xh(a,b){var c=
sa();b=void 0===b?null:b;var d=c.memoizedState;if(null!==d&&null!==b&&lf(b,d[1]))return d[0];c.memoizedState=[a,b];return a}function Yh(a,b){var c=sa();b=void 0===b?null:b;var d=c.memoizedState;if(null!==d&&null!==b&&lf(b,d[1]))return d[0];a=a();c.memoizedState=[a,b];return a}function Zh(a,b,c){if(0===(vb&21))return a.baseState&&(a.baseState=!1,ha=!0),a.memoizedState=c;ua(c,b)||(c=Dg(),C.lanes|=c,ra|=c,a.baseState=!0);return b}function pk(a,b,c){c=z;z=0!==c&&4>c?c:4;a(!0);var d=sf.transition;sf.transition=
{};try{a(!1),b()}finally{z=c,sf.transition=d}}function $h(){return sa().memoizedState}function qk(a,b,c){var d=hb(a);c={lane:d,action:c,hasEagerState:!1,eagerState:null,next:null};if(ai(a))bi(b,c);else if(c=Eh(a,b,c,d),null!==c){var e=Z();xa(c,a,d,e);ci(c,b,d)}}function ok(a,b,c){var d=hb(a),e={lane:d,action:c,hasEagerState:!1,eagerState:null,next:null};if(ai(a))bi(b,e);else{var f=a.alternate;if(0===a.lanes&&(null===f||0===f.lanes)&&(f=b.lastRenderedReducer,null!==f))try{var g=b.lastRenderedState,
h=f(g,c);e.hasEagerState=!0;e.eagerState=h;if(ua(h,g)){var k=b.interleaved;null===k?(e.next=e,ef(b)):(e.next=k.next,k.next=e);b.interleaved=e;return}}catch(n){}finally{}c=Eh(a,b,e,d);null!==c&&(e=Z(),xa(c,a,d,e),ci(c,b,d))}}function ai(a){var b=a.alternate;return a===C||null!==b&&b===C}function bi(a,b){zc=Ad=!0;var c=a.pending;null===c?b.next=b:(b.next=c.next,c.next=b);a.pending=b}function ci(a,b,c){if(0!==(c&4194240)){var d=b.lanes;d&=a.pendingLanes;c|=d;b.lanes=c;xe(a,c)}}function ya(a,b){if(a&&
a.defaultProps){b=E({},b);a=a.defaultProps;for(var c in a)void 0===b[c]&&(b[c]=a[c]);return b}return b}function tf(a,b,c,d){b=a.memoizedState;c=c(d,b);c=null===c||void 0===c?b:E({},b,c);a.memoizedState=c;0===a.lanes&&(a.updateQueue.baseState=c)}function di(a,b,c,d,e,f,g){a=a.stateNode;return"function"===typeof a.shouldComponentUpdate?a.shouldComponentUpdate(d,f,g):b.prototype&&b.prototype.isPureReactComponent?!qc(c,d)||!qc(e,f):!0}function ei(a,b,c){var d=!1,e=cb;var f=b.contextType;"object"===typeof f&&
null!==f?f=qa(f):(e=ea(b)?pb:J.current,d=b.contextTypes,f=(d=null!==d&&void 0!==d)?Nb(a,e):cb);b=new b(c,f);a.memoizedState=null!==b.state&&void 0!==b.state?b.state:null;b.updater=Dd;a.stateNode=b;b._reactInternals=a;d&&(a=a.stateNode,a.__reactInternalMemoizedUnmaskedChildContext=e,a.__reactInternalMemoizedMaskedChildContext=f);return b}function fi(a,b,c,d){a=b.state;"function"===typeof b.componentWillReceiveProps&&b.componentWillReceiveProps(c,d);"function"===typeof b.UNSAFE_componentWillReceiveProps&&
b.UNSAFE_componentWillReceiveProps(c,d);b.state!==a&&Dd.enqueueReplaceState(b,b.state,null)}function uf(a,b,c,d){var e=a.stateNode;e.props=c;e.state=a.memoizedState;e.refs={};ff(a);var f=b.contextType;"object"===typeof f&&null!==f?e.context=qa(f):(f=ea(b)?pb:J.current,e.context=Nb(a,f));e.state=a.memoizedState;f=b.getDerivedStateFromProps;"function"===typeof f&&(tf(a,b,f,c),e.state=a.memoizedState);"function"===typeof b.getDerivedStateFromProps||"function"===typeof e.getSnapshotBeforeUpdate||"function"!==
typeof e.UNSAFE_componentWillMount&&"function"!==typeof e.componentWillMount||(b=e.state,"function"===typeof e.componentWillMount&&e.componentWillMount(),"function"===typeof e.UNSAFE_componentWillMount&&e.UNSAFE_componentWillMount(),b!==e.state&&Dd.enqueueReplaceState(e,e.state,null),wd(a,c,e,d),e.state=a.memoizedState);"function"===typeof e.componentDidMount&&(a.flags|=4194308)}function Ub(a,b){try{var c="",d=b;do c+=fj(d),d=d.return;while(d);var e=c}catch(f){e="\nError generating stack: "+f.message+
"\n"+f.stack}return{value:a,source:b,stack:e,digest:null}}function vf(a,b,c){return{value:a,source:null,stack:null!=c?c:null,digest:null!=b?b:null}}function wf(a,b){try{console.error(b.value)}catch(c){setTimeout(function(){throw c;})}}function gi(a,b,c){c=Pa(-1,c);c.tag=3;c.payload={element:null};var d=b.value;c.callback=function(){Ed||(Ed=!0,xf=d);wf(a,b)};return c}function hi(a,b,c){c=Pa(-1,c);c.tag=3;var d=a.type.getDerivedStateFromError;if("function"===typeof d){var e=b.value;c.payload=function(){return d(e)};
c.callback=function(){wf(a,b)}}var f=a.stateNode;null!==f&&"function"===typeof f.componentDidCatch&&(c.callback=function(){wf(a,b);"function"!==typeof d&&(null===ib?ib=new Set([this]):ib.add(this));var c=b.stack;this.componentDidCatch(b.value,{componentStack:null!==c?c:""})});return c}function ii(a,b,c){var d=a.pingCache;if(null===d){d=a.pingCache=new rk;var e=new Set;d.set(b,e)}else e=d.get(b),void 0===e&&(e=new Set,d.set(b,e));e.has(c)||(e.add(c),a=sk.bind(null,a,b,c),b.then(a,a))}function ji(a){do{var b;
if(b=13===a.tag)b=a.memoizedState,b=null!==b?null!==b.dehydrated?!0:!1:!0;if(b)return a;a=a.return}while(null!==a);return null}function ki(a,b,c,d,e){if(0===(a.mode&1))return a===b?a.flags|=65536:(a.flags|=128,c.flags|=131072,c.flags&=-52805,1===c.tag&&(null===c.alternate?c.tag=17:(b=Pa(-1,1),b.tag=2,fb(c,b,1))),c.lanes|=1),a;a.flags|=65536;a.lanes=e;return a}function aa(a,b,c,d){b.child=null===a?li(b,null,c,d):Vb(b,a.child,c,d)}function mi(a,b,c,d,e){c=c.render;var f=b.ref;Sb(b,e);d=mf(a,b,c,d,f,
e);c=nf();if(null!==a&&!ha)return b.updateQueue=a.updateQueue,b.flags&=-2053,a.lanes&=~e,Qa(a,b,e);D&&c&&Ue(b);b.flags|=1;aa(a,b,d,e);return b.child}function ni(a,b,c,d,e){if(null===a){var f=c.type;if("function"===typeof f&&!yf(f)&&void 0===f.defaultProps&&null===c.compare&&void 0===c.defaultProps)return b.tag=15,b.type=f,oi(a,b,f,d,e);a=rd(c.type,null,d,b,b.mode,e);a.ref=b.ref;a.return=b;return b.child=a}f=a.child;if(0===(a.lanes&e)){var g=f.memoizedProps;c=c.compare;c=null!==c?c:qc;if(c(g,d)&&a.ref===
b.ref)return Qa(a,b,e)}b.flags|=1;a=eb(f,d);a.ref=b.ref;a.return=b;return b.child=a}function oi(a,b,c,d,e){if(null!==a){var f=a.memoizedProps;if(qc(f,d)&&a.ref===b.ref)if(ha=!1,b.pendingProps=d=f,0!==(a.lanes&e))0!==(a.flags&131072)&&(ha=!0);else return b.lanes=a.lanes,Qa(a,b,e)}return zf(a,b,c,d,e)}function pi(a,b,c){var d=b.pendingProps,e=d.children,f=null!==a?a.memoizedState:null;if("hidden"===d.mode)if(0===(b.mode&1))b.memoizedState={baseLanes:0,cachePool:null,transitions:null},y(Ga,ba),ba|=c;
else{if(0===(c&1073741824))return a=null!==f?f.baseLanes|c:c,b.lanes=b.childLanes=1073741824,b.memoizedState={baseLanes:a,cachePool:null,transitions:null},b.updateQueue=null,y(Ga,ba),ba|=a,null;b.memoizedState={baseLanes:0,cachePool:null,transitions:null};d=null!==f?f.baseLanes:c;y(Ga,ba);ba|=d}else null!==f?(d=f.baseLanes|c,b.memoizedState=null):d=c,y(Ga,ba),ba|=d;aa(a,b,e,c);return b.child}function qi(a,b){var c=b.ref;if(null===a&&null!==c||null!==a&&a.ref!==c)b.flags|=512,b.flags|=2097152}function zf(a,
b,c,d,e){var f=ea(c)?pb:J.current;f=Nb(b,f);Sb(b,e);c=mf(a,b,c,d,f,e);d=nf();if(null!==a&&!ha)return b.updateQueue=a.updateQueue,b.flags&=-2053,a.lanes&=~e,Qa(a,b,e);D&&d&&Ue(b);b.flags|=1;aa(a,b,c,e);return b.child}function ri(a,b,c,d,e){if(ea(c)){var f=!0;ld(b)}else f=!1;Sb(b,e);if(null===b.stateNode)Fd(a,b),ei(b,c,d),uf(b,c,d,e),d=!0;else if(null===a){var g=b.stateNode,h=b.memoizedProps;g.props=h;var k=g.context,n=c.contextType;"object"===typeof n&&null!==n?n=qa(n):(n=ea(c)?pb:J.current,n=Nb(b,
n));var l=c.getDerivedStateFromProps,m="function"===typeof l||"function"===typeof g.getSnapshotBeforeUpdate;m||"function"!==typeof g.UNSAFE_componentWillReceiveProps&&"function"!==typeof g.componentWillReceiveProps||(h!==d||k!==n)&&fi(b,g,d,n);gb=!1;var r=b.memoizedState;g.state=r;wd(b,d,g,e);k=b.memoizedState;h!==d||r!==k||S.current||gb?("function"===typeof l&&(tf(b,c,l,d),k=b.memoizedState),(h=gb||di(b,c,h,d,r,k,n))?(m||"function"!==typeof g.UNSAFE_componentWillMount&&"function"!==typeof g.componentWillMount||
("function"===typeof g.componentWillMount&&g.componentWillMount(),"function"===typeof g.UNSAFE_componentWillMount&&g.UNSAFE_componentWillMount()),"function"===typeof g.componentDidMount&&(b.flags|=4194308)):("function"===typeof g.componentDidMount&&(b.flags|=4194308),b.memoizedProps=d,b.memoizedState=k),g.props=d,g.state=k,g.context=n,d=h):("function"===typeof g.componentDidMount&&(b.flags|=4194308),d=!1)}else{g=b.stateNode;Fh(a,b);h=b.memoizedProps;n=b.type===b.elementType?h:ya(b.type,h);g.props=
n;m=b.pendingProps;r=g.context;k=c.contextType;"object"===typeof k&&null!==k?k=qa(k):(k=ea(c)?pb:J.current,k=Nb(b,k));var p=c.getDerivedStateFromProps;(l="function"===typeof p||"function"===typeof g.getSnapshotBeforeUpdate)||"function"!==typeof g.UNSAFE_componentWillReceiveProps&&"function"!==typeof g.componentWillReceiveProps||(h!==m||r!==k)&&fi(b,g,d,k);gb=!1;r=b.memoizedState;g.state=r;wd(b,d,g,e);var x=b.memoizedState;h!==m||r!==x||S.current||gb?("function"===typeof p&&(tf(b,c,p,d),x=b.memoizedState),
(n=gb||di(b,c,n,d,r,x,k)||!1)?(l||"function"!==typeof g.UNSAFE_componentWillUpdate&&"function"!==typeof g.componentWillUpdate||("function"===typeof g.componentWillUpdate&&g.componentWillUpdate(d,x,k),"function"===typeof g.UNSAFE_componentWillUpdate&&g.UNSAFE_componentWillUpdate(d,x,k)),"function"===typeof g.componentDidUpdate&&(b.flags|=4),"function"===typeof g.getSnapshotBeforeUpdate&&(b.flags|=1024)):("function"!==typeof g.componentDidUpdate||h===a.memoizedProps&&r===a.memoizedState||(b.flags|=
4),"function"!==typeof g.getSnapshotBeforeUpdate||h===a.memoizedProps&&r===a.memoizedState||(b.flags|=1024),b.memoizedProps=d,b.memoizedState=x),g.props=d,g.state=x,g.context=k,d=n):("function"!==typeof g.componentDidUpdate||h===a.memoizedProps&&r===a.memoizedState||(b.flags|=4),"function"!==typeof g.getSnapshotBeforeUpdate||h===a.memoizedProps&&r===a.memoizedState||(b.flags|=1024),d=!1)}return Af(a,b,c,d,f,e)}function Af(a,b,c,d,e,f){qi(a,b);var g=0!==(b.flags&128);if(!d&&!g)return e&&vh(b,c,!1),
Qa(a,b,f);d=b.stateNode;tk.current=b;var h=g&&"function"!==typeof c.getDerivedStateFromError?null:d.render();b.flags|=1;null!==a&&g?(b.child=Vb(b,a.child,null,f),b.child=Vb(b,null,h,f)):aa(a,b,h,f);b.memoizedState=d.state;e&&vh(b,c,!0);return b.child}function si(a){var b=a.stateNode;b.pendingContext?th(a,b.pendingContext,b.pendingContext!==b.context):b.context&&th(a,b.context,!1);gf(a,b.containerInfo)}function ti(a,b,c,d,e){Qb();Ye(e);b.flags|=256;aa(a,b,c,d);return b.child}function Bf(a){return{baseLanes:a,
cachePool:null,transitions:null}}function ui(a,b,c){var d=b.pendingProps,e=F.current,f=!1,g=0!==(b.flags&128),h;(h=g)||(h=null!==a&&null===a.memoizedState?!1:0!==(e&2));if(h)f=!0,b.flags&=-129;else if(null===a||null!==a.memoizedState)e|=1;y(F,e&1);if(null===a){Xe(b);a=b.memoizedState;if(null!==a&&(a=a.dehydrated,null!==a))return 0===(b.mode&1)?b.lanes=1:"$!"===a.data?b.lanes=8:b.lanes=1073741824,null;g=d.children;a=d.fallback;return f?(d=b.mode,f=b.child,g={mode:"hidden",children:g},0===(d&1)&&null!==
f?(f.childLanes=0,f.pendingProps=g):f=Gd(g,d,0,null),a=sb(a,d,c,null),f.return=b,a.return=b,f.sibling=a,b.child=f,b.child.memoizedState=Bf(c),b.memoizedState=Cf,a):Df(b,g)}e=a.memoizedState;if(null!==e&&(h=e.dehydrated,null!==h))return uk(a,b,g,d,h,e,c);if(f){f=d.fallback;g=b.mode;e=a.child;h=e.sibling;var k={mode:"hidden",children:d.children};0===(g&1)&&b.child!==e?(d=b.child,d.childLanes=0,d.pendingProps=k,b.deletions=null):(d=eb(e,k),d.subtreeFlags=e.subtreeFlags&14680064);null!==h?f=eb(h,f):(f=
sb(f,g,c,null),f.flags|=2);f.return=b;d.return=b;d.sibling=f;b.child=d;d=f;f=b.child;g=a.child.memoizedState;g=null===g?Bf(c):{baseLanes:g.baseLanes|c,cachePool:null,transitions:g.transitions};f.memoizedState=g;f.childLanes=a.childLanes&~c;b.memoizedState=Cf;return d}f=a.child;a=f.sibling;d=eb(f,{mode:"visible",children:d.children});0===(b.mode&1)&&(d.lanes=c);d.return=b;d.sibling=null;null!==a&&(c=b.deletions,null===c?(b.deletions=[a],b.flags|=16):c.push(a));b.child=d;b.memoizedState=null;return d}
function Df(a,b,c){b=Gd({mode:"visible",children:b},a.mode,0,null);b.return=a;return a.child=b}function Hd(a,b,c,d){null!==d&&Ye(d);Vb(b,a.child,null,c);a=Df(b,b.pendingProps.children);a.flags|=2;b.memoizedState=null;return a}function uk(a,b,c,d,e,f,g){if(c){if(b.flags&256)return b.flags&=-257,d=vf(Error(m(422))),Hd(a,b,g,d);if(null!==b.memoizedState)return b.child=a.child,b.flags|=128,null;f=d.fallback;e=b.mode;d=Gd({mode:"visible",children:d.children},e,0,null);f=sb(f,e,g,null);f.flags|=2;d.return=
b;f.return=b;d.sibling=f;b.child=d;0!==(b.mode&1)&&Vb(b,a.child,null,g);b.child.memoizedState=Bf(g);b.memoizedState=Cf;return f}if(0===(b.mode&1))return Hd(a,b,g,null);if("$!"===e.data){d=e.nextSibling&&e.nextSibling.dataset;if(d)var h=d.dgst;d=h;f=Error(m(419));d=vf(f,d,void 0);return Hd(a,b,g,d)}h=0!==(g&a.childLanes);if(ha||h){d=O;if(null!==d){switch(g&-g){case 4:e=2;break;case 16:e=8;break;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:e=
32;break;case 536870912:e=268435456;break;default:e=0}e=0!==(e&(d.suspendedLanes|g))?0:e;0!==e&&e!==f.retryLane&&(f.retryLane=e,Oa(a,e),xa(d,a,e,-1))}Ef();d=vf(Error(m(421)));return Hd(a,b,g,d)}if("$?"===e.data)return b.flags|=128,b.child=a.child,b=vk.bind(null,a),e._reactRetry=b,null;a=f.treeContext;fa=Ka(e.nextSibling);la=b;D=!0;wa=null;null!==a&&(na[oa++]=Ma,na[oa++]=Na,na[oa++]=rb,Ma=a.id,Na=a.overflow,rb=b);b=Df(b,d.children);b.flags|=4096;return b}function vi(a,b,c){a.lanes|=b;var d=a.alternate;
null!==d&&(d.lanes|=b);df(a.return,b,c)}function Ff(a,b,c,d,e){var f=a.memoizedState;null===f?a.memoizedState={isBackwards:b,rendering:null,renderingStartTime:0,last:d,tail:c,tailMode:e}:(f.isBackwards=b,f.rendering=null,f.renderingStartTime=0,f.last=d,f.tail=c,f.tailMode=e)}function wi(a,b,c){var d=b.pendingProps,e=d.revealOrder,f=d.tail;aa(a,b,d.children,c);d=F.current;if(0!==(d&2))d=d&1|2,b.flags|=128;else{if(null!==a&&0!==(a.flags&128))a:for(a=b.child;null!==a;){if(13===a.tag)null!==a.memoizedState&&
vi(a,c,b);else if(19===a.tag)vi(a,c,b);else if(null!==a.child){a.child.return=a;a=a.child;continue}if(a===b)break a;for(;null===a.sibling;){if(null===a.return||a.return===b)break a;a=a.return}a.sibling.return=a.return;a=a.sibling}d&=1}y(F,d);if(0===(b.mode&1))b.memoizedState=null;else switch(e){case "forwards":c=b.child;for(e=null;null!==c;)a=c.alternate,null!==a&&null===xd(a)&&(e=c),c=c.sibling;c=e;null===c?(e=b.child,b.child=null):(e=c.sibling,c.sibling=null);Ff(b,!1,e,c,f);break;case "backwards":c=
null;e=b.child;for(b.child=null;null!==e;){a=e.alternate;if(null!==a&&null===xd(a)){b.child=e;break}a=e.sibling;e.sibling=c;c=e;e=a}Ff(b,!0,c,null,f);break;case "together":Ff(b,!1,null,null,void 0);break;default:b.memoizedState=null}return b.child}function Fd(a,b){0===(b.mode&1)&&null!==a&&(a.alternate=null,b.alternate=null,b.flags|=2)}function Qa(a,b,c){null!==a&&(b.dependencies=a.dependencies);ra|=b.lanes;if(0===(c&b.childLanes))return null;if(null!==a&&b.child!==a.child)throw Error(m(153));if(null!==
b.child){a=b.child;c=eb(a,a.pendingProps);b.child=c;for(c.return=b;null!==a.sibling;)a=a.sibling,c=c.sibling=eb(a,a.pendingProps),c.return=b;c.sibling=null}return b.child}function wk(a,b,c){switch(b.tag){case 3:si(b);Qb();break;case 5:Ih(b);break;case 1:ea(b.type)&&ld(b);break;case 4:gf(b,b.stateNode.containerInfo);break;case 10:var d=b.type._context,e=b.memoizedProps.value;y(ud,d._currentValue);d._currentValue=e;break;case 13:d=b.memoizedState;if(null!==d){if(null!==d.dehydrated)return y(F,F.current&
1),b.flags|=128,null;if(0!==(c&b.child.childLanes))return ui(a,b,c);y(F,F.current&1);a=Qa(a,b,c);return null!==a?a.sibling:null}y(F,F.current&1);break;case 19:d=0!==(c&b.childLanes);if(0!==(a.flags&128)){if(d)return wi(a,b,c);b.flags|=128}e=b.memoizedState;null!==e&&(e.rendering=null,e.tail=null,e.lastEffect=null);y(F,F.current);if(d)break;else return null;case 22:case 23:return b.lanes=0,pi(a,b,c)}return Qa(a,b,c)}function Dc(a,b){if(!D)switch(a.tailMode){case "hidden":b=a.tail;for(var c=null;null!==
b;)null!==b.alternate&&(c=b),b=b.sibling;null===c?a.tail=null:c.sibling=null;break;case "collapsed":c=a.tail;for(var d=null;null!==c;)null!==c.alternate&&(d=c),c=c.sibling;null===d?b||null===a.tail?a.tail=null:a.tail.sibling=null:d.sibling=null}}function W(a){var b=null!==a.alternate&&a.alternate.child===a.child,c=0,d=0;if(b)for(var e=a.child;null!==e;)c|=e.lanes|e.childLanes,d|=e.subtreeFlags&14680064,d|=e.flags&14680064,e.return=a,e=e.sibling;else for(e=a.child;null!==e;)c|=e.lanes|e.childLanes,
d|=e.subtreeFlags,d|=e.flags,e.return=a,e=e.sibling;a.subtreeFlags|=d;a.childLanes=c;return b}function xk(a,b,c){var d=b.pendingProps;Ve(b);switch(b.tag){case 2:case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:return W(b),null;case 1:return ea(b.type)&&(v(S),v(J)),W(b),null;case 3:d=b.stateNode;Tb();v(S);v(J);jf();d.pendingContext&&(d.context=d.pendingContext,d.pendingContext=null);if(null===a||null===a.child)pd(b)?b.flags|=4:null===a||a.memoizedState.isDehydrated&&0===(b.flags&
256)||(b.flags|=1024,null!==wa&&(Gf(wa),wa=null));xi(a,b);W(b);return null;case 5:hf(b);var e=ub(xc.current);c=b.type;if(null!==a&&null!=b.stateNode)yk(a,b,c,d,e),a.ref!==b.ref&&(b.flags|=512,b.flags|=2097152);else{if(!d){if(null===b.stateNode)throw Error(m(166));W(b);return null}a=ub(Ea.current);if(pd(b)){d=b.stateNode;c=b.type;var f=b.memoizedProps;d[Da]=b;d[uc]=f;a=0!==(b.mode&1);switch(c){case "dialog":B("cancel",d);B("close",d);break;case "iframe":case "object":case "embed":B("load",d);break;
case "video":case "audio":for(e=0;e<Ec.length;e++)B(Ec[e],d);break;case "source":B("error",d);break;case "img":case "image":case "link":B("error",d);B("load",d);break;case "details":B("toggle",d);break;case "input":kg(d,f);B("invalid",d);break;case "select":d._wrapperState={wasMultiple:!!f.multiple};B("invalid",d);break;case "textarea":ng(d,f),B("invalid",d)}pe(c,f);e=null;for(var g in f)if(f.hasOwnProperty(g)){var h=f[g];"children"===g?"string"===typeof h?d.textContent!==h&&(!0!==f.suppressHydrationWarning&&
jd(d.textContent,h,a),e=["children",h]):"number"===typeof h&&d.textContent!==""+h&&(!0!==f.suppressHydrationWarning&&jd(d.textContent,h,a),e=["children",""+h]):$b.hasOwnProperty(g)&&null!=h&&"onScroll"===g&&B("scroll",d)}switch(c){case "input":Pc(d);mg(d,f,!0);break;case "textarea":Pc(d);pg(d);break;case "select":case "option":break;default:"function"===typeof f.onClick&&(d.onclick=kd)}d=e;b.updateQueue=d;null!==d&&(b.flags|=4)}else{g=9===e.nodeType?e:e.ownerDocument;"http://www.w3.org/1999/xhtml"===
a&&(a=qg(c));"http://www.w3.org/1999/xhtml"===a?"script"===c?(a=g.createElement("div"),a.innerHTML="<script>\x3c/script>",a=a.removeChild(a.firstChild)):"string"===typeof d.is?a=g.createElement(c,{is:d.is}):(a=g.createElement(c),"select"===c&&(g=a,d.multiple?g.multiple=!0:d.size&&(g.size=d.size))):a=g.createElementNS(a,c);a[Da]=b;a[uc]=d;zk(a,b,!1,!1);b.stateNode=a;a:{g=qe(c,d);switch(c){case "dialog":B("cancel",a);B("close",a);e=d;break;case "iframe":case "object":case "embed":B("load",a);e=d;break;
case "video":case "audio":for(e=0;e<Ec.length;e++)B(Ec[e],a);e=d;break;case "source":B("error",a);e=d;break;case "img":case "image":case "link":B("error",a);B("load",a);e=d;break;case "details":B("toggle",a);e=d;break;case "input":kg(a,d);e=ke(a,d);B("invalid",a);break;case "option":e=d;break;case "select":a._wrapperState={wasMultiple:!!d.multiple};e=E({},d,{value:void 0});B("invalid",a);break;case "textarea":ng(a,d);e=ne(a,d);B("invalid",a);break;default:e=d}pe(c,e);h=e;for(f in h)if(h.hasOwnProperty(f)){var k=
h[f];"style"===f?sg(a,k):"dangerouslySetInnerHTML"===f?(k=k?k.__html:void 0,null!=k&&yi(a,k)):"children"===f?"string"===typeof k?("textarea"!==c||""!==k)&&Fc(a,k):"number"===typeof k&&Fc(a,""+k):"suppressContentEditableWarning"!==f&&"suppressHydrationWarning"!==f&&"autoFocus"!==f&&($b.hasOwnProperty(f)?null!=k&&"onScroll"===f&&B("scroll",a):null!=k&&$d(a,f,k,g))}switch(c){case "input":Pc(a);mg(a,d,!1);break;case "textarea":Pc(a);pg(a);break;case "option":null!=d.value&&a.setAttribute("value",""+Ua(d.value));
break;case "select":a.multiple=!!d.multiple;f=d.value;null!=f?Db(a,!!d.multiple,f,!1):null!=d.defaultValue&&Db(a,!!d.multiple,d.defaultValue,!0);break;default:"function"===typeof e.onClick&&(a.onclick=kd)}switch(c){case "button":case "input":case "select":case "textarea":d=!!d.autoFocus;break a;case "img":d=!0;break a;default:d=!1}}d&&(b.flags|=4)}null!==b.ref&&(b.flags|=512,b.flags|=2097152)}W(b);return null;case 6:if(a&&null!=b.stateNode)Ak(a,b,a.memoizedProps,d);else{if("string"!==typeof d&&null===
b.stateNode)throw Error(m(166));c=ub(xc.current);ub(Ea.current);if(pd(b)){d=b.stateNode;c=b.memoizedProps;d[Da]=b;if(f=d.nodeValue!==c)if(a=la,null!==a)switch(a.tag){case 3:jd(d.nodeValue,c,0!==(a.mode&1));break;case 5:!0!==a.memoizedProps.suppressHydrationWarning&&jd(d.nodeValue,c,0!==(a.mode&1))}f&&(b.flags|=4)}else d=(9===c.nodeType?c:c.ownerDocument).createTextNode(d),d[Da]=b,b.stateNode=d}W(b);return null;case 13:v(F);d=b.memoizedState;if(null===a||null!==a.memoizedState&&null!==a.memoizedState.dehydrated){if(D&&
null!==fa&&0!==(b.mode&1)&&0===(b.flags&128)){for(f=fa;f;)f=Ka(f.nextSibling);Qb();b.flags|=98560;f=!1}else if(f=pd(b),null!==d&&null!==d.dehydrated){if(null===a){if(!f)throw Error(m(318));f=b.memoizedState;f=null!==f?f.dehydrated:null;if(!f)throw Error(m(317));f[Da]=b}else Qb(),0===(b.flags&128)&&(b.memoizedState=null),b.flags|=4;W(b);f=!1}else null!==wa&&(Gf(wa),wa=null),f=!0;if(!f)return b.flags&65536?b:null}if(0!==(b.flags&128))return b.lanes=c,b;d=null!==d;d!==(null!==a&&null!==a.memoizedState)&&
d&&(b.child.flags|=8192,0!==(b.mode&1)&&(null===a||0!==(F.current&1)?0===L&&(L=3):Ef()));null!==b.updateQueue&&(b.flags|=4);W(b);return null;case 4:return Tb(),xi(a,b),null===a&&sc(b.stateNode.containerInfo),W(b),null;case 10:return cf(b.type._context),W(b),null;case 17:return ea(b.type)&&(v(S),v(J)),W(b),null;case 19:v(F);f=b.memoizedState;if(null===f)return W(b),null;d=0!==(b.flags&128);g=f.rendering;if(null===g)if(d)Dc(f,!1);else{if(0!==L||null!==a&&0!==(a.flags&128))for(a=b.child;null!==a;){g=
xd(a);if(null!==g){b.flags|=128;Dc(f,!1);d=g.updateQueue;null!==d&&(b.updateQueue=d,b.flags|=4);b.subtreeFlags=0;d=c;for(c=b.child;null!==c;)f=c,a=d,f.flags&=14680066,g=f.alternate,null===g?(f.childLanes=0,f.lanes=a,f.child=null,f.subtreeFlags=0,f.memoizedProps=null,f.memoizedState=null,f.updateQueue=null,f.dependencies=null,f.stateNode=null):(f.childLanes=g.childLanes,f.lanes=g.lanes,f.child=g.child,f.subtreeFlags=0,f.deletions=null,f.memoizedProps=g.memoizedProps,f.memoizedState=g.memoizedState,
f.updateQueue=g.updateQueue,f.type=g.type,a=g.dependencies,f.dependencies=null===a?null:{lanes:a.lanes,firstContext:a.firstContext}),c=c.sibling;y(F,F.current&1|2);return b.child}a=a.sibling}null!==f.tail&&P()>Hf&&(b.flags|=128,d=!0,Dc(f,!1),b.lanes=4194304)}else{if(!d)if(a=xd(g),null!==a){if(b.flags|=128,d=!0,c=a.updateQueue,null!==c&&(b.updateQueue=c,b.flags|=4),Dc(f,!0),null===f.tail&&"hidden"===f.tailMode&&!g.alternate&&!D)return W(b),null}else 2*P()-f.renderingStartTime>Hf&&1073741824!==c&&(b.flags|=
128,d=!0,Dc(f,!1),b.lanes=4194304);f.isBackwards?(g.sibling=b.child,b.child=g):(c=f.last,null!==c?c.sibling=g:b.child=g,f.last=g)}if(null!==f.tail)return b=f.tail,f.rendering=b,f.tail=b.sibling,f.renderingStartTime=P(),b.sibling=null,c=F.current,y(F,d?c&1|2:c&1),b;W(b);return null;case 22:case 23:return ba=Ga.current,v(Ga),d=null!==b.memoizedState,null!==a&&null!==a.memoizedState!==d&&(b.flags|=8192),d&&0!==(b.mode&1)?0!==(ba&1073741824)&&(W(b),b.subtreeFlags&6&&(b.flags|=8192)):W(b),null;case 24:return null;
case 25:return null}throw Error(m(156,b.tag));}function Bk(a,b,c){Ve(b);switch(b.tag){case 1:return ea(b.type)&&(v(S),v(J)),a=b.flags,a&65536?(b.flags=a&-65537|128,b):null;case 3:return Tb(),v(S),v(J),jf(),a=b.flags,0!==(a&65536)&&0===(a&128)?(b.flags=a&-65537|128,b):null;case 5:return hf(b),null;case 13:v(F);a=b.memoizedState;if(null!==a&&null!==a.dehydrated){if(null===b.alternate)throw Error(m(340));Qb()}a=b.flags;return a&65536?(b.flags=a&-65537|128,b):null;case 19:return v(F),null;case 4:return Tb(),
null;case 10:return cf(b.type._context),null;case 22:case 23:return ba=Ga.current,v(Ga),null;case 24:return null;default:return null}}function Wb(a,b){var c=a.ref;if(null!==c)if("function"===typeof c)try{c(null)}catch(d){G(a,b,d)}else c.current=null}function If(a,b,c){try{c()}catch(d){G(a,b,d)}}function Ck(a,b){Jf=Zc;a=ch();if(Ie(a)){if("selectionStart"in a)var c={start:a.selectionStart,end:a.selectionEnd};else a:{c=(c=a.ownerDocument)&&c.defaultView||window;var d=c.getSelection&&c.getSelection();
if(d&&0!==d.rangeCount){c=d.anchorNode;var e=d.anchorOffset,f=d.focusNode;d=d.focusOffset;try{c.nodeType,f.nodeType}catch(M){c=null;break a}var g=0,h=-1,k=-1,n=0,q=0,u=a,r=null;b:for(;;){for(var p;;){u!==c||0!==e&&3!==u.nodeType||(h=g+e);u!==f||0!==d&&3!==u.nodeType||(k=g+d);3===u.nodeType&&(g+=u.nodeValue.length);if(null===(p=u.firstChild))break;r=u;u=p}for(;;){if(u===a)break b;r===c&&++n===e&&(h=g);r===f&&++q===d&&(k=g);if(null!==(p=u.nextSibling))break;u=r;r=u.parentNode}u=p}c=-1===h||-1===k?null:
{start:h,end:k}}else c=null}c=c||{start:0,end:0}}else c=null;Kf={focusedElem:a,selectionRange:c};Zc=!1;for(l=b;null!==l;)if(b=l,a=b.child,0!==(b.subtreeFlags&1028)&&null!==a)a.return=b,l=a;else for(;null!==l;){b=l;try{var x=b.alternate;if(0!==(b.flags&1024))switch(b.tag){case 0:case 11:case 15:break;case 1:if(null!==x){var v=x.memoizedProps,z=x.memoizedState,w=b.stateNode,A=w.getSnapshotBeforeUpdate(b.elementType===b.type?v:ya(b.type,v),z);w.__reactInternalSnapshotBeforeUpdate=A}break;case 3:var t=
b.stateNode.containerInfo;1===t.nodeType?t.textContent="":9===t.nodeType&&t.documentElement&&t.removeChild(t.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(m(163));}}catch(M){G(b,b.return,M)}a=b.sibling;if(null!==a){a.return=b.return;l=a;break}l=b.return}x=zi;zi=!1;return x}function Gc(a,b,c){var d=b.updateQueue;d=null!==d?d.lastEffect:null;if(null!==d){var e=d=d.next;do{if((e.tag&a)===a){var f=e.destroy;e.destroy=void 0;void 0!==f&&If(b,c,f)}e=e.next}while(e!==d)}}
function Id(a,b){b=b.updateQueue;b=null!==b?b.lastEffect:null;if(null!==b){var c=b=b.next;do{if((c.tag&a)===a){var d=c.create;c.destroy=d()}c=c.next}while(c!==b)}}function Lf(a){var b=a.ref;if(null!==b){var c=a.stateNode;switch(a.tag){case 5:a=c;break;default:a=c}"function"===typeof b?b(a):b.current=a}}function Ai(a){var b=a.alternate;null!==b&&(a.alternate=null,Ai(b));a.child=null;a.deletions=null;a.sibling=null;5===a.tag&&(b=a.stateNode,null!==b&&(delete b[Da],delete b[uc],delete b[Me],delete b[Dk],
delete b[Ek]));a.stateNode=null;a.return=null;a.dependencies=null;a.memoizedProps=null;a.memoizedState=null;a.pendingProps=null;a.stateNode=null;a.updateQueue=null}function Bi(a){return 5===a.tag||3===a.tag||4===a.tag}function Ci(a){a:for(;;){for(;null===a.sibling;){if(null===a.return||Bi(a.return))return null;a=a.return}a.sibling.return=a.return;for(a=a.sibling;5!==a.tag&&6!==a.tag&&18!==a.tag;){if(a.flags&2)continue a;if(null===a.child||4===a.tag)continue a;else a.child.return=a,a=a.child}if(!(a.flags&
2))return a.stateNode}}function Mf(a,b,c){var d=a.tag;if(5===d||6===d)a=a.stateNode,b?8===c.nodeType?c.parentNode.insertBefore(a,b):c.insertBefore(a,b):(8===c.nodeType?(b=c.parentNode,b.insertBefore(a,c)):(b=c,b.appendChild(a)),c=c._reactRootContainer,null!==c&&void 0!==c||null!==b.onclick||(b.onclick=kd));else if(4!==d&&(a=a.child,null!==a))for(Mf(a,b,c),a=a.sibling;null!==a;)Mf(a,b,c),a=a.sibling}function Nf(a,b,c){var d=a.tag;if(5===d||6===d)a=a.stateNode,b?c.insertBefore(a,b):c.appendChild(a);
else if(4!==d&&(a=a.child,null!==a))for(Nf(a,b,c),a=a.sibling;null!==a;)Nf(a,b,c),a=a.sibling}function jb(a,b,c){for(c=c.child;null!==c;)Di(a,b,c),c=c.sibling}function Di(a,b,c){if(Ca&&"function"===typeof Ca.onCommitFiberUnmount)try{Ca.onCommitFiberUnmount(Uc,c)}catch(h){}switch(c.tag){case 5:X||Wb(c,b);case 6:var d=T,e=za;T=null;jb(a,b,c);T=d;za=e;null!==T&&(za?(a=T,c=c.stateNode,8===a.nodeType?a.parentNode.removeChild(c):a.removeChild(c)):T.removeChild(c.stateNode));break;case 18:null!==T&&(za?
(a=T,c=c.stateNode,8===a.nodeType?Re(a.parentNode,c):1===a.nodeType&&Re(a,c),nc(a)):Re(T,c.stateNode));break;case 4:d=T;e=za;T=c.stateNode.containerInfo;za=!0;jb(a,b,c);T=d;za=e;break;case 0:case 11:case 14:case 15:if(!X&&(d=c.updateQueue,null!==d&&(d=d.lastEffect,null!==d))){e=d=d.next;do{var f=e,g=f.destroy;f=f.tag;void 0!==g&&(0!==(f&2)?If(c,b,g):0!==(f&4)&&If(c,b,g));e=e.next}while(e!==d)}jb(a,b,c);break;case 1:if(!X&&(Wb(c,b),d=c.stateNode,"function"===typeof d.componentWillUnmount))try{d.props=
c.memoizedProps,d.state=c.memoizedState,d.componentWillUnmount()}catch(h){G(c,b,h)}jb(a,b,c);break;case 21:jb(a,b,c);break;case 22:c.mode&1?(X=(d=X)||null!==c.memoizedState,jb(a,b,c),X=d):jb(a,b,c);break;default:jb(a,b,c)}}function Ei(a){var b=a.updateQueue;if(null!==b){a.updateQueue=null;var c=a.stateNode;null===c&&(c=a.stateNode=new Fk);b.forEach(function(b){var d=Gk.bind(null,a,b);c.has(b)||(c.add(b),b.then(d,d))})}}function Aa(a,b,c){c=b.deletions;if(null!==c)for(var d=0;d<c.length;d++){var e=
c[d];try{var f=a,g=b,h=g;a:for(;null!==h;){switch(h.tag){case 5:T=h.stateNode;za=!1;break a;case 3:T=h.stateNode.containerInfo;za=!0;break a;case 4:T=h.stateNode.containerInfo;za=!0;break a}h=h.return}if(null===T)throw Error(m(160));Di(f,g,e);T=null;za=!1;var k=e.alternate;null!==k&&(k.return=null);e.return=null}catch(n){G(e,b,n)}}if(b.subtreeFlags&12854)for(b=b.child;null!==b;)Fi(b,a),b=b.sibling}function Fi(a,b,c){var d=a.alternate;c=a.flags;switch(a.tag){case 0:case 11:case 14:case 15:Aa(b,a);
Ha(a);if(c&4){try{Gc(3,a,a.return),Id(3,a)}catch(I){G(a,a.return,I)}try{Gc(5,a,a.return)}catch(I){G(a,a.return,I)}}break;case 1:Aa(b,a);Ha(a);c&512&&null!==d&&Wb(d,d.return);break;case 5:Aa(b,a);Ha(a);c&512&&null!==d&&Wb(d,d.return);if(a.flags&32){var e=a.stateNode;try{Fc(e,"")}catch(I){G(a,a.return,I)}}if(c&4&&(e=a.stateNode,null!=e)){var f=a.memoizedProps,g=null!==d?d.memoizedProps:f,h=a.type,k=a.updateQueue;a.updateQueue=null;if(null!==k)try{"input"===h&&"radio"===f.type&&null!=f.name&&lg(e,f);
qe(h,g);var n=qe(h,f);for(g=0;g<k.length;g+=2){var q=k[g],u=k[g+1];"style"===q?sg(e,u):"dangerouslySetInnerHTML"===q?yi(e,u):"children"===q?Fc(e,u):$d(e,q,u,n)}switch(h){case "input":le(e,f);break;case "textarea":og(e,f);break;case "select":var r=e._wrapperState.wasMultiple;e._wrapperState.wasMultiple=!!f.multiple;var p=f.value;null!=p?Db(e,!!f.multiple,p,!1):r!==!!f.multiple&&(null!=f.defaultValue?Db(e,!!f.multiple,f.defaultValue,!0):Db(e,!!f.multiple,f.multiple?[]:"",!1))}e[uc]=f}catch(I){G(a,a.return,
I)}}break;case 6:Aa(b,a);Ha(a);if(c&4){if(null===a.stateNode)throw Error(m(162));e=a.stateNode;f=a.memoizedProps;try{e.nodeValue=f}catch(I){G(a,a.return,I)}}break;case 3:Aa(b,a);Ha(a);if(c&4&&null!==d&&d.memoizedState.isDehydrated)try{nc(b.containerInfo)}catch(I){G(a,a.return,I)}break;case 4:Aa(b,a);Ha(a);break;case 13:Aa(b,a);Ha(a);e=a.child;e.flags&8192&&(f=null!==e.memoizedState,e.stateNode.isHidden=f,!f||null!==e.alternate&&null!==e.alternate.memoizedState||(Of=P()));c&4&&Ei(a);break;case 22:q=
null!==d&&null!==d.memoizedState;a.mode&1?(X=(n=X)||q,Aa(b,a),X=n):Aa(b,a);Ha(a);if(c&8192){n=null!==a.memoizedState;if((a.stateNode.isHidden=n)&&!q&&0!==(a.mode&1))for(l=a,q=a.child;null!==q;){for(u=l=q;null!==l;){r=l;p=r.child;switch(r.tag){case 0:case 11:case 14:case 15:Gc(4,r,r.return);break;case 1:Wb(r,r.return);var x=r.stateNode;if("function"===typeof x.componentWillUnmount){c=r;b=r.return;try{d=c,x.props=d.memoizedProps,x.state=d.memoizedState,x.componentWillUnmount()}catch(I){G(c,b,I)}}break;
case 5:Wb(r,r.return);break;case 22:if(null!==r.memoizedState){Gi(u);continue}}null!==p?(p.return=r,l=p):Gi(u)}q=q.sibling}a:for(q=null,u=a;;){if(5===u.tag){if(null===q){q=u;try{e=u.stateNode,n?(f=e.style,"function"===typeof f.setProperty?f.setProperty("display","none","important"):f.display="none"):(h=u.stateNode,k=u.memoizedProps.style,g=void 0!==k&&null!==k&&k.hasOwnProperty("display")?k.display:null,h.style.display=rg("display",g))}catch(I){G(a,a.return,I)}}}else if(6===u.tag){if(null===q)try{u.stateNode.nodeValue=
n?"":u.memoizedProps}catch(I){G(a,a.return,I)}}else if((22!==u.tag&&23!==u.tag||null===u.memoizedState||u===a)&&null!==u.child){u.child.return=u;u=u.child;continue}if(u===a)break a;for(;null===u.sibling;){if(null===u.return||u.return===a)break a;q===u&&(q=null);u=u.return}q===u&&(q=null);u.sibling.return=u.return;u=u.sibling}}break;case 19:Aa(b,a);Ha(a);c&4&&Ei(a);break;case 21:break;default:Aa(b,a),Ha(a)}}function Ha(a){var b=a.flags;if(b&2){try{a:{for(var c=a.return;null!==c;){if(Bi(c)){var d=c;
break a}c=c.return}throw Error(m(160));}switch(d.tag){case 5:var e=d.stateNode;d.flags&32&&(Fc(e,""),d.flags&=-33);var f=Ci(a);Nf(a,f,e);break;case 3:case 4:var g=d.stateNode.containerInfo,h=Ci(a);Mf(a,h,g);break;default:throw Error(m(161));}}catch(k){G(a,a.return,k)}a.flags&=-3}b&4096&&(a.flags&=-4097)}function Hk(a,b,c){l=a;Hi(a,b,c)}function Hi(a,b,c){for(var d=0!==(a.mode&1);null!==l;){var e=l,f=e.child;if(22===e.tag&&d){var g=null!==e.memoizedState||Jd;if(!g){var h=e.alternate,k=null!==h&&null!==
h.memoizedState||X;h=Jd;var n=X;Jd=g;if((X=k)&&!n)for(l=e;null!==l;)g=l,k=g.child,22===g.tag&&null!==g.memoizedState?Ii(e):null!==k?(k.return=g,l=k):Ii(e);for(;null!==f;)l=f,Hi(f,b,c),f=f.sibling;l=e;Jd=h;X=n}Ji(a,b,c)}else 0!==(e.subtreeFlags&8772)&&null!==f?(f.return=e,l=f):Ji(a,b,c)}}function Ji(a,b,c){for(;null!==l;){b=l;if(0!==(b.flags&8772)){c=b.alternate;try{if(0!==(b.flags&8772))switch(b.tag){case 0:case 11:case 15:X||Id(5,b);break;case 1:var d=b.stateNode;if(b.flags&4&&!X)if(null===c)d.componentDidMount();
else{var e=b.elementType===b.type?c.memoizedProps:ya(b.type,c.memoizedProps);d.componentDidUpdate(e,c.memoizedState,d.__reactInternalSnapshotBeforeUpdate)}var f=b.updateQueue;null!==f&&Hh(b,f,d);break;case 3:var g=b.updateQueue;if(null!==g){c=null;if(null!==b.child)switch(b.child.tag){case 5:c=b.child.stateNode;break;case 1:c=b.child.stateNode}Hh(b,g,c)}break;case 5:var h=b.stateNode;if(null===c&&b.flags&4){c=h;var k=b.memoizedProps;switch(b.type){case "button":case "input":case "select":case "textarea":k.autoFocus&&
c.focus();break;case "img":k.src&&(c.src=k.src)}}break;case 6:break;case 4:break;case 12:break;case 13:if(null===b.memoizedState){var n=b.alternate;if(null!==n){var q=n.memoizedState;if(null!==q){var p=q.dehydrated;null!==p&&nc(p)}}}break;case 19:case 17:case 21:case 22:case 23:case 25:break;default:throw Error(m(163));}X||b.flags&512&&Lf(b)}catch(r){G(b,b.return,r)}}if(b===a){l=null;break}c=b.sibling;if(null!==c){c.return=b.return;l=c;break}l=b.return}}function Gi(a){for(;null!==l;){var b=l;if(b===
a){l=null;break}var c=b.sibling;if(null!==c){c.return=b.return;l=c;break}l=b.return}}function Ii(a){for(;null!==l;){var b=l;try{switch(b.tag){case 0:case 11:case 15:var c=b.return;try{Id(4,b)}catch(k){G(b,c,k)}break;case 1:var d=b.stateNode;if("function"===typeof d.componentDidMount){var e=b.return;try{d.componentDidMount()}catch(k){G(b,e,k)}}var f=b.return;try{Lf(b)}catch(k){G(b,f,k)}break;case 5:var g=b.return;try{Lf(b)}catch(k){G(b,g,k)}}}catch(k){G(b,b.return,k)}if(b===a){l=null;break}var h=b.sibling;
if(null!==h){h.return=b.return;l=h;break}l=b.return}}function Hc(){Hf=P()+500}function Z(){return 0!==(p&6)?P():-1!==Kd?Kd:Kd=P()}function hb(a){if(0===(a.mode&1))return 1;if(0!==(p&2)&&0!==U)return U&-U;if(null!==Ik.transition)return 0===Ld&&(Ld=Dg()),Ld;a=z;if(0!==a)return a;a=window.event;a=void 0===a?16:Lg(a.type);return a}function xa(a,b,c,d){if(50<Ic)throw Ic=0,Pf=null,Error(m(185));ic(a,c,d);if(0===(p&2)||a!==O)a===O&&(0===(p&2)&&(Md|=c),4===L&&kb(a,U)),ia(a,d),1===c&&0===p&&0===(b.mode&1)&&
(Hc(),md&&db())}function ia(a,b){var c=a.callbackNode;tj(a,b);var d=Vc(a,a===O?U:0);if(0===d)null!==c&&Ki(c),a.callbackNode=null,a.callbackPriority=0;else if(b=d&-d,a.callbackPriority!==b){null!=c&&Ki(c);if(1===b)0===a.tag?jk(Li.bind(null,a)):wh(Li.bind(null,a)),Jk(function(){0===(p&6)&&db()}),c=null;else{switch(Eg(d)){case 1:c=De;break;case 4:c=Mg;break;case 16:c=ad;break;case 536870912:c=Ng;break;default:c=ad}c=Mi(c,Ni.bind(null,a))}a.callbackPriority=b;a.callbackNode=c}}function Ni(a,b){Kd=-1;
Ld=0;if(0!==(p&6))throw Error(m(327));var c=a.callbackNode;if(Xb()&&a.callbackNode!==c)return null;var d=Vc(a,a===O?U:0);if(0===d)return null;if(0!==(d&30)||0!==(d&a.expiredLanes)||b)b=Nd(a,d);else{b=d;var e=p;p|=2;var f=Oi();if(O!==a||U!==b)Ra=null,Hc(),wb(a,b);do try{Kk();break}catch(h){Pi(a,h)}while(1);af();Od.current=f;p=e;null!==H?b=0:(O=null,U=0,b=L)}if(0!==b){2===b&&(e=ve(a),0!==e&&(d=e,b=Qf(a,e)));if(1===b)throw c=Jc,wb(a,0),kb(a,d),ia(a,P()),c;if(6===b)kb(a,d);else{e=a.current.alternate;
if(0===(d&30)&&!Lk(e)&&(b=Nd(a,d),2===b&&(f=ve(a),0!==f&&(d=f,b=Qf(a,f))),1===b))throw c=Jc,wb(a,0),kb(a,d),ia(a,P()),c;a.finishedWork=e;a.finishedLanes=d;switch(b){case 0:case 1:throw Error(m(345));case 2:xb(a,ja,Ra);break;case 3:kb(a,d);if((d&130023424)===d&&(b=Of+500-P(),10<b)){if(0!==Vc(a,0))break;e=a.suspendedLanes;if((e&d)!==d){Z();a.pingedLanes|=a.suspendedLanes&e;break}a.timeoutHandle=Rf(xb.bind(null,a,ja,Ra),b);break}xb(a,ja,Ra);break;case 4:kb(a,d);if((d&4194240)===d)break;b=a.eventTimes;
for(e=-1;0<d;){var g=31-ta(d);f=1<<g;g=b[g];g>e&&(e=g);d&=~f}d=e;d=P()-d;d=(120>d?120:480>d?480:1080>d?1080:1920>d?1920:3E3>d?3E3:4320>d?4320:1960*Mk(d/1960))-d;if(10<d){a.timeoutHandle=Rf(xb.bind(null,a,ja,Ra),d);break}xb(a,ja,Ra);break;case 5:xb(a,ja,Ra);break;default:throw Error(m(329));}}}ia(a,P());return a.callbackNode===c?Ni.bind(null,a):null}function Qf(a,b){var c=Kc;a.current.memoizedState.isDehydrated&&(wb(a,b).flags|=256);a=Nd(a,b);2!==a&&(b=ja,ja=c,null!==b&&Gf(b));return a}function Gf(a){null===
ja?ja=a:ja.push.apply(ja,a)}function Lk(a){for(var b=a;;){if(b.flags&16384){var c=b.updateQueue;if(null!==c&&(c=c.stores,null!==c))for(var d=0;d<c.length;d++){var e=c[d],f=e.getSnapshot;e=e.value;try{if(!ua(f(),e))return!1}catch(g){return!1}}}c=b.child;if(b.subtreeFlags&16384&&null!==c)c.return=b,b=c;else{if(b===a)break;for(;null===b.sibling;){if(null===b.return||b.return===a)return!0;b=b.return}b.sibling.return=b.return;b=b.sibling}}return!0}function kb(a,b){b&=~Sf;b&=~Md;a.suspendedLanes|=b;a.pingedLanes&=
~b;for(a=a.expirationTimes;0<b;){var c=31-ta(b),d=1<<c;a[c]=-1;b&=~d}}function Li(a){if(0!==(p&6))throw Error(m(327));Xb();var b=Vc(a,0);if(0===(b&1))return ia(a,P()),null;var c=Nd(a,b);if(0!==a.tag&&2===c){var d=ve(a);0!==d&&(b=d,c=Qf(a,d))}if(1===c)throw c=Jc,wb(a,0),kb(a,b),ia(a,P()),c;if(6===c)throw Error(m(345));a.finishedWork=a.current.alternate;a.finishedLanes=b;xb(a,ja,Ra);ia(a,P());return null}function Tf(a,b){var c=p;p|=1;try{return a(b)}finally{p=c,0===p&&(Hc(),md&&db())}}function yb(a){null!==
lb&&0===lb.tag&&0===(p&6)&&Xb();var b=p;p|=1;var c=ca.transition,d=z;try{if(ca.transition=null,z=1,a)return a()}finally{z=d,ca.transition=c,p=b,0===(p&6)&&db()}}function wb(a,b){a.finishedWork=null;a.finishedLanes=0;var c=a.timeoutHandle;-1!==c&&(a.timeoutHandle=-1,Nk(c));if(null!==H)for(c=H.return;null!==c;){var d=c;Ve(d);switch(d.tag){case 1:d=d.type.childContextTypes;null!==d&&void 0!==d&&(v(S),v(J));break;case 3:Tb();v(S);v(J);jf();break;case 5:hf(d);break;case 4:Tb();break;case 13:v(F);break;
case 19:v(F);break;case 10:cf(d.type._context);break;case 22:case 23:ba=Ga.current,v(Ga)}c=c.return}O=a;H=a=eb(a.current,null);U=ba=b;L=0;Jc=null;Sf=Md=ra=0;ja=Kc=null;if(null!==tb){for(b=0;b<tb.length;b++)if(c=tb[b],d=c.interleaved,null!==d){c.interleaved=null;var e=d.next,f=c.pending;if(null!==f){var g=f.next;f.next=e;d.next=g}c.pending=d}tb=null}return a}function Pi(a,b){do{var c=H;try{af();yd.current=zd;if(Ad){for(var d=C.memoizedState;null!==d;){var e=d.queue;null!==e&&(e.pending=null);d=d.next}Ad=
!1}vb=0;N=K=C=null;zc=!1;Ac=0;Uf.current=null;if(null===c||null===c.return){L=1;Jc=b;H=null;break}a:{var f=a,g=c.return,h=c,k=b;b=U;h.flags|=32768;if(null!==k&&"object"===typeof k&&"function"===typeof k.then){var n=k,l=h,p=l.tag;if(0===(l.mode&1)&&(0===p||11===p||15===p)){var r=l.alternate;r?(l.updateQueue=r.updateQueue,l.memoizedState=r.memoizedState,l.lanes=r.lanes):(l.updateQueue=null,l.memoizedState=null)}var v=ji(g);if(null!==v){v.flags&=-257;ki(v,g,h,f,b);v.mode&1&&ii(f,n,b);b=v;k=n;var x=b.updateQueue;
if(null===x){var z=new Set;z.add(k);b.updateQueue=z}else x.add(k);break a}else{if(0===(b&1)){ii(f,n,b);Ef();break a}k=Error(m(426))}}else if(D&&h.mode&1){var y=ji(g);if(null!==y){0===(y.flags&65536)&&(y.flags|=256);ki(y,g,h,f,b);Ye(Ub(k,h));break a}}f=k=Ub(k,h);4!==L&&(L=2);null===Kc?Kc=[f]:Kc.push(f);f=g;do{switch(f.tag){case 3:f.flags|=65536;b&=-b;f.lanes|=b;var w=gi(f,k,b);Gh(f,w);break a;case 1:h=k;var A=f.type,t=f.stateNode;if(0===(f.flags&128)&&("function"===typeof A.getDerivedStateFromError||
null!==t&&"function"===typeof t.componentDidCatch&&(null===ib||!ib.has(t)))){f.flags|=65536;b&=-b;f.lanes|=b;var B=hi(f,h,b);Gh(f,B);break a}}f=f.return}while(null!==f)}Qi(c)}catch(ma){b=ma;H===c&&null!==c&&(H=c=c.return);continue}break}while(1)}function Oi(){var a=Od.current;Od.current=zd;return null===a?zd:a}function Ef(){if(0===L||3===L||2===L)L=4;null===O||0===(ra&268435455)&&0===(Md&268435455)||kb(O,U)}function Nd(a,b){var c=p;p|=2;var d=Oi();if(O!==a||U!==b)Ra=null,wb(a,b);do try{Ok();break}catch(e){Pi(a,
e)}while(1);af();p=c;Od.current=d;if(null!==H)throw Error(m(261));O=null;U=0;return L}function Ok(){for(;null!==H;)Ri(H)}function Kk(){for(;null!==H&&!Pk();)Ri(H)}function Ri(a){var b=Qk(a.alternate,a,ba);a.memoizedProps=a.pendingProps;null===b?Qi(a):H=b;Uf.current=null}function Qi(a){var b=a;do{var c=b.alternate;a=b.return;if(0===(b.flags&32768)){if(c=xk(c,b,ba),null!==c){H=c;return}}else{c=Bk(c,b);if(null!==c){c.flags&=32767;H=c;return}if(null!==a)a.flags|=32768,a.subtreeFlags=0,a.deletions=null;
else{L=6;H=null;return}}b=b.sibling;if(null!==b){H=b;return}H=b=a}while(null!==b);0===L&&(L=5)}function xb(a,b,c){var d=z,e=ca.transition;try{ca.transition=null,z=1,Rk(a,b,c,d)}finally{ca.transition=e,z=d}return null}function Rk(a,b,c,d){do Xb();while(null!==lb);if(0!==(p&6))throw Error(m(327));c=a.finishedWork;var e=a.finishedLanes;if(null===c)return null;a.finishedWork=null;a.finishedLanes=0;if(c===a.current)throw Error(m(177));a.callbackNode=null;a.callbackPriority=0;var f=c.lanes|c.childLanes;
uj(a,f);a===O&&(H=O=null,U=0);0===(c.subtreeFlags&2064)&&0===(c.flags&2064)||Pd||(Pd=!0,Mi(ad,function(){Xb();return null}));f=0!==(c.flags&15990);if(0!==(c.subtreeFlags&15990)||f){f=ca.transition;ca.transition=null;var g=z;z=1;var h=p;p|=4;Uf.current=null;Ck(a,c);Fi(c,a);Tj(Kf);Zc=!!Jf;Kf=Jf=null;a.current=c;Hk(c,a,e);Sk();p=h;z=g;ca.transition=f}else a.current=c;Pd&&(Pd=!1,lb=a,Qd=e);f=a.pendingLanes;0===f&&(ib=null);oj(c.stateNode,d);ia(a,P());if(null!==b)for(d=a.onRecoverableError,c=0;c<b.length;c++)e=
b[c],d(e.value,{componentStack:e.stack,digest:e.digest});if(Ed)throw Ed=!1,a=xf,xf=null,a;0!==(Qd&1)&&0!==a.tag&&Xb();f=a.pendingLanes;0!==(f&1)?a===Pf?Ic++:(Ic=0,Pf=a):Ic=0;db();return null}function Xb(){if(null!==lb){var a=Eg(Qd),b=ca.transition,c=z;try{ca.transition=null;z=16>a?16:a;if(null===lb)var d=!1;else{a=lb;lb=null;Qd=0;if(0!==(p&6))throw Error(m(331));var e=p;p|=4;for(l=a.current;null!==l;){var f=l,g=f.child;if(0!==(l.flags&16)){var h=f.deletions;if(null!==h){for(var k=0;k<h.length;k++){var n=
h[k];for(l=n;null!==l;){var q=l;switch(q.tag){case 0:case 11:case 15:Gc(8,q,f)}var u=q.child;if(null!==u)u.return=q,l=u;else for(;null!==l;){q=l;var r=q.sibling,v=q.return;Ai(q);if(q===n){l=null;break}if(null!==r){r.return=v;l=r;break}l=v}}}var x=f.alternate;if(null!==x){var y=x.child;if(null!==y){x.child=null;do{var C=y.sibling;y.sibling=null;y=C}while(null!==y)}}l=f}}if(0!==(f.subtreeFlags&2064)&&null!==g)g.return=f,l=g;else b:for(;null!==l;){f=l;if(0!==(f.flags&2048))switch(f.tag){case 0:case 11:case 15:Gc(9,
f,f.return)}var w=f.sibling;if(null!==w){w.return=f.return;l=w;break b}l=f.return}}var A=a.current;for(l=A;null!==l;){g=l;var t=g.child;if(0!==(g.subtreeFlags&2064)&&null!==t)t.return=g,l=t;else b:for(g=A;null!==l;){h=l;if(0!==(h.flags&2048))try{switch(h.tag){case 0:case 11:case 15:Id(9,h)}}catch(ma){G(h,h.return,ma)}if(h===g){l=null;break b}var B=h.sibling;if(null!==B){B.return=h.return;l=B;break b}l=h.return}}p=e;db();if(Ca&&"function"===typeof Ca.onPostCommitFiberRoot)try{Ca.onPostCommitFiberRoot(Uc,
a)}catch(ma){}d=!0}return d}finally{z=c,ca.transition=b}}return!1}function Si(a,b,c){b=Ub(c,b);b=gi(a,b,1);a=fb(a,b,1);b=Z();null!==a&&(ic(a,1,b),ia(a,b))}function G(a,b,c){if(3===a.tag)Si(a,a,c);else for(;null!==b;){if(3===b.tag){Si(b,a,c);break}else if(1===b.tag){var d=b.stateNode;if("function"===typeof b.type.getDerivedStateFromError||"function"===typeof d.componentDidCatch&&(null===ib||!ib.has(d))){a=Ub(c,a);a=hi(b,a,1);b=fb(b,a,1);a=Z();null!==b&&(ic(b,1,a),ia(b,a));break}}b=b.return}}function sk(a,
b,c){var d=a.pingCache;null!==d&&d.delete(b);b=Z();a.pingedLanes|=a.suspendedLanes&c;O===a&&(U&c)===c&&(4===L||3===L&&(U&130023424)===U&&500>P()-Of?wb(a,0):Sf|=c);ia(a,b)}function Ti(a,b){0===b&&(0===(a.mode&1)?b=1:(b=Rd,Rd<<=1,0===(Rd&130023424)&&(Rd=4194304)));var c=Z();a=Oa(a,b);null!==a&&(ic(a,b,c),ia(a,c))}function vk(a){var b=a.memoizedState,c=0;null!==b&&(c=b.retryLane);Ti(a,c)}function Gk(a,b){var c=0;switch(a.tag){case 13:var d=a.stateNode;var e=a.memoizedState;null!==e&&(c=e.retryLane);
break;case 19:d=a.stateNode;break;default:throw Error(m(314));}null!==d&&d.delete(b);Ti(a,c)}function Mi(a,b){return xh(a,b)}function Tk(a,b,c,d){this.tag=a;this.key=c;this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null;this.index=0;this.ref=null;this.pendingProps=b;this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null;this.mode=d;this.subtreeFlags=this.flags=0;this.deletions=null;this.childLanes=this.lanes=0;this.alternate=null}function yf(a){a=
a.prototype;return!(!a||!a.isReactComponent)}function Uk(a){if("function"===typeof a)return yf(a)?1:0;if(void 0!==a&&null!==a){a=a.$$typeof;if(a===ie)return 11;if(a===je)return 14}return 2}function eb(a,b){var c=a.alternate;null===c?(c=pa(a.tag,b,a.key,a.mode),c.elementType=a.elementType,c.type=a.type,c.stateNode=a.stateNode,c.alternate=a,a.alternate=c):(c.pendingProps=b,c.type=a.type,c.flags=0,c.subtreeFlags=0,c.deletions=null);c.flags=a.flags&14680064;c.childLanes=a.childLanes;c.lanes=a.lanes;c.child=
a.child;c.memoizedProps=a.memoizedProps;c.memoizedState=a.memoizedState;c.updateQueue=a.updateQueue;b=a.dependencies;c.dependencies=null===b?null:{lanes:b.lanes,firstContext:b.firstContext};c.sibling=a.sibling;c.index=a.index;c.ref=a.ref;return c}function rd(a,b,c,d,e,f){var g=2;d=a;if("function"===typeof a)yf(a)&&(g=1);else if("string"===typeof a)g=5;else a:switch(a){case Bb:return sb(c.children,e,f,b);case fe:g=8;e|=8;break;case ee:return a=pa(12,c,b,e|2),a.elementType=ee,a.lanes=f,a;case ge:return a=
pa(13,c,b,e),a.elementType=ge,a.lanes=f,a;case he:return a=pa(19,c,b,e),a.elementType=he,a.lanes=f,a;case Ui:return Gd(c,e,f,b);default:if("object"===typeof a&&null!==a)switch(a.$$typeof){case hg:g=10;break a;case gg:g=9;break a;case ie:g=11;break a;case je:g=14;break a;case Ta:g=16;d=null;break a}throw Error(m(130,null==a?a:typeof a,""));}b=pa(g,c,b,e);b.elementType=a;b.type=d;b.lanes=f;return b}function sb(a,b,c,d){a=pa(7,a,d,b);a.lanes=c;return a}function Gd(a,b,c,d){a=pa(22,a,d,b);a.elementType=
Ui;a.lanes=c;a.stateNode={isHidden:!1};return a}function Ze(a,b,c){a=pa(6,a,null,b);a.lanes=c;return a}function $e(a,b,c){b=pa(4,null!==a.children?a.children:[],a.key,b);b.lanes=c;b.stateNode={containerInfo:a.containerInfo,pendingChildren:null,implementation:a.implementation};return b}function Vk(a,b,c,d,e){this.tag=b;this.containerInfo=a;this.finishedWork=this.pingCache=this.current=this.pendingChildren=null;this.timeoutHandle=-1;this.callbackNode=this.pendingContext=this.context=null;this.callbackPriority=
0;this.eventTimes=we(0);this.expirationTimes=we(-1);this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0;this.entanglements=we(0);this.identifierPrefix=d;this.onRecoverableError=e;this.mutableSourceEagerHydrationData=null}function Vf(a,b,c,d,e,f,g,h,k,l){a=new Vk(a,b,c,h,k);1===b?(b=1,!0===f&&(b|=8)):b=0;f=pa(3,null,null,b);a.current=f;f.stateNode=a;f.memoizedState={element:d,isDehydrated:c,cache:null,transitions:null,
pendingSuspenseBoundaries:null};ff(f);return a}function Wk(a,b,c){var d=3<arguments.length&&void 0!==arguments[3]?arguments[3]:null;return{$$typeof:Cb,key:null==d?null:""+d,children:a,containerInfo:b,implementation:c}}function Vi(a){if(!a)return cb;a=a._reactInternals;a:{if(nb(a)!==a||1!==a.tag)throw Error(m(170));var b=a;do{switch(b.tag){case 3:b=b.stateNode.context;break a;case 1:if(ea(b.type)){b=b.stateNode.__reactInternalMemoizedMergedChildContext;break a}}b=b.return}while(null!==b);throw Error(m(171));
}if(1===a.tag){var c=a.type;if(ea(c))return uh(a,c,b)}return b}function Wi(a,b,c,d,e,f,g,h,k,l){a=Vf(c,d,!0,a,e,f,g,h,k);a.context=Vi(null);c=a.current;d=Z();e=hb(c);f=Pa(d,e);f.callback=void 0!==b&&null!==b?b:null;fb(c,f,e);a.current.lanes=e;ic(a,e,d);ia(a,d);return a}function Sd(a,b,c,d){var e=b.current,f=Z(),g=hb(e);c=Vi(c);null===b.context?b.context=c:b.pendingContext=c;b=Pa(f,g);b.payload={element:a};d=void 0===d?null:d;null!==d&&(b.callback=d);a=fb(e,b,g);null!==a&&(xa(a,e,g,f),vd(a,e,g));return g}
function Td(a){a=a.current;if(!a.child)return null;switch(a.child.tag){case 5:return a.child.stateNode;default:return a.child.stateNode}}function Xi(a,b){a=a.memoizedState;if(null!==a&&null!==a.dehydrated){var c=a.retryLane;a.retryLane=0!==c&&c<b?c:b}}function Wf(a,b){Xi(a,b);(a=a.alternate)&&Xi(a,b)}function Xk(a){a=Bg(a);return null===a?null:a.stateNode}function Yk(a){return null}function Xf(a){this._internalRoot=a}function Ud(a){this._internalRoot=a}function Yf(a){return!(!a||1!==a.nodeType&&9!==
a.nodeType&&11!==a.nodeType)}function Vd(a){return!(!a||1!==a.nodeType&&9!==a.nodeType&&11!==a.nodeType&&(8!==a.nodeType||" react-mount-point-unstable "!==a.nodeValue))}function Yi(){}function Zk(a,b,c,d,e){if(e){if("function"===typeof d){var f=d;d=function(){var a=Td(g);f.call(a)}}var g=Wi(b,d,a,0,null,!1,!1,"",Yi);a._reactRootContainer=g;a[Ja]=g.current;sc(8===a.nodeType?a.parentNode:a);yb();return g}for(;e=a.lastChild;)a.removeChild(e);if("function"===typeof d){var h=d;d=function(){var a=Td(k);
h.call(a)}}var k=Vf(a,0,!1,null,null,!1,!1,"",Yi);a._reactRootContainer=k;a[Ja]=k.current;sc(8===a.nodeType?a.parentNode:a);yb(function(){Sd(b,k,c,d)});return k}function Wd(a,b,c,d,e){var f=c._reactRootContainer;if(f){var g=f;if("function"===typeof e){var h=e;e=function(){var a=Td(g);h.call(a)}}Sd(b,g,a,e)}else g=Zk(c,b,a,e,d);return Td(g)}var cg=new Set,$b={},Ia=!("undefined"===typeof window||"undefined"===typeof window.document||"undefined"===typeof window.document.createElement),Zd=Object.prototype.hasOwnProperty,
cj=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,eg={},dg={},R={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(a){R[a]=
new Y(a,0,!1,a,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(a){var b=a[0];R[b]=new Y(b,1,!1,a[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(a){R[a]=new Y(a,2,!1,a.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(a){R[a]=new Y(a,2,!1,a,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(a){R[a]=
new Y(a,3,!1,a.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(a){R[a]=new Y(a,3,!0,a,null,!1,!1)});["capture","download"].forEach(function(a){R[a]=new Y(a,4,!1,a,null,!1,!1)});["cols","rows","size","span"].forEach(function(a){R[a]=new Y(a,6,!1,a,null,!1,!1)});["rowSpan","start"].forEach(function(a){R[a]=new Y(a,5,!1,a.toLowerCase(),null,!1,!1)});var Zf=/[\-:]([a-z])/g,$f=function(a){return a[1].toUpperCase()};"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(a){var b=
a.replace(Zf,$f);R[b]=new Y(b,1,!1,a,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(a){var b=a.replace(Zf,$f);R[b]=new Y(b,1,!1,a,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(a){var b=a.replace(Zf,$f);R[b]=new Y(b,1,!1,a,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(a){R[a]=new Y(a,1,!1,a.toLowerCase(),null,!1,!1)});R.xlinkHref=new Y("xlinkHref",
1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(a){R[a]=new Y(a,1,!1,a.toLowerCase(),null,!0,!0)});var Sa=zb.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,sd=Symbol.for("react.element"),Cb=Symbol.for("react.portal"),Bb=Symbol.for("react.fragment"),fe=Symbol.for("react.strict_mode"),ee=Symbol.for("react.profiler"),hg=Symbol.for("react.provider"),gg=Symbol.for("react.context"),ie=Symbol.for("react.forward_ref"),ge=Symbol.for("react.suspense"),
he=Symbol.for("react.suspense_list"),je=Symbol.for("react.memo"),Ta=Symbol.for("react.lazy");Symbol.for("react.scope");Symbol.for("react.debug_trace_mode");var Ui=Symbol.for("react.offscreen");Symbol.for("react.legacy_hidden");Symbol.for("react.cache");Symbol.for("react.tracing_marker");var fg=Symbol.iterator,E=Object.assign,ae,ce=!1,cc=Array.isArray,Xd,yi=function(a){return"undefined"!==typeof MSApp&&MSApp.execUnsafeLocalFunction?function(b,c,d,e){MSApp.execUnsafeLocalFunction(function(){return a(b,
c,d,e)})}:a}(function(a,b){if("http://www.w3.org/2000/svg"!==a.namespaceURI||"innerHTML"in a)a.innerHTML=b;else{Xd=Xd||document.createElement("div");Xd.innerHTML="<svg>"+b.valueOf().toString()+"</svg>";for(b=Xd.firstChild;a.firstChild;)a.removeChild(a.firstChild);for(;b.firstChild;)a.appendChild(b.firstChild)}}),Fc=function(a,b){if(b){var c=a.firstChild;if(c&&c===a.lastChild&&3===c.nodeType){c.nodeValue=b;return}}a.textContent=b},dc={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,
borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,
strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},$k=["Webkit","ms","Moz","O"];Object.keys(dc).forEach(function(a){$k.forEach(function(b){b=b+a.charAt(0).toUpperCase()+a.substring(1);dc[b]=dc[a]})});var ij=E({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0}),ze=null,se=null,Eb=null,Fb=null,xg=function(a,b){return a(b)},yg=function(){},te=!1,Oe=!1;if(Ia)try{var Lc={};Object.defineProperty(Lc,
"passive",{get:function(){Oe=!0}});window.addEventListener("test",Lc,Lc);window.removeEventListener("test",Lc,Lc)}catch(a){Oe=!1}var kj=function(a,b,c,d,e,f,g,h,k){var l=Array.prototype.slice.call(arguments,3);try{b.apply(c,l)}catch(q){this.onError(q)}},gc=!1,Sc=null,Tc=!1,ue=null,lj={onError:function(a){gc=!0;Sc=a}},Ba=zb.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Scheduler,Jg=Ba.unstable_scheduleCallback,Kg=Ba.unstable_NormalPriority,xh=Jg,Ki=Ba.unstable_cancelCallback,Pk=Ba.unstable_shouldYield,
Sk=Ba.unstable_requestPaint,P=Ba.unstable_now,Dj=Ba.unstable_getCurrentPriorityLevel,De=Ba.unstable_ImmediatePriority,Mg=Ba.unstable_UserBlockingPriority,ad=Kg,Ej=Ba.unstable_LowPriority,Ng=Ba.unstable_IdlePriority,Uc=null,Ca=null,ta=Math.clz32?Math.clz32:pj,qj=Math.log,rj=Math.LN2,Wc=64,Rd=4194304,z=0,Ae=!1,Yc=[],Va=null,Wa=null,Xa=null,jc=new Map,kc=new Map,Ya=[],Bj="mousedown mouseup touchcancel touchend touchstart auxclick dblclick pointercancel pointerdown pointerup dragend dragstart drop compositionend compositionstart keydown keypress keyup input textInput copy cut paste click change contextmenu reset submit".split(" "),
Gb=Sa.ReactCurrentBatchConfig,Zc=!0,$c=null,Za=null,Ee=null,bd=null,Yb={eventPhase:0,bubbles:0,cancelable:0,timeStamp:function(a){return a.timeStamp||Date.now()},defaultPrevented:0,isTrusted:0},He=ka(Yb),Mc=E({},Yb,{view:0,detail:0}),ak=ka(Mc),ag,bg,Nc,Yd=E({},Mc,{screenX:0,screenY:0,clientX:0,clientY:0,pageX:0,pageY:0,ctrlKey:0,shiftKey:0,altKey:0,metaKey:0,getModifierState:Fe,button:0,buttons:0,relatedTarget:function(a){return void 0===a.relatedTarget?a.fromElement===a.srcElement?a.toElement:a.fromElement:
a.relatedTarget},movementX:function(a){if("movementX"in a)return a.movementX;a!==Nc&&(Nc&&"mousemove"===a.type?(ag=a.screenX-Nc.screenX,bg=a.screenY-Nc.screenY):bg=ag=0,Nc=a);return ag},movementY:function(a){return"movementY"in a?a.movementY:bg}}),ih=ka(Yd),al=E({},Yd,{dataTransfer:0}),Wj=ka(al),bl=E({},Mc,{relatedTarget:0}),Pe=ka(bl),cl=E({},Yb,{animationName:0,elapsedTime:0,pseudoElement:0}),Yj=ka(cl),dl=E({},Yb,{clipboardData:function(a){return"clipboardData"in a?a.clipboardData:window.clipboardData}}),
ck=ka(dl),el=E({},Yb,{data:0}),qh=ka(el),fk=qh,fl={Esc:"Escape",Spacebar:" ",Left:"ArrowLeft",Up:"ArrowUp",Right:"ArrowRight",Down:"ArrowDown",Del:"Delete",Win:"OS",Menu:"ContextMenu",Apps:"ContextMenu",Scroll:"ScrollLock",MozPrintableKey:"Unidentified"},gl={8:"Backspace",9:"Tab",12:"Clear",13:"Enter",16:"Shift",17:"Control",18:"Alt",19:"Pause",20:"CapsLock",27:"Escape",32:" ",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"ArrowLeft",38:"ArrowUp",39:"ArrowRight",40:"ArrowDown",45:"Insert",46:"Delete",
112:"F1",113:"F2",114:"F3",115:"F4",116:"F5",117:"F6",118:"F7",119:"F8",120:"F9",121:"F10",122:"F11",123:"F12",144:"NumLock",145:"ScrollLock",224:"Meta"},Gj={Alt:"altKey",Control:"ctrlKey",Meta:"metaKey",Shift:"shiftKey"},hl=E({},Mc,{key:function(a){if(a.key){var b=fl[a.key]||a.key;if("Unidentified"!==b)return b}return"keypress"===a.type?(a=cd(a),13===a?"Enter":String.fromCharCode(a)):"keydown"===a.type||"keyup"===a.type?gl[a.keyCode]||"Unidentified":""},code:0,location:0,ctrlKey:0,shiftKey:0,altKey:0,
metaKey:0,repeat:0,locale:0,getModifierState:Fe,charCode:function(a){return"keypress"===a.type?cd(a):0},keyCode:function(a){return"keydown"===a.type||"keyup"===a.type?a.keyCode:0},which:function(a){return"keypress"===a.type?cd(a):"keydown"===a.type||"keyup"===a.type?a.keyCode:0}}),Vj=ka(hl),il=E({},Yd,{pointerId:0,width:0,height:0,pressure:0,tangentialPressure:0,tiltX:0,tiltY:0,twist:0,pointerType:0,isPrimary:0}),nh=ka(il),jl=E({},Mc,{touches:0,targetTouches:0,changedTouches:0,altKey:0,metaKey:0,
ctrlKey:0,shiftKey:0,getModifierState:Fe}),Xj=ka(jl),kl=E({},Yb,{propertyName:0,elapsedTime:0,pseudoElement:0}),Zj=ka(kl),ll=E({},Yd,{deltaX:function(a){return"deltaX"in a?a.deltaX:"wheelDeltaX"in a?-a.wheelDeltaX:0},deltaY:function(a){return"deltaY"in a?a.deltaY:"wheelDeltaY"in a?-a.wheelDeltaY:"wheelDelta"in a?-a.wheelDelta:0},deltaZ:0,deltaMode:0}),bk=ka(ll),Hj=[9,13,27,32],Ge=Ia&&"CompositionEvent"in window,Oc=null;Ia&&"documentMode"in document&&(Oc=document.documentMode);var ek=Ia&&"TextEvent"in
window&&!Oc,Ug=Ia&&(!Ge||Oc&&8<Oc&&11>=Oc),Tg=String.fromCharCode(32),Sg=!1,Hb=!1,Kj={color:!0,date:!0,datetime:!0,"datetime-local":!0,email:!0,month:!0,number:!0,password:!0,range:!0,search:!0,tel:!0,text:!0,time:!0,url:!0,week:!0},oc=null,pc=null,ph=!1;Ia&&(ph=Lj("input")&&(!document.documentMode||9<document.documentMode));var ua="function"===typeof Object.is?Object.is:Sj,dk=Ia&&"documentMode"in document&&11>=document.documentMode,Jb=null,Ke=null,rc=null,Je=!1,Kb={animationend:gd("Animation","AnimationEnd"),
animationiteration:gd("Animation","AnimationIteration"),animationstart:gd("Animation","AnimationStart"),transitionend:gd("Transition","TransitionEnd")},Le={},eh={};Ia&&(eh=document.createElement("div").style,"AnimationEvent"in window||(delete Kb.animationend.animation,delete Kb.animationiteration.animation,delete Kb.animationstart.animation),"TransitionEvent"in window||delete Kb.transitionend.transition);var jh=hd("animationend"),kh=hd("animationiteration"),lh=hd("animationstart"),mh=hd("transitionend"),
fh=new Map,Zi="abort auxClick cancel canPlay canPlayThrough click close contextMenu copy cut drag dragEnd dragEnter dragExit dragLeave dragOver dragStart drop durationChange emptied encrypted ended error gotPointerCapture input invalid keyDown keyPress keyUp load loadedData loadedMetadata loadStart lostPointerCapture mouseDown mouseMove mouseOut mouseOver mouseUp paste pause play playing pointerCancel pointerDown pointerMove pointerOut pointerOver pointerUp progress rateChange reset resize seeked seeking stalled submit suspend timeUpdate touchCancel touchEnd touchStart volumeChange scroll toggle touchMove waiting wheel".split(" ");
(function(){for(var a=0;a<Zi.length;a++){var b=Zi[a],c=b.toLowerCase();b=b[0].toUpperCase()+b.slice(1);$a(c,"on"+b)}$a(jh,"onAnimationEnd");$a(kh,"onAnimationIteration");$a(lh,"onAnimationStart");$a("dblclick","onDoubleClick");$a("focusin","onFocus");$a("focusout","onBlur");$a(mh,"onTransitionEnd")})();Ab("onMouseEnter",["mouseout","mouseover"]);Ab("onMouseLeave",["mouseout","mouseover"]);Ab("onPointerEnter",["pointerout","pointerover"]);Ab("onPointerLeave",["pointerout","pointerover"]);mb("onChange",
"change click focusin focusout input keydown keyup selectionchange".split(" "));mb("onSelect","focusout contextmenu dragend focusin keydown keyup mousedown mouseup selectionchange".split(" "));mb("onBeforeInput",["compositionend","keypress","textInput","paste"]);mb("onCompositionEnd","compositionend focusout keydown keypress keyup mousedown".split(" "));mb("onCompositionStart","compositionstart focusout keydown keypress keyup mousedown".split(" "));mb("onCompositionUpdate","compositionupdate focusout keydown keypress keyup mousedown".split(" "));
var Ec="abort canplay canplaythrough durationchange emptied encrypted ended error loadeddata loadedmetadata loadstart pause play playing progress ratechange resize seeked seeking stalled suspend timeupdate volumechange waiting".split(" "),Uj=new Set("cancel close invalid load scroll toggle".split(" ").concat(Ec)),id="_reactListening"+Math.random().toString(36).slice(2),gk=/\r\n?/g,hk=/\u0000|\uFFFD/g,Jf=null,Kf=null,Rf="function"===typeof setTimeout?setTimeout:void 0,Nk="function"===typeof clearTimeout?
clearTimeout:void 0,$i="function"===typeof Promise?Promise:void 0,Jk="function"===typeof queueMicrotask?queueMicrotask:"undefined"!==typeof $i?function(a){return $i.resolve(null).then(a).catch(ik)}:Rf,Zb=Math.random().toString(36).slice(2),Da="__reactFiber$"+Zb,uc="__reactProps$"+Zb,Ja="__reactContainer$"+Zb,Me="__reactEvents$"+Zb,Dk="__reactListeners$"+Zb,Ek="__reactHandles$"+Zb,Se=[],Mb=-1,cb={},J=bb(cb),S=bb(!1),pb=cb,La=null,md=!1,Te=!1,Ob=[],Pb=0,od=null,nd=0,na=[],oa=0,rb=null,Ma=1,Na="",la=
null,fa=null,D=!1,wa=null,Ik=Sa.ReactCurrentBatchConfig,Vb=Dh(!0),li=Dh(!1),ud=bb(null),td=null,Rb=null,bf=null,tb=null,kk=Oa,gb=!1,wc={},Ea=bb(wc),yc=bb(wc),xc=bb(wc),F=bb(0),kf=[],yd=Sa.ReactCurrentDispatcher,sf=Sa.ReactCurrentBatchConfig,vb=0,C=null,K=null,N=null,Ad=!1,zc=!1,Ac=0,ml=0,zd={readContext:qa,useCallback:V,useContext:V,useEffect:V,useImperativeHandle:V,useInsertionEffect:V,useLayoutEffect:V,useMemo:V,useReducer:V,useRef:V,useState:V,useDebugValue:V,useDeferredValue:V,useTransition:V,
useMutableSource:V,useSyncExternalStore:V,useId:V,unstable_isNewReconciler:!1},lk={readContext:qa,useCallback:function(a,b){Fa().memoizedState=[a,void 0===b?null:b];return a},useContext:qa,useEffect:Sh,useImperativeHandle:function(a,b,c){c=null!==c&&void 0!==c?c.concat([a]):null;return Bd(4194308,4,Vh.bind(null,b,a),c)},useLayoutEffect:function(a,b){return Bd(4194308,4,a,b)},useInsertionEffect:function(a,b){return Bd(4,2,a,b)},useMemo:function(a,b){var c=Fa();b=void 0===b?null:b;a=a();c.memoizedState=
[a,b];return a},useReducer:function(a,b,c){var d=Fa();b=void 0!==c?c(b):b;d.memoizedState=d.baseState=b;a={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:a,lastRenderedState:b};d.queue=a;a=a.dispatch=qk.bind(null,C,a);return[d.memoizedState,a]},useRef:function(a){var b=Fa();a={current:a};return b.memoizedState=a},useState:Qh,useDebugValue:rf,useDeferredValue:function(a){return Fa().memoizedState=a},useTransition:function(){var a=Qh(!1),b=a[0];a=pk.bind(null,a[1]);Fa().memoizedState=
a;return[b,a]},useMutableSource:function(a,b,c){},useSyncExternalStore:function(a,b,c){var d=C,e=Fa();if(D){if(void 0===c)throw Error(m(407));c=c()}else{c=b();if(null===O)throw Error(m(349));0!==(vb&30)||Nh(d,b,c)}e.memoizedState=c;var f={value:c,getSnapshot:b};e.queue=f;Sh(Lh.bind(null,d,f,a),[a]);d.flags|=2048;Cc(9,Mh.bind(null,d,f,c,b),void 0,null);return c},useId:function(){var a=Fa(),b=O.identifierPrefix;if(D){var c=Na;var d=Ma;c=(d&~(1<<32-ta(d)-1)).toString(32)+c;b=":"+b+"R"+c;c=Ac++;0<c&&
(b+="H"+c.toString(32));b+=":"}else c=ml++,b=":"+b+"r"+c.toString(32)+":";return a.memoizedState=b},unstable_isNewReconciler:!1},mk={readContext:qa,useCallback:Xh,useContext:qa,useEffect:qf,useImperativeHandle:Wh,useInsertionEffect:Th,useLayoutEffect:Uh,useMemo:Yh,useReducer:of,useRef:Rh,useState:function(a){return of(Bc)},useDebugValue:rf,useDeferredValue:function(a){var b=sa();return Zh(b,K.memoizedState,a)},useTransition:function(){var a=of(Bc)[0],b=sa().memoizedState;return[a,b]},useMutableSource:Jh,
useSyncExternalStore:Kh,useId:$h,unstable_isNewReconciler:!1},nk={readContext:qa,useCallback:Xh,useContext:qa,useEffect:qf,useImperativeHandle:Wh,useInsertionEffect:Th,useLayoutEffect:Uh,useMemo:Yh,useReducer:pf,useRef:Rh,useState:function(a){return pf(Bc)},useDebugValue:rf,useDeferredValue:function(a){var b=sa();return null===K?b.memoizedState=a:Zh(b,K.memoizedState,a)},useTransition:function(){var a=pf(Bc)[0],b=sa().memoizedState;return[a,b]},useMutableSource:Jh,useSyncExternalStore:Kh,useId:$h,
unstable_isNewReconciler:!1},Dd={isMounted:function(a){return(a=a._reactInternals)?nb(a)===a:!1},enqueueSetState:function(a,b,c){a=a._reactInternals;var d=Z(),e=hb(a),f=Pa(d,e);f.payload=b;void 0!==c&&null!==c&&(f.callback=c);b=fb(a,f,e);null!==b&&(xa(b,a,e,d),vd(b,a,e))},enqueueReplaceState:function(a,b,c){a=a._reactInternals;var d=Z(),e=hb(a),f=Pa(d,e);f.tag=1;f.payload=b;void 0!==c&&null!==c&&(f.callback=c);b=fb(a,f,e);null!==b&&(xa(b,a,e,d),vd(b,a,e))},enqueueForceUpdate:function(a,b){a=a._reactInternals;
var c=Z(),d=hb(a),e=Pa(c,d);e.tag=2;void 0!==b&&null!==b&&(e.callback=b);b=fb(a,e,d);null!==b&&(xa(b,a,d,c),vd(b,a,d))}},rk="function"===typeof WeakMap?WeakMap:Map,tk=Sa.ReactCurrentOwner,ha=!1,Cf={dehydrated:null,treeContext:null,retryLane:0};var zk=function(a,b,c,d){for(c=b.child;null!==c;){if(5===c.tag||6===c.tag)a.appendChild(c.stateNode);else if(4!==c.tag&&null!==c.child){c.child.return=c;c=c.child;continue}if(c===b)break;for(;null===c.sibling;){if(null===c.return||c.return===b)return;c=c.return}c.sibling.return=
c.return;c=c.sibling}};var xi=function(a,b){};var yk=function(a,b,c,d,e){var f=a.memoizedProps;if(f!==d){a=b.stateNode;ub(Ea.current);e=null;switch(c){case "input":f=ke(a,f);d=ke(a,d);e=[];break;case "select":f=E({},f,{value:void 0});d=E({},d,{value:void 0});e=[];break;case "textarea":f=ne(a,f);d=ne(a,d);e=[];break;default:"function"!==typeof f.onClick&&"function"===typeof d.onClick&&(a.onclick=kd)}pe(c,d);var g;c=null;for(l in f)if(!d.hasOwnProperty(l)&&f.hasOwnProperty(l)&&null!=f[l])if("style"===
l){var h=f[l];for(g in h)h.hasOwnProperty(g)&&(c||(c={}),c[g]="")}else"dangerouslySetInnerHTML"!==l&&"children"!==l&&"suppressContentEditableWarning"!==l&&"suppressHydrationWarning"!==l&&"autoFocus"!==l&&($b.hasOwnProperty(l)?e||(e=[]):(e=e||[]).push(l,null));for(l in d){var k=d[l];h=null!=f?f[l]:void 0;if(d.hasOwnProperty(l)&&k!==h&&(null!=k||null!=h))if("style"===l)if(h){for(g in h)!h.hasOwnProperty(g)||k&&k.hasOwnProperty(g)||(c||(c={}),c[g]="");for(g in k)k.hasOwnProperty(g)&&h[g]!==k[g]&&(c||
(c={}),c[g]=k[g])}else c||(e||(e=[]),e.push(l,c)),c=k;else"dangerouslySetInnerHTML"===l?(k=k?k.__html:void 0,h=h?h.__html:void 0,null!=k&&h!==k&&(e=e||[]).push(l,k)):"children"===l?"string"!==typeof k&&"number"!==typeof k||(e=e||[]).push(l,""+k):"suppressContentEditableWarning"!==l&&"suppressHydrationWarning"!==l&&($b.hasOwnProperty(l)?(null!=k&&"onScroll"===l&&B("scroll",a),e||h===k||(e=[])):(e=e||[]).push(l,k))}c&&(e=e||[]).push("style",c);var l=e;if(b.updateQueue=l)b.flags|=4}};var Ak=function(a,
b,c,d){c!==d&&(b.flags|=4)};var Jd=!1,X=!1,Fk="function"===typeof WeakSet?WeakSet:Set,l=null,zi=!1,T=null,za=!1,Mk=Math.ceil,Od=Sa.ReactCurrentDispatcher,Uf=Sa.ReactCurrentOwner,ca=Sa.ReactCurrentBatchConfig,p=0,O=null,H=null,U=0,ba=0,Ga=bb(0),L=0,Jc=null,ra=0,Md=0,Sf=0,Kc=null,ja=null,Of=0,Hf=Infinity,Ra=null,Ed=!1,xf=null,ib=null,Pd=!1,lb=null,Qd=0,Ic=0,Pf=null,Kd=-1,Ld=0;var Qk=function(a,b,c){if(null!==a)if(a.memoizedProps!==b.pendingProps||S.current)ha=!0;else{if(0===(a.lanes&c)&&0===(b.flags&
128))return ha=!1,wk(a,b,c);ha=0!==(a.flags&131072)?!0:!1}else ha=!1,D&&0!==(b.flags&1048576)&&yh(b,nd,b.index);b.lanes=0;switch(b.tag){case 2:var d=b.type;Fd(a,b);a=b.pendingProps;var e=Nb(b,J.current);Sb(b,c);e=mf(null,b,d,a,e,c);var f=nf();b.flags|=1;"object"===typeof e&&null!==e&&"function"===typeof e.render&&void 0===e.$$typeof?(b.tag=1,b.memoizedState=null,b.updateQueue=null,ea(d)?(f=!0,ld(b)):f=!1,b.memoizedState=null!==e.state&&void 0!==e.state?e.state:null,ff(b),e.updater=Dd,b.stateNode=
e,e._reactInternals=b,uf(b,d,a,c),b=Af(null,b,d,!0,f,c)):(b.tag=0,D&&f&&Ue(b),aa(null,b,e,c),b=b.child);return b;case 16:d=b.elementType;a:{Fd(a,b);a=b.pendingProps;e=d._init;d=e(d._payload);b.type=d;e=b.tag=Uk(d);a=ya(d,a);switch(e){case 0:b=zf(null,b,d,a,c);break a;case 1:b=ri(null,b,d,a,c);break a;case 11:b=mi(null,b,d,a,c);break a;case 14:b=ni(null,b,d,ya(d.type,a),c);break a}throw Error(m(306,d,""));}return b;case 0:return d=b.type,e=b.pendingProps,e=b.elementType===d?e:ya(d,e),zf(a,b,d,e,c);
case 1:return d=b.type,e=b.pendingProps,e=b.elementType===d?e:ya(d,e),ri(a,b,d,e,c);case 3:a:{si(b);if(null===a)throw Error(m(387));d=b.pendingProps;f=b.memoizedState;e=f.element;Fh(a,b);wd(b,d,null,c);var g=b.memoizedState;d=g.element;if(f.isDehydrated)if(f={element:d,isDehydrated:!1,cache:g.cache,pendingSuspenseBoundaries:g.pendingSuspenseBoundaries,transitions:g.transitions},b.updateQueue.baseState=f,b.memoizedState=f,b.flags&256){e=Ub(Error(m(423)),b);b=ti(a,b,d,c,e);break a}else if(d!==e){e=
Ub(Error(m(424)),b);b=ti(a,b,d,c,e);break a}else for(fa=Ka(b.stateNode.containerInfo.firstChild),la=b,D=!0,wa=null,c=li(b,null,d,c),b.child=c;c;)c.flags=c.flags&-3|4096,c=c.sibling;else{Qb();if(d===e){b=Qa(a,b,c);break a}aa(a,b,d,c)}b=b.child}return b;case 5:return Ih(b),null===a&&Xe(b),d=b.type,e=b.pendingProps,f=null!==a?a.memoizedProps:null,g=e.children,Qe(d,e)?g=null:null!==f&&Qe(d,f)&&(b.flags|=32),qi(a,b),aa(a,b,g,c),b.child;case 6:return null===a&&Xe(b),null;case 13:return ui(a,b,c);case 4:return gf(b,
b.stateNode.containerInfo),d=b.pendingProps,null===a?b.child=Vb(b,null,d,c):aa(a,b,d,c),b.child;case 11:return d=b.type,e=b.pendingProps,e=b.elementType===d?e:ya(d,e),mi(a,b,d,e,c);case 7:return aa(a,b,b.pendingProps,c),b.child;case 8:return aa(a,b,b.pendingProps.children,c),b.child;case 12:return aa(a,b,b.pendingProps.children,c),b.child;case 10:a:{d=b.type._context;e=b.pendingProps;f=b.memoizedProps;g=e.value;y(ud,d._currentValue);d._currentValue=g;if(null!==f)if(ua(f.value,g)){if(f.children===
e.children&&!S.current){b=Qa(a,b,c);break a}}else for(f=b.child,null!==f&&(f.return=b);null!==f;){var h=f.dependencies;if(null!==h){g=f.child;for(var k=h.firstContext;null!==k;){if(k.context===d){if(1===f.tag){k=Pa(-1,c&-c);k.tag=2;var l=f.updateQueue;if(null!==l){l=l.shared;var p=l.pending;null===p?k.next=k:(k.next=p.next,p.next=k);l.pending=k}}f.lanes|=c;k=f.alternate;null!==k&&(k.lanes|=c);df(f.return,c,b);h.lanes|=c;break}k=k.next}}else if(10===f.tag)g=f.type===b.type?null:f.child;else if(18===
f.tag){g=f.return;if(null===g)throw Error(m(341));g.lanes|=c;h=g.alternate;null!==h&&(h.lanes|=c);df(g,c,b);g=f.sibling}else g=f.child;if(null!==g)g.return=f;else for(g=f;null!==g;){if(g===b){g=null;break}f=g.sibling;if(null!==f){f.return=g.return;g=f;break}g=g.return}f=g}aa(a,b,e.children,c);b=b.child}return b;case 9:return e=b.type,d=b.pendingProps.children,Sb(b,c),e=qa(e),d=d(e),b.flags|=1,aa(a,b,d,c),b.child;case 14:return d=b.type,e=ya(d,b.pendingProps),e=ya(d.type,e),ni(a,b,d,e,c);case 15:return oi(a,
b,b.type,b.pendingProps,c);case 17:return d=b.type,e=b.pendingProps,e=b.elementType===d?e:ya(d,e),Fd(a,b),b.tag=1,ea(d)?(a=!0,ld(b)):a=!1,Sb(b,c),ei(b,d,e),uf(b,d,e,c),Af(null,b,d,!0,a,c);case 19:return wi(a,b,c);case 22:return pi(a,b,c)}throw Error(m(156,b.tag));};var pa=function(a,b,c,d){return new Tk(a,b,c,d)},aj="function"===typeof reportError?reportError:function(a){console.error(a)};Ud.prototype.render=Xf.prototype.render=function(a){var b=this._internalRoot;if(null===b)throw Error(m(409));
Sd(a,b,null,null)};Ud.prototype.unmount=Xf.prototype.unmount=function(){var a=this._internalRoot;if(null!==a){this._internalRoot=null;var b=a.containerInfo;yb(function(){Sd(null,a,null,null)});b[Ja]=null}};Ud.prototype.unstable_scheduleHydration=function(a){if(a){var b=nl();a={blockedOn:null,target:a,priority:b};for(var c=0;c<Ya.length&&0!==b&&b<Ya[c].priority;c++);Ya.splice(c,0,a);0===c&&Hg(a)}};var Cj=function(a){switch(a.tag){case 3:var b=a.stateNode;if(b.current.memoizedState.isDehydrated){var c=
hc(b.pendingLanes);0!==c&&(xe(b,c|1),ia(b,P()),0===(p&6)&&(Hc(),db()))}break;case 13:yb(function(){var b=Oa(a,1);if(null!==b){var c=Z();xa(b,a,1,c)}}),Wf(a,1)}};var Gg=function(a){if(13===a.tag){var b=Oa(a,134217728);if(null!==b){var c=Z();xa(b,a,134217728,c)}Wf(a,134217728)}};var xj=function(a){if(13===a.tag){var b=hb(a),c=Oa(a,b);if(null!==c){var d=Z();xa(c,a,b,d)}Wf(a,b)}};var nl=function(){return z};var wj=function(a,b){var c=z;try{return z=a,b()}finally{z=c}};se=function(a,b,c){switch(b){case "input":le(a,
c);b=c.name;if("radio"===c.type&&null!=b){for(c=a;c.parentNode;)c=c.parentNode;c=c.querySelectorAll("input[name="+JSON.stringify(""+b)+'][type="radio"]');for(b=0;b<c.length;b++){var d=c[b];if(d!==a&&d.form===a.form){var e=Rc(d);if(!e)throw Error(m(90));jg(d);le(d,e)}}}break;case "textarea":og(a,c);break;case "select":b=c.value,null!=b&&Db(a,!!c.multiple,b,!1)}};(function(a,b,c){xg=a;yg=c})(Tf,function(a,b,c,d,e){var f=z,g=ca.transition;try{return ca.transition=null,z=1,a(b,c,d,e)}finally{z=f,ca.transition=
g,0===p&&Hc()}},yb);var ol={usingClientEntryPoint:!1,Events:[ec,Ib,Rc,ug,vg,Tf]};(function(a){a={bundleType:a.bundleType,version:a.version,rendererPackageName:a.rendererPackageName,rendererConfig:a.rendererConfig,overrideHookState:null,overrideHookStateDeletePath:null,overrideHookStateRenamePath:null,overrideProps:null,overridePropsDeletePath:null,overridePropsRenamePath:null,setErrorHandler:null,setSuspenseHandler:null,scheduleUpdate:null,currentDispatcherRef:Sa.ReactCurrentDispatcher,findHostInstanceByFiber:Xk,
findFiberByHostInstance:a.findFiberByHostInstance||Yk,findHostInstancesForRefresh:null,scheduleRefresh:null,scheduleRoot:null,setRefreshHandler:null,getCurrentFiber:null,reconcilerVersion:"18.3.1"};if("undefined"===typeof __REACT_DEVTOOLS_GLOBAL_HOOK__)a=!1;else{var b=__REACT_DEVTOOLS_GLOBAL_HOOK__;if(b.isDisabled||!b.supportsFiber)a=!0;else{try{Uc=b.inject(a),Ca=b}catch(c){}a=b.checkDCE?!0:!1}}return a})({findFiberByHostInstance:ob,bundleType:0,version:"18.3.1-next-f1338f8080-20240426",
rendererPackageName:"react-dom"});Q.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=ol;Q.createPortal=function(a,b){var c=2<arguments.length&&void 0!==arguments[2]?arguments[2]:null;if(!Yf(b))throw Error(m(200));return Wk(a,b,null,c)};Q.createRoot=function(a,b){if(!Yf(a))throw Error(m(299));var c=!1,d="",e=aj;null!==b&&void 0!==b&&(!0===b.unstable_strictMode&&(c=!0),void 0!==b.identifierPrefix&&(d=b.identifierPrefix),void 0!==b.onRecoverableError&&(e=b.onRecoverableError));b=Vf(a,1,!1,null,null,
c,!1,d,e);a[Ja]=b.current;sc(8===a.nodeType?a.parentNode:a);return new Xf(b)};Q.findDOMNode=function(a){if(null==a)return null;if(1===a.nodeType)return a;var b=a._reactInternals;if(void 0===b){if("function"===typeof a.render)throw Error(m(188));a=Object.keys(a).join(",");throw Error(m(268,a));}a=Bg(b);a=null===a?null:a.stateNode;return a};Q.flushSync=function(a){return yb(a)};Q.hydrate=function(a,b,c){if(!Vd(b))throw Error(m(200));return Wd(null,a,b,!0,c)};Q.hydrateRoot=function(a,b,c){if(!Yf(a))throw Error(m(405));
var d=null!=c&&c.hydratedSources||null,e=!1,f="",g=aj;null!==c&&void 0!==c&&(!0===c.unstable_strictMode&&(e=!0),void 0!==c.identifierPrefix&&(f=c.identifierPrefix),void 0!==c.onRecoverableError&&(g=c.onRecoverableError));b=Wi(b,null,a,1,null!=c?c:null,e,!1,f,g);a[Ja]=b.current;sc(a);if(d)for(a=0;a<d.length;a++)c=d[a],e=c._getVersion,e=e(c._source),null==b.mutableSourceEagerHydrationData?b.mutableSourceEagerHydrationData=[c,e]:b.mutableSourceEagerHydrationData.push(c,e);return new Ud(b)};Q.render=
function(a,b,c){if(!Vd(b))throw Error(m(200));return Wd(null,a,b,!1,c)};Q.unmountComponentAtNode=function(a){if(!Vd(a))throw Error(m(40));return a._reactRootContainer?(yb(function(){Wd(null,null,a,!1,function(){a._reactRootContainer=null;a[Ja]=null})}),!0):!1};Q.unstable_batchedUpdates=Tf;Q.unstable_renderSubtreeIntoContainer=function(a,b,c,d){if(!Vd(c))throw Error(m(200));if(null==a||void 0===a._reactInternals)throw Error(m(38));return Wd(a,b,c,!1,d)};Q.version="18.3.1-next-f1338f8080-20240426"});
})();
</script>
<!-- data.jsx: test-only seed data — not loaded by default.
To run with sample data, uncomment the line below:
<script type="text/babel" src="data.jsx"></script> -->
<script>
// Shared helpers, status definitions, filter engine, icons.
const STATUSES = [{
key: "open",
glyph: "[ ]",
label: "Open"
}, {
key: "in-progress",
glyph: "[/]",
label: "In progress"
}, {
key: "blocked",
glyph: "[!]",
label: "Blocked"
}, {
key: "postponed",
glyph: "[>]",
label: "Postponed"
}, {
key: "done",
glyph: "[x]",
label: "Done"
}, {
key: "cancelled",
glyph: "[-]",
label: "Cancelled"
}];
const STATUS_BY_KEY = Object.fromEntries(STATUSES.map(s => [s.key, s]));
const STATUS_ORDER = STATUSES.map(s => s.key);
const PRIORITIES = ["P0", "P1", "P2", "P3"];
// ---- date helpers ----
function parseDate(s) {
return s ? new Date(s + "T12:00:00Z") : null;
}
function daysBetween(a, b) {
return Math.round((a - b) / 86400000);
}
function isOverdue(item) {
if (!item.due || item.status === "done" || item.status === "cancelled") return false;
return parseDate(item.due) < new Date();
}
function dueRelative(item) {
if (!item.due) return null;
const d = daysBetween(parseDate(item.due), new Date());
if (d < 0) return `${-d}d overdue`;
if (d === 0) return "today";
if (d === 1) return "tomorrow";
if (d < 7) return `in ${d}d`;
if (d < 30) return `in ${Math.round(d / 7)}w`;
return item.due;
}
function fmtTimestamp(iso) {
if (!iso) return "—";
const d = new Date(iso);
const diff = (Date.now() - d.getTime()) / 1000;
if (diff < 60) return "just now";
if (diff < 3600) return `${Math.round(diff / 60)}m ago`;
if (diff < 86400) return `${Math.round(diff / 3600)}h ago`;
if (diff < 86400 * 7) return `${Math.round(diff / 86400)}d ago`;
return d.toISOString().slice(0, 10);
}
function fmtBytes(b) {
if (b < 1024) return `${b} B`;
if (b < 1024 * 1024) return `${(b / 1024).toFixed(1)} KB`;
return `${(b / 1024 / 1024).toFixed(2)} MB`;
}
const fmtRelative = fmtTimestamp;
function fmtShortDate(iso) {
if (!iso) return "—";
const d = new Date(iso);
const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
return `${months[d.getMonth()]} ${d.getDate()}, ${d.getFullYear()}`;
}
// ---- tree helpers ----
function walkTree(items, fn, depth = 0, parent = null) {
for (const it of items) {
fn(it, depth, parent);
if (it.children?.length) walkTree(it.children, fn, depth + 1, it);
}
}
function findItem(items, id) {
for (const it of items) {
if (it.id === id) return it;
if (it.children?.length) {
const f = findItem(it.children, id);
if (f) return f;
}
}
return null;
}
function allTags(items) {
const counts = new Map();
walkTree(items, it => (it.tags || []).forEach(t => counts.set(t, (counts.get(t) || 0) + 1)));
return [...counts.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).map(([t]) => t);
}
function countAll(items) {
let n = 0;
walkTree(items, () => n++);
return n;
}
function countByStatus(items) {
const c = Object.fromEntries(STATUSES.map(s => [s.key, 0]));
walkTree(items, it => {
c[it.status] = (c[it.status] || 0) + 1;
});
return c;
}
// ---- filter engine with parent-visibility rule ----
function filterTree(items, f) {
function matches(it) {
if (f.statuses?.length && !f.statuses.includes(it.status)) return false;
if (f.priorities?.length && !f.priorities.includes(it.priority)) return false;
if (f.tags?.length && !(it.tags || []).some(t => f.tags.includes(t))) return false;
if (f.dueRange) {
const overdue = isOverdue(it);
const d = it.due ? daysBetween(parseDate(it.due), new Date()) : null;
if (f.dueRange === "overdue" && !overdue) return false;
if (f.dueRange === "today" && !(d === 0)) return false;
if (f.dueRange === "week" && !(d !== null && d >= 0 && d <= 7)) return false;
if (f.dueRange === "month" && !(d !== null && d >= 0 && d <= 30)) return false;
}
if (f.text) {
const q = f.text.toLowerCase();
const hay = [it.title, it.reason, ...(it.tags || [])].filter(Boolean).join(" ").toLowerCase();
if (!hay.includes(q)) return false;
}
return true;
}
function recur(list) {
const out = [];
for (const it of list) {
const kids = it.children?.length ? recur(it.children) : [];
const self = matches(it);
if (self || kids.length) {
out.push({
...it,
children: kids,
_matches: self
});
}
}
return out;
}
return recur(items);
}
// ---- status visuals (4 styles, switchable via Tweaks) ----
// styles: "flat" (minimal monochrome SVG, inherits status color),
// "ascii" (original [/], [x] etc),
// "color" (filled colored icons, ChatGPT-style — green check, red blocked, etc),
// "emoji" (expressive native emoji — ✅ 🚧 ⏸ etc)
// Self-contained color palette for the "color" style — does NOT inherit currentColor.
const STATUS_COLORS = {
"open": {
stroke: "oklch(0.62 0.01 70)",
fill: "transparent"
},
"in-progress": {
stroke: "oklch(0.55 0.16 230)",
fill: "oklch(0.62 0.16 230)"
},
"blocked": {
stroke: "oklch(0.50 0.20 28)",
fill: "oklch(0.62 0.20 28)"
},
"postponed": {
stroke: "oklch(0.55 0.13 290)",
fill: "oklch(0.65 0.13 290)"
},
"done": {
stroke: "oklch(0.48 0.16 145)",
fill: "oklch(0.60 0.16 145)"
},
"cancelled": {
stroke: "oklch(0.55 0.01 70)",
fill: "oklch(0.65 0.01 70)"
}
};
// Expressive emoji pack — chosen for clarity at small sizes (avoid round colored dots).
const STATUS_EMOJI = {
"open": "⬜",
"in-progress": "✏️",
"blocked": "🚧",
"postponed": "⏸️",
"done": "✅",
"cancelled": "❌"
};
// Context so every StatusIcon in the tree picks up the current style automatically.
const StatusStyleContext = React.createContext("flat");
function StatusIcon({
status,
style,
size = 14
}) {
const ctx = React.useContext(StatusStyleContext);
style = style || ctx || "flat";
if (style === "ascii") {
return /*#__PURE__*/React.createElement("span", {
className: `glyph-ascii status-${status}`
}, STATUS_BY_KEY[status].glyph);
}
if (style === "color") {
return /*#__PURE__*/React.createElement(ColorStatusIcon, {
status: status,
size: size
});
}
if (style === "emoji") {
return /*#__PURE__*/React.createElement("span", {
className: "glyph-emoji",
style: {
fontSize: size + 2,
lineHeight: 1
}
}, STATUS_EMOJI[status]);
}
// flat — minimalistic SVG icons (square family, no circles)
const c = "currentColor";
const wrap = children => /*#__PURE__*/React.createElement("svg", {
width: size + 2,
height: size + 2,
viewBox: "0 0 16 16",
className: `glyph-flat status-${status}`
}, children);
switch (status) {
case "open":
// empty square outline
return wrap(/*#__PURE__*/React.createElement("rect", {
x: "2.5",
y: "2.5",
width: "11",
height: "11",
rx: "2",
fill: "none",
stroke: c,
strokeWidth: "1.4"
}));
case "in-progress":
// half-filled square (left filled)
return wrap(/*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("rect", {
x: "2.5",
y: "2.5",
width: "11",
height: "11",
rx: "2",
fill: "none",
stroke: c,
strokeWidth: "1.4"
}), /*#__PURE__*/React.createElement("path", {
d: "M3.5 3.5 H8 V12.5 H3.5 Z",
fill: c
})));
case "blocked":
// filled square with horizontal bar (no entry)
return wrap(/*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("rect", {
x: "2.5",
y: "2.5",
width: "11",
height: "11",
rx: "2",
fill: c
}), /*#__PURE__*/React.createElement("rect", {
x: "4.5",
y: "7.2",
width: "7",
height: "1.6",
rx: "0.5",
fill: "white"
})));
case "postponed":
// square with right-pointing chevron (deferred)
return wrap(/*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("rect", {
x: "2.5",
y: "2.5",
width: "11",
height: "11",
rx: "2",
fill: "none",
stroke: c,
strokeWidth: "1.4"
}), /*#__PURE__*/React.createElement("polyline", {
points: "6,5.5 9,8 6,10.5",
fill: "none",
stroke: c,
strokeWidth: "1.5",
strokeLinecap: "round",
strokeLinejoin: "round"
})));
case "done":
// filled square with checkmark
return wrap(/*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("rect", {
x: "2.5",
y: "2.5",
width: "11",
height: "11",
rx: "2",
fill: c
}), /*#__PURE__*/React.createElement("polyline", {
points: "5,8 7,10.2 11,5.8",
fill: "none",
stroke: "white",
strokeWidth: "1.7",
strokeLinecap: "round",
strokeLinejoin: "round"
})));
case "cancelled":
// outlined square with single clean diagonal slash
return wrap(/*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("rect", {
x: "2.5",
y: "2.5",
width: "11",
height: "11",
rx: "2",
fill: "none",
stroke: c,
strokeWidth: "1.4"
}), /*#__PURE__*/React.createElement("line", {
x1: "3.5",
y1: "12.5",
x2: "12.5",
y2: "3.5",
stroke: c,
strokeWidth: "1.6",
strokeLinecap: "round"
})));
default:
return null;
}
}
// ---- color status icons (ChatGPT / Linear / GitHub style) ----
// Filled circles with semantic colors and white glyphs. Self-coloring,
// not affected by currentColor — looks good on any background.
function ColorStatusIcon({
status,
size = 14
}) {
const c = STATUS_COLORS[status] || STATUS_COLORS.open;
const w = size + 2;
const cx = 8,
cy = 8,
r = 6.4;
switch (status) {
case "open":
// empty circle — thin gray ring
return /*#__PURE__*/React.createElement("svg", {
width: w,
height: w,
viewBox: "0 0 16 16",
className: `glyph-color status-${status}`
}, /*#__PURE__*/React.createElement("circle", {
cx: cx,
cy: cy,
r: r,
fill: "none",
stroke: c.stroke,
strokeWidth: "1.5"
}));
case "in-progress":
// half-filled pie (clockwise 50%) — Linear-style "in progress"
return /*#__PURE__*/React.createElement("svg", {
width: w,
height: w,
viewBox: "0 0 16 16",
className: `glyph-color status-${status}`
}, /*#__PURE__*/React.createElement("circle", {
cx: cx,
cy: cy,
r: r,
fill: "none",
stroke: c.fill,
strokeWidth: "1.5"
}), /*#__PURE__*/React.createElement("path", {
d: `M 8 1.6 A 6.4 6.4 0 0 1 8 14.4 Z`,
fill: c.fill
}));
case "blocked":
// red filled circle with white horizontal bar
return /*#__PURE__*/React.createElement("svg", {
width: w,
height: w,
viewBox: "0 0 16 16",
className: `glyph-color status-${status}`
}, /*#__PURE__*/React.createElement("circle", {
cx: cx,
cy: cy,
r: r,
fill: c.fill
}), /*#__PURE__*/React.createElement("rect", {
x: "4.6",
y: "7.2",
width: "6.8",
height: "1.6",
rx: "0.8",
fill: "white"
}));
case "postponed":
// purple filled circle with white right-chevron
return /*#__PURE__*/React.createElement("svg", {
width: w,
height: w,
viewBox: "0 0 16 16",
className: `glyph-color status-${status}`
}, /*#__PURE__*/React.createElement("circle", {
cx: cx,
cy: cy,
r: r,
fill: c.fill
}), /*#__PURE__*/React.createElement("polyline", {
points: "6.4,5.4 9.4,8 6.4,10.6",
fill: "none",
stroke: "white",
strokeWidth: "1.6",
strokeLinecap: "round",
strokeLinejoin: "round"
}));
case "done":
// green filled circle with white check
return /*#__PURE__*/React.createElement("svg", {
width: w,
height: w,
viewBox: "0 0 16 16",
className: `glyph-color status-${status}`
}, /*#__PURE__*/React.createElement("circle", {
cx: cx,
cy: cy,
r: r,
fill: c.fill
}), /*#__PURE__*/React.createElement("polyline", {
points: "5,8.2 7.2,10.3 11,5.9",
fill: "none",
stroke: "white",
strokeWidth: "1.7",
strokeLinecap: "round",
strokeLinejoin: "round"
}));
case "cancelled":
// gray filled circle with white X
return /*#__PURE__*/React.createElement("svg", {
width: w,
height: w,
viewBox: "0 0 16 16",
className: `glyph-color status-${status}`
}, /*#__PURE__*/React.createElement("circle", {
cx: cx,
cy: cy,
r: r,
fill: c.fill
}), /*#__PURE__*/React.createElement("g", {
stroke: "white",
strokeWidth: "1.6",
strokeLinecap: "round"
}, /*#__PURE__*/React.createElement("line", {
x1: "5.6",
y1: "5.6",
x2: "10.4",
y2: "10.4"
}), /*#__PURE__*/React.createElement("line", {
x1: "10.4",
y1: "5.6",
x2: "5.6",
y2: "10.4"
})));
default:
return null;
}
}
// ---- icons (inline SVG) ----
const Icon = ({
name,
size = 14
}) => {
const paths = {
chevron: /*#__PURE__*/React.createElement("polyline", {
points: "5,8 10,13 15,8",
fill: "none",
stroke: "currentColor",
strokeWidth: "1.6",
strokeLinecap: "round",
strokeLinejoin: "round"
}),
chevronRight: /*#__PURE__*/React.createElement("polyline", {
points: "8,5 13,10 8,15",
fill: "none",
stroke: "currentColor",
strokeWidth: "1.6",
strokeLinecap: "round",
strokeLinejoin: "round"
}),
plus: /*#__PURE__*/React.createElement("g", {
stroke: "currentColor",
strokeWidth: "1.6",
strokeLinecap: "round"
}, /*#__PURE__*/React.createElement("line", {
x1: "10",
y1: "4",
x2: "10",
y2: "16"
}), /*#__PURE__*/React.createElement("line", {
x1: "4",
y1: "10",
x2: "16",
y2: "10"
})),
search: /*#__PURE__*/React.createElement("g", {
fill: "none",
stroke: "currentColor",
strokeWidth: "1.6",
strokeLinecap: "round"
}, /*#__PURE__*/React.createElement("circle", {
cx: "9",
cy: "9",
r: "5"
}), /*#__PURE__*/React.createElement("line", {
x1: "13",
y1: "13",
x2: "17",
y2: "17"
})),
drag: /*#__PURE__*/React.createElement("g", {
fill: "currentColor"
}, /*#__PURE__*/React.createElement("circle", {
cx: "7",
cy: "5",
r: "1.2"
}), /*#__PURE__*/React.createElement("circle", {
cx: "13",
cy: "5",
r: "1.2"
}), /*#__PURE__*/React.createElement("circle", {
cx: "7",
cy: "10",
r: "1.2"
}), /*#__PURE__*/React.createElement("circle", {
cx: "13",
cy: "10",
r: "1.2"
}), /*#__PURE__*/React.createElement("circle", {
cx: "7",
cy: "15",
r: "1.2"
}), /*#__PURE__*/React.createElement("circle", {
cx: "13",
cy: "15",
r: "1.2"
})),
trash: /*#__PURE__*/React.createElement("g", {
fill: "none",
stroke: "currentColor",
strokeWidth: "1.5",
strokeLinecap: "round"
}, /*#__PURE__*/React.createElement("path", {
d: "M5 6h10M8 6V4h4v2M6 6l1 10h6l1-10"
})),
cog: /*#__PURE__*/React.createElement("g", {
fill: "none",
stroke: "currentColor",
strokeWidth: "1.5"
}, /*#__PURE__*/React.createElement("circle", {
cx: "10",
cy: "10",
r: "2.6"
}), /*#__PURE__*/React.createElement("path", {
d: "M10 2v2M10 16v2M2 10h2M16 10h2M4.3 4.3l1.4 1.4M14.3 14.3l1.4 1.4M4.3 15.7l1.4-1.4M14.3 5.7l1.4-1.4"
})),
list: /*#__PURE__*/React.createElement("g", {
fill: "none",
stroke: "currentColor",
strokeWidth: "1.6",
strokeLinecap: "round"
}, /*#__PURE__*/React.createElement("line", {
x1: "6",
y1: "6",
x2: "16",
y2: "6"
}), /*#__PURE__*/React.createElement("line", {
x1: "6",
y1: "10",
x2: "16",
y2: "10"
}), /*#__PURE__*/React.createElement("line", {
x1: "6",
y1: "14",
x2: "16",
y2: "14"
}), /*#__PURE__*/React.createElement("circle", {
cx: "3.5",
cy: "6",
r: "0.6",
fill: "currentColor"
}), /*#__PURE__*/React.createElement("circle", {
cx: "3.5",
cy: "10",
r: "0.6",
fill: "currentColor"
}), /*#__PURE__*/React.createElement("circle", {
cx: "3.5",
cy: "14",
r: "0.6",
fill: "currentColor"
})),
check: /*#__PURE__*/React.createElement("polyline", {
points: "4,10 8,14 16,5",
fill: "none",
stroke: "currentColor",
strokeWidth: "1.8",
strokeLinecap: "round",
strokeLinejoin: "round"
}),
download: /*#__PURE__*/React.createElement("g", {
fill: "none",
stroke: "currentColor",
strokeWidth: "1.5",
strokeLinecap: "round",
strokeLinejoin: "round"
}, /*#__PURE__*/React.createElement("path", {
d: "M10 3v10M5 9l5 5 5-5M3 17h14"
})),
upload: /*#__PURE__*/React.createElement("g", {
fill: "none",
stroke: "currentColor",
strokeWidth: "1.5",
strokeLinecap: "round",
strokeLinejoin: "round"
}, /*#__PURE__*/React.createElement("path", {
d: "M10 16V4M5 9l5-5 5 5M3 17h14"
})),
save: /*#__PURE__*/React.createElement("g", {
fill: "none",
stroke: "currentColor",
strokeWidth: "1.5",
strokeLinejoin: "round"
}, /*#__PURE__*/React.createElement("path", {
d: "M4 4h9l3 3v9H4z"
}), /*#__PURE__*/React.createElement("path", {
d: "M7 4v4h6V4M7 16v-5h6v5"
})),
refresh: /*#__PURE__*/React.createElement("g", {
fill: "none",
stroke: "currentColor",
strokeWidth: "1.5",
strokeLinecap: "round",
strokeLinejoin: "round"
}, /*#__PURE__*/React.createElement("path", {
d: "M3 10a7 7 0 0 1 12-5l2 2"
}), /*#__PURE__*/React.createElement("path", {
d: "M17 4v3h-3"
}), /*#__PURE__*/React.createElement("path", {
d: "M17 10a7 7 0 0 1-12 5l-2-2"
}), /*#__PURE__*/React.createElement("path", {
d: "M3 16v-3h3"
})),
warn: /*#__PURE__*/React.createElement("g", {
fill: "none",
stroke: "currentColor",
strokeWidth: "1.5",
strokeLinecap: "round",
strokeLinejoin: "round"
}, /*#__PURE__*/React.createElement("path", {
d: "M10 3l8 14H2z"
}), /*#__PURE__*/React.createElement("line", {
x1: "10",
y1: "8",
x2: "10",
y2: "12"
}), /*#__PURE__*/React.createElement("circle", {
cx: "10",
cy: "14.5",
r: "0.6",
fill: "currentColor"
})),
eye: /*#__PURE__*/React.createElement("g", {
fill: "none",
stroke: "currentColor",
strokeWidth: "1.5"
}, /*#__PURE__*/React.createElement("path", {
d: "M2 10s3-5 8-5 8 5 8 5-3 5-8 5-8-5-8-5z"
}), /*#__PURE__*/React.createElement("circle", {
cx: "10",
cy: "10",
r: "2"
})),
archive: /*#__PURE__*/React.createElement("g", {
fill: "none",
stroke: "currentColor",
strokeWidth: "1.5",
strokeLinejoin: "round"
}, /*#__PURE__*/React.createElement("rect", {
x: "3",
y: "5",
width: "14",
height: "3"
}), /*#__PURE__*/React.createElement("path", {
d: "M4 8v9h12V8"
}), /*#__PURE__*/React.createElement("line", {
x1: "8",
y1: "11",
x2: "12",
y2: "11"
})),
edit: /*#__PURE__*/React.createElement("g", {
fill: "none",
stroke: "currentColor",
strokeWidth: "1.5",
strokeLinecap: "round",
strokeLinejoin: "round"
}, /*#__PURE__*/React.createElement("path", {
d: "M4 14v2h2l8-8-2-2-8 8z"
}), /*#__PURE__*/React.createElement("path", {
d: "M12 4l2 2"
})),
addChild: /*#__PURE__*/React.createElement("g", {
fill: "none",
stroke: "currentColor",
strokeWidth: "1.5",
strokeLinecap: "round",
strokeLinejoin: "round"
}, /*#__PURE__*/React.createElement("path", {
d: "M5 4v6a3 3 0 0 0 3 3h4"
}), /*#__PURE__*/React.createElement("line", {
x1: "14",
y1: "13",
x2: "14",
y2: "17"
}), /*#__PURE__*/React.createElement("line", {
x1: "12",
y1: "15",
x2: "16",
y2: "15"
})),
copy: /*#__PURE__*/React.createElement("g", {
fill: "none",
stroke: "currentColor",
strokeWidth: "1.5",
strokeLinecap: "round",
strokeLinejoin: "round"
}, /*#__PURE__*/React.createElement("rect", {
x: "7",
y: "3",
width: "10",
height: "12",
rx: "1.5"
}), /*#__PURE__*/React.createElement("path", {
d: "M13 17H4a1 1 0 0 1-1-1V6"
})),
statusDots: /*#__PURE__*/React.createElement("g", {
fill: "currentColor"
}, /*#__PURE__*/React.createElement("circle", {
cx: "5",
cy: "10",
r: "1.6"
}), /*#__PURE__*/React.createElement("circle", {
cx: "10",
cy: "10",
r: "1.6"
}), /*#__PURE__*/React.createElement("circle", {
cx: "15",
cy: "10",
r: "1.6"
}))
};
return /*#__PURE__*/React.createElement("svg", {
width: size,
height: size,
viewBox: "0 0 20 20",
style: {
display: "inline-block",
verticalAlign: "middle",
flexShrink: 0
}
}, paths[name]);
};
// --- Progress (completion %) ---
// Quantized to 0/25/50/75/100 — coarse on purpose; tasks are rarely "73% done".
const PROGRESS_STEPS = [0, 25, 50, 75, 100];
function snapProgress(p) {
if (p == null || isNaN(p)) return 0;
if (p <= 0) return 0;
if (p >= 100) return 100;
// round to nearest 25
return Math.round(p / 25) * 25;
}
// Effective progress: done is always 100 regardless of stored value;
// cancelled returns null (don't render).
function progressFor(item) {
if (item.status === "done") return 100;
if (item.status === "cancelled") return null;
return snapProgress(item.progress ?? 0);
}
// When progress should be visible inline. Done shows nothing (line-through is enough).
// Open shows only if user explicitly set >0.
function shouldShowProgress(item) {
if (item.status === "cancelled") return false;
if (item.status === "done") return false;
if (item.status === "open") return (item.progress ?? 0) > 0;
return true; // in-progress, blocked, postponed (always visible, including at 100%)
}
// Click to advance through 0/25/50/75/100, wrapping.
function cycleProgress(p) {
const i = PROGRESS_STEPS.indexOf(snapProgress(p));
return PROGRESS_STEPS[(i + 1) % PROGRESS_STEPS.length];
}
// 4-segment gauge (visual representation of 0/25/50/75/100).
// 0 = empty, 100 = all 4 filled.
function ProgressGauge({
value,
onClick,
interactive = false,
size = "sm"
}) {
const v = snapProgress(value);
const filled = v / 25; // 0..4
const segs = [0, 1, 2, 3].map(i => i < filled);
return /*#__PURE__*/React.createElement("span", {
className: `gauge ${interactive ? "gauge-interactive" : ""} gauge-${size} gauge-v-${v}`,
onClick: onClick,
role: interactive ? "button" : undefined,
tabIndex: interactive ? 0 : undefined,
title: `${v}% complete${interactive ? " — click to change" : ""}`,
"aria-label": `Progress ${v} percent`
}, segs.map((on, i) => /*#__PURE__*/React.createElement("span", {
key: i,
className: `gauge-seg ${on ? "on" : ""}`
})), /*#__PURE__*/React.createElement("span", {
className: "gauge-num"
}, v, "%"));
}
Object.assign(window, {
STATUSES,
STATUS_BY_KEY,
STATUS_ORDER,
PRIORITIES,
parseDate,
daysBetween,
isOverdue,
dueRelative,
fmtTimestamp,
fmtBytes,
fmtRelative,
fmtShortDate,
walkTree,
findItem,
allTags,
countAll,
countByStatus,
filterTree,
Icon,
StatusIcon,
ColorStatusIcon,
STATUS_COLORS,
STATUS_EMOJI,
StatusStyleContext,
PROGRESS_STEPS,
snapProgress,
progressFor,
shouldShowProgress,
cycleProgress,
ProgressGauge
});
</script>
<script>
// Storage layer: Parser, ApiBackend, DirectBackend, Storage detection, SyncPoller.
// Compatible with web/index.html and server/server.py file format.
//
// File format (backlog.md):
// # Backlog
// <!-- SECTION: ENTRIES -->
// - [ ] [P1] Title *(due: ..., reason: ..., tags: tag1 tag2, progress: 50)*
// - [x] [P0] Child *(progress: 100)*
// <!-- SECTION: HISTORY -->
// | Timestamp | Item ID | Action | Details |
// <!-- SECTION: INTEGRITY -->
// <!-- saved: ... | checksum: sha256:... | entries: N | history: N -->
// ---- Parser ----
const Parser = {
async parse(text) {
if (!text || !text.trim()) {
return {
entries: [],
history: [],
meta: null,
checksumOk: false
};
}
const entStart = text.indexOf('<!-- SECTION: ENTRIES -->');
const histStart = text.indexOf('<!-- SECTION: HISTORY -->');
const intStart = text.indexOf('<!-- SECTION: INTEGRITY -->');
const entriesText = entStart !== -1 ? text.slice(entStart, histStart !== -1 ? histStart : intStart !== -1 ? intStart : text.length) : text;
const historyText = histStart !== -1 ? text.slice(histStart, intStart !== -1 ? intStart : text.length) : '';
// Parse integrity marker
let meta = null;
let checksumOk = false;
if (intStart !== -1) {
const m = text.slice(intStart).match(/saved:\s*([^|]+?)\s*\|\s*checksum:\s*([^|]+?)\s*\|\s*entries:\s*(\d+)\s*\|\s*history:\s*(\d+)/);
if (m) {
meta = {
saved: m[1].trim(),
checksum: m[2].trim(),
entryCount: +m[3],
historyCount: +m[4]
};
// Strip section-marker prefix + surrounding whitespace to get raw content,
// matching server.py's compute_checksum() which uses raw (marker-free) payload.
const rawEnt = entriesText.slice('<!-- SECTION: ENTRIES -->'.length).trim();
const rawHist = historyText.slice('<!-- SECTION: HISTORY -->'.length).trim();
const payload = rawEnt + '\n' + rawHist;
const buf = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(payload));
const hash = 'sha256:' + Array.from(new Uint8Array(buf)).map(b => b.toString(16).padStart(2, '0')).join('');
checksumOk = hash === meta.checksum;
}
}
// Parse history table
const history = [];
for (const line of historyText.split('\n')) {
if (!line.trim().startsWith('|')) continue;
const parts = line.split('|').map(s => s.trim()).filter(Boolean);
if (parts.length >= 4 && parts[0] !== 'Timestamp' && !parts[0].match(/^-+$/)) {
history.push({
timestamp: parts[0],
itemId: parts[1],
action: parts[2],
details: parts[3]
});
}
}
// Parse entries (indented markdown list)
const GLYPH_MAP = {
' ': 'open',
'x': 'done',
'!': 'blocked',
'>': 'postponed',
'/': 'in-progress',
'-': 'cancelled'
};
let idSeq = Date.now();
const uid = () => 'i-' + (++idSeq).toString(36);
const entries = [];
const stack = [{
children: entries,
depth: -1,
level: 0
}];
for (const line of entriesText.split('\n')) {
const m = line.match(/^(\s*)[-*]\s*\[([ x!>/\-])\]\s*(.*)$/);
if (!m) continue;
const depth = m[1].length / 2;
const status = GLYPH_MAP[m[2]] || 'open';
const raw = m[3].trim();
let title = raw,
due = null,
reason = null,
tags = [],
priority = 'P1',
progress = 0;
const metaM = raw.match(/^(.*?)\s*\*\((.*)\)\*\s*$/);
if (metaM) {
title = metaM[1].trim();
for (const p of metaM[2].split(',').map(s => s.trim())) {
if (p.startsWith('due:')) due = p.slice(4).trim();else if (p.startsWith('reason:')) reason = p.slice(7).trim();else if (p.startsWith('tags:')) tags = p.slice(5).trim().split(/\s+/).filter(Boolean);else if (p.startsWith('priority:')) priority = p.slice(9).trim().toUpperCase();else if (p.startsWith('progress:')) progress = parseInt(p.slice(9).trim(), 10) || 0;
}
}
// Priority prefix [P0] embedded in title
const pm = title.match(/^\[(P\d)\]\s*/);
if (pm) {
priority = pm[1];
title = title.slice(pm[0].length);
}
while (stack.length > 1 && stack[stack.length - 1].depth >= depth) stack.pop();
const parentLevel = stack[stack.length - 1].level;
const item = {
id: uid(),
level: parentLevel + 1,
title,
status,
priority,
due,
reason,
tags,
progress: status === 'done' ? 100 : progress,
collapsed: false,
children: []
};
stack[stack.length - 1].children.push(item);
stack.push({
children: item.children,
depth,
level: item.level
});
}
return {
entries,
history,
meta,
checksumOk
};
},
async serialize(data) {
const entriesText = this._serializeEntries(data.entries);
const historyText = this._serializeHistory(data.history);
const payload = entriesText + '\n' + historyText;
const buf = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(payload));
const hash = 'sha256:' + Array.from(new Uint8Array(buf)).map(b => b.toString(16).padStart(2, '0')).join('');
const saved = new Date().toISOString().slice(0, 19) + 'Z';
const nEntries = this._countItems(data.entries);
const nHistory = data.history.length;
const marker = `<!-- saved: ${saved} | checksum: ${hash} | entries: ${nEntries} | history: ${nHistory} -->`;
return `# Backlog\n\n<!-- SECTION: ENTRIES -->\n\n${entriesText}\n\n<!-- SECTION: HISTORY -->\n\n${historyText}\n\n<!-- SECTION: INTEGRITY -->\n\n${marker}\n`;
},
_serializeEntries(items, depth = 0) {
const indent = ' '.repeat(depth);
const GLYPH = {
open: ' ',
'in-progress': '/',
blocked: '!',
postponed: '>',
done: 'x',
cancelled: '-'
};
const lines = [];
for (const it of items) {
const meta = [];
if (it.due) meta.push(`due: ${it.due}`);
if (it.reason) meta.push(`reason: ${it.reason}`);
if (it.tags?.length) meta.push(`tags: ${it.tags.join(' ')}`);
if (it.priority && it.priority !== 'P1') meta.push(`priority: ${it.priority}`);
if ((it.progress ?? 0) > 0) meta.push(`progress: ${it.progress}`);
const metaStr = meta.length ? ` *(${meta.join(', ')})*` : '';
const prefix = it.priority ? `[${it.priority}] ` : '';
lines.push(`${indent}- [${GLYPH[it.status] || ' '}] ${prefix}${it.title}${metaStr}`);
if (it.children?.length) {
lines.push(...this._serializeEntries(it.children, depth + 1).split('\n'));
}
}
return lines.join('\n');
},
_serializeHistory(rows) {
const lines = ['| Timestamp | Item ID | Action | Details |', '|-----------|---------|--------|---------|'];
for (const r of rows) lines.push(`| ${r.timestamp} | ${r.itemId} | ${r.action} | ${r.details} |`);
return lines.join('\n');
},
_countItems(items) {
let n = 0;
for (const it of items) {
n++;
n += this._countItems(it.children || []);
}
return n;
}
};
// ---- API Backend (python server.py) ----
const ApiBackend = {
async detect() {
if (location.protocol === 'file:') return false; // no server in file:// context
const ctrl = new AbortController();
const t = setTimeout(() => ctrl.abort(), 800);
try {
const r = await fetch('/api/health', {
signal: ctrl.signal
});
clearTimeout(t);
return r.ok;
} catch {
clearTimeout(t);
return false;
}
},
async load() {
const r = await fetch('/api/backlog');
if (!r.ok) throw new Error('API load failed: ' + r.status);
return r.json(); // { content, checksum }
},
async save(content) {
const r = await fetch('/api/backlog', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
content
})
});
if (!r.ok) throw new Error('API save failed: ' + r.status);
return r.json(); // { ok, checksum, saved }
},
async listBackups() {
try {
const r = await fetch('/api/backups');
if (!r.ok) return [];
return (await r.json()).backups || [];
} catch {
return [];
}
},
async restoreBackup(name) {
const r = await fetch('/api/backups/restore', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name
})
});
return r.ok ? r.json() : {
ok: false
};
},
async getHealthInfo() {
try {
const r = await fetch('/api/health');
if (!r.ok) return {};
const j = await r.json();
return {
masterSize: j.masterSize || 0,
statsSize: 0,
masterPath: j.masterPath || '',
backupsPath: j.backupsPath || ''
};
} catch {
return {};
}
}
};
// ---- Direct File Backend (File System Access API) ----
const DirectBackend = {
dirHandle: null,
_DB_NAME: 'pb-storage-v2',
_STORE: 'handles',
_KEY: 'root',
async detect() {
return typeof window.showDirectoryPicker === 'function';
},
// Silent reconnect — no user gesture. Returns true if the stored handle
// is still accessible and permission is already granted.
async tryAutoConnect() {
this.dirHandle = await this._loadHandle();
if (!this.dirHandle) return false;
try {
return (await this.dirHandle.queryPermission({
mode: 'readwrite'
})) === 'granted';
} catch {
return false;
}
},
// Explicit connect — requires a user gesture (button click).
// Shows the directory picker on first use; re-prompts for permission on subsequent uses.
async connect() {
let handle = await this._loadHandle();
if (!handle) {
handle = await window.showDirectoryPicker({
mode: 'readwrite'
});
await this._saveHandle(handle);
}
const perm = await handle.requestPermission({
mode: 'readwrite'
});
if (perm !== 'granted') throw new Error('Permission denied');
this.dirHandle = handle;
},
_loadHandle() {
return new Promise(res => {
const req = indexedDB.open(this._DB_NAME, 1);
req.onupgradeneeded = e => e.target.result.createObjectStore(this._STORE);
req.onsuccess = e => {
const get = e.target.result.transaction(this._STORE, 'readonly').objectStore(this._STORE).get(this._KEY);
get.onsuccess = () => res(get.result || null);
get.onerror = () => res(null);
};
req.onerror = () => res(null);
});
},
_saveHandle(handle) {
return new Promise((res, rej) => {
const req = indexedDB.open(this._DB_NAME, 1);
req.onsuccess = e => {
const tx = e.target.result.transaction(this._STORE, 'readwrite');
tx.objectStore(this._STORE).put(handle, this._KEY);
tx.oncomplete = () => res();
tx.onerror = () => rej(tx.error);
};
});
},
async _readFile(name) {
try {
const h = await this.dirHandle.getFileHandle(name);
return (await h.getFile()).text();
} catch {
return null;
}
},
async _writeFile(name, content, dirHandle) {
const dir = dirHandle || this.dirHandle;
const h = await dir.getFileHandle(name, {
create: true
});
const w = await h.createWritable();
await w.write(content);
await w.close();
},
async load() {
const content = await this._readFile('backlog.md');
return {
content: content || '',
checksum: ''
};
},
async save(content) {
await this._writeFile('backlog.md', content);
// Create backup
try {
const ts = new Date().toISOString().slice(0, 19).replace(/[:T]/g, '-');
const dir = await this.dirHandle.getDirectoryHandle('backups', {
create: true
});
await this._writeFile(`backlog_${ts}.md`, content, dir);
} catch {/* backup failure is non-fatal */}
return {
ok: true
};
},
async listBackups() {
try {
const dir = await this.dirHandle.getDirectoryHandle('backups', {
create: true
});
const backups = [];
for await (const [name, h] of dir.entries()) {
if (!name.startsWith('backlog_') || !name.endsWith('.md')) continue;
const f = await h.getFile();
const text = await f.text();
backups.push({
name,
size: f.size,
timestamp: new Date(f.lastModified).toISOString(),
valid: text.includes('<!-- SECTION: INTEGRITY -->')
});
}
return backups.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
} catch {
return [];
}
},
async restoreBackup(name) {
try {
const dir = await this.dirHandle.getDirectoryHandle('backups');
const h = await dir.getFileHandle(name);
const text = await (await h.getFile()).text();
await this._writeFile('backlog.md', text);
return {
ok: true
};
} catch (e) {
return {
ok: false,
error: e.message
};
}
},
async getHealthInfo() {
try {
const f = await (await this.dirHandle.getFileHandle('backlog.md')).getFile();
return {
masterSize: f.size,
statsSize: 0,
dirName: this.dirHandle?.name ?? null
};
} catch {
return {
masterSize: 0,
statsSize: 0,
dirName: this.dirHandle?.name ?? null
};
}
}
};
// ---- Browser Storage Backend (IndexedDB + Storage Persistence API) ----
// Fallback for browsers without File System Access API (Firefox, Safari)
const BrowserStorageBackend = {
_DB_NAME: 'pb-browser-storage',
_STORE: 'data',
_CONTENT_KEY: 'backlog',
_BACKUPS_KEY: 'backups',
_MAX_BACKUPS: 10,
_persistenceRequested: false,
_persistenceGranted: null,
async detect() {
return typeof indexedDB !== 'undefined';
},
_openDB() {
return new Promise((resolve, reject) => {
const req = indexedDB.open(this._DB_NAME, 1);
req.onupgradeneeded = e => e.target.result.createObjectStore(this._STORE);
req.onsuccess = e => resolve(e.target.result);
req.onerror = () => reject(req.error);
});
},
async _get(key) {
const db = await this._openDB();
return new Promise(resolve => {
const tx = db.transaction(this._STORE, 'readonly');
const get = tx.objectStore(this._STORE).get(key);
get.onsuccess = () => resolve(get.result);
get.onerror = () => resolve(null);
});
},
async _set(key, value) {
const db = await this._openDB();
return new Promise((resolve, reject) => {
const tx = db.transaction(this._STORE, 'readwrite');
tx.objectStore(this._STORE).put(value, key);
tx.oncomplete = () => resolve();
tx.onerror = () => reject(tx.error);
});
},
async load() {
try {
const content = (await this._get(this._CONTENT_KEY)) || '';
return {
content,
checksum: ''
};
} catch {
return {
content: '',
checksum: ''
};
}
},
async save(content) {
// Request persistence on first save (triggered by user action = valid gesture)
if (!this._persistenceRequested) {
this._persistenceRequested = true;
this._requestPersistence();
}
try {
// Create backup before saving
const oldContent = await this._get(this._CONTENT_KEY);
if (oldContent) {
await this._addBackup(oldContent);
}
await this._set(this._CONTENT_KEY, content);
return {
ok: true
};
} catch (e) {
return {
ok: false,
error: e.message
};
}
},
async _requestPersistence() {
if (navigator.storage?.persist) {
try {
const alreadyPersisted = await navigator.storage.persisted();
if (alreadyPersisted) {
this._persistenceGranted = true;
return;
}
// This will prompt the user in Firefox
this._persistenceGranted = await navigator.storage.persist();
} catch {
this._persistenceGranted = false;
}
}
},
async _addBackup(content) {
try {
const backups = (await this._get(this._BACKUPS_KEY)) || [];
const ts = new Date().toISOString().slice(0, 19).replace(/[:T]/g, '-');
backups.unshift({
name: `backlog_${ts}.md`,
content,
timestamp: new Date().toISOString(),
size: new TextEncoder().encode(content).length
});
// Keep only last N backups
if (backups.length > this._MAX_BACKUPS) {
backups.length = this._MAX_BACKUPS;
}
await this._set(this._BACKUPS_KEY, backups);
} catch {/* backup failure is non-fatal */}
},
async listBackups() {
try {
const backups = (await this._get(this._BACKUPS_KEY)) || [];
return backups.map(b => ({
name: b.name,
size: b.size,
timestamp: b.timestamp,
valid: b.content?.includes('<!-- SECTION: INTEGRITY -->')
}));
} catch {
return [];
}
},
async restoreBackup(name) {
try {
const backups = (await this._get(this._BACKUPS_KEY)) || [];
const backup = backups.find(b => b.name === name);
if (!backup) return {
ok: false,
error: 'Backup not found'
};
await this._set(this._CONTENT_KEY, backup.content);
return {
ok: true
};
} catch (e) {
return {
ok: false,
error: e.message
};
}
},
async getHealthInfo() {
try {
const content = (await this._get(this._CONTENT_KEY)) || '';
const estimate = (await navigator.storage?.estimate?.()) || {};
const persisted = (await navigator.storage?.persisted?.()) || false;
return {
masterSize: new TextEncoder().encode(content).length,
statsSize: 0,
browserStorage: true,
persisted,
quota: estimate.quota,
usage: estimate.usage
};
} catch {
return {
masterSize: 0,
statsSize: 0,
browserStorage: true,
persisted: false
};
}
}
};
// ---- Storage — detect backend and delegate ----
const Storage = {
backend: null,
mode: 'local',
// 'api' | 'direct' | 'local'
async detect() {
if (await ApiBackend.detect()) {
this.backend = ApiBackend;
this.mode = 'api';
return 'api';
}
if (await DirectBackend.detect()) {
this.backend = DirectBackend;
this.mode = 'direct';
return 'direct';
}
if (await BrowserStorageBackend.detect()) {
this.backend = BrowserStorageBackend;
this.mode = 'browser';
return 'browser';
}
this.mode = 'local';
return 'local';
},
// Try to reconnect silently (no user gesture). Returns true if connected.
// For API mode this is always true; for Direct it checks the stored handle.
async tryAutoConnect() {
if (this.backend === DirectBackend) return DirectBackend.tryAutoConnect();
return true;
},
// Explicit connect — call from a user-gesture handler (button click).
async connect() {
if (this.backend === DirectBackend) await DirectBackend.connect();
},
// True only when a backend is detected AND fully initialised (dirHandle set for Direct).
isConnected() {
if (!this.backend) return false;
if (this.backend === DirectBackend) return !!DirectBackend.dirHandle;
return true;
},
async load() {
return this.backend?.load() ?? null;
},
async save(content) {
return this.backend?.save(content) ?? null;
},
async listBackups() {
return this.backend?.listBackups() ?? [];
},
async restoreBackup(name) {
return this.backend?.restoreBackup(name) ?? {
ok: false
};
},
async getHealthInfo() {
return this.backend?.getHealthInfo?.() ?? {};
}
};
// ---- SyncPoller — detect external file changes (5s interval) ----
const SyncPoller = {
_timer: null,
lastChecksum: '',
_onExternalChange: null,
_isDirty: null,
start({
onExternalChange,
isDirty
}) {
this._onExternalChange = onExternalChange;
this._isDirty = isDirty;
this._timer = setInterval(() => this._tick(), 5000);
},
stop() {
if (this._timer) {
clearInterval(this._timer);
this._timer = null;
}
},
async _tick() {
if (Storage.mode === 'local' || !Storage.backend) return;
try {
const raw = await Storage.load();
if (!raw?.content) return;
const parsed = await Parser.parse(raw.content);
const cs = parsed.meta?.checksum || '';
if (!cs || cs === this.lastChecksum) return;
this.lastChecksum = cs;
if (this._isDirty?.()) {
this._onExternalChange?.('warn', null);
} else {
this._onExternalChange?.('reload', parsed);
}
} catch {/* silent on poll errors */}
}
};
// ---- buildDataFromStorage — assemble the full App data object from parsed content ----
async function buildDataFromStorage(parsed, backups, storageMode, sizeInfo = {}) {
const {
entries,
history,
meta,
checksumOk
} = parsed;
// Assign level field (derived from tree depth, not stored in file)
function setLevels(items, level) {
for (const it of items) {
it.level = level;
if (it.children?.length) setLevels(it.children, level + 1);
}
}
setLevels(entries, 1);
// Migrate: ensure progress field is always a number
const progressDefaults = {
done: 100,
cancelled: 0,
'in-progress': 50,
blocked: 25,
postponed: 25,
open: 0
};
walkTree(entries, it => {
if (typeof it.progress !== 'number') it.progress = progressDefaults[it.status] ?? 0;else if (it.status === 'done') it.progress = 100;
});
// Status counts
const statusMix = {
open: 0,
'in-progress': 0,
blocked: 0,
postponed: 0,
done: 0,
cancelled: 0
};
walkTree(entries, it => {
statusMix[it.status] = (statusMix[it.status] || 0) + 1;
});
// Most active item by history event count
const actCounts = {};
walkTree(entries, it => {
actCounts[it.id] = 0;
});
for (const h of history) {
if (h.itemId in actCounts) actCounts[h.itemId]++;
}
const topId = Object.entries(actCounts).sort((a, b) => b[1] - a[1])[0]?.[0];
const topItem = topId ? findItem(entries, topId) : null;
const mostActiveProject = topItem?.title || entries[0]?.title || '—';
// Recent activity (last 7 days)
const sevenAgo = new Date(Date.now() - 7 * 86400000).toISOString();
const recentH = history.filter(h => h.timestamp >= sevenAgo);
const createdThisWeek = recentH.filter(h => h.action === 'item_created').length;
const completedThisWeek = recentH.filter(h => h.action === 'status_changed' && h.details.includes('→ done')).length;
const dayNames = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
const completionByDay = dayNames.map(day => ({
day,
count: 0
}));
const createdByDay = dayNames.map(day => ({
day,
count: 0
}));
for (const h of recentH) {
const dow = (new Date(h.timestamp).getDay() + 6) % 7; // 0=Mon
if (h.action === 'status_changed' && h.details.includes('→ done')) completionByDay[dow].count++;
if (h.action === 'item_created') createdByDay[dow].count++;
}
// Average days spent in-progress: pair "→ in-progress" with next "in-progress →" per item.
const ipStart = {}; // itemId → start timestamp ms
const ipDurations = [];
for (const h of [...history].reverse()) {
// chronological order
if (h.action !== 'status_changed') continue;
if (h.details.includes('→ in-progress')) ipStart[h.itemId] = new Date(h.timestamp).getTime();else if (h.details.startsWith('in-progress →') && ipStart[h.itemId]) {
const days = (new Date(h.timestamp).getTime() - ipStart[h.itemId]) / 86400000;
if (days >= 0 && days < 365) ipDurations.push(days);
delete ipStart[h.itemId];
}
}
const avgInProgressDays = ipDurations.length > 0 ? +(ipDurations.reduce((a, b) => a + b, 0) / ipDurations.length).toFixed(1) : null;
const historyOldest = history.length > 0 ? history[history.length - 1].timestamp : null;
const backupDirSize = backups.reduce((s, b) => s + (b.size || 0), 0);
const historySize = new TextEncoder().encode(JSON.stringify(history)).length;
const modeLabel = storageMode === 'api' ? 'API server' : storageMode === 'direct' ? 'Direct (File System API)' : storageMode === 'browser' ? 'Browser storage (IndexedDB)' : 'localStorage only';
return {
entries,
history,
meta: meta || {
saved: null,
checksum: '—',
entryCount: countAll(entries),
historyCount: history.length
},
health: {
integrityOk: checksumOk,
lastSave: meta?.saved || null,
lastBackup: backups[0]?.timestamp || null,
masterSize: sizeInfo.masterSize || 0,
backupDirSize,
backupCount: backups.length,
statsSize: sizeInfo.statsSize || 0,
historySize,
historyOldest,
mode: modeLabel,
masterPath: sizeInfo.masterPath || (sizeInfo.dirName ? `${sizeInfo.dirName}/backlog.md` : null),
backupsPath: sizeInfo.backupsPath || (sizeInfo.dirName ? `${sizeInfo.dirName}/backups/` : null)
},
stats: {
createdThisWeek,
completedThisWeek,
avgInProgressDays,
mostActiveProject,
completionByDay,
createdByDay,
statusMix
},
backups
};
}
Object.assign(window, {
Parser,
ApiBackend,
DirectBackend,
BrowserStorageBackend,
Storage,
SyncPoller,
buildDataFromStorage
});
</script>
<script>
// tweaks-panel.jsx
// Reusable Tweaks shell + form-control helpers.
//
// Owns the host protocol (listens for __activate_edit_mode / __deactivate_edit_mode,
// posts __edit_mode_available / __edit_mode_set_keys / __edit_mode_dismissed) so
// individual prototypes don't re-roll it. Ships a consistent set of controls so you
// don't hand-draw <input type="range">, segmented radios, steppers, etc.
//
// Usage (in an HTML file that loads React + Babel):
//
// const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
// "primaryColor": "#D97757",
// "fontSize": 16,
// "density": "regular",
// "dark": false
// }/*EDITMODE-END*/;
//
// function App() {
// const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
// return (
// <div style={{ fontSize: t.fontSize, color: t.primaryColor }}>
// Hello
// <TweaksPanel>
// <TweakSection label="Typography" />
// <TweakSlider label="Font size" value={t.fontSize} min={10} max={32} unit="px"
// onChange={(v) => setTweak('fontSize', v)} />
// <TweakRadio label="Density" value={t.density}
// options={['compact', 'regular', 'comfy']}
// onChange={(v) => setTweak('density', v)} />
// <TweakSection label="Theme" />
// <TweakColor label="Primary" value={t.primaryColor}
// onChange={(v) => setTweak('primaryColor', v)} />
// <TweakToggle label="Dark mode" value={t.dark}
// onChange={(v) => setTweak('dark', v)} />
// </TweaksPanel>
// </div>
// );
// }
//
// ─────────────────────────────────────────────────────────────────────────────
const __TWEAKS_STYLE = `
.twk-panel{position:fixed;right:16px;bottom:16px;z-index:2147483646;width:280px;
max-height:calc(100vh - 32px);display:flex;flex-direction:column;
background:rgba(250,249,247,.78);color:#29261b;
-webkit-backdrop-filter:blur(24px) saturate(160%);backdrop-filter:blur(24px) saturate(160%);
border:.5px solid rgba(255,255,255,.6);border-radius:14px;
box-shadow:0 1px 0 rgba(255,255,255,.5) inset,0 12px 40px rgba(0,0,0,.18);
font:11.5px/1.4 ui-sans-serif,system-ui,-apple-system,sans-serif;overflow:hidden}
.twk-hd{display:flex;align-items:center;justify-content:space-between;
padding:10px 8px 10px 14px;cursor:move;user-select:none}
.twk-hd b{font-size:12px;font-weight:600;letter-spacing:.01em}
.twk-x{appearance:none;border:0;background:transparent;color:rgba(41,38,27,.55);
width:22px;height:22px;border-radius:6px;cursor:default;font-size:13px;line-height:1}
.twk-x:hover{background:rgba(0,0,0,.06);color:#29261b}
.twk-body{padding:2px 14px 14px;display:flex;flex-direction:column;gap:10px;
overflow-y:auto;overflow-x:hidden;min-height:0;
scrollbar-width:thin;scrollbar-color:rgba(0,0,0,.15) transparent}
.twk-body::-webkit-scrollbar{width:8px}
.twk-body::-webkit-scrollbar-track{background:transparent;margin:2px}
.twk-body::-webkit-scrollbar-thumb{background:rgba(0,0,0,.15);border-radius:4px;
border:2px solid transparent;background-clip:content-box}
.twk-body::-webkit-scrollbar-thumb:hover{background:rgba(0,0,0,.25);
border:2px solid transparent;background-clip:content-box}
.twk-row{display:flex;flex-direction:column;gap:5px}
.twk-row-h{flex-direction:row;align-items:center;justify-content:space-between;gap:10px}
.twk-lbl{display:flex;justify-content:space-between;align-items:baseline;
color:rgba(41,38,27,.72)}
.twk-lbl>span:first-child{font-weight:500}
.twk-val{color:rgba(41,38,27,.5);font-variant-numeric:tabular-nums}
.twk-sect{font-size:10px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;
color:rgba(41,38,27,.45);padding:10px 0 0}
.twk-sect:first-child{padding-top:0}
.twk-field{appearance:none;width:100%;height:26px;padding:0 8px;
border:.5px solid rgba(0,0,0,.1);border-radius:7px;
background:rgba(255,255,255,.6);color:inherit;font:inherit;outline:none}
.twk-field:focus{border-color:rgba(0,0,0,.25);background:rgba(255,255,255,.85)}
select.twk-field{padding-right:22px;
background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'><path fill='rgba(0,0,0,.5)' d='M0 0h10L5 6z'/></svg>");
background-repeat:no-repeat;background-position:right 8px center}
.twk-slider{appearance:none;-webkit-appearance:none;width:100%;height:4px;margin:6px 0;
border-radius:999px;background:rgba(0,0,0,.12);outline:none}
.twk-slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;
width:14px;height:14px;border-radius:50%;background:#fff;
border:.5px solid rgba(0,0,0,.12);box-shadow:0 1px 3px rgba(0,0,0,.2);cursor:default}
.twk-slider::-moz-range-thumb{width:14px;height:14px;border-radius:50%;
background:#fff;border:.5px solid rgba(0,0,0,.12);box-shadow:0 1px 3px rgba(0,0,0,.2);cursor:default}
.twk-seg{position:relative;display:flex;padding:2px;border-radius:8px;
background:rgba(0,0,0,.06);user-select:none}
.twk-seg-thumb{position:absolute;top:2px;bottom:2px;border-radius:6px;
background:rgba(255,255,255,.9);box-shadow:0 1px 2px rgba(0,0,0,.12);
transition:left .15s cubic-bezier(.3,.7,.4,1),width .15s}
.twk-seg.dragging .twk-seg-thumb{transition:none}
.twk-seg button{appearance:none;position:relative;z-index:1;flex:1;border:0;
background:transparent;color:inherit;font:inherit;font-weight:500;min-height:22px;
border-radius:6px;cursor:default;padding:4px 6px;line-height:1.2;
overflow-wrap:anywhere}
.twk-toggle{position:relative;width:32px;height:18px;border:0;border-radius:999px;
background:rgba(0,0,0,.15);transition:background .15s;cursor:default;padding:0}
.twk-toggle[data-on="1"]{background:#34c759}
.twk-toggle i{position:absolute;top:2px;left:2px;width:14px;height:14px;border-radius:50%;
background:#fff;box-shadow:0 1px 2px rgba(0,0,0,.25);transition:transform .15s}
.twk-toggle[data-on="1"] i{transform:translateX(14px)}
.twk-num{display:flex;align-items:center;height:26px;padding:0 0 0 8px;
border:.5px solid rgba(0,0,0,.1);border-radius:7px;background:rgba(255,255,255,.6)}
.twk-num-lbl{font-weight:500;color:rgba(41,38,27,.6);cursor:ew-resize;
user-select:none;padding-right:8px}
.twk-num input{flex:1;min-width:0;height:100%;border:0;background:transparent;
font:inherit;font-variant-numeric:tabular-nums;text-align:right;padding:0 8px 0 0;
outline:none;color:inherit;-moz-appearance:textfield}
.twk-num input::-webkit-inner-spin-button,.twk-num input::-webkit-outer-spin-button{
-webkit-appearance:none;margin:0}
.twk-num-unit{padding-right:8px;color:rgba(41,38,27,.45)}
.twk-btn{appearance:none;height:26px;padding:0 12px;border:0;border-radius:7px;
background:rgba(0,0,0,.78);color:#fff;font:inherit;font-weight:500;cursor:default}
.twk-btn:hover{background:rgba(0,0,0,.88)}
.twk-btn.secondary{background:rgba(0,0,0,.06);color:inherit}
.twk-btn.secondary:hover{background:rgba(0,0,0,.1)}
.twk-swatch{appearance:none;-webkit-appearance:none;width:56px;height:22px;
border:.5px solid rgba(0,0,0,.1);border-radius:6px;padding:0;cursor:default;
background:transparent;flex-shrink:0}
.twk-swatch::-webkit-color-swatch-wrapper{padding:0}
.twk-swatch::-webkit-color-swatch{border:0;border-radius:5.5px}
.twk-swatch::-moz-color-swatch{border:0;border-radius:5.5px}
`;
// ── useTweaks ───────────────────────────────────────────────────────────────
// Single source of truth for tweak values. setTweak persists via the host
// (__edit_mode_set_keys → host rewrites the EDITMODE block on disk).
function useTweaks(defaults) {
const [values, setValues] = React.useState(defaults);
// Accepts either setTweak('key', value) or setTweak({ key: value, ... }) so a
// useState-style call doesn't write a "[object Object]" key into the persisted
// JSON block.
const setTweak = React.useCallback((keyOrEdits, val) => {
const edits = typeof keyOrEdits === 'object' && keyOrEdits !== null ? keyOrEdits : {
[keyOrEdits]: val
};
setValues(prev => ({
...prev,
...edits
}));
window.parent.postMessage({
type: '__edit_mode_set_keys',
edits
}, '*');
}, []);
return [values, setTweak];
}
// ── TweaksPanel ─────────────────────────────────────────────────────────────
// Floating shell. Registers the protocol listener BEFORE announcing
// availability — if the announce ran first, the host's activate could land
// before our handler exists and the toolbar toggle would silently no-op.
// The close button posts __edit_mode_dismissed so the host's toolbar toggle
// flips off in lockstep; the host echoes __deactivate_edit_mode back which
// is what actually hides the panel.
function TweaksPanel({
title = 'Tweaks',
children
}) {
const [open, setOpen] = React.useState(false);
const dragRef = React.useRef(null);
const offsetRef = React.useRef({
x: 16,
y: 16
});
const PAD = 16;
const clampToViewport = React.useCallback(() => {
const panel = dragRef.current;
if (!panel) return;
const w = panel.offsetWidth,
h = panel.offsetHeight;
const maxRight = Math.max(PAD, window.innerWidth - w - PAD);
const maxBottom = Math.max(PAD, window.innerHeight - h - PAD);
offsetRef.current = {
x: Math.min(maxRight, Math.max(PAD, offsetRef.current.x)),
y: Math.min(maxBottom, Math.max(PAD, offsetRef.current.y))
};
panel.style.right = offsetRef.current.x + 'px';
panel.style.bottom = offsetRef.current.y + 'px';
}, []);
React.useEffect(() => {
if (!open) return;
clampToViewport();
if (typeof ResizeObserver === 'undefined') {
window.addEventListener('resize', clampToViewport);
return () => window.removeEventListener('resize', clampToViewport);
}
const ro = new ResizeObserver(clampToViewport);
ro.observe(document.documentElement);
return () => ro.disconnect();
}, [open, clampToViewport]);
React.useEffect(() => {
const onMsg = e => {
const t = e?.data?.type;
if (t === '__activate_edit_mode') setOpen(true);else if (t === '__deactivate_edit_mode') setOpen(false);
};
window.addEventListener('message', onMsg);
window.parent.postMessage({
type: '__edit_mode_available'
}, '*');
return () => window.removeEventListener('message', onMsg);
}, []);
const dismiss = () => {
setOpen(false);
window.parent.postMessage({
type: '__edit_mode_dismissed'
}, '*');
};
const onDragStart = e => {
const panel = dragRef.current;
if (!panel) return;
const r = panel.getBoundingClientRect();
const sx = e.clientX,
sy = e.clientY;
const startRight = window.innerWidth - r.right;
const startBottom = window.innerHeight - r.bottom;
const move = ev => {
offsetRef.current = {
x: startRight - (ev.clientX - sx),
y: startBottom - (ev.clientY - sy)
};
clampToViewport();
};
const up = () => {
window.removeEventListener('mousemove', move);
window.removeEventListener('mouseup', up);
};
window.addEventListener('mousemove', move);
window.addEventListener('mouseup', up);
};
if (!open) return null;
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("style", null, __TWEAKS_STYLE), /*#__PURE__*/React.createElement("div", {
ref: dragRef,
className: "twk-panel",
"data-noncommentable": "",
style: {
right: offsetRef.current.x,
bottom: offsetRef.current.y
}
}, /*#__PURE__*/React.createElement("div", {
className: "twk-hd",
onMouseDown: onDragStart
}, /*#__PURE__*/React.createElement("b", null, title), /*#__PURE__*/React.createElement("button", {
className: "twk-x",
"aria-label": "Close tweaks",
onMouseDown: e => e.stopPropagation(),
onClick: dismiss
}, "\u2715")), /*#__PURE__*/React.createElement("div", {
className: "twk-body"
}, children)));
}
// ── Layout helpers ──────────────────────────────────────────────────────────
function TweakSection({
label,
children
}) {
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
className: "twk-sect"
}, label), children);
}
function TweakRow({
label,
value,
children,
inline = false
}) {
return /*#__PURE__*/React.createElement("div", {
className: inline ? 'twk-row twk-row-h' : 'twk-row'
}, /*#__PURE__*/React.createElement("div", {
className: "twk-lbl"
}, /*#__PURE__*/React.createElement("span", null, label), value != null && /*#__PURE__*/React.createElement("span", {
className: "twk-val"
}, value)), children);
}
// ── Controls ────────────────────────────────────────────────────────────────
function TweakSlider({
label,
value,
min = 0,
max = 100,
step = 1,
unit = '',
onChange
}) {
return /*#__PURE__*/React.createElement(TweakRow, {
label: label,
value: `${value}${unit}`
}, /*#__PURE__*/React.createElement("input", {
type: "range",
className: "twk-slider",
min: min,
max: max,
step: step,
value: value,
onChange: e => onChange(Number(e.target.value))
}));
}
function TweakToggle({
label,
value,
onChange
}) {
return /*#__PURE__*/React.createElement("div", {
className: "twk-row twk-row-h"
}, /*#__PURE__*/React.createElement("div", {
className: "twk-lbl"
}, /*#__PURE__*/React.createElement("span", null, label)), /*#__PURE__*/React.createElement("button", {
type: "button",
className: "twk-toggle",
"data-on": value ? '1' : '0',
role: "switch",
"aria-checked": !!value,
onClick: () => onChange(!value)
}, /*#__PURE__*/React.createElement("i", null)));
}
function TweakRadio({
label,
value,
options,
onChange
}) {
const trackRef = React.useRef(null);
const [dragging, setDragging] = React.useState(false);
const opts = options.map(o => typeof o === 'object' ? o : {
value: o,
label: o
});
const idx = Math.max(0, opts.findIndex(o => o.value === value));
const n = opts.length;
// The active value is read by pointer-move handlers attached for the lifetime
// of a drag — ref it so a stale closure doesn't fire onChange for every move.
const valueRef = React.useRef(value);
valueRef.current = value;
const segAt = clientX => {
const r = trackRef.current.getBoundingClientRect();
const inner = r.width - 4;
const i = Math.floor((clientX - r.left - 2) / inner * n);
return opts[Math.max(0, Math.min(n - 1, i))].value;
};
const onPointerDown = e => {
setDragging(true);
const v0 = segAt(e.clientX);
if (v0 !== valueRef.current) onChange(v0);
const move = ev => {
if (!trackRef.current) return;
const v = segAt(ev.clientX);
if (v !== valueRef.current) onChange(v);
};
const up = () => {
setDragging(false);
window.removeEventListener('pointermove', move);
window.removeEventListener('pointerup', up);
};
window.addEventListener('pointermove', move);
window.addEventListener('pointerup', up);
};
return /*#__PURE__*/React.createElement(TweakRow, {
label: label
}, /*#__PURE__*/React.createElement("div", {
ref: trackRef,
role: "radiogroup",
onPointerDown: onPointerDown,
className: dragging ? 'twk-seg dragging' : 'twk-seg'
}, /*#__PURE__*/React.createElement("div", {
className: "twk-seg-thumb",
style: {
left: `calc(2px + ${idx} * (100% - 4px) / ${n})`,
width: `calc((100% - 4px) / ${n})`
}
}), opts.map(o => /*#__PURE__*/React.createElement("button", {
key: o.value,
type: "button",
role: "radio",
"aria-checked": o.value === value
}, o.label))));
}
function TweakSelect({
label,
value,
options,
onChange
}) {
return /*#__PURE__*/React.createElement(TweakRow, {
label: label
}, /*#__PURE__*/React.createElement("select", {
className: "twk-field",
value: value,
onChange: e => onChange(e.target.value)
}, options.map(o => {
const v = typeof o === 'object' ? o.value : o;
const l = typeof o === 'object' ? o.label : o;
return /*#__PURE__*/React.createElement("option", {
key: v,
value: v
}, l);
})));
}
function TweakText({
label,
value,
placeholder,
onChange
}) {
return /*#__PURE__*/React.createElement(TweakRow, {
label: label
}, /*#__PURE__*/React.createElement("input", {
className: "twk-field",
type: "text",
value: value,
placeholder: placeholder,
onChange: e => onChange(e.target.value)
}));
}
function TweakNumber({
label,
value,
min,
max,
step = 1,
unit = '',
onChange
}) {
const clamp = n => {
if (min != null && n < min) return min;
if (max != null && n > max) return max;
return n;
};
const startRef = React.useRef({
x: 0,
val: 0
});
const onScrubStart = e => {
e.preventDefault();
startRef.current = {
x: e.clientX,
val: value
};
const decimals = (String(step).split('.')[1] || '').length;
const move = ev => {
const dx = ev.clientX - startRef.current.x;
const raw = startRef.current.val + dx * step;
const snapped = Math.round(raw / step) * step;
onChange(clamp(Number(snapped.toFixed(decimals))));
};
const up = () => {
window.removeEventListener('pointermove', move);
window.removeEventListener('pointerup', up);
};
window.addEventListener('pointermove', move);
window.addEventListener('pointerup', up);
};
return /*#__PURE__*/React.createElement("div", {
className: "twk-num"
}, /*#__PURE__*/React.createElement("span", {
className: "twk-num-lbl",
onPointerDown: onScrubStart
}, label), /*#__PURE__*/React.createElement("input", {
type: "number",
value: value,
min: min,
max: max,
step: step,
onChange: e => onChange(clamp(Number(e.target.value)))
}), unit && /*#__PURE__*/React.createElement("span", {
className: "twk-num-unit"
}, unit));
}
function TweakColor({
label,
value,
onChange
}) {
return /*#__PURE__*/React.createElement("div", {
className: "twk-row twk-row-h"
}, /*#__PURE__*/React.createElement("div", {
className: "twk-lbl"
}, /*#__PURE__*/React.createElement("span", null, label)), /*#__PURE__*/React.createElement("input", {
type: "color",
className: "twk-swatch",
value: value,
onChange: e => onChange(e.target.value)
}));
}
function TweakButton({
label,
onClick,
secondary = false
}) {
return /*#__PURE__*/React.createElement("button", {
type: "button",
className: secondary ? 'twk-btn secondary' : 'twk-btn',
onClick: onClick
}, label);
}
Object.assign(window, {
useTweaks,
TweaksPanel,
TweakSection,
TweakRow,
TweakSlider,
TweakToggle,
TweakRadio,
TweakSelect,
TweakText,
TweakNumber,
TweakColor,
TweakButton
});
</script>
<script>
// Filter sidebar: status, priority, due, tags + scope.
function FilterPanel({
filters,
setFilters,
tagsList,
counts
}) {
const toggle = (key, val) => {
const cur = new Set(filters[key] || []);
cur.has(val) ? cur.delete(val) : cur.add(val);
setFilters({
...filters,
[key]: [...cur]
});
};
const isActive = (key, val) => (filters[key] || []).includes(val);
return /*#__PURE__*/React.createElement("aside", {
className: "filter-panel"
}, /*#__PURE__*/React.createElement("div", {
className: "filter-section"
}, /*#__PURE__*/React.createElement("div", {
className: "filter-label"
}, "Status"), /*#__PURE__*/React.createElement("div", {
className: "filter-list"
}, STATUSES.map(s => /*#__PURE__*/React.createElement("button", {
key: s.key,
className: `filter-chip ${isActive("statuses", s.key) ? "active" : ""}`,
onClick: () => toggle("statuses", s.key)
}, /*#__PURE__*/React.createElement(StatusIcon, {
status: s.key,
size: 13
}), /*#__PURE__*/React.createElement("span", {
className: "filter-name"
}, s.label), /*#__PURE__*/React.createElement("span", {
className: "filter-count"
}, counts[s.key] || 0))))), /*#__PURE__*/React.createElement("div", {
className: "filter-section"
}, /*#__PURE__*/React.createElement("div", {
className: "filter-label"
}, "Priority"), /*#__PURE__*/React.createElement("div", {
className: "filter-list filter-list-row"
}, PRIORITIES.map(p => /*#__PURE__*/React.createElement("button", {
key: p,
className: `filter-chip mini ${isActive("priorities", p) ? "active" : ""} pri-${p}`,
onClick: () => toggle("priorities", p)
}, p === "P0" && /*#__PURE__*/React.createElement("span", {
className: "p0-dot"
}), p)))), /*#__PURE__*/React.createElement("div", {
className: "filter-section"
}, /*#__PURE__*/React.createElement("div", {
className: "filter-label"
}, "Due"), /*#__PURE__*/React.createElement("div", {
className: "filter-list"
}, [{
k: "overdue",
n: "Overdue"
}, {
k: "today",
n: "Today"
}, {
k: "week",
n: "This week"
}, {
k: "month",
n: "This month"
}].map(o => /*#__PURE__*/React.createElement("button", {
key: o.k,
className: `filter-chip ${filters.dueRange === o.k ? "active" : ""}`,
onClick: () => setFilters({
...filters,
dueRange: filters.dueRange === o.k ? null : o.k
})
}, /*#__PURE__*/React.createElement("span", {
className: "filter-name"
}, o.n))))), /*#__PURE__*/React.createElement(TagFilter, {
tagsList: tagsList,
selected: filters.tags || [],
onToggle: t => toggle("tags", t)
}), /*#__PURE__*/React.createElement("div", {
className: "filter-section"
}, /*#__PURE__*/React.createElement("div", {
className: "filter-label"
}, "Scope"), /*#__PURE__*/React.createElement("div", {
className: "filter-list"
}, [{
k: "all",
n: "All items"
}, {
k: "top",
n: "Top-level only"
}].map(o => /*#__PURE__*/React.createElement("button", {
key: o.k,
className: `filter-chip ${(filters.scope || "all") === o.k ? "active" : ""}`,
onClick: () => setFilters({
...filters,
scope: o.k
})
}, /*#__PURE__*/React.createElement("span", {
className: "filter-name"
}, o.n))))), (filters.statuses?.length || filters.priorities?.length || filters.tags?.length || filters.dueRange) && /*#__PURE__*/React.createElement("button", {
className: "clear-btn",
onClick: () => setFilters({
statuses: [],
priorities: [],
tags: [],
dueRange: null,
scope: filters.scope,
text: filters.text
})
}, "Clear filters"));
}
// ---- Tag filter with autocomplete (handles hundreds of tags) ----
function TagFilter({
tagsList,
selected,
onToggle
}) {
const [q, setQ] = React.useState("");
const [focused, setFocused] = React.useState(false);
const inputRef = React.useRef(null);
if (!tagsList.length) return null;
const ql = q.trim().toLowerCase();
const filtered = ql ? tagsList.filter(t => t.toLowerCase().includes(ql)).slice(0, 50) : tagsList.slice(0, 12); // top dozen by frequency when not searching
const exact = ql && tagsList.includes(ql);
const TOTAL = tagsList.length;
return /*#__PURE__*/React.createElement("div", {
className: "filter-section"
}, /*#__PURE__*/React.createElement("div", {
className: "filter-label"
}, "Tags ", /*#__PURE__*/React.createElement("span", {
className: "tag-total mono"
}, TOTAL)), selected.length > 0 && /*#__PURE__*/React.createElement("div", {
className: "tag-selected"
}, selected.map(t => /*#__PURE__*/React.createElement("button", {
key: t,
className: "tag-chip active",
onClick: () => onToggle(t),
title: "Remove"
}, "#", t, /*#__PURE__*/React.createElement("span", {
className: "tag-x"
}, "\xD7")))), /*#__PURE__*/React.createElement("div", {
className: `tag-search ${focused ? "focused" : ""}`
}, /*#__PURE__*/React.createElement(Icon, {
name: "search",
size: 12
}), /*#__PURE__*/React.createElement("input", {
ref: inputRef,
className: "tag-search-input",
placeholder: `Search ${TOTAL} tags…`,
value: q,
onChange: e => setQ(e.target.value),
onFocus: () => setFocused(true),
onBlur: () => setTimeout(() => setFocused(false), 120),
onKeyDown: e => {
if (e.key === "Enter" && filtered.length > 0) {
onToggle(filtered[0]);
setQ("");
} else if (e.key === "Escape") {
setQ("");
e.currentTarget.blur();
}
}
}), q && /*#__PURE__*/React.createElement("button", {
className: "tag-search-clear",
onClick: () => {
setQ("");
inputRef.current?.focus();
}
}, "\xD7")), /*#__PURE__*/React.createElement("div", {
className: "tag-results"
}, filtered.length === 0 ? /*#__PURE__*/React.createElement("div", {
className: "tag-empty"
}, "No tags match \"", q, "\"") : /*#__PURE__*/React.createElement(React.Fragment, null, filtered.map(t => {
const isSelected = selected.includes(t);
return /*#__PURE__*/React.createElement("button", {
key: t,
className: `tag-chip ${isSelected ? "active" : ""}`,
onClick: () => onToggle(t),
title: isSelected ? "Remove from filter" : "Add to filter"
}, ql && !isSelected ? /*#__PURE__*/React.createElement(TagHighlight, {
text: t,
match: ql
}) : `#${t}`);
}), !ql && tagsList.length > 12 && /*#__PURE__*/React.createElement("span", {
className: "tag-more mono"
}, "+", tagsList.length - 12, " more \u2014 type to find"))));
}
function TagHighlight({
text,
match
}) {
const i = text.toLowerCase().indexOf(match);
if (i < 0) return `#${text}`;
return /*#__PURE__*/React.createElement(React.Fragment, null, "#", text.slice(0, i), /*#__PURE__*/React.createElement("span", {
className: "hl"
}, text.slice(i, i + match.length)), text.slice(i + match.length));
}
window.FilterPanel = FilterPanel;
</script>
<script>
// Backlog tree view: rows, expand/collapse, status cycling, drag handle, add/delete.
const {
useState,
useRef,
useEffect,
useMemo
} = React;
// Inline priority popover
function PriorityPicker({
value,
onChange,
onClose
}) {
const ref = useRef(null);
useEffect(() => {
const close = e => {
if (!ref.current?.contains(e.target)) onClose();
};
document.addEventListener("mousedown", close);
return () => document.removeEventListener("mousedown", close);
}, [onClose]);
return /*#__PURE__*/React.createElement("div", {
className: "pri-pop",
ref: ref,
onClick: e => e.stopPropagation()
}, PRIORITIES.map(p => /*#__PURE__*/React.createElement("button", {
key: p,
className: `pri-pop-item pri-${p} ${value === p ? "active" : ""}`,
onClick: () => {
onChange(p);
onClose();
}
}, p === "P0" && /*#__PURE__*/React.createElement("span", {
className: "p0-dot"
}), /*#__PURE__*/React.createElement("span", null, p), /*#__PURE__*/React.createElement("span", {
className: "pri-pop-hint"
}, p === "P0" ? "Burning" : p === "P1" ? "High" : p === "P2" ? "Normal" : "Low"))));
}
// Inline status popover (replaces ●●● menu)
function StatusPopover({
value,
style,
onChange,
onClose,
anchorRect
}) {
const ref = useRef(null);
useEffect(() => {
const close = e => {
if (!ref.current?.contains(e.target)) onClose();
};
document.addEventListener("mousedown", close);
return () => document.removeEventListener("mousedown", close);
}, [onClose]);
return /*#__PURE__*/React.createElement("div", {
className: "status-pop",
ref: ref,
onClick: e => e.stopPropagation()
}, STATUSES.map(s => /*#__PURE__*/React.createElement("button", {
key: s.key,
className: `status-pop-item ${value === s.key ? "active" : ""}`,
onClick: () => {
onChange(s.key);
onClose();
}
}, /*#__PURE__*/React.createElement(StatusIcon, {
status: s.key,
style: style,
size: 14
}), /*#__PURE__*/React.createElement("span", null, s.label))));
}
// Single tree row
function ItemRow({
item,
depth,
expanded,
hasChildren,
statusStyle,
onToggle,
onSetStatus,
onAddChild,
onDelete,
onEdit,
onSetPriority,
onMoveUp,
onMoveDown,
canMoveUp,
canMoveDown,
onDragStart,
onDragOver,
onDrop,
dimmed,
query,
dropTarget
}) {
const [statusOpen, setStatusOpen] = useState(false);
const [priOpen, setPriOpen] = useState(false);
const overdue = isOverdue(item);
const isP0 = item.priority === "P0" && item.status !== "done" && item.status !== "cancelled";
const isDone = item.status === "done" || item.status === "cancelled";
const renderTitle = () => {
if (!query) return item.title;
const i = item.title.toLowerCase().indexOf(query.toLowerCase());
if (i < 0) return item.title;
return /*#__PURE__*/React.createElement(React.Fragment, null, item.title.slice(0, i), /*#__PURE__*/React.createElement("mark", {
className: "hl"
}, item.title.slice(i, i + query.length)), item.title.slice(i + query.length));
};
return /*#__PURE__*/React.createElement("div", {
className: `row level-${depth} ${dimmed ? "dimmed" : ""} ${isP0 ? "p0" : ""} ${dropTarget ? "drop-target" : ""}`,
draggable: true,
onDragStart: e => onDragStart?.(e, item),
onDragOver: e => onDragOver?.(e, item),
onDrop: e => onDrop?.(e, item)
}, /*#__PURE__*/React.createElement("span", {
className: "row-rail",
style: {
width: depth * 18
}
}), /*#__PURE__*/React.createElement("button", {
className: `twisty ${hasChildren ? "" : "empty"}`,
onClick: hasChildren ? onToggle : undefined,
"aria-label": expanded ? "Collapse" : "Expand",
tabIndex: hasChildren ? 0 : -1
}, hasChildren && /*#__PURE__*/React.createElement(Icon, {
name: expanded ? "chevron" : "chevronRight",
size: 12
})), /*#__PURE__*/React.createElement("span", {
className: "drag-handle",
title: "Drag to reorder within priority"
}, /*#__PURE__*/React.createElement(Icon, {
name: "drag",
size: 14
})), /*#__PURE__*/React.createElement("span", {
className: "status-wrap"
}, /*#__PURE__*/React.createElement("button", {
className: "status-btn",
onClick: () => setStatusOpen(v => !v),
title: `${STATUS_BY_KEY[item.status].label} — click to change`
}, /*#__PURE__*/React.createElement(StatusIcon, {
status: item.status,
style: statusStyle,
size: 14
})), statusOpen && /*#__PURE__*/React.createElement(StatusPopover, {
value: item.status,
style: statusStyle,
onChange: onSetStatus,
onClose: () => setStatusOpen(false)
})), /*#__PURE__*/React.createElement("span", {
className: "pri-wrap"
}, /*#__PURE__*/React.createElement("button", {
className: `pri pri-${item.priority}`,
onClick: () => setPriOpen(v => !v),
title: "Change priority"
}, item.priority === "P0" && /*#__PURE__*/React.createElement("span", {
className: "p0-dot"
}), item.priority), priOpen && /*#__PURE__*/React.createElement(PriorityPicker, {
value: item.priority,
onChange: p => onSetPriority(p),
onClose: () => setPriOpen(false)
})), /*#__PURE__*/React.createElement("span", {
className: `title ${isDone ? "done" : ""}`,
onDoubleClick: onEdit
}, renderTitle()), shouldShowProgress(item) && /*#__PURE__*/React.createElement(ProgressGauge, {
value: progressFor(item)
}), item.due && /*#__PURE__*/React.createElement("span", {
className: `due ${overdue ? "overdue" : ""}`
}, dueRelative(item)), item.tags?.length > 0 && /*#__PURE__*/React.createElement("span", {
className: "tags"
}, item.tags.map(t => /*#__PURE__*/React.createElement("span", {
key: t,
className: "tag"
}, "#", t))), item.status === "blocked" && item.reason && /*#__PURE__*/React.createElement("span", {
className: "reason",
title: item.reason
}, "\u21B3 ", item.reason), /*#__PURE__*/React.createElement("span", {
className: "row-spacer"
}), /*#__PURE__*/React.createElement("span", {
className: "row-actions"
}, /*#__PURE__*/React.createElement("button", {
className: "icon-btn",
onClick: onMoveUp,
disabled: !canMoveUp,
"data-tip": "Move up",
"aria-label": "Move up"
}, /*#__PURE__*/React.createElement("svg", {
width: "14",
height: "14",
viewBox: "0 0 16 16"
}, /*#__PURE__*/React.createElement("polyline", {
points: "4,10 8,5 12,10",
fill: "none",
stroke: "currentColor",
strokeWidth: "1.6",
strokeLinecap: "round",
strokeLinejoin: "round"
}))), /*#__PURE__*/React.createElement("button", {
className: "icon-btn",
onClick: onMoveDown,
disabled: !canMoveDown,
"data-tip": "Move down",
"aria-label": "Move down"
}, /*#__PURE__*/React.createElement("svg", {
width: "14",
height: "14",
viewBox: "0 0 16 16"
}, /*#__PURE__*/React.createElement("polyline", {
points: "4,6 8,11 12,6",
fill: "none",
stroke: "currentColor",
strokeWidth: "1.6",
strokeLinecap: "round",
strokeLinejoin: "round"
}))), /*#__PURE__*/React.createElement("span", {
className: "action-sep"
}), depth < 3 && /*#__PURE__*/React.createElement("button", {
className: "icon-btn",
onClick: onAddChild,
"data-tip": "Add sub-item",
"aria-label": "Add sub-item"
}, /*#__PURE__*/React.createElement(Icon, {
name: "addChild",
size: 14
})), /*#__PURE__*/React.createElement("button", {
className: "icon-btn",
onClick: onEdit,
"data-tip": "Edit item",
"aria-label": "Edit item"
}, /*#__PURE__*/React.createElement(Icon, {
name: "edit",
size: 13
})), /*#__PURE__*/React.createElement("button", {
className: "icon-btn danger",
onClick: onDelete,
"data-tip": "Delete",
"aria-label": "Delete"
}, /*#__PURE__*/React.createElement(Icon, {
name: "trash",
size: 13
}))));
}
// Expanded-state map kept in parent so filtering doesn't lose it.
function BacklogTree({
items,
expandedMap,
setExpanded,
onMutate,
query,
statusStyle,
manualOrder
}) {
const [draggedId, setDraggedId] = useState(null);
const [dropTargetId, setDropTargetId] = useState(null);
const onDragStart = (e, item) => {
setDraggedId(item.id);
e.dataTransfer.effectAllowed = "move";
try {
e.dataTransfer.setData("text/plain", item.id);
} catch (_) {}
};
const onDragOver = (e, item) => {
if (!draggedId || draggedId === item.id) return;
e.preventDefault();
e.dataTransfer.dropEffect = "move";
setDropTargetId(item.id);
};
const onDrop = (e, item) => {
e.preventDefault();
if (draggedId && draggedId !== item.id) {
onMutate.reorder(draggedId, item.id);
}
setDraggedId(null);
setDropTargetId(null);
};
function renderList(list, depth, parentList) {
return list.map((item, idx) => {
const expanded = expandedMap[item.id] ?? !item.collapsed;
const hasChildren = item.children?.length > 0;
const forceOpen = query && item._matches !== true && hasChildren;
const showKids = (expanded || forceOpen) && hasChildren;
// can-move logic: only swap with adjacent same-priority sibling
const samePri = parentList.map((x, i) => ({
x,
i
})).filter(({
x
}) => x.priority === item.priority);
const myIdx = samePri.findIndex(({
x
}) => x.id === item.id);
const canMoveUp = myIdx > 0;
const canMoveDown = myIdx >= 0 && myIdx < samePri.length - 1;
return /*#__PURE__*/React.createElement(React.Fragment, {
key: item.id
}, /*#__PURE__*/React.createElement(ItemRow, {
item: item,
depth: depth,
expanded: expanded || forceOpen,
hasChildren: hasChildren,
statusStyle: statusStyle,
dimmed: query && item._matches === false,
dropTarget: dropTargetId === item.id && draggedId !== item.id,
query: query,
onToggle: () => setExpanded(item.id, !expanded),
onSetStatus: s => onMutate.setStatus(item.id, s),
onSetPriority: p => onMutate.setPriority(item.id, p),
onAddChild: () => onMutate.addChild(item.id),
onDelete: () => onMutate.deleteItem(item.id),
onEdit: () => onMutate.editItem(item.id),
onMoveUp: () => onMutate.moveWithinPriority(item.id, -1),
onMoveDown: () => onMutate.moveWithinPriority(item.id, +1),
canMoveUp: canMoveUp,
canMoveDown: canMoveDown,
onDragStart: onDragStart,
onDragOver: onDragOver,
onDrop: onDrop
}), showKids && renderList(item.children, depth + 1, item.children));
});
}
return /*#__PURE__*/React.createElement("div", {
className: "tree"
}, renderList(items, 0, items));
}
window.BacklogTree = BacklogTree;
</script>
<script>
// Stylish dialog primitives + concrete dialogs (Edit/Add Item, Confirm).
const {
useState: useStateD,
useEffect: useEffectD,
useRef: useRefD
} = React;
function Dialog({
open,
onClose,
children,
width = 460,
labelledBy
}) {
useEffectD(() => {
if (!open) return;
const onKey = e => {
if (e.key === "Escape") onClose?.();
};
document.addEventListener("keydown", onKey);
document.body.style.overflow = "hidden";
return () => {
document.removeEventListener("keydown", onKey);
document.body.style.overflow = "";
};
}, [open, onClose]);
if (!open) return null;
return /*#__PURE__*/React.createElement("div", {
className: "dlg-backdrop",
onMouseDown: e => {
if (e.target === e.currentTarget) onClose?.();
}
}, /*#__PURE__*/React.createElement("div", {
className: "dlg",
role: "dialog",
"aria-modal": "true",
"aria-labelledby": labelledBy,
style: {
maxWidth: width
}
}, children));
}
function DialogHeader({
eyebrow,
title,
onClose,
id
}) {
return /*#__PURE__*/React.createElement("div", {
className: "dlg-head"
}, /*#__PURE__*/React.createElement("div", null, eyebrow && /*#__PURE__*/React.createElement("div", {
className: "eyebrow"
}, eyebrow), /*#__PURE__*/React.createElement("h3", {
id: id,
className: "dlg-title"
}, title)), onClose && /*#__PURE__*/React.createElement("button", {
className: "dlg-close",
onClick: onClose,
"aria-label": "Close"
}, /*#__PURE__*/React.createElement("svg", {
width: "14",
height: "14",
viewBox: "0 0 16 16"
}, /*#__PURE__*/React.createElement("path", {
d: "M3 3l10 10M13 3L3 13",
stroke: "currentColor",
strokeWidth: "1.6",
strokeLinecap: "round"
}))));
}
// --- Item editor (used for both edit and add) ---
function ItemDialog({
open,
mode,
initial,
onClose,
onSubmit,
recentTags = []
}) {
const [title, setTitle] = useStateD("");
const [priority, setPriority] = useStateD("P2");
const [status, setStatus] = useStateD("open");
const [due, setDue] = useStateD("");
const [tags, setTags] = useStateD([]);
const [tagInput, setTagInput] = useStateD("");
const [reason, setReason] = useStateD("");
const [progress, setProgress] = useStateD(0);
const titleRef = useRefD(null);
useEffectD(() => {
if (!open) return;
setTitle(initial?.title || "");
setPriority(initial?.priority || "P2");
setStatus(initial?.status || "open");
setDue(initial?.due || "");
setTags(initial?.tags || []);
setTagInput("");
setReason(initial?.reason || "");
setProgress(initial?.progress ?? 0);
setTimeout(() => titleRef.current?.focus(), 50);
}, [open, initial]);
const addTag = t => {
const v = t.trim().replace(/^#/, "");
if (!v) return;
if (tags.includes(v)) return;
setTags([...tags, v]);
};
const removeTag = t => setTags(tags.filter(x => x !== t));
const submit = e => {
e?.preventDefault();
if (!title.trim()) return;
// Reconcile progress with status before submitting.
let outProgress = snapProgress(progress);
if (status === "done") outProgress = 100;
onSubmit({
title: title.trim(),
priority,
status,
due: due || null,
tags,
reason: status === "blocked" ? reason.trim() || null : null,
progress: outProgress
});
};
const tagSuggestions = recentTags.filter(t => !tags.includes(t)).slice(0, 8);
return /*#__PURE__*/React.createElement(Dialog, {
open: open,
onClose: onClose,
width: 520,
labelledBy: "dlg-item-title"
}, /*#__PURE__*/React.createElement("form", {
onSubmit: submit
}, /*#__PURE__*/React.createElement(DialogHeader, {
id: "dlg-item-title",
eyebrow: mode === "edit" ? "Edit item" : mode === "add-child" ? "Add sub-item" : "New item",
title: mode === "edit" ? "Edit details" : "Create item",
onClose: onClose
}), /*#__PURE__*/React.createElement("div", {
className: "dlg-body"
}, /*#__PURE__*/React.createElement("div", {
className: "field"
}, /*#__PURE__*/React.createElement("label", {
className: "field-label"
}, "Title"), /*#__PURE__*/React.createElement("input", {
ref: titleRef,
className: "text-input",
value: title,
onChange: e => setTitle(e.target.value),
placeholder: "What needs to happen?",
required: true
})), /*#__PURE__*/React.createElement("div", {
className: "field-row"
}, /*#__PURE__*/React.createElement("div", {
className: "field"
}, /*#__PURE__*/React.createElement("label", {
className: "field-label"
}, "Priority"), /*#__PURE__*/React.createElement("div", {
className: "seg"
}, PRIORITIES.map(p => /*#__PURE__*/React.createElement("button", {
type: "button",
key: p,
className: `seg-btn pri-${p} ${priority === p ? "active" : ""}`,
onClick: () => setPriority(p)
}, p === "P0" && /*#__PURE__*/React.createElement("span", {
className: "p0-dot"
}), p)))), /*#__PURE__*/React.createElement("div", {
className: "field"
}, /*#__PURE__*/React.createElement("label", {
className: "field-label"
}, "Due"), /*#__PURE__*/React.createElement("input", {
className: "text-input",
type: "date",
value: due,
onChange: e => setDue(e.target.value)
}))), /*#__PURE__*/React.createElement("div", {
className: "field"
}, /*#__PURE__*/React.createElement("label", {
className: "field-label"
}, "Status"), /*#__PURE__*/React.createElement("div", {
className: "status-grid"
}, STATUSES.map(s => /*#__PURE__*/React.createElement("button", {
type: "button",
key: s.key,
className: `status-card ${status === s.key ? "active" : ""}`,
onClick: () => setStatus(s.key)
}, /*#__PURE__*/React.createElement("span", {
className: `status-card-icon status-${s.key}`
}, /*#__PURE__*/React.createElement(StatusIcon, {
status: s.key,
size: 16
})), /*#__PURE__*/React.createElement("span", {
className: "status-card-label"
}, s.label))))), status !== "cancelled" && /*#__PURE__*/React.createElement("div", {
className: "field"
}, /*#__PURE__*/React.createElement("label", {
className: "field-label"
}, "Completion", /*#__PURE__*/React.createElement("span", {
className: "field-hint"
}, status === "done" ? "locked at 100% while marked done" : "rough estimate — set 100% to mark done")), /*#__PURE__*/React.createElement("div", {
className: "progress-row"
}, /*#__PURE__*/React.createElement("div", {
className: `seg progress-seg ${status === "done" ? "locked" : ""}`
}, PROGRESS_STEPS.map(p => /*#__PURE__*/React.createElement("button", {
type: "button",
key: p,
className: `seg-btn ${progress === p ? "active" : ""}`,
onClick: () => setProgress(p),
disabled: status === "done"
}, p, "%"))), /*#__PURE__*/React.createElement(ProgressGauge, {
value: status === "done" ? 100 : progress,
size: "md"
}))), status === "blocked" && /*#__PURE__*/React.createElement("div", {
className: "field"
}, /*#__PURE__*/React.createElement("label", {
className: "field-label"
}, "Block reason"), /*#__PURE__*/React.createElement("input", {
className: "text-input",
value: reason,
onChange: e => setReason(e.target.value),
placeholder: "Waiting for\u2026"
})), /*#__PURE__*/React.createElement("div", {
className: "field"
}, /*#__PURE__*/React.createElement("label", {
className: "field-label"
}, "Tags ", /*#__PURE__*/React.createElement("span", {
className: "field-hint"
}, "type a name, press Enter or comma to add")), /*#__PURE__*/React.createElement(TagAutocompleteInput, {
tags: tags,
setTags: setTags,
tagInput: tagInput,
setTagInput: setTagInput,
addTag: addTag,
removeTag: removeTag,
allTags: recentTags
}))), /*#__PURE__*/React.createElement("div", {
className: "dlg-foot"
}, /*#__PURE__*/React.createElement("span", {
className: "dlg-hint"
}, "\u2318\u21A9 to save \xB7 Esc to cancel"), /*#__PURE__*/React.createElement("div", {
className: "dlg-foot-actions"
}, /*#__PURE__*/React.createElement("button", {
type: "button",
className: "btn-secondary",
onClick: onClose
}, "Cancel"), /*#__PURE__*/React.createElement("button", {
type: "submit",
className: "btn-primary",
disabled: !title.trim()
}, mode === "edit" ? "Save changes" : "Create item")))));
}
// --- Confirm dialog ---
function ConfirmDialog({
open,
title,
message,
detail,
confirmLabel = "Confirm",
danger = false,
onCancel,
onConfirm
}) {
return /*#__PURE__*/React.createElement(Dialog, {
open: open,
onClose: onCancel,
width: 420,
labelledBy: "dlg-confirm-title"
}, /*#__PURE__*/React.createElement(DialogHeader, {
id: "dlg-confirm-title",
eyebrow: "Confirm",
title: title,
onClose: onCancel
}), /*#__PURE__*/React.createElement("div", {
className: "dlg-body"
}, /*#__PURE__*/React.createElement("p", {
className: "dlg-msg"
}, message), detail && /*#__PURE__*/React.createElement("div", {
className: "dlg-detail"
}, detail)), /*#__PURE__*/React.createElement("div", {
className: "dlg-foot"
}, /*#__PURE__*/React.createElement("span", null), /*#__PURE__*/React.createElement("div", {
className: "dlg-foot-actions"
}, /*#__PURE__*/React.createElement("button", {
type: "button",
className: "btn-secondary",
onClick: onCancel
}, "Cancel"), /*#__PURE__*/React.createElement("button", {
type: "button",
className: danger ? "btn-danger" : "btn-primary",
onClick: onConfirm,
autoFocus: true
}, confirmLabel))));
}
// --- Tag autocomplete (typed input + filtered dropdown) ---
function TagAutocompleteInput({
tags,
setTags,
tagInput,
setTagInput,
addTag,
removeTag,
allTags
}) {
const [focused, setFocused] = useStateD(false);
const [highlighted, setHighlighted] = useStateD(0);
const inputRef = useRefD(null);
const wrapRef = useRefD(null);
const q = tagInput.trim().toLowerCase().replace(/^#/, "");
// suggestions: filter out already-applied; rank exact prefix > contains
const pool = (allTags || []).filter(t => !tags.includes(t));
let suggestions;
if (q) {
const starts = pool.filter(t => t.toLowerCase().startsWith(q));
const contains = pool.filter(t => !t.toLowerCase().startsWith(q) && t.toLowerCase().includes(q));
suggestions = [...starts, ...contains].slice(0, 8);
} else {
suggestions = pool.slice(0, 8); // recents
}
const exactMatch = q && pool.some(t => t.toLowerCase() === q);
const showCreate = q && !exactMatch && !tags.includes(q);
// index 0 = "create new" (if shown), then suggestions
const items = [...(showCreate ? [{
kind: "create",
value: q
}] : []), ...suggestions.map(t => ({
kind: "suggestion",
value: t
}))];
useEffectD(() => {
setHighlighted(0);
}, [tagInput, focused]);
const pick = it => {
if (!it) return;
addTag(it.value);
setTagInput("");
setHighlighted(0);
};
const onKey = e => {
if (e.key === "ArrowDown") {
e.preventDefault();
if (items.length) setHighlighted(h => (h + 1) % items.length);
} else if (e.key === "ArrowUp") {
e.preventDefault();
if (items.length) setHighlighted(h => (h - 1 + items.length) % items.length);
} else if (e.key === "Enter") {
e.preventDefault();
if (items[highlighted]) pick(items[highlighted]);else if (tagInput.trim()) {
addTag(tagInput);
setTagInput("");
}
} else if (e.key === "," || e.key === "Tab") {
if (tagInput.trim()) {
e.preventDefault();
if (items[highlighted]) pick(items[highlighted]);else {
addTag(tagInput);
setTagInput("");
}
}
} else if (e.key === "Backspace" && !tagInput && tags.length) {
removeTag(tags[tags.length - 1]);
} else if (e.key === "Escape") {
if (tagInput) {
setTagInput("");
e.preventDefault();
} else inputRef.current?.blur();
}
};
return /*#__PURE__*/React.createElement("div", {
className: "tag-ac",
ref: wrapRef
}, /*#__PURE__*/React.createElement("div", {
className: `tag-input ${focused ? "focused" : ""}`,
onClick: e => {
if (e.target === e.currentTarget) inputRef.current?.focus();
}
}, tags.map(t => /*#__PURE__*/React.createElement("span", {
key: t,
className: "tag-pill"
}, "#", t, /*#__PURE__*/React.createElement("button", {
type: "button",
onClick: () => removeTag(t),
"aria-label": `Remove ${t}`
}, "\xD7"))), /*#__PURE__*/React.createElement("input", {
ref: inputRef,
className: "tag-input-field",
placeholder: tags.length ? "+ add tag" : "e.g. urgent, frontend, errand",
value: tagInput,
onChange: e => setTagInput(e.target.value),
onFocus: () => setFocused(true),
onBlur: () => setTimeout(() => setFocused(false), 150),
onKeyDown: onKey,
autoComplete: "off",
"aria-autocomplete": "list",
"aria-expanded": focused && items.length > 0
})), focused && items.length > 0 && /*#__PURE__*/React.createElement("div", {
className: "tag-ac-pop",
role: "listbox"
}, !q && /*#__PURE__*/React.createElement("div", {
className: "tag-ac-cap"
}, "Recent"), items.map((it, i) => /*#__PURE__*/React.createElement("button", {
key: `${it.kind}-${it.value}`,
type: "button",
role: "option",
"aria-selected": i === highlighted,
className: `tag-ac-item ${i === highlighted ? "highlighted" : ""} ${it.kind === "create" ? "create" : ""}`,
onMouseEnter: () => setHighlighted(i),
onMouseDown: e => {
e.preventDefault();
pick(it);
}
}, it.kind === "create" ? /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Icon, {
name: "plus",
size: 11
}), /*#__PURE__*/React.createElement("span", null, "Create ", /*#__PURE__*/React.createElement("strong", null, "#", it.value))) : /*#__PURE__*/React.createElement("span", null, q ? /*#__PURE__*/React.createElement(TagMatchHL, {
text: it.value,
match: q
}) : `#${it.value}`))), /*#__PURE__*/React.createElement("div", {
className: "tag-ac-foot"
}, /*#__PURE__*/React.createElement("span", null, /*#__PURE__*/React.createElement("kbd", null, "\u2191"), /*#__PURE__*/React.createElement("kbd", null, "\u2193"), " to navigate"), /*#__PURE__*/React.createElement("span", null, /*#__PURE__*/React.createElement("kbd", null, "\u21B5"), " to add"), /*#__PURE__*/React.createElement("span", null, /*#__PURE__*/React.createElement("kbd", null, "esc"), " to dismiss"))));
}
function TagMatchHL({
text,
match
}) {
const i = text.toLowerCase().indexOf(match);
if (i < 0) return `#${text}`;
return /*#__PURE__*/React.createElement(React.Fragment, null, "#", text.slice(0, i), /*#__PURE__*/React.createElement("span", {
className: "hl"
}, text.slice(i, i + match.length)), text.slice(i + match.length));
}
window.Dialog = Dialog;
window.ItemDialog = ItemDialog;
window.ConfirmDialog = ConfirmDialog;
</script>
<script>
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
// Admin / Maintenance page: health, storage stats, backup browser, stats, manual actions.
// ---- Range-aware stats engine -----------------------------------------------
// Generates deterministic per-bucket counts based on seed numbers so switching
// range feels real (each range animates between fixed shapes, not random noise).
const RANGE_OPTIONS = [{
key: "week",
label: "This week",
buckets: 7,
bucketLabel: "d",
granularity: "day"
}, {
key: "month",
label: "This month",
buckets: 5,
bucketLabel: "w",
granularity: "week"
}, {
key: "year",
label: "This year",
buckets: 12,
bucketLabel: "m",
granularity: "month"
}, {
key: "7d",
label: "Last 7d",
buckets: 7,
bucketLabel: "d",
granularity: "day"
}, {
key: "30d",
label: "Last 30d",
buckets: 30,
bucketLabel: "d",
granularity: "day"
}, {
key: "365d",
label: "Last 365d",
buckets: 12,
bucketLabel: "m",
granularity: "month"
}];
// Returns [{start, end}] bucket boundaries matching bucketLabelsFor(rangeKey)
function bucketBounds(rangeKey, refDate) {
const d = new Date(refDate);
if (rangeKey === 'week') {
const dow = (d.getDay() + 6) % 7;
const mon = new Date(d.getFullYear(), d.getMonth(), d.getDate() - dow);
return Array.from({
length: 7
}, (_, i) => {
const s = new Date(mon);
s.setDate(mon.getDate() + i);
const e = new Date(s);
e.setDate(s.getDate() + 1);
return {
start: s,
end: e
};
});
}
if (rangeKey === '7d') {
return Array.from({
length: 7
}, (_, i) => {
const offset = 6 - i;
const s = new Date(d.getFullYear(), d.getMonth(), d.getDate() - offset);
const e = new Date(s);
e.setDate(s.getDate() + 1);
return {
start: s,
end: e
};
});
}
if (rangeKey === '30d') {
return Array.from({
length: 30
}, (_, i) => {
const offset = 29 - i;
const s = new Date(d.getFullYear(), d.getMonth(), d.getDate() - offset);
const e = new Date(s);
e.setDate(s.getDate() + 1);
return {
start: s,
end: e
};
});
}
if (rangeKey === 'month') {
const y = d.getFullYear(),
mo = d.getMonth();
return Array.from({
length: 5
}, (_, i) => ({
start: new Date(y, mo, 1 + i * 7),
end: i < 4 ? new Date(y, mo, 1 + (i + 1) * 7) : new Date(y, mo + 1, 1)
}));
}
if (rangeKey === 'year') {
const y = d.getFullYear();
return Array.from({
length: 12
}, (_, i) => ({
start: new Date(y, i, 1),
end: new Date(y, i + 1, 1)
}));
}
if (rangeKey === '365d') {
return Array.from({
length: 12
}, (_, i) => {
const offset = 11 - i;
const y = d.getFullYear(),
mo = d.getMonth();
return {
start: new Date(y, mo - offset, 1),
end: new Date(y, mo - offset + 1, 1)
};
});
}
return [];
}
function countInBuckets(history, buckets) {
const keys = ['created', 'in-progress', 'blocked', 'postponed', 'done', 'cancelled'];
const out = Object.fromEntries(keys.map(k => [k, Array(buckets.length).fill(0)]));
for (const h of history) {
const ts = new Date(h.timestamp);
const idx = buckets.findIndex(b => ts >= b.start && ts < b.end);
if (idx < 0) continue;
if (h.action === 'item_created') {
out.created[idx]++;
} else if (h.action === 'status_changed') {
const m = h.details.match(/→\s*(\S[\s\S]*?)$/);
if (m) {
const ns = m[1].trim();
if (ns in out) out[ns][idx]++;
}
}
}
return out;
}
function bucketLabelsFor(rangeKey) {
const today = new Date();
const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
const days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
if (rangeKey === "week") {
return days;
}
if (rangeKey === "7d") {
const out = [];
for (let i = 6; i >= 0; i--) {
const d = new Date(today);
d.setDate(today.getDate() - i);
out.push(days[(d.getDay() + 6) % 7]);
}
return out;
}
if (rangeKey === "30d") {
const out = [];
for (let i = 29; i >= 0; i--) {
const d = new Date(today);
d.setDate(today.getDate() - i);
out.push(String(d.getDate()));
}
return out;
}
if (rangeKey === "month") {
return ["W1", "W2", "W3", "W4", "W5"];
}
if (rangeKey === "year") {
return months;
}
if (rangeKey === "365d") {
const out = [];
for (let i = 11; i >= 0; i--) {
const d = new Date(today);
d.setMonth(today.getMonth() - i);
out.push(months[d.getMonth()]);
}
return out;
}
return [];
}
// Status keys in the order we want them stacked (bottom → top).
// "created" is a synthetic bucket: items that entered the system in that period.
const CHART_STATUSES = [{
key: "created",
label: "Created",
color: "oklch(0.78 0.13 220)"
},
// sky cyan-blue
{
key: "in-progress",
label: "In progress",
color: "oklch(0.72 0.14 270)"
},
// lavender
{
key: "blocked",
label: "Blocked",
color: "oklch(0.68 0.20 28)"
},
// red — fixed (0° HSL)
{
key: "postponed",
label: "Postponed",
color: "oklch(0.83 0.16 90)"
},
// bright golden yellow — bisector of red↔green (≈70° HSL)
{
key: "done",
label: "Done",
color: "oklch(0.68 0.16 150)"
},
// green — fixed (140° HSL)
{
key: "cancelled",
label: "Cancelled",
color: "oklch(0.62 0.04 280)"
} // slate
];
function computeRangeStats(rangeKey, dataStats, history) {
const opt = RANGE_OPTIONS.find(r => r.key === rangeKey);
const labels = bucketLabelsFor(rangeKey);
const now = new Date();
// Prior-period reference: shift back by one equivalent period
const priorRef = new Date(now);
if (rangeKey === 'week' || rangeKey === '7d') priorRef.setDate(priorRef.getDate() - 7);else if (rangeKey === 'month' || rangeKey === '30d') priorRef.setMonth(priorRef.getMonth() - 1);else if (rangeKey === 'year' || rangeKey === '365d') priorRef.setFullYear(priorRef.getFullYear() - 1);
const curr = countInBuckets(history, bucketBounds(rangeKey, now));
const prior = countInBuckets(history, bucketBounds(rangeKey, priorRef));
const series = {
created: curr.created,
'in-progress': curr['in-progress'],
blocked: curr.blocked,
postponed: curr.postponed,
done: curr.done,
cancelled: curr.cancelled
};
const sum = arr => arr.reduce((a, b) => a + b, 0);
const totalCreated = sum(curr.created);
const totalCompleted = sum(curr.done);
const priorCreated = sum(prior.created);
const priorCompleted = sum(prior.done);
const pct = (c, p) => p === 0 ? c > 0 ? 100 : 0 : Math.round((c - p) / p * 100);
const periodWeeks = {
week: 1,
'7d': 1,
month: 4.3,
'30d': 4.3,
year: 52,
'365d': 52
}[rangeKey];
const throughput = +(totalCompleted / periodWeeks).toFixed(1);
const priorThroughput = +(priorCompleted / periodWeeks).toFixed(1);
const completionRate = totalCreated > 0 ? Math.round(totalCompleted / totalCreated * 100) : 0;
const priorCompletionRate = priorCreated > 0 ? Math.round(priorCompleted / priorCreated * 100) : 0;
const cycle = dataStats.avgInProgressDays ?? 0;
return {
opt,
labels,
series,
totals: {
created: totalCreated,
completed: totalCompleted
},
kpis: {
created: {
value: totalCreated,
delta: pct(totalCreated, priorCreated)
},
completed: {
value: totalCompleted,
delta: pct(totalCompleted, priorCompleted)
},
throughput: {
value: throughput,
delta: pct(throughput, priorThroughput),
unit: '/wk'
},
cycle: {
value: cycle,
delta: 0,
unit: 'd',
deltaInverse: true
},
rate: {
value: completionRate,
delta: completionRate - priorCompletionRate,
unit: '%'
}
}
};
}
function StatsOverview({
dataStats,
mostActiveProject,
history
}) {
const [range, setRange] = useState("week");
const [chartMode, setChartMode] = useState("cumulative"); // cumulative | breakdown
const [hiddenStatuses, setHiddenStatuses] = useState(new Set());
const stats = useMemo(() => computeRangeStats(range, dataStats, history), [range, dataStats, history]);
const visibleStatuses = CHART_STATUSES.filter(s => !hiddenStatuses.has(s.key));
// Both modes show stacked totals; max is bucket sum across visible series.
const maxBar = useMemo(() => {
let m = 1;
for (let i = 0; i < stats.labels.length; i++) {
const s = visibleStatuses.reduce((acc, st) => acc + stats.series[st.key][i], 0);
if (s > m) m = s;
}
return m;
}, [stats, visibleStatuses]);
const dense = stats.labels.length > 12;
const labelStride = dense ? Math.ceil(stats.labels.length / 8) : 1;
const toggleStatus = key => {
setHiddenStatuses(prev => {
const next = new Set(prev);
if (next.has(key)) next.delete(key);else next.add(key);
return next;
});
};
return /*#__PURE__*/React.createElement("section", {
className: "card span-2 stats-card"
}, /*#__PURE__*/React.createElement("div", {
className: "card-head stats-head"
}, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("h3", null, "Stats overview"), /*#__PURE__*/React.createElement("span", {
className: "card-sub"
}, stats.opt.label.toLowerCase(), " \xB7 most active in ", /*#__PURE__*/React.createElement("strong", null, mostActiveProject))), /*#__PURE__*/React.createElement("div", {
className: "range-switch",
role: "tablist",
"aria-label": "Stats range"
}, RANGE_OPTIONS.map(opt => /*#__PURE__*/React.createElement("button", {
key: opt.key,
role: "tab",
"aria-selected": range === opt.key,
className: `range-btn ${range === opt.key ? "active" : ""}`,
onClick: () => setRange(opt.key)
}, opt.label)))), /*#__PURE__*/React.createElement("div", {
className: "kpi-grid"
}, /*#__PURE__*/React.createElement(Kpi, _extends({
label: "Created"
}, stats.kpis.created)), /*#__PURE__*/React.createElement(Kpi, _extends({
label: "Completed"
}, stats.kpis.completed)), /*#__PURE__*/React.createElement(Kpi, _extends({
label: "Throughput"
}, stats.kpis.throughput)), /*#__PURE__*/React.createElement(Kpi, _extends({
label: "Avg cycle"
}, stats.kpis.cycle)), /*#__PURE__*/React.createElement(Kpi, _extends({
label: "Completion rate"
}, stats.kpis.rate))), /*#__PURE__*/React.createElement("div", {
className: "chart-head"
}, /*#__PURE__*/React.createElement("div", {
className: "chart-legend",
role: "group",
"aria-label": "Toggle status series"
}, chartMode === "breakdown" ? CHART_STATUSES.map(s => {
const off = hiddenStatuses.has(s.key);
return /*#__PURE__*/React.createElement("button", {
key: s.key,
className: `legend-chip ${off ? "off" : ""}`,
onClick: () => toggleStatus(s.key),
title: off ? `Show ${s.label}` : `Hide ${s.label}`
}, /*#__PURE__*/React.createElement("span", {
className: "lg-swatch",
style: {
background: s.color
}
}), s.label);
}) : /*#__PURE__*/React.createElement("span", {
className: "legend-chip static"
}, /*#__PURE__*/React.createElement("span", {
className: "lg-swatch",
style: {
background: "var(--accent)"
}
}), "Total activity")), /*#__PURE__*/React.createElement("div", {
className: "mode-switch",
role: "tablist",
"aria-label": "Chart mode"
}, /*#__PURE__*/React.createElement("button", {
className: `mode-btn ${chartMode === "cumulative" ? "active" : ""}`,
onClick: () => setChartMode("cumulative"),
"aria-selected": chartMode === "cumulative",
role: "tab",
title: "Cumulative \u2014 single bar per bucket"
}, /*#__PURE__*/React.createElement(ModeIconCumulative, null), " Cumulative"), /*#__PURE__*/React.createElement("button", {
className: `mode-btn ${chartMode === "breakdown" ? "active" : ""}`,
onClick: () => setChartMode("breakdown"),
"aria-selected": chartMode === "breakdown",
role: "tab",
title: "Breakdown \u2014 stacked segments per status"
}, /*#__PURE__*/React.createElement(ModeIconBreakdown, null), " Breakdown"))), /*#__PURE__*/React.createElement("div", {
className: `stack-bars buckets-${stats.labels.length} mode-${chartMode}`
}, stats.labels.map((lbl, i) => {
const showLabel = i % labelStride === 0;
const bucketTotal = visibleStatuses.reduce((acc, st) => acc + stats.series[st.key][i], 0);
const tip = chartMode === "breakdown" ? visibleStatuses.map(st => `${st.label} ${stats.series[st.key][i]}`).join(" · ") : `total ${bucketTotal}`;
// Pre-compute % heights and bottoms for breakdown so segments stack
// without flex rounding errors. Bottom = sum of segments below.
let acc = 0;
const segs = chartMode === "breakdown" ? visibleStatuses.map(st => {
const v = stats.series[st.key][i];
if (v === 0) return null;
const heightPct = v / maxBar * 100;
const bottomPct = acc / maxBar * 100;
acc += v;
return {
st,
v,
heightPct,
bottomPct
};
}).filter(Boolean) : [];
return /*#__PURE__*/React.createElement("div", {
key: i,
className: "stack-col",
title: `${lbl} — ${tip}`
}, chartMode === "breakdown" ? /*#__PURE__*/React.createElement("div", {
className: "stack-stack"
}, segs.map((s, idx) => /*#__PURE__*/React.createElement("div", {
key: s.st.key,
className: `stack-seg ${idx === segs.length - 1 ? "top" : ""}`,
style: {
background: s.st.color,
height: `${s.heightPct}%`,
bottom: `${s.bottomPct}%`
},
"aria-label": `${s.st.label} ${s.v}`
}))) : /*#__PURE__*/React.createElement("div", {
className: "stack-stack cumulative-stack"
}, /*#__PURE__*/React.createElement("div", {
className: "stack-seg cumulative top",
style: {
height: `${bucketTotal / maxBar * 100}%`,
bottom: 0
},
"aria-label": `total ${bucketTotal}`
})), /*#__PURE__*/React.createElement("div", {
className: "stack-cap"
}, showLabel ? lbl : "", showLabel && bucketTotal > 0 && /*#__PURE__*/React.createElement("span", {
className: "stack-total"
}, bucketTotal)));
})));
}
const ModeIconCumulative = () => /*#__PURE__*/React.createElement("svg", {
width: "14",
height: "12",
viewBox: "0 0 14 12",
fill: "none",
"aria-hidden": true
}, /*#__PURE__*/React.createElement("rect", {
x: "0.5",
y: "6",
width: "3",
height: "5",
fill: "currentColor"
}), /*#__PURE__*/React.createElement("rect", {
x: "5.5",
y: "3",
width: "3",
height: "8",
fill: "currentColor"
}), /*#__PURE__*/React.createElement("rect", {
x: "10.5",
y: "5",
width: "3",
height: "6",
fill: "currentColor"
}));
const ModeIconBreakdown = () => /*#__PURE__*/React.createElement("svg", {
width: "14",
height: "12",
viewBox: "0 0 14 12",
fill: "none",
"aria-hidden": true
}, /*#__PURE__*/React.createElement("rect", {
x: "1",
y: "6",
width: "3",
height: "5",
fill: "currentColor",
opacity: "0.4"
}), /*#__PURE__*/React.createElement("rect", {
x: "1",
y: "2",
width: "3",
height: "4",
fill: "currentColor"
}), /*#__PURE__*/React.createElement("rect", {
x: "5.5",
y: "4",
width: "3",
height: "7",
fill: "currentColor",
opacity: "0.4"
}), /*#__PURE__*/React.createElement("rect", {
x: "5.5",
y: "1",
width: "3",
height: "3",
fill: "currentColor"
}), /*#__PURE__*/React.createElement("rect", {
x: "10",
y: "7",
width: "3",
height: "4",
fill: "currentColor",
opacity: "0.4"
}), /*#__PURE__*/React.createElement("rect", {
x: "10",
y: "3",
width: "3",
height: "4",
fill: "currentColor"
}));
function Kpi({
label,
value,
delta,
unit,
accent,
deltaInverse
}) {
// For metrics where lower is better (cycle time), invert sign
const positive = deltaInverse ? delta < 0 : delta > 0;
const negative = deltaInverse ? delta > 0 : delta < 0;
const arrow = delta === 0 ? "→" : positive ? "▲" : "▼";
const cls = delta === 0 ? "flat" : positive ? "up" : "down";
const formatted = Math.abs(delta) === 0 ? "0" : `${Math.abs(delta)}${unit === "%" ? "pp" : "%"}`;
return /*#__PURE__*/React.createElement("div", {
className: `kpi ${accent ? "kpi-accent" : ""}`
}, /*#__PURE__*/React.createElement("div", {
className: "kpi-label"
}, label), /*#__PURE__*/React.createElement("div", {
className: "kpi-value"
}, value, unit && /*#__PURE__*/React.createElement("span", {
className: "kpi-unit"
}, unit)), /*#__PURE__*/React.createElement("div", {
className: `kpi-delta ${cls}`
}, /*#__PURE__*/React.createElement("span", {
className: "kpi-arrow"
}, arrow), " ", formatted, " ", /*#__PURE__*/React.createElement("span", {
className: "kpi-vs"
}, "vs prior")));
}
const ICON_STYLES = [{
value: 'color',
label: 'Color',
hint: 'Filled circles with semantic colors'
}, {
value: 'flat',
label: 'Flat',
hint: 'Minimal monochrome SVG squares'
}, {
value: 'emoji',
label: 'Emoji',
hint: 'Native emoji glyphs'
}, {
value: 'ascii',
label: 'ASCII',
hint: 'Plain text glyphs: [ ] [/] [!] …'
}];
function AppearanceCard({
tweaks,
setTweak
}) {
const current = tweaks?.status_style || 'color';
return /*#__PURE__*/React.createElement("section", {
className: "card"
}, /*#__PURE__*/React.createElement("div", {
className: "card-head"
}, /*#__PURE__*/React.createElement("h3", null, "Appearance")), /*#__PURE__*/React.createElement("div", {
style: {
display: 'flex',
flexDirection: 'column',
gap: 6
}
}, ICON_STYLES.map(opt => /*#__PURE__*/React.createElement("label", {
key: opt.value,
style: {
display: 'flex',
alignItems: 'center',
gap: 10,
padding: '7px 10px',
borderRadius: 8,
cursor: 'pointer',
background: current === opt.value ? 'var(--bg-2)' : 'transparent',
border: `1px solid ${current === opt.value ? 'var(--rule)' : 'transparent'}`
}
}, /*#__PURE__*/React.createElement("input", {
type: "radio",
name: "icon-style",
value: opt.value,
checked: current === opt.value,
onChange: () => setTweak('status_style', opt.value),
style: {
accentColor: 'var(--accent)',
flexShrink: 0
}
}), /*#__PURE__*/React.createElement("div", {
style: {
display: 'flex',
gap: 5,
flexShrink: 0
}
}, ['open', 'in-progress', 'blocked', 'postponed', 'done', 'cancelled'].map(s => /*#__PURE__*/React.createElement(StatusStyleContext.Provider, {
key: s,
value: opt.value
}, /*#__PURE__*/React.createElement(StatusIcon, {
status: s,
size: 14
})))), /*#__PURE__*/React.createElement("div", {
style: {
display: 'flex',
flexDirection: 'column',
gap: 1
}
}, /*#__PURE__*/React.createElement("span", {
style: {
fontSize: 13,
fontWeight: 500,
color: 'var(--ink)'
}
}, opt.label), /*#__PURE__*/React.createElement("span", {
style: {
fontSize: 11.5,
color: 'var(--ink-3)'
}
}, opt.hint))))));
}
function AdminPage({
data,
onClose,
history,
tweaks,
setTweak,
onForceSave,
onForceBackup,
onCompact,
onRestore,
onDownloadBackup
}) {
const [previewBackup, setPreviewBackup] = useState(null);
const counts = countByStatus(data.entries);
const total = countAll(data.entries);
const maxStat = Math.max(1, ...Object.values(data.stats.statusMix));
return /*#__PURE__*/React.createElement("div", {
className: "admin"
}, /*#__PURE__*/React.createElement("div", {
className: "admin-head"
}, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
className: "eyebrow"
}, "Admin \xB7 Maintenance"), /*#__PURE__*/React.createElement("h2", null, "System overview")), /*#__PURE__*/React.createElement("button", {
className: "btn-secondary",
onClick: onClose
}, "\u2190 Back to backlog")), /*#__PURE__*/React.createElement("div", {
className: "admin-grid"
}, /*#__PURE__*/React.createElement("section", {
className: "card span-2"
}, /*#__PURE__*/React.createElement("div", {
className: "card-head"
}, /*#__PURE__*/React.createElement("h3", null, "System health"), /*#__PURE__*/React.createElement("span", {
className: `pill ${data.health.integrityOk ? "ok" : "warn"}`
}, data.health.integrityOk ? "✓ integrity ok" : "checksum mismatch")), /*#__PURE__*/React.createElement("dl", {
className: "kv"
}, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("dt", null, "Last save"), /*#__PURE__*/React.createElement("dd", null, fmtTimestamp(data.health.lastSave))), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("dt", null, "Last backup"), /*#__PURE__*/React.createElement("dd", null, fmtTimestamp(data.health.lastBackup))), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("dt", null, "Storage mode"), /*#__PURE__*/React.createElement("dd", null, data.health.mode)), data.health.masterPath && /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("dt", null, "File path"), /*#__PURE__*/React.createElement("dd", {
className: "mono small"
}, data.health.masterPath)), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("dt", null, "Checksum"), /*#__PURE__*/React.createElement("dd", {
className: "mono small"
}, data.meta.checksum.slice(0, 32), "\u2026")), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("dt", null, "Saved at"), /*#__PURE__*/React.createElement("dd", {
className: "mono small"
}, data.meta.saved)), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("dt", null, "Entries / history"), /*#__PURE__*/React.createElement("dd", null, data.meta.entryCount, " \xB7 ", data.meta.historyCount)))), /*#__PURE__*/React.createElement("section", {
className: "card"
}, /*#__PURE__*/React.createElement("div", {
className: "card-head"
}, /*#__PURE__*/React.createElement("h3", null, "Storage"), /*#__PURE__*/React.createElement("span", {
className: "card-sub mono"
}, fmtBytes(data.health.masterSize + data.health.backupDirSize + data.health.statsSize + data.health.historySize), " total")), /*#__PURE__*/React.createElement("dl", {
className: "kv"
}, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("dt", null, "backlog.md"), /*#__PURE__*/React.createElement("dd", null, fmtBytes(data.health.masterSize), " \xB7 ", data.meta.entryCount, " entries")), data.health.masterPath && /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("dt", null, "Path"), /*#__PURE__*/React.createElement("dd", {
className: "mono small"
}, data.health.masterPath)), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("dt", null, "history.jsonl"), /*#__PURE__*/React.createElement("dd", null, fmtBytes(data.health.historySize), " \xB7 ", data.meta.historyCount.toLocaleString(), " events")), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("dt", null, "backups/"), /*#__PURE__*/React.createElement("dd", null, fmtBytes(data.health.backupDirSize), " \xB7 ", data.health.backupCount, " files")), data.health.backupsPath && /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("dt", null, "Backups"), /*#__PURE__*/React.createElement("dd", {
className: "mono small"
}, data.health.backupsPath)), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("dt", null, "stats.jsonl"), /*#__PURE__*/React.createElement("dd", null, fmtBytes(data.health.statsSize), " \xB7 90-day rollup")), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("dt", null, "Oldest event"), /*#__PURE__*/React.createElement("dd", {
className: "mono small"
}, fmtTimestamp(data.health.historyOldest))))), /*#__PURE__*/React.createElement("section", {
className: "card"
}, /*#__PURE__*/React.createElement("div", {
className: "card-head"
}, /*#__PURE__*/React.createElement("h3", null, "Manual actions")), /*#__PURE__*/React.createElement("div", {
className: "action-list"
}, /*#__PURE__*/React.createElement("button", {
className: "action-btn",
onClick: onForceSave
}, /*#__PURE__*/React.createElement(Icon, {
name: "save",
size: 14
}), /*#__PURE__*/React.createElement("span", {
className: "action-text"
}, /*#__PURE__*/React.createElement("span", {
className: "action-label"
}, "Force save"), /*#__PURE__*/React.createElement("span", {
className: "action-meta"
}, "last save ", fmtRelative(data.health.lastSave)))), /*#__PURE__*/React.createElement("button", {
className: "action-btn",
onClick: onForceBackup
}, /*#__PURE__*/React.createElement(Icon, {
name: "archive",
size: 14
}), /*#__PURE__*/React.createElement("span", {
className: "action-text"
}, /*#__PURE__*/React.createElement("span", {
className: "action-label"
}, "Force backup"), /*#__PURE__*/React.createElement("span", {
className: "action-meta"
}, data.health.backupCount, " files \xB7 ", fmtBytes(data.health.backupDirSize)))), /*#__PURE__*/React.createElement("button", {
className: "action-btn",
onClick: onCompact
}, /*#__PURE__*/React.createElement(Icon, {
name: "refresh",
size: 14
}), /*#__PURE__*/React.createElement("span", {
className: "action-text"
}, /*#__PURE__*/React.createElement("span", {
className: "action-label"
}, "Compact history"), /*#__PURE__*/React.createElement("span", {
className: "action-meta"
}, data.meta.historyCount.toLocaleString(), " events \xB7 ", fmtBytes(data.health.historySize), " \xB7 since ", fmtShortDate(data.health.historyOldest)))))), /*#__PURE__*/React.createElement(StatsOverview, {
dataStats: data.stats,
mostActiveProject: data.stats.mostActiveProject,
history: history
}), /*#__PURE__*/React.createElement(AppearanceCard, {
tweaks: tweaks,
setTweak: setTweak
}), /*#__PURE__*/React.createElement("section", {
className: "card"
}, /*#__PURE__*/React.createElement("div", {
className: "card-head"
}, /*#__PURE__*/React.createElement("h3", null, "Status mix")), /*#__PURE__*/React.createElement("div", {
className: "status-mix"
}, STATUSES.map(s => {
const v = data.stats.statusMix[s.key] || 0;
return /*#__PURE__*/React.createElement("div", {
key: s.key,
className: "mix-row"
}, /*#__PURE__*/React.createElement("span", {
className: `glyph status-${s.key}`
}, s.glyph), /*#__PURE__*/React.createElement("span", {
className: "mix-label"
}, s.label), /*#__PURE__*/React.createElement("span", {
className: "mix-bar"
}, /*#__PURE__*/React.createElement("span", {
className: "mix-fill",
style: {
width: `${v / maxStat * 100}%`
}
})), /*#__PURE__*/React.createElement("span", {
className: "mix-num"
}, v));
}))), /*#__PURE__*/React.createElement("section", {
className: "card span-3"
}, /*#__PURE__*/React.createElement("div", {
className: "card-head"
}, /*#__PURE__*/React.createElement("h3", null, "Backup browser"), /*#__PURE__*/React.createElement("span", {
className: "card-sub"
}, data.backups.length, " files \xB7 keeping \u22657 days, \u226530 days of dailies")), /*#__PURE__*/React.createElement("table", {
className: "backup-table"
}, /*#__PURE__*/React.createElement("thead", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("th", null, "Filename"), /*#__PURE__*/React.createElement("th", null, "Timestamp"), /*#__PURE__*/React.createElement("th", null, "Size"), /*#__PURE__*/React.createElement("th", null, "Entries"), /*#__PURE__*/React.createElement("th", null, "Integrity"), /*#__PURE__*/React.createElement("th", null))), /*#__PURE__*/React.createElement("tbody", null, data.backups.map(b => /*#__PURE__*/React.createElement("tr", {
key: b.name,
className: previewBackup === b.name ? "active" : ""
}, /*#__PURE__*/React.createElement("td", {
className: "mono"
}, b.name), /*#__PURE__*/React.createElement("td", null, fmtTimestamp(b.timestamp)), /*#__PURE__*/React.createElement("td", null, fmtBytes(b.size)), /*#__PURE__*/React.createElement("td", null, b.entries ?? /*#__PURE__*/React.createElement("span", {
className: "muted"
}, "\u2014")), /*#__PURE__*/React.createElement("td", null, b.valid ? /*#__PURE__*/React.createElement("span", {
className: "pill mini ok"
}, "\u2713 valid") : /*#__PURE__*/React.createElement("span", {
className: "pill mini warn"
}, /*#__PURE__*/React.createElement(Icon, {
name: "warn",
size: 10
}), " mismatch")), /*#__PURE__*/React.createElement("td", {
className: "row-actions-cell"
}, /*#__PURE__*/React.createElement("button", {
className: "row-btn",
onClick: () => setPreviewBackup(previewBackup === b.name ? null : b.name)
}, /*#__PURE__*/React.createElement(Icon, {
name: "eye",
size: 12
}), " Preview"), /*#__PURE__*/React.createElement("button", {
className: "row-btn",
onClick: () => onDownloadBackup(b.name)
}, /*#__PURE__*/React.createElement(Icon, {
name: "download",
size: 12
}), " Download"), /*#__PURE__*/React.createElement("button", {
className: "row-btn primary",
onClick: () => onRestore(b)
}, "Restore")))))), previewBackup && /*#__PURE__*/React.createElement("div", {
className: "backup-preview"
}, /*#__PURE__*/React.createElement("div", {
className: "preview-head"
}, /*#__PURE__*/React.createElement("span", {
className: "mono"
}, previewBackup), /*#__PURE__*/React.createElement("span", {
className: "card-sub"
}, "read-only preview")), /*#__PURE__*/React.createElement("pre", {
className: "preview-body"
}, `# Backlog
<!-- SECTION: ENTRIES -->
## [P0] 🔥 Personal backlog app
- [x] Markdown parser + integrity marker *(done: 2026-04-29)*
- [x] Tokenize three sections
- [x] SHA-256 over entries+history
- [/] Tree renderer with parent-visibility filter *(due: 2026-05-04)*
- [ ] Expand / collapse animations
- [ ] Drag handle within priority group *(due: 2026-05-06)*
- [!] File System Access API direct mode *(reason: Need to test on Edge — no machine yet)*
…
<!-- SECTION: HISTORY -->
| Timestamp | Item ID | Action | Details |
…
<!-- SECTION: INTEGRITY -->
<!-- saved: 2026-04-30T19:44:02Z | checksum: sha256:8a1c3e… | entries: 27 | history: 10 -->`))), /*#__PURE__*/React.createElement("section", {
className: "card span-3"
}, /*#__PURE__*/React.createElement("div", {
className: "card-head"
}, /*#__PURE__*/React.createElement("h3", null, "Audit log"), /*#__PURE__*/React.createElement("span", {
className: "card-sub"
}, /*#__PURE__*/React.createElement("strong", null, data.meta.historyCount.toLocaleString()), " events \xB7", " ", fmtBytes(data.health.historySize), " \xB7", " ", "since ", fmtShortDate(data.health.historyOldest), " \xB7", " ", "showing latest 10")), /*#__PURE__*/React.createElement("table", {
className: "history-table"
}, /*#__PURE__*/React.createElement("thead", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("th", null, "Timestamp"), /*#__PURE__*/React.createElement("th", null, "Item ID"), /*#__PURE__*/React.createElement("th", null, "Action"), /*#__PURE__*/React.createElement("th", null, "Details"))), /*#__PURE__*/React.createElement("tbody", null, history.slice(0, 10).map((h, i) => /*#__PURE__*/React.createElement("tr", {
key: i
}, /*#__PURE__*/React.createElement("td", {
className: "mono small"
}, h.timestamp), /*#__PURE__*/React.createElement("td", {
className: "mono small"
}, h.itemId), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("span", {
className: "pill mini neutral"
}, h.action.replace(/_/g, " "))), /*#__PURE__*/React.createElement("td", null, h.details))))))));
}
window.AdminPage = AdminPage;
</script>
<script>
// Main App — top shell, state management, real storage load/save flow.
const {
useState: useStateMain,
useEffect: useEffectMain,
useMemo: useMemoMain,
useRef: useRefMain
} = React;
const LS_KEY = "personal-backlog-state-v1";
function loadLocalState() {
try {
const raw = localStorage.getItem(LS_KEY);
if (!raw) return null;
return JSON.parse(raw);
} catch {
return null;
}
}
// Only UI state (expanded rows, tweaks) is persisted locally.
// Backlog data always lives in backlog.md — never in localStorage.
function saveLocalState(expandedMap, tweaks) {
try {
localStorage.setItem(LS_KEY, JSON.stringify({
expandedMap,
tweaks
}));
} catch {/* quota / private mode */}
}
// Empty starting state — used when there is no saved data and no seed data loaded.
function buildEmptyData() {
const days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'].map(day => ({
day,
count: 0
}));
return {
entries: [],
history: [],
meta: {
saved: null,
checksum: '—',
entryCount: 0,
historyCount: 0
},
health: {
integrityOk: true,
lastSave: null,
lastBackup: null,
masterSize: 0,
backupDirSize: 0,
backupCount: 0,
statsSize: 0,
historySize: 0,
historyOldest: null,
mode: 'localStorage only'
},
stats: {
createdThisWeek: 0,
completedThisWeek: 0,
avgInProgressDays: null,
mostActiveProject: '—',
completionByDay: days.map(d => ({
...d
})),
createdByDay: days.map(d => ({
...d
})),
statusMix: {
open: 0,
'in-progress': 0,
blocked: 0,
postponed: 0,
done: 0,
cancelled: 0
}
},
backups: []
};
}
function App() {
const [data, setData] = useStateMain(buildEmptyData);
const [storageMode, setStorageMode] = useStateMain('local'); // 'api' | 'direct' | 'local'
const [isLoading, setIsLoading] = useStateMain(true);
const [view, setView] = useStateMain('backlog');
const [filters, setFilters] = useStateMain({
statuses: [],
priorities: [],
tags: [],
dueRange: null,
scope: 'all',
text: ''
});
const [expandedMap, setExpandedMap] = useStateMain(() => loadLocalState()?.expandedMap ?? {});
const [saveState, setSaveState] = useStateMain({
status: 'idle',
lastSaved: data.health?.lastSave || null
});
const [toast, setToast] = useStateMain(null);
const [showWarning, setShowWarning] = useStateMain(false);
const [importExportOpen, setImportExportOpen] = useStateMain(false);
const [itemDialog, setItemDialog] = useStateMain(null);
const [confirm, setConfirm] = useStateMain(null);
const [needsConnect, setNeedsConnect] = useStateMain(false);
const TWEAK_DEFAULTS = {
accent_hue: 35,
density: 'comfortable',
show_ids: false,
paper_texture: true,
status_style: 'color',
sort_mode: 'priority'
};
const [tweaks, setTweak] = useTweaks({
...TWEAK_DEFAULTS,
...(loadLocalState()?.tweaks ?? {})
});
// Refs for async callbacks that need latest state without stale closures.
const latestData = useRefMain(data);
const latestExpandedMap = useRefMain(expandedMap);
const isDirtyRef = useRefMain(false);
const saveTimerRef = useRefMain(null);
useEffectMain(() => {
latestData.current = data;
}, [data]);
useEffectMain(() => {
latestExpandedMap.current = expandedMap;
}, [expandedMap]);
useEffectMain(() => {
document.documentElement.style.setProperty('--accent-hue', tweaks.accent_hue);
document.documentElement.dataset.density = tweaks.density;
document.documentElement.dataset.showIds = tweaks.show_ids ? 'true' : 'false';
document.documentElement.dataset.paper = tweaks.paper_texture ? 'true' : 'false';
}, [tweaks]);
// ---- Storage initialisation (runs once on mount) ----
useEffectMain(() => {
let cancelled = false;
async function initStorage() {
try {
const mode = await Storage.detect();
setStorageMode(mode);
if (mode === 'local') {
setIsLoading(false);
return;
}
if (mode === 'browser') {
if (cancelled) return;
await applyStorageData(mode, () => cancelled);
return;
}
if (mode === 'direct') {
// Try silent reconnect — works if permission is still active from a previous session.
const ok = await Storage.tryAutoConnect();
if (!ok) {
// Can't connect without a user gesture — show the connect button instead of blocking.
setIsLoading(false);
setNeedsConnect(true);
return;
}
}
// API mode needs no init — server is already running.
if (cancelled) return;
await applyStorageData(mode, () => cancelled);
} catch (e) {
if (cancelled) return;
setStorageMode('local');
showToast('Storage init failed: ' + e.message, 'err');
} finally {
if (!cancelled) setIsLoading(false);
}
}
async function applyStorageData(mode, isCancelled) {
const [raw, backups, sizeInfo] = await Promise.all([Storage.load(), Storage.listBackups(), Storage.getHealthInfo()]);
if (isCancelled?.()) return;
const parsed = await Parser.parse(raw?.content || '');
const newData = await buildDataFromStorage(parsed, backups, mode || Storage.mode, sizeInfo);
if (isCancelled?.()) return;
setData(newData);
if (!loadLocalState()?.expandedMap) {
const em = {};
walkTree(newData.entries, it => {
em[it.id] = !it.collapsed;
});
setExpandedMap(em);
}
if (!parsed.checksumOk && parsed.meta) setShowWarning(true);
SyncPoller.lastChecksum = parsed.meta?.checksum || '';
SyncPoller.start({
isDirty: () => isDirtyRef.current,
onExternalChange: async (kind, freshParsed) => {
if (kind === 'warn') {
showToast('File changed externally — you have unsaved edits', 'warn');
} else if (kind === 'reload' && freshParsed) {
const [nb, ns] = await Promise.all([Storage.listBackups(), Storage.getHealthInfo()]);
setData(await buildDataFromStorage(freshParsed, nb, Storage.mode, ns));
showToast('Reloaded from disk');
}
}
});
}
initStorage();
return () => {
cancelled = true;
SyncPoller.stop();
};
}, []);
// Persist expanded/collapsed row state and tweaks locally. Data itself lives in backlog.md.
useEffectMain(() => {
saveLocalState(latestExpandedMap.current, tweaks);
}, [expandedMap, tweaks]);
const showToast = (msg, kind = 'ok') => {
setToast({
msg,
kind,
t: Date.now()
});
setTimeout(() => setToast(t => t && Date.now() - t.t >= 2400 ? null : t), 2500);
};
// ---- Connect to backlog.md (user-triggered, called from the connect banner) ----
const handleConnect = async () => {
try {
await Storage.connect();
const [raw, backups, sizeInfo] = await Promise.all([Storage.load(), Storage.listBackups(), Storage.getHealthInfo()]);
const parsed = await Parser.parse(raw?.content || '');
const newData = await buildDataFromStorage(parsed, backups, Storage.mode, sizeInfo);
setData(newData);
if (!loadLocalState()?.expandedMap) {
const em = {};
walkTree(newData.entries, it => {
em[it.id] = !it.collapsed;
});
setExpandedMap(em);
}
if (!parsed.checksumOk && parsed.meta) setShowWarning(true);
SyncPoller.lastChecksum = parsed.meta?.checksum || '';
SyncPoller.start({
isDirty: () => isDirtyRef.current,
onExternalChange: async (kind, freshParsed) => {
if (kind === 'warn') {
showToast('File changed externally — you have unsaved edits', 'warn');
} else if (kind === 'reload' && freshParsed) {
const [nb, ns] = await Promise.all([Storage.listBackups(), Storage.getHealthInfo()]);
setData(await buildDataFromStorage(freshParsed, nb, Storage.mode, ns));
showToast('Reloaded from disk');
}
}
});
setNeedsConnect(false);
} catch (e) {
showToast('Connect failed: ' + e.message, 'err');
}
};
// ---- Real async save ----
const triggerSave = label => {
isDirtyRef.current = true;
setSaveState(prev => ({
...prev,
status: 'saving'
}));
if (saveTimerRef.current) clearTimeout(saveTimerRef.current);
saveTimerRef.current = setTimeout(async () => {
const d = latestData.current;
const em = latestExpandedMap.current;
try {
if (Storage.isConnected()) {
const content = await Parser.serialize({
entries: d.entries,
history: d.history
});
await Storage.save(content);
// Keep SyncPoller in sync with our own save to avoid false external-change triggers.
const cm = content.match(/checksum:\s*(sha256:[a-f0-9]+)/);
if (cm) SyncPoller.lastChecksum = cm[1];
}
saveLocalState(em, tweaks);
isDirtyRef.current = false;
const now = new Date().toISOString();
setSaveState({
status: 'saved',
lastSaved: now
});
setData(prev => ({
...prev,
health: {
...prev.health,
lastSave: now
},
meta: {
...prev.meta,
saved: now
}
}));
if (label) showToast(label);
} catch (e) {
setSaveState(prev => ({
...prev,
status: 'error'
}));
showToast('Save failed: ' + e.message, 'err');
}
}, 600);
};
const mutate = fn => {
isDirtyRef.current = true;
setData(d => {
const c = structuredClone(d);
fn(c);
return c;
});
};
// ---- Helpers ----
function findParentList(items, id, parent = null) {
for (const it of items) {
if (it.id === id) return {
list: items,
parent
};
if (it.children?.length) {
const r = findParentList(it.children, id, it);
if (r) return r;
}
}
return null;
}
const recentTags = useMemoMain(() => {
const counts = {};
walkTree(data.entries, it => (it.tags || []).forEach(t => counts[t] = (counts[t] || 0) + 1));
return Object.entries(counts).sort((a, b) => b[1] - a[1]).map(([t]) => t);
}, [data]);
// ---- Mutations ----
const onMutate = {
setStatus: (id, status) => {
mutate(d => {
const it = findItem(d.entries, id);
if (!it || it.status === status) return;
d.history.unshift({
timestamp: new Date().toISOString(),
itemId: id,
action: 'status_changed',
details: `${it.status} → ${status}`
});
const wasDone = it.status === 'done';
it.status = status;
if (status !== 'blocked') it.reason = null;
if (status === 'done') it.progress = 100;else if (wasDone && (it.progress ?? 0) >= 100) it.progress = 75;
});
triggerSave();
},
setPriority: (id, priority) => {
mutate(d => {
const it = findItem(d.entries, id);
if (!it || it.priority === priority) return;
d.history.unshift({
timestamp: new Date().toISOString(),
itemId: id,
action: 'priority_changed',
details: `${it.priority} → ${priority}`
});
it.priority = priority;
});
triggerSave();
},
setProgress: (id, progress) => {
mutate(d => {
const it = findItem(d.entries, id);
if (!it) return;
const v = snapProgress(progress);
if ((it.progress ?? 0) === v) return;
const before = it.progress ?? 0;
it.progress = v;
d.history.unshift({
timestamp: new Date().toISOString(),
itemId: id,
action: 'progress_changed',
details: `${before}% → ${v}%`
});
});
triggerSave();
},
moveWithinPriority: (id, dir) => {
mutate(d => {
const r = findParentList(d.entries, id);
if (!r) return;
const i = r.list.findIndex(x => x.id === id);
if (i < 0) return;
const me = r.list[i];
let j = i + dir;
while (j >= 0 && j < r.list.length && r.list[j].priority !== me.priority) j += dir;
if (j < 0 || j >= r.list.length) return;
[r.list[i], r.list[j]] = [r.list[j], r.list[i]];
d.history.unshift({
timestamp: new Date().toISOString(),
itemId: id,
action: 'item_reordered',
details: `moved ${dir < 0 ? 'up' : 'down'}`
});
});
triggerSave();
},
reorder: (draggedId, targetId) => {
mutate(d => {
const src = findParentList(d.entries, draggedId);
const tgt = findParentList(d.entries, targetId);
if (!src || !tgt || src.list !== tgt.list) return;
const draggedIdx = src.list.findIndex(x => x.id === draggedId);
const dragged = src.list[draggedIdx];
src.list.splice(draggedIdx, 1);
const newTargetIdx = tgt.list.findIndex(x => x.id === targetId);
tgt.list.splice(newTargetIdx, 0, dragged);
d.history.unshift({
timestamp: new Date().toISOString(),
itemId: draggedId,
action: 'item_reordered',
details: `dropped before ${targetId}`
});
});
triggerSave('Reordered');
},
addChild: parentId => setItemDialog({
mode: 'add-child',
parentId,
initial: null
}),
addRoot: () => setItemDialog({
mode: 'add',
parentId: null,
initial: null
}),
editItem: id => {
const it = findItem(data.entries, id);
if (!it) return;
setItemDialog({
mode: 'edit',
itemId: id,
initial: it
});
},
deleteItem: id => {
const it = findItem(data.entries, id);
if (!it) return;
const childCount = (() => {
let n = 0;
walkTree([it], () => n++);
return n - 1;
})();
setConfirm({
title: 'Delete this item?',
message: /*#__PURE__*/React.createElement(React.Fragment, null, "Delete ", /*#__PURE__*/React.createElement("strong", null, it.title), childCount > 0 ? ` and ${childCount} sub-item${childCount > 1 ? 's' : ''}` : '', "?"),
detail: /*#__PURE__*/React.createElement("span", {
className: "muted"
}, "This will be recorded in the history log."),
confirmLabel: 'Delete',
danger: true,
onConfirm: () => {
mutate(d => {
function remove(list) {
const i = list.findIndex(x => x.id === id);
if (i >= 0) {
list.splice(i, 1);
return true;
}
for (const x of list) if (x.children?.length && remove(x.children)) return true;
return false;
}
remove(d.entries);
d.history.unshift({
timestamp: new Date().toISOString(),
itemId: id,
action: 'item_deleted',
details: `final: ${it.status}`
});
});
setConfirm(null);
triggerSave('Deleted');
}
});
}
};
const submitItemDialog = vals => {
if (itemDialog.mode === 'edit') {
mutate(d => {
const x = findItem(d.entries, itemDialog.itemId);
if (!x) return;
const before = {
priority: x.priority,
status: x.status
};
Object.assign(x, vals);
if (before.status !== vals.status) d.history.unshift({
timestamp: new Date().toISOString(),
itemId: x.id,
action: 'status_changed',
details: `${before.status} → ${vals.status}`
});
if (before.priority !== vals.priority) d.history.unshift({
timestamp: new Date().toISOString(),
itemId: x.id,
action: 'priority_changed',
details: `${before.priority} → ${vals.priority}`
});
});
triggerSave('Saved');
} else {
const newId = 'n-' + Math.random().toString(36).slice(2, 8);
mutate(d => {
const node = {
id: newId,
level: 1,
...vals,
children: [],
collapsed: false
};
if (itemDialog.mode === 'add-child' && itemDialog.parentId) {
const parent = findItem(d.entries, itemDialog.parentId);
if (parent) {
parent.children = parent.children || [];
node.level = (parent.level || 1) + 1;
parent.children.push(node);
setExpandedMap(m => ({
...m,
[parent.id]: true
}));
}
} else {
d.entries.push(node);
}
d.history.unshift({
timestamp: new Date().toISOString(),
itemId: newId,
action: 'item_created',
details: vals.title
});
});
triggerSave('Added');
}
setItemDialog(null);
};
const setExpanded = (id, val) => setExpandedMap(m => ({
...m,
[id]: val
}));
const tagsList = useMemoMain(() => allTags(data.entries), [data]);
const counts = useMemoMain(() => countByStatus(data.entries), [data]);
const filtered = useMemoMain(() => {
const f = {
...filters,
text: filters.text?.trim() || ''
};
const noFilters = !f.statuses?.length && !f.priorities?.length && !f.tags?.length && !f.dueRange && !f.text;
let tree = noFilters ? data.entries : filterTree(data.entries, f);
tree = structuredClone(tree);
if (tweaks.sort_mode === 'priority') {
function sortRecur(list) {
list.sort((a, b) => PRIORITIES.indexOf(a.priority) - PRIORITIES.indexOf(b.priority));
list.forEach(it => it.children?.length && sortRecur(it.children));
}
sortRecur(tree);
}
if (f.scope === 'top') tree = tree.map(it => ({
...it,
children: []
}));
return tree;
}, [data, filters, tweaks.sort_mode]);
const filteredCount = useMemoMain(() => countAll(filtered), [filtered]);
const totalCount = useMemoMain(() => countAll(data.entries), [data]);
// ---- Keyboard shortcuts ----
useEffectMain(() => {
const onKey = e => {
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
if (e.key === '/' && !e.metaKey) {
e.preventDefault();
document.querySelector('.search-input')?.focus();
}
if (e.key === 'g') setView('backlog');
if (e.key === 'a') setView('admin');
if (e.key === 'n') onMutate.addRoot();
};
window.addEventListener('keydown', onKey);
return () => window.removeEventListener('keydown', onKey);
}, []);
// ---- Restore from backup ----
const handleRestore = b => {
setConfirm({
title: 'Restore this backup?',
danger: false,
message: /*#__PURE__*/React.createElement(React.Fragment, null, "Overwrite ", /*#__PURE__*/React.createElement("code", {
className: "mono"
}, "backlog.md"), " with the contents of this backup."),
detail: /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
className: "mono small"
}, b.name), !b.valid && /*#__PURE__*/React.createElement("div", {
className: "restore-warn"
}, /*#__PURE__*/React.createElement(Icon, {
name: "warn",
size: 14
}), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
className: "restore-warn-title"
}, "Checksum mismatch on this backup"), /*#__PURE__*/React.createElement("div", {
className: "restore-warn-body"
}, "The file may be partially written or edited externally.")))),
confirmLabel: 'Restore',
onConfirm: async () => {
setConfirm(null);
try {
if (Storage.isConnected()) {
const result = await Storage.restoreBackup(b.name);
if (!result.ok) throw new Error(result.error || 'Restore failed');
const [raw, backups, sizeInfo] = await Promise.all([Storage.load(), Storage.listBackups(), Storage.getHealthInfo()]);
const parsed = await Parser.parse(raw?.content || '');
const newData = await buildDataFromStorage(parsed, backups, storageMode, sizeInfo);
setData(newData);
SyncPoller.lastChecksum = parsed.meta?.checksum || '';
isDirtyRef.current = false;
}
showToast(`Restored from ${b.name.slice(0, 28)}…`);
} catch (e) {
showToast('Restore failed: ' + e.message, 'err');
}
}
});
};
// ---- Import entries from parsed content ----
const handleImport = ({
entries,
history
}) => {
mutate(d => {
d.entries = entries;
if (history?.length) d.history = [...history, ...d.history];
d.history.unshift({
timestamp: new Date().toISOString(),
itemId: 'system',
action: 'imported',
details: `${entries.length} top-level entries`
});
});
setImportExportOpen(false);
triggerSave('Imported');
};
const saveLabel = saveState.status === 'saving' ? 'Saving…' : saveState.status === 'error' ? 'Save failed' : `Saved · ${fmtTimestamp(saveState.lastSaved)}`;
const hasFilters = filters.text || filters.statuses?.length || filters.priorities?.length || filters.tags?.length || filters.dueRange;
if (isLoading) {
return /*#__PURE__*/React.createElement("div", {
className: "app",
style: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
height: '100vh'
}
}, /*#__PURE__*/React.createElement("div", {
style: {
textAlign: 'center',
color: 'var(--ink-3)'
}
}, /*#__PURE__*/React.createElement("div", {
style: {
fontSize: 22,
marginBottom: 8
}
}, "Loading\u2026"), /*#__PURE__*/React.createElement("div", {
style: {
fontSize: 13
}
}, "Connecting to storage")));
}
return /*#__PURE__*/React.createElement("div", {
className: "app"
}, /*#__PURE__*/React.createElement(StatusStyleContext.Provider, {
value: tweaks.status_style
}, /*#__PURE__*/React.createElement(Header, {
view: view,
setView: setView,
saveState: saveState,
saveLabel: saveLabel,
storageMode: storageMode,
searchValue: filters.text,
onSearch: v => setFilters({
...filters,
text: v
}),
onForceSave: () => triggerSave('Saved manually'),
onOpenImportExport: () => setImportExportOpen(true)
}), storageMode === 'local' && /*#__PURE__*/React.createElement("div", {
className: "banner warn",
style: {
gap: 8
}
}, /*#__PURE__*/React.createElement(Icon, {
name: "warn",
size: 14
}), /*#__PURE__*/React.createElement("span", null, "This browser can't access local files directly \u2014 ", /*#__PURE__*/React.createElement("strong", null, "changes won't be saved."), ' ', "Open in Chrome or Edge to save without a server, or run", ' ', /*#__PURE__*/React.createElement("code", {
className: "mono"
}, "python3 server/server.py"), " for any browser.")), storageMode === 'browser' && /*#__PURE__*/React.createElement("div", {
className: "banner info",
style: {
gap: 8
}
}, /*#__PURE__*/React.createElement(Icon, {
name: "folder",
size: 14
}), /*#__PURE__*/React.createElement("span", null, "Data saved in ", /*#__PURE__*/React.createElement("strong", null, "browser storage"), " \u2014 persists until you clear site data.", ' ', "Use ", /*#__PURE__*/React.createElement("em", null, "Import/Export"), " to back up to a file.")), needsConnect && /*#__PURE__*/React.createElement("div", {
className: "banner info"
}, /*#__PURE__*/React.createElement(Icon, {
name: "folder",
size: 14
}), "No ", /*#__PURE__*/React.createElement("code", {
className: "mono"
}, "backlog.md"), " connected \u2014 grant one-time folder access, then reloads are silent.", /*#__PURE__*/React.createElement("button", {
className: "btn-primary",
style: {
marginLeft: 'auto',
flexShrink: 0,
fontSize: 12,
padding: '3px 10px'
},
onClick: handleConnect
}, "Open folder\u2026")), showWarning && /*#__PURE__*/React.createElement("div", {
className: "banner warn"
}, /*#__PURE__*/React.createElement(Icon, {
name: "warn",
size: 14
}), "File was edited outside the app \u2014 checksum mismatch. The next save will rewrite a correct marker.", /*#__PURE__*/React.createElement("button", {
className: "banner-close",
onClick: () => setShowWarning(false)
}, "dismiss")), view === 'backlog' ? /*#__PURE__*/React.createElement("div", {
className: "main"
}, /*#__PURE__*/React.createElement(FilterPanel, {
filters: filters,
setFilters: setFilters,
tagsList: tagsList,
counts: counts
}), /*#__PURE__*/React.createElement("section", {
className: "content"
}, /*#__PURE__*/React.createElement("div", {
className: "content-sticky"
}, /*#__PURE__*/React.createElement("div", {
className: "content-head"
}, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
className: "eyebrow"
}, "Backlog"), /*#__PURE__*/React.createElement("h1", {
className: "content-title"
}, hasFilters ? /*#__PURE__*/React.createElement(React.Fragment, null, filteredCount, " of ", totalCount, " items") : /*#__PURE__*/React.createElement(React.Fragment, null, totalCount, " items"))), /*#__PURE__*/React.createElement("div", {
className: "content-head-actions"
}, /*#__PURE__*/React.createElement("div", {
className: "seg seg-mini",
title: "Order"
}, /*#__PURE__*/React.createElement("button", {
className: `seg-btn ${tweaks.sort_mode === 'priority' ? 'active' : ''}`,
onClick: () => setTweak('sort_mode', 'priority')
}, "By priority"), /*#__PURE__*/React.createElement("button", {
className: `seg-btn ${tweaks.sort_mode === 'manual' ? 'active' : ''}`,
onClick: () => setTweak('sort_mode', 'manual')
}, "Manual")), /*#__PURE__*/React.createElement("button", {
className: "btn-primary",
onClick: onMutate.addRoot
}, /*#__PURE__*/React.createElement(Icon, {
name: "plus",
size: 12
}), " New item"))), /*#__PURE__*/React.createElement(ViewChips, {
filters: filters,
setFilters: setFilters
}), /*#__PURE__*/React.createElement("div", {
className: "legend"
}, /*#__PURE__*/React.createElement("span", {
className: "legend-cap"
}, "Status:"), STATUSES.map(s => /*#__PURE__*/React.createElement("span", {
key: s.key,
className: "legend-item"
}, /*#__PURE__*/React.createElement(StatusIcon, {
status: s.key,
size: 13
}), /*#__PURE__*/React.createElement("span", null, s.label))), /*#__PURE__*/React.createElement("span", {
className: "legend-sep"
}, "\xB7"), /*#__PURE__*/React.createElement("span", {
className: "legend-hint"
}, tweaks.sort_mode === 'manual' ? /*#__PURE__*/React.createElement(React.Fragment, null, "Drag rows to reorder \xB7 ") : /*#__PURE__*/React.createElement(React.Fragment, null, "Auto-sorted by priority \xB7 drag/arrows reorder within priority \xB7 "), /*#__PURE__*/React.createElement("kbd", null, "/"), " search \xB7 ", /*#__PURE__*/React.createElement("kbd", null, "n"), " new"))), /*#__PURE__*/React.createElement("div", {
className: "content-scroll"
}, filtered.length === 0 ? /*#__PURE__*/React.createElement("div", {
className: "empty-state"
}, /*#__PURE__*/React.createElement("div", {
className: "empty-glyph"
}, "\u2205"), /*#__PURE__*/React.createElement("div", null, hasFilters ? 'No items match these filters.' : 'No items yet. Press n or click "+ New item" to start.')) : /*#__PURE__*/React.createElement(BacklogTree, {
items: filtered,
expandedMap: expandedMap,
setExpanded: setExpanded,
onMutate: onMutate,
query: filters.text?.trim() || '',
statusStyle: tweaks.status_style,
manualOrder: tweaks.sort_mode === 'manual'
})))) : /*#__PURE__*/React.createElement(AdminPage, {
data: data,
history: data.history,
tweaks: tweaks,
setTweak: setTweak,
onClose: () => setView('backlog'),
onForceSave: () => triggerSave('Force-saved'),
onForceBackup: () => triggerSave('Force-backed up'),
onCompact: () => {
mutate(d => {
if (d.history.length > 200) d.history = d.history.slice(0, 200);
});
triggerSave('History compacted');
},
onRestore: handleRestore,
onDownloadBackup: name => {
if (Storage.mode === 'api') {
const a = document.createElement('a');
a.href = `/api/backups/${encodeURIComponent(name)}`;
a.download = name;
a.click();
} else {
showToast(`${name.slice(0, 28)}… — download not available in direct mode`);
}
}
}), /*#__PURE__*/React.createElement(ItemDialog, {
open: !!itemDialog,
mode: itemDialog?.mode,
initial: itemDialog?.initial,
recentTags: recentTags,
onClose: () => setItemDialog(null),
onSubmit: submitItemDialog
}), /*#__PURE__*/React.createElement(ConfirmDialog, {
open: !!confirm,
title: confirm?.title,
message: confirm?.message,
detail: confirm?.detail,
confirmLabel: confirm?.confirmLabel,
danger: confirm?.danger,
onCancel: () => setConfirm(null),
onConfirm: confirm?.onConfirm
}), /*#__PURE__*/React.createElement(ImportExportDialog, {
open: importExportOpen,
data: data,
storageMode: storageMode,
onClose: () => setImportExportOpen(false),
onImport: handleImport
}), toast && /*#__PURE__*/React.createElement("div", {
className: `toast ${toast.kind}`
}, /*#__PURE__*/React.createElement(Icon, {
name: "check",
size: 12
}), " ", toast.msg), /*#__PURE__*/React.createElement(TweaksPanel, {
title: "Tweaks"
}, /*#__PURE__*/React.createElement(TweakSection, {
title: "Status icons"
}, /*#__PURE__*/React.createElement(TweakRadio, {
label: "Style",
value: tweaks.status_style,
options: [{
value: 'flat',
label: 'Flat'
}, {
value: 'ascii',
label: 'ASCII'
}, {
value: 'color',
label: 'Color'
}, {
value: 'emoji',
label: 'Emoji'
}],
onChange: v => setTweak('status_style', v)
})), /*#__PURE__*/React.createElement(TweakSection, {
title: "Order"
}, /*#__PURE__*/React.createElement(TweakRadio, {
label: "Sort",
value: tweaks.sort_mode,
options: [{
value: 'priority',
label: 'By priority'
}, {
value: 'manual',
label: 'Manual'
}],
onChange: v => setTweak('sort_mode', v)
})), /*#__PURE__*/React.createElement(TweakSection, {
title: "Accent"
}, /*#__PURE__*/React.createElement(TweakSlider, {
label: "Hue",
value: tweaks.accent_hue,
min: 0,
max: 360,
step: 1,
onChange: v => setTweak('accent_hue', v),
formatValue: v => `${v}°`
})), /*#__PURE__*/React.createElement(TweakSection, {
title: "Layout"
}, /*#__PURE__*/React.createElement(TweakRadio, {
label: "Density",
value: tweaks.density,
options: [{
value: 'comfortable',
label: 'Comfortable'
}, {
value: 'compact',
label: 'Compact'
}],
onChange: v => setTweak('density', v)
}), /*#__PURE__*/React.createElement(TweakToggle, {
label: "Paper texture",
checked: tweaks.paper_texture,
onChange: v => setTweak('paper_texture', v)
})), /*#__PURE__*/React.createElement(TweakSection, {
title: "Demo"
}, /*#__PURE__*/React.createElement(TweakButton, {
label: "Show checksum-mismatch banner",
onClick: () => setShowWarning(true)
}), /*#__PURE__*/React.createElement(TweakButton, {
label: "Simulate external file change",
onClick: () => showToast('File reloaded from disk')
}), window.SEED_DATA && /*#__PURE__*/React.createElement(TweakButton, {
label: "Load sample / test data",
onClick: () => {
const seed = structuredClone(window.SEED_DATA);
const defaults = {
done: 100,
cancelled: 0,
'in-progress': 50,
blocked: 25,
postponed: 25,
open: 0
};
walkTree(seed.entries, it => {
if (typeof it.progress !== 'number') it.progress = defaults[it.status] ?? 0;else if (it.status === 'done') it.progress = 100;
});
setData(seed);
const em = {};
walkTree(seed.entries, it => {
em[it.id] = !it.collapsed;
});
setExpandedMap(em);
showToast('Sample data loaded');
}
})))));
}
// ----- View chips (saved searches) -----
const VIEW_CHIPS = [{
key: 'all',
label: 'All',
statuses: []
}, {
key: 'open',
label: 'Open',
statuses: ['open']
}, {
key: 'wip',
label: 'In progress',
statuses: ['in-progress']
}, {
key: 'active',
label: 'Active',
statuses: ['open', 'in-progress', 'blocked', 'postponed'],
hint: 'everything not done or cancelled'
}, {
key: 'blocked',
label: 'Blocked',
statuses: ['blocked']
}, {
key: 'closed',
label: 'Closed',
statuses: ['done', 'cancelled'],
hint: 'done + cancelled'
}];
function ViewChips({
filters,
setFilters
}) {
const cur = filters.statuses || [];
const same = (a, b) => a.length === b.length && a.every(x => b.includes(x));
const activeKey = VIEW_CHIPS.find(v => same(v.statuses, cur))?.key;
return /*#__PURE__*/React.createElement("div", {
className: "view-chips",
role: "tablist",
"aria-label": "Saved views"
}, VIEW_CHIPS.map(v => /*#__PURE__*/React.createElement("button", {
key: v.key,
role: "tab",
"aria-selected": activeKey === v.key,
className: `view-chip ${activeKey === v.key ? 'active' : ''}`,
title: v.hint || v.label,
onClick: () => setFilters({
...filters,
statuses: v.statuses
})
}, v.label)));
}
// ----- Header -----
function Header({
view,
setView,
saveState,
saveLabel,
storageMode,
searchValue,
onSearch,
onOpenImportExport
}) {
const modeIcon = storageMode === 'api' ? '⚡' : storageMode === 'direct' ? '📁' : storageMode === 'browser' ? '🌐' : '💾';
return /*#__PURE__*/React.createElement("header", {
className: "header"
}, /*#__PURE__*/React.createElement("div", {
className: "brand"
}, /*#__PURE__*/React.createElement("span", {
className: "brand-glyph"
}, /*#__PURE__*/React.createElement(StatusIcon, {
status: "in-progress",
size: 16
})), /*#__PURE__*/React.createElement("span", {
className: "brand-name"
}, "backlog"), /*#__PURE__*/React.createElement("span", {
className: "brand-sub mono",
title: `Storage: ${storageMode}`
}, "backlog.md ", modeIcon)), /*#__PURE__*/React.createElement("nav", {
className: "tabs"
}, /*#__PURE__*/React.createElement("button", {
className: `tab ${view === 'backlog' ? 'active' : ''}`,
onClick: () => setView('backlog')
}, /*#__PURE__*/React.createElement(Icon, {
name: "list",
size: 13
}), " Backlog"), /*#__PURE__*/React.createElement("button", {
className: `tab ${view === 'admin' ? 'active' : ''}`,
onClick: () => setView('admin')
}, /*#__PURE__*/React.createElement(Icon, {
name: "cog",
size: 13
}), " Admin")), /*#__PURE__*/React.createElement("div", {
className: "search-wrap"
}, /*#__PURE__*/React.createElement(Icon, {
name: "search",
size: 14
}), /*#__PURE__*/React.createElement("input", {
className: "search-input",
placeholder: "Search titles, tags, reasons\u2026 ( / )",
value: searchValue,
onChange: e => onSearch(e.target.value)
}), searchValue && /*#__PURE__*/React.createElement("button", {
className: "search-clear",
onClick: () => onSearch('')
}, "\xD7")), /*#__PURE__*/React.createElement("div", {
className: "header-right"
}, /*#__PURE__*/React.createElement("button", {
className: "header-btn",
onClick: onOpenImportExport,
title: "Import / Export"
}, /*#__PURE__*/React.createElement(Icon, {
name: "archive",
size: 13
}), " Import/Export"), /*#__PURE__*/React.createElement("div", {
className: `save-indicator ${saveState.status}`
}, /*#__PURE__*/React.createElement("span", {
className: `save-dot ${saveState.status}`
}), saveLabel)));
}
// ----- Import / Export dialog -----
function ImportExportDialog({
open,
data,
storageMode,
onClose,
onImport
}) {
const {
useState: useStateD,
useEffect: useEffectD,
useRef: useRefD
} = React;
const [tab, setTab] = useStateD('md');
const [copied, setCopied] = useStateD(false);
const [mdContent, setMdContent] = useStateD('');
const fileInputRef = useRefD(null);
// Async-generate markdown when dialog opens or data changes.
useEffectD(() => {
if (!open || !data) return;
let cancelled = false;
Parser.serialize({
entries: data.entries,
history: data.history
}).then(md => {
if (!cancelled) setMdContent(md);
}).catch(() => {});
return () => {
cancelled = true;
};
}, [open, data]);
const jsonContent = React.useMemo(() => {
if (!data) return '';
return JSON.stringify({
entries: data.entries,
history: data.history,
meta: data.meta
}, null, 2);
}, [data]);
const currentContent = tab === 'md' ? mdContent : jsonContent;
const filename = tab === 'md' ? 'backlog.md' : 'backlog_export.json';
const mimeType = tab === 'md' ? 'text/markdown' : 'application/json';
const copyContent = async () => {
try {
await navigator.clipboard.writeText(currentContent);
} catch {
const ta = Object.assign(document.createElement('textarea'), {
value: currentContent,
style: 'position:fixed;opacity:0'
});
document.body.appendChild(ta);
ta.select();
try {
document.execCommand('copy');
} catch {}
document.body.removeChild(ta);
}
setCopied(true);
setTimeout(() => setCopied(false), 1400);
};
const downloadFile = () => {
const blob = new Blob([currentContent], {
type: mimeType
});
const url = URL.createObjectURL(blob);
const a = Object.assign(document.createElement('a'), {
href: url,
download: filename
});
a.click();
URL.revokeObjectURL(url);
};
const handleFileInput = async e => {
const file = e.target.files?.[0];
if (!file) return;
e.target.value = '';
try {
const text = await file.text();
let entries, history;
if (file.name.endsWith('.json')) {
const obj = JSON.parse(text);
entries = obj.entries || [];
history = obj.history || [];
} else {
const parsed = await Parser.parse(text);
entries = parsed.entries;
history = parsed.history;
}
onImport({
entries,
history
});
} catch (err) {
alert('Import failed: ' + err.message);
}
};
return /*#__PURE__*/React.createElement(Dialog, {
open: open,
onClose: onClose,
width: 760,
labelledBy: "dlg-ie-title"
}, /*#__PURE__*/React.createElement(DialogHeader, {
id: "dlg-ie-title",
eyebrow: "Backup & sync",
title: "Import / Export",
onClose: onClose
}), /*#__PURE__*/React.createElement("div", {
className: "dlg-body"
}, /*#__PURE__*/React.createElement("div", {
className: "ie-tabs"
}, /*#__PURE__*/React.createElement("button", {
className: `ie-tab ${tab === 'md' ? 'active' : ''}`,
onClick: () => setTab('md')
}, "Markdown ", /*#__PURE__*/React.createElement("span", {
className: "ie-tab-sub"
}, ".md")), /*#__PURE__*/React.createElement("button", {
className: `ie-tab ${tab === 'json' ? 'active' : ''}`,
onClick: () => setTab('json')
}, "JSON ", /*#__PURE__*/React.createElement("span", {
className: "ie-tab-sub"
}, "structured")), /*#__PURE__*/React.createElement("button", {
className: `ie-copy-btn ${copied ? 'copied' : ''}`,
onClick: copyContent,
title: `Copy ${tab === 'md' ? 'Markdown' : 'JSON'} to clipboard`,
"aria-live": "polite"
}, copied ? /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Icon, {
name: "check",
size: 13
}), " ", /*#__PURE__*/React.createElement("span", null, "Copied")) : /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Icon, {
name: "copy",
size: 13
}), " ", /*#__PURE__*/React.createElement("span", null, "Copy")))), /*#__PURE__*/React.createElement("pre", {
className: "export-pre"
}, currentContent || '…generating…')), /*#__PURE__*/React.createElement("div", {
className: "dlg-foot"
}, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("input", {
ref: fileInputRef,
type: "file",
accept: ".md,.json",
style: {
display: 'none'
},
onChange: handleFileInput
}), /*#__PURE__*/React.createElement("button", {
className: "btn-secondary",
onClick: () => fileInputRef.current?.click()
}, /*#__PURE__*/React.createElement(Icon, {
name: "upload",
size: 12
}), " Import file\u2026")), /*#__PURE__*/React.createElement("div", {
className: "dlg-foot-actions"
}, /*#__PURE__*/React.createElement("button", {
className: "btn-secondary",
onClick: onClose
}, "Close"), /*#__PURE__*/React.createElement("button", {
className: "btn-primary",
onClick: downloadFile
}, /*#__PURE__*/React.createElement(Icon, {
name: "download",
size: 12
}), " Download ", tab === 'md' ? '.md' : '.json'))));
}
window.App = App;
</script>
<script>
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(/*#__PURE__*/React.createElement(App, null));
</script>
</body>
</html>