/* Nagomi Vie demo site. Plain CSS, no build step. DESIGN.md describes the system.
   Colours come from the hero photograph: sea haze, tide water, wet sandstone.
   js/main.js puts one of three level classes on <html>: motion (everything), motion-calm
   (opacity fades only) or motion-off (nothing moves). All animation sits behind one of the
   first two. Without any of them (no JavaScript) every element is fully visible and still.
   html.js is added by the same script, so the no-JavaScript menu fallback can be styled. */

:root {
  color-scheme: light;

  --fog: #EEF0EE;
  --stone: #E3E8E4;
  --tide: #14282B;
  --kelp: #33575A;
  --mist: #CBD3D0;
  --mist-on-tide: #A9BDBB;
  --sandstone: #B08968;
  --sandstone-line: #A88160;
  --warn-on-tide: #E8C4A0;

  --display: "Shippori Mincho", "Times New Roman", serif;
  --text: "Zen Kaku Gothic New", "Helvetica Neue", Arial, sans-serif;

  --ease-out: cubic-bezier(0.22, 0.8, 0.18, 1);
  --ease-soft: cubic-bezier(0.32, 0.72, 0, 1);

  --gutter: clamp(1.25rem, 5vw, 4rem);
  --col-gap: clamp(1rem, 2vw, 2rem);
  --space-wide: clamp(6rem, 13vw, 11rem);
  --space-base: clamp(4.5rem, 9vw, 8rem);
  --max: 1280px;

  /* Height of the header at the top of the page. Pages without a photo hero clear it. */
  --header-h: 5.9rem;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-padding-top: var(--header-h);
}

/* While the selection bar is showing, a focused control is scrolled clear of it. js/main.js keeps
   --bar-h equal to the bar's real height. */

html.bar-on {
  scroll-padding-bottom: calc(var(--bar-h, 0px) + 1rem);
}

html.motion {
  scroll-behavior: smooth;
}

/* The open menu locks the page behind it. */

html.menu-open,
html.menu-open body {
  overflow: hidden;
}

body {
  position: relative;
  margin: 0;
  background: var(--fog);
  color: var(--tide);
  font-family: var(--text);
  font-size: 1.0625rem;
  font-weight: 400;
  line-height: 1.65;
  font-kerning: normal;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
}

::selection {
  background: var(--tide);
  color: var(--fog);
}

/* Paper grain. Fixed, ignores the pointer, sits over everything at 4%. */

body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 40;
  pointer-events: none;
  opacity: 0.04;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='g' x='0' y='0' width='100%25' height='100%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E");
  background-size: 240px 240px;
}

h1, h2, h3, p, ol, ul {
  margin: 0;
}

ol, ul {
  padding: 0;
}

img {
  display: block;
  max-width: 100%;
  filter: saturate(0.92) contrast(1.03);
}

[hidden] {
  display: none !important;
}

/* Type */

h1, h2, h3 {
  font-family: var(--display);
  color: var(--tide);
}

h1 {
  font-size: clamp(2rem, 8.4vw, 3.4rem);
  font-weight: 400;
  line-height: 1.12;
  letter-spacing: -0.015em;
  text-wrap: balance;
}

@media (min-width: 860px) {
  h1 {
    font-size: min(4.8vw, 4rem);
    line-height: 1.08;
  }
}

h2 {
  font-size: clamp(2rem, 3.6vw, 2.75rem);
  font-weight: 400;
  line-height: 1.12;
  letter-spacing: -0.012em;
}

h3 {
  font-size: 1.25rem;
  font-weight: 500;
  line-height: 1.3;
}

h2, h3 {
  text-wrap: balance;
}

p {
  max-width: 62ch;
  text-wrap: pretty;
}

.small {
  font-size: 0.875rem;
  line-height: 1.55;
}

/* Display-face paragraphs: the lead under a heading, and the larger statement. */

.lead {
  font-family: var(--display);
  font-size: clamp(1.5rem, 2.4vw, 1.75rem);
  font-weight: 400;
  line-height: 1.3;
}

.statement {
  font-family: var(--display);
  font-size: clamp(1.75rem, 3.4vw, 2.9rem);
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: -0.01em;
}

.wordmark {
  display: inline-flex;
  align-items: center;
  gap: 0.9rem;
  font-family: var(--display);
  color: var(--tide);
}

/* The logo is an image, sized here and only here, so a new file of the same name drops in. Two
   versions, by background: assets/logo-192.png and assets/logo.png (dark character, bronze frame) on
   the light surfaces (header, footer, the Standard in brief, the entrance), and
   assets/logo-on-dark-192.png (single-colour tan) on the dark teal panel, where every form
   confirmation sits. It is not a photograph, so it takes none of the photo grade. */

.logo-mark,
.logo-brief,
.logo-veil,
.logo-confirm {
  display: block;
  flex: none;
  max-width: none;
  filter: none;
}

.logo-mark {
  width: 2.75rem;
  height: 2.75rem;
}

.site-header.is-stuck .logo-mark {
  width: 2.5rem;
  height: 2.5rem;
}

/* The small stamp: a 1px sandstone square holding 和, the first character of nagomi (和み). It marks
   a chosen row, a chosen plan and each example on the Standard page. It is a stamp, not the logo. */

.seal {
  display: grid;
  place-items: center;
  width: 1.9rem;
  height: 1.9rem;
  border: 1px solid var(--sandstone);
  font-family: var(--display);
  font-size: 1.05rem;
  font-weight: 500;
  line-height: 1;
}

.seal-sm {
  width: 1.5rem;
  height: 1.5rem;
  font-size: 0.8125rem;
}

.wordmark-name {
  margin-right: -0.34em;
  font-size: 0.9375rem;
  font-weight: 500;
  letter-spacing: 0.34em;
  line-height: 1;
  text-transform: uppercase;
}

a {
  color: var(--kelp);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.25em;
  text-decoration-color: rgb(51 87 90 / 0.55);
}

a:hover {
  text-decoration-color: var(--kelp);
}

a.wordmark {
  flex: none;
  text-decoration: none;
  white-space: nowrap;
}

html.motion a {
  transition: color 400ms var(--ease-out), text-decoration-color 400ms var(--ease-out);
}

/* Focus */

:focus-visible {
  outline: 2px solid var(--tide);
  outline-offset: 3px;
}

.request :focus-visible,
.panel-tide :focus-visible,
.independence :focus-visible,
.sel-bar :focus-visible {
  outline-color: var(--fog);
}

.confirmation h3:focus {
  outline: none;
}

/* Layout helpers */

.wrap {
  width: 100%;
  max-width: var(--max);
  margin-left: auto;
  margin-right: auto;
  padding-left: var(--gutter);
  padding-right: var(--gutter);
}

.grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--col-gap);
}

.clears-header {
  padding-top: var(--header-h);
}

/* The entrance overlay is in every page, and shown only while html.entrance is set. */

.entrance-veil {
  display: none;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  left: 0;
  z-index: 35;
  padding: 0.75rem 1rem;
  background: var(--tide);
  color: var(--fog);
  top: -5rem;
}

.skip-link:focus-visible {
  top: 0;
  outline-color: var(--fog);
  outline-offset: -4px;
}

/* Photo frames. Every image gets one grade; the frame clips it. */

.parallax {
  position: absolute;
  top: -10%;
  left: 0;
  right: 0;
  height: 120%;
}

.parallax img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Buttons. The fill sweeps up from the bottom on hover. */

.btn {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: inline-block;
  padding: 0.95rem 1.6rem;
  border: 0;
  border-radius: 0;
  background: var(--tide);
  color: var(--fog);
  font-family: var(--text);
  font-size: 1rem;
  font-weight: 500;
  line-height: 1.2;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}

.btn::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--kelp);
  transform: translateY(101%);
}

.btn:hover::before {
  transform: translateY(0);
}

.request .btn,
.panel-tide .btn,
.sel-bar .btn {
  background: var(--fog);
  color: var(--tide);
}

.request .btn::before,
.panel-tide .btn::before,
.sel-bar .btn::before {
  background: var(--mist);
}

html.motion .btn {
  transition: transform 200ms var(--ease-out);
}

html.motion .btn:active {
  transform: scale(0.985);
}

html.motion .btn::before {
  transition: transform 500ms var(--ease-soft);
}

/* Header. Fixed and transparent at the top of the page, so a photo can run to the window edge.
   js/main.js adds is-stuck after 80px of scroll, and is-hidden while the visitor scrolls down. */

.site-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 30;
  border-bottom: 1px solid transparent;
}

html:not(.js) .site-header {
  position: absolute;
}

.site-header.is-stuck,
.home .site-header {
  background: var(--fog);
  border-bottom-color: var(--mist);
}

.site-header.is-hidden {
  transform: translateY(-100%);
}

html.motion .site-header {
  transition: transform 500ms var(--ease-soft);
}

/* An open menu is a fixed panel, and a transform on its parent would resize it. */

html .site-header.menu-open {
  transform: none;
  transition: none;
}

.header-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1.25rem;
  padding-top: 1.5rem;
  padding-bottom: 1.5rem;
}

.site-header.is-stuck .header-row {
  padding-top: 0.75rem;
  padding-bottom: 0.75rem;
}

.header-row .wordmark,
.menu-btn {
  position: relative;
  z-index: 2;
}

.header-menu {
  display: flex;
  flex: 1;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1.25rem;
}

.header-nav ul {
  display: flex;
  flex-wrap: wrap;
  gap: 1.1rem;
  margin: 0;
  list-style: none;
}

