/* ---------------------------------------------------------------------------
 * Worthly, the instrument.
 *
 * This is reached FROM the landing page, and until now the two read as separate
 * products: the page set as a statement in one typeface and palette, the app in
 * system sans and a default blue. A prospect clicking "See a live demo" was
 * shown something that looked like it came from a different company.
 *
 * So the app borrows the page's vocabulary rather than a new one:
 *
 *   THE SAME TYPEFACE. sans.woff2 is the file the landing serves, copied here
 *   rather than linked, because the two are separate origins and a cross-origin
 *   font request is a request that can fail on its own.
 *
 *   EVERY FIGURE IS MONO AND TABULAR. This is a balance sheet. Numbers that do
 *   not line up in a column are the one thing this product cannot afford, and
 *   proportional digits in a tree of totals read as an estimate.
 *
 *   COLOUR HAS TWO JOBS AND THEY DO NOT CROSS. Blue is interface: links, focus,
 *   the active tab. Teal and rust are DATA - up and down, real and overstated -
 *   and appear on figures, never on furniture.
 *
 * Dark is the default here and light is the considered alternative, which is the
 * opposite of the landing page and deliberately so: this is a tool someone keeps
 * open, and the landing is a page they read once.
 * ------------------------------------------------------------------------- */

@font-face {
  font-family: "Instrument Sans";
  src: url("/static/sans.woff2") format("woff2");
  font-weight: 400 700; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F, U+20AC;
}

:root {
  --bg:     #ECEFF3;
  --card:   #FFFFFF;
  --sunk:   #E3E7ED;
  --fg:     #0B1220;
  --muted:  #58627A;
  --line:   #D5DBE3;
  --hair:   #E4E8EE;
  --warn-bg: #FBF1DD;
  --warn-line: #B98A2E;
  --pos:    #0D6B57;
  --neg:    #A33F2A;
  --accent: #1B44C8;

  --sans: "Instrument Sans", ui-sans-serif, -apple-system, "Segoe UI", system-ui, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  color-scheme: light;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg:     #0C1017;
    --card:   #141A23;
    --sunk:   #10151D;
    --fg:     #E6EAF0;
    --muted:  #8C97AB;
    --line:   #242C38;
    --hair:   #1C232D;
    --warn-bg: #2A2413;
    --warn-line: #B08A3C;
    --pos:    #55C8AC;
    --neg:    #E0906F;
    --accent: #8AA6FF;
    color-scheme: dark;
  }
}

* { box-sizing: border-box; }

body {
  margin: 0;
  padding: 0 0 4rem;
  background: var(--bg);
  color: var(--fg);
  font: 14px/1.55 var(--sans);
  -webkit-font-smoothing: antialiased;
}

/* Every number in the product. Tabular so a column of totals lines up, which is
   the whole visual claim of a balance sheet. */
.r, .figure .value, .kpi .v, summary .amt, .deltas, td.r, th.r,
.trend-foot, code, textarea {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}
.figure .value, .kpi .v, summary .amt, .r { font-family: var(--mono); }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 2px; }

nav {
  display: flex; align-items: center; gap: 1.35rem; flex-wrap: wrap;
  /* MIN-height, not height. A fixed height on a wrapping flex row is a
     contradiction: on a phone the items wrapped to a second line, the bar did
     not grow, and the overflow landed on top of the banner below it - "Get
     Worthly" and the snapshot date printed over the demo notice. */
  padding: .45rem 1.5rem; min-height: 3.25rem;
  border-bottom: 1px solid var(--hair);
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: saturate(1.6) blur(10px);
  position: sticky; top: 0; z-index: 5;
}
nav strong { font-weight: 680; letter-spacing: -.03em; font-size: 1.02rem; }
nav a {
  color: var(--muted); text-decoration: none; font-size: .92rem;
  padding: .15rem 0; border-bottom: 2px solid transparent;
}
nav a { transition: color .18s cubic-bezier(.32,.72,0,1); }
nav a:hover { color: var(--fg); border-bottom-color: var(--accent); }
/* Where you are. Full-strength text plus the rule underneath, so the cue does
   not depend on colour alone. */
nav a[aria-current="page"] { color: var(--fg); border-bottom-color: var(--accent); }
nav .spacer { flex: 1; }
/* The demo's one conversion control. Sized down to sit in a 3.25rem bar without
   dominating it, but still the only filled thing in the row. */
