- commit
- c4ae0c4a5ccb332ccb5c4451240158d7dbfffcd5
- parent
- 220a4790ccabcb85b9700f31b25a02a26b07149f
- parent
- 436d6709f1b9c978a112c830a359fee4e4be3c9d
- author
- Dami <dami.etoile@gmail.com>
@@ -116,7 +116,7 @@ demos: build
116116 mkdir -p demos/out/stills117117 bin/fakejev -addr $(FAKEJEV_ADDR) & pid=$$!; trap "kill $$pid" EXIT; \118118 export DEMOS_TTYD="$$(command -v ttyd)" PATH="$(CURDIR)/demos/lib:$$PATH"; \119- export XDG_CONFIG_HOME="$$(mktemp -d)" O12_JEV_CREDENTIAL_STORE=false O12_CHART_IMAGES=false O12_THEME= O12_LOCALE=en-US; \119+ export XDG_CONFIG_HOME="$$(mktemp -d)" O12_JEV_CREDENTIAL_STORE=false O12_THEME= O12_LOCALE=en-US; \120120 cd demos && for d in $(DEMOS); do echo "vhs $$d.tape"; vhs -q $$d.tape || exit 1; done121121 mkdir -p demos/out/media122122 for d in $(DEMOS); do ffmpeg -v error -y -i demos/out/$$d.gif -filter_complex \@@ -42,8 +42,10 @@ rest: building from a clone, importing files, `012 serve` and settings.
4242 - **Files**: a diff-friendly JSON format, import from CSV, TSV, JSON,4343 nushell's NUON, XLSX, SQLite, Parquet and Lotus 1-2-3, export to CSV,4444 TSV, JSON, NUON, XLSX and SQLite ([files](docs/files/README.md)).45-- **A stage in a pipeline**: `ls | to nuon | ^012 --pipe | from nuon`46- edits a table on the terminal and sends it on with its types45+- **A stage in a pipeline**: `ls | sheet | where size > 1kb` edits a46+ table on the terminal and sends it on with its types, through the47+ nushell module `012 nu --install-module` installs, or as48+ `ls | to nuon | ^012 --pipe | from nuon` without it4749 ([pipelines](docs/nushell/pipelines.md)).4850 - **Nushell notebooks**: `012 nu` (or Data > Shell in any workbook) runs nushell4951 pipelines whose tables become live, named regions of the sheet;@@ -36,7 +36,7 @@ formulas, charts and pivots use. It replaces the grid-based notebook sheet.
3636 | Item | Result | Size |3737 |---|---|---|3838 | Notebook tabs: code and note cells, outputs rendered in place (tables that scroll and open full-screen as a grid, text, records, errors), Jupyter keys inside the notebook (Shift+Enter run and next, Ctrl+Enter run, a/b add above/below, dd delete, m/y note/code, Esc/Enter command/edit mode) plus menus and palette; run cell, run all, run above, run below, stop, clear outputs; run counts and timings; cells named for their output (`$files`), stale marks when a cell they read has changed, an opt-in reactive mode that re-runs dependents; send an output to a sheet as a live region (`nu.files`); outputs saved in the workbook up to a size cap; existing notebook sheets converted, one code cell per region; `012 nu` opens a notebook | A TUI Jupyter with nushell and 012 | L |39-| Nushell's own completions in code cells; a way to call 012 from nu without `^012` (a shipped `012.nu` module, or `nu_plugin_012`) | | S to M |39+| Code cells highlighted, completed and checked as you type by nushell itself: `nu --ide-ast` token shapes mapped to theme roles, `nu --ide-complete` plus 012's cell, region and sheet names on Tab, `nu --ide-check` errors underlined; debounced in the background, plain text when nu is missing or slow; hover docs through `nu --lsp` later | Writing pipelines in 012 feels like nushell's own prompt | S to M |4040 4141 ### 3. Toward multiplayer4242 @@ -114,6 +114,7 @@ stream above rather than a design of their own.
114114 **Nushell**115115 116116 - 012 as a stage in a pipeline: `012 -` reads a table from standard input, `012 --pipe` sends the sheet or selection on, with nushell's types kept through NUON: [Pipelines](docs/nushell/pipelines.md)117+- The `sheet` command: a nushell module shipped in the binary (`012 nu --install-module`), so nu calls 012 without `^012` or NUON on either side: [Pipelines](docs/nushell/pipelines.md#the-sheet-command)117118 - `012 nu` and notebook sheets: nushell pipelines at a prompt on the formula bar become live, named regions that read each other and refresh in dependency order, saved as commands and never run on open: [Notebooks](docs/nushell/notebooks.md)118119 119120 **Files**@@ -66,8 +66,9 @@ func usage() error {
6666 return errors.New("usage: 012 " + config.FlagUsage() + " [file]: a " + sheet.FileExt +6767 " sheet, or a .csv, .tsv, .json, .nuon, .xlsx, .sqlite, .parquet or .wk1 file to import\n" +6868 " 012 [flags] -: a table from standard input (NUON, JSON, CSV or TSV)\n" +69- " 012 [flags] --pipe [--to nuon|json|csv|tsv] [file]: on quitting, send the table to standard output\n" +69+ " 012 [flags] --pipe [--to nuon|json|csv|tsv] [--send ask|selection|sheet] [file]: on quitting, send the table to standard output\n" +7070 " 012 nu [flags] [file]: a nushell notebook, at its prompt (see docs/nushell/notebooks.md)\n" +71+ " 012 nu --module | --install-module [--force] [path]: the nushell module with sheet (see docs/nushell/README.md)\n" +7172 " 012 serve [flags] [dir]: serve sheets in dir over SSH (see docs/terminal/ssh.md)\n" +7273 " 012 config [path|edit|default|themes|set-key|delete-key]\n" +7374 " 012 version")@@ -84,6 +85,9 @@ func run(args []string, e env) error {
8485 // A file called serve opens as ./serve.8586 return runServe(args[1:], e)8687 }88+ if len(args) > 0 && args[0] == "nu" && isModuleCommand(args[1:]) {89+ return runNuModule(args[1:], e)90+ }8791 // A file called nu opens as ./nu.8892 notebook := len(args) > 0 && args[0] == "nu"8993 if notebook {@@ -0,0 +1,116 @@
1+package main2+3+import (4+ "bytes"5+ "errors"6+ "fmt"7+ "io/fs"8+ "os"9+ "os/exec"10+ "path/filepath"11+ "strings"12+13+ "github.com/FelineStateMachine/012/internal/nushell/module"14+)15+16+// 012 nu --module and 012 nu --install-module: the nushell module that17+// gives 012 the command `sheet` (see docs/nushell/README.md).18+19+// nuConfigDir asks nu for its config directory, where config.nu is and20+// whose scripts folder is on nushell's library path. Tests replace it.21+var nuConfigDir = func() (string, error) {22+ out, err := exec.Command("nu", "--no-config-file", "-c", "$nu.default-config-dir").Output()23+ if err != nil {24+ return "", fmt.Errorf("asking nu for its config directory: %w; name the file instead: 012 nu --install-module path/to/%s", err, module.Name)25+ }26+ return strings.TrimSpace(string(out)), nil27+}28+29+// isModuleCommand reports whether 012 nu's arguments ask for the module30+// rather than a notebook.31+func isModuleCommand(args []string) bool {32+ return len(args) > 0 && (args[0] == "--module" || args[0] == "--install-module")33+}34+35+// runNuModule is 012 nu --module (print the module) or 012 nu36+// --install-module [--force] [path].37+func runNuModule(args []string, e env) error {38+ if args[0] == "--module" {39+ if len(args) > 1 {40+ return usage()41+ }42+ _, err := fmt.Fprint(e.stdout, module.Source)43+ return err44+ }45+ force := false46+ var paths []string47+ for _, a := range args[1:] {48+ if a == "--force" {49+ force = true50+ } else {51+ paths = append(paths, a)52+ }53+ }54+ if len(paths) > 1 {55+ return usage()56+ }57+ path, useLine, err := modulePath(paths)58+ if err != nil {59+ return err60+ }61+ wrote, err := installModule(path, force)62+ if err != nil {63+ return err64+ }65+ if wrote {66+ fmt.Fprintln(e.stdout, "Wrote", path)67+ } else {68+ fmt.Fprintln(e.stdout, path, "is up to date")69+ }70+ fmt.Fprintln(e.stdout, "Add this line to config.nu (config nu opens it):")71+ fmt.Fprintln(e.stdout, useLine)72+ return nil73+}74+75+// modulePath is where the module goes, and the line config.nu needs to76+// use it: the path given, or scripts/012.nu in nu's config directory,77+// which config.nu names relative to itself.78+func modulePath(given []string) (path, useLine string, err error) {79+ if len(given) == 1 {80+ path, err := filepath.Abs(given[0])81+ if err != nil {82+ return "", "", err83+ }84+ if info, err := os.Stat(path); err == nil && info.IsDir() {85+ path = filepath.Join(path, module.Name)86+ }87+ return path, fmt.Sprintf("use %q *", path), nil88+ }89+ dir, err := nuConfigDir()90+ if err != nil {91+ return "", "", err92+ }93+ if dir == "" {94+ return "", "", errors.New("nu named no config directory")95+ }96+ return filepath.Join(dir, "scripts", module.Name), "use scripts/" + module.Name + " *", nil97+}98+99+// installModule writes the module to path, creating its directory. A100+// file already there is replaced only with force, unless it's the same101+// module; wrote is false then.102+func installModule(path string, force bool) (wrote bool, err error) {103+ old, err := os.ReadFile(path)104+ switch {105+ case err == nil && bytes.Equal(old, []byte(module.Source)):106+ return false, nil107+ case err == nil && !force:108+ return false, fmt.Errorf("%s exists and isn't this 012's module; --force replaces it", path)109+ case err != nil && !errors.Is(err, fs.ErrNotExist):110+ return false, err111+ }112+ if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {113+ return false, err114+ }115+ return true, os.WriteFile(path, []byte(module.Source), 0o644)116+}@@ -0,0 +1,97 @@
1+package main2+3+import (4+ "os"5+ "path/filepath"6+ "strings"7+ "testing"8+9+ "github.com/FelineStateMachine/012/internal/nushell/module"10+)11+12+func TestNuModulePrints(t *testing.T) {13+ e, out, _ := testEnv(t, nil)14+ if err := run([]string{"nu", "--module"}, e); err != nil {15+ t.Fatal(err)16+ }17+ if out.String() != module.Source || !strings.Contains(out.String(), "export def sheet [") {18+ t.Errorf("printed:\n%s", out)19+ }20+}21+22+// fakeNuConfig points 012 nu --install-module at a temporary nu config23+// directory.24+func fakeNuConfig(t *testing.T) string {25+ t.Helper()26+ dir := filepath.Join(t.TempDir(), "nushell")27+ old := nuConfigDir28+ nuConfigDir = func() (string, error) { return dir, nil }29+ t.Cleanup(func() { nuConfigDir = old })30+ return dir31+}32+33+func TestNuInstallModule(t *testing.T) {34+ e, out, _ := testEnv(t, nil)35+ dir := fakeNuConfig(t)36+ path := filepath.Join(dir, "scripts", "012.nu")37+ if err := run([]string{"nu", "--install-module"}, e); err != nil {38+ t.Fatal(err)39+ }40+ if got, err := os.ReadFile(path); err != nil || string(got) != module.Source {41+ t.Fatalf("installed %q, %v", got, err)42+ }43+ if want := "Wrote " + path + "\nAdd this line to config.nu (config nu opens it):\nuse scripts/012.nu *\n"; out.String() != want {44+ t.Errorf("printed %q, want %q", out, want)45+ }46+47+ // Again: the same module is left as it is.48+ out.Reset()49+ if err := run([]string{"nu", "--install-module"}, e); err != nil || !strings.HasPrefix(out.String(), path+" is up to date\n") {50+ t.Errorf("reinstalling: %v, %q", err, out)51+ }52+53+ // A different file there stays unless --force.54+ os.WriteFile(path, []byte("# mine\n"), 0o644)55+ err := run([]string{"nu", "--install-module"}, e)56+ if err == nil || !strings.Contains(err.Error(), "--force replaces it") {57+ t.Errorf("overwrote without --force: %v", err)58+ }59+ if got, _ := os.ReadFile(path); string(got) != "# mine\n" {60+ t.Errorf("file changed: %q", got)61+ }62+ if err := run([]string{"nu", "--install-module", "--force"}, e); err != nil {63+ t.Fatal(err)64+ }65+ if got, _ := os.ReadFile(path); string(got) != module.Source {66+ t.Errorf("--force didn't replace it: %q", got)67+ }68+}69+70+// An explicit path is used as given, or as the folder to put 012.nu in,71+// and config.nu names it in full.72+func TestNuInstallModuleAt(t *testing.T) {73+ e, out, _ := testEnv(t, nil)74+ old := nuConfigDir75+ nuConfigDir = func() (string, error) { t.Fatal("asked nu"); return "", nil }76+ t.Cleanup(func() { nuConfigDir = old })77+ dir := t.TempDir()78+ file := filepath.Join(dir, "lib", "sheet.nu")79+ if err := run([]string{"nu", "--install-module", file}, e); err != nil {80+ t.Fatal(err)81+ }82+ if got, _ := os.ReadFile(file); string(got) != module.Source {83+ t.Errorf("installed %q", got)84+ }85+ if !strings.HasSuffix(out.String(), "use \""+file+"\" *\n") {86+ t.Errorf("printed %q", out)87+ }88+ if err := run([]string{"nu", "--install-module", dir}, e); err != nil {89+ t.Fatal(err)90+ }91+ if _, err := os.Stat(filepath.Join(dir, "012.nu")); err != nil {92+ t.Error(err)93+ }94+ if err := run([]string{"nu", "--module", "extra"}, e); err == nil {95+ t.Error("--module took an argument")96+ }97+}@@ -20,11 +20,16 @@ import (
2020 2121 // pipeMode is what the command line asked of standard input and output.2222 type pipeMode struct {23- stdin bool // 012 -, or --pipe without a file: read a table from standard input24- pipe bool // --pipe: write the result to standard output on quitting25- to fileio.Kind // --to: the format to write, or 0 for the input's23+ stdin bool // 012 -, or --pipe without a file: read a table from standard input24+ pipe bool // --pipe: write the result to standard output on quitting25+ to fileio.Kind // --to: the format to write, or 0 for the input's26+ send ui.Send // --send: what quitting sends, or ask27+ sendAs string // --send's value, or "" without it2628 }2729 30+// sends are --send's values.31+var sends = map[string]ui.Send{"ask": ui.SendAsk, "selection": ui.SendSelection, "sheet": ui.SendSheet}32+2833 // on reports whether the UI must run on the terminal rather than on2934 // standard input and output.3035 func (p pipeMode) on() bool { return p.stdin || p.pipe }@@ -33,43 +38,67 @@ func (p pipeMode) on() bool { return p.stdin || p.pipe }
3338 // status 1 so the pipeline can tell.3439 var errNotSent = errors.New("quit without sending anything to the pipeline")3540 36-// parsePipe takes -, --pipe and --to from args, returning the rest.41+// parsePipe takes -, --pipe, --to and --send from args, returning the42+// rest.3743 func parsePipe(args []string) (pipeMode, []string, error) {3844 var p pipeMode3945 var rest []string4046 for i := 0; i < len(args); i++ {4147 name, value, hasValue := strings.Cut(args[i], "=")42- switch {43- case args[i] == "-":44- p.stdin = true45- case args[i] == "--pipe":46- p.pipe = true47- case name == "--to":48- if !hasValue {49- if i+1 == len(args) {50- return p, nil, errors.New("--to needs a format: nuon, json, csv or tsv")51- }52- i++53- value = args[i]48+ if name != "--to" && name != "--send" {49+ switch args[i] {50+ case "-":51+ p.stdin = true52+ case "--pipe":53+ p.pipe = true54+ default:55+ rest = append(rest, args[i])5456 }55- k, ok := fileio.KindNamed(value)56- if !ok || !k.IsText() {57- return p, nil, fmt.Errorf("--to %s: 012 writes nuon, json, csv or tsv", value)57+ continue58+ }59+ if !hasValue {60+ if i+1 == len(args) {61+ return p, nil, fmt.Errorf("%s needs a value: %s", name, pipeValues[name])5862 }59- p.to = k60- default:61- rest = append(rest, args[i])63+ i++64+ value = args[i]65+ }66+ if err := p.set(name, value); err != nil {67+ return p, nil, err6268 }6369 }6470 return p, rest, nil6571 }6672 67-// check reports what doesn't go together: --to without --pipe, a file68-// and -, or nothing to read.73+// pipeValues are what --to and --send take, for their errors.74+var pipeValues = map[string]string{"--to": "nuon, json, csv or tsv", "--send": "ask, selection or sheet"}75+76+// set takes --to's or --send's value.77+func (p *pipeMode) set(name, value string) error {78+ if name == "--send" {79+ s, ok := sends[value]80+ if !ok {81+ return fmt.Errorf("--send %s: 012 sends %s", value, pipeValues[name])82+ }83+ p.send, p.sendAs = s, value84+ return nil85+ }86+ k, ok := fileio.KindNamed(value)87+ if !ok || !k.IsText() {88+ return fmt.Errorf("--to %s: 012 writes %s", value, pipeValues[name])89+ }90+ p.to = k91+ return nil92+}93+94+// check reports what doesn't go together: --to or --send without95+// --pipe, a file and -, or nothing to read.6996 func (p *pipeMode) check(files []string, stdinTTY bool) error {7097 switch {7198 case p.to != 0 && !p.pipe:7299 return errors.New("--to goes with --pipe")100+ case p.sendAs != "" && !p.pipe:101+ return errors.New("--send goes with --pipe: 012 --pipe --send " + p.sendAs)73102 case p.stdin && len(files) > 0:74103 return errors.New("012 - reads standard input; name a file or -, not both")75104 case p.pipe && len(files) == 0:@@ -103,6 +132,7 @@ func setPipe(m *ui.Model, p pipeMode, stdin io.Reader) {
103132 }104133 if p.pipe {105134 m.SetPipe(p.to)135+ m.SetSend(p.send)106136 }107137 }108138 @@ -15,6 +15,7 @@ import (
1515 1616 var (1717 ctrlQ = tea.KeyPressMsg{Code: 'q', Mod: tea.ModCtrl}18+ down = tea.KeyPressMsg{Code: tea.KeyDown, Mod: tea.ModShift}1819 enter = tea.KeyPressMsg{Code: tea.KeyEnter}1920 keyD = tea.KeyPressMsg{Code: 'd', Text: "d"}2021 )@@ -129,6 +130,31 @@ func TestPipeTo(t *testing.T) {
129130 }130131 }131132 133+// TestPipeSend: with --send, Ctrl+Q sends without asking: the134+// selection, or the sheet whatever is selected.135+func TestPipeSend(t *testing.T) {136+ for _, tc := range []struct {137+ args []string138+ want string139+ }{140+ {[]string{"--pipe", "--send", "selection", "--to", "csv"}, "name\nCLAUDE.md\n"},141+ {[]string{"--pipe", "--send=sheet", "--to", "csv"}, "name,size\nCLAUDE.md,1.6 kB\ngo.mod,1.5 kB\n"},142+ } {143+ e, out, _ := pipeEnv(t, lsNUON, down, ctrlQ)144+ if err := run(tc.args, e); err != nil {145+ t.Fatal(err)146+ }147+ if out.String() != tc.want {148+ t.Errorf("%q: stdout %q, want %q", tc.args, out, tc.want)149+ }150+ }151+ // Only one cell selected: --send selection sends the sheet.152+ e, out, _ := pipeEnv(t, lsNUON, ctrlQ)153+ if err := run([]string{"--pipe", "--send", "selection", "--to", "tsv"}, e); err != nil || out.String() != "name\tsize\nCLAUDE.md\t1.6 kB\ngo.mod\t1.5 kB\n" {154+ t.Errorf("one cell: %v, stdout %q", err, out)155+ }156+}157+132158 func TestPipeQuitWithoutSending(t *testing.T) {133159 e, out, _ := pipeEnv(t, lsNUON, ctrlQ, keyD)134160 if err := run([]string{"--pipe"}, e); !errors.Is(err, errNotSent) {@@ -175,8 +201,12 @@ func TestPipeArguments(t *testing.T) {
175201 {[]string{"--pipe"}, true, "nothing piped in"},176202 {[]string{"--to", "csv"}, false, "--to goes with --pipe"},177203 {[]string{"--pipe", "--to", "xlsx"}, false, "012 writes nuon, json, csv or tsv"},178- {[]string{"--pipe", "--to"}, false, "--to needs a format"},204+ {[]string{"--pipe", "--to"}, false, "--to needs a value: nuon, json, csv or tsv"},179205 {[]string{"-", "a.csv"}, false, "not both"},206+ {[]string{"-", "--send", "sheet"}, false, "--send goes with --pipe: 012 --pipe --send sheet"},207+ {[]string{"--send=ask", "a.csv"}, false, "--send goes with --pipe"},208+ {[]string{"--pipe", "--send", "all"}, false, "--send all: 012 sends ask, selection or sheet"},209+ {[]string{"--pipe", "--send"}, false, "--send needs a value: ask, selection or sheet"},180210 } {181211 e, _, _ := pipeEnv(t, lsNUON)182212 e.isTTY = tc.tty@@ -1,7 +1,7 @@
11 # Charts: Insert > Chart (here from the palette) charts the table22 # around the active cell; the editor bar switches the type with3-# Left/Right, and the chart redraws as its data changes. Terminals with the kitty graphics protocol get a real4-# image; this recording shows the text rendering every terminal gets.3+# Left/Right, and the chart redraws as its data changes. Terminals with kitty graphics or sixel get a real4+# image; VHS records only the text layer, so this shows the text chart under it.55 Output out/charts.gif66 Source lib/setup.tape77 @@ -0,0 +1,41 @@
1+# The sheet command: nushell's module from 012 nu --install-module, used2+# in a nu session. ls's table goes through sheet, three rows are sent3+# back and nu keeps filtering them by size; then quitting without4+# sending makes sheet fail with 012's reason, which try catches. Needs5+# nu on the PATH.6+Output out/sheet.gif7+Source lib/setup.tape8+Source lib/nu.tape9+10+# The module goes next to the binary, out of the recording.11+Hide12+Type "^012 nu --install-module ../bin/012.nu" Enter13+Sleep 1s14+Type "use ../bin/012.nu *; clear" Enter15+Sleep 1s16+Show17+18+Sleep 600ms19+Type "ls data | select name size | sort-by size --reverse | sheet | where size > 1kb"20+Sleep 600ms21+Enter22+Sleep 2s23+Ctrl+G24+Type "A1:B4" Enter25+Sleep 1s26+Screenshot out/stills/sheet-sheet.png27+Ctrl+Q28+Sleep 1.6s29+Enter30+Sleep 2.5s31+Screenshot out/stills/sheet-result.png32+Type "try { ls data | sheet } catch {|e| $e.msg }"33+Sleep 600ms34+Enter35+Sleep 2s36+Ctrl+Q37+Sleep 1.4s38+Type "d"39+Sleep 2.5s40+Screenshot out/stills/sheet-error.png41+Sleep 1s@@ -25,6 +25,7 @@ internal/jev the API key's resolution, answer cache and TypeSafe client
2525 internal/keyring the OS credential store the API key lives in2626 internal/macro macros: the Starlark scripting API, recorded actions as scripts, step limits2727 internal/nushell a notebook's commands: nu run as a process, tables in as NUON files, a table back28+ module 012.nu, the nushell module with sheet, embedded for 012 nu --module and --install-module2829 internal/telemetry opt-in JSON log and OTLP export of spans, events and frame stats2930 internal/serve the SSH server: auth, host key, a Model per session (charm.land/wish/v2)3031 internal/confine resolving typed file names, confined to a directory when served@@ -43,6 +43,24 @@ heading makes, a missing image or two pages at one address. It checks
4343 the same links `scripts/doccheck` does, as the site resolves them, so a4444 page that passes `make lint` but breaks on the site shows up here.4545 46+## Old addresses keep working47+48+A page's address is its path under `docs/`, so moving or deleting a49+page would break links to it from elsewhere. A page that moves or goes50+leaves a redirect in `website/redirects.json`, from its old address to51+the page its reader wants now:52+53+```json54+{"from": "/docs/terminal/nushell/", "to": "/docs/nushell/notebooks/"}55+```56+57+`@docusaurus/plugin-client-redirects` writes a page at each old address58+that sends the browser on, since a static host can't redirect by59+itself, and the build fails on a redirect to a page that doesn't exist.60+`scripts/doccheck` (in `make lint`) fails when a page the site has61+published is gone without a redirect: it reads git's history back to62+the site's first commit for every page there has been.63+4664 ## How the docs become pages4765 4866 - Pages are Markdown as GitHub reads it (`markdown.format: 'detect'`):@@ -101,8 +101,10 @@ so Alt+letter reaches the app. VHS has no mouse commands, so the tapes
101101 use the keyboard, and they reach commands through the palette (Ctrl+K)102102 rather than counting menu items, so a new menu item doesn't break them.103103 Tapes that change settings set them for the run (`O12_KEYMAP=vim`)104-rather than writing the config file the other tapes share, and charts105-are drawn as text (`O12_CHART_IMAGES=false`), since VHS records text.104+rather than writing the config file the other tapes share. VHS's ttyd105+has sixel on, so 012 draws charts as sixel images, but VHS records only106+xterm.js's text layer: the recordings show the text chart each image107+covers ([Charts](../sheets/charts.md)).106108 The nushell tapes need `nu`: `demos/lib/nu.tape` starts a session107109 without your config files, with a fixed prompt and 012 on the PATH, and108110 their data is in `demos/data`, so each recording comes out the same.@@ -134,8 +136,10 @@ and a line in the folder's README. `make site` builds them into the
134136 history (see [CLAUDE.md](../../CLAUDE.md)), and `scripts/doccheck`, which135137 checks the tree above, that relative links and anchors resolve, that136138 every `docs/...md` path Go code names exists, that every file in137-`docs/media` is shown by a doc and made by a tape, and that every tape138-records something a doc shows. Unit tests check what the docs say about139+`docs/media` is shown by a doc and made by a tape, that every tape140+records something a doc shows, and that a page the site has published141+isn't gone without a redirect ([The docs site](site.md#old-addresses-keep-working)).142+Unit tests check what the docs say about139143 the code: menu paths lead to menu items, command ids and keys exist and140144 every bound key is in [Keys and mouse](../reference/keys.md)141145 (`internal/ui/docs_test.go`), settings and variables are options@@ -33,7 +33,9 @@ Sheets copies a filtered range; XLSX keeps every row, the hidden ones
3333 hidden.3434 3535 Formats other than XLSX import as one sheet named after the file (or the36-SQLite table). A file can also be followed instead, its table in a36+SQLite table). Formats that keep no column widths (all but XLSX and37+1-2-3) have their columns fitted to the header and the first 200 rows,38+at most 30 characters wide, as are tables read from standard input. A file can also be followed instead, its table in a3739 linked region that takes in new rows as the file grows or is rewritten:3840 see [Following files](following.md). A table can also come in on standard input, and go back3941 out on standard output: see [Pipelines](../nushell/pipelines.md).Binary file.
Binary file.
Binary file.
Binary file.
Binary file.
Binary file.
Binary file.
Binary file.
Binary file.
Binary file.
Binary file.
@@ -18,7 +18,7 @@ each pipeline's table a live part of the sheet.
1818 1919 | Way | Looks like | For |2020 |---|---|---|21-| [A stage in a pipeline](pipelines.md) | `ls \| to nuon \| ^012 --pipe \| from nuon` | Looking at a table on the terminal, editing it, and sending it on to the next command |21+| [A stage in a pipeline](pipelines.md) | `ls \| sheet \| where size > 1kb` | Looking at a table on the terminal, editing it, and sending it on to the next command |2222 | [A notebook](notebooks.md) | `012 nu`, then `ls \| select name size` at the `nu❯` prompt | Pipelines you keep: each one's table is a named region of the sheet that formulas, charts and other pipelines read, run again when you ask |2323 | [A followed file](../files/following.md) | Data > Linked file, then `$app \| where status >= 500` | A log or export that keeps growing: its rows come in as they're written, and pipelines read the rows it has now |2424 @@ -27,14 +27,48 @@ The first needs nothing but nushell. The other two run `nu` from inside
2727 nushell](https://www.nushell.sh/book/installation.html)); without it the2828 prompt says so, and the rest of 012 works as before.2929 30+## Install the `sheet` command31+32+012 comes with a nushell module, `012.nu`, whose `sheet` command runs33+012 in a pipeline. Write it into nushell's `scripts` folder:34+35+```nu36+^012 nu --install-module37+```38+39+and add the line it prints to `config.nu` (`config nu` opens it):40+41+```nu42+use scripts/012.nu *43+```44+45+In a new nushell, `help sheet` describes it:46+47+| Command | Does |48+|---|---|49+| `sheet` | Opens the table piped in (or a file: `sheet budget.xlsx`) and returns what you send back, with its types; `--send selection` or `--send sheet` sends it on quitting without asking ([Pipelines](pipelines.md#the-sheet-command)) |50+| `sheet view` | Opens the table piped in and returns nothing |51+| `sheet nu` | Opens a [notebook](notebooks.md), as `012 nu` |52+53+`^012 nu --install-module` refuses to replace a different file already54+there unless given `--force`; given a path, it writes the module there55+instead. `^012 nu --module` prints the module, to read or to put56+somewhere yourself.57+58+Without the module, 012 is run as `^012`: in nushell, a word that59+starts with a digit is a number, and the caret calls an external60+command by name ([Running external61+commands](https://www.nushell.sh/book/running_externals.html)). Other62+shells run it as `012`.63+3064 ## A 30-second tour3165 3266 ```nu3367 # A table in, edited, and out again, with its types34-ls | select name size | to nuon | ^012 --pipe | from nuon | where size > 1kb68+ls | select name size | sheet | where size > 1kb3569 3670 # A notebook: each pipeline's table lands in the grid37-^012 nu work.01271+sheet nu work.0123872 ```3973 4074 At the notebook's `nu❯` prompt:@@ -48,16 +82,11 @@ The second region reads the first as `$sales`; typing a new command for
4882 `sales` runs it and then the region that reads it. In a formula on any4983 sheet, `=SUM(nu.sales)` reads the same table.5084 51-In nushell, a word that starts with a digit is a number, so 012 is run52-as `^012`, the caret nushell uses to call an external command by name53-([Running external commands](https://www.nushell.sh/book/running_externals.html)).54-Other shells run it as `012`.55-5685 ## Pages5786 5887 | Page | For |5988 |---|---|60-| [Pipelines](pipelines.md) | `012 -` and `012 --pipe`: tables in on standard input and out on standard output, sending back, the exit status |89+| [Pipelines](pipelines.md) | `sheet`, `012 -` and `012 --pipe`: tables in on standard input and out on standard output, sending back, the exit status |6190 | [Notebooks](notebooks.md) | `012 nu` and the `nu❯` prompt: regions, `$r1` and `$in`, `nu.r1` in formulas, refreshing, saving and trust |6291 | [Types](types.md) | How each nushell type becomes a cell and goes back, and what doesn't survive the trip |6392 | [Cookbook](cookbook.md) | Worked examples: disk usage, a log followed live, a CSV cleaned and summarized, an API, processes, git history |@@ -19,19 +19,32 @@ ls | select name size | to nuon | ^012 --pipe | from nuon | where size > 1kb
1919 the table in NUON, nushell's own notation, so file sizes, durations and2020 dates arrive as themselves, and2121 [`from nuon`](https://www.nushell.sh/commands/docs/from_nuon.html) reads22-what 012 sends back with the same types ([Types](types.md)). In23-nushell, 012 is called as `^012`, since a word starting with a digit is24-a number there.22+what 012 sends back with the same types ([Types](types.md)). With the23+[`sheet` command](#the-sheet-command) installed, the same stage is24+`ls | select name size | sheet | where size > 1kb`.2525 2626 The screen is the terminal's own (`/dev/tty`, or the console on2727 Windows), not standard input or output, so the pipeline's data never2828 mixes with what 012 draws, and nothing but the table reaches standard2929 output.3030 31+```mermaid32+sequenceDiagram33+ participant nu as nushell34+ participant o12 as 012 --pipe35+ participant tty as the terminal36+ nu->>o12: to nuon: the table on standard input37+ o12->>tty: the sheet, drawn on /dev/tty38+ tty->>o12: keys: edit, select, Ctrl+Q, Enter39+ o12->>nu: the selection or the sheet, as NUON on standard output40+ Note over nu: from nuon: a table with its types41+```42+3143 | Command | Reads | Writes |3244 |---|---|---|3345 | `012 -` | A table from standard input, into a new sheet | Nothing; the table stays in 012 until you save or download it |34-| `012 --pipe` | A table from standard input, or a file named after it | The sheet or the selection, to standard output, when you quit |46+| `012 --pipe` | A table from standard input, or a file named after it | The sheet or the selection, to standard output, when you quit (asking which, unless `--send` says) |47+| `sheet`, `sheet view` | As `012 --pipe` and `012 -`, from nushell values | A nushell table, or nothing |3548 3649 ## Reading a table: `012 -`3750 @@ -64,8 +77,26 @@ standard output:
6477 one is made, or else the sheet; S sends the whole sheet instead; D6578 quits without sending; Esc goes back to the sheet.6679 - File > Quit and send selection and File > Quit and send sheet send67- without asking. They're in the menus and the palette only with68- `--pipe`.80+ without asking, and File > Quit without sending (or `:q!`) sends81+ nothing. They're in the menus and the palette only with `--pipe`.82+83+`--send` makes Quit send without asking, for a pipeline that always84+wants the same thing back:85+86+| `--send` | Quit sends |87+|---|---|88+| `ask` (the default) | What you choose at the question above |89+| `selection` | The selection; with only the active cell selected, the sheet, as Enter at the question does |90+| `sheet` | The sheet, whatever is selected |91+92+```nu93+open orders.csv | to nuon | ^012 --pipe --send sheet | from nuon | save -f orders.nuon94+```95+96+The status line still names what Ctrl+Q will send, and File > Quit97+without sending stays in the menu. The active cell on its own isn't a98+selection to send, as at the question: `--send selection` sends the99+sheet until a range is selected.69100 70101 The sheet is its used range from A1. A selection is sent as selected,71102 and its first row names the columns. Either way, rows a filter hides@@ -80,9 +111,42 @@ instead:
80111 open budget.xlsx | to nuon | ^012 --pipe --to csv | save budget.csv81112 ```82113 114+## The `sheet` command115+116+The nushell module that comes with 012 ([Install the `sheet`117+command](README.md#install-the-sheet-command)) wraps both commands, so a118+pipeline needs neither `^012` nor NUON on either side:119+120+```nu121+ls | select name size | sheet | where size > 1kb122+ps | sheet view123+sheet budget.xlsx | save -f budget.csv124+```125+126+127+128+`sheet` is `to nuon | ^012 --pipe --to nuon | from nuon`: it opens the129+table piped in, or the file it names, and returns what you send back130+with its types. `sheet --send sheet` and `sheet --send selection` pass131+`--send` on, so quitting sends without asking:132+133+```nu134+ls | sheet --send sheet | where size > 1kb135+```136+ Text piped in, such as `open --raw data.csv`, goes to137+012 as it is, to be read as `012 -` reads it. `sheet view` is138+`to nuon | ^012 -`, and returns nothing. Quitting without sending makes139+`sheet` fail with 012's reason:140+141+```nu142+try { ls | sheet | save -f picked.nuon } catch {|e| print $e.msg }143+# quit without sending anything to the pipeline144+```145+83146 ## The exit status84147 85-Quitting without sending (D at the question) writes nothing and exits148+Quitting without sending (D at the question, File > Quit without149+sending, `:q!`) writes nothing and exits86150 with status 1, so the pipeline stops rather than carrying on with87151 nothing. Nushell treats that88152 as a failed external command and stops the pipeline with an error@@ -95,25 +159,26 @@ try { ls | to nuon | ^012 --pipe | from nuon | save -f picked.nuon } catch { pri
95159 96160 ## Recipes97161 98-Each of these reads a table into 012; add `--pipe` and `| from nuon`99-to carry on with what you send back.162+Each of these reads a table into 012 with `sheet view`; `sheet`163+instead carries on with what you send back. Without the module, each164+`sheet view` is `to nuon | ^012 -`.100165 101166 ```nu102167 # Files, largest first: sizes in the Size format, dates as dates103-ls | sort-by size --reverse | to nuon | ^012 -168+ls | sort-by size --reverse | sheet view104169 105170 # Processes: CPU as numbers, memory as file sizes106-ps | select pid name cpu mem | to nuon | ^012 -171+ps | select pid name cpu mem | sheet view107172 108173 # Every CSV here, one table, with the file each row came from109-glob *.csv | each {|f| open $f | insert file ($f | path basename) } | flatten | to nuon | ^012 -174+glob *.csv | each {|f| open $f | insert file ($f | path basename) } | flatten | sheet view110175 111176 # An API's JSON, its dates made datetimes on the way112-http get https://api.github.com/repos/nushell/nushell/releases | select name published_at | update published_at { into datetime } | to nuon | ^012 -177+http get https://api.github.com/repos/nushell/nushell/releases | select name published_at | update published_at { into datetime } | sheet view113178 114179 # This computer: sys host is a record, which comes in as one row115-sys host | to nuon | ^012 -116-sys disks | select mount total free | to nuon | ^012 -180+sys host | sheet view181+sys disks | select mount total free | sheet | sort-by free117182 ```118183 119184 The commands are nushell's:@@ -9,10 +9,11 @@ Each [nushell type](https://www.nushell.sh/book/types_of_data.html)
99 becomes a cell of a kind a spreadsheet can work with, and goes back to1010 the same type. A file size is a number of bytes in the Size format, so1111 `=SUM` adds it and `where size > 1kb` still compares it once it's back12-in nushell:12+in nushell ([`sheet`](pipelines.md#the-sheet-command) is 012 as a stage13+of a pipeline):1314 1415 ```nu15-ls | select name size | to nuon | ^012 --pipe | from nuon | describe16+ls | select name size | sheet | describe1617 # table<name: string, size: filesize>1718 ```1819 @@ -22,7 +22,7 @@ mouse and the vim keymap added.
2222 | PgUp, PgDn | A screen up, down |2323 | Alt+PgUp, Alt+PgDn | A screen left, right |2424 | Home, Ctrl+Home, Ctrl+End | Column A, cell A1, the last used cell |25-| Ctrl+G, F5 | Go to a cell, a range or a named range, on any sheet (`Sheet2!B3`) |25+| Ctrl+G, F5 | Go to a cell, a range, a named range or a region's table (`nu.r1`), on any sheet (`Sheet2!B3`) |2626 2727 ## Entering data2828 @@ -113,7 +113,7 @@ range, F2 renames or repoints it and Ctrl+D deletes it.
113113 114114 | Key | Action |115115 |---|---|116-| Ctrl+S, Ctrl+O, Ctrl+Q | Save, open (and import other formats), quit |116+| Ctrl+S, Ctrl+O, Ctrl+Q | Save, open (and import other formats), quit; with `012 --pipe`, quitting asks what to send, or sends what `--send` chose ([Pipelines](../nushell/pipelines.md#sending-it-on-012---pipe)) |117117 | F10, Alt+F, Alt+E, Alt+V, Alt+I, Alt+O, Alt+D, Alt+H | Open a menu; arrows move, Enter runs, Esc closes |118118 | Ctrl+K, Alt+/, Ctrl+Shift+P | Search the menus: find and run any command |119119 | Shift+F10, right-click | The cell, column or row menu |@@ -231,7 +231,7 @@ The `:` line takes:
231231 | `:40` | Go to row 40 |232232 | `:w`, `:w name`, `:w out.csv` | Save, Save as, or Download as another format, as the File menu does |233233 | `:w!`, `:w! name`, `:wq!` | Save even if the file changed on disk since it was opened, and replace a file of the name given, without asking (as choosing Overwrite or Replace would) |234-| `:q`, `:q!` | Quit (asking about unsaved changes), quit discarding them |234+| `:q`, `:q!` | Quit (asking about unsaved changes), quit discarding them; with `012 --pipe`, `:q` quits as Ctrl+Q does and `:q!` quits without sending |235235 | `:wq`, `:x` | Save and quit; `:x` saves only if something changed |236236 | `:e name`, `:e!` | Open a sheet or import a file; refused with unsaved changes unless `:e!` |237237 | `:edit.fill_down`, `:fill down` | Any command, by its id or title |@@ -47,11 +47,16 @@ kitty graphics protocol. Where it does (kitty, Ghostty, WezTerm) the plot is
4747 a real image, drawn in the terminal's own palette and placed with Unicode4848 placeholders, so redraws never erase it. Otherwise, where the terminal4949 lists sixel graphics among its device attributes (foot, xterm, mlterm,50-Windows Terminal), the plot is a sixel image in the terminal's palette,51-in as many colors as it has color registers. A sixel image is drawn over52-the finished screen, so it shows only where its whole plot area does: a53-chart scrolled partly out of the grid, or under another chart, a menu or54-a dialog, is text until it shows whole again, and the image is drawn55-again after scrolling, resizing or an edit to its data. Elsewhere, and56-inside tmux, the plot is drawn with block and braille characters. Axis57-labels, the legend and the frame are text either way.50+Windows Terminal, and terminals built on xterm.js with its image addon51+on, such as VS Code with `terminal.integrated.enableImages`), the plot is52+a sixel image in the terminal's palette, in as many colors as it has53+color registers. A sixel image is drawn over the finished screen, on top54+of the text chart, which it covers whole: a terminal that lists sixel but55+doesn't show the image, or a recording of the text alone (VHS records56+xterm.js's text layer, not its image layer), shows the text chart. The57+image shows only where its whole plot area does: a chart scrolled partly58+out of the grid, or under another chart, a menu or a dialog, is text59+until it shows whole again, and the image is drawn again after60+scrolling, resizing or an edit to its data. Elsewhere, and inside tmux,61+the plot is drawn with block and braille characters. Axis labels, the62+legend and the frame are text either way.@@ -0,0 +1,91 @@
1+package e2e2+3+import (4+ "os"5+ "os/exec"6+ "path/filepath"7+ "strings"8+ "testing"9+)10+11+// The nushell module (012 nu --install-module, then `sheet` in nu): nu12+// runs as a pipeline stage in the terminal, with 012 on its PATH, the13+// module installed where 012 puts it and used by the line 012 prints14+// for config.nu.15+16+// startSheet installs the module in a temporary nu config directory and17+// runs script in nu with it, standard output captured.18+func startSheet(t *testing.T, startsOn, script string) *session {19+ t.Helper()20+ needNu(t)21+ dir := t.TempDir()22+ xdg := filepath.Join(dir, ".config") // the session's own (configEnv)23+ install := exec.Command(binPath, "nu", "--install-module")24+ install.Env = append(os.Environ(), "XDG_CONFIG_HOME="+xdg)25+ out, err := install.CombinedOutput()26+ if err != nil {27+ t.Fatalf("installing the module: %v\n%s", err, out)28+ }29+ lines := strings.Split(strings.TrimSpace(string(out)), "\n")30+ config := filepath.Join(xdg, "nushell", "config.nu")31+ if err := os.WriteFile(config, []byte(lines[len(lines)-1]+"\n"), 0o644); err != nil {32+ t.Fatal(err)33+ }34+ path := "PATH=" + filepath.Dir(binPath) + string(os.PathListSeparator) + os.Getenv("PATH")35+ return startWith(t, options{dir: dir, piped: true, program: "nu", startsOn: startsOn, env: []string{path}},36+ "--config", config, "-c", script)37+}38+39+const sizesNu = "[[name size]; [a 2kb] [b 10b] [c 5mb]]"40+41+// A table goes through sheet: a selection is sent back, and nu gets it42+// with its types, file sizes as file sizes.43+func TestSheetSendsSelection(t *testing.T) {44+ s := startSheet(t, "5.0 MB", "let t = "+sizesNu+" | sheet; print ($t | get size | describe); $t | to nuon")45+ s.keys("<shift+down>", "<shift+down>", "<shift+right>")46+ s.waitFor("send A1:B3 as NUON")47+ s.keys("<ctrl+q>")48+ s.waitFor("Send A1:B3 as NUON?")49+ s.keys("<enter>")50+ out, code := s.finish()51+ if want := "list<filesize>\n[[name, size]; [a, 2000b], [b, 10b]]\n"; code != 0 || out != want {52+ t.Errorf("exit %d, stdout %q, want %q", code, out, want)53+ }54+}55+56+// sheet --send sheet gives back all of ls's table on Ctrl+Q, whatever57+// is selected.58+func TestSheetSendSheet(t *testing.T) {59+ s := startSheet(t, "b.txt", "cd (mktemp -d); 'x' | save a.txt; 'yyy' | save b.txt; "+60+ "let t = ls | sheet --send sheet; print ($t | columns | to nuon); "+61+ "print (($t | select name type size) == (ls | select name type size)); print ($t | length)")62+ s.keys("<shift+down>")63+ s.waitFor("Ctrl+Q send the sheet as NUON")64+ s.keys("<ctrl+q>")65+ out, code := s.finish()66+ if want := "[name, type, size, modified]\ntrue\n2\n"; code != 0 || out != want {67+ t.Errorf("exit %d, stdout %q, want %q", code, out, want)68+ }69+}70+71+// Quitting without sending raises sheet's error, with 012's reason.72+func TestSheetNotSent(t *testing.T) {73+ s := startSheet(t, "5.0 MB", "try { "+sizesNu+" | sheet } catch {|e| print $'caught: ($e.msg)' }")74+ s.keys("<ctrl+q>", "d")75+ out, code := s.finish()76+ if want := "caught: quit without sending anything to the pipeline\n"; code != 0 || out != want {77+ t.Errorf("exit %d, stdout %q, want %q", code, out, want)78+ }79+}80+81+// sheet view shows the table and returns nothing.82+func TestSheetView(t *testing.T) {83+ s := startSheet(t, "5.0 MB", sizesNu+" | sheet view | describe")84+ s.keys("<ctrl+q>")85+ s.waitFor("You have unsaved changes.")86+ s.keys("d")87+ out, code := s.finish()88+ if code != 0 || out != "nothing\n" {89+ t.Errorf("exit %d, stdout %q", code, out)90+ }91+}@@ -105,6 +105,45 @@ func TestPipeSendSelectionAsCSV(t *testing.T) {
105105 }106106 }107107 108+// TestPipeSendSelectionWithoutAsking: --send selection makes Ctrl+Q109+// send the selection at once.110+func TestPipeSendSelectionWithoutAsking(t *testing.T) {111+ s := startWith(t, options{piped: true, stdin: lsNUON}, "--pipe", "--send", "selection", "--to", "csv")112+ s.waitFor("Ctrl+Q send the sheet as CSV")113+ s.keys("<shift+down>", "<shift+right>")114+ s.waitFor("Ctrl+Q send A1:B2 as CSV")115+ s.keys("<ctrl+q>")116+ out, code := s.finish()117+ if code != 0 || out != "name,size\nCLAUDE.md,1.6 kB\n" {118+ t.Errorf("exit %d, stdout %q", code, out)119+ }120+}121+122+// TestPipeSendSheetWithoutAsking: --send sheet makes Ctrl+Q send the123+// whole sheet, whatever is selected; File > Quit without sending still124+// sends nothing.125+func TestPipeSendSheetWithoutAsking(t *testing.T) {126+ s := startWith(t, options{piped: true, stdin: "a,b\n1,2\n3,4\n"}, "--pipe", "--send", "sheet")127+ s.waitFor("Read 3 rows of CSV from standard input")128+ s.keys("<shift+down>")129+ s.waitFor("Ctrl+Q send the sheet as CSV")130+ s.keys("<ctrl+q>")131+ out, code := s.finish()132+ if code != 0 || out != "a,b\n1,2\n3,4\n" {133+ t.Errorf("exit %d, stdout %q", code, out)134+ }135+136+ s = startWith(t, options{piped: true, stdin: "a,b\n1,2\n"}, "--pipe", "--send", "sheet")137+ s.waitFor("Read 2 rows of CSV from standard input")138+ s.keys("<ctrl+k>", "without sending")139+ s.waitFor("Quit without sending")140+ s.keys("<enter>")141+ out, code = s.finish()142+ if code != 1 || out != "" {143+ t.Errorf("quit without sending: exit %d, stdout %q", code, out)144+ }145+}146+108147 // TestPipeQuitWithoutSending exits with status 1 and writes nothing.109148 func TestPipeQuitWithoutSending(t *testing.T) {110149 s := startWith(t, options{piped: true, stdin: "a,b\n1,2\n"}, "--pipe")@@ -102,7 +102,7 @@ var screens = []screen{
102102 }},103103 {name: "error-goto", setup: func(s *session) {104104 s.keys("<f5>", "nope", "<enter>")105- s.waitFor("Not a cell, range or named range")105+ s.waitFor("Not a cell, range, named range or region")106106 }},107107 {name: "help", setup: func(s *session) {108108 s.keys("<f1>")@@ -5,16 +5,16 @@
55 <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">1</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Month</span><span style="background:var(--vt-palette-6)"> </span> Rent Food <span style="color:var(--vt-palette-8)">┌─</span> <span style="font-weight:bold">Rent</span> <span style="font-weight:bold">and</span> <span style="font-weight:bold">Food</span> <span style="color:var(--vt-palette-8)">──────────────────────────────┐</span>66 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">2</span><span style="background:var(--vt-palette-7)"> </span> Jan $1,450 $600 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span>77 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">3</span><span style="background:var(--vt-palette-7)"> </span> Feb $1,450 $640 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span>8-<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">4</span><span style="background:var(--vt-palette-7)"> </span> Mar $1,500 $612 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-0)">$1,500</span> <span style="color:var(--vt-palette-8)">┤</span><span style="color:var(--vt-palette-4)">▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▇▇▇▇▇██████████████</span> <span style="color:var(--vt-palette-8)">│</span>8+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">4</span><span style="background:var(--vt-palette-7)"> </span> Mar $1,500 $612 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-0)">$1,500</span> <span style="color:var(--vt-palette-8)">┤</span><span style="color:var(--vt-palette-4)">▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▃▃▃▃▃▄▄▄▄▄▄▄▄▄▄▄▄▄▄</span> <span style="color:var(--vt-palette-8)">│</span>99 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">5</span><span style="background:var(--vt-palette-7)"> </span> Apr $1,500 $700 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-4)">███████████████████████████████████</span> <span style="color:var(--vt-palette-8)">│</span>1010 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">6</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-4)">███████████████████████████████████</span> <span style="color:var(--vt-palette-8)">│</span>1111 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">7</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-0)">$1,000</span> <span style="color:var(--vt-palette-8)">┤</span><span style="color:var(--vt-palette-4)">███████████████████████████████████</span> <span style="color:var(--vt-palette-8)">│</span>12-<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">8</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-4)">████████████████████████████████</span><span style="color:var(--vt-palette-5);background:var(--vt-palette-4)">▁▁▂</span> <span style="color:var(--vt-palette-8)">│</span>13-<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">9</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-5);background:var(--vt-palette-4)">▅▅▅▅▆▆▆▆▆▆▇▇▇▇▆▆▆▆▆▆▆▆▅▅▆▆▇▇▇</span><span style="color:var(--vt-palette-5)">██████</span> <span style="color:var(--vt-palette-8)">│</span>12+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">8</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-4)">███████████████████████████████████</span> <span style="color:var(--vt-palette-8)">│</span>13+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">9</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-5);background:var(--vt-palette-4)">▁▁▁▁▂▂▂▂▂▂▃▃▃▃▂▂▂▂▂▂▂▂▁▁▂▂▃▃▃▄▄▄▅▅▆</span> <span style="color:var(--vt-palette-8)">│</span>1414 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">10</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-0)">$500</span> <span style="color:var(--vt-palette-8)">┤</span><span style="color:var(--vt-palette-5)">███████████████████████████████████</span> <span style="color:var(--vt-palette-8)">│</span>1515 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">11</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-5)">███████████████████████████████████</span> <span style="color:var(--vt-palette-8)">│</span>1616 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">12</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-5)">███████████████████████████████████</span> <span style="color:var(--vt-palette-8)">│</span>17-<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">13</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-0)">$0</span> <span style="color:var(--vt-palette-8)">┼────────────────────────────────────</span> <span style="color:var(--vt-palette-8)">│</span>17+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">13</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-0)">$0</span> <span style="color:var(--vt-palette-8)">┼</span><span style="color:var(--vt-palette-5)">▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀</span><span style="color:var(--vt-palette-8)">─</span> <span style="color:var(--vt-palette-8)">│</span>1818 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">14</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-0)">Jan</span> <span style="color:var(--vt-palette-0)">Feb</span> <span style="color:var(--vt-palette-0)">Mar</span> <span style="color:var(--vt-palette-0)">Apr</span> <span style="color:var(--vt-palette-8)">│</span>1919 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">15</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-4)">■</span> <span style="color:var(--vt-palette-0)">Rent</span> <span style="color:var(--vt-palette-5)">■</span> <span style="color:var(--vt-palette-0)">Food</span> <span style="color:var(--vt-palette-8)">│</span>2020 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">16</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">└──────────────────────────────────────</span> <span style="color:var(--vt-palette-0)">A1:C5</span> <span style="color:var(--vt-palette-8)">─┘</span>@@ -5,16 +5,16 @@
55 <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">1</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Month</span><span style="background:var(--vt-palette-6)"> </span> Rent Food <span style="color:var(--vt-palette-8)">┌─</span> <span style="font-weight:bold">Rent</span> <span style="font-weight:bold">and</span> <span style="font-weight:bold">Food</span> <span style="color:var(--vt-palette-8)">──────────────────────────────┐</span>66 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">2</span><span style="background:var(--vt-palette-8)"> </span> Jan $1,450 $600 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span>77 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">3</span><span style="background:var(--vt-palette-8)"> </span> Feb $1,450 $640 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span>8-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">4</span><span style="background:var(--vt-palette-8)"> </span> Mar $1,500 $612 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$1,500</span> <span style="color:var(--vt-palette-8)">┤</span><span style="color:var(--vt-palette-6)">▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▇▇▇▇▇██████████████</span> <span style="color:var(--vt-palette-8)">│</span>8+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">4</span><span style="background:var(--vt-palette-8)"> </span> Mar $1,500 $612 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$1,500</span> <span style="color:var(--vt-palette-8)">┤</span><span style="color:var(--vt-palette-6)">▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▃▃▃▃▃▄▄▄▄▄▄▄▄▄▄▄▄▄▄</span> <span style="color:var(--vt-palette-8)">│</span>99 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">5</span><span style="background:var(--vt-palette-8)"> </span> Apr $1,500 $700 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-6)">███████████████████████████████████</span> <span style="color:var(--vt-palette-8)">│</span>1010 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">6</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-6)">███████████████████████████████████</span> <span style="color:var(--vt-palette-8)">│</span>1111 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">7</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$1,000</span> <span style="color:var(--vt-palette-8)">┤</span><span style="color:var(--vt-palette-6)">███████████████████████████████████</span> <span style="color:var(--vt-palette-8)">│</span>12-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">8</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-6)">████████████████████████████████</span><span style="color:var(--vt-palette-5);background:var(--vt-palette-6)">▁▁▂</span> <span style="color:var(--vt-palette-8)">│</span>13-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">9</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-5);background:var(--vt-palette-6)">▅▅▅▅▆▆▆▆▆▆▇▇▇▇▆▆▆▆▆▆▆▆▅▅▆▆▇▇▇</span><span style="color:var(--vt-palette-5)">██████</span> <span style="color:var(--vt-palette-8)">│</span>12+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">8</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-6)">███████████████████████████████████</span> <span style="color:var(--vt-palette-8)">│</span>13+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">9</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-5);background:var(--vt-palette-6)">▁▁▁▁▂▂▂▂▂▂▃▃▃▃▂▂▂▂▂▂▂▂▁▁▂▂▃▃▃▄▄▄▅▅▆</span> <span style="color:var(--vt-palette-8)">│</span>1414 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">10</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$500</span> <span style="color:var(--vt-palette-8)">┤</span><span style="color:var(--vt-palette-5)">███████████████████████████████████</span> <span style="color:var(--vt-palette-8)">│</span>1515 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">11</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-5)">███████████████████████████████████</span> <span style="color:var(--vt-palette-8)">│</span>1616 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">12</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-5)">███████████████████████████████████</span> <span style="color:var(--vt-palette-8)">│</span>17-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">13</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$0</span> <span style="color:var(--vt-palette-8)">┼────────────────────────────────────</span> <span style="color:var(--vt-palette-8)">│</span>17+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">13</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$0</span> <span style="color:var(--vt-palette-8)">┼</span><span style="color:var(--vt-palette-5)">▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀</span><span style="color:var(--vt-palette-8)">─</span> <span style="color:var(--vt-palette-8)">│</span>1818 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">14</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">Jan</span> <span style="color:var(--vt-palette-8)">Feb</span> <span style="color:var(--vt-palette-8)">Mar</span> <span style="color:var(--vt-palette-8)">Apr</span> <span style="color:var(--vt-palette-8)">│</span>1919 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">15</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">■</span> <span style="color:var(--vt-palette-8)">Rent</span> <span style="color:var(--vt-palette-5)">■</span> <span style="color:var(--vt-palette-8)">Food</span> <span style="color:var(--vt-palette-8)">│</span>2020 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">16</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">└──────────────────────────────────────</span> <span style="color:var(--vt-palette-8)">A1:C5</span> <span style="color:var(--vt-palette-8)">─┘</span>@@ -3,19 +3,19 @@
33 <span style="color:var(--vt-palette-0)">Min</span> <span style="color:var(--vt-palette-0)">auto</span> <span style="color:var(--vt-palette-0)">Max</span> <span style="color:var(--vt-palette-0)">auto</span> <span style="color:var(--vt-palette-0)">Log</span> <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Gridlines</span><span style="background:var(--vt-palette-6)"> </span> <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Legend</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">right</span><span style="background:var(--vt-palette-6)"> </span>44 <span style="background:var(--vt-palette-7)"> </span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">A</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">B</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">C</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">D</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">E</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">F</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">G</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">H</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">I</span><span style="background:var(--vt-palette-7)"> </span>55 <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">1</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Month</span><span style="background:var(--vt-palette-6)"> </span> Rent Food <span style="color:var(--vt-palette-6);font-weight:bold">┌─</span> <span style="font-weight:bold">Rent</span> <span style="font-weight:bold">and</span> <span style="font-weight:bold">Food</span> <span style="color:var(--vt-palette-6);font-weight:bold">──────────────────────────────┐</span>6-<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">2</span><span style="background:var(--vt-palette-7)"> </span> Jan $1,450 $600 <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-0)">$1,500</span> <span style="color:var(--vt-palette-8)">┤</span><span style="color:var(--vt-palette-4)">▅▅▅</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span><span style="color:var(--vt-palette-4)">▅▅▅</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>6+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">2</span><span style="background:var(--vt-palette-7)"> </span> Jan $1,450 $600 <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-0)">$1,500</span> <span style="color:var(--vt-palette-8)">┤</span><span style="color:var(--vt-palette-4)">▁▁▁</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span><span style="color:var(--vt-palette-4)">▁▁▁</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span><span style="color:var(--vt-palette-4)">▄▄▄</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span><span style="color:var(--vt-palette-4)">▄▄▄</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>77 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">3</span><span style="background:var(--vt-palette-7)"> </span> Feb $1,450 $640 <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>88 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">4</span><span style="background:var(--vt-palette-7)"> </span> Mar $1,500 $612 <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-0)">$1,250</span> <span style="color:var(--vt-palette-8)">┤</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>99 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">5</span><span style="background:var(--vt-palette-7)"> </span> Apr $1,500 $700 <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1010 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">6</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-0)">$1,000</span> <span style="color:var(--vt-palette-8)">┤</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1111 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">7</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>12-<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">8</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-0)">$750</span> <span style="color:var(--vt-palette-8)">┤</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">▁▁▁</span><span style="color:var(--vt-palette-8)">┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">▅▅▅</span><span style="color:var(--vt-palette-8)">┈</span> <span style="color:var(--vt-palette-4)">■</span> <span style="color:var(--vt-palette-0)">Rent</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>13-<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">9</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">▆▆▆</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">▇▇▇</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-5)">■</span> <span style="color:var(--vt-palette-0)">Food</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>12+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">8</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-0)">$750</span> <span style="color:var(--vt-palette-8)">┤</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">▁▁▁</span><span style="color:var(--vt-palette-8)">┈</span> <span style="color:var(--vt-palette-4)">■</span> <span style="color:var(--vt-palette-0)">Rent</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>13+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">9</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">▂▂▂</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">▅▅▅</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">▃▃▃</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-5)">■</span> <span style="color:var(--vt-palette-0)">Food</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1414 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">10</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-0)">$500</span> <span style="color:var(--vt-palette-8)">┤</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1515 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">11</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1616 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">12</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-0)">$250</span> <span style="color:var(--vt-palette-8)">┤</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1717 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">13</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>18-<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">14</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-0)">$0</span> <span style="color:var(--vt-palette-8)">┼─────────────────────────────</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>18+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">14</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-0)">$0</span> <span style="color:var(--vt-palette-8)">┼</span><span style="color:var(--vt-palette-4)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">─</span><span style="color:var(--vt-palette-4)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">─</span><span style="color:var(--vt-palette-4)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">─</span><span style="color:var(--vt-palette-4)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">──</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1919 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">15</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-0)">Jan</span> <span style="color:var(--vt-palette-0)">Feb</span> <span style="color:var(--vt-palette-0)">Mar</span> <span style="color:var(--vt-palette-0)">Apr</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>2020 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">16</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">└──────────────────────────────────────</span> <span style="color:var(--vt-palette-0)">A1:C5</span> <span style="color:var(--vt-palette-6);font-weight:bold">─◢</span>2121 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">17</span><span style="background:var(--vt-palette-7)"> </span>@@ -6,10 +6,10 @@
66 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">7</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-6);font-weight:bold">┌─</span> <span style="font-weight:bold">Rent</span> <span style="font-weight:bold">and</span> <span style="font-weight:bold">Food</span> <span style="color:var(--vt-palette-6);font-weight:bold">──────────────────────────────┐</span>77 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">8</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>88 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">9</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">$2,000</span> <span style="color:var(--vt-palette-8)">┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>9-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">10</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">▇▇▇</span> <span style="color:var(--vt-palette-6)">▇▇▇</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>10-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">11</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">$1,000</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▂▂▂</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▂▂▂</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▂▂▂</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▃▃▃</span><span style="color:var(--vt-palette-8)">┈┈┈</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>11-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">12</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>12-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">13</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">$0</span> <span style="color:var(--vt-palette-8)">┼────────────────────────────────────</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>9+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">10</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">▃▃▃</span> <span style="color:var(--vt-palette-6)">▃▃▃</span> <span style="color:var(--vt-palette-6)">▄▄▄</span> <span style="color:var(--vt-palette-6)">▄▄▄</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>10+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">11</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">$1,000</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>11+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">12</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▆▆▆</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▆▆▆</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▆▆▆</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▇▇▇</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>12+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">13</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">$0</span> <span style="color:var(--vt-palette-8)">┼──</span><span style="color:var(--vt-palette-6)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">──</span><span style="color:var(--vt-palette-6)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">──</span><span style="color:var(--vt-palette-6)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">──</span><span style="color:var(--vt-palette-6)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">────</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1313 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">14</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">Jan</span> <span style="color:var(--vt-palette-8)">Feb</span> <span style="color:var(--vt-palette-8)">Mar</span> <span style="color:var(--vt-palette-8)">Apr</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1414 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">15</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-6)">■</span> <span style="color:var(--vt-palette-8)">Rent</span> <span style="color:var(--vt-palette-5)">■</span> <span style="color:var(--vt-palette-8)">Food</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1515 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">16</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-6);font-weight:bold">└──────────────────────────────────────</span> <span style="color:var(--vt-palette-8)">A1:C5</span> <span style="color:var(--vt-palette-6);font-weight:bold">─◢</span></pre>\ No newline at end of file@@ -3,19 +3,19 @@
33 <span style="color:var(--vt-palette-8)">Min</span> <span style="color:var(--vt-palette-8)">auto</span> <span style="color:var(--vt-palette-8)">Max</span> <span style="color:var(--vt-palette-8)">auto</span> <span style="color:var(--vt-palette-8)">Log</span> <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Gridlines</span><span style="background:var(--vt-palette-6)"> </span> <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Legend</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">right</span><span style="background:var(--vt-palette-6)"> </span>44 <span style="background:var(--vt-palette-8)"> </span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">A</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">B</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">C</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">D</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">E</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">F</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">G</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">H</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">I</span><span style="background:var(--vt-palette-8)"> </span>55 <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">1</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Month</span><span style="background:var(--vt-palette-6)"> </span> Rent Food <span style="color:var(--vt-palette-6);font-weight:bold">┌─</span> <span style="font-weight:bold">Rent</span> <span style="font-weight:bold">and</span> <span style="font-weight:bold">Food</span> <span style="color:var(--vt-palette-6);font-weight:bold">──────────────────────────────┐</span>6-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">2</span><span style="background:var(--vt-palette-8)"> </span> Jan $1,450 $600 <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">$1,500</span> <span style="color:var(--vt-palette-8)">┤</span><span style="color:var(--vt-palette-6)">▅▅▅</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span><span style="color:var(--vt-palette-6)">▅▅▅</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>6+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">2</span><span style="background:var(--vt-palette-8)"> </span> Jan $1,450 $600 <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">$1,500</span> <span style="color:var(--vt-palette-8)">┤</span><span style="color:var(--vt-palette-6)">▁▁▁</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span><span style="color:var(--vt-palette-6)">▁▁▁</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span><span style="color:var(--vt-palette-6)">▄▄▄</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span><span style="color:var(--vt-palette-6)">▄▄▄</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>77 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">3</span><span style="background:var(--vt-palette-8)"> </span> Feb $1,450 $640 <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>88 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">4</span><span style="background:var(--vt-palette-8)"> </span> Mar $1,500 $612 <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">$1,250</span> <span style="color:var(--vt-palette-8)">┤</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>99 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">5</span><span style="background:var(--vt-palette-8)"> </span> Apr $1,500 $700 <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1010 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">6</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">$1,000</span> <span style="color:var(--vt-palette-8)">┤</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1111 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">7</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>12-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">8</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">$750</span> <span style="color:var(--vt-palette-8)">┤</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▁▁▁</span><span style="color:var(--vt-palette-8)">┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▅▅▅</span><span style="color:var(--vt-palette-8)">┈</span> <span style="color:var(--vt-palette-6)">■</span> <span style="color:var(--vt-palette-8)">Rent</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>13-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">9</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▆▆▆</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▇▇▇</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-5)">■</span> <span style="color:var(--vt-palette-8)">Food</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>12+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">8</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">$750</span> <span style="color:var(--vt-palette-8)">┤</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▁▁▁</span><span style="color:var(--vt-palette-8)">┈</span> <span style="color:var(--vt-palette-6)">■</span> <span style="color:var(--vt-palette-8)">Rent</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>13+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">9</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▂▂▂</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▅▅▅</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▃▃▃</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-5)">■</span> <span style="color:var(--vt-palette-8)">Food</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1414 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">10</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">$500</span> <span style="color:var(--vt-palette-8)">┤</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1515 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">11</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1616 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">12</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">$250</span> <span style="color:var(--vt-palette-8)">┤</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1717 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">13</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>18-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">14</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">$0</span> <span style="color:var(--vt-palette-8)">┼─────────────────────────────</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>18+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">14</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">$0</span> <span style="color:var(--vt-palette-8)">┼</span><span style="color:var(--vt-palette-6)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">─</span><span style="color:var(--vt-palette-6)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">─</span><span style="color:var(--vt-palette-6)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">─</span><span style="color:var(--vt-palette-6)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">──</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1919 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">15</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">Jan</span> <span style="color:var(--vt-palette-8)">Feb</span> <span style="color:var(--vt-palette-8)">Mar</span> <span style="color:var(--vt-palette-8)">Apr</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>2020 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">16</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">└──────────────────────────────────────</span> <span style="color:var(--vt-palette-8)">A1:C5</span> <span style="color:var(--vt-palette-6);font-weight:bold">─◢</span>2121 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">17</span><span style="background:var(--vt-palette-8)"> </span>@@ -3,13 +3,13 @@
33 44 <span style="background:var(--vt-palette-8)"> </span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">A</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">B</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">C</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">D</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">E</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">F</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">G</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">H</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">I</span><span style="background:var(--vt-palette-8)"> </span>55 <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">1</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Month</span><span style="background:var(--vt-palette-6)"> </span> Rent Food <span style="color:var(--vt-palette-8)">┌─</span> <span style="font-weight:bold">Rent</span> <span style="font-weight:bold">and</span> <span style="font-weight:bold">Food</span> <span style="color:var(--vt-palette-8)">──────────────────────────────┐</span>6-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">2</span><span style="background:var(--vt-palette-8)"> </span> Jan $1,450 $600 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">Jan</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-6)">████████████████████████</span><span style="color:var(--vt-palette-6);background:var(--vt-palette-5)">▊</span><span style="color:var(--vt-palette-5)">██████████</span> <span style="color:var(--vt-palette-8)">│</span>6+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">2</span><span style="background:var(--vt-palette-8)"> </span> Jan $1,450 $600 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">Jan</span> <span style="color:var(--vt-palette-6)">▐████████████████████████</span><span style="color:var(--vt-palette-6);background:var(--vt-palette-5)">▎</span><span style="color:var(--vt-palette-5)">█████████▌</span> <span style="color:var(--vt-palette-8)">│</span>77 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">3</span><span style="background:var(--vt-palette-8)"> </span> Feb $1,450 $640 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">│</span>8-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">4</span><span style="background:var(--vt-palette-8)"> </span> Mar $1,500 $612 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">Feb</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-6)">████████████████████████</span><span style="color:var(--vt-palette-6);background:var(--vt-palette-5)">▎</span><span style="color:var(--vt-palette-5)">██████████</span> <span style="color:var(--vt-palette-8)">│</span>8+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">4</span><span style="background:var(--vt-palette-8)"> </span> Mar $1,500 $612 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">Feb</span> <span style="color:var(--vt-palette-6)">▐███████████████████████</span><span style="color:var(--vt-palette-6);background:var(--vt-palette-5)">▊</span><span style="color:var(--vt-palette-5)">██████████▌</span> <span style="color:var(--vt-palette-8)">│</span>99 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">5</span><span style="background:var(--vt-palette-8)"> </span> Apr $1,500 $700 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">│</span>10-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">6</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">Mar</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-6)">████████████████████████</span><span style="color:var(--vt-palette-6);background:var(--vt-palette-5)">▉</span><span style="color:var(--vt-palette-5)">██████████</span> <span style="color:var(--vt-palette-8)">│</span>10+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">6</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">Mar</span> <span style="color:var(--vt-palette-6)">▐████████████████████████</span><span style="color:var(--vt-palette-6);background:var(--vt-palette-5)">▍</span><span style="color:var(--vt-palette-5)">█████████▌</span> <span style="color:var(--vt-palette-8)">│</span>1111 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">7</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">│</span>12-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">8</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">Apr</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-6)">███████████████████████</span><span style="color:var(--vt-palette-6);background:var(--vt-palette-5)">▉</span><span style="color:var(--vt-palette-5)">███████████</span> <span style="color:var(--vt-palette-8)">│</span>12+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">8</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">Apr</span> <span style="color:var(--vt-palette-6)">▐███████████████████████</span><span style="color:var(--vt-palette-6);background:var(--vt-palette-5)">▍</span><span style="color:var(--vt-palette-5)">██████████▌</span> <span style="color:var(--vt-palette-8)">│</span>1313 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">9</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">│</span>1414 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">10</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">│</span>1515 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">11</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">│</span>@@ -3,17 +3,17 @@
33 44 <span style="background:var(--vt-palette-8)"> </span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">A</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">B</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">C</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">D</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">E</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">F</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">G</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">H</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">I</span><span style="background:var(--vt-palette-8)"> </span>55 <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">1</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Month</span><span style="background:var(--vt-palette-6)"> </span> Rent Food <span style="color:var(--vt-palette-8)">┌─</span> <span style="font-weight:bold">Rent</span> <span style="font-weight:bold">and</span> <span style="font-weight:bold">Food</span> <span style="color:var(--vt-palette-8)">──────────────────────────────┐</span>6-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">2</span><span style="background:var(--vt-palette-8)"> </span> Jan $1,450 $600 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">Jan</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-6)">██████████████████████████████████▊</span><span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">│</span>7-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">3</span><span style="background:var(--vt-palette-8)"> </span> Feb $1,450 $640 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-5)">██████████████▍</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">│</span>6+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">2</span><span style="background:var(--vt-palette-8)"> </span> Jan $1,450 $600 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">Jan</span> <span style="color:var(--vt-palette-6)">▐██████████████████████████████████▎</span><span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">│</span>7+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">3</span><span style="background:var(--vt-palette-8)"> </span> Feb $1,450 $640 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-5)">▐█████████████▉</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">│</span>88 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">4</span><span style="background:var(--vt-palette-8)"> </span> Mar $1,500 $612 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">│</span>9-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">5</span><span style="background:var(--vt-palette-8)"> </span> Apr $1,500 $700 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">Feb</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-6)">██████████████████████████████████▊</span><span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">│</span>10-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">6</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-5)">███████████████▍</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">│</span>9+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">5</span><span style="background:var(--vt-palette-8)"> </span> Apr $1,500 $700 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">Feb</span> <span style="color:var(--vt-palette-6)">▐██████████████████████████████████▎</span><span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">│</span>10+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">6</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-5)">▐██████████████▉</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">│</span>1111 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">7</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">│</span>12-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">8</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">Mar</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-6)">████████████████████████████████████</span> <span style="color:var(--vt-palette-8)">│</span>13-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">9</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-5)">██████████████▊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">│</span>12+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">8</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">Mar</span> <span style="color:var(--vt-palette-6)">▐███████████████████████████████████▌</span> <span style="color:var(--vt-palette-8)">│</span>13+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">9</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-5)">▐██████████████▎</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">│</span>1414 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">10</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">│</span>15-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">11</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">Apr</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-6)">████████████████████████████████████</span> <span style="color:var(--vt-palette-8)">│</span>16-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">12</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-5)">████████████████▊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">│</span>15+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">11</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">Apr</span> <span style="color:var(--vt-palette-6)">▐███████████████████████████████████▌</span> <span style="color:var(--vt-palette-8)">│</span>16+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">12</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-5)">▐████████████████▎</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">┊</span> <span style="color:var(--vt-palette-8)">│</span>1717 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">13</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">└───────────┬───────────┬───────────┬</span> <span style="color:var(--vt-palette-8)">│</span>1818 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">14</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$0</span> <span style="color:var(--vt-palette-8)">$500</span> <span style="color:var(--vt-palette-8)">$1,000</span> <span style="color:var(--vt-palette-8)">$1,500</span> <span style="color:var(--vt-palette-8)">│</span>1919 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">15</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">■</span> <span style="color:var(--vt-palette-8)">Rent</span> <span style="color:var(--vt-palette-5)">■</span> <span style="color:var(--vt-palette-8)">Food</span> <span style="color:var(--vt-palette-8)">│</span>@@ -5,16 +5,16 @@
55 <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">1</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Month</span><span style="background:var(--vt-palette-6)"> </span> Rent Food <span style="color:var(--vt-palette-6);font-weight:bold">┌─</span> <span style="font-weight:bold">Rent</span> <span style="font-weight:bold">and</span> <span style="font-weight:bold">Food</span> <span style="color:var(--vt-palette-6);font-weight:bold">──────────────────────────────┐</span>66 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">2</span><span style="background:var(--vt-palette-7)"> </span> Jan $1,450 $600 <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>77 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">3</span><span style="background:var(--vt-palette-7)"> </span> Feb $1,450 $640 <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>8-<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">4</span><span style="background:var(--vt-palette-7)"> </span> Mar $1,500 $612 <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-0)">$1,500</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-4)">▆▆▆</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-4)">▆▆▆</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>8+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">4</span><span style="background:var(--vt-palette-7)"> </span> Mar $1,500 $612 <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-0)">$1,500</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-4)">▂▂▂</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-4)">▂▂▂</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-4)">▄▄▄</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-4)">▄▄▄</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>99 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">5</span><span style="background:var(--vt-palette-7)"> </span> Apr $1,500 $700 <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1010 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">6</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1111 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">7</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-0)">$1,000</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>12-<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">8</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">▂▂▂</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>13-<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">9</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">▅▅▅</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">▇▇▇</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">▅▅▅</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>12+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">8</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>13+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">9</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">▁▁▁</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">▃▃▃</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">▁▁▁</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">▆▆▆</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1414 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">10</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-0)">$500</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈┈┈</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1515 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">11</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1616 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">12</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>17-<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">13</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-0)">$0</span> <span style="color:var(--vt-palette-8)">┼────────────────────────────────────</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>17+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">13</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-0)">$0</span> <span style="color:var(--vt-palette-8)">┼──</span><span style="color:var(--vt-palette-4)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">──</span><span style="color:var(--vt-palette-4)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">──</span><span style="color:var(--vt-palette-4)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">──</span><span style="color:var(--vt-palette-4)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">────</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1818 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">14</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-0)">Jan</span> <span style="color:var(--vt-palette-0)">Feb</span> <span style="color:var(--vt-palette-0)">Mar</span> <span style="color:var(--vt-palette-0)">Apr</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1919 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">15</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-4)">■</span> <span style="color:var(--vt-palette-0)">Rent</span> <span style="color:var(--vt-palette-5)">■</span> <span style="color:var(--vt-palette-0)">Food</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>2020 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">16</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">└──────────────────────────────────────</span> <span style="color:var(--vt-palette-0)">A1:C5</span> <span style="color:var(--vt-palette-6);font-weight:bold">─◢</span>@@ -5,16 +5,16 @@
55 <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">1</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Month</span><span style="background:var(--vt-palette-6)"> </span> Rent Food <span style="color:var(--vt-palette-6);font-weight:bold">┌─</span> <span style="font-weight:bold">Rent</span> <span style="font-weight:bold">and</span> <span style="font-weight:bold">Food</span> <span style="color:var(--vt-palette-6);font-weight:bold">──────────────────────────────┐</span>66 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">2</span><span style="background:var(--vt-palette-8)"> </span> Jan $1,450 $600 <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>77 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">3</span><span style="background:var(--vt-palette-8)"> </span> Feb $1,450 $640 <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>8-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">4</span><span style="background:var(--vt-palette-8)"> </span> Mar $1,500 $612 <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">$1,500</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-6)">▆▆▆</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">▆▆▆</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>8+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">4</span><span style="background:var(--vt-palette-8)"> </span> Mar $1,500 $612 <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">$1,500</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-6)">▂▂▂</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">▂▂▂</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">▄▄▄</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">▄▄▄</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>99 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">5</span><span style="background:var(--vt-palette-8)"> </span> Apr $1,500 $700 <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1010 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">6</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1111 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">7</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">$1,000</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>12-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">8</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▂▂▂</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>13-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">9</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▅▅▅</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▇▇▇</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▅▅▅</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>12+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">8</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>13+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">9</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▁▁▁</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▃▃▃</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▁▁▁</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▆▆▆</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1414 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">10</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">$500</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈┈┈</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1515 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">11</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1616 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">12</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>17-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">13</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">$0</span> <span style="color:var(--vt-palette-8)">┼────────────────────────────────────</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>17+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">13</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">$0</span> <span style="color:var(--vt-palette-8)">┼──</span><span style="color:var(--vt-palette-6)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">──</span><span style="color:var(--vt-palette-6)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">──</span><span style="color:var(--vt-palette-6)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">──</span><span style="color:var(--vt-palette-6)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">────</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1818 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">14</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">Jan</span> <span style="color:var(--vt-palette-8)">Feb</span> <span style="color:var(--vt-palette-8)">Mar</span> <span style="color:var(--vt-palette-8)">Apr</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1919 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">15</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-6)">■</span> <span style="color:var(--vt-palette-8)">Rent</span> <span style="color:var(--vt-palette-5)">■</span> <span style="color:var(--vt-palette-8)">Food</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>2020 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">16</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">└──────────────────────────────────────</span> <span style="color:var(--vt-palette-8)">A1:C5</span> <span style="color:var(--vt-palette-6);font-weight:bold">─◢</span>@@ -5,16 +5,16 @@
55 <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">1</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Month</span><span style="background:var(--vt-palette-6)"> </span> Rent Food <span style="color:var(--vt-palette-8)">┌─</span> <span style="font-weight:bold">Rent</span> <span style="font-weight:bold">and</span> <span style="font-weight:bold">Food</span> <span style="color:var(--vt-palette-8)">──────────────────────────────┐</span>66 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">2</span><span style="background:var(--vt-palette-7)"> </span> Jan $1,450 $600 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span>77 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">3</span><span style="background:var(--vt-palette-7)"> </span> Feb $1,450 $640 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span>8-<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">4</span><span style="background:var(--vt-palette-7)"> </span> Mar $1,500 $612 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-0)">$1,500</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-4)">▆▆▆</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-4)">▆▆▆</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>8+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">4</span><span style="background:var(--vt-palette-7)"> </span> Mar $1,500 $612 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-0)">$1,500</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-4)">▂▂▂</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-4)">▂▂▂</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-4)">▄▄▄</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-4)">▄▄▄</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>99 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">5</span><span style="background:var(--vt-palette-7)"> </span> Apr $1,500 $700 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-8)">│</span>1010 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">6</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-8)">│</span>1111 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">7</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-0)">$1,000</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>12-<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">8</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">▂▂▂</span> <span style="color:var(--vt-palette-8)">│</span>13-<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">9</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">▅▅▅</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">▇▇▇</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">▅▅▅</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-8)">│</span>12+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">8</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-4)">███</span> <span style="color:var(--vt-palette-8)">│</span>13+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">9</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">▁▁▁</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">▃▃▃</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">▁▁▁</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">▆▆▆</span> <span style="color:var(--vt-palette-8)">│</span>1414 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">10</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-0)">$500</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>1515 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">11</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-8)">│</span>1616 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">12</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-4)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-8)">│</span>17-<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">13</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-0)">$0</span> <span style="color:var(--vt-palette-8)">┼────────────────────────────────────</span> <span style="color:var(--vt-palette-8)">│</span>17+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">13</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-0)">$0</span> <span style="color:var(--vt-palette-8)">┼──</span><span style="color:var(--vt-palette-4)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">──</span><span style="color:var(--vt-palette-4)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">──</span><span style="color:var(--vt-palette-4)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">──</span><span style="color:var(--vt-palette-4)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">────</span> <span style="color:var(--vt-palette-8)">│</span>1818 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">14</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-0)">Jan</span> <span style="color:var(--vt-palette-0)">Feb</span> <span style="color:var(--vt-palette-0)">Mar</span> <span style="color:var(--vt-palette-0)">Apr</span> <span style="color:var(--vt-palette-8)">│</span>1919 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">15</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-4)">■</span> <span style="color:var(--vt-palette-0)">Rent</span> <span style="color:var(--vt-palette-5)">■</span> <span style="color:var(--vt-palette-0)">Food</span> <span style="color:var(--vt-palette-8)">│</span>2020 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">16</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">└──────────────────────────────────────</span> <span style="color:var(--vt-palette-0)">A1:C5</span> <span style="color:var(--vt-palette-8)">─┘</span>@@ -5,15 +5,15 @@
55 <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">1</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Month</span><span style="background:var(--vt-palette-6)"> </span> Rent Food <span style="color:var(--vt-palette-8)">┌─</span> <span style="font-weight:bold">Rent</span> <span style="font-weight:bold">and</span> <span style="font-weight:bold">Food</span> <span style="color:var(--vt-palette-8)">──────────────────────────────┐</span>66 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">2</span><span style="background:var(--vt-palette-7)"> </span> Jan $1,450 $600 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span>77 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">3</span><span style="background:var(--vt-palette-7)"> </span> Feb $1,450 $640 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-0)">$1,600</span> <span style="color:var(--vt-palette-8)">┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>8-<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">4</span><span style="background:var(--vt-palette-7)"> </span> Mar $1,500 $612 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-4)">⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠔⠒⠒⠒⠒⠒⠊⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉</span> <span style="color:var(--vt-palette-8)">│</span>9-<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">5</span><span style="background:var(--vt-palette-7)"> </span> Apr $1,500 $700 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-0)">$1,400</span> <span style="color:var(--vt-palette-8)">┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>8+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">4</span><span style="background:var(--vt-palette-7)"> </span> Mar $1,500 $612 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-4)">⢀⣀⣀⣀⣀⣀⡠⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤</span> <span style="color:var(--vt-palette-8)">│</span>9+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">5</span><span style="background:var(--vt-palette-7)"> </span> Apr $1,500 $700 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-0)">$1,400</span> <span style="color:var(--vt-palette-8)">┤</span><span style="color:var(--vt-palette-4)">⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠁</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>1010 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">6</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span>1111 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">7</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-0)">$1,200</span> <span style="color:var(--vt-palette-8)">┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>1212 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">8</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span>1313 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">9</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-0)">$1,000</span> <span style="color:var(--vt-palette-8)">┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>1414 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">10</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span>15-<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">11</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-0)">$800</span> <span style="color:var(--vt-palette-8)">┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈</span><span style="color:var(--vt-palette-5)">⢀⣀</span> <span style="color:var(--vt-palette-8)">│</span>16-<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">12</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-5)">⣀⣀⣀⠤⠤⠤⠤⠤⠤⠒⠒⠒⠒⠒⠢⠤⠤⠤⠤⠤⢄⣀⣀⣀⡠⠤⠤⠔⠒⠒⠊⠉⠉⠁</span> <span style="color:var(--vt-palette-8)">│</span>15+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">11</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-0)">$800</span> <span style="color:var(--vt-palette-8)">┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>16+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">12</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-5)">⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⠤⠤⠤⠤⠤⠤</span> <span style="color:var(--vt-palette-8)">│</span>1717 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">13</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-0)">$600</span> <span style="color:var(--vt-palette-8)">┼────────────────────────────────────</span> <span style="color:var(--vt-palette-8)">│</span>1818 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">14</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-0)">Jan</span> <span style="color:var(--vt-palette-0)">Feb</span> <span style="color:var(--vt-palette-0)">Mar</span> <span style="color:var(--vt-palette-0)">Apr</span> <span style="color:var(--vt-palette-8)">│</span>1919 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">15</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-4)">■</span> <span style="color:var(--vt-palette-0)">Rent</span> <span style="color:var(--vt-palette-5)">■</span> <span style="color:var(--vt-palette-0)">Food</span> <span style="color:var(--vt-palette-8)">│</span>@@ -5,15 +5,15 @@
55 <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">1</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Month</span><span style="background:var(--vt-palette-6)"> </span> Rent Food <span style="color:var(--vt-palette-8)">┌─</span> <span style="font-weight:bold">Rent</span> <span style="font-weight:bold">and</span> <span style="font-weight:bold">Food</span> <span style="color:var(--vt-palette-8)">──────────────────────────────┐</span>66 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">2</span><span style="background:var(--vt-palette-8)"> </span> Jan $1,450 $600 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span>77 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">3</span><span style="background:var(--vt-palette-8)"> </span> Feb $1,450 $640 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$1,600</span> <span style="color:var(--vt-palette-8)">┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>8-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">4</span><span style="background:var(--vt-palette-8)"> </span> Mar $1,500 $612 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-6)">⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠔⠒⠒⠒⠒⠒⠊⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉</span> <span style="color:var(--vt-palette-8)">│</span>9-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">5</span><span style="background:var(--vt-palette-8)"> </span> Apr $1,500 $700 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$1,400</span> <span style="color:var(--vt-palette-8)">┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>8+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">4</span><span style="background:var(--vt-palette-8)"> </span> Mar $1,500 $612 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">⢀⣀⣀⣀⣀⣀⡠⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤</span> <span style="color:var(--vt-palette-8)">│</span>9+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">5</span><span style="background:var(--vt-palette-8)"> </span> Apr $1,500 $700 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$1,400</span> <span style="color:var(--vt-palette-8)">┤</span><span style="color:var(--vt-palette-6)">⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠁</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>1010 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">6</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span>1111 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">7</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$1,200</span> <span style="color:var(--vt-palette-8)">┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>1212 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">8</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span>1313 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">9</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$1,000</span> <span style="color:var(--vt-palette-8)">┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>1414 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">10</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span>15-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">11</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$800</span> <span style="color:var(--vt-palette-8)">┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈</span><span style="color:var(--vt-palette-5)">⢀⣀</span> <span style="color:var(--vt-palette-8)">│</span>16-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">12</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-5)">⣀⣀⣀⠤⠤⠤⠤⠤⠤⠒⠒⠒⠒⠒⠢⠤⠤⠤⠤⠤⢄⣀⣀⣀⡠⠤⠤⠔⠒⠒⠊⠉⠉⠁</span> <span style="color:var(--vt-palette-8)">│</span>15+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">11</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$800</span> <span style="color:var(--vt-palette-8)">┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>16+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">12</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-5)">⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⠤⠤⠤⠤⠤⠤</span> <span style="color:var(--vt-palette-8)">│</span>1717 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">13</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$600</span> <span style="color:var(--vt-palette-8)">┼────────────────────────────────────</span> <span style="color:var(--vt-palette-8)">│</span>1818 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">14</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">Jan</span> <span style="color:var(--vt-palette-8)">Feb</span> <span style="color:var(--vt-palette-8)">Mar</span> <span style="color:var(--vt-palette-8)">Apr</span> <span style="color:var(--vt-palette-8)">│</span>1919 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">15</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">■</span> <span style="color:var(--vt-palette-8)">Rent</span> <span style="color:var(--vt-palette-5)">■</span> <span style="color:var(--vt-palette-8)">Food</span> <span style="color:var(--vt-palette-8)">│</span>@@ -6,10 +6,10 @@
66 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">7</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-6);font-weight:bold">┌─</span> <span style="font-weight:bold">Rent</span> <span style="font-weight:bold">and</span> <span style="font-weight:bold">Food</span> <span style="color:var(--vt-palette-6);font-weight:bold">──────────────────────────────┐</span>77 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">8</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>88 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">9</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">$2,000</span> <span style="color:var(--vt-palette-8)">┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>9-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">10</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">▇▇▇</span> <span style="color:var(--vt-palette-6)">▇▇▇</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>10-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">11</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">$1,000</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▂▂▂</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▂▂▂</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▂▂▂</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▃▃▃</span><span style="color:var(--vt-palette-8)">┈┈┈</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>11-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">12</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>12-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">13</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">$0</span> <span style="color:var(--vt-palette-8)">┼────────────────────────────────────</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>9+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">10</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">▃▃▃</span> <span style="color:var(--vt-palette-6)">▃▃▃</span> <span style="color:var(--vt-palette-6)">▄▄▄</span> <span style="color:var(--vt-palette-6)">▄▄▄</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>10+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">11</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">$1,000</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>11+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">12</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▆▆▆</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▆▆▆</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▆▆▆</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▇▇▇</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>12+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">13</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">$0</span> <span style="color:var(--vt-palette-8)">┼──</span><span style="color:var(--vt-palette-6)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">──</span><span style="color:var(--vt-palette-6)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">──</span><span style="color:var(--vt-palette-6)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">──</span><span style="color:var(--vt-palette-6)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">────</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1313 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">14</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">Jan</span> <span style="color:var(--vt-palette-8)">Feb</span> <span style="color:var(--vt-palette-8)">Mar</span> <span style="color:var(--vt-palette-8)">Apr</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1414 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">15</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-6)">■</span> <span style="color:var(--vt-palette-8)">Rent</span> <span style="color:var(--vt-palette-5)">■</span> <span style="color:var(--vt-palette-8)">Food</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1515 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">16</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-6);font-weight:bold">└──────────────────────────────────────</span> <span style="color:var(--vt-palette-8)">A1:C5</span> <span style="color:var(--vt-palette-6);font-weight:bold">─◢</span></pre>\ No newline at end of file@@ -5,16 +5,16 @@
55 <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">1</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Month</span><span style="background:var(--vt-palette-6)"> </span> Rent Food <span style="color:var(--vt-palette-6);font-weight:bold">┌─</span> <span style="font-weight:bold">Rent</span> <span style="font-weight:bold">and</span> <span style="font-weight:bold">Food</span> <span style="color:var(--vt-palette-6);font-weight:bold">──────────────────────────────┐</span>66 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">2</span><span style="background:var(--vt-palette-8)"> </span> Jan $1,450 $600 <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>77 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">3</span><span style="background:var(--vt-palette-8)"> </span> Feb $1,450 $640 <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>8-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">4</span><span style="background:var(--vt-palette-8)"> </span> Mar $1,500 $612 <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">$1,500</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-6)">▆▆▆</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">▆▆▆</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>8+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">4</span><span style="background:var(--vt-palette-8)"> </span> Mar $1,500 $612 <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">$1,500</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-6)">▂▂▂</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">▂▂▂</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">▄▄▄</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">▄▄▄</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>99 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">5</span><span style="background:var(--vt-palette-8)"> </span> Apr $1,500 $700 <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1010 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">6</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1111 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">7</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">$1,000</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>12-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">8</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▂▂▂</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>13-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">9</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▅▅▅</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▇▇▇</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▅▅▅</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>12+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">8</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>13+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">9</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▁▁▁</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▃▃▃</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▁▁▁</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▆▆▆</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1414 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">10</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">$500</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈┈┈</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1515 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">11</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1616 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">12</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>17-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">13</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">$0</span> <span style="color:var(--vt-palette-8)">┼────────────────────────────────────</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>17+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">13</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">$0</span> <span style="color:var(--vt-palette-8)">┼──</span><span style="color:var(--vt-palette-6)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">──</span><span style="color:var(--vt-palette-6)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">──</span><span style="color:var(--vt-palette-6)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">──</span><span style="color:var(--vt-palette-6)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">────</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1818 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">14</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-8)">Jan</span> <span style="color:var(--vt-palette-8)">Feb</span> <span style="color:var(--vt-palette-8)">Mar</span> <span style="color:var(--vt-palette-8)">Apr</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>1919 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">15</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span> <span style="color:var(--vt-palette-6)">■</span> <span style="color:var(--vt-palette-8)">Rent</span> <span style="color:var(--vt-palette-5)">■</span> <span style="color:var(--vt-palette-8)">Food</span> <span style="color:var(--vt-palette-6);font-weight:bold">│</span>2020 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">16</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-6);font-weight:bold">└──────────────────────────────────────</span> <span style="color:var(--vt-palette-8)">A1:C5</span> <span style="color:var(--vt-palette-6);font-weight:bold">─◢</span>@@ -5,16 +5,16 @@
55 <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">1</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Month</span><span style="background:var(--vt-palette-6)"> </span> Rent Food <span style="color:var(--vt-palette-8)">┌─</span> <span style="font-weight:bold">Rent</span> <span style="font-weight:bold">and</span> <span style="font-weight:bold">Food</span> <span style="color:var(--vt-palette-8)">──────────────────────────────┐</span>66 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">2</span><span style="background:var(--vt-palette-7)"> </span> Jan $1,450 $600 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span>77 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">3</span><span style="background:var(--vt-palette-7)"> </span> Feb $1,450 $640 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-0)">$2,500</span> <span style="color:var(--vt-palette-8)">┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>8-<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">4</span><span style="background:var(--vt-palette-7)"> </span> Mar $1,500 $612 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-5)">▂▂▂▂▂▂</span> <span style="color:var(--vt-palette-5)">▃▃▃▃▃▃</span> <span style="color:var(--vt-palette-5)">▄▄▄▄▄▄</span> <span style="color:var(--vt-palette-5)">▆▆▆▆▆▆</span> <span style="color:var(--vt-palette-8)">│</span>9-<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">5</span><span style="background:var(--vt-palette-7)"> </span> Apr $1,500 $700 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-0)">$2,000</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-5)">██████</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-5)">██████</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-5)">██████</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-5)">██████</span><span style="color:var(--vt-palette-8)">┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>8+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">4</span><span style="background:var(--vt-palette-7)"> </span> Mar $1,500 $612 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-5)">▂▂▂▂▂▂</span> <span style="color:var(--vt-palette-8)">│</span>9+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">5</span><span style="background:var(--vt-palette-7)"> </span> Apr $1,500 $700 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-0)">$2,000</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-5)">▆▆▆▆▆▆</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-5)">▇▇▇▇▇▇</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-5)">██████</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-5)">██████</span><span style="color:var(--vt-palette-8)">┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>1010 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">6</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-5)">██████</span> <span style="color:var(--vt-palette-5)">██████</span> <span style="color:var(--vt-palette-5)">██████</span> <span style="color:var(--vt-palette-5)">██████</span> <span style="color:var(--vt-palette-8)">│</span>11-<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">7</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-0)">$1,500</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-4);background:var(--vt-palette-5)">▆▆▆▆▆▆</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-4);background:var(--vt-palette-5)">▆▆▆▆▆▆</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-4)">██████</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-4)">██████</span><span style="color:var(--vt-palette-8)">┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>11+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">7</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-0)">$1,500</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-4);background:var(--vt-palette-5)">▂▂▂▂▂▂</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-4);background:var(--vt-palette-5)">▂▂▂▂▂▂</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-4);background:var(--vt-palette-5)">▄▄▄▄▄▄</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-4);background:var(--vt-palette-5)">▄▄▄▄▄▄</span><span style="color:var(--vt-palette-8)">┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>1212 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">8</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-4)">██████</span> <span style="color:var(--vt-palette-4)">██████</span> <span style="color:var(--vt-palette-4)">██████</span> <span style="color:var(--vt-palette-4)">██████</span> <span style="color:var(--vt-palette-8)">│</span>1313 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">9</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-0)">$1,000</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-4)">██████</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-4)">██████</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-4)">██████</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-4)">██████</span><span style="color:var(--vt-palette-8)">┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>1414 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">10</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-4)">██████</span> <span style="color:var(--vt-palette-4)">██████</span> <span style="color:var(--vt-palette-4)">██████</span> <span style="color:var(--vt-palette-4)">██████</span> <span style="color:var(--vt-palette-8)">│</span>1515 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">11</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-0)">$500</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-4)">██████</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-4)">██████</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-4)">██████</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-4)">██████</span><span style="color:var(--vt-palette-8)">┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>1616 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">12</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-4)">██████</span> <span style="color:var(--vt-palette-4)">██████</span> <span style="color:var(--vt-palette-4)">██████</span> <span style="color:var(--vt-palette-4)">██████</span> <span style="color:var(--vt-palette-8)">│</span>17-<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">13</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-0)">$0</span> <span style="color:var(--vt-palette-8)">┼────────────────────────────────────</span> <span style="color:var(--vt-palette-8)">│</span>17+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">13</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-0)">$0</span> <span style="color:var(--vt-palette-8)">┼──</span><span style="color:var(--vt-palette-4)">▀▀▀▀▀▀</span><span style="color:var(--vt-palette-8)">──</span><span style="color:var(--vt-palette-4)">▀▀▀▀▀▀</span><span style="color:var(--vt-palette-8)">──</span><span style="color:var(--vt-palette-4)">▀▀▀▀▀▀</span><span style="color:var(--vt-palette-8)">──</span><span style="color:var(--vt-palette-4)">▀▀▀▀▀▀</span><span style="color:var(--vt-palette-8)">────</span> <span style="color:var(--vt-palette-8)">│</span>1818 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">14</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-0)">Jan</span> <span style="color:var(--vt-palette-0)">Feb</span> <span style="color:var(--vt-palette-0)">Mar</span> <span style="color:var(--vt-palette-0)">Apr</span> <span style="color:var(--vt-palette-8)">│</span>1919 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">15</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-4)">■</span> <span style="color:var(--vt-palette-0)">Rent</span> <span style="color:var(--vt-palette-5)">■</span> <span style="color:var(--vt-palette-0)">Food</span> <span style="color:var(--vt-palette-8)">│</span>2020 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">16</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">└──────────────────────────────────────</span> <span style="color:var(--vt-palette-0)">A1:C5</span> <span style="color:var(--vt-palette-8)">─┘</span>@@ -5,16 +5,16 @@
55 <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">1</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Month</span><span style="background:var(--vt-palette-6)"> </span> Rent Food <span style="color:var(--vt-palette-8)">┌─</span> <span style="font-weight:bold">Rent</span> <span style="font-weight:bold">and</span> <span style="font-weight:bold">Food</span> <span style="color:var(--vt-palette-8)">──────────────────────────────┐</span>66 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">2</span><span style="background:var(--vt-palette-8)"> </span> Jan $1,450 $600 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span>77 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">3</span><span style="background:var(--vt-palette-8)"> </span> Feb $1,450 $640 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$2,500</span> <span style="color:var(--vt-palette-8)">┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>8-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">4</span><span style="background:var(--vt-palette-8)"> </span> Mar $1,500 $612 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-5)">▂▂▂▂▂▂</span> <span style="color:var(--vt-palette-5)">▃▃▃▃▃▃</span> <span style="color:var(--vt-palette-5)">▄▄▄▄▄▄</span> <span style="color:var(--vt-palette-5)">▆▆▆▆▆▆</span> <span style="color:var(--vt-palette-8)">│</span>9-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">5</span><span style="background:var(--vt-palette-8)"> </span> Apr $1,500 $700 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$2,000</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-5)">██████</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-5)">██████</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-5)">██████</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-5)">██████</span><span style="color:var(--vt-palette-8)">┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>8+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">4</span><span style="background:var(--vt-palette-8)"> </span> Mar $1,500 $612 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-5)">▂▂▂▂▂▂</span> <span style="color:var(--vt-palette-8)">│</span>9+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">5</span><span style="background:var(--vt-palette-8)"> </span> Apr $1,500 $700 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$2,000</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-5)">▆▆▆▆▆▆</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-5)">▇▇▇▇▇▇</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-5)">██████</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-5)">██████</span><span style="color:var(--vt-palette-8)">┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>1010 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">6</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-5)">██████</span> <span style="color:var(--vt-palette-5)">██████</span> <span style="color:var(--vt-palette-5)">██████</span> <span style="color:var(--vt-palette-5)">██████</span> <span style="color:var(--vt-palette-8)">│</span>11-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">7</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$1,500</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-6);background:var(--vt-palette-5)">▆▆▆▆▆▆</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-6);background:var(--vt-palette-5)">▆▆▆▆▆▆</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-6)">██████</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-6)">██████</span><span style="color:var(--vt-palette-8)">┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>11+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">7</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$1,500</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-6);background:var(--vt-palette-5)">▂▂▂▂▂▂</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-6);background:var(--vt-palette-5)">▂▂▂▂▂▂</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-6);background:var(--vt-palette-5)">▄▄▄▄▄▄</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-6);background:var(--vt-palette-5)">▄▄▄▄▄▄</span><span style="color:var(--vt-palette-8)">┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>1212 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">8</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">██████</span> <span style="color:var(--vt-palette-6)">██████</span> <span style="color:var(--vt-palette-6)">██████</span> <span style="color:var(--vt-palette-6)">██████</span> <span style="color:var(--vt-palette-8)">│</span>1313 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">9</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$1,000</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-6)">██████</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-6)">██████</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-6)">██████</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-6)">██████</span><span style="color:var(--vt-palette-8)">┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>1414 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">10</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">██████</span> <span style="color:var(--vt-palette-6)">██████</span> <span style="color:var(--vt-palette-6)">██████</span> <span style="color:var(--vt-palette-6)">██████</span> <span style="color:var(--vt-palette-8)">│</span>1515 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">11</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$500</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-6)">██████</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-6)">██████</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-6)">██████</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-6)">██████</span><span style="color:var(--vt-palette-8)">┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>1616 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">12</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">██████</span> <span style="color:var(--vt-palette-6)">██████</span> <span style="color:var(--vt-palette-6)">██████</span> <span style="color:var(--vt-palette-6)">██████</span> <span style="color:var(--vt-palette-8)">│</span>17-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">13</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$0</span> <span style="color:var(--vt-palette-8)">┼────────────────────────────────────</span> <span style="color:var(--vt-palette-8)">│</span>17+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">13</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$0</span> <span style="color:var(--vt-palette-8)">┼──</span><span style="color:var(--vt-palette-6)">▀▀▀▀▀▀</span><span style="color:var(--vt-palette-8)">──</span><span style="color:var(--vt-palette-6)">▀▀▀▀▀▀</span><span style="color:var(--vt-palette-8)">──</span><span style="color:var(--vt-palette-6)">▀▀▀▀▀▀</span><span style="color:var(--vt-palette-8)">──</span><span style="color:var(--vt-palette-6)">▀▀▀▀▀▀</span><span style="color:var(--vt-palette-8)">────</span> <span style="color:var(--vt-palette-8)">│</span>1818 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">14</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">Jan</span> <span style="color:var(--vt-palette-8)">Feb</span> <span style="color:var(--vt-palette-8)">Mar</span> <span style="color:var(--vt-palette-8)">Apr</span> <span style="color:var(--vt-palette-8)">│</span>1919 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">15</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">■</span> <span style="color:var(--vt-palette-8)">Rent</span> <span style="color:var(--vt-palette-5)">■</span> <span style="color:var(--vt-palette-8)">Food</span> <span style="color:var(--vt-palette-8)">│</span>2020 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">16</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">└──────────────────────────────────────</span> <span style="color:var(--vt-palette-8)">A1:C5</span> <span style="color:var(--vt-palette-8)">─┘</span>@@ -5,16 +5,16 @@
55 <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">1</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Month</span><span style="background:var(--vt-palette-6)"> </span> Rent Food <span style="color:var(--vt-palette-8)">┌─</span> <span style="font-weight:bold">Rent</span> <span style="font-weight:bold">and</span> <span style="font-weight:bold">Food</span> <span style="color:var(--vt-palette-8)">──────────────────────────────┐</span>66 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">2</span><span style="background:var(--vt-palette-8)"> </span> Jan $1,450 $600 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span>77 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">3</span><span style="background:var(--vt-palette-8)"> </span> Feb $1,450 $640 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span>8-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">4</span><span style="background:var(--vt-palette-8)"> </span> Mar $1,500 $612 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$1,500</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-6)">▆▆▆</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">▆▆▆</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>8+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">4</span><span style="background:var(--vt-palette-8)"> </span> Mar $1,500 $612 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$1,500</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-6)">▂▂▂</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">▂▂▂</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">▄▄▄</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">▄▄▄</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>99 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">5</span><span style="background:var(--vt-palette-8)"> </span> Apr $1,500 $700 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-8)">│</span>1010 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">6</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-8)">│</span>1111 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">7</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$1,000</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>12-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">8</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▂▂▂</span> <span style="color:var(--vt-palette-8)">│</span>13-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">9</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▅▅▅</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▇▇▇</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▅▅▅</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-8)">│</span>12+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">8</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-8)">│</span>13+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">9</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▁▁▁</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▃▃▃</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▁▁▁</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▆▆▆</span> <span style="color:var(--vt-palette-8)">│</span>1414 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">10</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$500</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>1515 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">11</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-8)">│</span>1616 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">12</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-8)">│</span>17-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">13</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$0</span> <span style="color:var(--vt-palette-8)">┼────────────────────────────────────</span> <span style="color:var(--vt-palette-8)">│</span>17+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">13</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$0</span> <span style="color:var(--vt-palette-8)">┼──</span><span style="color:var(--vt-palette-6)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">──</span><span style="color:var(--vt-palette-6)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">──</span><span style="color:var(--vt-palette-6)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">──</span><span style="color:var(--vt-palette-6)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">────</span> <span style="color:var(--vt-palette-8)">│</span>1818 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">14</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">Jan</span> <span style="color:var(--vt-palette-8)">Feb</span> <span style="color:var(--vt-palette-8)">Mar</span> <span style="color:var(--vt-palette-8)">Apr</span> <span style="color:var(--vt-palette-8)">│</span>1919 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">15</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">■</span> <span style="color:var(--vt-palette-8)">Rent</span> <span style="color:var(--vt-palette-5)">■</span> <span style="color:var(--vt-palette-8)">Food</span> <span style="color:var(--vt-palette-8)">│</span>2020 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">16</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">└──────────────────────────────────────</span> <span style="color:var(--vt-palette-8)">A1:C5</span> <span style="color:var(--vt-palette-8)">─┘</span>@@ -5,16 +5,16 @@
55 <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">1</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Month</span><span style="background:var(--vt-palette-6)"> </span> Rent Food <span style="color:var(--vt-palette-8)">┌─</span> <span style="font-weight:bold">Rent</span> <span style="font-weight:bold">and</span> <span style="font-weight:bold">Food</span> <span style="color:var(--vt-palette-8)">──────────────────────────────┐</span>66 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">2</span><span style="background:var(--vt-palette-8)"> </span> Jan $1,450 $600 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span>77 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">3</span><span style="background:var(--vt-palette-8)"> </span> Feb $1,450 $640 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span>8-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">4</span><span style="background:var(--vt-palette-8)"> </span> Mar $1,500 $612 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$1,500</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-6)">▆▆▆</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">▆▆▆</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>8+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">4</span><span style="background:var(--vt-palette-8)"> </span> Mar $1,500 $612 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$1,500</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-6)">▂▂▂</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">▂▂▂</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">▄▄▄</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">▄▄▄</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>99 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">5</span><span style="background:var(--vt-palette-8)"> </span> Apr $1,500 $700 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-8)">│</span>1010 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">6</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-8)">│</span>1111 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">7</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$1,000</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-8)">┈┈┈┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>12-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">8</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▂▂▂</span> <span style="color:var(--vt-palette-8)">│</span>13-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">9</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▅▅▅</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▇▇▇</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▅▅▅</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-8)">│</span>12+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">8</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-6)">███</span> <span style="color:var(--vt-palette-8)">│</span>13+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">9</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▁▁▁</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▃▃▃</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▁▁▁</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">▆▆▆</span> <span style="color:var(--vt-palette-8)">│</span>1414 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">10</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$500</span> <span style="color:var(--vt-palette-8)">┤┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈┈</span><span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span><span style="color:var(--vt-palette-8)">┈┈┈</span> <span style="color:var(--vt-palette-8)">│</span>1515 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">11</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-8)">│</span>1616 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">12</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-6)">███</span><span style="color:var(--vt-palette-5)">███</span> <span style="color:var(--vt-palette-8)">│</span>17-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">13</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$0</span> <span style="color:var(--vt-palette-8)">┼────────────────────────────────────</span> <span style="color:var(--vt-palette-8)">│</span>17+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">13</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">$0</span> <span style="color:var(--vt-palette-8)">┼──</span><span style="color:var(--vt-palette-6)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">──</span><span style="color:var(--vt-palette-6)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">──</span><span style="color:var(--vt-palette-6)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">──</span><span style="color:var(--vt-palette-6)">▀▀▀</span><span style="color:var(--vt-palette-5)">▀▀▀</span><span style="color:var(--vt-palette-8)">────</span> <span style="color:var(--vt-palette-8)">│</span>1818 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">14</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">Jan</span> <span style="color:var(--vt-palette-8)">Feb</span> <span style="color:var(--vt-palette-8)">Mar</span> <span style="color:var(--vt-palette-8)">Apr</span> <span style="color:var(--vt-palette-8)">│</span>1919 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">15</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-6)">■</span> <span style="color:var(--vt-palette-8)">Rent</span> <span style="color:var(--vt-palette-5)">■</span> <span style="color:var(--vt-palette-8)">Food</span> <span style="color:var(--vt-palette-8)">│</span>2020 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">16</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">└──────────────────────────────────────</span> <span style="color:var(--vt-palette-8)">A1:C5</span> <span style="color:var(--vt-palette-8)">─┘</span>@@ -27,4 +27,4 @@
2727 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">23</span><span style="background:var(--vt-palette-8)"> </span>2828 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">24</span><span style="background:var(--vt-palette-8)"> </span>2929 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">25</span><span style="background:var(--vt-palette-8)"> </span>30-<span style="color:var(--vt-palette-9);font-weight:bold">Not</span> <span style="color:var(--vt-palette-9);font-weight:bold">a</span> <span style="color:var(--vt-palette-9);font-weight:bold">cell,</span> <span style="color:var(--vt-palette-9);font-weight:bold">range</span> <span style="color:var(--vt-palette-9);font-weight:bold">or</span> <span style="color:var(--vt-palette-9);font-weight:bold">named</span> <span style="color:var(--vt-palette-9);font-weight:bold">range:</span> <span style="color:var(--vt-palette-9);font-weight:bold">nope</span> <span style="color:var(--vt-palette-8)">press</span> <span style="color:var(--vt-palette-8)">any</span> <span style="color:var(--vt-palette-8)">key</span></pre>\ No newline at end of file30+<span style="color:var(--vt-palette-9);font-weight:bold">Not</span> <span style="color:var(--vt-palette-9);font-weight:bold">a</span> <span style="color:var(--vt-palette-9);font-weight:bold">cell,</span> <span style="color:var(--vt-palette-9);font-weight:bold">range,</span> <span style="color:var(--vt-palette-9);font-weight:bold">named</span> <span style="color:var(--vt-palette-9);font-weight:bold">range</span> <span style="color:var(--vt-palette-9);font-weight:bold">or</span> <span style="color:var(--vt-palette-9);font-weight:bold">region:</span> <span style="color:var(--vt-palette-9);font-weight:bold">nope</span> <span style="color:var(--vt-palette-8)">press</span> <span style="color:var(--vt-palette-8)">any</span> <span style="color:var(--vt-palette-8)">key</span></pre>\ No newline at end of file@@ -1,11 +1,11 @@
11 <pre class="screen"> <span style="text-decoration:underline">F</span>ile <span style="text-decoration:underline">E</span>dit <span style="text-decoration:underline">V</span>iew <span style="text-decoration:underline">I</span>nsert F<span style="text-decoration:underline">o</span>rmat <span style="text-decoration:underline">D</span>ata <span style="text-decoration:underline">H</span>elp <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">MENU</span><span style="background:var(--vt-palette-6)"> </span>22 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">A1:B3</span><span style="background:var(--vt-palette-7)"> </span> name33 Send A1:B3 as NUON? <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Enter</span><span style="background:var(--vt-palette-7)"> </span> Send selection <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">S</span><span style="background:var(--vt-palette-7)"> </span> Send sheet <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">D</span><span style="background:var(--vt-palette-7)"> </span> Don't send <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Esc</span><span style="background:var(--vt-palette-7)"> </span> Cancel4-<span style="background:var(--vt-palette-7)"> </span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">A</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">B</span><span style="background:var(--vt-palette-4)"> </span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">C</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">D</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">E</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">F</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">G</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">H</span><span style="background:var(--vt-palette-7)"> </span>5-<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">1</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">name</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">size</span><span style="background:var(--vt-palette-4)"> </span> modified6-<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">2</span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">CLAUDE.md</span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">1.6</span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">kB</span><span style="background:var(--vt-palette-4)"> </span> 9/27/2026 11:27:317-<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">3</span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">go.mod</span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">812</span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">B</span><span style="background:var(--vt-palette-4)"> </span> 9/20/2026 8:00:008-<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">4</span><span style="background:var(--vt-palette-7)"> </span> e2e 4.2 kB 9/28/2026 17:45:104+<span style="background:var(--vt-palette-7)"> </span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">A</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">B</span><span style="background:var(--vt-palette-4)"> </span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">C</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">D</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">E</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">F</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">G</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">H</span><span style="background:var(--vt-palette-7)"> </span>5+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">1</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">name</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">size</span><span style="background:var(--vt-palette-4)"> </span> modified6+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">2</span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">CLAUDE.md</span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">1.6</span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">kB</span><span style="background:var(--vt-palette-4)"> </span> 9/27/2026 11:27:317+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">3</span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">go.mod</span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">812</span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">B</span><span style="background:var(--vt-palette-4)"> </span> 9/20/2026 8:00:008+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">4</span><span style="background:var(--vt-palette-7)"> </span> e2e 4.2 kB 9/28/2026 17:45:1099 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">5</span><span style="background:var(--vt-palette-7)"> </span>1010 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">6</span><span style="background:var(--vt-palette-7)"> </span>1111 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">7</span><span style="background:var(--vt-palette-7)"> </span>@@ -1,11 +1,11 @@
11 <pre class="screen"> <span style="text-decoration:underline">F</span>ile <span style="text-decoration:underline">E</span>dit <span style="text-decoration:underline">V</span>iew <span style="text-decoration:underline">I</span>nsert F<span style="text-decoration:underline">o</span>rmat <span style="text-decoration:underline">D</span>ata <span style="text-decoration:underline">H</span>elp <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">MENU</span><span style="background:var(--vt-palette-6)"> </span>22 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">A1:B3</span><span style="background:var(--vt-palette-8)"> </span> name33 Send A1:B3 as NUON? <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Enter</span><span style="background:var(--vt-palette-8)"> </span> Send selection <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">S</span><span style="background:var(--vt-palette-8)"> </span> Send sheet <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">D</span><span style="background:var(--vt-palette-8)"> </span> Don't send <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Esc</span><span style="background:var(--vt-palette-8)"> </span> Cancel4-<span style="background:var(--vt-palette-8)"> </span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">A</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">B</span><span style="background:var(--vt-palette-4)"> </span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">C</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">D</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">E</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">F</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">G</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">H</span><span style="background:var(--vt-palette-8)"> </span>5-<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">1</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">name</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">size</span><span style="background:var(--vt-palette-4)"> </span> modified6-<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">2</span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">CLAUDE.md</span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">1.6</span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">kB</span><span style="background:var(--vt-palette-4)"> </span> 9/27/2026 11:27:317-<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">3</span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">go.mod</span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">812</span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">B</span><span style="background:var(--vt-palette-4)"> </span> 9/20/2026 8:00:008-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">4</span><span style="background:var(--vt-palette-8)"> </span> e2e 4.2 kB 9/28/2026 17:45:104+<span style="background:var(--vt-palette-8)"> </span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">A</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">B</span><span style="background:var(--vt-palette-4)"> </span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">C</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">D</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">E</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">F</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">G</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">H</span><span style="background:var(--vt-palette-8)"> </span>5+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">1</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">name</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">size</span><span style="background:var(--vt-palette-4)"> </span> modified6+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">2</span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">CLAUDE.md</span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">1.6</span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">kB</span><span style="background:var(--vt-palette-4)"> </span> 9/27/2026 11:27:317+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">3</span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">go.mod</span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">812</span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">B</span><span style="background:var(--vt-palette-4)"> </span> 9/20/2026 8:00:008+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">4</span><span style="background:var(--vt-palette-8)"> </span> e2e 4.2 kB 9/28/2026 17:45:1099 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">5</span><span style="background:var(--vt-palette-8)"> </span>1010 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">6</span><span style="background:var(--vt-palette-8)"> </span>1111 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">7</span><span style="background:var(--vt-palette-8)"> </span>@@ -1,11 +1,11 @@
11 <pre class="screen"> <span style="text-decoration:underline">F</span>ile <span style="text-decoration:underline">E</span>dit <span style="text-decoration:underline">V</span>iew <span style="text-decoration:underline">I</span>nsert F<span style="text-decoration:underline">o</span>rmat <span style="text-decoration:underline">D</span>ata <span style="text-decoration:underline">H</span>elp <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">READY</span><span style="background:var(--vt-palette-6)"> </span>22 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">A1</span><span style="background:var(--vt-palette-7)"> </span> name33 Read 4 rows of NUON from standard input4-<span style="background:var(--vt-palette-7)"> </span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">A</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">B</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">C</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">D</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">E</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">F</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">G</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">H</span><span style="background:var(--vt-palette-7)"> </span>5-<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">1</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">name</span><span style="background:var(--vt-palette-6)"> </span> size modified6-<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">2</span><span style="background:var(--vt-palette-7)"> </span> CLAUDE.md 1.6 kB 9/27/2026 11:27:317-<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">3</span><span style="background:var(--vt-palette-7)"> </span> go.mod 812 B 9/20/2026 8:00:008-<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">4</span><span style="background:var(--vt-palette-7)"> </span> e2e 4.2 kB 9/28/2026 17:45:104+<span style="background:var(--vt-palette-7)"> </span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">A</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">B</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">C</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">D</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">E</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">F</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">G</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">H</span><span style="background:var(--vt-palette-7)"> </span>5+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">1</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">name</span><span style="background:var(--vt-palette-6)"> </span> size modified6+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">2</span><span style="background:var(--vt-palette-7)"> </span> CLAUDE.md 1.6 kB 9/27/2026 11:27:317+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">3</span><span style="background:var(--vt-palette-7)"> </span> go.mod 812 B 9/20/2026 8:00:008+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">4</span><span style="background:var(--vt-palette-7)"> </span> e2e 4.2 kB 9/28/2026 17:45:1099 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">5</span><span style="background:var(--vt-palette-7)"> </span>1010 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">6</span><span style="background:var(--vt-palette-7)"> </span>1111 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">7</span><span style="background:var(--vt-palette-7)"> </span>@@ -1,11 +1,11 @@
11 <pre class="screen"> <span style="text-decoration:underline">F</span>ile <span style="text-decoration:underline">E</span>dit <span style="text-decoration:underline">V</span>iew <span style="text-decoration:underline">I</span>nsert F<span style="text-decoration:underline">o</span>rmat <span style="text-decoration:underline">D</span>ata <span style="text-decoration:underline">H</span>elp <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">READY</span><span style="background:var(--vt-palette-6)"> </span>22 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">A1</span><span style="background:var(--vt-palette-8)"> </span> name33 Read 4 rows of NUON from standard input4-<span style="background:var(--vt-palette-8)"> </span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">A</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">B</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">C</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">D</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">E</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">F</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">G</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">H</span><span style="background:var(--vt-palette-8)"> </span>5-<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">1</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">name</span><span style="background:var(--vt-palette-6)"> </span> size modified6-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">2</span><span style="background:var(--vt-palette-8)"> </span> CLAUDE.md 1.6 kB 9/27/2026 11:27:317-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">3</span><span style="background:var(--vt-palette-8)"> </span> go.mod 812 B 9/20/2026 8:00:008-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">4</span><span style="background:var(--vt-palette-8)"> </span> e2e 4.2 kB 9/28/2026 17:45:104+<span style="background:var(--vt-palette-8)"> </span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">A</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">B</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">C</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">D</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">E</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">F</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">G</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">H</span><span style="background:var(--vt-palette-8)"> </span>5+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">1</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">name</span><span style="background:var(--vt-palette-6)"> </span> size modified6+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">2</span><span style="background:var(--vt-palette-8)"> </span> CLAUDE.md 1.6 kB 9/27/2026 11:27:317+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">3</span><span style="background:var(--vt-palette-8)"> </span> go.mod 812 B 9/20/2026 8:00:008+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">4</span><span style="background:var(--vt-palette-8)"> </span> e2e 4.2 kB 9/28/2026 17:45:1099 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">5</span><span style="background:var(--vt-palette-8)"> </span>1010 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">6</span><span style="background:var(--vt-palette-8)"> </span>1111 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">7</span><span style="background:var(--vt-palette-8)"> </span>@@ -313,3 +313,36 @@ func TestPlaceholderAndDelete(t *testing.T) {
313313 t.Errorf("query %q", got)314314 }315315 }316+317+// Text bars start on the axis line, in the middle of the axis row or318+// column, and a value on a tick ends on the tick's line: columns up319+// and down from zero, bars to the right.320+func TestBarsMeetTheAxis(t *testing.T) {321+ ticks := sheet.ChartData{322+ Categories: []string{"a", "b"},323+ Series: []sheet.ChartSeries{{Name: "v", Values: []float64{100, -100}}},324+ }325+ col := Draw(sheet.ChartColumn, ticks, 30, 10, Options{})326+ p, _ := planFor(sheet.ChartColumn, ticks, 30, 10, Options{})327+ cp := p.(*columnPlan)328+ up, _ := cp.bar(0, 0)329+ down, _ := cp.bar(1, 0)330+ zero := cp.axisRow - int(cp.sc.pos(0))/cp.sc.k*cp.sc.k // the zero tick's row331+ top := cp.axisRow - cp.sc.cells() // the 100 tick's row332+ for _, c := range []struct {333+ x, y int334+ want string335+ }{336+ {up, zero, "▀"}, {up, zero - 1, "█"}, {up, top, "▄"},337+ {down, zero, "▄"}, {down, cp.axisRow, "▀"},338+ } {339+ if got := col.At(c.x, c.y).Text; got != c.want {340+ t.Errorf("column cell %d,%d = %q, want %q\n%s", c.x, c.y, got, c.want, col)341+ }342+ }343+ bar := Draw(sheet.ChartBar, single, 40, 10, Options{})344+ bp, _ := planFor(sheet.ChartBar, single, 40, 10, Options{})345+ if got := bar.At(bp.(*barPlan).axisX, 0).Text; got != "▐" {346+ t.Errorf("bar at the axis = %q, want ▐\n%s", got, bar)347+ }348+}@@ -16,7 +16,7 @@ import (
1616 // 1,500 ┤ █▆1717 // 1,000 ┤ ██ ▆1818 // 500 ┤ ██ █19-// 0 ┼─────────19+// 0 ┼─▀▀─▀────2020 // Jan Feb2121 type columnPlan struct {2222 d sheet.ChartData@@ -224,11 +224,13 @@ func (p *columnPlan) drawBars(g *Grid) {
224224 })225225 }226226 227-// dotY maps a value to a braille dot row, four per cell, from the top.227+// dotY maps a value to a braille dot row, four per cell, from the top:228+// a value on a tick is on the tick's line, through the middle of its229+// row, as bars are (see inCells), and the axis's value on the lowest230+// dots above the axis row.228231 func (p *columnPlan) dotY(v float64) int {229232 rows := p.axisRow * 4230- full := p.sc.cells()*4 - 1231- y := rows - 1 - int(math.Round(p.sc.at(v)/float64(p.sc.cells())*float64(full)))233+ y := int(math.Floor((float64(p.axisRow) + 0.5 - p.sc.at(v)) * 4))232234 return min(max(y, 0), rows-1)233235 }234236 @@ -11,14 +11,14 @@ import (
1111 // Sixel is the other way images reach a terminal, for terminals without1212 // kitty graphics (foot, xterm, mlterm, Windows Terminal and others). A1313 // sixel image is pixels drawn at the cursor, not text: the UI draws it14-// after the frame over blank cells it keeps for it (see the ui package's15-// sixel.go). The image is sent whole each time, in at most as many16-// colors as the terminal has color registers, run-length encoded.14+// after the frame, over the text chart the cells hold (see the ui15+// package's sixel.go), so every pixel is set and the text never shows16+// through. The image is sent whole each time, in at most as many colors17+// as the terminal has color registers, run-length encoded.1718 18-// Sixel returns the DCS sequence that draws img at the cursor: pixels19-// with any coverage composited over bg, fully transparent ones left20-// unset so the cell background shows, in at most registers colors21-// (at least 2, at most 256).19+// Sixel returns the DCS sequence that draws img at the cursor, every20+// pixel composited over bg, in at most registers colors (at least 2, at21+// most 256).2222 func Sixel(img *image.RGBA, bg color.RGBA, registers int) string {2323 registers = min(max(registers, 2), 256)2424 b := img.Bounds()@@ -28,8 +28,9 @@ func Sixel(img *image.RGBA, bg color.RGBA, registers int) string {
2828 }2929 idx, pal := quantize(img, bg, registers)3030 var out strings.Builder31- // P2 = 1: pixels not drawn keep what's under them. The raster32- // attributes set square pixels and the image's size.31+ // P2 = 1: pixels not drawn keep what's under them, which only the32+ // empty sixels past the image's last row are. The raster attributes33+ // set square pixels and the image's size.3334 out.WriteString("\x1bP0;1;0q\"1;1;")3435 out.WriteString(strconv.Itoa(w) + ";" + strconv.Itoa(h))3536 for i, c := range pal {@@ -44,7 +45,7 @@ func Sixel(img *image.RGBA, bg color.RGBA, registers int) string {
4445 // percent is a color channel as sixel's 0 to 100.4546 func percent(v uint8) string { return strconv.Itoa((int(v)*100 + 127) / 255) }4647 47-// sixelBands encodes the image of register indexes (-1 for unset), six48+// sixelBands encodes the image of register indexes, six4849 // rows at a time: for each color in the band, its row of sixels,4950 // run-length encoded, then "$" to go back for the next color, and "-"5051 // between bands.@@ -79,9 +80,6 @@ type bands struct {
7980 func (b *bands) gather(px []int16, y0 int) {8081 b.used = b.used[:0]8182 for i, c := range px {82- if c < 0 {83- continue84- }8583 if b.band[c] != y0+1 {8684 b.band[c] = y0 + 18785 b.used = append(b.used, c)@@ -122,7 +120,7 @@ func writeRuns(out *strings.Builder, row []byte) {
122120 }123121 124122 // quantize maps each pixel of img, composited over bg, to a register,125-// -1 for a fully transparent pixel, and returns the registers' colors.123+// and returns the registers' colors.126124 // Colors are kept exactly while there are at most registers of them;127125 // past that, their low bits are dropped until they fit, and each128126 // register is the average of the colors it stands for. Registers are@@ -131,12 +129,11 @@ func writeRuns(out *strings.Builder, row []byte) {
131129 func quantize(img *image.RGBA, bg color.RGBA, registers int) ([]int16, []color.RGBA) {132130 b := img.Bounds()133131 w, h := b.Dx(), b.Dy()134- px := make([]uint32, w*h) // 0 for transparent, else 1<<24 | RGB132+ px := make([]uint32, w*h) // 1<<24 | RGB135133 for y := range h {136134 for x := range w {137- if c := over(img, b.Min.X+x, b.Min.Y+y, bg); c.A != 0 {138- px[y*w+x] = 1<<24 | uint32(c.R)<<16 | uint32(c.G)<<8 | uint32(c.B)139- }135+ c := over(img, b.Min.X+x, b.Min.Y+y, bg)136+ px[y*w+x] = 1<<24 | uint32(c.R)<<16 | uint32(c.G)<<8 | uint32(c.B)140137 }141138 }142139 shift := uint(0)@@ -150,10 +147,6 @@ func quantize(img *image.RGBA, bg color.RGBA, registers int) ([]int16, []color.R
150147 idx := make([]int16, w*h)151148 last, lastReg := uint32(0), int16(-1) // runs of one color are common: look each up once152149 for i, p := range px {153- if p == 0 {154- idx[i] = -1155- continue156- }157150 r := lastReg158151 if p != last {159152 k := bucket(p, shift)@@ -191,7 +184,7 @@ func distinct(px []uint32, shift uint, limit int) int {
191184 seen := map[uint32]struct{}{}192185 last := uint32(0)193186 for _, p := range px {194- if p == 0 || p == last {187+ if p == last {195188 continue196189 }197190 last = p@@ -204,14 +197,11 @@ func distinct(px []uint32, shift uint, limit int) int {
204197 }205198 206199 // over is the pixel at x, y of the premultiplied img composited over207-// bg, opaque, or transparent where img has no coverage.200+// bg, opaque.208201 func over(img *image.RGBA, x, y int, bg color.RGBA) color.RGBA {209202 i := img.PixOffset(x, y)210203 p := img.Pix[i : i+4 : i+4]211204 a := int(p[3])212- if a == 0 {213- return color.RGBA{}214- }215205 return color.RGBA{mix(p[0], bg.R, a), mix(p[1], bg.G, a), mix(p[2], bg.B, a), 255}216206 }217207 @@ -13,7 +13,8 @@ import (
1313 // order they appear, runs of four or more as "!n", trailing empty1414 // sixels left out, "$" between the colors of a band and "-" between1515 // bands, a pixel with half coverage composited over the background and16-// a transparent one left unset.16+// a transparent one drawn in the background, so text under the image17+// never shows through.1718 func TestSixelGolden(t *testing.T) {1819 img := image.NewRGBA(image.Rect(0, 0, 4, 7))1920 red := color.RGBA{255, 0, 0, 255}@@ -27,9 +28,9 @@ func TestSixelGolden(t *testing.T) {
2728 img.SetRGBA(0, 6, color.RGBA{0, 0, 255, 255})2829 got := Sixel(img, color.RGBA{0, 0, 0, 255}, 256)2930 want := "\x1bP0;1;0q\"1;1;4;7" +30- "#0;2;100;0;0#1;2;0;50;0#2;2;0;0;100" +31- "#0DDD@$#1?A" + // red: rows 0 and 2 (1+4) three times, then row 0 alone32- "-#2@" +31+ "#0;2;100;0;0#1;2;0;0;0#2;2;0;50;0#3;2;0;0;100" +32+ "#0DDD@$#1ywy}$#2?A" + // red: rows 0 and 2 (1+4) three times, then row 0 alone; black around33+ "-#1?@@@$#3@" +3334 "\x1b\\"3435 if got != want {3536 t.Errorf("Sixel =\n%q\nwant\n%q", got, want)@@ -81,8 +82,8 @@ func TestSixelChart(t *testing.T) {
8182 }8283 8384 // A chart's sixel image decodes to the image composited over the84-// background, each channel within sixel's percent steps, and pixels85-// without coverage unset.85+// background, each channel within sixel's percent steps, pixels86+// without coverage included.8687 func TestSixelDecodes(t *testing.T) {8788 bg := color.RGBA{250, 250, 245, 255}8889 for _, ct := range []sheet.ChartType{sheet.ChartLine, sheet.ChartPie, sheet.ChartArea} {@@ -93,7 +94,7 @@ func TestSixelDecodes(t *testing.T) {
9394 for x := range b.Dx() {9495 want := over(img, x, y, bg)9596 c, set := got[image.Pt(x, y)]96- if set != (want.A != 0) || set && (diff(c.R, want.R) > 3 || diff(c.G, want.G) > 3 || diff(c.B, want.B) > 3) {97+ if !set || (diff(c.R, want.R) > 3 || diff(c.G, want.G) > 3 || diff(c.B, want.B) > 3) {9798 t.Fatalf("%v at %d,%d: %v %v, want %v", ct, x, y, c, set, want)9899 }99100 }@@ -176,10 +176,14 @@ func drawPiles(sc scale, shown int, stacked bool, piles func(int, []span) []span
176176 }177177 178178 // inCells maps spans in values to spans in cells along sc, into out.179+// Text ticks and the axis are lines through the middle of their cells,180+// so values are placed half a cell back from where sc puts them: a181+// bar starts at the axis line, in the middle of cell -1 (the axis row182+// or column), and a value on a tick ends on the tick's line.179183 func inCells(sc scale, spans []span, out []span) []span {180184 out = out[:0]181185 for _, s := range spans {182- out = append(out, span{sc.at(s.lo), sc.at(s.hi), s.j})186+ out = append(out, span{sc.at(s.lo) - 0.5, sc.at(s.hi) - 0.5, s.j})183187 }184188 return out185189 }@@ -1,10 +1,10 @@
11 22 3- 20% ┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈▁▃▅▇4- │▂ ▁▃▅▇████5- 10% ┤██▅▂┈┈┈┈┈┈┈┈┈┈┈┈┈▁▃▅▇████████6- │████▇▄▁ ▂▅▇████████████7- 0% ┤┈┈┈┈┈┈┈┈▀██▀┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈8- │3+ 20% ┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈▁▃4+ │ ▁▃▅▇██5+ 10% ┤▆▄▁┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈▁▃▅▇██████6+ │███▆▃ ▁▃▅▇██████████7+ 0% ┤▀▀▀▀▀▀┈┈▄▄▄▄┈┈┈▀▀▀▀▀▀▀▀▀▀▀▀▀▀8+ │ ▀▀99 -10% ┼──────────────────────────────1010 Q1 Q2 Q3 Q4@@ -1,12 +1,12 @@
11 $3,000 ┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈22 │3- │ ▃▃▃▃▃▄▄▄▄▄▅▅4-$2,000 ┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈████████████5- │▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄6- │███████████████████████████████████3+ │ ▁▁4+$2,000 ┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈▇▇▇▇▇███████5+ │ ████████████6+ │▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇█████████████████77 $1,000 ┤███████████████████████████████████88 │███████████████████████████████████99 │███████████████████████████████████10- $0 ┼────────────────────────────────────10+ $0 ┼▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀─1111 Jan Feb Mar Apr1212 ■ Rent ■ Food@@ -1,12 +1,12 @@
1-$1,500 ┤▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▇▇▇▇▇██████████████1+$1,500 ┤▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▃▃▃▃▃▄▄▄▄▄▄▄▄▄▄▄▄▄▄22 │███████████████████████████████████33 │███████████████████████████████████44 $1,000 ┤███████████████████████████████████5- │████████████████████████████████▁▁▂6- │███████████████████████▅▆▆▇▇▇██████5+ │███████████████████████████████████6+ │███████████████████████▁▂▂▃▃▃▄▄▄▅▅▆77 $500 ┤███████████████████████████████████88 │███████████████████████████████████99 │███████████████████████████████████10- $0 ┼────────────────────────────────────10+ $0 ┼▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀─1111 Jan Feb Mar Apr1212 ■ Rent ■ Food@@ -1,12 +1,12 @@
11 22 3- 10K ┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈▇▇▇▇▇┈┈┈┈┈┈┈┈3+ 10K ┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈▃▃▃▃▃┈┈┈┈┈┈┈┈44 │ █████5-1,000 ┤┈┈┈┈┈┈┈┈┈┈┈┈┈▆▆▆▆▆┈█████┈┈┈┈┈┈┈┈5+1,000 ┤┈┈┈┈┈┈┈┈┈┈┈┈┈▂▂▂▂▂┈█████┈┈┈┈┈┈┈┈66 │ █████ █████7- 100 ┤┈┈┈┈┈┈┈▂▂▂▂▂┈█████┈█████┈┈┈┈┈┈┈┈8- │ █████ █████ █████7+ 100 ┤┈┈┈┈┈┈┈┈┈┈┈┈┈█████┈█████┈┈┈┈┈┈┈┈8+ │ ▆▆▆▆▆ █████ █████99 10 ┤┈┈┈┈┈┈┈█████┈█████┈█████┈┈┈┈┈┈┈┈10- │ █████ █████ █████ █████11- 1 ┼─────────────────────────────────10+ │ ▄▄▄▄▄ █████ █████ █████11+ 1 ┼─▀▀▀▀▀─▀▀▀▀▀─▀▀▀▀▀─▀▀▀▀▀─────────1212 Y1 Y2 Y3 Y4 Y5@@ -1,12 +1,12 @@
11 2-$1,600 ┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈▂▂▂┈┈┈┈┈▂▂▂┈┈┈┈┈┈3- │ ▇▇▇ ▇▇▇ ███ ███2+$1,600 ┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈3+ │ ▃▃▃ ▃▃▃ ▆▆▆ ▆▆▆44 $1,325 ┤┈┈███┈┈┈┈┈███┈┈┈┈┈███┈┈┈┈┈███┈┈┈┈┈┈55 │ ███ ███ ███ ███66 $1,050 ┤┈┈███┈┈┈┈┈███┈┈┈┈┈███┈┈┈┈┈███┈┈┈┈┈┈77 │ ███ ███ ███ ███8- $775 ┤┈┈███┈┈┈┈┈███┈┈┈┈┈███┈┈┈┈┈███▄▄▄┈┈┈9- │ ███▆▆▆ ███ ███▇▇▇ ██████10- $500 ┼────────────────────────────────────8+ $775 ┤┈┈███┈┈┈┈┈███┈┈┈┈┈███┈┈┈┈┈███┈┈┈┈┈┈9+ │ ███▂▂▂ ███ ███▃▃▃ ██████10+ $500 ┼──▀▀▀▀▀▀──▀▀▀─────▀▀▀▀▀▀──▀▀▀▀▀▀────1111 Jan Feb Mar Apr1212 ■ Rent ■ Food@@ -1,12 +1,12 @@
11 $1,900 ┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈22 │3- │⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠔⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒4-$1,400 ┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈3+ │ ⢀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀4+$1,400 ┤⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠁┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈55 │66 │77 $900 ┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈8- │⠄ ⠤⠤⠤⠒⠒⠒⠒⠒⠒⠉⠉⠉9- │8+ │ ⣀⣀⣀⣀⣀⣀⠤⠤⠤9+ │⠂ ⠉⠉⠉1010 $400 ┼────────────────────────────────────1111 Jan Feb Mar Apr1212 ■ Rent ■ Food@@ -1,10 +1,10 @@
1-Jan │████████████████████████▊██████████1+Jan ▐████████████████████████▎█████████▌22 │ ┊ ┊ ┊ ┊ ┊3-Feb │███████████████████████████████████3+Feb ▐██████████████████████████████████▌44 │ ┊ ┊ ┊ ┊ ┊5-Mar │████████████████████████▉██████████5+Mar ▐████████████████████████▍█████████▌66 │ ┊ ┊ ┊ ┊ ┊7-Apr │███████████████████████▉███████████7+Apr ▐███████████████████████▍██████████▌88 │ ┊ ┊ ┊ ┊ ┊99 │ ┊ ┊ ┊ ┊ ┊1010 └──────┬──────┬──────┬──────┬──────┬@@ -1,7 +1,7 @@
1-North │██████████████████████████████2-South │████████████████████ ┊ ┊3- East │███████████▎ ┊ ┊ ┊ ┊4- West │███████▌ ┊ ┊ ┊ ┊ ┊1+North ▐█████████████████████████████▌2+South ▐███████████████████▌ ┊ ┊3+ East ▐██████████▊ ┊ ┊ ┊ ┊4+ West ▐███████ ┊ ┊ ┊ ┊ ┊55 │ ┊ ┊ ┊ ┊ ┊ ┊66 │ ┊ ┊ ┊ ┊ ┊ ┊77 └────┬────┬────┬────┬────┬────┬@@ -1,10 +1,10 @@
1-Jan │█████████████████▍██████▋ ┊1+Jan ▐████████████████▉███████▏ ┊22 │ ┊ ┊ ┊3-Feb │█████████████████▍ ┊ ┊3+Feb ▐████████████████▉ ┊ ┊44 │ ┊ ┊ ┊5-Mar │█████████████████████████▍ ┊5+Mar ▐█████████████████▌██████▉ ┊66 │ ┊ ┊ ┊7-Apr │██████████████████████████▍ ┊7+Apr ▐█████████████████▌███████▉ ┊88 │ ┊ ┊ ┊99 │ ┊ ┊ ┊1010 └───────────┬───────────┬───────────┬@@ -1,11 +1,11 @@
1-Jan │██████████████████████████████████▊┊2- │██████████████▍ ┊ ┊3-Feb │██████████████████████████████████▊┊1+Jan ▐██████████████████████████████████▎┊2+ ▐█████████████▉ ┊ ┊3+Feb ▐██████████████████████████████████▎┊44 │ ┊ ┊ ┊5-Mar │████████████████████████████████████6- │██████████████▊ ┊ ┊7-Apr │████████████████████████████████████8- │████████████████▊ ┊ ┊5+Mar ▐███████████████████████████████████▌6+ ▐██████████████▎ ┊ ┊7+Apr ▐███████████████████████████████████▌8+ ▐████████████████▎ ┊ ┊99 │ ┊ ┊ ┊1010 └───────────┬───────────┬───────────┬1111 $0 $500 $1,000 $1,500@@ -1,10 +1,10 @@
11 22 3- 20% ┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈██████┈┈4- │▃▃▃▃▃▃ ██████5- 10% ┤██████┈┈┈┈┈┈┈┈▅▅▅▅▅▅┈██████┈┈3+ 20% ┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈▄▄▄▄▄▄┈┈4+ │ ██████5+ 10% ┤▇▇▇▇▇▇┈┈┈┈┈┈┈┈▁▁▁▁▁▁┈██████┈┈66 │██████ ██████ ██████7- 0% ┤┈┈┈┈┈┈┈██████┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈8- │7+ 0% ┤▀▀▀▀▀▀┈▄▄▄▄▄▄┈▀▀▀▀▀▀┈▀▀▀▀▀▀┈┈8+ │ ▀▀▀▀▀▀99 -10% ┼──────────────────────────────1010 Q1 Q2 Q3 Q4@@ -1,12 +1,12 @@
11 2-100% ┤┈███████┈┈███████┈┈███████┈┈███████┈┈2+100% ┤┈▄▄▄▄▄▄▄┈┈▄▄▄▄▄▄▄┈┈▄▄▄▄▄▄▄┈┈▄▄▄▄▄▄▄┈┈33 │ ███████ ███████ ███████ ███████4- 75% ┤┈▅▅▅▅▅▅▅┈┈███████┈┈▅▅▅▅▅▅▅┈┈▄▄▄▄▄▄▄┈┈4+ 75% ┤┈▁▁▁▁▁▁▁┈┈███████┈┈▁▁▁▁▁▁▁┈┈███████┈┈55 │ ███████ ███████ ███████ ███████66 50% ┤┈███████┈┈███████┈┈███████┈┈███████┈┈77 │ ███████ ███████ ███████ ███████88 25% ┤┈███████┈┈███████┈┈███████┈┈███████┈┈99 │ ███████ ███████ ███████ ███████10- 0% ┼──────────────────────────────────────10+ 0% ┼─▀▀▀▀▀▀▀──▀▀▀▀▀▀▀──▀▀▀▀▀▀▀──▀▀▀▀▀▀▀───1111 Jan Feb Mar Apr1212 ■ Rent ■ Food@@ -1,10 +1,10 @@
11 22 33 150 ┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈4- │ ▆▆▆▆▆▆5-100 ┤┈┈██████┈┈▂▂▂▂▂▂┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈6- │ ██████ ██████7- 50 ┤┈┈██████┈┈██████┈┈▆▆▆▆▆▆┈┈▂▂▂▂▂▂┈┈8- │ ██████ ██████ ██████ ██████9- 0 ┼───────────────────────────────────4+ │ ▂▂▂▂▂▂5+100 ┤┈┈██████┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈6+ │ ██████ ▆▆▆▆▆▆7+ 50 ┤┈┈██████┈┈██████┈┈▂▂▂▂▂▂┈┈┈┈┈┈┈┈┈┈8+ │ ██████ ██████ ██████ ▆▆▆▆▆▆9+ 0 ┼──▀▀▀▀▀▀──▀▀▀▀▀▀──▀▀▀▀▀▀──▀▀▀▀▀▀───1010 North South East West@@ -1,12 +1,12 @@
11 2- 40 ┤┈█████████┈┈█████████┈┈▄▄▄▄▄▄▄▄▄┈┈2+ 40 ┤┈▄▄▄▄▄▄▄▄▄┈┈▄▄▄▄▄▄▄▄▄┈┈┈┈┈┈┈┈┈┈┈┈┈3+ │ ▄▄▄▄▄▄▄▄▄ █████████ █████████4+ 20 ┤┈█████████┈┈█████████┈┈▄▄▄▄▄▄▄▄▄┈┈35 │ █████████ █████████ █████████4- 20 ┤┈█████████┈┈█████████┈┈█████████┈┈5- │ █████████ █████████ █████████6- 0 ┤┈█████████┈┈█████████┈┈█████████┈┈7- │ █████████ ▀▀▀▀▀▀▀▀▀ █████████8--20 ┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈█████████┈┈9- │6+ 0 ┤┈▄▄▄▄▄▄▄▄▄┈┈▄▄▄▄▄▄▄▄▄┈┈▄▄▄▄▄▄▄▄▄┈┈7+ │ █████████ ▄▄▄▄▄▄▄▄▄ █████████8+-20 ┤┈▀▀▀▀▀▀▀▀▀┈┈┈┈┈┈┈┈┈┈┈┈┈█████████┈┈9+ │ ▀▀▀▀▀▀▀▀▀1010 -40 ┼───────────────────────────────────1111 Q1 Q2 Q31212 ■ Sales ■ Costs ■ Other@@ -1,12 +1,12 @@
11 $3,000 ┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈22 │3- │ ▁▁▁▁▁▁ ▃▃▃▃▃▃ ▅▅▅▅▅▅4-$2,000 ┤┈┈██████┈┈┈┈┈┈┈┈┈┈██████┈┈██████┈┈┈5- │ ▃▃▃▃▃▃ ▃▃▃▃▃▃ ▄▄▄▄▄▄ ▄▄▄▄▄▄6- │ ██████ ██████ ██████ ██████3+ │ ▁▁▁▁▁▁4+$2,000 ┤┈┈▅▅▅▅▅▅┈┈┈┈┈┈┈┈┈┈▇▇▇▇▇▇┈┈██████┈┈┈5+ │ ██████ ██████ ██████6+ │ ▇▇▇▇▇▇ ▇▇▇▇▇▇ ██████ ██████77 $1,000 ┤┈┈██████┈┈██████┈┈██████┈┈██████┈┈┈88 │ ██████ ██████ ██████ ██████99 │ ██████ ██████ ██████ ██████10- $0 ┼────────────────────────────────────10+ $0 ┼──▀▀▀▀▀▀──▀▀▀▀▀▀──▀▀▀▀▀▀──▀▀▀▀▀▀────1111 Jan Feb Mar Apr1212 ■ Rent ■ Food@@ -1,12 +1,12 @@
1-$1,500 ┤┈┈▆▆▆┈┈┈┈┈▆▆▆┈┈┈┈┈███┈┈┈┈┈███┈┈┈┈┈┈1+$1,500 ┤┈┈▂▂▂┈┈┈┈┈▂▂▂┈┈┈┈┈▄▄▄┈┈┈┈┈▄▄▄┈┈┈┈┈┈22 │ ███ ███ ███ ███33 │ ███ ███ ███ ███44 $1,000 ┤┈┈███┈┈┈┈┈███┈┈┈┈┈███┈┈┈┈┈███┈┈┈┈┈┈5- │ ███ ███ ███ ███▂▂▂6- │ ███▅▅▅ ███ ███▅▅▅ ██████5+ │ ███ ███ ███ ███6+ │ ███▁▁▁ ███ ███▁▁▁ ███▆▆▆77 $500 ┤┈┈██████┈┈███┈┈┈┈┈██████┈┈██████┈┈┈88 │ ██████ ███ ██████ ██████99 │ ██████ ███ ██████ ██████10- $0 ┼────────────────────────────────────10+ $0 ┼──▀▀▀▀▀▀──▀▀▀─────▀▀▀▀▀▀──▀▀▀▀▀▀────1111 Jan Feb Mar Apr1212 ■ Rent ■ Food@@ -1,12 +1,12 @@
11 $1,600 ┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈2- │⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠔⠒⠒⠒⠒⠒⠊⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉3-$1,400 ┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈2+ │ ⢀⣀⣀⣀⣀⣀⡠⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤3+$1,400 ┤⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠁┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈44 │55 $1,200 ┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈66 │77 $1,000 ┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈88 │9- $800 ┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈⢀⣀10- │⡀ ⣀⡠⠤⠤⠔⠒⠒⠊⠉⠉⠁9+ $800 ┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈10+ │⡀ ⣀⣀⣀⣀⣀⣀⠤⠤⠤⠤⠤⠤1111 $600 ┼────────────────────────────────────1212 Jan Feb Mar Apr@@ -1,12 +1,12 @@
11 2-$1,500 ┤▆▆▆┈┈┈┈▆▆▆┈┈┈┈███┈┈┈┈███┈┈┈┈2+$1,500 ┤▂▂▂┈┈┈┈▂▂▂┈┈┈┈▄▄▄┈┈┈┈▄▄▄┈┈┈┈33 │███ ███ ███ ███44 │███ ███ ███ ███55 $1,000 ┤███┈┈┈┈███┈┈┈┈███┈┈┈┈███┈┈┈┈6- │███ ███ ███ ███▂▂▂ ■ Rent7- │███▅▅▅ ███ ███▅▅▅ ██████ ■ Food6+ │███ ███ ███ ███ ■ Rent7+ │███▁▁▁ ███ ███▁▁▁ ███▆▆▆ ■ Food88 $500 ┤██████┈███┈┈┈┈██████┈██████┈99 │██████ ███ ██████ ██████1010 │██████ ███ ██████ ██████11- $0 ┼─────────────────────────────11+ $0 ┼▀▀▀▀▀▀─▀▀▀────▀▀▀▀▀▀─▀▀▀▀▀▀──1212 Jan Feb Mar Apr@@ -1,10 +1,10 @@
1-125 ┤⢄⡀┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈2- │ ⠈⠑⠢⢄⡀3-100 ┤┈┈┈┈┈⠈⠒⠤⣀┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈4- │ ⠉⠒⠤⣀5- 75 ┤┈┈┈┈┈┈┈┈┈┈┈┈┈⠉⠒⠤⣀┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈6- │ ⠉⠒⠤⣀7- 50 ┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈⠉⠒⠒⠤⠤⠤⣀⣀⡀┈┈┈┈8- │ ⠈⠉⠉⠑⠒1+125 ┤⡀┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈2+ │⠈⠑⠢⣀3+100 ┤┈┈┈┈⠉⠢⢄⡀┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈4+ │ ⠈⠑⠤⣀5+ 75 ┤┈┈┈┈┈┈┈┈┈┈┈⠉⠒⠤⣀┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈6+ │ ⠉⠒⠤⣀7+ 50 ┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈⠉⠒⠤⣀⣀┈┈┈┈┈┈┈┈┈┈8+ │ ⠉⠉⠉⠒⠒⠢⠤⠤⢄⣀99 25 ┼───────────────────────────────────1010 North South East West@@ -1,12 +1,12 @@
11 2-$1,500 ┤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠔⠒⠒⠒⠒⠒⠊⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉2+$1,500 ┤⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⡠⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤33 │44 $1,250 ┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈55 │66 $1,000 ┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈77 │8- $750 ┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈⣀⣀⣀⣀⠤⠤⠤⠤⠒⠒9- │⠁ ⠉⠉8+ $750 ┤┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈⣀⣀9+ │⠄ ⠤⠤⠒⠒⠒⠒⠉⠉⠉⠉1010 $500 ┼────────────────────────────────────1111 Jan Feb Mar Apr1212 ■ Rent ■ Food@@ -1,10 +1,10 @@
11 22 33 150 ┤4- │ ▆▆▆▆▆▆5-100 ┤ ██████ ▂▂▂▂▂▂6- │ ██████ ██████7- 50 ┤ ██████ ██████ ▆▆▆▆▆▆ ▂▂▂▂▂▂8- │ ██████ ██████ ██████ ██████9- 0 ┼───────────────────────────────────4+ │ ▂▂▂▂▂▂5+100 ┤ ██████6+ │ ██████ ▆▆▆▆▆▆7+ 50 ┤ ██████ ██████ ▂▂▂▂▂▂8+ │ ██████ ██████ ██████ ▆▆▆▆▆▆9+ 0 ┼──▀▀▀▀▀▀──▀▀▀▀▀▀──▀▀▀▀▀▀──▀▀▀▀▀▀───1010 North South East West@@ -141,6 +141,9 @@ func importKind(ctx context.Context, name string, k Kind, opt Options) (*Result,
141141 }142142 }143143 r.Kind = k144+ if !k.format().widths {145+ r.Sheet.LoadFitWidths()146+ }144147 if p := opt.Progress; p != nil && p.permille.Load() >= 0 {145148 p.permille.Store(1000)146149 }@@ -49,6 +49,10 @@ type fileFormat struct {
4949 // tables is set for databases: an import picks a table, and an5050 // export writes the sheet or the selection as a named table.5151 tables bool52+ // widths is set for formats that keep column widths: an import53+ // keeps them, where the other formats' columns are fitted to their54+ // data (Sheet.LoadFitWidths).55+ widths bool5256 }5357 5458 // An importer reads a file into a new workbook, returning the sheet to@@ -71,7 +75,7 @@ var kinds = []fileFormat{{
7175 kind: XLSX, name: "XLSX", noun: "Excel", label: "Excel workbook", exts: []string{".xlsx", ".xlsm"},7276 read: importXLSX, write: exportXLSX, menu: "Microsoft Excel",7377 about: "Save as an Excel workbook (.xlsx) with formulas, formats and widths",74- book: true,78+ book: true, widths: true,7579 }, {7680 kind: SQLite, name: "SQLite", noun: "SQLite", label: "SQLite database", exts: []string{".sqlite", ".sqlite3", ".db"},7781 read: importSQLite, write: exportSQLite, menu: "SQLite database",@@ -82,7 +86,7 @@ var kinds = []fileFormat{{
8286 read: importParquet,8387 }, {8488 kind: WK1, name: "WK1", noun: "1-2-3", label: "Lotus 1-2-3 worksheet", exts: []string{".wk1", ".wks"},85- read: importWK1,89+ read: importWK1, widths: true,8690 }, {8791 kind: JSON, name: "JSON", noun: "JSON", label: "JSON list of records", exts: []string{".json", ".ndjson", ".jsonl"},8892 read: importJSON, write: exportJSON, menu: "JSON list of records", encode: encodeJSON,@@ -31,6 +31,7 @@ func ImportReader(ctx context.Context, name string, r io.Reader, opt Options) (*
3131 if book := res.Sheet.Book(); book.RenameSheet(res.Sheet, sheetName(name)) == nil {3232 book.ClearHistory()3333 }34+ res.Sheet.LoadFitWidths() // a stream is CSV, TSV, JSON or NUON: no widths of its own3435 if p := opt.Progress; p != nil {3536 p.permille.Store(1000)3637 }@@ -0,0 +1,72 @@
1+package fileio2+3+import (4+ "context"5+ "os"6+ "path/filepath"7+ "strings"8+ "testing"9+10+ "github.com/FelineStateMachine/012/internal/sheet"11+)12+13+// Formats without widths of their own fit their columns to the header14+// and the rows below it, capped, and leave narrow columns at the15+// default; read from a stream too.16+func TestImportFitsWidths(t *testing.T) {17+ long := strings.Repeat("x", 60)18+ files := map[string]string{19+ "t.csv": "Item,Qty,Note\nStapler with a long name,3," + long + "\n",20+ "t.tsv": "Item\tQty\tNote\nStapler with a long name\t3\t" + long + "\n",21+ "t.json": `[{"Item":"Stapler with a long name","Qty":3,"Note":"` + long + `"}]`,22+ "t.nuon": `[[Item, Qty, Note]; ["Stapler with a long name", 3, "` + long + `"]]`,23+ "t.jsonl": `{"Item":"Stapler with a long name","Qty":3,"Note":"` + long + `"}`,24+ }25+ check := func(t *testing.T, s *sheet.Sheet) {26+ t.Helper()27+ if got := s.ColWidth(0); got != len("Stapler with a long name")+2 {28+ t.Errorf("Item is %d wide", got)29+ }30+ if got := s.ColWidth(1); got != sheet.DefaultWidth {31+ t.Errorf("Qty is %d wide, want the default", got)32+ }33+ if got := s.ColWidth(2); got != 30 {34+ t.Errorf("Note is %d wide, want the cap", got)35+ }36+ }37+ dir := t.TempDir()38+ for name, text := range files {39+ t.Run(name, func(t *testing.T) {40+ path := filepath.Join(dir, name)41+ os.WriteFile(path, []byte(text), 0o600)42+ r, err := Import(context.Background(), path, Options{})43+ if err != nil {44+ t.Fatal(err)45+ }46+ check(t, r.Sheet)47+ r, err = ImportReader(context.Background(), "stdin", strings.NewReader(text), Options{})48+ if err != nil {49+ t.Fatal(err)50+ }51+ check(t, r.Sheet)52+ })53+ }54+}55+56+// A format that keeps widths keeps them, and columns it leaves at the57+// default stay there.58+func TestImportKeepsFileWidths(t *testing.T) {59+ s := sheet.New()60+ s.Set(sheet.Addr{}, strings.Repeat("x", 40))61+ path := filepath.Join(t.TempDir(), "t.xlsx")62+ if _, err := Export(context.Background(), path, XLSX, SnapBook(s), ExportOptions{}); err != nil {63+ t.Fatal(err)64+ }65+ r, err := Import(context.Background(), path, Options{})66+ if err != nil {67+ t.Fatal(err)68+ }69+ if got := r.Sheet.ColWidth(0); got != sheet.DefaultWidth {70+ t.Errorf("A is %d wide, want the file's default", got)71+ }72+}@@ -0,0 +1,75 @@
1+# 012 in nushell pipelines: `sheet` opens the table piped to it in 0122+# and returns what you send back, with its types.3+#4+# Install: 012 nu --install-module, then add `use scripts/012.nu *` to5+# config.nu. See https://github.com/FelineStateMachine/012 (docs/nushell).6+7+# Open a table in 012, and return the table sent back on quitting.8+#9+# The table piped in opens as a sheet, or the file named instead. Edit10+# it, sort it or select a range; quitting asks whether to send the11+# selection or the whole sheet back as NUON, so file sizes, durations12+# and dates come back as themselves. With --send, quitting sends13+# without asking. Quitting without sending raises an error, so `try`14+# can catch it. Text piped in (CSV, TSV, JSON, NUON) is read as 01215+# reads it.16+@example "Pick files in 012 and keep filtering" { ls | sheet | where size > 1kb }17+@example "Edit the table and get all of it back when you quit" { ls | sheet --send sheet }18+@example "Get back the range selected when you quit, its first row naming the columns" { ls | select name size | sheet --send selection }19+@example "Edit a workbook and save what you send back as CSV" { sheet budget.xlsx | save -f budget.csv }20+@example "Carry on when nothing is sent back" { try { ps | sheet } catch { [] } }21+@search-terms [spreadsheet table edit 012]22+export def sheet [23+ file?: path # open this workbook or file instead of the input24+ --send: string # send without asking on quitting: selection (the sheet when one cell is selected) or sheet25+] {26+ let input = $in27+ if $send != null and $send not-in [selection sheet] {28+ error make {29+ msg: $"--send ($send): sheet sends selection or sheet"30+ label: {text: "selection or sheet", span: (metadata $send).span}31+ }32+ }33+ let send_args = if $send == null { [] } else { [--send $send] }34+ let file_args = if $file == null { [] } else { [$file] }35+ let args = [--pipe --to nuon ...$send_args ...$file_args]36+ let r = if $input == null {37+ ^012 ...$args | complete38+ } else if ($input | describe) in [string binary] {39+ $input | ^012 ...$args | complete40+ } else {41+ $input | to nuon | ^012 ...$args | complete42+ }43+ if $r.exit_code != 0 {44+ let why = $r.stderr | str trim | str replace --regex '^012: ' ''45+ error make {46+ msg: (if $why == "" { $"012 exited with status ($r.exit_code)" } else { $why })47+ help: (if $send == null { "nothing was sent back; quit with Enter or S to send a table" } else { $"nothing was sent back; Ctrl+Q sends the ($send)" })48+ }49+ }50+ $r.stdout | from nuon51+}52+53+# Look at a table in 012, then carry on with nothing.54+#55+# Like `sheet`, without sending anything back: the table stays in 01256+# until you save or download it.57+@example "Look at the processes" { ps | sheet view }58+@search-terms [spreadsheet table view 012]59+export def "sheet view" [] {60+ let input = $in61+ if ($input | describe) in [string binary] {62+ $input | ^012 -63+ } else {64+ $input | to nuon | ^012 -65+ }66+ null67+}68+69+# Open a nushell notebook in 012.70+@example "Open a notebook" { sheet nu work.012 }71+export def "sheet nu" [72+ file?: path # the workbook to open73+] {74+ if $file == null { ^012 nu } else { ^012 nu $file }75+}@@ -0,0 +1,15 @@
1+// Package module holds 012.nu, the nushell module that gives 012 the2+// command `sheet`, so nushell users needn't type `^012` (a bare 012 is a3+// number to nushell). `012 nu --module` prints it and `012 nu4+// --install-module` installs it (see docs/nushell/README.md).5+package module6+7+import _ "embed"8+9+// Source is the text of 012.nu.10+//11+//go:embed 012.nu12+var Source string13+14+// Name is the module's file name, and so its name in nushell.15+const Name = "012.nu"@@ -31,6 +31,17 @@ func (s *Sheet) LoadColWidth(c, w int) {
3131 }3232 }3333 34+// LoadFitWidths widens each column of the used range whose width isn't35+// set to its widest text among the first rows (a header and a sample36+// below it), capped, as a table a region shows is fitted: what an37+// importer does for a format that keeps no widths of its own (CSV,38+// JSON). Without recording undo.39+func (s *Sheet) LoadFitWidths() {40+ if used, ok := s.UsedRange(); ok {41+ s.fitTable(used.From, used.To.Row-used.From.Row+1, used.To.Col-used.From.Col+1)42+ }43+}44+3445 // Unload removes a cell a loader stored, as an importer does with a row3546 // that doesn't fit whole.3647 func (s *Sheet) Unload(a Addr) { s.place(a, nil) }@@ -14,8 +14,8 @@ import (
1414 "github.com/FelineStateMachine/012/internal/ui/theme"1515 )1616 17-// Charts follow Sheets: Insert > Chart charts the selection (or the block18-// of data around the active cell) and opens the chart editor, a bar on the17+// Charts follow Sheets: Insert > Chart charts the selection (or the table18+// around the active cell) and opens the chart editor, a bar on the1919 // context line for the type, series direction, headers, range and title.2020 // Charts float over the grid anchored at a cell, redraw as their data2121 // recalculates, and can be dragged, resized from the corner, and deleted@@ -89,7 +89,7 @@ func (m *Model) targetChart() int {
8989 func (m *Model) insertChart() tea.Cmd {9090 r := m.selection()9191 if !m.hasRange() {92- r = m.sheet.Region(m.cur)92+ r = m.tableAround(m.cur)9393 }9494 if used, ok := m.sheet.UsedRange(); !ok || r.From.Col > used.To.Col || r.From.Row > used.To.Row {9595 m.note = "Select the data to chart first"@@ -228,11 +228,11 @@ func (m *Model) chartBoxes() []overlay.Box {
228228 // border with a resize handle in the corner.229229 func (m *Model) drawChart(i int, c sheet.Chart, selected bool) []string {230230 w, h := chartInner(c)231+ // A sixel image covers the text chart drawn under it (see sixel.go),232+ // whose bars meet the axis in the row below the image, so the plot233+ // stops being text for kitty placeholders only.231234 o := m.term.chartOptions()232235 o.Chart = c.ChartOptions233- if m.term.sixelOn() {234- o.Image = m.term.six.placed(i) // see sixel.go235- }236236 if i >= maxImages {237237 o.Image = false238238 }@@ -251,7 +251,7 @@ func (m *Model) drawChart(i int, c sheet.Chart, selected bool) []string {
251251 lines = append(lines, border.Render("┌─")+m.th.Title.Render(title)+252252 border.Render(strings.Repeat("─", max(c.W-3-ansi.StringWidth(title), 0))+"┐"))253253 for y := range h {254- lines = append(lines, border.Render("│")+" "+chartRow(&m.th, g, y, firstImageID+i, o.Image, m.term.kitty)+" "+border.Render("│"))254+ lines = append(lines, border.Render("│")+" "+chartRow(&m.th, g, y, firstImageID+i, o.Image)+" "+border.Render("│"))255255 }256256 corner := "┘"257257 if selected {@@ -267,9 +267,8 @@ func (m *Model) drawChart(i int, c sheet.Chart, selected bool) []string {
267267 }268268 269269 // chartRow renders row y of a drawn chart with the theme; with images,270-// the plot area is the image's kitty placeholders, or blank cells for a271-// sixel image to cover.272-func chartRow(th *theme.Theme, g *chart.Grid, y, imageID int, image, kitty bool) string {270+// the plot area is the image's kitty placeholders.271+func chartRow(th *theme.Theme, g *chart.Grid, y, imageID int, image bool) string {273272 var b, run strings.Builder274273 var style lipgloss.Style275274 styled := false@@ -290,8 +289,6 @@ func chartRow(th *theme.Theme, g *chart.Grid, y, imageID int, image, kitty bool)
290289 key, st, isStyled := 0, lipgloss.Style{}, true291290 text := c.Text292291 switch inPlot := y >= g.Plot.Min.Y && y < g.Plot.Max.Y && x >= g.Plot.Min.X && x < g.Plot.Max.X; {293- case image && inPlot && !kitty:294- key, isStyled, text = 2, false, " "295292 case image && inPlot:296293 key, st = 1, th.ImageID(imageID)297294 text = chart.Placeholder(y-g.Plot.Min.Y, x-g.Plot.Min.X)@@ -32,11 +32,11 @@ func (m *Model) ask(q question) {
3232 }3333 3434 // quit exits, asking first when there are unsaved changes. Enter saves35-// and quits, so the quick path never loses work. In a pipeline it asks36-// what to send instead (askSend).35+// and quits, so the quick path never loses work. In a pipeline it sends36+// a table instead, or asks which (quitPiped).3737 func (m *Model) quit() tea.Cmd {3838 if m.pipe.on {39- return m.askSend()39+ return m.quitPiped()4040 }4141 if !m.changed {4242 return m.exit()@@ -56,11 +56,11 @@ func (m *Model) createFilter() tea.Cmd {
5656 }5757 5858 // dataRange is the range data commands act on: the selection when there59-// is one, cut to the data in it, or else the block of data around the60-// active cell.59+// is one, cut to the data in it, or else the table around the active60+// cell.6161 func (g *grid) dataRange() sheet.Rect {6262 if !g.hasRange() {63- return g.sheet.Region(g.cur)63+ return g.tableAround(g.cur)6464 }6565 r := g.selection()6666 if used, ok := g.sheet.UsedRange(); ok {@@ -70,6 +70,18 @@ func (g *grid) dataRange() sheet.Rect {
7070 return r7171 }7272 73+// tableAround is the table around a: in a region, the region's table74+// from its header row down, whatever is next to it; elsewhere the block75+// of data around a (Sheet.Region).76+func (g *grid) tableAround(a sheet.Addr) sheet.Rect {77+ if reg, ok := g.sheet.RegionAt(a); ok {78+ if t, ok := g.sheet.RegionTable(reg.Name); ok {79+ return t80+ }81+ }82+ return g.sheet.Region(a)83+}84+7385 // filterMark is the filter button in column c's header, if c is in the7486 // filter's range, and whether the column's filter hides anything.7587 func (g *grid) filterMark(c int) (string, bool) {@@ -0,0 +1,89 @@
1+package ui2+3+import (4+ "strconv"5+ "testing"6+7+ "github.com/FelineStateMachine/012/internal/notebook"8+ "github.com/FelineStateMachine/012/internal/sheet"9+)10+11+// withRegion adds a sheet after the one shown holding, at B2, the12+// output of a notebook cell named name: a header row and two rows of13+// numbers. It returns the sheet and the table.14+func withRegion(t *testing.T, m *Model, name string) (*sheet.Sheet, sheet.Rect) {15+ t.Helper()16+ w := m.book()17+ nb, err := w.AddNotebook("", m.sheet)18+ if err != nil {19+ t.Fatal(err)20+ }21+ nb.SetNotebookCells("add cell", []notebook.Cell{{Source: name + " = ls"}})22+ w.SetOutput(nb.NotebookCells()[0].ID, ¬ebook.Output{NUON: []byte("[[name, size]; [a, 1], [b, 2]]")})23+ s, err := w.AddSheet("Shell", w.Index(m.sheet)+1)24+ if err != nil {25+ t.Fatal(err)26+ }27+ if err := s.AddRegion(sheet.Region{Name: name, At: sheet.Addr{Col: 1, Row: 1}, Output: true}); err != nil {28+ t.Fatal(err)29+ }30+ m.feedOutput(name)31+ table, ok := s.RegionTable(name)32+ if !ok {33+ t.Fatal("no table")34+ }35+ return s, table36+}37+38+// Go to takes a region's name as formulas write it and selects its39+// table, header row included, on whichever sheet holds it.40+func TestGotoRegion(t *testing.T) {41+ m := newModel()42+ nb, want := withRegion(t, m, "totals")43+ press(t, m, "<ctrl+g>", "NU.Totals", "<enter>")44+ if m.mode != modeReady || m.sheet != nb {45+ t.Fatalf("mode %v, sheet %q, err %q", m.mode, m.sheet.Name(), m.errMsg)46+ }47+ if got := m.selection(); got != want {48+ t.Errorf("selected %v, want the table %v", got, want)49+ }50+ press(t, m, "<f5>", "nu.nothing", "<enter>")51+ if m.mode != modeError {52+ t.Errorf("an unknown region: mode %v", m.mode)53+ }54+}55+56+// From a cell of a region, the table around it is the region's table,57+// not the block of data around the cell, which may run into cells next58+// to it; Insert > Chart and a pivot table read it.59+func TestTableAroundRegion(t *testing.T) {60+ m := newModel()61+ nb, table := withRegion(t, m, "r1")62+ m.showSheet(nb)63+ nb.Set(sheet.Addr{Col: 3, Row: 1}, "next to it")64+ for _, at := range []sheet.Addr{table.To, table.From} {65+ m.clearSelection()66+ m.cur = at67+ if got := m.dataRange(); got != table {68+ t.Errorf("from %v: %v, want the table %v", at, got, table)69+ }70+ if got, ok := m.pivotData(); !ok || got != table {71+ t.Errorf("from %v: pivot reads %v %v, want %v", at, got, ok, table)72+ }73+ }74+ m.cur = table.To75+ m.runCommand("insert.chart")76+ press(t, m, "<enter>")77+ if cs := nb.Charts(); len(cs) != 1 || cs[0].Data != table {78+ t.Fatalf("charts %+v, want one of %v", cs, table)79+ }80+ // Ordinary data is still the block around the cell.81+ m.showSheet(m.book().Sheets()[0])82+ for r := range 3 {83+ m.sheet.Set(sheet.Addr{Row: r}, strconv.Itoa(r))84+ }85+ m.cur = sheet.Addr{Row: 1}86+ if got := m.dataRange(); got != (sheet.Rect{To: sheet.Addr{Row: 2}}) {87+ t.Errorf("ordinary data: %v", got)88+ }89+}@@ -24,7 +24,8 @@ import (
2424 // Charts become images when the terminal answers a kitty graphics query2525 // (kitty, Ghostty, WezTerm and others), or else when its primary device2626 // attributes (DA1) list sixel graphics (foot, xterm, mlterm, Windows27-// Terminal; see sixel.go); everywhere else they stay text. Images use27+// Terminal, xterm.js with its image addon; see sixel.go); everywhere28+// else they stay text. Images use2829 // the terminal's own palette, asked for with OSC 4 at startup, so bars2930 // match the text legend.3031 type terminal struct {@@ -39,7 +39,7 @@ var menuBar = []menuDef{
3939 {cmd: "settings.theme"}, {cmd: "settings.jev_key"}, sep,4040 {cmd: "settings.config_edit"}, {cmd: "settings.config_reload"},4141 }}, sep,42- {cmd: "pipe.send_selection"}, {cmd: "pipe.send_sheet"}, {cmd: "quit"},42+ {cmd: "pipe.send_selection"}, {cmd: "pipe.send_sheet"}, {cmd: "pipe.quit_unsent"}, {cmd: "quit"},4343 }},4444 {title: "Edit", accel: 'e', items: []menuItem{4545 {cmd: "edit.undo"}, {cmd: "edit.redo"}, sep,@@ -126,7 +126,7 @@ func TestGotoAcceptsNamesAndRanges(t *testing.T) {
126126 t.Errorf("range: %v", m.selection())127127 }128128 press(t, m, "<f5>", "nope", "<enter>")129- if m.mode != modeError || m.errMsg != "Not a cell, range or named range: nope" {129+ if m.mode != modeError || m.errMsg != "Not a cell, range, named range or region: nope" {130130 t.Errorf("%v %q", m.mode, m.errMsg)131131 }132132 }@@ -16,8 +16,9 @@ import (
1616 // table to standard output when it quits: the selection or the sheet,1717 // as the user chooses, in the input's format unless another was asked1818 // for. The screen is the terminal's own (cmd/012 opens it), so nothing19-// else reaches standard output. Quitting asks what to send, and20-// quitting without sending lets the pipeline know by the exit status.19+// else reaches standard output. Quitting asks what to send, or sends20+// what --send chose without asking, and quitting without sending lets21+// the pipeline know by the exit status.2122 2223 // StdinName is what a table read from standard input is called: its2324 // sheet's name.@@ -27,8 +28,9 @@ const StdinName = "stdin"
2728 type pipeState struct {2829 in io.Reader // standard input, read as the program starts; nil once read2930 30- on bool // --pipe: quitting writes a table to standard output31- to fileio.Kind // the format asked for (--to), or 0 for the input's31+ on bool // --pipe: quitting writes a table to standard output32+ to fileio.Kind // the format asked for (--to), or 0 for the input's33+ send Send // what quitting sends (--send)3234 3335 // Set by a quit that sends: what to write, and in which format.3436 sent *fileio.Snapshot@@ -43,6 +45,18 @@ func (m *Model) ReadStdin(r io.Reader) { m.pipe.in = r }
4345 // (a text format; 0 for the input's, or NUON when the input isn't text).4446 func (m *Model) SetPipe(to fileio.Kind) { m.pipe.on, m.pipe.to = true, to }4547 48+// Send is what quitting sends in a pipeline (012 --pipe --send).49+type Send int50+51+const (52+ SendAsk Send = iota // ask: the selection, the sheet, or nothing53+ SendSelection // the selection, or the sheet when only one cell is selected54+ SendSheet // the sheet, whatever is selected55+)56+57+// SetSend makes quitting in a pipeline send s rather than ask.58+func (m *Model) SetSend(s Send) { m.pipe.send = s }59+4660 // Piped is what quitting sent: the table and its format, or false when4761 // the user quit without sending.4862 func (m *Model) Piped() (*fileio.Snapshot, fileio.Kind, bool) {@@ -61,6 +75,10 @@ func init() {
6175 enabled: func(m *Model) bool { return m.pipe.on },6276 hidden: func(m *Model) bool { return !m.pipe.on },6377 run: func(m *Model) tea.Cmd { return m.send(sheet.Rect{}) }},78+ &command{id: "pipe.quit_unsent", macro: macroNever, title: "Quit without sending",79+ desc: "Quit, writing nothing to standard output: the pipeline sees exit status 1",80+ hidden: func(m *Model) bool { return !m.pipe.on },81+ run: (*Model).exit},6482 )6583 }6684 @@ -98,16 +116,34 @@ func (m *Model) pipeKind() fileio.Kind {
98116 return fileio.NUON99117 }100118 119+// sendRange is what quitting would send: the selection, when a range120+// is selected and --send doesn't ask for the sheet, or else the sheet121+// (the zero Rect).122+func (m *Model) sendRange() sheet.Rect {123+ if m.pipe.send != SendSheet && m.hasRange() {124+ return m.selection()125+ }126+ return sheet.Rect{}127+}128+101129 // sendWhat names what quitting would send: "B2:D9" or "the sheet".102130 func (m *Model) sendWhat() string {103- if m.hasRange() {104- return m.selection().String()131+ if r := m.sendRange(); r != (sheet.Rect{}) {132+ return r.String()105133 }106134 return "the sheet"107135 }108136 109-// askSend is Quit in a pipeline: send the selection, if there is one,110-// or the sheet, or quit without sending.137+// quitPiped is Quit in a pipeline: send what --send chose, or ask.138+func (m *Model) quitPiped() tea.Cmd {139+ if m.pipe.send == SendAsk {140+ return m.askSend()141+ }142+ return m.send(m.sendRange())143+}144+145+// askSend asks what to send: the selection, if there is one, or the146+// sheet, or nothing.111147 func (m *Model) askSend() tea.Cmd {112148 var choices []choice113149 if m.hasRange() {@@ -104,8 +104,66 @@ func TestPipeQuitWithoutSending(t *testing.T) {
104104 }105105 }106106 107-// TestPipeCommands: the send commands are in File and the palette only108-// in a pipeline, and run from there.107+// TestPipeSendSelection: with --send selection, Quit sends the108+// selection without asking, or the sheet when only one cell is109+// selected, and the status line says which.110+func TestPipeSendSelection(t *testing.T) {111+ m := stdinModel(t, filesNUON, true, 0)112+ m.SetSend(SendSelection)113+ if st := line(m, m.height-1); !strings.Contains(st, "Ctrl+Q send the sheet as NUON") {114+ t.Errorf("status line %q", st)115+ }116+ press(t, m, "<shift+down>", "<shift+right>")117+ if st := line(m, m.height-1); !strings.Contains(st, "Ctrl+Q send A1:B2 as NUON") {118+ t.Errorf("status line %q", st)119+ }120+ if _, quit := press(t, m, "<ctrl+q>").(tea.QuitMsg); !quit {121+ t.Fatal("asked rather than quit")122+ }123+ if snap, _, ok := m.Piped(); !ok || snap.Range.String() != "A1:B2" {124+ t.Errorf("sent %v %v", snap.Range, ok)125+ }126+127+ m = stdinModel(t, filesNUON, true, 0)128+ m.SetSend(SendSelection)129+ press(t, m, "<down>")130+ cmd, _ := m.runCmdLine("q")131+ if _, quit := run(m, cmd).(tea.QuitMsg); !quit {132+ t.Fatal(":q asked rather than quit")133+ }134+ if snap, _, ok := m.Piped(); !ok || snap.Range.String() != "A1:B3" {135+ t.Errorf("one cell selected sent %v %v", snap.Range, ok)136+ }137+}138+139+// TestPipeSendSheet: with --send sheet, Quit sends the sheet whatever140+// is selected, and Quit without sending is still in the palette.141+func TestPipeSendSheet(t *testing.T) {142+ m := stdinModel(t, filesNUON, true, fileio.CSV)143+ m.SetSend(SendSheet)144+ press(t, m, "<shift+down>")145+ if st := line(m, m.height-1); !strings.Contains(st, "Ctrl+Q send the sheet as CSV") {146+ t.Errorf("status line %q", st)147+ }148+ if _, quit := run(m, m.runCommand("quit")).(tea.QuitMsg); !quit {149+ t.Fatal("File > Quit asked rather than quit")150+ }151+ if snap, k, ok := m.Piped(); !ok || k != fileio.CSV || snap.Range.String() != "A1:B3" {152+ t.Errorf("sent %v %v %v", snap.Range, k, ok)153+ }154+155+ m = stdinModel(t, filesNUON, true, 0)156+ m.SetSend(SendSheet)157+ if _, quit := run(m, m.runCommand("pipe.quit_unsent")).(tea.QuitMsg); !quit {158+ t.Fatal("Quit without sending didn't quit")159+ }160+ if _, _, ok := m.Piped(); ok {161+ t.Error("Quit without sending sent")162+ }163+}164+165+// TestPipeCommands: the send commands and Quit without sending are in166+// File and the palette only in a pipeline, and run from there.109167 func TestPipeCommands(t *testing.T) {110168 titles := func(m *Model) []string {111169 var out []string@@ -115,11 +173,12 @@ func TestPipeCommands(t *testing.T) {
115173 return out116174 }117175 m := newModel()118- if slices.Contains(titles(m), "Quit and send sheet") || len(m.applicable(menuBar[0].items)) != len(menuBar[0].items)-2 {176+ if slices.Contains(titles(m), "Quit and send sheet") || len(m.applicable(menuBar[0].items)) != len(menuBar[0].items)-3 {119177 t.Error("send commands outside a pipeline")120178 }121179 m = stdinModel(t, filesNUON, true, 0)122- if !slices.Contains(titles(m), "Quit and send sheet") || !slices.Contains(titles(m), "Quit and send selection") {180+ if !slices.Contains(titles(m), "Quit and send sheet") || !slices.Contains(titles(m), "Quit and send selection") ||181+ !slices.Contains(titles(m), "Quit without sending") {123182 t.Error("send commands missing in a pipeline")124183 }125184 if commands["pipe.send_selection"].available(m) {@@ -258,16 +258,16 @@ func isMoveKey(key string) bool {
258258 func (m *Model) openGoto() {259259 m.openText("Go to:", m.cur.String(), func(m *Model, text string) tea.Cmd {260260 if !m.gotoText(strings.TrimSpace(text)) {261- m.fail("Not a cell, range or named range: " + text)261+ m.fail("Not a cell, range, named range or region: " + text)262262 }263263 return nil264264 })265265 m.prompt.indicator = "POINT"266266 }267267 268-// gotoText goes to a cell, range or named range, on any sheet, and269-// reports whether text named one. A sheet may lead: Sheet2!A1,270-// 'Q3 plan'!B2:C9, or just Sheet2!.268+// gotoText goes to a cell, range, named range or region's table (nu.r1,269+// as formulas name it), on any sheet, and reports whether text named270+// one. A sheet may lead: Sheet2!A1, 'Q3 plan'!B2:C9, or just Sheet2!.271271 func (m *Model) gotoText(text string) bool {272272 target := m.sheet273273 if name, rest := sheet.SplitSheet(text); name != "" {@@ -286,6 +286,9 @@ func (m *Model) gotoText(text string) bool {
286286 if n, named := m.sheet.LookupName(text); named && !n.Gone() && target == m.sheet {287287 r, ok, target = n.Range, true, n.Sheet288288 }289+ if !ok && target == m.sheet {290+ r, target, ok = m.regionTable(text)291+ }289292 if !ok {290293 return false291294 }@@ -301,3 +304,21 @@ func (m *Model) gotoText(text string) bool {
301304 m.selectRect(r)302305 return true303306 }307+308+// regionTable finds the region formulas name as text (nu.r1), ignoring309+// case, and returns its table, header row included, and its sheet. A310+// region with no rows yet has no table: its first cell stands for it.311+func (m *Model) regionTable(text string) (sheet.Rect, *sheet.Sheet, bool) {312+ const prefix = "nu."313+ if len(text) <= len(prefix) || !strings.EqualFold(text[:len(prefix)], prefix) {314+ return sheet.Rect{}, nil, false315+ }316+ s, reg, ok := m.book().Region(text[len(prefix):])317+ if !ok {318+ return sheet.Rect{}, nil, false319+ }320+ if t, ok := s.RegionTable(reg.Name); ok {321+ return t, s, true322+ }323+ return sheet.Rect{From: reg.At, To: reg.At}, s, true324+}@@ -24,9 +24,14 @@ import (
2424 //2525 // - A chart is an image only where the whole of its plot area shows: in2626 // the grid, under no chart drawn later and no floating box (a menu,27-// a dialog, formula suggestions, a note). Elsewhere it is text. The28-// frame keeps blank cells where an image goes, so the renderer has29-// nothing to write there.27+// a dialog, formula suggestions, a note). Elsewhere it is text.28+// - Under an image the frame keeps the text chart, which the image29+// covers whole (every pixel is set). The renderer writes those cells30+// only when the chart changes, and then the image is drawn again.31+// DA1 only says a terminal parses sixel: one that lists it without32+// showing images, or a recording of the text alone (VHS records33+// xterm.js's text layer, not its image layer), shows the text chart34+// rather than an empty plot.3035 // - Images are drawn after the frame: a sixelDrawMsg comes once the3136 // frame has been still for sixelSettle, longer than a frame, and3237 // draws each image with the cursor saved and restored around it.@@ -116,11 +121,6 @@ func (s *sixelState) clock() time.Time {
116121 // off.117122 func (t *terminal) sixelOn() bool { return t.sixel && !t.noImages && t.cellW > 0 && t.cellH > 0 }118123 119-// placed reports whether chart i is an image in the current frame.120-func (s *sixelState) placed(i int) bool {121- return slices.ContainsFunc(s.plan, func(p sixelPlace) bool { return p.chart == i })122-}123-124124 // syncSixel follows msg, after Update has handled it: it encodes the125125 // charts that changed, works out where images go, clears the screen when126126 // one drawn moved, changed or went, and asks for the images to be drawn@@ -68,8 +68,10 @@ func sixelOut(m *Model, msg tea.Msg) string {
6868 6969 func TestSixelImages(t *testing.T) {7070 m, clock := sixelModel(t)71- if len(m.term.six.plan) != 1 || strings.Contains(screen(m), "█") {72- t.Fatalf("plan %v; the plot area isn't blank:\n%s", m.term.six.plan, screen(m))71+ // The text chart stays under the image, for a terminal that says it72+ // has sixel but doesn't show it, or a recording of the text alone.73+ if len(m.term.six.plan) != 1 || !strings.Contains(screen(m), "█") {74+ t.Fatalf("plan %v; no text chart under the image:\n%s", m.term.six.plan, screen(m))7375 }7476 if !strings.Contains(screen(m), "1,500") {7577 t.Error("the axes aren't text around the image")@@ -9,7 +9,9 @@
99 // - every docs/...md path Go code names exists;1010 // - every file in docs/media is shown by some doc, comes from a VHS tape1111 // in demos/ (its Output or a Screenshot), and no GIF is over maxGIF;12-// - every tape in demos/ records something a doc shows.12+// - every tape in demos/ records something a doc shows;13+// - every docs page the site has published is still a page, or has a14+// redirect from its address in website/redirects.json (redirects.go).1315 //1416 // What the docs say about the program (keys, menus, commands, options) is1517 // checked by tests next to the code they name: internal/ui's docs_test.go@@ -44,6 +46,7 @@ func main() {
4446 problems = append(problems, checkTree(docs)...)4547 problems = append(problems, checkGoPaths()...)4648 problems = append(problems, checkMedia(docs)...)49+ problems = append(problems, checkRedirects(docs)...)4750 for _, p := range problems {4851 fmt.Println(p)4952 }@@ -0,0 +1,116 @@
1+package main2+3+import (4+ "encoding/json"5+ "fmt"6+ "os"7+ "os/exec"8+ "path"9+ "slices"10+ "strings"11+)12+13+// The docs site keeps its old addresses: a page that moves or goes14+// leaves a redirect in website/redirects.json, from its old address to15+// where its reader goes now. The site's build checks that each redirect16+// leads to a page; checkRedirects checks that none is missing, by17+// finding every docs page the site has had since it began (in git's18+// history) that isn't a page any more.19+20+// siteConfig is the file whose first commit began the site.21+const siteConfig = "website/docusaurus.config.ts"22+23+// redirectsFile lists the site's redirects.24+const redirectsFile = "website/redirects.json"25+26+// checkRedirects reports each docs page the site has published that is27+// gone without a redirect from its address. Without git or the history28+// back to the site's beginning (a shallow clone), there is nothing to29+// compare with, and it checks nothing.30+func checkRedirects(docs map[string]*doc) []string {31+ published, ok := publishedPages()32+ if !ok {33+ return nil34+ }35+ b, err := os.ReadFile(redirectsFile)36+ if err != nil {37+ return []string{redirectsFile + ": " + err.Error()}38+ }39+ var redirects []struct{ From, To string }40+ if err := json.Unmarshal(b, &redirects); err != nil {41+ return []string{redirectsFile + ": " + err.Error()}42+ }43+ from := map[string]bool{}44+ for _, r := range redirects {45+ from[r.From] = true46+ }47+ var problems []string48+ for _, p := range published {49+ if _, still := docs[p]; still {50+ continue51+ }52+ if url := pageURL(p); !from[url] {53+ problems = append(problems, fmt.Sprintf("%s: gone, but the site has published it at %s: add a redirect from there in %s", p, url, redirectsFile))54+ }55+ }56+ return problems57+}58+59+// publishedPages lists the docs pages that existed when the site began60+// or were added, changed or deleted since, sorted.61+func publishedPages() ([]string, bool) {62+ adds, err := gitLines("log", "--diff-filter=A", "--format=%H", "--", siteConfig)63+ if err != nil || len(adds) == 0 {64+ return nil, false65+ }66+ first := adds[len(adds)-1]67+ then, err := gitLines("ls-tree", "-r", "--name-only", first, "--", "docs")68+ if err != nil {69+ return nil, false70+ }71+ since, err := gitLines("log", "--no-renames", "--format=", "--name-only", first+"..HEAD", "--", "docs")72+ if err != nil {73+ return nil, false74+ }75+ var pages []string76+ for _, p := range append(then, since...) {77+ if isPage(p) {78+ pages = append(pages, p)79+ }80+ }81+ slices.Sort(pages)82+ return slices.Compact(pages), true83+}84+85+func gitLines(args ...string) ([]string, error) {86+ out, err := exec.Command("git", args...).Output()87+ if err != nil {88+ return nil, err89+ }90+ return strings.Fields(string(out)), nil91+}92+93+// isPage reports whether p, a path under docs/, is a page of the site:94+// Markdown not excluded by a leading _ (see the docs preset's exclude).95+func isPage(p string) bool {96+ if path.Ext(p) != ".md" {97+ return false98+ }99+ for _, part := range strings.Split(p, "/") {100+ if strings.HasPrefix(part, "_") {101+ return false102+ }103+ }104+ return true105+}106+107+// pageURL is where the site serves the page at p: its path without108+// .md and with a trailing slash, a folder's README.md at the folder's109+// address.110+func pageURL(p string) string {111+ p = strings.TrimSuffix(p, ".md")112+ if base := path.Base(p); base == "README" {113+ p = path.Dir(p)114+ }115+ return "/" + p + "/"116+}@@ -3,6 +3,10 @@ import type {Config} from '@docusaurus/types';
33 import type * as Preset from '@docusaurus/preset-classic';44 import {themes as prismThemes} from 'prism-react-renderer';55 import repoLinks from './src/remark/repo-links';6+// The addresses of pages that moved or went, each to where its reader7+// goes now; doccheck makes sure every docs page the site has published8+// is still a page or is here.9+import redirects from './redirects.json';610 711 const repo = 'https://github.com/FelineStateMachine/012';812 const repoDir = path.resolve(__dirname, '..');@@ -57,6 +61,10 @@ const config: Config = {
5761 ],5862 ],5963 64+ // A page at each old address that sends its reader on (a static host65+ // can't redirect by itself).66+ plugins: [['@docusaurus/plugin-client-redirects', {redirects}]],67+6068 themes: [6169 [6270 '@easyops-cn/docusaurus-search-local',@@ -7,6 +7,7 @@
77 "name": "012-website",88 "dependencies": {99 "@docusaurus/core": "3.10.2",10+ "@docusaurus/plugin-client-redirects": "3.10.2",1011 "@docusaurus/preset-classic": "3.10.2",1112 "@easyops-cn/docusaurus-search-local": "0.55.3",1213 "@fontsource/ibm-plex-mono": "5.3.0",@@ -3640,6 +3641,30 @@
36403641 "react-dom": "*"36413642 }36423643 },3644+ "node_modules/@docusaurus/plugin-client-redirects": {3645+ "version": "3.10.2",3646+ "resolved": "https://registry.npmjs.org/@docusaurus/plugin-client-redirects/-/plugin-client-redirects-3.10.2.tgz",3647+ "integrity": "sha512-z5I5ttCXw+8y2gHVZvqAMmUw4Rb0ZzKA5eCPk87SfM/jCKOTvE24yDpPAwwipvug96ij7mOwEHXWw8G4LlWdGA==",3648+ "license": "MIT",3649+ "dependencies": {3650+ "@docusaurus/core": "3.10.2",3651+ "@docusaurus/logger": "3.10.2",3652+ "@docusaurus/utils": "3.10.2",3653+ "@docusaurus/utils-common": "3.10.2",3654+ "@docusaurus/utils-validation": "3.10.2",3655+ "eta": "^2.2.0",3656+ "fs-extra": "^11.1.1",3657+ "lodash": "^4.17.21",3658+ "tslib": "^2.6.0"3659+ },3660+ "engines": {3661+ "node": ">=20.0"3662+ },3663+ "peerDependencies": {3664+ "react": "^18.0.0 || ^19.0.0",3665+ "react-dom": "^18.0.0 || ^19.0.0"3666+ }3667+ },36433668 "node_modules/@docusaurus/plugin-content-blog": {36443669 "version": "3.10.2",36453670 "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.10.2.tgz",@@ -60,7 +60,7 @@ const cells: Cell[] = [
6060 },6161 {6262 addr: 'A3',63- entry: "'ls | to nuon | ^012 --pipe | from nuon",63+ entry: "'ls | sheet | where size > 1kb",6464 hint: 'Nushell: pipelines, notebooks, types, a cookbook',6565 title: 'Nushell, both ways',6666 body: "A stage in a nushell pipeline with file sizes, durations and dates kept, or a notebook where each pipeline's table is a live, named region that formulas and charts read.",