.header-nav a {
  color: var(--tide);
  font-size: 0.9375rem;
  white-space: nowrap;
}

.header-nav a:hover {
  color: var(--kelp);
}

.header-menu .btn {
  flex: none;
  padding: 0.8rem 1.2rem;
}

.menu-note {
  display: none;
}

.menu-btn {
  display: none;
  align-items: center;
  min-height: 2.75rem;
  padding: 0 0.25rem;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--tide);
  font-family: var(--text);
  font-size: 1rem;
  font-weight: 500;
  line-height: 1;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.25em;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}

@media (min-width: 77.5em) {
  .header-row {
    gap: 3rem;
  }

  .header-nav ul {
    gap: 1.75rem;
  }

  .header-menu .btn {
    padding-left: 1.4rem;
    padding-right: 1.4rem;
  }
}

/* Hero */

.hero {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 58fr) minmax(0, 42fr);
  min-height: calc(100vh - var(--header-h));
  min-height: calc(100svh - var(--header-h));
  container-type: inline-size;
}

.hero-text {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
  padding-top: 4rem;
  padding-bottom: 4.5rem;
  padding-left: calc(max(0px, (100cqw - var(--max)) / 2) + var(--gutter));
  padding-right: clamp(1.5rem, 3vw, 3rem);
}

/* The greeting is written by js/main.js. It reserves one line, so writing it moves nothing, and
   without the script it is not there at all. */

.hero-greeting {
  margin-bottom: 1rem;
  color: var(--kelp);
  font-family: var(--display);
  font-size: 1.125rem;
  line-height: 1.5;
}

html.js .hero-greeting {
  min-height: 1.5em;
}

html:not(.js) .hero-greeting {
  display: none;
}

.hero-intro {
  margin-top: 1.75rem;
  max-width: 46ch;
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem 2rem;
  margin-top: 2.25rem;
}

.hero-note {
  margin-top: 2rem;
  color: var(--kelp);
}

/* Video frames. The poster is the first thing seen: it is also painted behind the video (from
   --poster, set on the frame), so the video can fade in over it and the poster stays if the video
   never loads. Both layers take the one photo grade. */

.media {
  position: relative;
  overflow: hidden;
  background: var(--stone);
}

/* The hero's video sits in its own frame, so the image label covers the video and not the button.
   The frame fills the .media and holds the absolutely placed video. */

.media-frame {
  position: absolute;
  inset: 0;
}

.hero-photo::before,
.band .parallax::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--poster) center 55% / cover no-repeat;
  filter: saturate(0.92) contrast(1.03);
}

.media-video {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 55%;
  filter: saturate(0.92) contrast(1.03);
}

html.js .media-video {
  opacity: 0;
}

html.js .media.has-played .media-video {
  opacity: 1;
}

.media-toggle {
  position: absolute;
  left: 1rem;
  bottom: 1rem;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  padding: 0 1.1rem;
  border: 0;
  border-radius: 0;
  background: rgb(20 40 43 / 0.82);
  color: var(--fog);
  font-family: var(--text);
  font-size: 0.875rem;
  font-weight: 500;
  line-height: 1;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}

.media-toggle:hover {
  background: var(--tide);
}

.media-toggle:focus-visible {
  outline-color: var(--fog);
  outline-offset: -4px;
}

html:not(.js) .media-toggle {
  display: none;
}

.hero-photo {
  min-width: 0;
}

/* Sections that share the standard rhythm. Sticky heads clear the header. */

.what,
.arrange {
  padding-top: var(--space-wide);
  padding-bottom: var(--space-wide);
}

.section-intro {
  margin-top: 1.25rem;
}

.note {
  margin-top: 1.25rem;
  color: var(--kelp);
}

/* Rows with a hairline on top that draws in. Vertical lists drop the first line and the outer padding. */

.ruled {
  position: relative;
}

.ruled::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  background: var(--mist);
  transform-origin: left center;
}

.rows {
  --row-pad: 2.5rem;
  margin: 0;
  list-style: none;
}

.rows > .ruled {
  padding-top: var(--row-pad);
  padding-bottom: var(--row-pad);
}

.rows > .ruled:first-child {
  padding-top: 0;
}

.rows > .ruled:last-child {
  padding-bottom: 0;
}

.rows > .ruled:first-child::before {
  display: none;
}

/* What we do */

.what .grid {
  align-items: start;
}

.what-copy {
  grid-column: 1 / span 5;
}

.what-copy .lead {
  margin-top: 1.75rem;
}

.what-photo {
  grid-column: 8 / span 5;
  aspect-ratio: 4 / 5;
  overflow: hidden;
}

.what-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 55%;
}

.what-steps {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  column-gap: clamp(1.5rem, 3vw, 3rem);
  margin-top: clamp(3.5rem, 7vw, 6rem);
  list-style: none;
}

.what-steps > li {
  padding-top: 1.75rem;
}

.step-num {
  display: block;
  color: var(--kelp);
  font-family: var(--display);
  font-size: clamp(2rem, 3vw, 2.75rem);
  line-height: 1;
}

.what-steps h3 {
  margin-top: 1.25rem;
}

.what-steps p {
  margin-top: 0.5rem;
}

/* Band */

.band {
  position: relative;
  height: min(72vh, 720px);
  overflow: hidden;
}

.band .parallax .media-video {
  object-position: center 55%;
}

/* What we arrange */

.arrange .grid {
  align-items: start;
}

.arrange-head {
  grid-column: 1 / span 4;
  position: sticky;
  top: calc(var(--header-h) + 1rem);
}

.arrange-body {
  grid-column: 6 / span 7;
}

.arrange-list {
  --row-pad: 1.75rem;
}

.arrange-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
  column-gap: var(--col-gap);
  align-items: baseline;
}

.arrange-name {
  font-size: clamp(1.75rem, 3.2vw, 2.25rem);
  font-weight: 400;
  line-height: 1.15;
  letter-spacing: -0.01em;
}

.arrange-after {
  margin-top: 2.5rem;
}

.arrange-after a {
  white-space: nowrap;
}

.arrange-after a + a {
  margin-left: 1.5rem;
}

/* The Standard, in brief */

.brief {
  padding-top: var(--space-wide);
  padding-bottom: var(--space-wide);
  background: var(--stone);
}

.brief .grid {
  align-items: start;
}

.brief .logo-brief {
  grid-column: 1 / span 2;
  width: 6.5rem;
  height: 6.5rem;
}

.brief-copy {
  grid-column: 3 / span 8;
}

.statement-line {
  display: block;
  max-width: 22ch;
  text-wrap: balance;
}

.statement-line + .statement-line {
  margin-top: 0.6em;
}

.brief-link {
  margin-top: 2rem;
}

/* The Private Reset */

.reset {
  padding-top: var(--space-wide);
  padding-bottom: var(--space-base);
}

.reset .grid {
  align-items: start;
}

.reset-photo {
  grid-column: 1 / span 5;
  position: sticky;
  top: calc(var(--header-h) + 1rem);
  aspect-ratio: 4 / 5;
  overflow: hidden;
}

.reset-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 75%;
}

.reset-copy {
  grid-column: 7 / span 6;
}

.steps {
  margin-top: 2rem;
  padding-left: 2.25rem;
  list-style: decimal;
}

.steps li {
  padding-left: 0.5rem;
}

.steps li + li {
  margin-top: 1.4rem;
}

.steps li::marker {
  color: var(--kelp);
  font-family: var(--display);
  font-size: 1.5rem;
}

.steps strong {
  display: block;
  font-weight: 500;
}

.after-list {
  margin-top: 2rem;
}

/* What we believe */

.beliefs {
  padding-top: var(--space-base);
  padding-bottom: var(--space-wide);
}

.beliefs-head,
.discretion-head,
.check-head,
.process-head {
  grid-column: 1 / span 4;
  align-self: start;
  position: sticky;
  top: calc(var(--header-h) + 1rem);
}

.beliefs-list,
.discretion-list,
.check-list,
.process-body {
  grid-column: 6 / span 7;
}

.belief h3,
.check-item h3,
.how-list h3,
.facts h2 {
  font-size: clamp(1.5rem, 2.4vw, 1.75rem);
  line-height: 1.25;
}

/* The three facts follow the page's h1 directly, so they are h2s that keep the h3 look. */

.facts h2 {
  font-weight: 500;
  letter-spacing: normal;
}

.belief p,
.check-item p,
.how-list p {
  margin-top: 0.75rem;
  font-size: 1.125rem;
}

/* Discretion: What we believe's layout, straight after it on the same fog, so it takes no top padding
   of its own. */

.discretion {
  padding-bottom: var(--space-wide);
}

/* Request: a photo on the left, a solid panel on the right, both bleeding to the window edges. */

.request {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  background: var(--tide);
  color: var(--fog);
}

.request h2,
.panel-tide h2 {
  color: var(--fog);
}

.request-photo {
  position: relative;
  overflow: hidden;
}

.request-photo img {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 60%;
}

.request-panel {
  padding: clamp(4rem, 8vw, 7rem);
  background: var(--tide);
}

.request-panel > * {
  max-width: 34rem;
}

.request-copy p {
  margin-top: 1.25rem;
}

/* How it begins: three short steps in quiet type, with the lead-ins in fog. */

.request-steps {
  margin-top: 2rem;
  padding-left: 1.5rem;
  list-style: decimal;
  color: var(--mist-on-tide);
}

.request-steps li + li {
  margin-top: 0.75rem;
}

.request-steps strong {
  color: var(--fog);
  font-weight: 500;
}

.request-form-wrap,
.form-wrap {
  margin-top: 2.5rem;
}

