/* yolfez.com, the coast.
   A night coast you sail along, one landmark for each project. The night
   itself is one canvas (js/sea.js); what is laid over it here is the brush y,
   each landmark's name in its own lettering, the chart along the foot of the
   screen, and the word in the corner. */

@font-face {
  font-family: Newsreader;
  src: url(/fonts/newsreader.woff2) format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: Newsreader;
  src: url(/fonts/newsreader-italic.woff2) format('woff2');
  font-weight: 400; font-style: italic; font-display: swap;
}

:root {
  color-scheme: dark;
  --night: #03050a;
  --cream: oklch(93% 0.028 84);
  --dim: color-mix(in oklch, var(--cream) 72%, transparent);
  --flame: oklch(86% 0.125 78);
  --brass-lo: oklch(48% 0.07 72);
  --brass-hi: oklch(86% 0.1 86);
  --iron: oklch(34% 0.012 60);
  --serif: Newsreader, Georgia, 'Times New Roman', serif;
  --gut: clamp(1.1rem, 4vw, 3.25rem);
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; background: var(--night); }
body {
  margin: 0;
  font-family: var(--serif);
  color: var(--cream);
  background: var(--night);
}
[hidden] { display: none !important; }
:focus-visible {
  outline: 2px solid color-mix(in oklch, var(--flame) 80%, var(--cream));
  outline-offset: 4px;
}

/* the coast holds still in the window; the page scrolls under it, and the
   scroll is the sailing */
.coast {
  position: fixed;
  inset: 0;
  z-index: 1;
  overflow: clip;
  background:
    linear-gradient(180deg, #03060f 0%, #0c1222 42%, #0a111f 45%, #04070d 100%);
}
.sea {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  opacity: 0;
  transition: opacity 900ms ease;
}
.coast.is-ready .sea, .coast .sea.on { opacity: 1; }
.coast.is-pointing { cursor: pointer; }

/* the length of the voyage: as tall as the coast is long, set by coast.js */
.voyage { position: relative; z-index: 0; height: 100vh; }

/* ---- the brush y ---------------------------------------------------------- */

.mast {
  position: fixed;
  z-index: 9;
  left: 0;
  top: 0;
  padding: clamp(1.4rem, 5vh, 3rem) var(--gut);
  pointer-events: none;
}
.wordline { margin: 0; font-size: clamp(2.4rem, 5.5vw, 5rem); font-weight: 400; line-height: 0.9; }
.mark { position: relative; display: inline-block; line-height: 0; }
.mark img { width: auto; height: 0.92em; display: block; visibility: hidden; }
.mark::after {
  content: '';
  position: absolute;
  inset: 0;
  background: currentColor;
  -webkit-mask: url(/mark.svg) 50% 50% / contain no-repeat;
  mask: url(/mark.svg) 50% 50% / contain no-repeat;
  filter: drop-shadow(0 1px 6px oklch(3% 0 0 / 0.8));
}
.mark i { display: none; font-style: italic; line-height: 1; }
.mark.no-svg img { display: none; }
.mark.no-svg::after { content: none; }
.mark.no-svg i { display: inline-block; }
.sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ---- the opening -------------------------------------------------------------

   html.ident is set by the head script on a first view and taken off by
   coast.js when the opening is over or will not play. While it is on, the
   night is all there is: the canvas, the brush y, the names, the chart and
   the bell wait, and come in on the frames the water gives them (js/
   opening.js animates each on its cue). The word in the corner never waits:
   it is the control of a reader who asked for less motion. The names, the
   chart, the bell and the privacy word wait at a five-hundredth, which no
   eye sees, so they
   are drawn while the pictures load and not on the frame they come in on
   (that first drawing held the water still for a fifth of a second). If
   coast.js never runs, the night lifts and the y, the chart and the bell
   come up by themselves after 3.6 seconds, which is when coast.js would have
   let them go itself. */

.mark, .chart, .tokens, .privacy { transition: opacity 420ms cubic-bezier(0.3, 0.6, 0.4, 1); }
html.ident .coast::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  background: var(--night);
  animation: ident-late 420ms ease 3.6s reverse both;
}
html.ident .coast .sea,
html.ident .mast .mark { opacity: 0; transition: none; }
html.ident .coast.is-ready .door,
html.ident .chart,
html.ident .tokens,
html.ident .privacy { opacity: 0.002; transition: none; }
html.ident .mast .mark,
html.ident .chart,
html.ident .tokens,
html.ident .privacy { animation: ident-late 420ms cubic-bezier(0.3, 0.6, 0.4, 1) 3.6s both; }
html.ident-live .coast::before,
html.ident-live .mast .mark,
html.ident-live .chart,
html.ident-live .tokens,
html.ident-live .privacy { animation: none; }
@keyframes ident-late { from { opacity: 0; } to { opacity: 1; } }