nav .btn.buy { padding: .3rem .7rem; font-size: .85rem; border-bottom: 0; }
nav .btn.buy:hover { border-bottom: 0; }

@media (max-width: 40rem) {
  /* A phone cannot hold the brand, four tabs, a buy button and a timestamp on
     one row. The timestamp goes: it is a detail for someone already using the
     product, and on the demo - which is where most phone traffic arrives - it
     is the least useful thing in the bar. */
  nav { gap: .9rem; padding-inline: 1rem; }
  nav > .muted { display: none; }
  main { padding: 1.25rem 1rem; }
  footer { padding: 0 1rem; }
}

main { max-width: 1100px; margin: 0 auto; padding: 1.75rem 1.5rem; }
footer { max-width: 1100px; margin: 0 auto; padding: 0 1.5rem; }

h1, h2, h3 { letter-spacing: -.022em; line-height: 1.15; }
h1 { font-size: 1.55rem; font-weight: 660; margin: 0 0 .5rem; }
h2 { font-size: 1.08rem; font-weight: 640; margin: 2.25rem 0 .6rem; }
h3 { font-size: .98rem; font-weight: 620; margin: 1.5rem 0 .4rem; }

.muted { color: var(--muted); font-size: .85em; }
.r { text-align: right; }

/* Small-caps mono labels, the same device the landing uses for section marks.
   It is what makes a row of figures read as a statement rather than a form. */
.figure .label, .kpi .k, thead th, figcaption {
  font-family: var(--mono); font-size: .68rem; letter-spacing: .09em;
  text-transform: uppercase; color: var(--muted); font-weight: 500;
}
.pos { color: var(--pos); }
.neg { color: var(--neg); }

.warn {
  margin: 0; padding: .7rem 1.5rem;
  background: var(--warn-bg); border-bottom: 1px solid var(--warn-line);
}

.badge {
  background: var(--neg); color: #fff; border-radius: 999px;
  padding: 0 .4rem; font-size: .75em;
}

/* The two headline figures: the whole product in one row.
   Consolidated is the fact; personal-after-extraction is the claim nobody else
   makes, so it gets the accent rail and the data colour. */
.headline { display: flex; gap: 1rem; flex-wrap: wrap; margin: 1.25rem 0 2rem; }
.figure {
  flex: 1 1 320px; padding: 1.1rem 1.3rem;
  background: var(--card); border: 1px solid var(--line); border-radius: 6px;
  display: flex; flex-direction: column; gap: .35rem;
  box-shadow: 0 1px 2px rgba(0,0,0,.04), 0 14px 30px -24px rgba(0,0,0,.35);
}
.figure .value {
  /* Shrinks rather than wraps. "Invoice 7,762 EUR/mo" is longer than a bare
     total and broke across two lines mid-figure at 2rem, which is the one thing
     a headline number must never do. */
  font-size: clamp(1.45rem, 1.05rem + 1.1vw, 2rem);
  line-height: 1.05; letter-spacing: -.035em; font-weight: 500;
  text-wrap: nowrap;
}

/* Emphasis is SEMANTIC, marked in the template, not positional.
   It was `.figure + .figure`, which meant "every card after the first" - correct
   by accident on the balance sheet's two cards, and on the plan page it painted
   both the reverse solve AND the capacity figure, so the colour stopped meaning
   anything. The marked figure is the one claim on each page that no competitor
   can produce. */
.figure.key { border-left: 2px solid var(--pos); }
.figure.key .value { color: var(--pos); }

details { border-left: 2px solid var(--line); margin: .25rem 0 .25rem .25rem; padding-left: .75rem; }
details.entity { border-left-color: var(--accent); margin-left: 0; padding-left: 1rem; }
summary { cursor: pointer; display: flex; align-items: baseline; gap: .75rem; padding: .3rem 0; }
summary .name { flex: 1; }
summary .amt { font-variant-numeric: tabular-nums; }
details.entity > summary { font-size: 1.15rem; font-weight: 600; }
details.bucket > summary { font-weight: 600; text-transform: capitalize; }