.field + .field {
  margin-top: 1.75rem;
}

.field label {
  display: block;
  margin-bottom: 0.25rem;
  color: var(--mist-on-tide);
  font-size: 0.875rem;
  line-height: 1.5;
}

.control {
  position: relative;
}

.control::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: var(--fog);
  transform: scaleX(0);
  transform-origin: left center;
}

.control:focus-within::after {
  transform: scaleX(1);
}

html.motion .control::after {
  transition: transform 600ms var(--ease-out);
}

.field input,
.field textarea {
  display: block;
  width: 100%;
  padding-top: 0.6rem;
  padding-bottom: 0.6rem;
  padding-left: 0;
  padding-right: 0;
  border: 0;
  border-bottom: 1px solid var(--mist-on-tide);
  border-radius: 0;
  background: transparent;
  color: var(--fog);
  font-family: var(--text);
  font-size: 1.0625rem;
  line-height: 1.5;
  -webkit-appearance: none;
  appearance: none;
}

.field textarea {
  resize: vertical;
}

.field input[aria-invalid="true"] {
  border-bottom-color: var(--warn-on-tide);
}

.error {
  margin-top: 0.5rem;
  color: var(--warn-on-tide);
  font-size: 0.875rem;
  line-height: 1.5;
}

.error:empty {
  margin-top: 0;
}

[data-demo-form] .btn {
  margin-top: 2.25rem;
}

.confirmation .logo-confirm {
  width: 4rem;
  height: 4rem;
  margin-bottom: 1.5rem;
}

.confirmation h3 {
  color: var(--fog);
}

.confirmation p {
  margin-top: 0.75rem;
}

.demo-line {
  color: var(--mist-on-tide);
}

.privacy-line {
  margin-top: 1.5rem;
  color: var(--mist-on-tide);
}

/* Footer */

.site-footer {
  padding-top: clamp(4rem, 8vw, 6.5rem);
  padding-bottom: clamp(3rem, 6vw, 5rem);
  background: var(--stone);
}

.signoff {
  max-width: none;
  font-family: var(--display);
  font-size: clamp(2.6rem, 8.5vw, 7.5rem);
  font-weight: 400;
  line-height: 1;
  letter-spacing: -0.02em;
}

.footer-rule {
  position: relative;
  height: 1px;
  margin-top: clamp(2rem, 4vw, 3rem);
  margin-bottom: clamp(2rem, 4vw, 3rem);
}

.footer-rule::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--mist);
  transform-origin: left center;
}

.footer-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 2rem 3rem;
}

.footer-lines p {
  max-width: none;
  color: var(--kelp);
}

/* The local time is written by js/main.js. Until then (and without it) the line is absent. */

.footer-lines p:empty {
  display: none;
}

.footer-nav ul {
  margin: 0;
  list-style: none;
}

.footer-nav li + li {
  margin-top: 0.35rem;
}

.footer-end {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

/* The motion control. Looks like the footer links; hidden without JavaScript. */

.motion-toggle {
  margin: 0.35rem 0 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--kelp);
  font-family: var(--text);
  text-align: left;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.25em;
  text-decoration-color: rgb(51 87 90 / 0.55);
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}

.motion-toggle:hover {
  text-decoration-color: var(--kelp);
}

html:not(.js) .motion-toggle {
  display: none;
}

/* Inner pages: the Standard, For providers and the 404 page. Same parts as the home page. */

/* The 404 page keeps its footer at the foot of the window. */

.page-fill {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100svh;
}

.page-fill > main {
  flex: 1 0 auto;
}

/* Opening: a heading and a lead, with a photo on the Standard page. The header height is cleared by main. */

.page-open {
  padding-top: clamp(2.5rem, 6vw, 5rem);
}

.page-open .grid {
  align-items: start;
}

.page-open-copy {
  grid-column: 1 / span 7;
}

.page-open-text .page-open-copy {
  grid-column: 1 / span 8;
}

.page-open-copy .lead {
  margin-top: 1.75rem;
}

.page-open-copy .btn {
  margin-top: 2.25rem;
}

.page-photo {
  grid-column: 9 / span 4;
  aspect-ratio: 4 / 5;
  overflow: hidden;
}

.page-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 12%;
}

.exp-open .page-photo img {
  object-position: center 65%;
}

.not-found {
  padding-bottom: var(--space-wide);
}

/* What we check, and What happens: a heading on the left, rows or steps on the right. */

.check,
.process {
  padding-top: var(--space-wide);
  padding-bottom: var(--space-wide);
}

.check .grid,
.process .grid {
  align-items: start;
}

.process .steps {
  margin-top: 0;
}

/* Three facts in three columns, each with a hairline on top. Not a sequence, so no numerals. */

.provider-facts {
  padding-top: var(--space-base);
}

.facts {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  column-gap: clamp(1.5rem, 3vw, 3rem);
  margin: 0;
  list-style: none;
}

.facts > li {
  padding-top: 1.75rem;
}

.facts p {
  margin-top: 0.75rem;
}

/* Independence: three statements on the dark band, with hairlines between. */

.independence {
  padding-top: var(--space-wide);
  padding-bottom: var(--space-wide);
  background: var(--tide);
  color: var(--fog);
}

.independence .rows {
  --row-pad: 2rem;
}

.independence .ruled::before,
.panel-tide .ruled::before {
  background: var(--mist-on-tide);
}

.independence .statement {
  text-wrap: balance;
}

/* The list. Each category is a heading over rows in the 12-column grid. Not a table. */

.list {
  padding-top: var(--space-wide);
  padding-bottom: var(--space-wide);
}

.list-groups {
  margin-top: clamp(3rem, 6vw, 4.5rem);
}

.list-group + .list-group {
  margin-top: clamp(3rem, 6vw, 4.5rem);
}

.list-cat {
  margin-bottom: 1.25rem;
  font-size: clamp(1.5rem, 2.4vw, 2.1rem);
  font-weight: 400;
  line-height: 1.25;
}

.entries {
  margin: 0;
  list-style: none;
}

.entry {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--col-gap);
  align-items: start;
  padding-top: 1.5rem;
  padding-bottom: 1.5rem;
}

.entry-name {
  grid-column: 1 / span 4;
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
}

.entry-name .seal {
  flex: none;
  margin-top: 0.15rem;
}

.entry-title {
  font-weight: 500;
}

.entry-place {
  grid-column: 5 / span 3;
  color: var(--kelp);
}

.entry-reason {
  grid-column: 8 / span 5;
}

/* The Example tag. A 1px sandstone box around small text. Not a label in capitals. */

.tag {
  display: inline-block;
  margin-top: 0.5rem;
  padding: 0.05rem 0.5rem;
  border: 1px solid var(--sandstone);
  color: var(--tide);
  font-size: 0.875rem;
  line-height: 1.5;
}

/* Ask: a statement and the request button, on stone. */

.ask {
  padding-top: var(--space-base);
  padding-bottom: var(--space-base);
  background: var(--stone);
}

.ask .statement {
  max-width: 30ch;
  text-wrap: balance;
}

.ask .btn {
  margin-top: 2rem;
}

/* The closing line of a page sits at the foot of the section before it, so the page ends in one
   continuous tone into the footer. */

.providers-line,
.not-listed {
  max-width: none;
  margin-top: 2.5rem;
}

/* A dark panel with a heading and a form. The field styles are the request form's. */

.panel-tide {
  padding-top: var(--space-base);
  padding-bottom: var(--space-base);
  background: var(--tide);
  color: var(--fog);
}

.panel-tide .grid {
  align-items: start;
}

.panel-head {
  grid-column: 1 / span 5;
}

.panel-form {
  grid-column: 7 / span 6;
}

.panel-form .form-wrap {
  margin-top: 0;
}

/* Experiences. A menu of cells in columns, filtered by category, with a bar and a selection panel.
   Cells are not boxes: a hairline on top and nothing else. The selection lives in js/main.js only. */

.rule-line {
  margin-top: 1.5rem;
  color: var(--kelp);
}

.exp-menu,
.plan-menu {
  padding-top: var(--space-base);
  padding-bottom: var(--space-wide);
}

.menu-rule {
  position: relative;
  height: 1px;
}

.menu-rule::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--mist);
  transform-origin: left center;
}

/* The filter row: plain text buttons, underlined when pressed. */

.filters {
  display: flex;
  flex-wrap: wrap;
  column-gap: 1.75rem;
  margin-top: 0.75rem;
}

.filter {
  min-width: 2.75rem;
  min-height: 2.75rem;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--kelp);
  font-family: var(--text);
  font-size: 1rem;
  line-height: 1.2;
  text-align: left;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}

.filter:hover {
  color: var(--tide);
}

/* The sandstone accent is used sparingly on this page: under the active filter (in --sandstone-line,
   a shade that holds 3:1 on the fog), as a short rule beneath each category heading, and on a chosen
   row. It is never used for text. */

.filter[aria-pressed="true"] {
  color: var(--tide);
  text-decoration: underline;
  text-decoration-color: var(--sandstone-line);
  text-decoration-thickness: 2px;
  text-underline-offset: 0.4em;
}

/* The menu is one group per category. From 1080px a group is on the 12-column grid: a sticky head
   in columns 1 to 4 (the category and its count) and the rows in columns 6 to 12. Under 1080px the
   head sits above its rows and does not stick. */

.exp-group {
  margin-top: clamp(4rem, 8vw, 7rem);
}

.exp-group-head {
  margin-bottom: 1.5rem;
}