/* the brush y, once the opening is over: press it and the water does it
   again (laid exactly over the y in the corner by coast.js; it comes after
   the names in the page, so it is never the first thing Tab reaches) */
.mark-ring {
  position: fixed;
  z-index: 9;
  left: var(--mx, var(--gut));
  top: var(--my, 1.4rem);
  width: var(--ms, 4rem);
  height: var(--ms, 4rem);
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  cursor: pointer;
  pointer-events: auto;
}

/* ---- the names -----------------------------------------------------------

   Each landmark's article is laid over the night just above its landmark,
   moved there on every frame by coast.js (--px, --py), scaled with its
   distance (--ps), and stacked with it (--pz). The name is set in the
   project's own lettering, read off the room's data by the build step; it is
   always there, quiet, and comes up with its line when the landmark is pointed
   at or is the one in the middle of the screen. */

.places { position: absolute; inset: 0; pointer-events: none; z-index: 4; }
.door {
  position: absolute;
  left: 0;
  top: 0;
  z-index: var(--pz, 1);
  width: max-content;
  max-width: 34rem;
  transform: translate(var(--px, -999px), var(--py, -999px)) translate(-50%, -100%) scale(var(--ps, 1));
  transform-origin: 50% 100%;
  text-align: center;
  pointer-events: none;
  opacity: 0;
  transition: opacity 600ms ease;
}
.coast.is-ready .door { opacity: 1; }
/* a landmark off the window keeps its name in the Tab order and in what a
   screen reader hears, unseen; reached by the keyboard, it sails there */
.coast .door.is-off { opacity: 0; }
.coast .door.is-off .name { pointer-events: none; }
.coast .door.is-off:focus-within { opacity: 1; }
/* a name the edge of the window would cut waits out of sight */
.coast .door.is-edge { opacity: 0; }
.plate {
  display: grid;
  justify-items: center;
  gap: 0.35rem;
  padding: 0 0 1.1rem;
}
.name {
  pointer-events: auto;
  font-family: var(--face, var(--serif)), var(--serif);
  font-weight: var(--weight, 400);
  font-variant: var(--variant, normal);
  text-transform: var(--case, none);
  letter-spacing: var(--track, 0.02em);
  font-size: clamp(1.15rem, 1.6vw + 0.6rem, 2.1rem);
  line-height: 1.05;
  color: color-mix(in oklch, var(--cream) 86%, transparent);
  text-decoration: none;
  text-shadow: 0 0 18px oklch(80% 0.12 75 / 0.35), 0 1px 3px oklch(3% 0 0 / 0.95);
  transition: color 400ms ease, text-shadow 400ms ease;
  padding: 0.2em 0.4em;
}
a.name::after {
  content: '';
  display: block;
  height: 1px;
  margin: 0.28em auto 0;
  width: 1.6em;
  background: color-mix(in oklch, var(--flame) 55%, transparent);
  transition: width 400ms ease;
}
.door.is-lit .name, .door.is-near .name, .name:focus-visible {
  color: var(--cream);
  text-shadow: 0 0 24px oklch(85% 0.13 78 / 0.6), 0 1px 3px oklch(3% 0 0 / 0.95);
}
.door.is-lit a.name::after, .door.is-near a.name::after { width: 3.2em; }
.line {
  font-style: italic;
  font-size: clamp(0.88rem, 0.6vw + 0.62rem, 1.08rem);
  line-height: 1.35;
  color: var(--dim);
  text-shadow: 0 1px 3px oklch(3% 0 0 / 0.95), 0 0 12px oklch(3% 0 0 / 0.8);
  max-width: 22rem;
  text-wrap: balance;
  opacity: 0;
  transform: translateY(0.3rem);
  transition: opacity 450ms ease, transform 450ms ease;
}
.door.is-lit .line, .door.is-near .line { opacity: 1; transform: none; }
.nb { white-space: nowrap; }