table { width: 100%; border-collapse: collapse; margin: .5rem 0 1rem; }
th, td { text-align: left; padding: .45rem .6rem; border-bottom: 1px solid var(--hair); vertical-align: top; }
thead th { border-bottom: 1px solid var(--line); }
tbody tr:hover { background: color-mix(in srgb, var(--accent) 7%, transparent); }
table.compact { max-width: 520px; }
tr.total th, tr.total td { border-top: 2px solid var(--line); font-weight: 600; }
tr.stale td { background: color-mix(in srgb, var(--warn-line) 15%, transparent); }
tr.carried td { color: var(--muted); font-style: italic; }

.flag {
  background: var(--neg); color: #fff; border-radius: 3px;
  padding: 0 .3rem; font-size: .72em; margin-left: .4rem;
}

a { color: var(--accent); }

figure { margin: .5rem 0 1.5rem; }
figcaption { color: var(--muted); font-size: .85em; margin-bottom: .25rem; }
svg.chart {
  width: 100%; height: 260px; display: block;
  background: var(--card); border: 1px solid var(--line); border-radius: 6px;
}
svg.chart .ax { stroke: var(--line); stroke-width: 1; }
svg.chart .grid { stroke: var(--line); stroke-width: 1; stroke-dasharray: 2 4; }
svg.chart .tick { fill: var(--muted); font-size: 11px; }

.legend { display: flex; gap: 1rem; flex-wrap: wrap; margin-top: .4rem; font-size: .85em; color: var(--muted); }
.legend .key { display: inline-flex; align-items: center; gap: .35rem; }
.legend i { width: .7rem; height: .7rem; border-radius: 2px; display: inline-block; }

form.inline { display: flex; gap: 1rem; flex-wrap: wrap; align-items: end; margin: 1rem 0; }
label { display: flex; flex-direction: column; gap: .2rem; font-size: .85em; color: var(--muted); }
input, textarea, button, .btn {
  font: inherit; padding: .42rem .65rem;
  border: 1px solid var(--line); border-radius: 4px;
  background: var(--card); color: var(--fg);
}
textarea { width: 100%; font-family: var(--mono); font-size: 13px; }
/* A form that reads top to bottom rather than as an inline row: the
   config editor is one tall field and its button, not a set of inputs. */
form.stack { display: flex; flex-direction: column; align-items: flex-start;
             gap: .75rem; margin: 1rem 0; }
/* Ink, not accent. The accent is for links and focus; a page where every button
   is the loudest colour has no way left to say which one matters. */
button, .btn {
  cursor: pointer; background: var(--fg); color: var(--bg);
  border-color: var(--fg); text-decoration: none; font-weight: 560;
  transition: opacity .12s ease;
}
button:hover, .btn:hover { opacity: .88; }
.btn { display: inline-block; }

code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .9em; }
ul.examples { padding-left: 1.2rem; }
ul.examples li { margin: .3rem 0; }

/* Wide tables and charts scroll inside their own box; the page never does. */
main { overflow-x: hidden; }
table { display: block; overflow-x: auto; }

/* --- write actions --- */
.ok {
  margin: 0; padding: .7rem 1.5rem;
  background: color-mix(in srgb, var(--pos) 18%, transparent);
  border-bottom: 1px solid var(--pos);
}

.badge.live { background: var(--pos); }

select { font: inherit; padding: .4rem .6rem; border: 1px solid var(--line);
         border-radius: 5px; background: var(--card); color: var(--fg); }

button.danger { background: transparent; color: var(--neg); border: 1px solid var(--neg); padding: .15rem .4rem; }
button:disabled { opacity: .55; cursor: default; }
form.tiny { display: inline; }

label.check { flex-direction: row; align-items: center; gap: .4rem; }
label.check input { width: auto; }

/* Per-row forms live outside the table and are wired to their inputs with the
   HTML5 `form` attribute: a <form> nested inside <tr> is invalid and the parser
   hoists it out of the table, silently breaking the submit. */
form.rowform { display: none; }
td input[type="number"], td input[type="text"] { width: 100%; min-width: 5rem; }

