# Product

<!-- impeccable:product-schema 1 -->

## Platform

web

## Users

**Confirmed by Paul, 2026-09-01: Paul and his collaborators, dogfooding.**
Real use, small N. Design for the people actually in it rather than a
hypothesised market — a feature nobody here uses is not evidence of
anything.

They are running the CARLOS suite already, so Sheets is not entered cold:
a person arrives from the suite home with a session, and the spreadsheet
is one of several apps on one instance. The job is the ordinary one —
put numbers in a shared grid, have the other person see them — under a
storage rule that is stricter than the ordinary one.

Two roles exist beyond the team: a **guest** holds no team-wide rights
and sees exactly the sheets granted to them; a **link viewer** is
anonymous, read-only, and mints no membership at all. Both are real
audiences for the read surfaces even though neither is the primary user.

## Product Purpose

A spreadsheet for one team, on that team's own instance, whose contents
are sealed at rest.

Success is that a team can do its actual spreadsheet work — grid editing,
formulas, live collaboration, import and export — without the storage
layer ever holding a plaintext cell, and without the product lying to
them about what that does and does not protect.

## Positioning

Three claims a neighbouring product could not truthfully copy, all
confirmed binding by Paul on 2026-09-01:

1. **Sealed at rest, honestly scoped.** The bucket never holds a
   plaintext cell. The instance holds the key while it runs, so a
   compromised live host *can* read an open sheet — and the README says
   so. **We never claim "we can't read your data."** The UI must never
   imply otherwise, in copy, in iconography, or by omission.
2. **One instance per team.** Sharing is membership across teams: the
   sheet never moves, and an outside person becomes a scoped member of the
   team that owns it. There is no federation story across teams and there
   will not be one. Within a team, Sheets is one of several apps sharing
   one trust domain (suite ruling 1), and a same-team sibling may pull
   team-visible sheets under the suite contract.
3. **No affordance is script-required.** Sign-in, the sheet list, sharing
   and membership, settings, version history, comments, import and export
   all work scriptless, as does a paginated table view of any sheet with
   per-cell edit forms. The grid editor is an enhancement on top of a
   floor, not the floor.

## Operating Context

- **One binary per instance**, `CGO_ENABLED=0`, cgo-free SQLite,
  deployed to CARLOS. Review happens on a deployed canary, never
  localhost.
- **The suite home is a separate product in a separate repo.** Sheets
  depends on it for identity and consumes a five-call contract; it does
  not define it. Passkeys enroll at the home's origin only — instances
  never enroll them.
- **Sheets sits beside Docs and the home** under the Oficina suite, which
  shares a design system (`estilo`). Chrome that appears in more than one
  app is the suite's, not Sheets'.
- Live collaboration is cell-level last-write-wins over SSE. Version
  history replays inputs and recomputes; derived values are never logged.

## Capabilities and Constraints

**Built and working as of 2026-09-02:** sign-in, sheet list and creation
with a live preview thumbnail on every row, a grid backed by a Go calc
engine, live sync across tabs over SSE, a scriptless paginated table
view with per-cell editing, XLSX import and export (import by upload or
by dragging a file onto the list; it runs as a background job and lands
on the new sheet), and a contrast notice for imported fills.

The editing surface is a menu bar (File, Edit, Insert, Format, Data,
Help), a formatting toolbar, a name box and formula bar, and a tab
strip. Cells carry bold, italic, alignment, a number format, a fill and
a text colour; columns and rows can be resized and stay resized. A
colour picked here is stored as hue and chroma with no lightness, so it
follows the reader's light/dark choice; a colour an imported file
authored is painted exactly as the file wrote it.

**Not reachable yet, though the code is there.** This line previously
read "XLSX/CSV import and export", which was true of the converter and
false of the product. Import stopped being an example of that on
2026-09-02 and **export stopped being one the same day** — `xlsx.Export`
now has a route and File ▸ Download as .xlsx reaches it. What remains
true is CSV: there is no CSV code in the repo at all, and the line above
does not claim any.

**Constraints that bind design:**

- **No build step.** Jspreadsheet CE v5 is vendored as a static asset —
  no CDN, no bundler. Its own formula engine is disabled; Go owns calc.
- **300-line cap on any JS module we write**, test-enforced, ratchet-down
  only. The vendored grid blob is exempt and named as such.
- **Light/dark is per person, not per document** (confirmed binding,
  2026-09-01), and must resolve before first paint from a cookie read
  server-side. Cell fills resolve against the theme, so a late preference
  repaints every coloured cell. Never a fetch.
