# Meridian prototype, design system and build notes Static marketing-site prototype. Plain HTML5, vanilla CSS custom properties, vanilla JS. No framework, no build step, no package manager. Run it: `python3 -m http.server 8000` from this folder, open `http://localhost:8000`. Everything below reflects the build as it stands. It supersedes any earlier brief. Where the live site (meridianworkspaces.com) and the original spec disagree, the resolution is recorded under **Open questions**. --- ## 1. Brand palette Sampled directly from the logo file (`assets/logo/meridian-mark.svg`). These four are the entire palette. The mark is mostly ink with a coral eastern half, and the site is built to roughly that same ratio. | Token | Hex | In the logo | Used for | |---|---|---|---| | `--ink` | `#14161C` | ring and wordmark | all text, dark sections, footer | | `--coral` | `#FF7A5C` | eastern half | primary CTA fill, accent rules, chips, highlights | | `--amber` | `#F79E4B` | warm longitude | hover states, Singapore branch colour | | `--sky` | `#8FB8FF` | cool longitude | Copenhagen branch colour, link underlines, washes | `--sunflower`, `--ember` and `--teal` survive as aliases of `--coral`, `--amber` and `--sky` so the component layer did not need a 2,000-line rename. New work should use the names in the table. ### The one rule that matters **Coral, amber and sky are fills, strokes and shapes. They are never text colour on a light background.** All three fail WCAG AA as text on paper (2.30:1, 1.89:1, 1.80:1 respectively). When you want a coloured accent carrying words, invert it: put `--ink` text on a solid accent fill. Ink on coral is 7.05:1, ink on amber 8.57:1, ink on sky 9.01:1. All three accents are deliberately light enough to take ink text, because every one of them is used as a chip or a fill somewhere on the site. This rule has been broken twice during the build and caught both times by the contrast audit. Check any new accent-coloured text against it. ### Surfaces | Token | Hex | Notes | |---|---|---| | `--offwhite` | `#F5F2EC` | page background. Never pure white, it reads cold | | `--surface` | `#FCFAF6` | card faces, one step above the page | | `--surface-sunk` | `#EDE9E1` | alternating section bands, image letterboxes | | `--warmgrey` | `#6C6A73` | muted and secondary text. 4.76:1 on offwhite | | `--line` | `rgba(20,22,28,.10)` | hairlines | | `--line-strong` | `rgba(20,22,28,.18)` | input borders, ghost buttons | ### Washes, for large soft fills `--sunflower-wash` `rgba(255,122,92,.14)` · `--ember-wash` `rgba(247,158,75,.14)` · `--teal-wash` `rgba(143,184,255,.20)` Ink on any wash is 17:1 or better. Warmgrey on a wash is 4.9 to 5.2:1, which passes but leaves little headroom, so do not go lighter than warmgrey on one. --- ## 2. Typography ``` --font-head: 'Hanken Grotesk' headings, numbers, prices --font-body: 'Inter' body copy, labels, UI ``` **These are stand-ins.** The live site serves **Galano Grotesque** (headings) and **Apercu** (body), confirmed from its own `@font-face` declarations. When the licensed files arrive, change the two tokens in `css/tokens.css` and the `` in each page head. Nothing else needs touching. ### Scale | Token | Value | Used for | |---|---|---| | `--display` | `clamp(3rem, 7.5vw, 6rem)` | page-defining headlines | | `--h1` | `clamp(2.4rem, 5vw, 4rem)` | | | `--h2` | `clamp(1.8rem, 3.5vw, 2.75rem)` | section headings | | `--statement` | `clamp(1.5rem, 3.2vw, 2.5rem)` | manifesto and pull-quote type | | `--num` | `clamp(2rem, 4.5vw, 3.5rem)` | large numerals | | `--h3` | `1.35rem` | | | `--body` | `1.0625rem` | | | `--kicker` | `.8125rem` | uppercase eyebrow, +10% tracking, warmgrey. No leading rule: the tracking does that work | | `--micro` | `.75rem` | labels, meta, notes | Headings run `font-weight: 700`, `line-height: 1.08`, `letter-spacing: -0.02em`, tightening to `-0.035em` at display sizes. Body is `line-height: 1.6`. The hero on the homepage scales on **both axes**, `clamp(2.5rem, min(7.2vw, 10.5vh), 6rem)`, so a short landscape monitor shrinks the headline instead of overflowing it. ### The tittle swap The dot on the **first lowercase "i" in every `