.exp-group-head h2 {
  font-size: clamp(1.75rem, 3.2vw, 2.25rem);
}

.exp-count {
  margin-top: 1.1rem;
  color: var(--kelp);
}

.exp-count::before {
  content: "";
  display: block;
  width: 2.5rem;
  height: 2px;
  margin-bottom: 0.9rem;
  background: var(--sandstone);
}

@media (min-width: 1080px) {
  .exp-group {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    column-gap: var(--col-gap);
    align-items: start;
  }

  .exp-group-head {
    grid-column: 1 / span 4;
    position: sticky;
    top: calc(var(--header-h) + 2rem);
    margin-bottom: 0;
    padding-top: 1.75rem;
  }

  .exp-group > .exp-list {
    grid-column: 6 / span 7;
  }
}

/* A row, in the family of the What we arrange rows: a hairline on top that draws in, the text on the
   left, the Choose button on the right at the top of the row. */

.exp-list {
  margin: 0;
  list-style: none;
}

.exp {
  --exp-name-size: clamp(1.5rem, 2.2vw, 1.9rem);
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  column-gap: var(--col-gap);
  align-items: start;
  padding-top: 1.75rem;
  padding-bottom: 1.75rem;
}

.exp::before,
.exp::after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  transform-origin: left center;
}

.exp::before {
  height: 1px;
  background: var(--mist);
}

/* Chosen: a 2px sandstone line lies over the hairline. */

.exp::after {
  height: 2px;
  background: var(--sandstone);
  opacity: 0;
}

.exp.is-chosen::after {
  opacity: 1;
}

/* The seal that marks a chosen row is taken out of the flow, so choosing never moves the name. From
   1080px it sits in the margin to the left of the name. Under 1080px the text block keeps a fixed
   left inset, 2.25rem, whether or not the seal is showing, and the seal sits in that inset. */

.exp-body {
  position: relative;
  min-width: 0;
  padding-left: 2.25rem;
}

.exp-body > .seal {
  display: none;
  position: absolute;
  left: 0;
  top: calc((var(--exp-name-size) * 1.2 - 1.5rem) / 2);
}

.exp.is-chosen .exp-body > .seal {
  display: grid;
}

@media (min-width: 1080px) {
  .exp-body {
    padding-left: 0;
  }

  .exp-body > .seal {
    left: -2.25rem;
  }
}

html:not(.js) .exp-body {
  padding-left: 0;
}

.exp-name {
  font-size: var(--exp-name-size);
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: -0.01em;
}

.exp-summary {
  margin-top: 0.75rem;
  max-width: 46ch;
}

.exp-meta {
  margin-top: 0.75rem;
  color: var(--kelp);
}

.exp-pick,
.plan-pick {
  min-height: 2.75rem;
  padding: 0 1.25rem;
  border: 1px solid var(--tide);
  border-radius: 0;
  background: transparent;
  color: var(--tide);
  font-family: var(--text);
  font-size: 0.9375rem;
  font-weight: 500;
  line-height: 1.2;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}

.exp-pick[aria-pressed="true"],
.plan-pick[aria-pressed="true"] {
  background: var(--tide);
  color: var(--fog);
}

/* Hover only where there is a real pointer, so a tapped button does not stay tinted on phones. */

@media (hover: hover) and (pointer: fine) {
  .exp-pick:hover,
  .plan-pick:hover {
    border-color: var(--kelp);
    color: var(--kelp);
  }

  .exp-pick[aria-pressed="true"]:hover,
  .plan-pick[aria-pressed="true"]:hover {
    border-color: var(--kelp);
    background: var(--kelp);
    color: var(--fog);
  }
}

html.motion .exp-pick,
html.motion .plan-pick {
  transition: background-color 400ms var(--ease-out), color 400ms var(--ease-out), border-color 400ms var(--ease-out);
}

/* Under 640px the button sits under the text block. */

@media (max-width: 639px) {
  .exp {
    grid-template-columns: minmax(0, 1fr);
  }

  .exp-pick {
    justify-self: start;
    margin-top: 1.25rem;
    margin-left: 2.25rem;
  }

  html:not(.js) .exp-pick {
    margin-left: 0;
  }
}

/* Without JavaScript the menu is a plain list: nothing to filter or choose. */

html:not(.js) .filters,
html:not(.js) .exp-pick,
html:not(.js) .plan-pick,
html:not(.js) .sel-bar,
html:not(.js) .selection,
html:not(.js) .plan-request {
  display: none;
}

html:not(.js) .exp {
  grid-template-columns: minmax(0, 1fr);
}

/* The selection bar. Fixed to the window's foot while at least one experience is chosen and the
   selection section is out of view. Hidden with visibility, which is switched after the slide. */

.sel-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 25;
  padding-top: 0.75rem;
  padding-bottom: 0.75rem;
  background: var(--tide);
  color: var(--fog);
  visibility: hidden;
}

.sel-bar.is-shown {
  visibility: visible;
}

.sel-bar-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.sel-bar-count {
  font-weight: 500;
}

.sel-bar .btn {
  flex: none;
  min-height: 2.75rem;
  padding: 0.8rem 1.2rem;
}

html.bar-on body {
  padding-bottom: var(--bar-h, 0px);
}

/* Your selection: the chosen list on the left, the form on the right (the panel's own columns). */

#selection-title:focus,
#request-plan-title:focus {
  outline: none;
}

.selection-empty {
  margin-top: 1.5rem;
  color: var(--mist-on-tide);
}

.selection-list {
  --row-pad: 1rem;
  margin-top: 2rem;
}

.sel-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.sel-name {
  font-family: var(--display);
  font-size: 1.25rem;
  font-weight: 500;
  line-height: 1.3;
}

.sel-cat {
  color: var(--mist-on-tide);
}

.sel-remove {
  flex: none;
  min-height: 2.75rem;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--fog);
  font-family: var(--text);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.25em;
  text-decoration-color: rgb(238 240 238 / 0.55);
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}

.sel-remove:hover {
  text-decoration-color: var(--fog);
}

/* How these are chosen: a heading on the left and three rows on the right, on stone. */

.how {
  padding-top: var(--space-base);
  padding-bottom: var(--space-base);
  background: var(--stone);
}

.how .grid {
  align-items: start;
}

.how-head {
  grid-column: 1 / span 4;
  align-self: start;
  position: sticky;
  top: calc(var(--header-h) + 1rem);
}

.how-body {
  grid-column: 6 / span 7;
}

.how-link {
  margin-top: 2.5rem;
}

/* Days and weekends. A plan is a head (name, summary, booking count, Choose) beside one or two days,
   each a timeline: the start time and its length, a rail, and the name with its setting. The same
   .timeline is drafted in the Your selection panel on the Experiences page and drawn on the home page
   under A day, planned, restyled for the tide panel. The plans are written by build-days.py; the
   choosing lives in js/main.js. */

.plan {
  position: relative;
  container-type: inline-size;
  margin-top: clamp(4rem, 8vw, 7rem);
  padding-top: 2rem;
}

.plan::before,
.plan::after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  transform-origin: left center;
}

.plan::before {
  height: 1px;
  background: var(--mist);
}

/* Chosen: a 2px sandstone line lies over the hairline. */

.plan::after {
  height: 2px;
  background: var(--sandstone);
  opacity: 0;
}

.plan.is-chosen::after {
  opacity: 1;
}

/* The seal that marks a chosen plan is out of the flow, so choosing never moves the name: from 1080px
   it sits in the margin to the left of the head, and under it the head keeps a fixed left inset
   (2.25rem) whether or not the seal is showing. */

.plan-head {
  --plan-name-size: clamp(2rem, 3.6vw, 2.75rem);
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
  min-width: 0;
  padding-left: 2.25rem;
}

.plan-head h2 {
  font-size: var(--plan-name-size);
}

.plan-head > .seal {
  display: none;
  position: absolute;
  left: 0;
  top: calc((var(--plan-name-size) * 1.12 - 1.5rem) / 2);
}

.plan.is-chosen .plan-head > .seal {
  display: grid;
}

html:not(.js) .plan-head {
  padding-left: 0;
}

.plan-summary {
  margin-top: 1rem;
  max-width: 34ch;
}

/* The count of booked stops, under a short sandstone rule: the rule used under the Experiences
   category headings. */

.plan-count {
  margin-top: 1.1rem;
  color: var(--kelp);
}

.plan-count::before {
  content: "";
  display: block;
  width: 2.5rem;
  height: 2px;
  margin-bottom: 0.9rem;
  background: var(--sandstone);
}

.plan-pick {
  justify-self: start;
  margin-top: 1.5rem;
}

.plan-days {
  display: grid;
  row-gap: 2.5rem;
  margin-top: 2.5rem;
  min-width: 0;
}

.plan-day {
  min-width: 0;
}

.plan-day-label {
  margin-bottom: 0.25rem;
  font-family: var(--display);
  font-size: 1.25rem;
  font-weight: 500;
  line-height: 1.3;
}

/* A weekend's day heading: the day, the span of the day in small kelp text, then the 2.5rem sandstone
   rule. The draft's labels have no span line, so they only get room before their timeline. */

.plan-day-span {
  color: var(--kelp);
}

.plan-day-span::after {
  content: "";
  display: block;
  width: 2.5rem;
  height: 2px;
  margin-top: 0.9rem;
  background: var(--sandstone);
}

.plan-day-span + .timeline {
  margin-top: 1.5rem;
}

.plan-day-label + .timeline {
  margin-top: 1rem;
}

