S/Y Celestine logoStyle guide

Style guide

Every color, size, component and rule of the S/Y Celestine site, shown as it ships. The specimens are the real components, and the numbers are read from the source.

65°06′W65°00′W64°54′W64°48′W64°42′W64°36′W64°30′W64°24′W64°18′W18°42′N18°36′N18°30′N18°24′N18°18′NN5 NAUTICAL MILESVirgin IslandsA SEVEN-NIGHT PASSAGE

Drag the chart to pan

The itineraries hero chartNot for navigation

The system is called The Chartroom Logbook: a navigator's chart table made elegant. Deep navy fields printed with charts and blueprints alternate with pale frost pages; a classical serif speaks, and small tracked capitals annotate.

This page shows what ships. DESIGN.md holds the reasoning behind every rule named here, and where the two disagree the source is the truth. tools/build-docs.py writes the token values and contrast ratios, and lifts several specimens straight out of the generated pages.

Palette

Three pinned colors and one coral. Every other color is a lightness step inside one of the three families, computed to hit a contrast target, not picked by eye.

The palette is cool on purpose: Harbor Coral is the only warm thing on the page, which gives it its force. A new pin is a decision for the client.

Field

Celestine Navy#061e45
Night Watch#041530
Midnight Hull#020c1d

Structure

Chart Ink#36454f
Harbor Steel#4a5f6d
Slate Muted#566771
Steel Blue#5b7d90
Chart Label#3d6b7d

Water

Harbor Sky#7fa8b8
Shallow Water#9dc4d2
Chart Rule#a9cbd6
Pale Sky#d6ecf1

Light

Sea Glass#c3e3eb
Sea Glass Deep#cfdfe5
Canvas#eaf3f6
Sea Glass Light#f4fafc

The one coral

Harbor Coral#ff5a5f

What each color is for

ColorTokenRole
Celestine Navy Pinned--navy-coreThe anchor. Every navy field and every chart field, photo wells, the browser's theme color.
Night Watch--navy-shadeThe darker navy step: the field behind the destination card photos.
Midnight Hull--navy-deepText on frost, dark buttons, badges, overlays and the footer.
Chart Ink Pinned--steel-inkThe charcoal. Body and secondary text on frost, the nav links over the hero, fine linework.
Harbor Steel--steel-shadeSupporting text and the base link color. Canvas surfaces only.
Slate Muted--slate-mutedMuted small print. Canvas surfaces only.
Steel Blue--steel-blueThe focus ring, chosen to clear 3:1 against navy, Canvas and Sea Glass at once. Small accents.
Chart Label--chart-labelTracked uppercase annotations on Canvas: places, days, captions. Canvas surfaces only.
Harbor Sky--harbor-skySecondary action fill with Midnight Hull text; gauge fills; the on-hold stripe; text selection; the log section's background.
Shallow Water--sky-tintHighlights on navy: chart pins, key numerals, the weather reading. Open days in the calendar.
Chart Rule--chart-ruleHairlines. Quiet on purpose: it marks an edge, not a boundary anyone has to read.
Pale Sky--pale-skyQuiet panels, and the base of the calendar's on-hold stripe.
Sea Glass Pinned--seaglassThe pale. The text color on every navy field, small chrome on navy, the hover fill of dark buttons.
Sea Glass Deep--seaglass-deepWhat shows behind a photograph while it loads.
Canvas--canvasThe one light section surface. A background only, never a text color.
Sea Glass Light--seaglass-lightThe polaroid mat around plates and chart insets, and caption panels.
Harbor Coral--harbor-coralThe primary booking action and nothing else, always with Midnight Hull text.

Translucent steps are written from the channel tokens, for example rgb(var(--seaglass-rgb) / 0.72). Sea Glass runs from 0.12 (borders) to 0.95 (halos); Midnight Hull from 0.72 to 0.96 for overlays. Functional labels never drop below 0.72.

  • The Three Pins RuleThe palette derives from #061e45, #36454f and #c3e3eb, plus Harbor Coral. Reference colors through the tokens, never as raw hex.
  • The One Coral RuleCoral marks the single most important action in a view, the Charter Smarter booking link. Never decoration, text or tags, and never two competing in one viewport: the floating bar hides itself while the closing section's coral button is on screen.

Two worlds and contrast

Every section is either navy with Sea Glass ink, or Canvas with navy and charcoal ink. There is no white section and no gray one.

The site has one color scheme (color-scheme: light). The two worlds do the work a theme would: navy for atmosphere (stats, destinations, the tour, booking), frost for detail and decisions (gallery, crew, layout, rates, availability).

On Canvas

A week has shape and generosity.

Body copy takes Chart Ink. Prose links take Harbor Steel, and Celestine Navy on hover.