pre.report {
  background: var(--card); border: 1px solid var(--line); border-radius: 6px;
  padding: .8rem 1rem; overflow-x: auto; font-size: 13px; white-space: pre-wrap;
}
.met { background: var(--pos); color: #fff; border-radius: 3px; padding: 0 .3rem; font-size: .72em; }

/* --- insight callouts and status pills --- */
.insight {
  margin: 1rem 0; padding: .8rem 1rem;
  background: color-mix(in srgb, var(--accent) 8%, transparent);
  border-left: 3px solid var(--accent); border-radius: 0 6px 6px 0;
  font-size: .92em;
}

.pill {
  display: inline-block; margin: 0 .25rem .25rem 0; padding: .05rem .4rem;
  border-radius: 3px; font-size: .75em; white-space: nowrap;
  border: 1px solid var(--line);
}
.pill.ok  { background: color-mix(in srgb, var(--pos) 18%, transparent); border-color: var(--pos); }
.pill.bad { background: color-mix(in srgb, var(--neg) 15%, transparent); border-color: var(--neg); }

/* Compact KPI strip */
.kpis { display: flex; gap: .75rem; flex-wrap: wrap; margin: 1rem 0 1.5rem; }
.kpi {
  flex: 1 1 150px; padding: .6rem .8rem;
  background: var(--card); border: 1px solid var(--line); border-radius: 6px;
}
.kpi .k { color: var(--muted); font-size: .75em; text-transform: uppercase; letter-spacing: .03em; }
.kpi .v { font-size: 1.25rem; font-variant-numeric: tabular-nums; }
.kpi .s { color: var(--muted); font-size: .78em; }

details > summary { font-weight: 600; }
details.section { border-left: none; padding-left: 0; margin: 1rem 0; }

/* --- needs-doing checklist --- */
.todo { margin: 1rem 0 1.5rem; }
.todo h2 { margin-top: 0; }
.todo ul { list-style: none; margin: 0; padding: 0; }
.todo li {
  display: flex; align-items: baseline; gap: .6rem;
  padding: .6rem .85rem; border: 1px solid var(--line);
  border-radius: 6px; margin-bottom: .4rem; background: var(--card);
}
.todo .what { flex: 1; }
.todo .what .muted { display: block; }
.todo .dot { width: .55rem; height: .55rem; border-radius: 50%; flex: none; }
.todo .sev-blocking .dot { background: var(--neg); }
.todo .sev-stale    .dot { background: var(--warn-line); }
.todo .sev-info     .dot { background: var(--muted); }
.todo .sev-blocking { border-left: 3px solid var(--neg); }
.todo .sev-stale    { border-left: 3px solid var(--warn-line); }
.todo .btn { padding: .2rem .5rem; font-size: .8em; }

/* --- donuts and bars --- */
.donut-row { display: flex; gap: 1.5rem; flex-wrap: wrap; align-items: flex-start; }
.donut-fig { flex: 1 1 280px; max-width: 420px; margin: .5rem 0 1rem; }
svg.donut { width: 100%; max-width: 260px; height: auto; display: block; margin: 0 auto; }
svg.donut .hole-v { fill: var(--fg); font-size: 30px; font-weight: 600; }
svg.donut .hole-k { fill: var(--muted); font-size: 12px; }
svg.donut path:hover { fill-opacity: 1; }
svg.bars { width: 100%; height: auto; display: block;
           background: var(--card); border: 1px solid var(--line); border-radius: 6px; padding: .4rem; }
svg.bars .tick { fill: var(--muted); font-size: 12px; }

/* ---- the net worth trend ------------------------------------------------
   Server-rendered SVG rather than a charting library: the page loads no
   third-party code, and this works with JavaScript off. */
.trend {
  margin: 0 0 1.6rem; padding: 1rem 1.2rem .85rem;
  background: var(--card); border: 1px solid var(--line); border-radius: 6px;
}
.trend svg { display: block; width: 100%; height: 148px; overflow: visible; }
.trend-line { fill: none; stroke: var(--accent); stroke-width: 1.75;
              vector-effect: non-scaling-stroke; stroke-linejoin: round;
              stroke-linecap: round; }
.trend-fill { fill: var(--accent); opacity: .09; }
.trend-foot { display: flex; justify-content: space-between; align-items: baseline;
              margin-top: .7rem; gap: 1rem; flex-wrap: wrap; }
.deltas { display: flex; gap: 1.25rem; font-family: var(--mono); }
/* The window label ("30d") stays quiet; the number carries the colour, because
   the number is the data and the label is furniture. */
.delta { font-size: .78rem; color: var(--muted); }
.delta strong { font-weight: 500; }
.delta.up strong { color: var(--pos); }
.delta.down strong { color: var(--neg); }
