/*
 * Life OS — the design system. Every page reads from here; nothing below the
 * token blocks knows which palette is active.
 *
 * TYPOGRAPHY IS FIXED. 13px / 1.5 on a monospace stack whose advance is 0.60em,
 * which puts a character at 7.8px. Those three numbers were measured off the
 * reference design and are what make every page line up; change --fs and the
 * whole grid moves. Sizes are tokens, never literals, so there is one place to
 * change them.
 *
 * No webfont. The stack is system fonts only — CLAUDE.md rule 5 is no runtime
 * dependencies, and a font file is a render-blocking request to someone else's
 * CDN. SF Mono / JetBrains Mono / Menlo all share the 0.60 advance the layout
 * assumes; Consolas (0.55) is the fallback and runs slightly narrow.
 *
 * FIVE PALETTES, one token vocabulary. Switching is a dev affordance and lives
 * on /config, never in a public nav (SCOPE.md). `:root` is GitHub Dark so the
 * site still has the intended palette before JavaScript runs.
 */

:root{
  /* type */
  --mono:ui-monospace,"SF Mono","JetBrains Mono",Menlo,Consolas,"Liberation Mono",monospace;
  --fs:13px;        /* body — measured from the reference */
  --fs-sm:12px;     /* meta, captions, the // comment lines */
  --fs-lg:15px;     /* the header prompt */
  --fs-xl:22px;     /* the landing hero, the one display size */
  --lh:1.5;         /* 19.5px pitch */
  --pad:18px;       /* panel inner padding */
  --radius:8px;

  /* structure */
  --bg:#0d1117; --panel:#161b22; --raise:#161b22; --panel-2:#010409; --border:#30363d;
  /* text, brightest to faintest */
  --bright:#e6edf3; --fg:#c9d1d9; --muted:#8b949e; --faint:#484f58;
  /* semantic accents */
  --green:#3fb950; --blue:#58a6ff; --yellow:#d29922; --red:#f85149; --purple:#bc8cff;
  --accent:#3fb950; --accent-dim:#2ea043; --accent-hi:#56d364; --danger:#f85149;
}

/* Vesper. Two accents only — orange carries links/keys/numbers, mint carries
   strings and "done". Warnings get a hotter orange so they don't read as links. */
[data-theme="vesper"]{
  --bg:#101010; --panel:#161616; --raise:#161616; --panel-2:#141414; --border:#282828;
  --bright:#ffffff; --fg:#ffffff; --muted:#a0a0a0; --faint:#505050;
  --green:#99ffe4; --blue:#ffc799; --yellow:#ff9d5c; --red:#ff8080; --purple:#ffc799;
  --accent:#ffc799; --accent-dim:#a87a4f; --accent-hi:#ffcfa8; --danger:#ff8080;
}

[data-theme="gruvbox-dark"]{
  --bg:#282828; --panel:#32302f; --raise:#32302f; --panel-2:#1d2021; --border:#504945;
  --bright:#fbf1c7; --fg:#ebdbb2; --muted:#a89984; --faint:#665c54;
  --green:#b8bb26; --blue:#83a598; --yellow:#fabd2f; --red:#fb4934; --purple:#d3869b;
  --accent:#fe8019; --accent-dim:#d65d0e; --accent-hi:#fabd2f; --danger:#fb4934;
}

[data-theme="solarized-dark"]{
  --bg:#002b36; --panel:#073642; --raise:#073642; --panel-2:#00212b; --border:#586e75;
  --bright:#fdf6e3; --fg:#839496; --muted:#657b83; --faint:#586e75;
  --green:#859900; --blue:#268bd2; --yellow:#b58900; --red:#dc322f; --purple:#d33682;
  --accent:#2aa198; --accent-dim:#1b7f79; --accent-hi:#5ccac3; --danger:#dc322f;
}

[data-theme="dark-plus"]{
  --bg:#1e1e1e; --panel:#252526; --raise:#252526; --panel-2:#181818; --border:#3c3c3c;
  --bright:#ffffff; --fg:#d4d4d4; --muted:#9d9d9d; --faint:#6a6a6a;
  --green:#6a9955; --blue:#569cd6; --yellow:#dcdcaa; --red:#f44747; --purple:#c586c0;
  --accent:#4ec9b0; --accent-dim:#16825d; --accent-hi:#9cdcfe; --danger:#f44747;
}

