# maintenance-timer

A drop-in vanilla-JS primitive for **recurring service intervals**. Give it a
last-done date + a cadence and it renders the next-due date, a live countdown, a
due/overdue **status pill**, and a **progress bar** of the interval consumed — so
no operator ever does the "when is this next due?" math by hand.

The interval-based cousin of [`../date-counter/`](../date-counter/) (which counts
down to one fixed date). Use `date-counter` for a one-off deadline;
`maintenance-timer` for anything that recurs on a cadence.

## Live URL

```
https://assets.gf.cx/maintenance-timer/maintenance-timer.js
https://assets.gf.cx/maintenance-timer/maintenance-timer.css
```

## Usage

```html
<link rel="stylesheet" href="https://assets.gf.cx/maintenance-timer/maintenance-timer.css">
<script src="https://assets.gf.cx/maintenance-timer/maintenance-timer.js" defer></script>

<!-- Minimal -->
<div data-maintenance data-label="Descale" data-last="2026-08-13" data-interval="6mo"></div>

<!-- Full: sub-line + a "mark done today" button backed by localStorage -->
<div data-maintenance
     data-label="Descale"
     data-detail="DeLonghi EcoDecalk"
     data-last="2026-08-13"
     data-interval="6mo"
     data-store="delonghi-ec9255-descale"></div>

<!-- Never logged: omit data-last → renders overdue-red "NEVER LOGGED" -->
<div data-maintenance data-label="Descale" data-interval="6mo"></div>
```

After dynamic DOM insertion call `window.MaintenanceTimer.refresh()`.

## Attributes

| Attribute | Required | Meaning |
|---|---|---|
| `data-maintenance` | ✓ | Marker (value ignored) |
| `data-label` | — | Task name, e.g. `"Descale"` |
| `data-last` | — | `YYYY-MM-DD` last done. Omit → "never logged" |
| `data-interval` | — | Cadence: `Nd` `Nw` `Nmo` `Ny` (default `6mo`) |
| `data-detail` | — | Sub-line under the label (product / note) |
| `data-store` | — | localStorage key → shows a "✓ Mark done today" button |

## The `data-store` provenance handshake

`data-last` in the committed HTML is the **source of truth**. When `data-store`
is set, a "✓ Mark done today" button appears; clicking it stamps today into
`localStorage` (`mt:<key>`), which **overrides the baked date locally** and
surfaces the exact `data-last="…"` line to paste back into the page. The browser
never becomes the record — it just tells you what to commit. This keeps the
git-tracked page authoritative while giving a one-tap "I just did this" affordance
(the same pattern as the work-log: the ledger is the truth, the tool eases the write).

## Status bands

| Days until due | Class | Pill |
|---|---|---|
| never logged | `.mt-never` | red · `NEVER LOGGED` |
| past | `.mt-overdue` | red · `OVERDUE 12d` |
| 0–7d | `.mt-due` | red · `DUE NOW` / `DUE 3d` |
| 8–30d | `.mt-soon` | amber · `DUE 3w` |
| > 30d | `.mt-ok` | green · `DUE 5mo` |

## Theming

Self-contained + adapts to `prefers-color-scheme`. Override tokens per surface:
`--mt-radius`, `--mt-ok/-soon/-due/-overdue/-never`, `--mt-track`, `--mt-ink-soft`.

## First consumer

The 6-month descale cadence on the DeLonghi EC9255M La Specialista Arte Evo page
(`home.gf.cx/household/delonghi-ec9255m-la-specialista-arte-evo`) — 2026-08-13.

## Siblings in the toolkit

- `../date-counter/` — one fixed future date, two readings
- `../status-pill/` — the standalone status pill
- `../depth-timeline/` — historical event depth