Annotation in Chart Label

Measured contrast

Computed from the shipped tokens, with a translucent ink composited over its field first, and rounded down so no pair is rounded up over a threshold. Text needs 4.5:1; large text and non-text marks such as the focus ring need 3:1.

SamplePairRatioUsed for
Aa Sea GlassSea Glass on Celestine Navy12.1:1All text on navy fields.
Aa at 0.72Sea Glass at 0.72 on Celestine Navy6.8:1Secondary labels on navy: the floor for anything functional.
Aa Shallow WaterShallow Water on Celestine Navy8.8:1Highlights on navy; the arrow in a leg's title.
Aa Sea GlassSea Glass on Midnight Hull14.4:1The footer, badges, dark buttons.
Aa Midnight HullMidnight Hull on Canvas17.3:1Headings and primary text on frost.
Aa Chart InkChart Ink on Canvas8.7:1Body and secondary text on frost.
Aa Harbor SteelHarbor Steel on Canvas5.9:1Supporting text and links.
Aa Slate MutedSlate Muted on Canvas5.2:1Muted small print.
Aa Chart LabelChart Label on Canvas5.1:1Tracked uppercase annotations.
12 at 0.62Midnight Hull at 0.62 on Canvas5.3:1Booked, unavailable and past days in the calendar.
Aa BookMidnight Hull on Harbor Coral6.4:1The primary button.
Aa BrokersMidnight Hull on Harbor Sky7.6:1The secondary button on navy.
7 pinMidnight Hull on Shallow Water10.4:1Chart pins, key numerals, open calendar days.
ringSteel Blue on Celestine Navy3.7:1The focus ring: one color that clears 3:1 on all three fields. On navy surfaces the ring switches to Sea Glass anyway.
ringSteel Blue on Canvas3.9:1
ringSteel Blue on Sea Glass3.2:1

Pairs that are never used

Recorded so that nobody reaches for them. Each has cost a bug before.

SamplePairRatioInstead
Sea Glass on Harbor Coral2.2:1Coral and Harbor Sky fills always take Midnight Hull.
Harbor Steel on Celestine Navy2.4:1The base link color is for Canvas. A navy surface names its own link ink: Sea Glass.
Chart Rule on Canvas1.5:1Chart Rule is for hairlines only. It never carries text or a boundary that must be read.
  • The Two Worlds RuleEvery section is navy or light. Canvas is the one approved light surface; Sea Glass stays available as a panel fill that reads as a panel.
  • The Photographic Field RuleA light section that carries a photograph (crew, rates) is still a Canvas section. It is washed with rgb(var(--canvas-rgb) / α), and α is solved so Chart Ink clears 4.5:1 over the photograph's darkest pixel: 0.74 on crew, 0.64 on rates. Harbor Steel, Chart Label and Slate Muted never sit on the wash; they get a Canvas panel. Re-measure when a photograph changes.
  • The Calendar Legibility RuleEvery calendar day state clears 4.5:1, and state is never carried by color alone: each day has hidden text, and on-hold days keep their stripe.

Type system

A classical, high-contrast serif for voice, and one geometric sans in two voices: used light for everything you read or count, and tracked out in capitals like the lettering on an instrument panel.

Aa Aa

Cormorant Garamond

400 and 400 italic. Headlines, ledes, names, the serif running text inside components.

A week aboard Celestine 0123456789

Aa

Jost, read

300 for body copy and readings, 400 for prices and the odd stressed fact. Its italic is not loaded, so a ship's name in body copy is slanted by the browser.

Short sails, long afternoons 0123456789

Aa

Jost, annotated

The same face as the label voice: always uppercase and tracked, 400 for labels, 500 for short standout labels and pin numbers, 300 for the faint print on the charts. Nothing heavier exists here.

Under sail · Book · 1 h 30 min

That is everything in assets/fonts/, and CSS may ask for nothing else: a missing weight is silently drawn at the nearest one. The families are reached through --font-display, --font-body and --font-label. Both sans tokens are Jost; they stay separate so either voice can change face alone. Each stack leads with a metric-matched stand-in (Georgia at 88.4%, Arial at 92.8%) so the swap to the webfont moves no line break.

  • The Logbook Voice RuleSerif for things you would say; tracked uppercase Jost for things you would annotate or press; light Jost, in sentence case, for everything you would read or count. Never a label in Cormorant, never a paragraph in tracked capitals, never a headline in Jost. Facts follow the reading voice: an inclusion, a discount, “per person, for the week” are light Jost, even inside a card whose name is serif.
  • The One Weight Per Voice RuleThe serif is 400, the label voice is Jost 400 and body is Jost 300, on every page. On the inner pages, labels and serif fragments are named in two grouped rules beside .lede in pages.css. A new class joins the matching group.
  • The Light Hand RuleBold is not part of the system. 500 is the ceiling, and only for short uppercase labels that must hold up over photography.
  • The Heading Carries the Section RuleNo uppercase eyebrow sits above a heading. Uppercase strings are written in sentence case in the source and transformed by CSS, so assistive technology reads words, not letters.