*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
body{
  margin:0; background:var(--bg); color:var(--fg); font-family:var(--mono);
  font-size:var(--fs); line-height:var(--lh); padding:24px 16px 96px;
  max-width:820px; margin-inline:auto;
  transition:background .25s,color .25s;
}
/* The landing page runs full-bleed so its nav can be sticky edge-to-edge. */
body.site{max-width:none;padding:0;line-height:1.7}
.wrap{max-width:680px;margin:0 auto;padding:0 16px}
/* today is a dashboard, not a list — its section grid needs the width. */
body.wide{max-width:1240px}

a{color:var(--blue);text-decoration:none}
a:hover{text-decoration:underline;text-underline-offset:3px}
.muted{color:var(--muted)} .faint{color:var(--faint)} .bright{color:var(--bright)}
.green{color:var(--green)} .blue{color:var(--blue)} .accent{color:var(--accent)}
.yellow{color:var(--yellow)} .red{color:var(--red)} .purple{color:var(--purple)}
.danger{color:var(--danger)}

/* ── header ─────────────────────────────────────────────────────── */
header{margin-bottom:20px}
.prompt{font-size:var(--fs-lg); display:flex; align-items:baseline; gap:8px; flex-wrap:wrap}
.prompt .path{color:var(--blue)}
.prompt .dollar{color:var(--green)}
.prompt .cmd{color:var(--fg)}
.cursor{display:inline-block;width:8px;height:15px;background:var(--green);
  transform:translateY(2px);animation:blink 1.1s steps(1) infinite}
@keyframes blink{50%{opacity:0}}
@media (prefers-reduced-motion:reduce){.cursor{animation:none}html{scroll-behavior:auto}}
.sub{color:var(--muted);margin-top:4px}

/* ── shell prompt line, inline form (landing) ───────────────────── */
.line{white-space:pre-wrap;word-break:break-word}
.pr .u{color:var(--muted)} .pr .p{color:var(--faint)} .pr .d{color:var(--accent)}
.pr .cmd{color:var(--fg)}
.lead{margin:0 0 16px}

/* ── terminal — the 404 page and the NFC log pages (assets/term.js) ─ */
.term{text-align:left}
.term-log .line{min-height:calc(var(--fs) * var(--lh))}
/* In ls and tree a page is a link in the text colour; api files stay blue
   and folders accent, so what opens and what reads look different. */
.term-log a{color:var(--fg)}
.term-log a:hover{color:var(--accent)}
.term-row{display:flex;align-items:baseline;gap:8px;margin-top:4px}
/* The ghost sits under a transparent input, same font and origin, so the grey
   rest of the suggestion lines up after the typed text. */
.term-field{position:relative;flex:1;min-width:0}
.term-ghost{position:absolute;left:0;top:0;right:0;white-space:pre;overflow:hidden;pointer-events:none;color:var(--muted)}
.term-ghost .t{visibility:hidden}
/* No underline and no native caret: a block cursor in the mirror marks the
   caret and is the focus indicator, shown only while the input has focus. */
.term-in{position:relative;width:100%;padding:0;background:transparent;color:var(--fg);font:inherit;
  border:0;border-radius:0;caret-color:transparent;outline:none}
.term-in::placeholder{color:var(--faint)}
.term-ghost .c{display:none;width:1ch;margin-right:-1ch;height:1.2em;vertical-align:text-bottom;background:var(--accent);
  animation:blink 1.1s steps(1) infinite}
.term-field:focus-within .term-ghost .c{display:inline-block}
@media (prefers-reduced-motion:reduce){.term-ghost .c{animation:none}}
/* The picker prints like fzf: plain lines in the output, no box. The current
   line is reverse video over exactly the characters it prints. */
/* --term-indent (set by term.js) puts the commands under the first typed
   character; the > marker takes the two columns before it. */
.term-menu{margin:0 0 0 var(--term-indent,0px);padding:0;list-style:none}
.term-menu[hidden],.term-hint[hidden]{display:none}
.term-opt{width:fit-content;max-width:100%;white-space:pre;overflow:hidden;text-overflow:ellipsis;cursor:pointer}
.term-opt .m{color:var(--accent)}
.term-opt .v{color:var(--muted)}
.term-opt:hover .k{color:var(--accent)}
.term-opt[aria-selected="true"],.term-opt[aria-selected="true"] span{background:var(--fg);color:var(--bg)}
.term-hint{margin-left:calc(var(--term-indent,0px) + 2ch);color:var(--faint);font-size:var(--fs-sm)}

