# Baseline 1.0.0: the shared site template

This package is the shared template of Jeff Posluns's 6 project sites (secureconfig.ai, opfiles.ai, auditthis.ai, cleanlanguage.ai, aiqt.ai, grclibrary.ai): 1 stylesheet, 1 palette file, 4 fonts, 3 scripts, the logos and marks, and 7 reference pages that fix the markup. A site that copies it, sets its site class and generates its pages with the reference markup looks and behaves as part of the family and differs only in its colours, logo and content. The normative description is the template specification 1.0, `SPECIFICATION.md` in this package; the content guidelines 1.0, `CONTENT-GUIDELINES.md`, govern the wording, and the Clean Language standard (https://cleanlanguage.ai) governs the prose.

A published version never changes. Any change is a new version at `https://posluns.ca/baseline/<version>/`.

## What is in the package

| Path | Content |
|---|---|
| `baseline.css` | The whole shared stylesheet: reset, typography, layout, every component, the footer's container query stages and their fallback. Reads only the tokens in `palettes.css` and the family and layout tokens it declares at the top. |
| `palettes.css`, `gen_palettes.py`, `contrast-report.txt` | The 6 site palettes (light, dark, and `[data-scheme]` forced variants for previews), the cyclic rainbow and the footer's neutral grey. `gen_palettes.py` writes `palettes.css` and the report beside itself and exits non-zero if any text pair misses 4.5:1 (UI pairs 3:1). Edit the script, never the CSS. |
| `fonts.css`, `fonts/` | Newsreader, Public Sans, JetBrains Mono and Dancing Script, latin subsets, variable weight, each with its SIL OFL 1.1 licence file. The font paths are relative to `fonts.css`. |
| `copy.js`, `select.js`, `search.js` | Copy to clipboard for prompt and command blocks; the install selector; the client-side list filter. Each is opt-in per page and enhances markup that works without it. Load with `defer`. |
| `logos/` | Per site: `<site>.svg` (full colour: hero, rail, footer), `<site>-mono.svg`, `<site>-favicon.svg`, `<site>-card.svg` (link preview). |
| `marks/` | GitHub, LinkedIn and ORCID marks for the footer, with `marks/NOTICE.md` (sources, dates, terms). |
| `reference/` | 7 reference pages, 1 per page type (section "The reference pages" below). |
| `tools/measure.js` | Measures the 2 per-site constants (section "Per-site constants"). |
| `SHA256SUMS`, `LICENSE`, `NOTICE.md`, `CHANGELOG.md` | Checksums of every file; CC0 1.0; the exceptions (fonts, marks); history. |

## Adoption in a repository

1. Copy this version's files into the site's own asset folder (proposed `assets/baseline/`), verifying every file against `SHA256SUMS` at copy time: `sha256sum -c SHA256SUMS` from the version folder.
2. Record the version and each file's SHA-256 in a pin file (proposed `.baseline/PIN`, the same format as `.aiqt/PIN`).
3. Add an offline gate that fails if any copied file differs from the pin. No gate reaches the network.
4. Put `class="site-<name>"` on `<html>` (`site-secureconfig`, `site-opfiles`, `site-auditthis`, `site-cleanlanguage`, `site-aiqt`, `site-grclibrary`). That class, the logo files and the content are the only per-site differences. A site must not add CSS that overrides `baseline.css`; a need the template cannot meet is a change request to the baseline.
5. Generate every page from the site's own sources with the markup of the reference pages; they are the contract. Every page links `fonts.css`, `palettes.css` and `baseline.css` in that order, carries the skip link, the top bar, 1 `h1`, the footer and the `#copy-status` live region, and contains no inline style, inline script or `on*` attribute.
6. Update the site's own gates where they conflict (`SPECIFICATION.md`, section 11).
7. Updates arrive as 1 pull request per site that bumps the pin and the copied files.

### Staging at `/draft/` and promotion

1. Base path. Generate every page, asset and internal link with a configurable base path: `/draft/` while staging, `/` after promotion. The draft is self-contained: no draft page links to, or loads anything from, the live pages at the root. The baseline files are copied under the draft (`/draft/assets/baseline/`) and move with it. Every path in this package is relative, so the files work at any base path.
2. Kept out of search and away from the live site. Every draft page carries `<meta name="robots" content="noindex, nofollow">`; `_headers` sends `X-Robots-Tag: noindex` for `/draft/*`; the draft is absent from `sitemap.xml`, `llms.txt` and every other index the live site publishes; the live pages never link to it.
3. Live site unchanged. Building the draft changes no live page, path, redirect or published file. Every existing gate keeps passing on the live tree; gates that scan every HTML file either cover the draft under the template's rules or exclude `/draft/` explicitly, and the exclusion is removed at promotion.
4. Review. The draft is complete when every page of the site's page list exists under `/draft/`, the site's checks and the content guidelines checklist pass, and the implementer has reported to the owner with the draft's URL.
5. Promotion, after the owner's approval only. In 1 pull request: remove the old pages from the published tree (they remain in git history); rebuild the draft with base path `/`; add redirects for every old public path that changes; restore the root's `sitemap.xml`, `llms.txt` and other indexes for the new pages; remove the `/draft/` noindex rules and any gate exclusion; verify every fixed path on the preview deployment before merging.