Type scale

Roles are tokens, named for the job and not the value. Every size below is set live from its token.

Display--type-display
clamp(48px, 8vw, 92px)
leading 0.98 · hero only

Set sail.

Headline--type-headline
clamp(38px, 9vw, 58px)
leading 1 to 1.02

People who make it happen

Subhead--type-subhead
clamp(30px, 7vw, 44px)
leading 1.1

Open weeks at a glance

Title L--type-title-lg
34px · leading 1.15

Also on the chart

Title--type-title
28px · every card and entry heading

Norman Island to the Baths

Title S--type-title-sm
24px · every tile title on a phone

Clearing in and out

Lead--type-lead
22px · leading 1.5
on five columns

Every charter aboard Celestine is planned around the people on board, so no two weeks are alike.

Serif text--type-serif
20px · the floor for serif running text

The balance this charter was planned around, from its planning sheet. Yours is drawn to your own taste.

Body--type-body
17px · Jost 300 · leading 1.65
45 to 75 characters

We head for the Baths for light swimming and a hike through the granite boulders, then on to Spanish Town for dinner ashore.

Body on navy--type-body-navy
18px · Jost 300 · leading 1.65
Sea Glass on a navy field
Small--type-small
14px · Jost 300

per person, for the week

Label--type-label
12px to 13px · Jost 400 · 2 to 4px tracking

1 h 30 min under sail

Standout label16px · Jost 500 · 1px tracking
badges only

Most popular

Stat46px · Jost 300 · leading 1
instrument readings, so not the serif
  • The Optical Size RuleCormorant's x-height is 0.386em to Jost's 0.460em, so the serif reads about a sixth smaller at the same pixel size. Serif running text is never set below Serif text (20px), which is what sits level with 17px Jost: Side by side: Jost 17 · Cormorant 20 · and Cormorant 17, which is lost
  • The Heading Leads RuleA heading takes its space from above, so it binds to the block it introduces. --head-lead (1.25em) sits over a heading that follows content; --head-trail (0.4em) sits under every heading. Both are em, so a subhead leads by more than a title. A definition list cannot use a grid gap, which would put a term as far from its own explanation as from the next entry. The rule Clearing in The term hugs its own explanation and keeps its distance from the entry above. On a grid gap Clearing in One gap between every child, so the term floats and reads as the tail of what came before.
  • The Dark Field RuleLight text on navy reads smaller and thinner than the same text on Canvas. Body copy there steps up to Body on navy (18px), and running text of 14px or smaller is never lighter than 400, which is why the footer sets 400. The 46px stats numerals keep 300: at that size the hairline is the point.
  • The Plain Figures RuleFigures here are data. Cormorant's default old-style 1 and 0 read as letters, so body sets lining-nums site-wide and anything columnar adds tabular-nums beside it. The property is not additive: a rule that sets tabular-nums alone turns the old-style figures back on. $4,100 lining$4,100 old-style, never

The mark

One mark, in two inks: its own colors over light grounds, and Sea Glass on navy.

The S/Y Celestine mark in its own colors