/* ── PANEL — the standard box for data ──────────────────────────────
 * The default container. Its title sits ON the top rule and interrupts it,
 * so the box reads as one labelled unit rather than a heading stacked above
 * a border. Rows inside are separated by space, never by lines.
 *
 *   <section class="panel">
 *     <h2 class="t">$ today</h2>
 *     <div class="row">…</div>
 *   </section>
 *
 * The title's background must match whatever sits behind the panel, which is
 * why it paints var(--bg): panels go on the page, not inside other panels.
 */
.panel{
  position:relative;
  border:1px solid var(--border);
  border-radius:var(--radius);
  padding:var(--pad);
  margin:22px 0;
}
.panel > .t{
  position:absolute; top:0; left:14px; transform:translateY(-50%);
  margin:0; padding:0 8px;
  background:var(--bg);
  font-size:var(--fs); font-weight:400; line-height:1;
  color:var(--muted); letter-spacing:.02em;
}
.panel > .t .dollar{color:var(--green)}
.panel > .t .name{color:var(--fg)}
.panel > .t.accent{color:var(--accent)}
/* Off-band / off-week: dimmed, never removed. An early dose still has to log. */
.panel.off{opacity:.5}
.panel.off:hover,.panel.off:focus-within{opacity:1;transition:opacity .12s}
/* A panel opening with a row shouldn't double up on padding. */
.panel > .row:first-child{padding-top:0}
.panel > .row:last-child{padding-bottom:0}

/* ── contribution density ─────────────────────────────────────────
 * Shared by the public life summary and /today. It is history, not a streak:
 * no target, counter or red state. The card stays one dashboard column wide. */
.contributions-panel{width:min(100%,390px)}
.contrib-scroll{overflow-x:auto;padding:2px 0 8px;scrollbar-color:var(--border) transparent}
.contrib-chart{display:grid;grid-template-columns:18px repeat(var(--contrib-weeks),10px);
  grid-template-rows:14px repeat(7,10px);gap:3px;width:max-content;min-width:100%}
.contrib-month{grid-row:1;color:var(--muted);font-size:10px;line-height:10px}
.contrib-day{grid-column:1;color:var(--faint);font-size:9px;line-height:10px;text-transform:lowercase}
.contrib-cell{width:10px;height:10px;border-radius:2px;background:var(--green)}
.contrib-cell.l0{background:var(--panel-2);box-shadow:inset 0 0 0 1px var(--border)}
.contrib-cell.l1{opacity:.25}.contrib-cell.l2{opacity:.4}.contrib-cell.l3{opacity:.58}
.contrib-cell.l4{opacity:.78}.contrib-cell.l5{opacity:1}
.contrib-cell.future{visibility:hidden}
.contrib-legend{display:flex;justify-content:flex-end;align-items:center;gap:4px;
  color:var(--muted);font-size:10px;margin-top:2px}
.contrib-legend .contrib-cell{display:inline-block;flex:none}

/* ── controls ───────────────────────────────────────────────────── */
.toolbar{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin:16px 0 8px}
.btn{
  font-family:var(--mono);font-size:var(--fs-sm);color:var(--fg);background:var(--panel);
  border:1px solid var(--border);border-radius:6px;padding:6px 12px;cursor:pointer;
  transition:border-color .12s,color .12s}
.btn:hover{border-color:var(--accent);color:var(--accent)}
.btn:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.btn.danger:hover{border-color:var(--red);color:var(--red)}
.btn.ghost{background:transparent}
.btn[disabled]{opacity:.45;cursor:not-allowed}
a.btn{text-decoration:none;display:inline-block}
a.btn:hover{text-decoration:none}
.toggle{margin-left:auto;color:var(--muted);cursor:pointer;user-select:none}
.toggle input{accent-color:var(--accent);vertical-align:middle;margin-right:6px}
.spacer{margin-left:auto}

/* ── rows ───────────────────────────────────────────────────────────
 * No dividers. Rows are separated by their own padding, which is what makes
 * a dense list read as a block of text rather than a table.
 */
.list{display:block}
.row{padding:3px 0;display:grid;grid-template-columns:auto 1fr auto;gap:10px;align-items:start}
.main .name{color:var(--fg)}
.main .slug{color:var(--accent);font-weight:600;margin-right:8px}
.meta{color:var(--muted);font-size:var(--fs-sm);margin-top:1px}
.meta .type{color:var(--yellow)}
.empty{padding:4px 0;color:var(--muted);font-size:var(--fs-sm)}

/* Group label inside a panel — a bare caption, no rule. */
.group{padding:14px 0 4px;color:var(--muted);font-size:var(--fs-sm);letter-spacing:.06em}
.group:first-child{padding-top:0}