/* ---- the chart -------------------------------------------------------------

   A sea chart along the foot of the screen: an engraved brass waterline with
   the sea drawn small under it, every landing standing on it as its own
   landmark in brass (cut from the landmark's own picture by coast.js, a dot
   until it comes) with its reflection under the line, and the boat, lantern
   lit and its wake behind it while it goes. It grows a landmark with every
   project; the more there are, the smaller each stands. */

.chart {
  --line: 1.15rem;
  --mark: clamp(1rem, calc(19rem / max(1, var(--n, 3) - 1)), 2.1rem);
  /* the marks' brass, which coast.js works into each mark's picture (BRASS_TOP, BRASS_FOOT) */
  --brass: linear-gradient(0deg, var(--brass-lo), color-mix(in oklch, var(--brass-hi) 78%, var(--brass-lo)));
  position: fixed;
  z-index: 8;
  left: 50%;
  bottom: calc(0.75rem + env(safe-area-inset-bottom));
  width: min(34rem, 76vw);
  height: calc(var(--line) + var(--mark) + 0.6rem);
  transform: translateX(-50%);
}
/* the waterline, brightest in the middle, and a fainter rule under it */
.chart::before,
.chart::after {
  content: '';
  position: absolute;
  height: 1px;
  pointer-events: none;
}
.chart::before {
  left: 0;
  right: 0;
  bottom: var(--line);
  background: linear-gradient(90deg, transparent,
    color-mix(in oklch, var(--brass-lo) 85%, transparent) 9%,
    color-mix(in oklch, var(--brass-hi) 80%, transparent) 50%,
    color-mix(in oklch, var(--brass-lo) 85%, transparent) 91%, transparent);
}
.chart::after {
  left: 7%;
  right: 7%;
  bottom: calc(var(--line) - 4px);
  background: linear-gradient(90deg, transparent, color-mix(in oklch, var(--brass-lo) 45%, transparent) 15%,
    color-mix(in oklch, var(--brass-lo) 45%, transparent) 85%, transparent);
}
/* the sea under it, in the small strokes old charts drew it with */
.chart ol {
  list-style: none;
  margin: 0;
  padding: 0;
}
.chart ol::before {
  content: '';
  position: absolute;
  left: 10%;
  right: 10%;
  bottom: calc(var(--line) - 0.95rem);
  height: 0.6rem;
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='30' height='10' viewBox='0 0 30 10'%3E%3Cpath d='M1 3.5q3.5-2.4 7 0t7 0M16 8q3.5-2.4 7 0t7 0' fill='none' stroke='%23d9c9a3' stroke-width='0.75' stroke-linecap='round'/%3E%3C/svg%3E") 0 0 / 1.9rem 0.6rem repeat-x;
  opacity: 0.22;
  -webkit-mask: linear-gradient(90deg, transparent, #000 25%, #000 75%, transparent);
  mask: linear-gradient(90deg, transparent, #000 25%, #000 75%, transparent);
  pointer-events: none;
}

.mark-place {
  position: absolute;
  bottom: var(--line);
  left: calc(4% + var(--at) * 92%);
  width: calc(var(--mark) * 1.55);
  height: var(--mark);
  margin-left: calc(var(--mark) * -0.775);
  padding: 0;
  border: 0;
  border-radius: 0.3rem 0.3rem 0 0;
  background: none;
  font-family: inherit;
  cursor: pointer;
  transition: filter 400ms ease;
}
.mark-art,
.mark-echo {
  position: absolute;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
/* the landmark's own painting, tinted brass: its light and dark kept, its
   colour the chart's. coast.js tints the small copy itself (--tint), since
   WebKit draws no masked layer that blends and filters its picture. */
.mark-art {
  bottom: 0;
  background: var(--tint) center bottom / contain no-repeat;
  opacity: 0.55;
  transition: opacity 400ms ease;
}
/* its reflection: the same shape upside down under the line, fading */
.mark-echo {
  -webkit-mask: var(--art) center bottom / contain no-repeat;
  mask: var(--art) center bottom / contain no-repeat;
  top: calc(100% + 2px);
  transform: scaleY(-1);
  background: linear-gradient(0deg, color-mix(in oklch, var(--brass-hi) 60%, transparent), transparent 55%);
  opacity: 0.22;
}
.mark-place:not(.has-shape) .mark-art,
.mark-place:not(.has-shape) .mark-echo { display: none; }
/* until its landmark comes, a landing is a lamp on the line */
.mark-place:not(.has-shape)::before {
  content: '';
  position: absolute;
  left: 50%;
  bottom: -3px;
  width: 6px;
  height: 6px;
  margin-left: -3px;
  border-radius: 50%;
  background: var(--flame);
  box-shadow: 0 0 10px oklch(85% 0.13 78 / 0.7);
  opacity: 0.75;
}
.mark-place:focus-visible .mark-art,
.mark-place.is-near .mark-art { opacity: 1; }
.mark-place:focus-visible,
.mark-place.is-near { filter: drop-shadow(0 0 7px oklch(80% 0.12 76 / 0.5)); }
/* a skipped opening: the glow comes in after its 200 ms, not over the
   heal's last frames (js/opening.js skip) */
html.ident-skip .mark-place { filter: none; }
.mark-place span {
  position: absolute;
  bottom: calc(100% + 0.45rem);
  left: 50%;
  transform: translate(-50%, 0.2rem);
  white-space: nowrap;
  font-size: 0.8rem;
  font-style: italic;
  color: var(--cream);
  text-shadow: 0 1px 3px oklch(3% 0 0 / 0.95);
  opacity: 0;
  pointer-events: none;
  transition: opacity 250ms ease, transform 250ms ease;
}
.mark-place:focus-visible span { opacity: 1; transform: translate(-50%, 0); }
/* only a hand on a mouse points: a tapped mark would stay lit on a phone */
@media (hover: hover) and (pointer: fine) {
  .mark-place:hover .mark-art { opacity: 1; }
  .mark-place:hover { filter: drop-shadow(0 0 7px oklch(80% 0.12 76 / 0.5)); }
  .mark-place:hover span { opacity: 1; transform: translate(-50%, 0); }
}

/* the boat: --face is the side its lantern hangs on (1 the right), and the
   side that goes first is --face times --lead (coast.js); its picture has the
   lantern on the left */
.chart-boat {
  --face: 1;
  position: absolute;
  bottom: calc(var(--line) - 0.12rem);
  left: calc(4% + var(--at, 0) * 92%);
  width: 1.55rem;
  height: 0.9rem;
  margin-left: -0.775rem;
  pointer-events: none;
}
.chart-boat .hull,
.chart-boat .echo {
  position: absolute;
  left: 0;
  width: 100%;
  height: 100%;
  -webkit-mask: var(--boat) center bottom / contain no-repeat;
  mask: var(--boat) center bottom / contain no-repeat;
}
.chart-boat .hull {
  bottom: 0;
  background: linear-gradient(0deg, color-mix(in oklch, var(--cream) 50%, var(--brass-lo)), var(--cream));
  transform: scaleX(calc(var(--face) * -1));
}
.chart-boat .echo {
  top: 100%;
  transform: scale(calc(var(--face) * -1), -1);
  background: linear-gradient(0deg, color-mix(in oklch, var(--cream) 45%, transparent), transparent 60%);
  opacity: 0.25;
}
.chart-boat:not(.has-shape) .hull,
.chart-boat:not(.has-shape) .echo { display: none; }
.chart-boat:not(.has-shape)::before {
  content: '';
  position: absolute;
  left: 0.3rem;
  right: 0.3rem;
  bottom: 0.1rem;
  height: 0.38rem;
  border-radius: 0 0 0.5rem 0.5rem;
  background: color-mix(in oklch, var(--cream) 75%, transparent);
}
/* the lantern at its stern */
.chart-boat .glow {
  position: absolute;
  top: 0.06rem;
  left: calc(50% + var(--face) * 0.69rem - 2px);
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--flame);
  box-shadow: 0 0 5px 2px oklch(85% 0.14 76 / 0.7);
}
/* its wake, drawn out behind it while it goes */
.chart-boat .wake {
  position: absolute;
  right: 50%;
  bottom: 0.12rem;
  width: 2.8rem;
  height: 1px;
  transform-origin: right center;
  transform: scaleX(calc(var(--face) * var(--lead, 1)));
  background: linear-gradient(90deg, transparent, color-mix(in oklch, var(--cream) 55%, transparent));
  opacity: var(--wake, 0);
  transition: opacity 500ms ease;
}

/* ---- the word in the corner -------------------------------------------- */

.corner {
  appearance: none;
  border: 0;
  padding: 0;
  background: none;
  font-family: inherit;
  cursor: pointer;
  position: fixed;
  z-index: 10;
  top: calc(1.35rem + env(safe-area-inset-top));
  right: calc(var(--gut) + 3rem + env(safe-area-inset-right));
  font-size: 0.85rem;
  font-style: italic;
  color: var(--dim);
  text-decoration: underline;
  text-decoration-color: color-mix(in oklch, var(--flame) 45%, transparent);
  text-underline-offset: 3px;
}
.corner:hover { color: var(--cream); }

/* ---- the privacy word ------------------------------------------------------

   One small word at the foot of the coast, left of the chart, as quiet as the
   bell's tag and always there once the coast is up. Its tap area is a
   thumb's (44 px); the words sit on a soft dark halo, so a bright reflection
   passing under them never takes them below the contrast they need. Where
   the chart takes the whole foot of a narrow screen, it stands just above
   the chart's left end instead. */

.privacy {
  position: fixed;
  z-index: 10;
  left: calc(var(--gut) - 6px + env(safe-area-inset-left));
  bottom: calc(0.75rem + env(safe-area-inset-bottom));
  display: block;
  min-width: 44px;
  height: 44px;
  line-height: 44px;
  text-align: center;
  padding: 0 6px;
  font-size: 0.8rem;
  font-style: italic;
  color: var(--dim);
  text-decoration: underline;
  text-decoration-color: color-mix(in oklch, var(--flame) 35%, transparent);
  text-underline-offset: 3px;
  text-shadow: 0 1px 3px oklch(0% 0 0 / 0.8), 0 0 10px var(--night), 0 0 4px var(--night);
}
/* the halo: a soft dark pad under the words, unseen on the night water and
   there when a lamp's glints or a landmark pass beneath them. It runs a few
   px past each end of the word, so its tapered tips never sit under a
   letter when a glint column passes right beside it. */
.privacy::before {
  content: '';
  position: absolute;
  z-index: -1;
  left: 2px;
  right: 2px;
  top: 50%;
  height: 1.1em;
  transform: translateY(-50%);
  border-radius: 50%;
  background: color-mix(in oklch, var(--night) 78%, transparent);
  box-shadow: 0 0 10px 7px color-mix(in oklch, var(--night) 78%, transparent);
  pointer-events: none;
}
/* on pale fog a dark pad would show as a smudge: a lighter, wider one there */
.coast[data-weather="fog"] .privacy::before {
  background: color-mix(in oklch, var(--night) 40%, transparent);
  box-shadow: 0 0 16px 10px color-mix(in oklch, var(--night) 40%, transparent);
}
.privacy:hover, .privacy:focus-visible { color: var(--cream); }
.privacy:focus-visible { outline-offset: 0; }
@media (max-width: 540px) {
  .privacy { bottom: calc(4.6rem + env(safe-area-inset-bottom)); }
}
/* with no script the directory is the page, and it says Privacy itself */
@media (scripting: none) {
  .privacy { display: none; }
}

/* ---- the bell ----------------------------------------------------------------

   The same brass bell every room hangs: dull, its clapper tied up, while the
   coast is quiet, and lit while its music plays. The first touch anywhere
   starts the music; the bell stops it, and the stop is remembered. */

.tokens {
  position: fixed;
  z-index: 10;
  top: calc(0.45rem + env(safe-area-inset-top));
  right: calc(var(--gut) - 0.5rem + env(safe-area-inset-right));
}
.token {
  position: relative;
  appearance: none;
  border: 0;
  padding: 0;
  margin: 0;
  background: none;
  color: inherit;
  font: inherit;
  width: 44px;
  height: 52px;
  display: grid;
  place-items: center;
  cursor: pointer;
}
.token svg { display: block; width: 34px; height: 44px; overflow: visible; }
.token__tag {
  position: absolute;
  top: 100%;
  right: 0;
  padding-top: 2px;
  white-space: nowrap;
  font-size: 0.8rem;
  font-style: italic;
  color: var(--dim);
  text-shadow: 0 1px 3px oklch(0% 0 0 / 0.8);
  opacity: 0;
  pointer-events: none;
  transition: opacity 200ms ease;
}
.token:hover .token__tag,
.token:focus-visible .token__tag { opacity: 1; }
.bell__bracket { fill: none; stroke: var(--iron); stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.bell__rivet { fill: var(--iron); }
.bell__body {
  transform-box: view-box;
  transform-origin: 20px 10px;
  transition: opacity 300ms ease;
}
.bell__ring { fill: none; stroke: var(--brass-lo); stroke-width: 1.3; }
.bell__shell { fill: url(#brass); stroke: color-mix(in oklch, var(--brass-lo) 60%, black); stroke-width: 0.6; }
.bell__lip { fill: none; stroke: color-mix(in oklch, var(--brass-lo) 80%, black); stroke-width: 0.9; }
.bell__mouth { fill: oklch(14% 0.02 60); }
.bell__shine { fill: none; stroke: oklch(96% 0.04 90 / 0.55); stroke-width: 1.1; stroke-linecap: round; }
.bell__clapper { fill: var(--brass-lo); transition: opacity 300ms ease; }
.bell[data-state='off'] .bell__body { opacity: 0.66; }
.bell[data-state='off'] .bell__clapper { opacity: 0; }
.bell[data-state='on'] svg { filter: drop-shadow(0 0 6px color-mix(in oklch, var(--flame) 45%, transparent)); }
@keyframes swing {
  0%   { transform: rotate(0deg); }
  14%  { transform: rotate(calc(var(--amp, 1) * 16deg)); }
  34%  { transform: rotate(calc(var(--amp, 1) * -11deg)); }
  54%  { transform: rotate(calc(var(--amp, 1) * 6deg)); }
  74%  { transform: rotate(calc(var(--amp, 1) * -3deg)); }
  100% { transform: rotate(0deg); }
}
.bell.is-swinging .bell__body { animation: swing 1.6s cubic-bezier(0.3, 0.6, 0.4, 1); }

/* ---- the way in ------------------------------------------------------------------

   The film a click on a landmark plays, made by coast.js: laid over the coast
   where its first frame stands, edges soft so the water it starts on runs on
   past them, then grown past the edges of the window. The fade to the room's
   colour (.walkin) closes over it. */

.arrival {
  position: fixed;
  inset: 0;
  z-index: 55;
  overflow: hidden;
  pointer-events: none;
  opacity: 0;
  transition: opacity 320ms ease;
}
.arrival.is-on { opacity: 1; pointer-events: auto; cursor: pointer; }
/* where the film does not reach yet (a phone, a very wide window), the
   night closes in around it as it starts, so its soft edges go into dark */
.arrival::before {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--night);
  opacity: 0;
  transition: opacity 900ms ease 150ms;
}
.arrival.is-on::before { opacity: 0.92; }
.arrival video {
  position: absolute;
  left: 0;
  top: 0;
  max-width: none;
  transform-origin: 0 0;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 4%, #000 96%, transparent), linear-gradient(180deg, transparent, #000 4.5%, #000 95.5%, transparent);
  -webkit-mask-composite: source-in;
  mask-image: linear-gradient(90deg, transparent, #000 4%, #000 96%, transparent), linear-gradient(180deg, transparent, #000 4.5%, #000 95.5%, transparent);
  mask-composite: intersect;
}
body.arriving .door, body.arriving .chart, body.arriving .mast, body.arriving .tokens, body.arriving .corner, body.arriving .privacy {
  opacity: 0;
  pointer-events: none;
  transition: opacity 300ms ease;
}

/* ---- the directory, said plainly and never painted ---------------------- */

.directory {
  position: fixed;
  bottom: 0;
  left: 0;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}
/* with no script the coast cannot be drawn, so the directory is the page */
@media (scripting: none) {
  .directory {
    z-index: 20;
    right: 0;
    width: auto;
    height: auto;
    overflow: visible;
    clip-path: none;
    padding: 0 var(--gut) clamp(1.4rem, 6vh, 3rem);
  }
  .directory a { color: var(--cream); }
  /* each name keeps its short rule under it, not adrift mid-row */
  .directory a.name { display: inline-block; }
}

/* The water's context lost (a GPU reset, a phone taking its memory back):
   coast.js marks the coast no-sea, and until it is given back the canvas is
   put away so the night shows instead of the browser's blank sheet, and the
   directory is said plainly, as with no script, so every room is still a
   word away. It stands clear of the chart, and it says Privacy itself. */
.coast.no-sea .sea { visibility: hidden; }
.coast.no-sea .privacy { display: none; }
.coast.no-sea ~ .directory {
  z-index: 20;
  right: 0;
  width: auto;
  height: auto;
  overflow: visible;
  clip-path: none;
  padding: 0 var(--gut) calc(5.8rem + env(safe-area-inset-bottom));
}
.coast.no-sea ~ .directory a { color: var(--cream); }
.coast.no-sea ~ .directory a.name { display: inline-block; }

/* ---- going in ------------------------------------------------------------------ */

.walkin {
  position: fixed;
  inset: 0;
  z-index: 60;
  pointer-events: none;
  background: var(--ground, #05070d);
  opacity: 0;
  transition: opacity 460ms ease;
}
body.leaving .walkin { opacity: 1; }
body.leaving .door, body.leaving .chart, body.leaving .mast { opacity: 0; transition: opacity 300ms ease; }

/* ---- a phone ------------------------------------------------------------------ */

@media (max-width: 700px) {
  .mast { padding: calc(env(safe-area-inset-top) + 1rem) var(--gut) 0; }
  .wordline { font-size: clamp(2.2rem, 11vw, 3rem); }
  .name { font-size: clamp(1.1rem, 5.4vw, 1.6rem); }
  .line { max-width: 16rem; }
  .chart { width: min(22rem, 80vw); }
}

/* ---- reduced motion ------------------------------------------------------------ */

@media (prefers-reduced-motion: reduce) {
  .door, .line, .name, a.name::after, .sea, .walkin { transition: none; }
  .bell { --amp: 0.45; }
}
/* a reader who has stilled the water gets the same, whatever the system says
   (coast.js marks the root while the water is held) */
html[data-held] .door, html[data-held] .line, html[data-held] .name, html[data-held] a.name::after,
html[data-held] .sea, html[data-held] .walkin { transition: none; }
html[data-held] .bell { --amp: 0.45; }
