makeover-webview 0.97.0

The webview renderer for makeover-layout. Emits CSS, and is the one renderer that needs no palette: var() is the late binding, so resolution stays with the browser.
Documentation
# makeover-webview

The webview renderer for
[`makeover-layout`](https://makenot.work/git/max/makeover-layout). Emits CSS.

## The renderer that needs no palette

`makeover-immediate` and `makeover-tui` both take a `Palette`, because egui and
a terminal need an actual colour before they can put anything on screen. A
webview does not. `var(--surface-raised)` *is* the late binding, and the browser
resolves it against whatever the theme layer last wrote onto `:root`.

So this crate emits text naming intents and never learns a colour. It is also
why the webview is the wrong renderer to derive a vocabulary from: it can
express anything, so it never pushes back.

## The stylesheet

`stylesheet(&Emit)` writes the component CSS: depths, controls, tokens,
selectors, rows, tables, facets, meters, charts, figures and placeholders. An
app that builds its own markup keeps every line of it and gains the classes.

```css
:root {
    --bevel-raised: inset 1px 1px 0 var(--bevel-light), inset -1px -1px 0 var(--bevel-dark);
    --bevel-inset: inset 1px 1px 0 var(--bevel-dark), inset -1px -1px 0 var(--bevel-light);
}

.raised { background: var(--surface-raised); box-shadow: var(--bevel-raised); }
.well { background: var(--surface-well, var(--surface-page)); box-shadow: var(--bevel-inset); }
.button:active { background: var(--surface-well, var(--surface-page)); box-shadow: var(--bevel-inset); }
```

The depth classes are surfaces and nothing more, and the states belong to the
named surfaces. `.button` is that same depth *and* a control, so it carries
hover, press, focus and disabled. `.card` is a raised object, and carries those
states only when it is written on a control: `a.card`, `button.card`,
`label.card`, or a card with `data-act`. A card that is only read has no hover
to cancel.

Hover rules are gated on the pointer density `makeover-touch` and
`makeover-geometry` answer for, never decided here, and every focus ring is the
one `focus_rule` writes.

## The markup

Each module renders one description member to markup, and each has a
`_into` form that writes into a buffer the caller already has:

- `form::field_html` renders a `makeover_layout::Field`: label, control, hint,
  error and note, marked `aria-invalid` and `aria-describedby` from the
  description itself.
- `list::cells_html` renders a row's cells against its columns, and `table`
  holds the rules that narrow a table by column priority.
- `facet`, `meter`, `chart`, `figure` and `placeholder` render the members of
  the same names.

```rust
use makeover_layout::{Field, FieldKind, Value};
use makeover_webview::{Emit, form::{Filling, field_html}};

let field = Field::new(FieldKind::Text, "title", "Title");
let html = field_html(&field, &Filling::of(Value::Text("Ship it")), &Emit::default());
```

Everything is escaped here. One escaper covers both text and attribute sinks,
and the single hole is `form::Markup`, which a caller has to name. The copy the
markup carries (the required marker, the exclude button's name, the markdown
editor's modes) comes from `Emit`, English by default.

Numbers the rules read, such as a bar's value, ride in `data-vars` rather than
`style`, so a page under a `style-src` without `'unsafe-inline'` still draws
them. Serve `VARS_JS` beside the stylesheet to apply them.

The `_placed` forms write the same bytes and also report where each part
landed, for a caller compiling this markup into a template.

## Substitution, three ways

A theme with no `surface-well` is answered differently by each of the three
renderers, which is why substitution belongs to a renderer and not to the
description:

- `makeover-immediate` substitutes the page in Rust.
- `makeover-tui` refuses to substitute and draws an edge, because a terminal
  quantises the two together.
- here, CSS already has the mechanism. `var(--surface-well, var(--surface-page))`
  falls back in the browser and nothing in Rust decides anything.

## Status

On crates.io. Consumers take it directly or through `makeover-build`, which
writes the stylesheet into an app's frontend at build time.

## Licence

MIT.