/* From 1080px a plan is on the 12-column grid: the head in columns 1 to 4 (sticky, like the
   Experiences group heads) and the days in columns 6 to 12. A weekend's two days sit side by side
   from 1280px and stack below that. */

@media (min-width: 1080px) {
  .plan {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    column-gap: var(--col-gap);
    align-items: start;
  }

  .plan-head {
    grid-column: 1 / span 4;
    position: sticky;
    top: calc(var(--header-h) + 2rem);
    padding-left: 0;
  }

  .plan-head > .seal {
    left: -2.25rem;
  }

  .plan-days {
    grid-column: 6 / span 7;
    margin-top: 0;
  }
}

/* The two days of a weekend sit side by side once the plan is 72rem wide (1152px at the default text
   size, which is a 1280px window). It is a container query, so that larger text, which needs wider
   columns, stacks them instead of overflowing, whether the text size is a browser setting or a
   font-size on the page. */

@container (min-width: 72rem) {
  .plan[data-kind="weekend"] .plan-days {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: var(--col-gap);
  }

  .plan[data-kind="weekend"] .timeline {
    --time-w: 5.5rem;
  }
}

/* The timeline. Each stop is a row of three columns: the time, the rail and the body. The time column
   is right-aligned, so every start time ends at the same edge, next to the rail, and the eye can run
   down a column of them. The rail carries the meaning. A booked stop is a solid 2px bar with a 7px
   sandstone square at its top; it stops 0.75rem short of the row's bottom, which is the room left to
   get to the next stop. Free time is a dotted line the full height of its row, with no square. Each day
   ends in an outlined square. Nothing runs behind them: the bars and dotted runs are the rail. A row
   is as tall as its stop is long (the generator and the draft write --mins), so a long booking reads
   as long. Under 640px the time moves above the name as "9:00 am, 1 hour" and the rail sits beside
   both. */

.timeline {
  --time-w: 5.5rem;
  --rail-w: 2.5rem;
  margin: 0;
  list-style: none;
}

.stop,
.stop-end {
  position: relative;
  display: grid;
  grid-template-columns: var(--time-w) var(--rail-w) minmax(0, 1fr);
  align-items: baseline;
}

.stop {
  --stop-size: clamp(1.25rem, 1.8vw, 1.5rem);
  /* The square sits on the middle of the name's first line (a line is 1.25 times the type size). */
  --dot-top: calc(var(--stop-size) * 0.625 - 3.5px);
  min-height: clamp(4.75rem, calc(var(--mins) * 0.065rem), 11rem);
  /* However much text a row holds, the next row never starts closer than 1rem to it. */
  padding-bottom: 1rem;
}

.stop-open {
  min-height: clamp(3.5rem, calc(var(--mins) * 0.018rem), 6rem);
}

.stop-time {
  font-family: var(--display);
  font-size: 1.125rem;
  line-height: 1.2;
  color: var(--tide);
  text-align: right;
  font-variant-numeric: tabular-nums lining-nums;
}

.stop-time time {
  white-space: nowrap;
}

.stop-length {
  display: block;
  margin-top: 0.125rem;
  font-family: var(--text);
  font-size: 0.875rem;
  line-height: 1.55;
  color: var(--kelp);
}

.stop-rail {
  position: relative;
  align-self: stretch;
}

.stop:not(.stop-open) .stop-rail::before {
  content: "";
  position: absolute;
  top: var(--dot-top);
  bottom: 0.75rem;
  left: calc(50% - 1px);
  width: 2px;
  background: var(--tide);
  transform-origin: center top;
}

.stop:not(.stop-open) .stop-rail::after {
  content: "";
  position: absolute;
  top: var(--dot-top);
  left: calc(50% - 3.5px);
  width: 7px;
  height: 7px;
  background: var(--sandstone);
}

.stop-open .stop-rail::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: calc(50% - 0.5px);
  border-left: 1px dotted rgb(51 87 90 / 0.55);
  transform-origin: center top;
}

.stop-body {
  min-width: 0;
}

.stop-name {
  font-family: var(--display);
  font-size: var(--stop-size);
  font-weight: 400;
  line-height: 1.25;
  letter-spacing: -0.01em;
}

.stop-meta {
  margin-top: 0.25rem;
  color: var(--kelp);
}

.stop-note {
  font-family: var(--display);
  font-size: 1.125rem;
  line-height: 1.3;
  color: var(--kelp);
}

/* The closing row: the time the day ends, small and kelp with no length, and an outlined square. */

.stop-end .stop-time {
  font-family: var(--text);
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--kelp);
}

.stop-end .stop-rail::after {
  content: "";
  position: absolute;
  top: calc(0.875rem * 0.75 - 3.5px);
  left: calc(50% - 3.5px);
  width: 7px;
  height: 7px;
  border: 1px solid var(--sandstone);
}

/* From 1080px the time column is a little wider. */

@media (min-width: 1080px) {
  .plan .timeline {
    --time-w: 6.5rem;
  }
}

/* Hover, fine pointers only, booked stops only. The bar turns sandstone (a second bar fades in over
   it, so only opacity moves) and, at full motion, the name steps 0.25rem right. */

.stop:not(.stop-open)::after {
  content: "";
  position: absolute;
  top: var(--dot-top);
  bottom: 0.75rem;
  left: calc(var(--time-w) + var(--rail-w) / 2 - 1px);
  width: 2px;
  background: var(--sandstone);
  opacity: 0;
  pointer-events: none;
}

@media (hover: hover) and (pointer: fine) {
  .stop:not(.stop-open):hover::after {
    opacity: 1;
  }

  html.motion .stop:not(.stop-open)::after,
  html.motion-calm .stop:not(.stop-open)::after {
    transition: opacity 400ms var(--ease-out);
  }

  html.motion .stop:not(.stop-open) .stop-name {
    transition: transform 400ms var(--ease-out);
  }

  html.motion .stop:not(.stop-open):hover .stop-name {
    transform: translateX(0.25rem);
  }
}

@media (max-width: 639px) {
  .timeline {
    --rail-w: 1.5rem;
  }

  .stop,
  .stop-end {
    grid-template-columns: var(--rail-w) minmax(0, 1fr);
    grid-template-areas: "rail time" "rail body";
    grid-template-rows: auto 1fr;
    align-items: start;
    row-gap: 0.25rem;
  }

  .stop-end {
    grid-template-areas: "rail time";
    grid-template-rows: auto;
  }

  .stop {
    /* The square sits on the middle of the time line, which is the first line here. */
    --dot-top: calc(1.125rem * 0.75 - 3.5px);
  }

  .stop-rail {
    grid-area: rail;
  }

  .stop-time {
    grid-area: time;
    line-height: 1.5;
    text-align: left;
  }

  .stop-end .stop-time {
    line-height: 1.5;
  }

  .stop-length {
    display: inline;
    margin-top: 0;
  }

  .stop-length::before {
    content: ", ";
  }

  .stop-body {
    grid-area: body;
  }

  .stop:not(.stop-open)::after {
    left: calc(var(--rail-w) / 2 - 1px);
  }
}

/* On the tide panel (the draft, and the home page's vertical timeline): the bar and the times are fog,
   the small text and the dotted run are mist-on-tide, and the squares stay sandstone. */

.panel-tide .stop-time {
  color: var(--fog);
}

.panel-tide .stop:not(.stop-open) .stop-rail::before {
  background: var(--fog);
}

.panel-tide .stop-open .stop-rail::before {
  border-left-color: var(--mist-on-tide);
}

.panel-tide .stop-length,
.panel-tide .stop-meta,
.panel-tide .stop-note,
.panel-tide .stop-end .stop-time {
  color: var(--mist-on-tide);
}

/* The request section on the Days page, and the draft in Your selection on the Experiences page. */

.plan-chosen {
  margin-top: 1.5rem;
}

.draft {
  margin-top: 3rem;
}

.draft-mode {
  display: flex;
  flex-wrap: wrap;
  column-gap: 1.75rem;
}

.draft-opt {
  min-height: 2.75rem;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--mist-on-tide);
  font-family: var(--text);
  font-size: 1rem;
  line-height: 1.2;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}

.draft-opt:hover {
  color: var(--fog);
}

.draft-opt[aria-pressed="true"] {
  color: var(--fog);
  text-decoration: underline;
  text-decoration-color: var(--sandstone);
  text-decoration-thickness: 2px;
  text-underline-offset: 0.4em;
}

.draft h3 {
  margin-top: 1.25rem;
  color: var(--fog);
}

.draft-days {
  margin-top: 0.75rem;
}

.draft .plan-day + .plan-day {
  margin-top: 2rem;
}

.draft-note {
  margin-top: 1.25rem;
  color: var(--mist-on-tide);
}

.draft-sep {
  margin-top: 0.5rem;
  color: var(--mist-on-tide);
}

.draft-warn {
  margin-top: 0.5rem;
  color: var(--warn-on-tide);
}

/* A day, planned. The home page's one dark moment before the request panel: one plan from
   the itineraries data file drawn to scale along a day. From 1080px the axis runs from the earlier of
   9:00 and the first start to the later of 21:00 and the last end, with a tick label every three
   hours, and each stop placed by --s (its start) and --w (its width), both percentages of the axis,
   and --room (the distance to the next label on its side). It is the timeline on its side: a booked
   stop is a 3px fog bar with a 7px sandstone square at its start, free time is a dotted run, and the
   last span ends in an outlined square. There is no line under the whole axis; the bars and runs make
   it. Each label is the name over one small line, "9:00 am, 1 hour", and the labels alternate above
   and below. Under 1080px it is the vertical .timeline in its tide variant (the section is
   .panel-tide, which sets that). */