- **Every drag-only affordance has a menu equivalent.**
- **No cell content, sheet title or tab name in any log line, error
  string, job status or metric label.** Errors carry coordinates and
  codes. This constrains error copy directly.
- Cell values are IEEE doubles end to end; currency is a number format,
  not a type.
- Cell fill is stored as OKLCH intent; an imported hex is retained as
  authored, even when it fails contrast (see Accessibility).
- Link sharing is viewer-or-commenter, **never editor** — an anonymous
  editor would write unattributed rows into version history.

**Explicitly undecided:** the suite's own domain (the passkey relying
party is provisionally an `oncarlos.com` host). Sheets' own visual world
beyond the suite theme — see Brand Commitments.

## Brand Commitments

- **Name:** Sheets, within the **Oficina** suite (CARLOS).
- **Design system:** `rastrillo` (the framework) with **`estilo`** as the
  suite's shared variant. estilo's theme *is* rastrillo's `day` — not
  derived from it, identical — until a **named need** says a token has to
  differ. "It would look better" is explicitly not such a need; the bar
  is "Sheets' grid requires a denser row token that day does not
  declare". Any divergence is recorded as a decision, not applied.
- **Markup grammar:** the attribute spelling (`rst-btn="primary compact"`),
  never the class spelling. Utilities stay classes. Adopt per screen,
  never per element.
- **Voice:** plain, exact, and never reassuring beyond the facts. The
  repo's own prose is the reference — it names its residual risks in the
  same breath as its guarantees.
- **Authorship is disclosed.** 🤖 / 👨 markers, published prompt and
  carbon ledgers. Every path works with AI switched off.

## Evidence on Hand

- `docs/superpowers/specs/2026-08-30-sheets-design.md` — the design spec.
  §1 is a dated, attributed settled-decisions table with the rejected
  alternative beside each ruling. §2 is the leak list. §14 is the
  deferred table, each row carrying a written trigger.
- `AGENTS.md` — binding engineering rules, several of them design-facing.
- A working deployment at `https://sheets.bds.oncarlos.com`.
- `tools/drive/drive.mjs` — drives the real binary in a real browser,
  for live sync across two tabs.
- `tools/drive/chrome.mjs` — its sibling, for the editing chrome: the
  menu bar, the toolbar, the formula bar, the cell paint, export, and
  the 320px reflow budget. It earned its place on the day it was
  written, by finding a menu bar that worked perfectly from the keyboard
  and not at all with a mouse.

**Absences future work must not fabricate:** there are no customers, no
testimonials, no benchmarks, no pricing and no usage numbers. There is no
market claim of any kind. Sheets is being dogfooded by its author and his
collaborators, and nothing in the product may suggest more than that.

## Product Principles

1. **Say the true thing, including the unflattering half.** The trust
   model is a genuine differentiator *and* has a named residual risk. Copy
   that states the first without the second is a defect, not a
   simplification.
2. **The scriptless path is the product, not the fallback.** If an
   affordance exists in the grid and not in the table view, the table view
   is unfinished. "Fallback" is the wrong word and invites the wrong
   design.
3. **One instance, one team, no federation.** Never design a flow that
   implies data can move to another instance, or that a person outside
   this team is a first-class participant.
4. **The chrome is the suite's; the grid is ours.** Anything that appears
   in Docs and the home too belongs to `estilo` and should look identical
   there. A spreadsheet's menu bar and formula bar are Sheets'.
5. **A preference resolves before first paint or it is a bug.** This is a
   correctness rule that happens to be about design.

## Accessibility & Inclusion

- **WCAG AA (4.5:1) is the floor for text**, and it is test-enforced
  against the theme's own pairs.
- **A retained imported fill may fail that floor, and that is correct.**
  Rendering an imported file as authored is the ruling; silently
  correcting a colour would lie about the document. The obligation that
  follows is to *say so* — a per-cell marker plus a notice — and leave
  the decision to the person. Never quietly recolour a cell.
- **The page header's rule is decorative and carries no contrast floor.**
  It is deliberately absent from rastrillo's contrast pair table; a later
  pass must not argue it up to 1.4.11's 3:1.
- **The theme switcher must work with scripting off** — a person who
  needs a high-contrast theme is not well served by being told to enable
  JavaScript first.
- Three light/dark states, not two: "follow the machine" is a real
  preference.
