Adopt the Stitch design system
Google Stitch produced an Atelier Dining & Hospitality system for this app: warm ivory linen and espresso for the guest surfaces, burnished gold for the single active thing, Playfair Display for the restaurant's voice and Plus Jakarta Sans for everything transactional, editorial rows with dot leaders, pill controls, hairline containment instead of drop shadows. The four screens and the system document are kept in docs/design/stitch/ as the source. Both fonts are now self-hosted with their licences, the guest stylesheet is rebuilt on the system, and the admin is the same system in its dark mode (espresso workspace, obsidian pods, gold actions) by overriding the same tokens at a higher specificity, since the per-Site theme is injected inline after the stylesheets. The Site theme in config/ moves to the system's palette, which is where per-Site branding belongs; the old Archivo font is dropped.
This commit is contained in:
1 parent
a29c5c4b0c
commit
b13042f0db
17 files changed
+679
-191
No files matched your search
@@ -6,19 +6,49 @@
|
||||
"logo": "/assets/favicon.svg"
|
||||
},
|
||||
"theme": {
|
||||
"steel": "#14181b",
|
||||
"rail": "#1f262b",
|
||||
"paper": "#f2efe9",
|
||||
"accent": "#0088aa",
|
||||
"copper": "#b2703b"
|
||||
"steel": "#faf8f5",
|
||||
"rail": "#f4f1ea",
|
||||
"paper": "#ffffff",
|
||||
"accent": "#c59b58",
|
||||
"copper": "#b08544"
|
||||
},
|
||||
"sections": [
|
||||
{ "slug": "food", "label": "Food", "shortLabel": "Food", "order": 1 },
|
||||
{ "slug": "bar", "label": "Bar", "shortLabel": "Bar", "order": 2 },
|
||||
{ "slug": "wine", "label": "Wine", "shortLabel": "Wine", "order": 3 },
|
||||
{ "slug": "straight-drinks", "label": "Straight Drinks", "shortLabel": "Drinks", "order": 4 },
|
||||
{ "slug": "delivery", "label": "Delivery", "shortLabel": "Delivery", "order": 5 },
|
||||
{ "slug": "whats-on", "label": "What's On", "shortLabel": "What's On", "order": 6 }
|
||||
{
|
||||
"slug": "food",
|
||||
"label": "Food",
|
||||
"shortLabel": "Food",
|
||||
"order": 1
|
||||
},
|
||||
{
|
||||
"slug": "bar",
|
||||
"label": "Bar",
|
||||
"shortLabel": "Bar",
|
||||
"order": 2
|
||||
},
|
||||
{
|
||||
"slug": "wine",
|
||||
"label": "Wine",
|
||||
"shortLabel": "Wine",
|
||||
"order": 3
|
||||
},
|
||||
{
|
||||
"slug": "straight-drinks",
|
||||
"label": "Straight Drinks",
|
||||
"shortLabel": "Drinks",
|
||||
"order": 4
|
||||
},
|
||||
{
|
||||
"slug": "delivery",
|
||||
"label": "Delivery",
|
||||
"shortLabel": "Delivery",
|
||||
"order": 5
|
||||
},
|
||||
{
|
||||
"slug": "whats-on",
|
||||
"label": "What's On",
|
||||
"shortLabel": "What's On",
|
||||
"order": 6
|
||||
}
|
||||
],
|
||||
"limits": {
|
||||
"maxUploadBytes": 31457280,
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 716 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 628 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 206 KiB |
@@ -0,0 +1,261 @@
|
||||
---
|
||||
name: Atelier Dining & Hospitality
|
||||
colors:
|
||||
surface: '#fbf9f6'
|
||||
surface-dim: '#dbdad7'
|
||||
surface-bright: '#fbf9f6'
|
||||
surface-container-lowest: '#ffffff'
|
||||
surface-container-low: '#f5f3f0'
|
||||
surface-container: '#efeeeb'
|
||||
surface-container-high: '#eae8e5'
|
||||
surface-container-highest: '#e4e2df'
|
||||
on-surface: '#1b1c1a'
|
||||
on-surface-variant: '#4b4640'
|
||||
inverse-surface: '#30312f'
|
||||
inverse-on-surface: '#f2f0ed'
|
||||
outline: '#7c766f'
|
||||
outline-variant: '#cdc5bd'
|
||||
surface-tint: '#605e5c'
|
||||
primary: '#000000'
|
||||
on-primary: '#ffffff'
|
||||
primary-container: '#1d1b1a'
|
||||
on-primary-container: '#868381'
|
||||
inverse-primary: '#cac6c3'
|
||||
secondary: '#7a581c'
|
||||
on-secondary: '#ffffff'
|
||||
secondary-container: '#ffd087'
|
||||
on-secondary-container: '#79571b'
|
||||
tertiary: '#000000'
|
||||
on-tertiary: '#ffffff'
|
||||
tertiary-container: '#291800'
|
||||
on-tertiary-container: '#a67c3c'
|
||||
error: '#ba1a1a'
|
||||
on-error: '#ffffff'
|
||||
error-container: '#ffdad6'
|
||||
on-error-container: '#93000a'
|
||||
primary-fixed: '#e6e1df'
|
||||
primary-fixed-dim: '#cac6c3'
|
||||
on-primary-fixed: '#1d1b1a'
|
||||
on-primary-fixed-variant: '#484645'
|
||||
secondary-fixed: '#ffdeae'
|
||||
secondary-fixed-dim: '#edbf78'
|
||||
on-secondary-fixed: '#281900'
|
||||
on-secondary-fixed-variant: '#604103'
|
||||
tertiary-fixed: '#ffddb1'
|
||||
tertiary-fixed-dim: '#efbe77'
|
||||
on-tertiary-fixed: '#291800'
|
||||
on-tertiary-fixed-variant: '#614002'
|
||||
background: '#fbf9f6'
|
||||
on-background: '#1b1c1a'
|
||||
surface-variant: '#e4e2df'
|
||||
typography:
|
||||
display-lg:
|
||||
fontFamily: Playfair Display
|
||||
fontSize: 56px
|
||||
fontWeight: '400'
|
||||
lineHeight: 64px
|
||||
letterSpacing: -0.02em
|
||||
display-lg-mobile:
|
||||
fontFamily: Playfair Display
|
||||
fontSize: 36px
|
||||
fontWeight: '400'
|
||||
lineHeight: 44px
|
||||
letterSpacing: -0.01em
|
||||
headline-xl:
|
||||
fontFamily: Playfair Display
|
||||
fontSize: 40px
|
||||
fontWeight: '400'
|
||||
lineHeight: 48px
|
||||
letterSpacing: -0.01em
|
||||
headline-xl-mobile:
|
||||
fontFamily: Playfair Display
|
||||
fontSize: 28px
|
||||
fontWeight: '400'
|
||||
lineHeight: 36px
|
||||
letterSpacing: 0em
|
||||
headline-lg:
|
||||
fontFamily: Playfair Display
|
||||
fontSize: 30px
|
||||
fontWeight: '500'
|
||||
lineHeight: 38px
|
||||
headline-md:
|
||||
fontFamily: Playfair Display
|
||||
fontSize: 22px
|
||||
fontWeight: '500'
|
||||
lineHeight: 30px
|
||||
headline-sm:
|
||||
fontFamily: Plus Jakarta Sans
|
||||
fontSize: 18px
|
||||
fontWeight: '600'
|
||||
lineHeight: 24px
|
||||
body-lg:
|
||||
fontFamily: Plus Jakarta Sans
|
||||
fontSize: 16px
|
||||
fontWeight: '400'
|
||||
lineHeight: 26px
|
||||
body-md:
|
||||
fontFamily: Plus Jakarta Sans
|
||||
fontSize: 14px
|
||||
fontWeight: '400'
|
||||
lineHeight: 22px
|
||||
body-sm:
|
||||
fontFamily: Plus Jakarta Sans
|
||||
fontSize: 12px
|
||||
fontWeight: '400'
|
||||
lineHeight: 18px
|
||||
label-lg:
|
||||
fontFamily: Plus Jakarta Sans
|
||||
fontSize: 13px
|
||||
fontWeight: '600'
|
||||
lineHeight: 18px
|
||||
letterSpacing: 0.02em
|
||||
label-md:
|
||||
fontFamily: Plus Jakarta Sans
|
||||
fontSize: 11px
|
||||
fontWeight: '600'
|
||||
lineHeight: 16px
|
||||
letterSpacing: 0.06em
|
||||
label-sm:
|
||||
fontFamily: Plus Jakarta Sans
|
||||
fontSize: 10px
|
||||
fontWeight: '700'
|
||||
lineHeight: 14px
|
||||
letterSpacing: 0.08em
|
||||
currency-md:
|
||||
fontFamily: Plus Jakarta Sans
|
||||
fontSize: 15px
|
||||
fontWeight: '600'
|
||||
lineHeight: 20px
|
||||
letterSpacing: 0.01em
|
||||
rounded:
|
||||
sm: 0.5rem
|
||||
DEFAULT: 1rem
|
||||
md: 1.5rem
|
||||
lg: 2rem
|
||||
xl: 3rem
|
||||
full: 9999px
|
||||
spacing:
|
||||
gutter: 1.5rem
|
||||
gutter-sm: 1rem
|
||||
margin: 2.5rem
|
||||
margin-sm: 1.25rem
|
||||
space-xs: 0.25rem
|
||||
space-sm: 0.5rem
|
||||
space-md: 1rem
|
||||
space-lg: 1.5rem
|
||||
space-xl: 2.5rem
|
||||
---
|
||||
|
||||
## Brand & Style
|
||||
|
||||
This design system pairs the tactile grace of Michelin-caliber editorial print with the razor-sharp operational ergonomics required by high-velocity hospitality management. The aesthetic bridges two primary touchpoints: the guest-facing digital menu experience (epicurean, sensory, leisurely) and the back-of-house administrative command suite (lucid, dense, decisive).
|
||||
|
||||
The brand communicates restraint, discernment, and bespoke craft. It deliberately rejects noisy animations, saturated alert badges, and harsh utilitarian UI tropes in favor of warm, quiet authority. The visual language blends:
|
||||
- **Warm Editorial Minimalism:** Generous negative space, museum-grade typographic hierarchy, and paper-textured tonal canvas shifts.
|
||||
- **Modern Executive Precision:** Structured data grids, micro-etched dividers, disciplined layout modules, and subdued state transitions.
|
||||
|
||||
Target users span fine-dining proprietors, beverage directors, and floor captains managing inventory and covers in real time, alongside discerning diners experiencing a curated tableside or pre-arrival digital carte.
|
||||
|
||||
## Colors
|
||||
|
||||
The system establishes an evocative dual-surface architecture: a luminous, parchment-tinted guest presentation mode contrasted against an espresso-grounded administrative control environment.
|
||||
|
||||
- **Primary (`#121110`):** Deep charcoal espresso. Used for primary typography in public surfaces, dominant action containers, and primary surfaces in dark management viewports.
|
||||
- **Secondary (`#C59B58`):** Warm burnished gold. Deployed deliberately for active states, vintage highlights, tasting notes, key curation tags, and focal callouts.
|
||||
- **Tertiary (`#B08544`):** Deep aged amber. Serves as interactive hover values, tactile micro-accents, pressed states, and secondary visual balances.
|
||||
- **Neutral Surface Baseline (`#FAF8F5`):** Warm ivory linen. Forms the underlying page canvas, evoking heavy unbleached cotton menu stock.
|
||||
|
||||
### Supporting Tone System
|
||||
- **Sub-Surface Canvas:** `#F4F1EA` (warm alabaster cream for inset cards, table rows, and secondary wells).
|
||||
- **Hairline Dividers & Framing:** `#E6E1D8` (muted bone linen with low visual vibration).
|
||||
- **Dark Surface Modules:** `#1E1C1A` (warm obsidian for administrative pods, metric cards, and back-of-house viewports).
|
||||
- **Dark Surface Hairlines:** `#2D2A26` (charred espresso borders for dark-mode cards and tables).
|
||||
- **Semantic Signals:** Muted moss green (`#4A6B53`) for table ready/open items, subtle terracotta red (`#A34839`) for 86'd/unavailable items, and soft slate amber (`#D99E32`) for active reservations or pending kitchen courses.
|
||||
|
||||
## Typography
|
||||
|
||||
Typography governs the dual identity of this system. `Playfair Display` evokes the provenance of printed carte menus, vineyard reserves, and editorial headlining. It must remain untruncated and breathed with open line heights. It is reserved exclusively for major restaurant identity sections, dish names, tasting menu chapters, and prominent administrative dashboard greetings.
|
||||
|
||||
`Plus Jakarta Sans` handles all transactional clarity: ingredient pairings, culinary provenance descriptions, dietary identifiers, inventory counts, modifier groups, and data tables.
|
||||
|
||||
### Rules of Application
|
||||
- All uppercase section labels and culinary course markers (`AMUSE-BOUCHE`, `PREMIER`, `CELLAR RESERVE`) must utilize `label-md` or `label-sm` with explicit letter-spacing between `0.06em` and `0.08em`.
|
||||
- Pricing labels must never use serif fonts; they must render in `currency-md` or `label-lg` using tabular numbers (`font-variant-numeric: tabular-nums`) to align vertically across dish items and administrative balance sheets.
|
||||
- Line heights on editorial dish descriptions remain generous (`body-md` at `22px`) to ensure optimal readability under dim, ambient dining room lighting conditions.
|
||||
|
||||
## Layout & Spacing
|
||||
|
||||
The system deploys an adaptable 12-column responsive grid with a dual rhythmic structure:
|
||||
|
||||
- **Desktop Operations Suite (>= 1200px):** 12-column structure with `2.5rem` (`margin`) outer offsets and `1.5rem` (`gutter`). Fixed sidebar navigation (width `260px` or collapsed to `72px`) paired with fluid administrative canvas modules.
|
||||
- **Tablet Service View (768px - 1199px):** 8-column layout with `1.5rem` margins and `1rem` gutters optimized for floor management tablets, order dispatch stations, and wine list browsing.
|
||||
- **Mobile Guest Menu (< 768px):** 4-column layout with `1.25rem` (`margin-sm`) canvas boundaries. Content stacks vertically with deliberate whitespace between course sections to preserve editorial luxury.
|
||||
|
||||
### Spacing Scale & Rhythm
|
||||
- Spacing relies on a base 8px increment system supplemented by 4px micro-steps (`space-xs`).
|
||||
- Section separations within digital menu books require intentional room: dishes within a single course sit apart by `space-md` (`1rem`), while distinct courses (`Entrées` to `Desserts`) transition across `space-xl` (`2.5rem`).
|
||||
- Table layout densities in SaaS viewports default to comfortable padded lines (`0.75rem` vertical cell padding) with a dense toggle (`0.5rem`) for high-volume service shifts.
|
||||
|
||||
## Elevation & Depth
|
||||
|
||||
Spatial depth avoids synthetic heavy dropshadows in favor of tactile surfaces, whisper-thin borders, and warm ambient luminescence.
|
||||
|
||||
### 1. Ghost Border Layering
|
||||
Surfaces default to structural containment through subtle lines rather than elevation. In light mode, containers leverage a 1px border of `#E6E1D8`. In dark operations mode, surfaces frame in 1px `#2D2A26`.
|
||||
|
||||
### 2. Warm Ambient Shadow (Level 1)
|
||||
Applied to elevated menu cards, active category pills, and dropdown selectors:
|
||||
- `box-shadow: 0 4px 20px -2px rgba(18, 17, 16, 0.04), 0 2px 6px -1px rgba(18, 17, 16, 0.02)`
|
||||
|
||||
### 3. Floated Surface & Overlay (Level 2)
|
||||
Applied to tableside modifier trays, wine vintage filter sheets, and administrative modals:
|
||||
- `box-shadow: 0 12px 36px -4px rgba(18, 17, 16, 0.08), 0 4px 12px -2px rgba(18, 17, 16, 0.04)`
|
||||
- Paired with an editorial frosted overlay: `background: rgba(18, 17, 16, 0.45); backdrop-filter: blur(8px);`
|
||||
|
||||
### 4. Back-of-House Dark Elevation
|
||||
For the administrative cards (`#1E1C1A`), stacked elements rely on tonal surface lightening (`#262320` for nested sub-cards or hover rows) rather than drop shadows, maintaining crisp contrast against the `#121110` workspace background.
|
||||
|
||||
## Shapes
|
||||
|
||||
The shape architecture centers on high-tactile refinement. Structural content carriers (menu containers, data panels, administrative tables, dish image wrappers) use deliberate micro-radii to maintain discipline and architectural structure, while interactive elements leverage full pill profiles (`roundedness: 3`) to evoke polished physical artifacts.
|
||||
|
||||
- **Primary & Secondary Action Controls:** Full pill geometry (`rounded-full` / 9999px) delivering soft, smooth touch targets suitable for finger tapping on floor devices or guest mobile screens.
|
||||
- **Badges, Vintage Years, & Diet Tags:** Pill silhouettes (`rounded-full`) that cradle typography with proportional horizontal padding.
|
||||
- **Card Containers & Modules:** Soft architectural radius (`0.5rem` to `0.75rem`) preventing the interface from feeling clinical or sharp.
|
||||
- **Dish Photography & Imagery:** Cropped with subtle `0.5rem` corners or displayed as pristine full-bleed rectangles with hairline interior frames.
|
||||
|
||||
## Components
|
||||
|
||||
### Buttons
|
||||
- **Primary Pill:** Background `#121110`, text `#FAF8F5`, hairline gold interior halo on hover (`box-shadow: inset 0 0 0 1px #C59B58`). Fully rounded pill shape.
|
||||
- **Gold Accent Pill:** Background `#C59B58`, text `#121110`, transitioning to `#B08544` on active press. Reserved for high-value conversions ("Reserve Table", "Order Tasting Pairings", "Confirm Service").
|
||||
- **Secondary Ghost Pill:** Background transparent, border 1px solid `#E6E1D8`, text `#121110`. Hover invokes background `#F4F1EA`.
|
||||
- **Admin Mini Actions:** Subdued dark pills (`#1E1C1A` with border 1px solid `#2D2A26`, text `#FAF8F5`).
|
||||
|
||||
### Dish & Product Cards
|
||||
- **Editorial Menu Row:** Borderless or separated by hairline `#E6E1D8`. Features the dish title in `headline-md` (`Playfair Display`), dot leader or right-aligned price in `currency-md`, followed by component descriptions in `body-md` (`Plus Jakarta Sans`).
|
||||
- **Showcase Dish Card:** Clean parchment surface (`#FAF8F5`), 1px `#E6E1D8` border, subtle 16:10 ratio photograph with soft radius, dietary pill badges pinned at bottom-left, price anchored at top-right.
|
||||
|
||||
### Chips & Dietary Badges
|
||||
- Compact pill geometries with heights of 24px to 28px.
|
||||
- **Dietary Tags (GF, V, VG, NF):** Background `#F4F1EA`, border 1px solid `#E6E1D8`, text `#121110`, uppercase `label-sm`.
|
||||
- **Sommelier Selection / Reserve Pick:** Background `rgba(197, 155, 88, 0.12)`, border 1px solid `#C59B58`, text `#B08544`.
|
||||
|
||||
### Input Fields & Selectors
|
||||
- Background `#FFFFFF` (guest views) or `#1E1C1A` (admin views).
|
||||
- Border 1px solid `#E6E1D8` (admin: `#2D2A26`).
|
||||
- Height 44px for high touch accessibility.
|
||||
- Focus state: Border transitions to `#C59B58` with no loud glow rings; utilizes a faint 2px ambient amber whisper ring (`rgba(197, 155, 88, 0.18)`).
|
||||
- Typography: `body-md` with placeholder text in warm stone tone (`#8C857B`).
|
||||
|
||||
### Checkboxes, Radios, & Switches
|
||||
- **Radios & Checkboxes:** Unchecked state defined by 1.5px border `#E6E1D8`. Checked state fills `#121110` with gold accent tick mark (`#C59B58`).
|
||||
- **Hospitality Toggle Switch:** 20px height pill track; inactive track `#E6E1D8`, active track `#121110`. The toggle knob is cream `#FAF8F5`, sliding smoothly with a warm micro-shadow.
|
||||
|
||||
### Admin Data Tables & Kitchen Station Queues
|
||||
- **Header:** Sticky top, uppercase `label-md` in stone charcoal (`#59544D`), background `#FAF8F5` or dark `#121110`.
|
||||
- **Row Architecture:** Subtle bottom divider `#E6E1D8` (dark: `#2D2A26`). Alternating or hover tint using `#F4F1EA` (dark: `#262320`).
|
||||
- **Live Status Indicators:** 6px solid circular pips:
|
||||
- *Seated / Active:* `#4A6B53` (Moss)
|
||||
- *86'd / Depleted:* `#A34839` (Terracotta)
|
||||
- *Reserved / Firing:* `#D99E32` (Gold)
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.6 MiB |
+1
-1
@@ -13,7 +13,7 @@ For whoever is on the other end of "the menu is wrong". The design is in
|
||||
| Admin | `https://<vhost>/admin` |
|
||||
| The password | `/var/lib/menu-app.<site>/site.env` (mode 600, never in git) |
|
||||
| Categories | `data/sections.json`, edited in the admin |
|
||||
| Brand and theme | `config/<site>.site.json` in this repo, baked into the image |
|
||||
| Brand and theme | `config/<site>.site.json` in this repo, baked into the image (the palette follows the Stitch system in `docs/design/stitch/`) |
|
||||
|
||||
## Everyday tasks
|
||||
|
||||
|
||||
+2
-2
@@ -89,7 +89,7 @@ Protection: a `scrypt` hash (from `node:crypto`, so no native build dependency)
|
||||
|
||||
### Customer design
|
||||
|
||||
The navigation is made of the restaurant's own paper: the landing is a row of cards, each one the first page of a menu with the category name over it and the page count on a strip beneath, scrolling sideways and snapping (wrapping into a grid on a wide screen). The bar links every menu as a filled segment, the current one the only teal thing on screen, and a 2px brass line under it tracks how far through the pages you are.
|
||||
The look is the Atelier Dining & Hospitality system from Stitch (`docs/design/stitch/`): warm ivory linen and espresso for the guest surfaces, burnished gold for the one active thing, Playfair Display carrying the restaurant's voice, Plus Jakarta Sans carrying everything transactional. The landing is an editorial directory — each category a hairline row with a small plate of that menu's paper, its name in Playfair, a dot leader and a tabular page count. The bar names the restaurant, links every menu as a pill (the current one espresso-filled), and a gold hairline under it tracks progress through the pages. The administrative side is the same system in its dark mode: espresso workspace, obsidian pods, gold actions.
|
||||
|
||||
```
|
||||
┌────────────────────────────┐ ┌────────────────────────────┐
|
||||
@@ -114,7 +114,7 @@ The navigation is made of the restaurant's own paper: the landing is a row of ca
|
||||
|
||||
- New repo `menu-admin` on `git.tanshu.com`: app source, `Dockerfile`, `compose.yaml` for local dev, `docs/` (this plan, `CONTEXT.md`, the ADRs), `node --test` tests, and `deploy.sh` (tests, build, push).
|
||||
- The container is `node:24-alpine` running TypeScript directly, so there is no build step; sharp's musl binaries come from `npm ci` on the image's own platform. It writes only under `MENU_ROOT` and healthchecks its own `/healthz`.
|
||||
- The Site's brand and theme live in `config/<site>.site.json`, baked into the image and selected with `MENU_SITE_CONFIG`; its Section list only seeds `data/sections.json` the first time. Categories are edited in the admin from then on (ADR 0007), so adding one does not need a redeploy.
|
||||
- The design system is documented in `docs/design/stitch/atelier-dining-hospitality.md`, with the four screens Stitch produced beside it. The Site's brand and theme live in `config/<site>.site.json`, baked into the image and selected with `MENU_SITE_CONFIG`; its Section list only seeds `data/sections.json` the first time. Categories are edited in the admin from then on (ADR 0007), so adding one does not need a redeploy.
|
||||
- Build locally and push `registry.tanshu.com/menu-admin:<tag>`, matching the sibling `deploy.sh` / `make build-production TAG=` convention.
|
||||
- New `menu-admin` playbook in `ansible-playbooks` with per-Site vars (`vars/hopsngrains.yml` first, the other two stubbed): roles `network`, `menu-app` (pull image, create `/var/lib/menu-app.<site>`, start container, health check, then `verify` the data directory) and `caddy` (snippet upsert).
|
||||
- The existing `roles/caddy` only *adds* a snippet when its exact text is missing, which cannot change a proxy target; the new playbook's role uses a stable marker so `blockinfile` updates in place, and removes the old role's per-hostname marker at cutover so Caddy never holds two blocks for one hostname.
|
||||
|
||||
@@ -1,3 +1,62 @@
|
||||
/* The administrative side of the same system: an espresso workspace with warm
|
||||
obsidian pods and burnished gold for the one active thing. See
|
||||
docs/design/stitch/atelier-dining-hospitality.md. */
|
||||
|
||||
body.admin-page {
|
||||
--steel: #121110;
|
||||
--rail: #1e1c1a;
|
||||
--paper: #faf8f5;
|
||||
--ink: #faf8f5;
|
||||
--ink-soft: #c9c4bd;
|
||||
--ink-dim: #a9a29a;
|
||||
--ink-on-paper: #121110;
|
||||
--accent: #c59b58;
|
||||
--copper: #b08544;
|
||||
--hairline: #2d2a26;
|
||||
--hairline-soft: #262320;
|
||||
--sheet-shadow: rgba(0, 0, 0, 0.45);
|
||||
--shadow-card: none;
|
||||
--shadow-float: 0 12px 36px -4px rgba(0, 0, 0, 0.5);
|
||||
--radius-card: 0.5rem;
|
||||
--radius-pill: 9999px;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: var(--font-ui, 'Plus Jakarta Sans', system-ui, sans-serif);
|
||||
}
|
||||
|
||||
.button {
|
||||
border-radius: var(--radius-pill);
|
||||
font-size: 0.78rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
|
||||
.field input,
|
||||
.catrow__name input {
|
||||
min-height: 44px;
|
||||
border-radius: var(--radius-card);
|
||||
}
|
||||
|
||||
.field input:focus,
|
||||
.catrow__name input:focus {
|
||||
border-color: var(--accent);
|
||||
box-shadow: 0 0 0 2px rgba(197, 155, 88, 0.18);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.page-admin,
|
||||
.drop {
|
||||
border-radius: var(--radius-card);
|
||||
}
|
||||
|
||||
.pill {
|
||||
border-radius: var(--radius-pill);
|
||||
letter-spacing: 0.06em;
|
||||
text-transform: uppercase;
|
||||
font-size: 0.62rem;
|
||||
}
|
||||
|
||||
/* The admin shares the customer tokens and stays out of the way: forms,
|
||||
lists, and thumbnails good enough to judge a page by. */
|
||||
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
Copyright 2017 The Playfair Display Project Authors (https://github.com/clauseggers/Playfair-Display), with Reserved Font Name "Playfair Display"
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright 2020 The Archivo Project Authors (https://github.com/Omnibus-Type/Archivo)
|
||||
Copyright 2020 The Plus Jakarta Sans Project Authors (https://github.com/tokotype/PlusJakartaSans)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+218
-175
@@ -1,49 +1,54 @@
|
||||
/* Hops n Grains menus.
|
||||
The chrome is the shelf; the menus are the paper standing on it. Brass is the
|
||||
taproom's metal, the logo's teal is the only active colour, and the paper of
|
||||
the photographed menus is the brightest thing on the page. */
|
||||
/* Hops n Grains menus, to the Atelier Dining & Hospitality system that came out
|
||||
of Stitch: ivory linen and espresso for the guest's menu, burnished gold for
|
||||
the one active thing on screen, Playfair Display carrying the restaurant's
|
||||
voice and Plus Jakarta Sans carrying everything transactional.
|
||||
See docs/design/stitch/atelier-dining-hospitality.md. */
|
||||
|
||||
@font-face {
|
||||
font-family: 'Archivo';
|
||||
font-family: 'Playfair Display';
|
||||
font-style: normal;
|
||||
font-weight: 100 900;
|
||||
font-stretch: 62% 125%;
|
||||
font-weight: 400 700;
|
||||
font-display: swap;
|
||||
src: url('/assets/fonts/archivo-latin.woff2') format('woff2');
|
||||
src: url('/assets/fonts/playfair-display-latin.woff2') format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304,
|
||||
U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Archivo';
|
||||
font-family: 'Plus Jakarta Sans';
|
||||
font-style: normal;
|
||||
font-weight: 100 900;
|
||||
font-stretch: 62% 125%;
|
||||
font-weight: 200 800;
|
||||
font-display: swap;
|
||||
src: url('/assets/fonts/archivo-latin-ext.woff2') format('woff2');
|
||||
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308,
|
||||
U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113,
|
||||
U+2C60-2C7F, U+A720-A7FF;
|
||||
src: url('/assets/fonts/plus-jakarta-sans-latin.woff2') format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304,
|
||||
U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
|
||||
:root {
|
||||
--steel: #101719;
|
||||
--rail: #182125;
|
||||
--paper: #efeae0;
|
||||
--accent: #0088aa;
|
||||
--copper: #c08544;
|
||||
--ink: #e8e5dd;
|
||||
--ink-dim: #8f979a;
|
||||
--ink-on-paper: #1b1f22;
|
||||
--brass-edge: color-mix(in srgb, var(--copper) 42%, transparent);
|
||||
--hairline: color-mix(in srgb, var(--copper) 26%, transparent);
|
||||
--hairline-soft: color-mix(in srgb, var(--copper) 14%, transparent);
|
||||
--sheet-shadow: color-mix(in srgb, #000 45%, transparent);
|
||||
/* guest surfaces: warm ivory linen, never stark white */
|
||||
--steel: #faf8f5;
|
||||
--rail: #f4f1ea;
|
||||
--paper: #ffffff;
|
||||
--ink: #121110;
|
||||
--ink-soft: #4b4640;
|
||||
--ink-dim: #8c857b;
|
||||
--ink-on-paper: #121110;
|
||||
--accent: #c59b58;
|
||||
--copper: #b08544;
|
||||
--hairline: #e6e1d8;
|
||||
--hairline-soft: #efebe4;
|
||||
--sheet-shadow: rgba(18, 17, 16, 0.06);
|
||||
--shadow-card: 0 4px 20px -2px rgba(18, 17, 16, 0.04), 0 2px 6px -1px rgba(18, 17, 16, 0.02);
|
||||
--shadow-float: 0 12px 36px -4px rgba(18, 17, 16, 0.08), 0 4px 12px -2px rgba(18, 17, 16, 0.04);
|
||||
--font-display: 'Playfair Display', Georgia, 'Times New Roman', serif;
|
||||
--font-ui: 'Plus Jakarta Sans', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
|
||||
--radius-card: 0.5rem;
|
||||
--radius-pill: 9999px;
|
||||
--step-0: 1rem;
|
||||
--step-1: 1.25rem;
|
||||
--step-2: 1.55rem;
|
||||
--step-2: 1.75rem;
|
||||
--page-max: 780px;
|
||||
--content-max: 52rem;
|
||||
--content-max: 46rem;
|
||||
}
|
||||
|
||||
*,
|
||||
@@ -60,7 +65,7 @@ body {
|
||||
margin: 0;
|
||||
background: var(--steel);
|
||||
color: var(--ink);
|
||||
font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
|
||||
font-family: var(--font-ui);
|
||||
font-size: var(--step-0);
|
||||
line-height: 1.5;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
@@ -76,70 +81,62 @@ a {
|
||||
outline-offset: 3px;
|
||||
}
|
||||
|
||||
/* ---------- Landing: the menus as tap handles ----------
|
||||
Each category is a card whose face is the first page of that menu, so the
|
||||
navigation is made of the restaurant's own paper. The row scrolls sideways
|
||||
and snaps; on a wide screen it wraps into a grid instead. */
|
||||
/* Every uppercase label in this system is tracked, never tight. */
|
||||
.label {
|
||||
font-size: 0.68rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
/* ---------- Landing: the menu directory ---------- */
|
||||
|
||||
.landing {
|
||||
max-width: var(--content-max);
|
||||
margin: 0 auto;
|
||||
padding: 0 0 3rem;
|
||||
padding: 0 1.25rem 3.5rem;
|
||||
}
|
||||
|
||||
.masthead {
|
||||
padding: clamp(2.2rem, 10vh, 4.5rem) 1.1rem 1.5rem;
|
||||
padding: clamp(2.25rem, 10vh, 4.5rem) 0 1.75rem;
|
||||
border-bottom: 1px solid var(--hairline);
|
||||
}
|
||||
|
||||
.wordmark {
|
||||
margin: 0;
|
||||
font-size: clamp(1.95rem, 8.5vw, 2.9rem);
|
||||
font-weight: 700;
|
||||
font-stretch: 118%;
|
||||
letter-spacing: -0.025em;
|
||||
line-height: 1;
|
||||
font-family: var(--font-display);
|
||||
font-size: clamp(2rem, 8vw, 2.75rem);
|
||||
font-weight: 400;
|
||||
letter-spacing: -0.02em;
|
||||
line-height: 1.05;
|
||||
}
|
||||
|
||||
.masthead__tagline {
|
||||
margin: 0.5rem 0 0;
|
||||
color: var(--ink-dim);
|
||||
font-size: 0.98rem;
|
||||
margin: 0.6rem 0 0;
|
||||
color: var(--ink-soft);
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.shelves {
|
||||
display: flex;
|
||||
gap: 0.85rem;
|
||||
padding: 0.15rem 0 1rem 1.1rem;
|
||||
overflow-x: auto;
|
||||
scroll-snap-type: x mandatory;
|
||||
/* snap against the same inset the first card starts at, so nothing is ever
|
||||
left half-scrolled under the screen edge */
|
||||
scroll-padding-left: 1.1rem;
|
||||
scrollbar-width: none;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.shelves::-webkit-scrollbar {
|
||||
display: none;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.shelf {
|
||||
position: relative;
|
||||
flex: 0 0 10.5rem;
|
||||
height: 15rem;
|
||||
overflow: hidden;
|
||||
background: var(--paper);
|
||||
box-shadow: 0 1px 0 var(--sheet-shadow);
|
||||
scroll-snap-align: start;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.9rem;
|
||||
padding: 0.95rem 0;
|
||||
border-bottom: 1px solid var(--hairline);
|
||||
}
|
||||
|
||||
.shelf__peek {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 3.2rem;
|
||||
left: 0;
|
||||
display: block;
|
||||
flex: 0 0 auto;
|
||||
width: 3.4rem;
|
||||
height: 4.4rem;
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--hairline);
|
||||
border-radius: var(--radius-card);
|
||||
background: var(--paper);
|
||||
}
|
||||
|
||||
.shelf__peek img {
|
||||
@@ -152,49 +149,48 @@ a {
|
||||
}
|
||||
|
||||
.shelf__name {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 3.2rem;
|
||||
left: 0;
|
||||
padding: 0.45rem 0.6rem;
|
||||
background: color-mix(in srgb, var(--steel) 88%, transparent);
|
||||
font-size: 1.05rem;
|
||||
font-weight: 700;
|
||||
font-family: var(--font-display);
|
||||
font-size: 1.45rem;
|
||||
font-weight: 400;
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
.shelf__pages {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
height: 3.2rem;
|
||||
padding: 0.85rem 0.6rem;
|
||||
background: var(--paper);
|
||||
color: var(--ink-on-paper);
|
||||
font-size: 0.8rem;
|
||||
font-variant-numeric: tabular-nums;
|
||||
line-height: 1.15;
|
||||
}
|
||||
|
||||
.shelf:hover .shelf__name,
|
||||
.shelf:focus-visible .shelf__name {
|
||||
background: color-mix(in srgb, var(--accent) 90%, transparent);
|
||||
color: var(--steel);
|
||||
color: var(--amber-deep, #b08544);
|
||||
}
|
||||
|
||||
.shelf:hover .shelf__peek img,
|
||||
.shelf:focus-visible .shelf__peek img {
|
||||
transform: scale(1.04);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
/* the dot leader that carries the eye from the name to the count */
|
||||
.leader {
|
||||
flex: 1 1 auto;
|
||||
align-self: flex-end;
|
||||
margin-bottom: 0.4rem;
|
||||
border-bottom: 1px dotted #cdc5bd;
|
||||
}
|
||||
|
||||
.shelf__pages {
|
||||
flex: 0 0 auto;
|
||||
color: var(--ink-soft);
|
||||
font-size: 0.78rem;
|
||||
font-weight: 600;
|
||||
font-variant-numeric: tabular-nums;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
|
||||
.empty {
|
||||
max-width: 34ch;
|
||||
margin: 1rem 1.1rem 0;
|
||||
color: var(--ink-dim);
|
||||
font-size: var(--step-1);
|
||||
margin: 1.25rem 0 0;
|
||||
color: var(--ink-soft);
|
||||
font-size: 1.05rem;
|
||||
}
|
||||
|
||||
/* ---------- Section page: the bar and the switcher ---------- */
|
||||
/* ---------- Section page: the menu bar ---------- */
|
||||
|
||||
.bar {
|
||||
position: sticky;
|
||||
@@ -202,27 +198,38 @@ a {
|
||||
z-index: 20;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.7rem;
|
||||
padding: 0.5rem 0.85rem 0.45rem;
|
||||
background: color-mix(in srgb, var(--rail) 94%, transparent);
|
||||
backdrop-filter: blur(6px);
|
||||
gap: 1rem;
|
||||
padding: 0.6rem 1.25rem;
|
||||
background: color-mix(in srgb, var(--steel) 92%, transparent);
|
||||
backdrop-filter: blur(8px);
|
||||
border-bottom: 1px solid var(--hairline);
|
||||
}
|
||||
|
||||
.bar__brand {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.55rem;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.bar__brand img {
|
||||
display: block;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
border-radius: var(--radius-pill);
|
||||
}
|
||||
|
||||
.bar__name {
|
||||
font-family: var(--font-display);
|
||||
font-size: 1.05rem;
|
||||
letter-spacing: -0.01em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.bar__nav {
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
gap: 0.15rem;
|
||||
gap: 0.35rem;
|
||||
overflow-x: auto;
|
||||
scrollbar-width: none;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
@@ -233,38 +240,41 @@ a {
|
||||
}
|
||||
|
||||
.bar__link {
|
||||
padding: 0.35rem 0.65rem;
|
||||
background: color-mix(in srgb, var(--ink) 9%, transparent);
|
||||
color: var(--ink-dim);
|
||||
font-size: 0.95rem;
|
||||
padding: 0.42rem 0.9rem;
|
||||
border: 1px solid transparent;
|
||||
border-radius: var(--radius-pill);
|
||||
color: var(--ink-soft);
|
||||
font-size: 0.78rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.02em;
|
||||
white-space: nowrap;
|
||||
transition: background 0.18s ease, color 0.18s ease;
|
||||
}
|
||||
|
||||
.bar__link:hover {
|
||||
background: color-mix(in srgb, var(--accent) 16%, transparent);
|
||||
color: var(--ink);
|
||||
background: color-mix(in srgb, var(--ink) 15%, transparent);
|
||||
}
|
||||
|
||||
.bar__link.is-current {
|
||||
background: var(--accent);
|
||||
background: var(--ink);
|
||||
color: var(--steel);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.pour {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
bottom: -1px;
|
||||
left: 0;
|
||||
height: 2px;
|
||||
background: var(--hairline-soft);
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.pour__fill {
|
||||
display: block;
|
||||
width: 0;
|
||||
height: 100%;
|
||||
background: var(--copper);
|
||||
background: var(--accent);
|
||||
}
|
||||
|
||||
/* ---------- The pages themselves ---------- */
|
||||
@@ -275,52 +285,58 @@ a {
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
max-width: var(--page-max);
|
||||
margin: 1.2rem auto 0.75rem;
|
||||
padding: 0 0.9rem;
|
||||
margin: 1.75rem auto 1rem;
|
||||
padding: 0 1.25rem;
|
||||
}
|
||||
|
||||
.section-heading__label {
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--step-2);
|
||||
font-weight: 700;
|
||||
letter-spacing: -0.02em;
|
||||
font-weight: 400;
|
||||
letter-spacing: -0.015em;
|
||||
}
|
||||
|
||||
.section-heading__date {
|
||||
color: var(--ink-dim);
|
||||
font-size: 0.88rem;
|
||||
font-size: 0.68rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.notice {
|
||||
max-width: var(--page-max);
|
||||
margin: 0 auto 1rem;
|
||||
padding: 0.6rem 0.8rem;
|
||||
border-left: 2px solid var(--copper);
|
||||
margin: 0 auto 1.25rem;
|
||||
padding: 0.7rem 0.9rem;
|
||||
border-left: 2px solid var(--accent);
|
||||
background: var(--rail);
|
||||
font-size: 0.95rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.notice a {
|
||||
color: var(--accent);
|
||||
color: var(--copper);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.notice--admin {
|
||||
max-width: none;
|
||||
border-left-color: var(--accent);
|
||||
background: color-mix(in srgb, var(--accent) 20%, var(--rail));
|
||||
background: color-mix(in srgb, var(--accent) 12%, var(--rail));
|
||||
}
|
||||
|
||||
.pages {
|
||||
max-width: var(--page-max);
|
||||
margin: 0 auto;
|
||||
padding: 0 0.7rem 1.25rem;
|
||||
padding: 0 1.25rem 1.5rem;
|
||||
}
|
||||
|
||||
.page {
|
||||
margin: 0 0 0.6rem;
|
||||
margin: 0 0 0.85rem;
|
||||
padding: 0.4rem;
|
||||
background: var(--paper);
|
||||
box-shadow: 0 1px 0 color-mix(in srgb, #000 35%, transparent);
|
||||
border: 1px solid var(--hairline);
|
||||
border-radius: var(--radius-card);
|
||||
box-shadow: var(--shadow-card);
|
||||
}
|
||||
|
||||
.page__zoom {
|
||||
@@ -331,25 +347,29 @@ a {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
|
||||
/* ---------- Footer: page index and older menus ---------- */
|
||||
|
||||
.foot {
|
||||
max-width: var(--page-max);
|
||||
margin: 0 auto 4.5rem;
|
||||
padding: 0 0.9rem 1rem;
|
||||
border-top: 1px solid var(--hairline-soft);
|
||||
margin: 0 auto 5rem;
|
||||
padding: 0 1.25rem 1rem;
|
||||
border-top: 1px solid var(--hairline);
|
||||
}
|
||||
|
||||
.fold {
|
||||
padding: 0.7rem 0;
|
||||
border-bottom: 1px solid var(--hairline-soft);
|
||||
padding: 0.85rem 0;
|
||||
border-bottom: 1px solid var(--hairline);
|
||||
}
|
||||
|
||||
.fold summary {
|
||||
color: var(--ink-dim);
|
||||
font-size: 0.92rem;
|
||||
color: var(--ink-soft);
|
||||
font-size: 0.68rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -360,29 +380,33 @@ a {
|
||||
.index {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.4rem;
|
||||
gap: 0.45rem;
|
||||
margin: 0;
|
||||
padding: 0.85rem 0 0;
|
||||
padding: 1rem 0 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.index a {
|
||||
display: block;
|
||||
min-width: 2.3rem;
|
||||
padding: 0.3rem 0.45rem;
|
||||
background: var(--rail);
|
||||
min-width: 2.4rem;
|
||||
padding: 0.35rem 0.5rem;
|
||||
border: 1px solid var(--hairline);
|
||||
border-radius: var(--radius-pill);
|
||||
color: var(--ink-soft);
|
||||
font-size: 0.78rem;
|
||||
font-weight: 600;
|
||||
font-variant-numeric: tabular-nums;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.index a:hover,
|
||||
.index a:focus-visible {
|
||||
background: var(--accent);
|
||||
background: var(--ink);
|
||||
color: var(--steel);
|
||||
}
|
||||
|
||||
.older {
|
||||
margin: 0.5rem 0 0;
|
||||
margin: 0.6rem 0 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
@@ -391,25 +415,30 @@ a {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
padding: 0.45rem 0.15rem;
|
||||
padding: 0.55rem 0.15rem;
|
||||
border-bottom: 1px solid var(--hairline-soft);
|
||||
}
|
||||
|
||||
.older__label {
|
||||
font-weight: 500;
|
||||
font-family: var(--font-display);
|
||||
font-size: 1.05rem;
|
||||
}
|
||||
|
||||
.older__date {
|
||||
color: var(--ink-dim);
|
||||
font-size: 0.88rem;
|
||||
font-size: 0.72rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.06em;
|
||||
text-transform: uppercase;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.fold__back {
|
||||
margin: 0.7rem 0 0;
|
||||
margin: 0.85rem 0 0;
|
||||
}
|
||||
|
||||
.fold__back a {
|
||||
color: var(--accent);
|
||||
color: var(--copper);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
@@ -417,19 +446,24 @@ a {
|
||||
|
||||
.counter {
|
||||
position: fixed;
|
||||
right: 0.85rem;
|
||||
bottom: calc(0.85rem + env(safe-area-inset-bottom));
|
||||
right: 1.25rem;
|
||||
bottom: calc(1.25rem + env(safe-area-inset-bottom));
|
||||
z-index: 30;
|
||||
display: inline-flex;
|
||||
align-items: baseline;
|
||||
gap: 0.3rem;
|
||||
padding: 0.45rem 0.7rem;
|
||||
border: 1px solid var(--brass-edge);
|
||||
background: var(--paper);
|
||||
color: var(--ink-on-paper);
|
||||
gap: 0.35rem;
|
||||
padding: 0.55rem 0.9rem;
|
||||
border: 0;
|
||||
border-radius: var(--radius-pill);
|
||||
background: var(--ink);
|
||||
color: var(--steel);
|
||||
font: inherit;
|
||||
font-size: 0.88rem;
|
||||
font-size: 0.72rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
font-variant-numeric: tabular-nums;
|
||||
box-shadow: var(--shadow-float);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -438,7 +472,7 @@ a {
|
||||
}
|
||||
|
||||
.counter__total {
|
||||
color: color-mix(in srgb, var(--ink-on-paper) 55%, transparent);
|
||||
color: color-mix(in srgb, var(--steel) 62%, transparent);
|
||||
}
|
||||
|
||||
.zoom {
|
||||
@@ -446,8 +480,10 @@ a {
|
||||
inset: 0;
|
||||
z-index: 50;
|
||||
overflow: auto;
|
||||
background: rgba(6, 9, 10, 0.96);
|
||||
background: rgba(18, 17, 16, 0.45);
|
||||
backdrop-filter: blur(8px);
|
||||
-webkit-overflow-scrolling: touch;
|
||||
padding: 1.25rem 0;
|
||||
}
|
||||
|
||||
.zoom img {
|
||||
@@ -455,34 +491,41 @@ a {
|
||||
width: min(100%, 1600px);
|
||||
height: auto;
|
||||
margin: 0 auto;
|
||||
border-radius: var(--radius-card);
|
||||
box-shadow: var(--shadow-float);
|
||||
}
|
||||
|
||||
.zoom__close {
|
||||
position: fixed;
|
||||
top: 0.6rem;
|
||||
right: 0.6rem;
|
||||
top: 0.75rem;
|
||||
right: 0.75rem;
|
||||
z-index: 1;
|
||||
padding: 0.5rem 0.75rem;
|
||||
border: 1px solid var(--brass-edge);
|
||||
background: var(--paper);
|
||||
color: var(--ink-on-paper);
|
||||
padding: 0.55rem 1rem;
|
||||
border: 0;
|
||||
border-radius: var(--radius-pill);
|
||||
background: var(--ink);
|
||||
color: var(--steel);
|
||||
font: inherit;
|
||||
font-size: 0.72rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* ---------- Wider screens ---------- */
|
||||
|
||||
@media (min-width: 62rem) {
|
||||
.shelves {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(10.5rem, 1fr));
|
||||
gap: 1rem;
|
||||
padding: 0.15rem 1.1rem 1rem;
|
||||
overflow: visible;
|
||||
.landing {
|
||||
padding-bottom: 4.5rem;
|
||||
}
|
||||
|
||||
.shelf {
|
||||
height: 16rem;
|
||||
padding: 1.15rem 0;
|
||||
}
|
||||
|
||||
.shelf__name {
|
||||
font-size: 1.7rem;
|
||||
}
|
||||
|
||||
.pages {
|
||||
@@ -492,7 +535,6 @@ a {
|
||||
|
||||
@media print {
|
||||
.bar,
|
||||
.sheet,
|
||||
.counter,
|
||||
.fold,
|
||||
.notice {
|
||||
@@ -501,10 +543,11 @@ a {
|
||||
|
||||
body {
|
||||
background: #fff;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.page {
|
||||
border: 0;
|
||||
box-shadow: none;
|
||||
break-inside: avoid;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -72,7 +72,8 @@ export function setDateLabel(manifest: SetManifest): string {
|
||||
function renderBar(config: SiteConfig, currentSlug: string, menu: readonly MenuLink[]): Html {
|
||||
return html`<header class="bar">
|
||||
<a class="bar__brand" href="/" aria-label="${config.brand.name} — all menus">
|
||||
<img src="${config.brand.logo ?? '/assets/favicon.svg'}" alt="" width="24" height="24" />
|
||||
<img src="${config.brand.logo ?? '/assets/favicon.svg'}" alt="" width="26" height="26" />
|
||||
<span class="bar__name">${config.brand.name}</span>
|
||||
</a>
|
||||
<nav class="bar__nav" aria-label="Menus">
|
||||
${join(
|
||||
@@ -178,6 +179,7 @@ export function renderLanding(input: LandingInput): Html {
|
||||
><img src="${entry.cover}" alt="" loading="lazy" decoding="async"
|
||||
/></span>`}
|
||||
<span class="shelf__name">${entry.section.label}</span>
|
||||
<span class="leader" aria-hidden="true"></span>
|
||||
<span class="shelf__pages">${pageCountLabel(entry.pages)}</span>
|
||||
</a>`,
|
||||
),
|
||||
|
||||
Reference in new issue
Block a user