.day-home {
  padding-top: var(--space-wide);
  padding-bottom: var(--space-wide);
}

.day-home h2 {
  grid-column: 1 / span 5;
}

.day-home-copy {
  grid-column: 7 / span 6;
}

.day-home-name {
  font-family: var(--display);
  font-size: clamp(1.5rem, 2.4vw, 1.75rem);
  line-height: 1.3;
}

.day-home-summary {
  margin-top: 0.75rem;
}

.day-home-intro {
  margin-top: 1.25rem;
  color: var(--mist-on-tide);
}

.day-home-body {
  grid-column: 1 / -1;
  margin-top: clamp(3rem, 6vw, 5rem);
}

.day-home-guide,
.day-home-link {
  grid-column: 1 / -1;
  max-width: none;
}

.day-home-guide {
  margin-top: 1.5rem;
  color: var(--mist-on-tide);
}

.day-home-link {
  margin-top: 0.5rem;
}

.day-home a {
  color: var(--fog);
  text-decoration-color: rgb(238 240 238 / 0.55);
}

.day-home a:hover {
  text-decoration-color: var(--fog);
}

.day-home .timeline {
  margin-top: 0;
}

.day-axis {
  display: none;
}

.day-stops,
.day-ticks {
  margin: 0;
  list-style: none;
}

.day-time {
  max-width: none;
  margin-top: 0.125rem;
  color: var(--mist-on-tide);
  font-size: 0.875rem;
  line-height: 1.55;
}

.day-time time {
  white-space: nowrap;
}

.day-name {
  max-width: none;
  color: var(--fog);
  font-family: var(--display);
  font-size: 1.125rem;
  line-height: 1.3;
}

.day-note {
  max-width: none;
  color: var(--mist-on-tide);
  font-family: var(--display);
  font-size: 1.125rem;
  line-height: 1.3;
}

@media (min-width: 1080px) {
  .day-axis {
    --above-h: 6rem;
    --below-h: 9.5rem;
    position: relative;
    display: block;
    height: calc(var(--above-h) + 1px + var(--below-h));
  }

  .day-home .timeline {
    display: none;
  }

  /* The axis sits at --above-h: a bar is 3px across it, a dotted run is its middle pixel, the square is
     7px centred on it, so all three share one centre. */

  .day-bar,
  .day-mark,
  .day-run {
    position: absolute;
    left: var(--s);
  }

  .day-bar {
    top: calc(var(--above-h) - 1px);
    width: var(--w);
    height: 3px;
    background: var(--fog);
    transform-origin: left center;
  }

  .day-mark {
    top: calc(var(--above-h) - 3px);
    width: 7px;
    height: 7px;
    background: var(--sandstone);
  }

  .day-run {
    top: var(--above-h);
    width: var(--w);
    height: 0;
    border-top: 1px dotted var(--mist-on-tide);
    transform-origin: left center;
  }

  .day-label {
    position: absolute;
    left: var(--s);
    max-width: calc(var(--room) - 1rem);
  }

  .day-stop.is-above .day-label {
    bottom: calc(var(--below-h) + 1px + 1rem);
  }

  .day-stop.is-below .day-label {
    top: calc(var(--above-h) + 1px + 2.75rem);
  }

  /* A tick label is a box of no width on its hour, with its text centred on it (flex centring lets the
     text overflow evenly both ways), so it needs no transform. The first and last sit inside the line.
     A 1px by 0.5rem tick hangs from the axis above each label. The closing label is the same, with the
     outlined square at its hour; the generator leaves its text out when a tick label is that close. */

  .day-tick,
  .day-close {
    position: absolute;
    top: calc(var(--above-h) + 1px + 0.75rem);
    left: var(--s);
    display: flex;
    justify-content: center;
    width: 0;
    color: var(--mist-on-tide);
    font-size: 0.875rem;
    line-height: 1.55;
    white-space: nowrap;
  }

  .day-tick::before {
    content: "";
    position: absolute;
    top: calc(-0.75rem + 2px);
    left: 0;
    width: 1px;
    height: 0.5rem;
    background: var(--mist-on-tide);
  }

  .day-tick.tick-start {
    justify-content: flex-start;
  }

  .day-tick.tick-end {
    justify-content: flex-end;
  }

  .day-tick.tick-end::before {
    left: auto;
    right: 0;
  }

  .day-close::before {
    content: "";
    position: absolute;
    top: calc(-0.75rem - 4px);
    left: -3.5px;
    width: 7px;
    height: 7px;
    border: 1px solid var(--sandstone);
  }
}

/* Motion. The vertical timeline (under 1080px) draws like a plan's (see the timeline's motion below).
   From 1080px, at full motion, each span draws from its start in order, 120ms apart: a bar or a dotted
   run grows from its left edge (700ms), and its square and label fade in with it; the ticks fade in at
   the start and the closing square after the last span. The wrapper carries data-reveal="day". Calm:
   the wrapper fades as a whole (the generic reveal rule). */

@media (min-width: 1080px) {
  html.motion .day-home-body[data-reveal="day"] .day-bar,
  html.motion .day-home-body[data-reveal="day"] .day-run {
    transform: scaleX(0);
    transition: transform 700ms var(--ease-out) calc(200ms + var(--i, 0) * 120ms);
  }

  html.motion .day-home-body[data-reveal="day"].is-in .day-bar,
  html.motion .day-home-body[data-reveal="day"].is-in .day-run {
    transform: none;
  }

  html.motion .day-home-body[data-reveal="day"] .day-mark,
  html.motion .day-home-body[data-reveal="day"] .day-label,
  html.motion .day-home-body[data-reveal="day"] .day-close {
    opacity: 0;
    transition: opacity 700ms var(--ease-out) calc(200ms + var(--i, 0) * 120ms);
  }

  html.motion .day-home-body[data-reveal="day"] .day-tick {
    opacity: 0;
    transition: opacity 700ms var(--ease-out);
  }

  html.motion .day-home-body[data-reveal="day"].is-in .day-mark,
  html.motion .day-home-body[data-reveal="day"].is-in .day-label,
  html.motion .day-home-body[data-reveal="day"].is-in .day-close,
  html.motion .day-home-body[data-reveal="day"].is-in .day-tick {
    opacity: 1;
  }
}

/* The underline that draws on hover is kelp elsewhere; on the tide it is fog. */

@media (hover: hover) and (pointer: fine) {
  html.motion .day-home a:not(.btn)::before,
  html.motion .day-home a:not(.btn)::after {
    background: var(--fog);
  }
}

@media (max-width: 859px) {
  .day-home-guide,
  .day-home-link {
    margin-top: 0;
  }

  .day-home-body {
    margin-top: 0;
  }

  .day-home-link a {
    display: inline-flex;
    align-items: center;
    min-height: 2.75rem;
  }
}

/* Stagger for reveal groups */

.what-steps li:nth-child(2) { --d: 120ms; }
.what-steps li:nth-child(3) { --d: 240ms; }

.steps li:nth-child(2) { --d: 90ms; }
.steps li:nth-child(3) { --d: 180ms; }
.steps li:nth-child(4) { --d: 270ms; }
.steps li:nth-child(5) { --d: 360ms; }
.steps li:nth-child(6) { --d: 450ms; }

.request-form-wrap,
.form-wrap { --d: 140ms; }

.facts li:nth-child(2) { --d: 120ms; }
.facts li:nth-child(3) { --d: 240ms; }

/* Stagger for the arrange rows (names rise one after another). */

.arrange-row:nth-child(2) { --stagger: 90ms; }
.arrange-row:nth-child(3) { --stagger: 180ms; }
.arrange-row:nth-child(4) { --stagger: 270ms; }
.arrange-row:nth-child(5) { --stagger: 360ms; }

/* Motion. js/main.js sets one level class on <html>:
     html.motion        everything below
     html.motion-calm   opacity fades only: no transforms, no clip-path, no parallax
     html.motion-off    nothing animates
   Without a level class (no JavaScript) every element is fully visible and still. */

@keyframes hero-photo-settle {
  from { transform: scale(1.08); }
  to   { transform: scale(1); }
}

@keyframes hero-rise {
  from { opacity: 0; transform: translateY(18px); }
  to   { opacity: 1; transform: translateY(0); }
}

@keyframes hero-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes parallax-drift {
  from { transform: translateY(-6%); }
  to   { transform: translateY(6%); }
}

@keyframes still-drift {
  from { transform: scale(1); }
  to   { transform: scale(1.06); }
}

@keyframes menu-rise {
  from { opacity: 0; transform: translateY(18px); }
  to   { opacity: 1; transform: none; }
}