h2.sec{font-size:var(--fs-sm);color:var(--muted);font-weight:400;letter-spacing:.06em;
  margin:26px 0 8px;padding:0}

/* ── progress bar ───────────────────────────────────────────────── */
.bar{display:flex;align-items:center;gap:10px;margin:2px 0 6px;font-size:var(--fs-sm);color:var(--muted)}
.bar .track{flex:1;height:6px;background:var(--panel);border:1px solid var(--border);
  border-radius:999px;overflow:hidden}
.bar .fill{height:100%;background:var(--accent);width:0;transition:width .3s ease}

/* ── forms ──────────────────────────────────────────────────────── */
.editor{display:none}
.editor.open{display:block}
.field{display:grid;grid-template-columns:90px 1fr;gap:10px;align-items:center;margin-bottom:8px}
.field label,.field .lbl{color:var(--muted);font-size:var(--fs)}
.field input,.field select{
  font-family:var(--mono);font-size:var(--fs);color:var(--fg);background:var(--panel-2);
  border:1px solid var(--border);border-radius:5px;padding:7px 10px;width:100%}
.field input:focus,.field select:focus{outline:none;border-color:var(--accent)}
.field input:disabled{opacity:.5;cursor:not-allowed}
.row-btns{display:flex;gap:8px;margin-top:12px}

/* ── status log ─────────────────────────────────────────────────── */
.statuslog{margin-top:18px;font-size:var(--fs-sm);min-height:20px}
.statuslog div{padding:1px 0}
.statuslog .ok::before{content:"[ok] ";color:var(--green)}
.statuslog .err::before{content:"[err] ";color:var(--red)}
.statuslog .info::before{content:"[..] ";color:var(--blue)}
.statuslog .ok,.statuslog .info{color:var(--muted)}
.statuslog .err{color:var(--fg)}

footer{margin-top:32px;color:var(--muted);font-size:var(--fs-sm);text-align:center}

/* ── notes — the owner-only notes button, bottom-right on every page (assets/notes.js) ─ */
/* Round like a chat button, drawn in the palette, 45px so a thumb finds it.
   Only rendered for a logged-in owner; visitors never get the markup. */
.notes-fab{position:fixed;z-index:10;right:max(var(--pad), env(safe-area-inset-right));
  bottom:max(var(--pad), env(safe-area-inset-bottom));width:calc(var(--fs) * 3.5);height:calc(var(--fs) * 3.5);
  display:grid;place-items:center;padding:0;border:1px solid var(--border);border-radius:50%;
  background:var(--panel);color:var(--accent);cursor:pointer}
.notes-fab svg{width:50%;height:50%;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.notes-fab:hover,.notes-fab[aria-expanded="true"]{border-color:var(--accent)}
.notes-fab:focus-visible{outline:1px solid var(--accent);outline-offset:4px}
/* The dot: this page already has a note. */
.notes-fab.has::after{content:'';position:absolute;top:0;right:0;width:calc(var(--fs) * .8);height:calc(var(--fs) * .8);
  border:2px solid var(--bg);border-radius:50%;background:var(--accent)}
.notes-panel{position:fixed;z-index:10;right:max(var(--pad), env(safe-area-inset-right));
  bottom:calc(max(var(--pad), env(safe-area-inset-bottom)) + var(--fs) * 3.5 + 8px);
  width:min(calc(var(--fs) * 28), calc(100vw - 2 * var(--pad)));display:flex;flex-direction:column;gap:8px;
  padding:var(--pad);background:var(--panel);border:1px solid var(--border);border-radius:var(--radius)}
.notes-panel[hidden]{display:none}
.notes-head{display:flex;align-items:baseline;gap:8px}
.notes-head .t{color:var(--fg)}
.notes-head .pg{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--muted)}
.notes-x{padding:0;border:0;background:none;color:var(--muted);font:inherit;cursor:pointer}
.notes-x:hover,.notes-x:focus-visible{color:var(--fg)}
.notes-text{width:100%;min-height:calc(var(--fs) * var(--lh) * 8);max-height:50vh;resize:vertical;padding:8px;
  background:var(--bg);color:var(--fg);font:inherit;border:1px solid var(--border);border-radius:var(--radius)}
.notes-text::placeholder{color:var(--faint)}
.notes-text:focus-visible{outline:none;border-color:var(--accent)}
.notes-status{color:var(--faint);font-size:var(--fs-sm)}
.notes-status.err{color:var(--danger)}
@media (max-width:480px){.notes-panel{left:var(--pad);width:auto}}
@media print{.notes-fab,.notes-panel{display:none}}