`** is replaced by the coral fill from the logo mark. - `js/main.js` wraps that one letter in `i`. - `.tittle__g` carries a CSS mask that **cuts the dot off the glyph** at `.30em` from the top of its 1em inline box. That figure was measured against Hanken Grotesk 700, not guessed. Re-measure it if the heading font changes. - `.tittle__t` is a sibling, not a pseudo-element, because a mask applies to an element's whole subtree and would erase the triangle too. - Masking rather than covering is deliberate: the headline often sits on a photograph, so a coloured patch over the dot would show its edges. - The real `i` stays in the DOM, so copy-paste, find-in-page and screen readers are unaffected. **First occurrence only.** A long headline can hold five or six lowercase i's and marking all of them reads as noise. Opt a heading out entirely with `data-no-tittle` on the `h1` or any ancestor. **Article pages are opted out** and use normal letters. --- ## 3. Other tokens ``` --maxw 1200px container width --gap clamp(1rem, 2.5vw, 2rem) --section-y clamp(4rem, 9vw, 7rem) --radius 16px --radius-sm 10px --radius-lg 24px --radius-pill 999px --ease cubic-bezier(.22,.61,.36,1) --ease-out cubic-bezier(.16,1,.3,1) --dur-fast 140ms --dur 200ms --dur-slow 380ms ``` Shadows are **warm-tinted, never neutral grey**: `--shadow-sm`, `--shadow-md`, `--shadow-lg`. Focus rings are double-stroke so they read on any ground: `--focus` on light, `--focus-on-ink` inside `.on-ink` containers. --- ## 4. File layout ``` / index.html homepage services.html services hub service-coworking.html \ service-dedicated-desk.html | service-serviced-office.html | 6 service pages service-virtual-office.html | service-event-space.html | service-meeting-room.html / locations.html locations hub location-salcedo.html \ location-legazpi.html | 3 location pages location-rockwell.html / news.html news archive article.html single article template contact.html contact css/tokens.css palette, type scale, rhythm. Edit this first css/base.css reset, typography, layout primitives css/components.css everything else, ~2400 lines js/main.js all behaviour, ~250 lines assets/logo/ 4 logo variants assets/icons/ 23 brand line-icons assets/img/ photography ``` There are no partials or includes. **Nav and footer markup is duplicated in every page.** When you change either, change it everywhere, or regenerate the pages from one another with a script. --- ## 5. Layout primitives | Class | Does | |---|---| | `.wrap` | centred container, `--maxw`, responsive gutter | | `.section` | vertical rhythm band, `--section-y` | | `.section--tight` | 62% of that | | `.section--sunk` | `--surface-sunk` background, for alternating bands | | `.section--ink` | ink background, light text | | `.on-ink` | switches focus rings to the light variant | | `.sec-head` | kicker + h2 on the left, optional link on the right | | `.split` | two-column editorial pair, collapses at 900px | | `.measure` | 62ch cap for long-form copy | | `.grid-2/3/4` | equal columns, collapse at 960 then 640 | --- ## 6. Component inventory ### Global - **`.nav`** fixed, transparent over photo heroes, turns to glass on scroll. Add **`.nav--onlight`** on any page that opens on a light background, or the white links vanish against off-white. Add `.nav--solid` to start glassy. `z-index: 130`, above the drawer, so the close button stays reachable. - **Nav dropdowns** `.nav__item--has-menu` with `.nav__toggle` and `.nav__menu`. Two menus: Services (two columns, prices inline) and Locations (branch dots in logo colours). Hover or click on desktop, click-accordion in the mobile drawer. Escape closes, click-outside closes, tabbing out closes, `aria-expanded` mirrors state. - **`.nav__drawer`** mobile slide-in, reuses the same dropdown markup. - **`.booking-fab`** floating glass pill, appears past 520px of scroll, carries the logo's stacked circle pair. - **`.footer`** ink, four columns, three addresses, newsletter, socials. ### Buttons `.btn` plus one of `--primary` (coral fill, ink text), `--ink`, `--ghost`, `--ghost-light` (for photo backgrounds). Sizes `--sm`, `--lg`, `--block`. All pill-radius. ### Cards and content blocks | Class | Where | |---|---| | `.tile` + `.bento` | homepage services grid, six items in six unequal cells | | `.room` + `.rooms` | event space and meeting room rate cards | | `.rooms--wide` | two columns with the photo alongside, for content-heavy cards | | `.plan` + `.plans` | dedicated desk and serviced office, per-branch pricing | | `.ptable` | plan comparison tables, coworking and virtual office | | `.svcrow` + `.rows` | index rows, services hub and location pages | | `.row` | numbered hairline rows, homepage "Why Meridian" | | `.loccard` + `.loccards` | location cards with glass caption panels | | `.locindex` | homepage locations band, three-column index over a photo | | `.amen` + `.amengrid` | 20 amenities, each with its own brand icon | | `.biz` + `.bizgrid` | business solutions, services hub | | `.setup` + `.setups` | event space layout options | | `.post` + `.postgrid` | news archive cards, `.post--lead` for the featured one | | `.cmethod` | contact methods, colour-coded left border | | `.branchmap` | map plus address, contact page | ### Heroes - **`.hero`** homepage only. Full-bleed photo, `min-height: 100svh` so it fills exactly one viewport on any monitor. `svh` not `vh`, so mobile browser chrome cannot push the CTAs below the fold. Content vertically centred, with heavier top padding than bottom so it centres in the space *below* the overlaid nav. Drops out of full-screen under 640px viewport height. - **`.svchero`** every other page. Photo band, `min(66svh, 620px)`, breadcrumbs, h1, lead, optional `.availpill`. Both heroes close with a three-colour rule in coral, sky and amber. ### Glass Frosted glass appears on exactly four things: the sticky nav, the floating booking pill, panels sitting over a real photograph, and the nav dropdowns. **Never glass over a flat background with nothing behind it.** Every glass surface has a `@supports not (backdrop-filter: ...)` solid fallback, and tint climbs on small screens where the crop behind is busier. The booking form on the CTA band is **ink-tinted glass at 72%**, not light. A light frost there sits over the coral wedge and drops its labels below AA. ### Motion `.reveal` fades and lifts on scroll via IntersectionObserver. `[data-reveal-group="60"]` staggers children by that many ms. `.reveal` starts at `opacity: 0`, so a **2 second failsafe** in `main.js` shows anything the observer never reported on. Without it, a missed callback would leave content invisible for good. All motion collapses under `prefers-reduced-motion`. The perks marquee stops and rewraps into a readable list rather than freezing mid-scroll. --- ## 7. Page architecture The homepage deliberately uses **eight different layout families in eight sections**, because an earlier draft used the same kicker-heading-grid shape throughout and read as templated. | # | Section | Family | |---|---|---| | 1 | Hero | full-bleed photo, bottom-anchored two-part composition | | 2 | Manifesto | centred type statement, no image, no grid | | 3 | Spaces | asymmetric bento, six items in six cells | | 4 | Locations | full-bleed panorama with an overlaid three-column index | | 5 | Why Meridian | hairline rows with colour chips, no cards | | 6 | Perks | marquee, the only one on the site | | 7 | Quote | single large pull quote | | 7b | Testimonials | hairline three-column quote row under the pull quote | | 8 | CTA | full-bleed ink, photo background, coral wedge, glass form | Two conventions worth keeping: - **Eyebrow budget.** At most one `.kicker` per three sections. The homepage has three across eight sections. They multiply easily and flatten the rhythm. - **No decorative dots.** Coloured dots are used only where they carry meaning, the branch colour coding, never as ornament. --- ## 8. Accessibility - **Every colour pair in the build has been checked.** Roughly 120 combinations across all components, including glass composited over both dark and bright photo crops. All pass WCAG AA. Re-run the check when adding a coloured surface, and remember the fills-not-text rule in section 1. - Alt text on every image. Decorative images carry `alt=""`. - Focus visible everywhere, double-stroke so it reads on any ground. - Semantic landmarks, real `` and `