@keyframes name-rise {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* A video fades in over its poster the first time it plays (calm and full levels). */

html.motion .media-video,
html.motion-calm .media-video {
  transition: opacity 900ms var(--ease-out);
}

/* 1. Hero on load. The poster layer and the video settle together. */

html.entrance {
  --hero-delay: 900ms;
}

html.motion .hero-photo::before,
html.motion .hero-photo .media-video {
  animation: hero-photo-settle 2200ms var(--ease-soft) var(--hero-delay, 0ms) both;
}

html.motion .hero-text > * {
  animation: hero-rise 1100ms var(--ease-out) var(--hero-delay, 0ms) both;
}

html.motion .hero-text > :nth-child(2) { animation-delay: calc(var(--hero-delay, 0ms) + 140ms); }
html.motion .hero-text > :nth-child(3) { animation-delay: calc(var(--hero-delay, 0ms) + 260ms); }
html.motion .hero-text > :nth-child(4) { animation-delay: calc(var(--hero-delay, 0ms) + 360ms); }
html.motion .hero-text > :nth-child(5) { animation-delay: calc(var(--hero-delay, 0ms) + 460ms); }

/* 2. Text reveals */

html.motion [data-reveal=""] {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 900ms var(--ease-out) var(--d, 0ms), transform 900ms var(--ease-out) var(--d, 0ms);
}

html.motion [data-reveal=""].is-in {
  opacity: 1;
  transform: translateY(0);
}

/* 3. Image reveals */

/* The clip sits on the picture, not on the marked frame: IntersectionObserver applies a target's
   own clip-path, so a fully clipped frame would never report as visible. The picture is an img, or
   a video with the poster layer behind it. */

html.motion [data-reveal="image"] img,
html.motion [data-reveal="image"] .media-video,
html.motion [data-reveal="image"] .parallax::before {
  clip-path: inset(0 0 100% 0);
  transform: scale(1.12);
  transition: clip-path 1300ms var(--ease-soft), transform 1800ms var(--ease-soft);
}

html.motion [data-reveal="image"] .media-video {
  transition: clip-path 1300ms var(--ease-soft), transform 1800ms var(--ease-soft), opacity 900ms var(--ease-out);
}

html.motion [data-reveal="image"].is-in img,
html.motion [data-reveal="image"].is-in .media-video,
html.motion [data-reveal="image"].is-in .parallax::before {
  clip-path: inset(0);
  transform: scale(1);
}

/* 3b. Heading curtain. Starts clipped and a little low, then opens downward and settles.
   The end clip reaches past the box so descenders are never cut. */

html.motion [data-reveal="heading"] {
  clip-path: inset(0 0 100% 0);
  transform: translateY(0.35em);
  transition: clip-path 1100ms var(--ease-soft), transform 1100ms var(--ease-soft);
}

html.motion [data-reveal="heading"].is-in {
  clip-path: inset(-0.3em -0.1em -0.3em -0.1em);
  transform: translateY(0);
}

/* 4. Rules draw in */

html.motion [data-reveal="rule"]::before {
  transform: scaleX(0);
  transition: transform 1100ms var(--ease-out) var(--d, 0ms);
}

html.motion [data-reveal="rule"].is-in::before {
  transform: scaleX(1);
}

/* 5. Parallax, where the browser can tie it to scroll position */

@supports (animation-timeline: view()) {
  html.motion .parallax {
    animation: parallax-drift var(--ease-soft) both;
    animation-timeline: view();
  }
}

/* 6. Arrange rows: each name rises and fades in, one row after the next, on top of the hairline.
   The category name also eases right when a pointer rests on its row. */

html.motion .arrange-name {
  opacity: 0;
}

html.motion .arrange-row.is-in .arrange-name {
  opacity: 1;
  animation: name-rise 800ms var(--ease-out) var(--stagger, 0ms) backwards;
}

@media (hover: hover) and (pointer: fine) {
  html.motion .arrange-name {
    transition: transform 500ms var(--ease-out);
  }

  html.motion .arrange-row:hover .arrange-name {
    transform: translateX(0.5rem);
  }
}

/* 7. The logo in "The Standard, in brief" fades in and rises 12px in place (900ms). At the calm level
   the generic reveal rule fades it. */

html.motion [data-reveal="logo"] {
  opacity: 0;
  transform: translateY(12px);
  transition: opacity 900ms var(--ease-out), transform 900ms var(--ease-out);
}

html.motion [data-reveal="logo"].is-in {
  opacity: 1;
  transform: translateY(0);
}

/* 8. The entrance. js/main.js sets html.entrance on the first page of a visit, at full motion only.
   Every page carries the overlay, hidden until then. It is pure CSS from there: a fog field, the logo
   fading in (500ms), and then the field fades away and the overlay ends hidden, 1200ms in all. It
   never takes a click, and the page beneath is fully laid out throughout. The hero waits 900ms. */

@keyframes veil-away {
  0%, 75% { opacity: 1; visibility: visible; }
  100%    { opacity: 0; visibility: hidden; }
}

@keyframes logo-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

html.entrance .entrance-veil {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--fog);
  pointer-events: none;
  animation: veil-away 1200ms var(--ease-out) forwards;
}

.logo-veil {
  width: 8rem;
  height: 8rem;
}

html.entrance .logo-veil {
  animation: logo-in 500ms var(--ease-out) both;
}

/* 9. Body links draw their underline from the left on hover or keyboard focus. Fine pointers
   only. The resting underline moves from the browser's to a 1px line so the two can overlay. */

@media (hover: hover) and (pointer: fine) {
  html.motion main a:not(.btn) {
    position: relative;
    text-decoration: none;
  }

  html.motion main a:not(.btn)::before,
  html.motion main a:not(.btn)::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0.05em;
    height: 1px;
    background: var(--kelp);
    pointer-events: none;
  }

  html.motion main a:not(.btn)::before {
    opacity: 0.55;
  }

  html.motion main a:not(.btn)::after {
    transform: scaleX(0);
    transform-origin: left center;
    transition: transform 500ms var(--ease-out);
  }

  html.motion main a:not(.btn):hover::after,
  html.motion main a:not(.btn):focus-visible::after {
    transform: scaleX(1);
  }
}

/* 10. Still photos drift very slowly, only while their frame is in view (js/main.js toggles
   is-live) and only after the reveal has finished (1800ms, the length of its scale). */

html.motion [data-reveal="image"].is-in img {
  animation: still-drift 24s var(--ease-soft) 1800ms infinite alternate;
  animation-play-state: paused;
}

html.motion [data-reveal="image"].is-in.is-live img {
  animation-play-state: running;
}

/* 11. Experiences. Choosing draws the sandstone line in from the left and fades the seal in.
   A filter change fades the visible cells in (js/main.js adds is-refiltered). The selection bar
   slides up from the window's foot; visibility only switches after the slide has finished. */

@keyframes exp-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}

html.motion .exp::after {
  opacity: 1;
  transform: scaleX(0);
  transition: transform 500ms var(--ease-out);
}

html.motion .exp.is-chosen::after {
  transform: scaleX(1);
}

html.motion .exp.is-chosen .exp-body > .seal,
html.motion-calm .exp.is-chosen .exp-body > .seal {
  animation: exp-fade 400ms var(--ease-out) backwards;
}

html.motion .exp-group.is-refiltered,
html.motion .plan.is-refiltered {
  animation: exp-fade 400ms var(--ease-out) backwards;
}

/* The rows of a group rise 12px and fade in one after another (70ms apart) as the group comes into
   view, on top of the hairline draw. The calm level fades the whole row instead (reveal rules). */

html.motion .exp > * {
  opacity: 0;
}

html.motion .exp.is-in > * {
  opacity: 1;
  animation: name-rise 800ms var(--ease-out) var(--stagger, 0ms) backwards;
}

.exp:nth-child(2) { --stagger: 70ms; }
.exp:nth-child(3) { --stagger: 140ms; }
.exp:nth-child(4) { --stagger: 210ms; }
.exp:nth-child(5) { --stagger: 280ms; }
.exp:nth-child(6) { --stagger: 350ms; }
.exp:nth-child(n + 7) { --stagger: 420ms; }

/* A timeline's rows play in order; --row-i is a row's place in its list, and the motion below spaces
   the rows by it. */

.timeline > :nth-child(2) { --row-i: 1; }
.timeline > :nth-child(3) { --row-i: 2; }
.timeline > :nth-child(4) { --row-i: 3; }
.timeline > :nth-child(5) { --row-i: 4; }
.timeline > :nth-child(6) { --row-i: 5; }
.timeline > :nth-child(7) { --row-i: 6; }
.timeline > :nth-child(8) { --row-i: 7; }
.timeline > :nth-child(9) { --row-i: 8; }
.timeline > :nth-child(10) { --row-i: 9; }
.timeline > :nth-child(n + 11) { --row-i: 10; }

@media (hover: hover) and (pointer: fine) {
  html.motion .exp-name {
    transition: transform 500ms var(--ease-out);
  }

  html.motion .exp:hover .exp-name {
    transform: translateX(0.5rem);
  }
}

/* The plans. As a plan comes into view its timeline plays, on top of the hairline draw: the rows in
   order, 110ms apart. In each row the bar or dotted run grows down from the top (scaleY, 700ms
   --ease-soft), the square fades in, and the time and body fade in with a 10px rise. Choosing draws
   the sandstone line in from the left and fades the seal in. The home page's vertical timeline plays
   the same way when its wrapper comes into view. The draft on the Experiences page is not revealed by
   scrolling: it plays the same sequence every time it is redrawn, at half the durations (and, at the
   calm level, its rows only fade). At the calm level a plan fades as a whole (the reveal rule), so
   nothing in a timeline carries a transform. */

html.motion .plan::after {
  opacity: 1;
  transform: scaleX(0);
  transition: transform 500ms var(--ease-out);
}

html.motion .plan.is-chosen::after {
  transform: scaleX(1);
}

html.motion .plan.is-chosen .plan-head > .seal,
html.motion-calm .plan.is-chosen .plan-head > .seal {
  animation: exp-fade 400ms var(--ease-out) backwards;
}

@keyframes rail-draw {
  from { transform: scaleY(0); }
  to   { transform: none; }
}