The file is assets/Celestine-Logo.svg. Its two blues (#1f2b5b and #1e5c9f) belong to the asset and sit outside the token set. On navy the same file becomes a mask over a Sea Glass fill, so the ink is the token itself. Never tint it with a CSS filter chain: iOS Safari does not clamp between steps, and drew the mark cyan.

background: var(--seaglass);
mask: url("Celestine-Logo.svg") center / contain no-repeat;   /* with the -webkit- twin */
object-position: -999px 0;   /* the img's own pixels, out of the box */
WhereHeightInk
Homepage nav, over the hero60pxOwn colors, on the photograph
Homepage nav once scrolled; every inner page's nav46pxSea Glass, by mask
Footer46pxSea Glass, by mask, at 90%
This guide's bar40pxSea Glass, by mask

Beside it

The favicon: the mark on a rounded navy field The touch icon: the mark square to the edge The Charter Smarter mark

The favicon (assets/icon.svg) sets the mark on a rounded field of Celestine Navy, the pages' theme-color. tools/build-icons.py rasterizes every other icon from it; the touch and manifest icons are square to the edge, because the platform cuts its own corners. Paradise Yacht Management's mark sits beside Celestine's in the footer at the same 46px. The Charter Smarter mark appears once, on the homepage's booking card, where it says where the coral button leads.

Grid and measure

A nine-column page grid: 1040px at most, a 32px gutter, and everything else derived from those two numbers.

Nine is chosen for the editorial 3 + 6 and 4 + 5 splits it allows; it is deliberately not a twelve-column utility grid. The grid governs page-level placement only. Components subdivide freely inside their span, because the page's natural groupings (four stats, two destinations, seven days) do not divide by nine.

One column is 87px. The widths above are worked out from the tokens by tools/build-docs.py.

Margins and rhythm

TokenDesktop768px and belowUse
--section-x56px24pxThe horizontal page margin, everywhere: sections, nav, hero and footer.
--section-y56px64pxDefault vertical section padding.
--section-y-lg96px64pxEmphasis: availability, and the inner pages' main sections.
--section-y-xl128px80pxThe closing booking section.
--gutter32px24pxBetween columns, and between most paired blocks.

Vertical rhythm goes lower on a phone, not higher.

Breakpoints

WidthWhat changes
1152px and upThe nine-column line exists. Derived, not chosen: --grid-max plus twice --section-x. Compositions that need a full-width column line engage here and no earlier, or their bases overflow and wrap.
1151px and belowTwo-column compositions go fluid: 5fr to 6fr with an 8% alley.
920pxNav links give way to the burger and its drawer. The crew cards go to one column.
900px, 800pxCharts hold their width and pan sideways. Passage plans and notes, then pilot entries, drop to one column.
768pxThe phone layout: margins and rhythm step down, grids go to one column, the floating bar becomes a row along the bottom.
600pxThe rate table turns each row into a party-size header over two season cells.
500px, 480px, 430px, 380px, 360pxSmall repairs: the hero headline's glass plate, the calendar to one month across, the footer address, the pictogram legend.
  • The Column Span RuleA new container takes a span token, never a hand-picked pixel width. If a block needs a width the scale does not offer, the scale is wrong: fix the tokens, not the block.
  • The One Margin RuleThe horizontal page margin comes from --section-x and nothing else. A full-bleed escape is written calc(-1 * var(--section-x)), so it tracks the margin.
  • The Shrinkable Track RuleA single-column grid is written minmax(0, 1fr), never a bare 1fr, which cannot shrink below its content. With a pannable chart inside, a bare track once ran a 390px phone page to 734px. When checking a phone layout, confirm that innerWidth equals the width you asked for.

Layouts

The compositions the pages are built from, drawn on the nine columns. Every split sums to nine, so edges land on the same column lines from section to section.

Blue blocks are photographs, navy blocks are charts, gray blocks are type, outlined blocks are Canvas panels. Below 1152px these go fluid, and on a phone each is a single column in source order.

The yacht: header

Six columns of headline and lede against a three-column round portrait.

The yacht: feature field

Two four-column tiles with a derived one-column alley (dashed), opened and closed by full-measure plates.

Crew

Three equal cards on the eight-column measure, centered. A post still to be announced keeps its card, with a “Coming soon” disc for a portrait.

Passage plan

Four columns of chart, sticky below the nav, against five of log.

Chart index

On navy: six columns of chart against a three-column key. A chart too wide to share a row takes all nine, with the key in three columns beneath.

Pilot entries

Four columns of chart inset against five of text, mirrored on every second entry.

Notes

Reading the plan, and Between the anchorages: a heading and lede on four columns against a definition list on five.

Also on the chart

A three-column heading against the two cross links.

Buttons and controls

Square, tracked and quiet. Small, widely tracked uppercase labels with generous padding and a color swap on hover.

Every button is a link: the site has no form. An external one says so in its accessible name (“Book with Charter Smarter (opens in a new tab)”). These are the real .btn classes from pages.css; the homepage draws the same buttons with inline styles.

On Canvas: .btn-primary, .btn-dark, and the focus ring in Steel Blue

On navy: the closing section's actions. .btn-sky, .btn-ghost, and the ring in Sea Glass

The floating action bar, over photography. Dark is 92% so it holds on any frame

ButtonFill and inkType and paddingWhere
PrimaryHarbor Coral, Midnight Hull12px, 4px tracking; 18 by 26px; 132px minimumBooking, once per view.
DarkMidnight Hull at 92%, Sea GlassAs primaryCall and Email in the floating bar and under the calendar.
SkyHarbor Sky, Midnight Hull14px, 2px tracking; 18 by 40pxSecondary actions on navy: Broker partners, Learn about layaway.
Ghost1px Sea Glass at 50%, Sea GlassAs skyNavy fields only: the phone number, hero jump links.

On hover every filled button swaps to a Sea Glass fill with Midnight Hull ink over 0.25s; the ghost firms its outline and takes a 10% fill. In the closing section the three actions share a 236px minimum width, so none reads as the runt.

Icon controls

Round is reserved for controls that are only an icon. Anything on imagery carries the Control shadow.

7 / 17 3

Carousel arrow 52px · lightbox arrow 56px · close 48px · counter chip · chart pin 24px · a 24px mark inside its 44px hit area

The divider knob (40px) and the map opener (34px) share this vocabulary; both are live on the inset under Components.

  • The Hit Area RuleA small target keeps its drawn size and grows an invisible 44px hit area from an ::after with a negative inset: the destination cards' text links, the footer's 24px social marks, the closing section's brochure link. The footer's contact links grow to 28px beside the address, and to 44px on a phone. Chart pins stay at their drawn size, because each has a full-height row in the key that does the same thing, and padded pins on a crowded chart would steal each other's taps.
  • Promise only what worksNo role="button" with a guarded handler, and no “Tap” hint under a mouse. The plate zoom is available at every width, never enlarges past the source's own pixels, and words its hint for the pointer in use.

Components

Sections sit flat. Only what floats over content gets a shadow, and only contained cards get a radius.

DepthShadowOn
Float0 8px 24px rgba(0,0,0,0.15)Polaroid tiles, chart insets, the plan chart's mat.
Lift0 8px 32px rgba(0,0,0,0.2)Wide plates, the tour embeds, the menu drawer.
Control0 4px 18px rgba(0,0,0,0.35)Any control on imagery: close buttons, the divider knob, the map opener.
Stage0 30px 80px rgba(0,0,0,0.5)The photograph in the lightbox.

Corners: none on buttons and section edges; 2px on mats and frames; 14 to 16px on contained panels such as the crew cards; fully round for icon-only controls and portraits.

The polaroid mat, carrying a chart inset

Sea Glass Light wraps the plate on three sides and deepens into a lip that carries the caption. Photographs sit square, never tilted. On the destination pages the same mat carries a chart inset, which can be swapped for a photograph. This one is lifted from usvi.html and is live: drag the divider, or focus it and use the arrow keys.

Satellite view of Trunk and Cinnamon Bays
9
Chart inset18°21.2′N 64°46.2′W

Badge

A short Standout label on a square Midnight Hull plate. One vocabulary for the hero's line, the “Most popular” tag and the photo band's caption. Never coral, never a pill.

Private yacht vacationsMost popular

Navigation

Uppercase Jost at 13px with 2px tracking. The link for where you are carries a 1px hairline 8px below the label, drawn as a pseudo-element so that it stops at the last letter. On the homepage it follows a reading line two fifths of the way down the viewport and draws in over 0.35s; inner pages mark Destinations, their parent.

Planning pictograms

The thirteen pictograms the crew's printed itineraries use, in assets/icons/tags.svg. They fill with currentColor: Chart Label on frost, Shallow Water on navy. In a log they stand alone at 24px, each named by its title and an accessible label; only the legend gives them visible names.

  • Beach chairs
  • Beach time
  • Dive / SCUBA
  • Dock available
  • Hiking
  • Island tour
  • Jumping
  • Lobster specialty
  • Notable bar
  • Paddleboarding
  • Secluded
  • Snorkeling
  • Swimming

Gauges

“How the week leans”: relative emphasis from a charter's planning sheet, on a scale ruled in quarters. These are the seven-night passage's. Each fill runs once, from the left, when the block enters view.

  • Snorkeling
  • Beach time
  • Sailing time

Calendar days

The availability grid's six states. An open day that touches a booking or a hold is a turnaround day: it is computed, never entered, and draws exactly as unavailable. Pointing at an open window above the grid inks its days.

12Open
13On hold
14Booked
15Unavailable, or a turnaround day
16Past
17Inked: its window is pointed at

The months drawn run only as far as the blocks are maintained. A date with no block reads as open, so an unmaintained month would advertise weeks nobody has checked.

Charts

The inner pages draw real nautical charts; they do not decorate with them. One asset carries the geography, and every chart on the site is a viewBox crop of that one drawing.

This is the seven-night plan chart and the first two entries of its log, lifted from itineraries.html. Point at an entry, or tab to a pin, and its leg lights while the others fall to 28%. The satellite view is the same window, in register; the passage stays plotted on both.

64°54′W64°48′W64°42′W64°36′W64°30′W64°24′W64°18′W18°42′N18°36′N18°30′N18°24′N18°18′N
Satellite view of the seven nights passage
12345678
Numbered by legNot for navigation

Drag the chart to pan

  1. Day 1
    Saturday

    Charlotte Amalie to Norman Island

    1 h under sail

    Welcome to the Virgin Islands. After everyone is aboard, we hold a short safety briefing and set sail for Norman Island: snorkeling at the Caves, then an evening at the Willy T, the floating bar in the Bight.

  2. Day 2
    Sunday

    Norman Island to The Baths, Virgin Gorda

    3 h under sail

    We head for the Baths for light swimming and a hike through the granite boulders, then on to Spanish Town for dinner ashore at CocoMaya.

Anatomy

PartHow it is drawn
FieldAlways Celestine Navy.
Shoal halo, landassets/chart/vi-land.svg referenced twice through <use>: once as a wide faint line (Sea Glass at 7%, 11px), once as the land (Sea Glass fill at 16% under a 1px line). Coastline from OpenStreetMap.
FurnitureIn the label voice at chart scale: a graticule every tenth of a degree with edge labels, a four-point compass rose, a nautical-mile scale bar, a serif title block, and the line every chart carries: Not for navigation.
RoutesDashed Sea Glass, one passage to a chart, drawn on once through a mask. A leg is the track a yacht sails: a smooth spline through waypoints in open water, turning a corner only where the yacht stops.
Pins, marksHTML, so they hold their size at any chart scale and take focus: a 24px Shallow Water disc with a Midnight Hull numeral for a stop, a small ring for a place a leg passes through.
Satellite plateEvery chart but the itineraries hero carries one under a draggable divider. Open water in every plate is toned to Celestine Navy, so the sea is continuous across the divider and only land, reef and shallows change.
x = (lon + 65.12) × 1000        y = (18.80 − lat) × 1054.35        1 nautical mile = 17.57 units

The divider

A role="slider" whose value text names the share of satellite. Only the knob and the line take a drag, never the whole plate, because on a phone the chart already pans sideways and the page has to scroll past it.

InputEffect
Arrow keys2%; 10% with Shift
Page Up, Page Down10%
Home, EndSatellite only, chart only
Double-click the knobBack to rest

Where the divider rests and how high the knob rides are chosen by hand per chart to clear its pins and labels, the same license a label's side has.

  • The Chart Truth RuleChart geometry is data, never drawn by eye: coastlines come from the asset, positions from coordinates, the scale bar from the projection. A pin is where the yacht lies (the mooring field, not the beach or the town), and the generator's check_afloat() names any pin or track that touches land. A satellite plate is emitted only at the chart's exact viewBox, so imagery is never shown out of register.

Overlays and dialogs

Four overlays, one behavior. Each is a real dialog, and each gives the keyboard back exactly where it took it.

DialogFieldOpens with focus onAlso
Photo viewer (homepage)Midnight Hull at 94%CloseArrow keys and a horizontal swipe turn the photo; a counter chip; a polite “Photo 7 of 17”.
Plate zoom (homepage)Midnight Hull at 96%CloseClick toggles fit and enlarged; never past the source's own pixels; its hint sits on a Midnight Hull plate so it survives white cabinetry.
Menu drawer (every page)Celestine Navy, from the right, up to 24rem, over a Midnight Hull backdrop at 60%. The same nine links and Book on every pageIts first linkThe burger stays on screen as the close control and is part of the focus trap. A tap on the backdrop closes it too.
Anchorage map (inner pages)Midnight Hull at 96%CloseDormant until a MapKit token is set. Until then the opener is a link to Apple Maps, or to Google Maps off Apple devices.

The contract: role="dialog" and aria-modal; the element that had focus is remembered; the page stops scrolling behind; Tab wraps inside; Escape closes; focus returns to where it came from. A closed overlay is visibility: hidden as well as transparent, because pointer-events: none alone leaves its links in the tab order.

The implementations are openOverlay(), closeOverlay() and onOverlayKeys() on the homepage, and toggleMenu(), onMenuKeys(), openMap() and mapKeys() in pages.js; see the JavaScript reference.

Motion

Slow and calm. Things arrive once, over most of a second, on one soft curve, and then stay put.

--ease-reveal: cubic-bezier(0.22, 0.61, 0.36, 1)
What movesHowUnder reduced motion
Hero photographFades in once it has loaded, 0.6s, the shortest reveal, because its length counts toward load time. None if it is ready for the first frame0.2s fade
Reveal (.reveal)36px rise and fade, 0.8s0.4s fade, no movement
Polaroid plates, slide-insFrom 70px or 90px to the side, 0.9 to 1s0.4s fade
Gallery stageSharpens from gray and blurred, 1.2s; it does not moveNone
A chart's routeDraws itself on through a mask, 2.6s; pins follow 0.14s apartAlready drawn
Satellite plateWipes in from the east, 1.5s, after the route has drawnAlready at rest
GaugesFill from the left, 1.2s, 0.1s apartAlready full
Nav hairlineDraws in from the left, 0.35sAppears at once
Buttons, calendar daysColor swaps, 0.2 to 0.25s. A chosen window's ink fades out over 1.2s after ten secondsUnchanged
Rate table mist, the seaplaneA 34s drift; one 7s flight near the page's footBoth still
Footer weatherChanges harbor every ten seconds behind a 0.5s fade, on the homepage only while the footer is on screenHomepage: holds on Tortola

Every animation has its counterpart in the prefers-reduced-motion block at the foot of each stylesheet, and a new one needs a line there. Adding ?static to an inner page's URL resolves every entrance at once, for screenshots and print.

CSS tokens

Every custom property on :root, with its value read from the source.

The set is written twice, in assets/home.css and assets/pages.css. The two must agree, and tools/build-docs.py reports any that do not. Descriptions come from the @token tags in pages.css.

TokenValueAt 768px and belowWhat it is for
Color
--navy-core#061e45Celestine Navy. The pinned anchor: every navy field, the chart field, photo wells, the theme color.
--navy-shade#041530Night Watch. The darker navy step: the field behind the homepage's destination card photos.
--navy-deep#020c1dMidnight Hull. Text on frost, dark buttons, badges, overlays and the footer.
--navy-core-rgb6 30 69Celestine Navy as channels, for navy washes and legibility halos.
--navy-deep-rgb2 12 29Midnight Hull as channels, for overlays (0.72 to 0.96) and muted calendar days (0.62).
--steel-ink#36454fChart Ink. The pinned charcoal: body and secondary text on frost, fine linework.
--steel-shade#4a5f6dHarbor Steel. Supporting text and the base link color. A Canvas-surface color: never on a photograph or on navy.
--steel-blue#5b7d90Steel Blue. The focus ring, chosen to clear 3:1 against navy, Canvas and Sea Glass at once; small accents.
--slate-muted#566771Slate Muted. Muted small print. A Canvas-surface color.
--sky-tint#9dc4d2Shallow Water. Highlights on navy: chart pins, key numerals, the weather reading; open days in the calendar.
--harbor-sky#7fa8b8Harbor Sky. Secondary action fill (with Midnight Hull text), gauge fills, the on-hold stripe, text selection.
--harbor-sky-rgb127 168 184Harbor Sky as channels.
--pale-sky#d6ecf1Pale Sky. Quiet panels, and the base of the calendar's on-hold stripe.
--seaglass#c3e3ebSea Glass. The pinned pale: the text color on every navy field, small chrome on navy, the hover fill of dark buttons.
--seaglass-rgb195 227 235Sea Glass as channels: borders, ghost outlines and secondary text on navy (0.12 to 0.95).
--canvas#eaf3f6Canvas. The one light section surface. A background only, never a text color.
--canvas-rgb234 243 246Canvas as channels: the wash over the homepage's photographic light sections. Homepage only. home.css only
--seaglass-light#f4fafcSea Glass Light. The polaroid mat around plates and chart insets, and caption panels.
--seaglass-deep#cfdfe5Sea Glass Deep. What shows behind a photograph while it loads.
--seaglass-deep-rgb207 223 229Sea Glass Deep as channels.
--seaglass-mistrgb(180 214 224 / 0.55)Sea Glass Mist. The slow-drifting haze inside the rate table. Homepage only. home.css only
--seaglass-mist-clearrgb(180 214 224 / 0)The same color at zero alpha, so the haze's gradients fade without graying. Homepage only. home.css only
--chart-rule#a9cbd6Chart Rule. Hairlines between log entries, facts and notes. Quiet on purpose: it marks an edge, not a boundary anyone reads.
--chart-label#3d6b7dChart Label. Tracked uppercase annotations on Canvas: places, days, captions. A Canvas-surface color.
--harbor-coral#ff5a5fHarbor Coral. The one warm color. The primary booking action and nothing else, always with Midnight Hull text.
--nav-glassrgb(205 224 231 / 0.82)Nav Glass. Once the translucent nav bar over the homepage hero; unused now that the bar has no background.
--nav-glass-rgb205 224 231Nav Glass as channels. The plate behind the homepage's hero headline on a phone.
Blueprint gains
--blueprint-gain-1#4096aeMultiply gain that rescales the blueprint1 plate so its field lands on Celestine Navy. Asset-bound: re-measure if the plate is redrawn.
--blueprint-gain-2#3d90acThe same for the blueprint2 plate, behind the closing section.
Type
--font-display'Cormorant Garamond', 'Cormorant Fallback', Georgia, serifCormorant Garamond, then its metric-matched fallback. The voice: headings, ledes, names.
--font-body'Jost', 'Jost Fallback', system-ui, sans-serifJost, then its metric-matched fallback. Everything you read or count: paragraphs, figures, links in prose.
--font-label'Jost', 'Jost Fallback', system-ui, sans-serifJost again, under its own name. The tracked uppercase label voice: navigation, buttons, captions, chart furniture.
--type-displayclamp(48px, 8vw, 92px)Display: the homepage hero headline only.
--type-headlineclamp(38px, 9vw, 58px)Headline: section titles.
--type-subheadclamp(30px, 7vw, 44px)Subhead: a second heading inside a section.
--type-title-lg34pxTitle L: closing index headings and the homepage's wide plate names.
--type-title28pxTitle: every card and entry heading.
--type-title-sm24pxTitle S: small titles, and every tile title on a phone.
--type-lead22pxLead: the one serif paragraph that introduces a section.
--type-serif20pxSerif text: serif running text inside a component.
--type-body17pxBody: Jost 300 paragraphs.
--type-body-navy18pxBody on navy: one step up, because light text on a dark field reads smaller. The closing paragraph; the homepage's destination blurbs.
--type-small14pxSmall: secondary facts and credits.
--type-label12pxLabel: the floor for tracked uppercase annotations.
--leading-serif1.5Line height for serif running text.
--leading-body1.65Line height for body copy.
--leading-title1.15Line height for titles.
--head-lead1.25emSpace over a heading that follows content in the same flow (The Heading Leads Rule).
--head-trail0.4emSpace under a heading, binding it to what it introduces.
Motion
--ease-revealcubic-bezier(0.22, 0.61, 0.36, 1)The one easing curve for entrances: soft, decelerating.
Grid and measure
--grid-cols9Columns in the page grid. Informational; the spans below are what rules use. Homepage only. home.css only
--grid-max1040pxFull width of the nine-column page grid.
--gutter32px24pxGutter between columns.
--colcalc((var(--grid-max) - 8 * var(--gutter)) / 9)One column, derived from the two above.
--span-3calc(3 * var(--col) + 2 * var(--gutter))Three columns and their two gutters. Spans 4 to 8 follow the same pattern.
--span-4calc(4 * var(--col) + 3 * var(--gutter))Four columns.
--span-5calc(5 * var(--col) + 4 * var(--gutter))Five columns: the measure for a lede.
--span-6calc(6 * var(--col) + 5 * var(--gutter))Six columns.
--span-7calc(7 * var(--col) + 6 * var(--gutter))Seven columns.
--span-8calc(8 * var(--col) + 7 * var(--gutter))Eight columns.
--measure-readvar(--span-6)Reading container (span 6).
--measure-midvar(--span-7)Mid container (span 7).
--measure-widevar(--span-8)Wide container (span 8).
--measure-fullvar(--grid-max)The whole grid (span 9).
Spacing
--section-x56px24pxHorizontal page margin. The only source of it: anything that breaks the margin computes from this.
--section-y56px64pxDefault vertical section padding.
--section-y-lg96px64pxEmphasis step: the homepage's availability section, and the main sections of these pages.
--section-y-xl128px80pxEmphasis step for the closing booking section.
--nav-h89px70pxHeight of the fixed nav bar: hero top padding, sticky offsets and scroll margins clear it. These pages only. pages.css only

Component properties

A few custom properties are scoped to a component. They carry a measurement from the generator or from script, never a design decision.

PropertySet byMeaning
--splitpages.jsThe chart / satellite divider's position, in percent from the left.
--knob-y, --split-delaythe generator, inlineHow high the knob rides, and how long the satellite's entrance waits for the route.
--chart-minthe generator, inlineThe width a chart keeps on a phone, where it pans.
--ithe generator, inlineA pin's place in the entrance order.
--v, --nmthe generator, inlineA gauge's reading; one nautical mile as a share of an inset's width.
--mat, --plate-arthe stylesheets; inline per tileThe polaroid mat's width, and a plate's proportion.
--cta-vvboth scriptsHow far a phone's toolbar or keyboard has pushed the visible bottom edge up.
--link-hover, --hero-copy-rightindex.htmlThe link hover ink for a surface; where the hero headline's first line ends, for the haze.

Code reference

The source comments are the documentation. The reference pages are generated from them.

PageGenerated from
JavaScript referenceThe JSDoc in assets/home.js and assets/pages.js: every function, its parameters, the events it listens for, and the shapes of the data it handles.
CSS referenceThe doc comments in assets/home.css and assets/pages.css: every section, selector, modifier, state, script hook, custom property and breakpoint.
ARCHITECTURE.mdWritten by hand: how the site is put together, where its data comes from, and what to touch when something has to change.
DESIGN.mdWritten by hand: the reasoning behind every rule on this page.

After changing a doc comment, a token or this page, run the builder and commit what it writes:

python3 tools/build-docs.py            # writes docs/ and updates this page
python3 tools/build-docs.py --check    # writes nothing; exits 1 if anything is out of date

An internal page, marked noindex and linked only from About this site, which credits the work this guide describes. Values here are written by tools/build-docs.py.