### Site class, logo and base path

- The site class on `<html>` selects the palette (`palettes.css`) and the per-site constants in `baseline.css` (`--sw`, `--logo-inset`, `--tail-from`).
- The logo appears once per page: in the hero on the landing page (`.hero-art img`), above the rail on every other page (`.rail-logo`); the footer uses all 6 full-colour logos; `<link rel="icon" href="<base>assets/baseline/logos/<site>-favicon.svg" type="image/svg+xml">` in the head; the card logo is for link previews.
- The top bar of every site ends its internal items with "Disclosure" then "Licence", then the external GitHub item where the site has one. The licence page lives at `/license/` (heading "Licence"), the disclosure page at `/disclosure/`.
- aiqt.ai's rules page keeps the anchors `#rule1` to `#rule5` on its 5 clause sections, so the live redirects from `/rule1` to `/rule5` keep working.

## The reference pages

Each page in `reference/` is built for 1 example site and opens directly from the folder, in light or dark mode as the operating system prefers. Cross-links between pages that exist in the set go to that page; links to pages of the example site that are not in the set go to `landing.html`, so the set stays self-contained. The pages are markup examples, not a site.

| Page | Example site | What it fixes |
|---|---|---|
| `landing.html` | secureconfig.ai | The hero (kicker, statement, introduction, start link, logo), the "Start here" entry tiles, the "What it gives you" value paragraph, the footer |
| `document.html` | aiqt.ai, the standard | The document grid with label column, rail ("On this page"), document control strip, numbered clauses, callout, Next block |
| `reference.html` | aiqt.ai, mappings | Figures, framed registers, a fixed-layout table with `colgroup` widths and wrapping cells, a commit in 7-character form, details blocks |
| `install.html` | cleanlanguage.ai | The selector (`select.js`), download blocks, copy buttons (`copy.js`), steps, the "Last verified" line |
| `license.html` | auditthis.ai | The licence page: scope sentence, parts under another licence, the complete plain-language summary, the owner's note, Next |
| `disclosure.html` | opfiles.ai (entries quoted from the AIQT disclosure as an example of the format) | The disclosure page: opening sentence, entries of claim, limitation and evidence, the vulnerability disclosure line, Next |
| `404.html` | grclibrary.ai | The 404 page with the logo-only rail |

## Per-site constants

Two values in `baseline.css` depend on a site's content and are measured, not designed:

- `--sw` (per site, light and dark): the hero statement's width on 1 line in em. `font-size: clamp(3.2rem, 98cqw / var(--sw), 5rem)` then puts the statement on 1 line whenever that fits at 3.2rem or more. Re-measure whenever the statement's words change: `node tools/measure.js statement <url or file of the landing page>` prints the light and dark values; set them in the site's own `site.css`, loaded after `baseline.css` (`.site-<name> .statement { --sw: ...; }`, and the dark value inside `@media (prefers-color-scheme: dark)`). Never edit the copied `baseline.css`: the pin and its checksum must keep matching. The values shipped in `baseline.css` are those of the 6 approved statements.
- `--logo-inset` (per site): the logo artwork's visible left margin as a fraction of the SVG box, used to indent the rail's text under the artwork's left edge. Re-measure whenever a logo changes: `node tools/measure.js logo logos/<site>.svg`, and set the value in `site.css` as for `--sw`.

`tools/measure.js` needs Node and the `playwright` package with Chromium (`npx playwright install chromium`). It makes no network requests other than loading the page you name.

## Security contact

Each domain should publish `/.well-known/security.txt` pointing at the owner's vulnerability disclosure policy, `https://posluns.ca/security/`, and the disclosure page's closing line links to the same policy.

## Checking a build

- No en or em dash in any file; no inline style or script; no `on*` attribute; every external link with `target="_blank" rel="noopener noreferrer"` and a visually hidden "(opens in a new tab)".
- Render at 390, 820, 1180, 1512 and 2000 px in light and dark: no horizontal scroll; the footer on 1 line from 600 px of content width and on 2 lines below it; the hero statement on 1 line at 1440 px and above for a 1-sentence statement.
- The landing page within 2 screens at 1180 by 820; body text 20 px on desktop and 18 px on phones.