@keyframes row-rise {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

html.motion :is(.plan, .day-home-body) .stop-rail::before {
  transform: scaleY(0);
}

html.motion :is(.plan, .day-home-body) .stop-rail::after,
html.motion :is(.plan, .day-home-body) :is(.stop-time, .stop-body) {
  opacity: 0;
}

html.motion :is(.plan, .day-home-body).is-in .stop-rail::before {
  transform: none;
  animation: rail-draw 700ms var(--ease-soft) calc(var(--row-i, 0) * 110ms) backwards;
}

html.motion :is(.plan, .day-home-body).is-in .stop-rail::after {
  opacity: 1;
  animation: exp-fade 500ms var(--ease-out) calc(var(--row-i, 0) * 110ms) backwards;
}

html.motion :is(.plan, .day-home-body).is-in :is(.stop-time, .stop-body) {
  opacity: 1;
  animation: row-rise 800ms var(--ease-out) calc(var(--row-i, 0) * 110ms) backwards;
}

html.motion .draft .stop-rail::before {
  animation: rail-draw 350ms var(--ease-soft) calc(var(--row-i, 0) * 55ms) backwards;
}

html.motion .draft .stop-rail::after {
  animation: exp-fade 250ms var(--ease-out) calc(var(--row-i, 0) * 55ms) backwards;
}

html.motion .draft :is(.stop-time, .stop-body) {
  animation: row-rise 400ms var(--ease-out) calc(var(--row-i, 0) * 55ms) backwards;
}

html.motion-calm .draft .timeline > li {
  animation: exp-fade 350ms var(--ease-out) backwards;
}

html.motion .sel-bar {
  transform: translateY(100%);
  transition: transform 500ms var(--ease-soft), visibility 0s var(--ease-soft) 500ms;
}

html.motion .sel-bar.is-shown {
  transform: none;
  transition: transform 500ms var(--ease-soft), visibility 0s var(--ease-soft) 0s;
}

/* Calm level: opacity cross-fades only. No transform, no clip-path, no parallax, no drift,
   no sweep, no stagger longer than 60ms. */

html.motion-calm [data-reveal] {
  opacity: 0;
  transition: opacity 700ms var(--ease-out) min(var(--d, 0ms), 60ms);
}

html.motion-calm [data-reveal].is-in {
  opacity: 1;
}

html.motion-calm .hero-photo,
html.motion-calm .hero-text > * {
  animation: hero-fade 700ms var(--ease-out) both;
}

html.motion-calm .hero-text > :nth-child(n + 2) {
  animation-delay: 60ms;
}

/* The button sweep and the field's focus line rest off-screen or at zero width under a transform.
   Below full motion they are plain colour and opacity changes, so nothing carries a transform. */

html.motion-calm .btn::before,
html.motion-off .btn::before,
html.motion-calm .control::after,
html.motion-off .control::after {
  transform: none;
  opacity: 0;
}

html.motion-calm .btn:hover::before,
html.motion-off .btn:hover::before,
html.motion-calm .control:focus-within::after,
html.motion-off .control:focus-within::after {
  opacity: 1;
}

html.motion-calm .exp::after,
html.motion-calm .plan::after {
  transition: opacity 700ms var(--ease-out);
}

html.motion-calm .sel-bar {
  opacity: 0;
  transition: opacity 700ms var(--ease-out), visibility 0s var(--ease-out) 700ms;
}

html.motion-calm .sel-bar.is-shown {
  opacity: 1;
  transition: opacity 700ms var(--ease-out), visibility 0s var(--ease-out) 0s;
}

/* Page transitions. They only run when the site is hosted, and never with reduced motion.
   Turning motion off in the footer also turns them off. */

@media (prefers-reduced-motion: no-preference) {
  @view-transition {
    navigation: auto;
  }

  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation-duration: 400ms;
    animation-timing-function: var(--ease-out);
  }
}

html.motion-off::view-transition-old(root),
html.motion-off::view-transition-new(root) {
  animation-duration: 0s;
}

/* Single column under 860px */

@media (max-width: 859px) {
  .hero {
    display: flex;
    flex-direction: column;
    min-height: 0;
  }

  .hero-photo {
    order: -1;
    height: 33vh;
    height: 33svh;
  }

  .hero-text {
    padding-top: 3rem;
    padding-bottom: 4.5rem;
    padding-left: var(--gutter);
    padding-right: var(--gutter);
  }

  .grid {
    row-gap: 2.5rem;
  }

  .grid > * {
    grid-column: 1 / -1;
  }

  .what-steps {
    grid-template-columns: minmax(0, 1fr);
    row-gap: 2rem;
    margin-top: 1rem;
  }

  .page-open-text .page-open-copy {
    grid-column: 1 / -1;
  }

  .arrange-head,
  .beliefs-head,
  .discretion-head,
  .check-head,
  .process-head,
  .how-head,
  .reset-photo {
    position: static;
  }

  .facts {
    grid-template-columns: minmax(0, 1fr);
    row-gap: 2rem;
  }

  .entry {
    display: block;
  }

  .entry > * + * {
    margin-top: 0.25rem;
  }

  /* The name sits after its small seal, so the area and the reason take the same inset: one left edge. */

  .entry > .entry-place,
  .entry > .entry-reason {
    padding-left: 2.25rem;
  }

  .arrange-row {
    grid-template-columns: minmax(0, 1fr);
    row-gap: 0.5rem;
  }

  .brief .grid {
    row-gap: 2rem;
  }

  .request {
    display: block;
  }

  .request-photo {
    aspect-ratio: 4 / 3;
  }

  .request-panel {
    padding-left: var(--gutter);
    padding-right: var(--gutter);
  }

  .footer-row {
    flex-direction: column;
    gap: 1.75rem;
  }

  /* Touch targets: every link and control is at least 44px tall. */

  .hero-actions a:not(.btn),
  .brief-link a,
  .how-link a,
  .footer-nav a,
  .motion-toggle {
    display: inline-flex;
    align-items: center;
    min-height: 2.75rem;
  }

  .arrange-after a,
  .providers-line a {
    display: flex;
    align-items: center;
    width: fit-content;
    min-height: 2.75rem;
  }

  /* The line above the footer holds two sentences, each ending in a link, so its links stay in the text. */

  .not-listed a {
    display: inline-flex;
    align-items: center;
    min-height: 2.75rem;
  }

  .arrange-after a + a {
    margin-left: 0;
  }

  .footer-nav li + li {
    margin-top: 0;
  }

  .btn {
    min-height: 2.75rem;
  }
}

/* The Menu panel. Five links, the wordmark and the request button need about 1000px of content
   (1080px with the wider spacing from 1240px), so the links collapse behind the Menu button under
   1140px. The single-column layout above stays at 860px. */

@media (max-width: 71.1875em) {
  .header-nav a {
    display: inline-flex;
    align-items: center;
    min-height: 2.75rem;
  }

  .header-row .wordmark {
    min-height: 2.75rem;
  }

  /* Without JavaScript the links wrap in a row under the wordmark. */

  html:not(.js) .header-row {
    flex-wrap: wrap;
    row-gap: 0.25rem;
  }

  html:not(.js) .header-menu {
    flex: 1 1 100%;
    flex-wrap: wrap;
    justify-content: flex-start;
    gap: 0 1.5rem;
    padding-bottom: 0.75rem;
  }

  html:not(.js) .header-nav ul {
    flex-wrap: wrap;
    gap: 0 1.5rem;
  }

  html.js .menu-btn {
    display: inline-flex;
  }

  /* With JavaScript the links sit behind a Menu button and open as a full-screen fog panel. */

  html.js .header-menu {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 1;
    flex-direction: column;
    flex-wrap: nowrap;
    align-items: flex-start;
    justify-content: flex-start;
    gap: 0;
    padding: calc(var(--header-h) + 1rem) var(--gutter) 2rem;
    overflow-y: auto;
    background: var(--fog);
  }

  html.js .site-header.menu-open .header-menu {
    display: flex;
  }

  html.js .header-nav ul {
    flex-direction: column;
    gap: 0.25rem;
  }

  html.js .header-nav a {
    display: block;
    min-height: 0;
    padding-top: 0.3rem;
    padding-bottom: 0.3rem;
    font-family: var(--display);
    font-size: clamp(2rem, 9vw, 3rem);
    line-height: 1.2;
    text-decoration: none;
  }

  html.js .header-menu .btn {
    margin-top: 2.5rem;
    padding: 0.95rem 1.6rem;
  }

  html.js .menu-note {
    display: block;
    margin-top: auto;
    padding-top: 2rem;
    color: var(--kelp);
  }

  html.motion .site-header.menu-open .header-nav li,
  html.motion .site-header.menu-open .header-menu .btn,
  html.motion .site-header.menu-open .menu-note {
    animation: menu-rise 700ms var(--ease-out) backwards;
  }

  html.motion .site-header.menu-open .header-nav li:nth-child(2) { animation-delay: 80ms; }
  html.motion .site-header.menu-open .header-nav li:nth-child(3) { animation-delay: 160ms; }
  html.motion .site-header.menu-open .header-nav li:nth-child(4) { animation-delay: 240ms; }
  html.motion .site-header.menu-open .header-nav li:nth-child(5) { animation-delay: 320ms; }
  html.motion .site-header.menu-open .header-menu .btn { animation-delay: 400ms; }
  html.motion .site-header.menu-open .menu-note { animation-delay: 480ms; }
}

@media (max-width: 26.25em) {
  .header-row {
    gap: 1rem;
  }

  .wordmark {
    gap: 0.65rem;
  }

  .wordmark .logo-mark {
    width: 2.5rem;
    height: 2.5rem;
  }

  .wordmark-name {
    margin-right: -0.22em;
    font-size: 0.8125rem;
    letter-spacing: 0.22em;
  }
}
