Theme Table
Blocks & themesPreviewTable, a Tome theme for places people visit (restaurants and cafés first, then bars, bakeries, venues and boutique retail): a Now Bar that answers "are you open", a photo-first menu with prices on the dish's baseline, Fraunces with palette-set axes and tabular Work Sans figures, the accent as punctuation. Two palettes (Linen, Garden) plus dark, self-hosted OFL fonts, activated by data-tome-theme="table".
Get a registry token from your credentials page. You need a purchase that includes this package, or a Craft Library membership.
Add the registry and your token to the
.npmrcat the root of your project, with your token in place ofYOUR_TOKEN:@wabbit:registry=https://npm.wabbit.com/ //npm.wabbit.com/:_authToken=YOUR_TOKENThen install:
npm install @wabbit/tome-theme-table
Overview
@wabbit/tome-theme-table
Table is a Tome theme for places people visit: restaurants and cafés first, then bars, bakeries, breweries, venues, salons and boutique retail. Its stance is "Come in. Here's what's on tonight." The site should feel like the place itself, and it answers the visitor's three questions (are you open, what's good, how do I get there) before it tries to charm anyone. A sticky Now Bar carries the live opening state on every page; the menu is the sales argument, with every dish's own photograph and its price on the same baseline as its name. It ships two palettes, Linen (an upscale dining room, the default) and Garden (a café or brunch room), each in light and a derived dark. Each palette sets the display face's axes and the radius scale as well as its colours, so one type system spans a brunch café and a quiet dining room.
This package is a theme (a ThemeManifest of kind: 'theme'). It owns no blocks. It declares the whole token surface blocks read, self-hosts its two OFL font families, and restyles blocks and chrome through their public hooks.
Layer: ui · Family / tier: themes / addon · Versioning: independent.
Install
pnpm add @wabbit/tome-theme-table| Peer | Range | Required | |---|---|---| | @wabbit/tome-ui | >=0.18.0 <1.0.0 | yes | | @wabbit/tome-core | >=1.21.1 <2.0.0 | no (optional) |
@wabbit/tome-ui is a CSS-contract peer. Its tokens.css re-declares the var()-aliased Layer 2 under [data-tome-theme] and defines the fixed-band ink family this theme sets, and 0.18.0 is the release that ships the platform scroll reveal Table turns on. @wabbit/tome-core is needed only for the ./register subpath and the ThemeManifest type. The package imports no React and no Payload.
Table's treatments style hooks that the same release adds (the Table v1 hook contract): the new @wabbit/tome-blocks-local-pack (local-price-list, local-live-status, local-logistics and its ordering island), the high-impact-hero venue variant, the contact reserve variant, and chrome's announcementSlot and headerPosition. On older block packs the theme still applies, and those parts render with the blocks' own look.
Usage
Import the stylesheet once at the app root, after tome-ui's tokens, and activate the theme on <html>:
// app/layout.tsx
import '@wabbit/tome-ui/tokens.css'
import '@wabbit/tome-theme-table/styles.css'
import '@wabbit/tome-theme-table/fonts.css'<html data-tome-theme="table"> <!-- Linen, light -->
<html data-tome-theme="table" data-tome-palette="garden" data-table-effect="grain">With no data-tome-palette the theme renders Linen. Table is designed light: light pages with dark bands (the Now Bar, the reserve band, the menu page's pickup band). data-theme="dark" gives a full dark page, derived from each palette's band colour; it is allowed, contrast-checked, and not the default. The true dark palette (Cellar) is a later palette. The bands stay dark in both modes.
To have the admin ThemeSwitcher, createThemeConfig() and other registry readers list it, register it on the server before building the Payload config:
import '@wabbit/tome-theme-table/register'The Now Bar: local-live-status in chrome's announcementSlot
Render LocalLiveStatusAnnouncement from @wabbit/tome-blocks-local-pack/render (the local-live-status block, variant bar) in the header's `announcementSlot`. Chrome places it before the header frame, sticky at the top, and publishes its height as --tome-announcement-height; every sticky offset and scroll margin in the theme reads that variable, never a constant. At 640px and up the bar is one 44px row: the status dot (hollow when closed), "Open now · kitchen closes at 2:30" (the theme draws the · between [data-live-lead] and [data-live-detail]), the phone number, Directions and one state action as a pill on the band action. Below 640px it becomes the page's most prominent element: the lead in Fraunces, the detail beneath it, and three equal 44px pills (Call, Directions, the action); when the state action is Directions the separate link hides and the row becomes 1fr 2fr.
Header: Navbar 5 with headerPosition: 'static'
Set the Header global to Navbar 5 (Simple), `headerPosition: 'static'` and the page background: a plain header on the page ground that scrolls away under the sticky Now Bar. Nav links are Work Sans 500 with no hover fill; hover and the current page (aria-current="page") take a 2px accent underline. The CTA ("Book a table", "Reserve a table") is a 44px ink pill through chrome's --tome-header-cta-* seam. Below 1024px the links collapse into chrome's menu sheet.
The wordmark is your LogoComponent, marked with the theme's hook:
<span data-table-wordmark>Tansy</span>It renders the venue name in Fraunces at the palette's axes, in the header and in footer 7.
On a menu page with ordering on, render the ordering island's OrderButton in the header's `accountSlot` (and leave the route's CMS CTA out): an ink pill "Your order" with a count chip that bumps for 180ms on change. On phones the order lives in the floating pill.
Footer: footer 7
Set the Footer global to design version '7', with `backgroundColor: 'muted'` for Linen (Garden keeps the page ground). Put the five links in one column; the theme flattens it to a row (--tome-footer-nav-cols: 1, the group title kept for screen readers) and lays out one row at 1024px: the wordmark, the links, the copyright line on the right, in muted Work Sans under a top hairline. There is no footer CTA band: the reserve band and Find Us close the page.
The sections
| Section | Block | Notes | |---|---|---| | Hero | high-impact-hero, variant venue | venue.mediaPlacement: behind (Garden: copy over the photo, the scrim's floor 62% under the copy) or above (Linen: the room, then the name on the cloth across ten columns). The scrim is --tome-hero-scrim, set by the theme from the palette's scrim ink. | | Menu teaser (home) | local-price-list, variant teaser | Photo panel and numbered list; hover or focus brings a row forward and swaps the photo; phones give each row a thumbnail. | | Book or order | contact, variant reserve (with a provider) | The link-out GET form, the sample slot chips with their label, "Or:" alternatives. | | Find Us | local-logistics, variant split | The illustrative map with its label, the address, Get directions and the phone, the hours with today's group in accent text, Getting here and Access. | | Featured dish and menu (menu page) | local-price-list, variant card-grid | The featured band with the stamp, the numbered rail, mastheads, photo cards with in-card details, one grid-breaker. ledger is the printed-list alternative for bars and salons. | | Pickup / "At home" (menu page) | contact, variant reserve (no provider) | No form: "Review your order" opens the drawer, Call, three facts, Garden's pickup-time chips. | | Order drawer and pill | the local pack's ordering island | A native <dialog> on the card colour sliding from the right over a 45% scrim, the floating pill bottom right (full width on phones). Checkout hands off to the venue's ordering URL with the demo label beside it. |
Scroll reveal
Table turns on tome-ui's opt-in platform scroll reveal (--tome-reveal: on) with a touch quicker timing than Groundwork's for its lively rhythm: --tome-reveal-rise 12px, --tome-reveal-duration 420ms, --tome-reveal-stagger 60ms, the theme's ease-out. Dish cards and teaser rows are reveal items, so a category's cards stagger in. It runs only where the site mounts the controller once:
import { TomeReveal } from '@wabbit/tome-ui/reveal'
<TomeReveal />data-tome-reveal="off" on <html>, a region or a block root turns it off there. Under reduced motion there is no reveal, crossfade, photo scale, drawer slide or smooth scroll; state changes still apply (the drawer opens, the panel shows, the stepper swaps). The Now Bar never animates.
Fonts
Fraunces and Work Sans ship inside the package as latin-subset woff2 from fontsource 5.3.0, with their SIL OFL 1.1 licences (fonts/OFL-Fraunces.md, fonts/OFL-WorkSans.md; neither has a Reserved Font Name). There is no third-party font request. 167.3 KB for both.
- Fraunces is the
fullcut: one variable file carrying all four axes,opsz9 to 144,wght100 to 900,SOFT0 to 100 andWONK0 to 1. It sets venue names, headings, category and dish names, the rail, the stamp's core and single display prices. Roman only: the theme never sets an italic serif, so no italic file ships. - Work Sans (
wght100 to 900) sets the body, the UI, the meta voice (600, uppercase, 0.14em tracking) and every number that sits in a column or a row: card prices, hours, counts, the drawer. Fraunces has no tabular figures; Work Sans does.
The file's default Fraunces instance is opsz 9, wght 900, WONK 1, so every Fraunces surface in the theme states its axes (font-variation-settings: var(--table-display-fvs) with font-optical-sizing: none), including foreign blocks' h1 to h4. Weight goes through font-weight (the palette's --tome-type-weight-display, the seam ThemeConfig's displayWeights writes), never "wght" inside the variation settings. Pick one delivery path:
import '@wabbit/tome-theme-table/fonts.css': the bundler resolves the files from this package.- Your own host: copy the files from
@wabbit/tome-theme-table/fonts/*and injectgetTableFontStyles({ src }). next/font/local, using the file list fromgetTableFontFaces().
import { getTableFontPreloads } from '@wabbit/tome-theme-table/fonts'
{getTableFontPreloads({ src: '/fonts/table/' }).map((l) => <link key={l.href} {...l} />)}The grain
There is one opt-in effect: a faint, static fractal-noise grain at 5.5% opacity, multiplied over the page, below chrome and dialogs. Garden's demo turns it on; Linen has none.
<html data-tome-theme="table" data-table-effect="grain">
<section data-table-effect="grain">…</section>Sites can also mark their own section as a dark band with data-table-band="dark", set a meta line with data-table-meta, and give a section label the accent rule with data-table-label.
Public API
| Export | Subpath | Purpose | |---|---|---| | tableThemeManifest (ThemeManifest) | ., ./manifest | The theme's manifest: name table, kind: 'theme', tier addon, two palettes, fonts and one pairing, recommended blocks and chrome (Navbar 5, footer 7), styledBlocks, requires.tomeUi. | | TABLE_PALETTE_IDS, TablePaletteId | ., ./manifest | ['linen', 'garden'], the data-tome-palette values. | | TABLE_STYLED_BLOCKS, TABLE_RECOMMENDED_BLOCKS | ., ./manifest | The block slugs the theme restyles, and the slugs its demo is composed from. | | ThemeManifest (type) | . | Re-exported from @wabbit/tome-core/registry/theme. | | getTableFontFaces(), getTableFontStyles({ src }), getTableFontPreloads({ src }) | ., ./fonts | Font descriptors (with each file's axes), @font-face CSS for a custom host, and preload links. | | TABLE_FONT_STACKS, TABLE_FONT_LICENSES, TABLE_LATIN_UNICODE_RANGE, TABLE_DISPLAY_WEIGHTS, TABLE_UI_WEIGHTS | ., ./fonts | The CSS stacks the tokens use, the licence file per family, the subset range, and the weights used. | | TableFontFace, TableFontPreloadDescriptor, TableFontStylesOptions (types) | ., ./fonts | The descriptor shapes. | | side effect | ./register | Registers tableThemeManifest in tome-core's theme registry. | | stylesheet | ./styles.css | Tokens, treatments and the effect. The file that does everything visual. | | stylesheet | ./fonts.css | The two @font-face rules. Optional. | | font files | ./fonts/* | The woff2 files and their OFL licences, for self-hosting. |
Tokens
The theme sets Layer 1 (--background, --foreground, --card, --primary, --accent, --muted, --border, --input, --ring, the feedback, chart and muted2 names) and lets tome-ui derive the aliased Layer 2. It sets these Layer-2 literals directly: --tome-color-accent-text and the feedback *-text weights, --tome-color-surface-tint, the fixed-band inks (--tome-color-surface-solid-dark and its on-, on-…-muted, accent-on-, primary-on- inks, --tome-color-border-inverse, and the light fixed surface --tome-color-surface-inverse with its inks), and the four --tome-type-* families, each paired with its --font-* slot.
Naming: the mockups' "inverse" band is the platform's solid-dark. tome-ui's "inverse" is the light fixed surface.
Selector ladder (specificity, never load order):
| Selector | Specificity | Holds | |---|---|---| | [data-tome-theme="table"] | 0,1,0 | Linen light (with its axes and radius), type, rhythm, motion | | [data-tome-theme="table"][data-theme="dark"] | 0,2,0 | Linen dark | | [data-tome-theme="table"][data-tome-palette="p"] | 0,2,0 | palette light, with its axes and radius | | [data-tome-theme="table"][data-tome-palette="p"][data-theme="dark"] | 0,3,0 | palette dark |
Every palette rule, light and dark, declares the full colour set plus Table's private colours: --table-leader (the dotted price leader, the mockup's input value), --table-placeholder, --table-band-field-edge, --table-band-action and its ink (the action on every dark band), --table-stamp and its ink, --table-map-ground and --table-map-ink, --table-scrim-ink (the hero scrim and the drawer backdrop) and --table-on-photo (the hero copy over a photo). Each light rule also sets the display axes, weights and radius:
| Token | Linen | Garden | |---|---|---| | --tome-type-weight-display | 340 | 580 | | --table-display-opsz / -soft / -wonk | 144 / 0 / 0 | 40 / 100 / 1 | | --table-display-tracking | -0.02em | -0.015em | | --tome-type-weight-regular (body) | 420 | 450 | | --tome-radius-sm / md / lg / xl / full | 6 / 4 / 4 / 4 / 999px | 6 / 12 / 22 / 22 / 999px | | --radius | 4px | 12px |
Other private tokens use the --table-* prefix: the meta-voice and display sizes (the mockups' 16px-root values times 16/18, since tome-ui's root is 18px), control heights, sticky offsets (from --tome-announcement-height), the four shadows (--table-shadow-chip, -raised, -drawer, -pill: the info button, the breaker panel, the drawer and the order pill, the only shadows in the theme), the scrim floor (62%) and the drawer scrim (45%), the reveal timing (mapped onto tome-ui's --tome-reveal-*), and the grain tile. One section rhythm (--tome-section-py, 56 to 104px), a 600px prose measure, and tome-ui's grid unchanged.
Palettes
| Palette | Ground / surface / muted | Ink / muted ink | Accent / accent text | Band | Band action | |---|---|---|---|---|---| | Linen (default) | #FAF8F4 / #FFFFFF / #F0EDE5 | #1A1A17 / #58564E | olive #5F6B23 / #55601F | #1A1A17, band accent #B5C46E | #F3F0E8 with ink #1A1A17 | | Garden | #EDF2E4 / #F7FAF1 / #E0E9D4 | green #1D3A28 / #455D4C | radish #D23B6E / #A8234F | #1D3A28, band accent #FF7AA6 | radish #B8285A with white |
The accent is punctuation: the section label's rule, the status dot, the rail's active bar, the teaser's active edge, the tag dot, today's hours, kickers and masthead numbers. It is never a large fill.
Contrast
WCAG 2.x. Text at least 4.5; field outlines, accent marks and the focus ring at least 3. The test suite re-measures these floors from the shipped values.
| Pair | Linen | Garden | |---|---|---| | body on page / surface | 16.44 / 17.44 | 10.91 / 11.79 | | muted on page / surface-muted | 6.93 / 6.28 | 6.30 / 5.74 | | accent text on page / surface-muted | 6.43 / 5.83 | 6.10 / 5.56 | | accent mark on page | 5.48 | 4.01 | | input outline on surface / page | 3.20 / 3.01 | 3.24 / 3.00 | | band ink / muted / accent | 15.32 / 10.12 / 9.21 | 10.91 / 7.67 / 5.09 | | band field edge / band action label | 3.22 / 15.32 | 3.48 / 6.02 | | stamp text on the disc | 5.48 | 5.64 |
Three visible departures from the approved mockups, each an approved accessibility requirement:
- Field outlines darken in both palettes (the mockups measured 2.3 to 2.7:1). The dotted price leader is decorative and keeps the mockup value, so the menu looks unchanged.
- Garden's hero scrim keeps the mockup's gradient shape and raises its floor under the copy to 62% of the scrim ink, so the white hero line holds 4.5:1 over any photo.
- The focus ring on the dark bands is the band accent; the palette ring measures 1.79:1 on Garden's band.
Phones also use chrome's menu sheet instead of the mockup's inline header links.
What it styles
| Hook | Treatment | |---|---| | [data-chrome-announcement], local-live-status bar | The Now Bar, through the block's --tome-live-* knobs (band, ink, dot, action pill, focus): the "·" between [data-live-lead] and [data-live-detail] from 640px, the lead in Fraunces on phones, the state action ([data-live-action]) on the band action, hollow closed dots ([data-live-state="closed"], "closed-today"). The block lays the bar out, including the phone pills and the call label/number swap. | | Chrome header ([data-nav-theme], [data-header-position="static"]) | Navbar 5 links, aria-current="page", the CTA through --tome-header-cta-*, the order button ([data-order-button], [data-order-count], [data-bump]). | | high-impact-hero venue | --tome-hero-scrim for [data-hero-media-placement="behind"] (the 62% floor) and none for "above"; the copy over a photo in white; [data-hero-meta] in the meta voice, [data-hero-name] at the venue size and the palette's axes, [data-hero-line]; the photo's focal point. The block lays out both compositions. | | local-price-list teaser | [data-local-label], the row's [data-menu-item-num] (accent), [data-menu-item-name] (Fraunces), [data-price] and [data-menu-item-line], [data-teaser-caption], and the engaged state ([data-teaser-list][data-engaged="true"], [data-teaser-row][data-active="true"]). | | local-price-list card-grid | The knobs --tome-menu-leader, --tome-menu-stamp, --tome-menu-stamp-ink, --tome-menu-meta-size; Fraunces at the palette's axes on [data-menu-item-name] (opsz 48 on cards), the masthead h2 and [data-menu-rail-link]; the display prices in [data-menu-featured] and [data-menu-breaker]; tabular Work Sans for every other [data-price], [data-menu-rail-num], [data-menu-rail-count], [data-menu-section-num], [data-menu-course-num]; accent text on [data-menu-kicker], [data-menu-breaker-availability] and the numbers; flat [data-menu-tag]; the ask in [data-menu-foot]. | | local-price-list ledger | [data-menu-row] names at opsz 36 (Linen at 400). | | The stamp | [data-menu-stamp] at -9deg, [data-stamp-ring] at 55%, [data-stamp-text] and [data-stamp-core]; the disc's colour through --tome-menu-stamp. | | The ordering island | dialog[data-order-drawer] (the drawer shadow) and its ::backdrop (45% scrim ink), [data-order-title] and [data-order-line-name] in Fraunces, [data-order-line-total], [data-order-subtotal], [data-order-total] tabular, [data-order-pickup], [data-order-close], [data-order-checkout], the demo note, [data-order-pill] (the pill shadow). Visibility and motion stay the island's. | | contact reserve | [data-contact-eyebrow] with the band-accent rule, the h2 per [data-reserve-mode], the [data-reserve-field] controls on the band field edge, [data-reserve-submit] and [data-order-open] on the band action, [data-reserve-slot] chips, the alternatives in [data-reserve-alt] and [data-contact-call], [data-contact-fact] labels. No display rule, so [data-order-open] stays hidden until the ordering island mounts. | | local-logistics split | The ground per palette, the knobs --tome-logistics-map-bg, -map-ink, -today, -dot; [data-local-label] with the accent rule, [data-logistics-heading] in Fraunces, the map label chip, [data-logistics-address], the actions, [data-logistics-hours] ([data-today="true"]), the note and [data-visit-group] lists. | | [data-compliance-label] (every block) | One look: the meta voice in muted ink. The map label is a surface chip; the drawer's demo note is a plain small sentence. | | Chrome footer 7 | One row at 1024px, --tome-footer-nav-cols: 1, --tome-footer-pad-block, the fine print. |
Treatments target only public hooks: data-block-type (the catalog slug), data-block-variant, the blocks' documented data-* part attributes, and published component knobs (--tome-menu-*, --tome-live-*, --tome-logistics-*, --tome-hero-scrim, chrome's --tome-header-* and --tome-footer-*). The blocks own their layout; the theme places nothing, and it never uses class names or structural chains such as > div:last-child.
Server / client posture
The package is pure CSS plus constants. It has no React components and no 'use client' files, so it is inert under React Server Components. It adds nothing to a client bundle beyond the stylesheets the consumer imports. ./register is a server-side import.
Tests
pnpm --filter @wabbit/tome-theme-table testThe vitest suites cover:
- the theme conformance check in theme mode and in platform mode
- manifest validation, its agreement with
package.json, and registration - both palettes defining the full required set in both modes, their axes, weights and radius, and the contrast floors re-measured from the shipped values (including the hero scrim floor and the stepper disc)
- the A4.1 font pairing; the self-hosted faces read from the woff2 files themselves (Fraunces's four axes, Work Sans's
tnum); every Fraunces surface stating its axes, roman, weight throughfont-weight - no colour literal outside
src/tokens/, no comment that swallows a rule, no structural or class selector, drop shadows only from the four tokens, and every treatment rule scoped to the theme - the reveal switch and timing, each section's contract hooks, the band rule, flat tags and the one stamp
Exports
@wabbit/tome-theme-table@wabbit/tome-theme-table/manifest@wabbit/tome-theme-table/register@wabbit/tome-theme-table/fonts@wabbit/tome-theme-table/styles.css@wabbit/tome-theme-table/fonts.css@wabbit/tome-theme-table/fonts/*
Changelog
323534d: Table now styles the ordering surfaces, the venue hero's action and Footer 7 completely, so they match the mockups at 1440 and 375. - **Ordering.** Checkout is the ink pill (primary fill, on-primary label at rest and on hover, 54px, no underline). Before this, tome-ui's link colour made the label ink on ink. The floating pill is the 54px ink pill with the pill shadow, and its label and total spread across the phone width. The pickup select gets a 1.5px `--input` edge, the md radius, the surface fill and a caret. The close button and line steppers keep their hairline ring. These rules sit at (0,2,1) or higher (`[data-order-drawer] a[data-order-checkout]`, `button[data-order-pill]`), so they still win once the island's hook selectors leave `:where()`, as long as the island stays at (0,2,0) or below. - **Venue hero.** The action (`[data-hero-actions] a`) is the 50px ink pill in Work Sans 600. The hero's links carry no `data-appearance`, so they had kept the block's small button. The hero line keeps the mockup's 34ch measure (`--table-hero-line-measure`). - **Footer 7.** From 1024px the footer sits on the page grid's lanes. The wordmark is in the left marginalia lane, the links run in one row from reading-start, and the copyright is right-aligned in the right lane. The lane width is `--table-footer-lane`, computed from the 16-column grid and `--tome-grid-gap`. Links and plain rows share the muted ink and the body weight. The copyright bar takes the footer size. The wordmark no longer takes Footer 7's 2.75rem logo height, and phones keep the brand and copyright left-aligned.
- 323534d: Table now styles the ordering surfaces, the venue hero's action and Footer 7 completely, so they match the mockups at 1440 and 375. - **Ordering.** Checkout is the ink pill (primary fill, on-primary label at rest and on hover, 54px, no underline). Before this, tome-ui's link colour made the label ink on ink. The floating pill is the 54px ink pill with the pill shadow, and its label and total spread across the phone width. The pickup select gets a 1.5px `--input` edge, the md radius, the surface fill and a caret. The close button and line steppers keep their hairline ring. These rules sit at (0,2,1) or higher (`[data-order-drawer] a[data-order-checkout]`, `button[data-order-pill]`), so they still win once the island's hook selectors leave `:where()`, as long as the island stays at (0,2,0) or below. - **Venue hero.** The action (`[data-hero-actions] a`) is the 50px ink pill in Work Sans 600. The hero's links carry no `data-appearance`, so they had kept the block's small button. The hero line keeps the mockup's 34ch measure (`--table-hero-line-measure`). - **Footer 7.** From 1024px the footer sits on the page grid's lanes. The wordmark is in the left marginalia lane, the links run in one row from reading-start, and the copyright is right-aligned in the right lane. The lane width is `--table-footer-lane`, computed from the 16-column grid and `--tome-grid-gap`. Links and plain rows share the muted ink and the body weight. The copyright bar takes the footer size. The wordmark no longer takes Footer 7's 2.75rem logo height, and phones keep the brand and copyright left-aligned.
e957219: New theme: Table, for places people visit (restaurants and cafés first, then bars, bakeries, breweries, venues, salons and boutique retail), activated with `data-tome-theme="table"`. - Two palettes (Linen, the default; Garden), each in light and a derived dark, selected with `data-tome-palette`. Every palette sets Layer 1, the `*-text` literals, the tinted surface, the fixed-band ink family and Table's private colours (the band action, the stamp, the illustrative map, the scrim), contrast-checked (text at least 4.5:1; field outlines, accent marks and the focus ring at least 3:1). Each palette also sets the display face's axes (Linen: opsz 144, SOFT 0, WONK 0 at 340; Garden: opsz 40, SOFT 100, WONK 1 at 580), the body weight and the radius scale. - Self-hosted OFL fonts: Fraunces (the fontsource full cut, one variable face carrying opsz, wght, SOFT and WONK) for display, and Work Sans (variable weight) for the body, the UI, the meta voice and every tabular figure, latin-subset woff2 with their licences, via `./fonts.css`, the `./fonts` descriptors or `./fonts/*` for your own host. Each `--font-*` slot is paired with its `--tome-type-*` alias, and every Fraunces surface states its axes. - Treatments through public hooks only (the Table v1 hook contract): the Now Bar in chrome's announcement slot, Navbar 5 with the static header and the order button, the `venue` hero (photo behind with a 62% scrim floor, or above with the name on the cloth), the menu teaser, the `card-grid` menu (featured dish with the stamp, the numbered rail, mastheads, photo cards with in-card details, one grid-breaker) and the `ledger`, the ordering island's stepper, drawer and pill, the `reserve` band with sample slot chips and the pickup band, Find Us, and footer 7 in one row. The accent is punctuation; only four things cast a shadow. - The platform scroll reveal is on, with Table's timing (12px rise, 420ms, 60ms stagger); it runs only where the site mounts `TomeReveal`. - One opt-in effect: a faint static grain (`data-table-effect="grain"`). - `./register` adds the theme to tome-core's theme registry. Requires `@wabbit/tome-ui` 0.18.0 or later; `@wabbit/tome-core` is an optional peer.
- e957219: New theme: Table, for places people visit (restaurants and cafés first, then bars, bakeries, breweries, venues, salons and boutique retail), activated with `data-tome-theme="table"`. - Two palettes (Linen, the default; Garden), each in light and a derived dark, selected with `data-tome-palette`. Every palette sets Layer 1, the `*-text` literals, the tinted surface, the fixed-band ink family and Table's private colours (the band action, the stamp, the illustrative map, the scrim), contrast-checked (text at least 4.5:1; field outlines, accent marks and the focus ring at least 3:1). Each palette also sets the display face's axes (Linen: opsz 144, SOFT 0, WONK 0 at 340; Garden: opsz 40, SOFT 100, WONK 1 at 580), the body weight and the radius scale. - Self-hosted OFL fonts: Fraunces (the fontsource full cut, one variable face carrying opsz, wght, SOFT and WONK) for display, and Work Sans (variable weight) for the body, the UI, the meta voice and every tabular figure, latin-subset woff2 with their licences, via `./fonts.css`, the `./fonts` descriptors or `./fonts/*` for your own host. Each `--font-*` slot is paired with its `--tome-type-*` alias, and every Fraunces surface states its axes. - Treatments through public hooks only (the Table v1 hook contract): the Now Bar in chrome's announcement slot, Navbar 5 with the static header and the order button, the `venue` hero (photo behind with a 62% scrim floor, or above with the name on the cloth), the menu teaser, the `card-grid` menu (featured dish with the stamp, the numbered rail, mastheads, photo cards with in-card details, one grid-breaker) and the `ledger`, the ordering island's stepper, drawer and pill, the `reserve` band with sample slot chips and the pickup band, Find Us, and footer 7 in one row. The accent is punctuation; only four things cast a shadow. - The platform scroll reveal is on, with Table's timing (12px rise, 420ms, 60ms stagger); it runs only where the site mounts `TomeReveal`. - One opt-in effect: a faint static grain (`data-table-effect="grain"`). - `./register` adds the theme to tome-core's theme registry. Requires `@wabbit/tome-ui` 0.18.0 or later; `@wabbit/tome-core` is an optional peer.