/*
 * Anti Hair Salon: the public site, and the tokens the admin area builds on.
 *
 * The page is complete without this file. Everything here is presentation
 * over markup whose order, headings and words do not depend on it.
 *
 * The palette is the salon's own room (session 18): cream walls, walnut
 * panelling, black chairs with brass arms. Cream is the page; night is only
 * the hero and the footer; walnut appears once, behind the closing Book.
 * Brass is the Book button's alone. The logo's teal is in the diamond and
 * nowhere else: no green surface, wash or gradient exists on the site.
 *
 * bin/make-favicons.php reads --diamond-deep and --diamond-light from this
 * file and writes the favicons from them. bin/check-environment.php fails the
 * deploy when the two disagree.
 */

/* Each font is cut to the weights and characters the site uses and served
   from this origin: no request leaves for a font service. Cormorant is one
   weight, 500; Inter runs from 400 to 700, the admin area's heaviest;
   Shippori Mincho carries only the Japanese words at the turns of the page.
   A new weight or a new Japanese word needs the fonts cut again
   (docs/fonts.md). */
@font-face {
  font-family: "Cormorant";
  src: url("../fonts/cormorant/cormorant-garamond.woff2?v=5") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Inter";
  src: url("../fonts/inter/inter.woff2?v=5") format("woff2");
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Shippori Mincho";
  src: url("../fonts/shippori-mincho/shippori-mincho.woff2?v=6") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

:root {
  /* The room. */
  --paper: #f6f1e9;
  --linen: #ece4d6;
  --ink: #1c1a16;
  --ink-2: #4a443c;
  --ink-3: #6b6358;
  --night: #15120e;
  --night-2: #241e18;
  --mist: #bdb3a3;
  --walnut: #5e3a22;
  /* Brass for rules and marks; brass-text where it must be read on paper
     (5.1:1); brass-light is the Book button. */
  --brass: #b8913f;
  --brass-text: #80621f;
  --brass-light: #d4b46a;
  --danger: #8a2a1f;
  /* The rail lines' own colours, for the station badges alone (run 35). */
  --line-bts-silom: #007e43;
  --line-mrt-blue: #1f4e9d;
  --line: rgb(28 26 22 / 0.12);
  --line-strong: rgb(28 26 22 / 0.28);
  --line-night: rgb(246 241 233 / 0.18);

  /* The logo diamond, and only the diamond. */
  --diamond-deep: #1e7266;
  --diamond-mid: #6fbfb2;
  --diamond-light: #c8e6e2;
  --diamond: linear-gradient(90deg, var(--diamond-mid) 38%, var(--diamond-light) 67%, #fff);

  --font-display: "Cormorant", "Cormorant Garamond", "Times New Roman", serif;
  --font-body: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-ja: "Shippori Mincho", "Hiragino Mincho ProN", "Yu Mincho", serif;

  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --gutter: clamp(20px, 5vw, 72px);
  --section: clamp(96px, 14vw, 200px);
  --container: 1240px;
  --width: min(calc(100% - 2 * var(--gutter)), var(--container));

  /* Surfaces on paper. The console no longer reads this file (decision
     0032), so the aliases it once took from here are gone. */
  --surface: rgb(255 253 249 / 0.7);
  --surface-strong: #fffdf9;
}

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

/* Hidden means hidden, whatever a class sets display to (session 31): a
   class such as .button or .booking__field otherwise outranks the hidden
   attribute, and controls meant to wait for their script showed without
   it, "Forget my details" among them. */
[hidden] {
  display: none !important;
}

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100vh;
  font: 400 1.0625rem/1.65 var(--font-body);
  color: var(--ink);
  background: var(--paper);
  font-synthesis: none;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: clip;
}

img {
  display: block;
  max-width: 100%;
  height: auto;
}

picture {
  display: block;
}

/* Brass is Book's alone (decision 0017): a link is underlined in ink. */
a {
  color: var(--ink);
  text-decoration-color: var(--line-strong);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.24em;
  transition: text-decoration-color 0.2s var(--ease), color 0.2s var(--ease);
}

a:hover {
  text-decoration-color: currentColor;
}

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

h1,
h2,
h3,
h4 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 500;
  line-height: 1.1;
  letter-spacing: -0.01em;
  text-wrap: balance;
}

p {
  margin: 0 0 1em;
}

address {
  font-style: normal;
}

figure {
  margin: 0;
}

[id] {
  scroll-margin-top: 24px;
}

.visually-hidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.sprite {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

.wrap {
  width: var(--width);
  margin-inline: auto;
}

/* ---------------------------------------------------------------------------
   Buttons. Book is brass and the most prominent thing wherever it appears;
   nothing else is brass. Every button is at least 48px tall.
   ------------------------------------------------------------------------ */

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  min-height: 48px;
  padding: 0 26px;
  border: 1px solid var(--ink);
  border-radius: 2px;
  font: 600 1rem/1.2 var(--font-body);
  letter-spacing: 0.04em;
  color: var(--ink);
  text-align: center;
  text-decoration: none;
  background: transparent;
  cursor: pointer;
  transition: background-color 0.2s var(--ease), border-color 0.2s var(--ease), color 0.2s var(--ease);
}

.button:hover {
  color: var(--paper);
  background: var(--ink);
}

.button--primary {
  color: var(--paper);
  background: var(--ink);
}

.button--primary:hover {
  background: var(--night-2);
}

.button--book {
  border-color: var(--brass-light);
  color: var(--night);
  background: var(--brass-light);
}

.button--book:hover {
  border-color: #e2c783;
  color: var(--night);
  background: #e2c783;
}

/* On night: an outline in paper. */
.button--light {
  border-color: rgb(246 241 233 / 0.55);
  color: var(--paper);
}

.button--light:hover {
  border-color: var(--paper);
  color: var(--night);
  background: var(--paper);
}

/* The diamond in a button, as a mark; never teal, which is the logo's. */
.button__mark {
  flex: none;
  width: 7px;
  height: 7px;
  background: currentColor;
  transform: rotate(45deg);
}

.card {
  padding: 22px;
  border: 1px solid var(--line);
  border-radius: 2px;
  background: var(--surface-strong);
}

/* The small diamond of the logo, as separator and list marker. */
.diamond {
  display: inline-block;
  width: 8px;
  height: 8px;
  background: var(--diamond);
  outline: 1px solid var(--diamond-deep);
  outline-offset: -1px;
  transform: rotate(45deg);
}

/* ---------------------------------------------------------------------------
   The wordmark, on pages other than the home page.
   ------------------------------------------------------------------------ */

.wordmark {
  display: block;
  width: 88px;
  height: auto;
}

.wordmark__letters {
  fill: var(--ink);
}

.wordmark__diamond {
  fill: var(--diamond-deep);
}

.site-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  width: var(--width);
  margin-inline: auto;
  padding: 20px 0;
  border-bottom: 1px solid var(--line);
}

.site-header__home {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

.site-header__links {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 28px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.site-header__links a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-size: 0.9375rem;
  text-decoration: none;
}

/* On the home page the header lies over the photograph: the in-page links
   on a wide screen, and Menu, to the footer's list of them, on a phone. */
.site-header--home {
  position: absolute;
  z-index: 3;
  inset: 0 0 auto;
  justify-content: flex-end;
  column-gap: 28px;
  width: auto;
  padding: 22px var(--gutter);
  border: 0;
}

.site-header--home a {
  color: var(--paper);
}

.site-header--home .site-header__nav {
  display: none;
}

/* "My booking": opposite the wordmark, or over the photograph beside the
   in-page links and Menu (2026-10-05). */
.site-header__booking {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-size: 0.9375rem;
  text-decoration: none;
}

.site-header__menu {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-size: 0.9375rem;
  text-decoration: none;
}

@media (min-width: 900px) {
  .site-header--home {
    padding-top: 36px;
  }

  .site-header--home .site-header__nav {
    display: block;
  }

  .site-header__menu {
    display: none;
  }
}

/* ---------------------------------------------------------------------------
   The hero. The photograph is the whole screen; the scrim darkens only where
   the words are, measured against the brightest pixel under every line at
   360, 390 and 1440 wide (session 18, all 7:1 or better).
   ------------------------------------------------------------------------ */

.hero {
  position: relative;
  display: grid;
  min-height: max(560px, 100svh);
  overflow: hidden;
  color: var(--paper);
  background: var(--night);
}

.hero__media,
.hero__media picture,
.hero__media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.hero__media img {
  object-fit: cover;
}

.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(180deg, rgb(21 18 14 / 0.94) 0, rgb(21 18 14 / 0.9) 50%, rgb(21 18 14 / 0.55) 62%, rgb(21 18 14 / 0) 76%);
}

.hero__brand {
  position: absolute;
  z-index: 2;
  top: 22px;
  left: var(--gutter);
  margin: 0;
  line-height: 0;
}

.hero__lockup {
  display: block;
  width: 112px;
  height: auto;
  color: var(--paper);
}

.hero__body {
  position: relative;
  z-index: 2;
  align-self: start;
  display: grid;
  justify-items: start;
  gap: 20px;
  max-width: 760px;
  padding: 132px var(--gutter) 0;
}

.hero__line {
  margin: 0;
  font: 500 clamp(2.15rem, 1.4rem + 3.4vw, 4.4rem)/1.06 var(--font-display);
  letter-spacing: -0.012em;
  text-wrap: balance;
}

.hero__actions {
  display: grid;
  gap: 12px;
  width: 100%;
}

.hero__where {
  margin: 0;
  font-size: 0.875rem;
  color: var(--mist);
  text-wrap: balance;
}

@media (min-width: 900px) {
  .hero::after {
    background:
      linear-gradient(180deg, rgb(21 18 14 / 0.9) 0, rgb(21 18 14 / 0.84) 19%, rgb(21 18 14 / 0) 32%),
      linear-gradient(90deg, rgb(21 18 14 / 0.95) 0, rgb(21 18 14 / 0.9) 42%, rgb(21 18 14 / 0.3) 58%, rgb(21 18 14 / 0) 70%),
      linear-gradient(180deg, rgb(21 18 14 / 0) 60%, rgb(21 18 14 / 0.6) 100%);
  }

  .hero__brand {
    top: 36px;
  }

  .hero__lockup {
    width: 150px;
  }

  .hero__body {
    align-self: end;
    gap: 28px;
    padding: 0 var(--gutter) 72px;
  }

  .hero__actions {
    display: flex;
    align-items: center;
    gap: 18px;
    width: auto;
  }

  /* Directly under the line, and larger than anything else that acts. */
  .hero__actions .button--book {
    min-height: 64px;
    padding: 0 52px;
    font-size: 1.125rem;
  }
}

.hero :focus-visible,
.footer :focus-visible,
.closing :focus-visible {
  outline-color: var(--brass-light);
}

/* ---------------------------------------------------------------------------
   Below the hero (session 29, direction B): bands of paper, walnut, night
   and linen, like the room; turns centred like an apothecary's label; and a
   frame of two hairlines where a label is meant. Nothing moves.
   ------------------------------------------------------------------------ */

.band {
  padding-block: clamp(72px, 11vw, 144px);
}

.band--walnut {
  color: var(--paper);
  background: var(--walnut);
}

.band--night {
  color: var(--paper);
  background: var(--night-2);
}

.band--linen {
  background: var(--linen);
}

/* Paper after paper keeps a hairline between, so a band still reads as one. */
.band:not(.band--walnut, .band--night, .band--linen) + .band:not(.band--walnut, .band--night, .band--linen) {
  border-top: 1px solid var(--line);
}

.band--walnut a:not(.button),
.band--night a:not(.button) {
  color: var(--paper);
  text-decoration-color: rgb(246 241 233 / 0.5);
}

.band--walnut :focus-visible,
.band--night :focus-visible {
  outline-color: var(--paper);
}

/* The turn: the Japanese word, the eyebrow, the heading, a short rule. */
.turn {
  display: grid;
  justify-items: center;
  text-align: center;
}

.turn__ja {
  margin: 0 0 12px;
  font: 400 clamp(0.95rem, 0.9rem + 0.3vw, 1.15rem)/1 var(--font-ja);
  letter-spacing: 0.4em;
  /* The letter spacing trails the last character: pull it back to centre. */
  margin-right: -0.4em;
  color: var(--ink-2);
}

.eyebrow {
  margin: 0;
  font: 600 0.75rem/1.3 var(--font-body);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.turn h2 {
  max-width: 18ch;
  margin-top: 14px;
  font-size: clamp(2.1rem, 1.5rem + 2.6vw, 3.6rem);
  line-height: 1.08;
}

.turn__rule {
  display: block;
  width: 40px;
  height: 1px;
  margin-top: 22px;
  background: currentColor;
  opacity: 0.35;
}

.turn__lede {
  max-width: 44ch;
  margin: 22px 0 0;
  color: var(--ink-2);
}

.band--walnut .turn__ja,
.band--night .turn__ja,
.band--walnut .eyebrow,
.band--night .eyebrow {
  color: var(--mist);
}

.band--walnut .turn__lede,
.band--night .turn__lede {
  color: var(--linen);
}

/* A label: two hairlines, the inner one set in. */
.label {
  padding: clamp(24px, 4vw, 40px) clamp(18px, 3vw, 36px);
  border: 1px solid currentColor;
  outline: 1px solid currentColor;
  outline-offset: 5px;
  margin: 6px;
}

/* ---------------------------------------------------------------- promises */

.promises__title {
  margin-bottom: clamp(24px, 4vw, 40px);
  text-align: center;
  color: var(--mist);
}

.promises__list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1px;
  margin: 0;
  padding: 0;
  border: 1px solid rgb(246 241 233 / 0.22);
  background: rgb(246 241 233 / 0.22);
  list-style: none;
}

.promises__item {
  padding: clamp(22px, 3vw, 36px) clamp(12px, 2vw, 28px);
  text-align: center;
  background: var(--walnut);
}

.promises__icon {
  width: 26px;
  height: 26px;
  margin: 0 auto 14px;
  color: var(--paper);
  stroke-width: 1.4;
  opacity: 0.9;
}

.promises__name {
  margin: 0 0 8px;
  font-size: clamp(1.15rem, 1rem + 0.6vw, 1.45rem);
  line-height: 1.2;
}

.promises__text {
  margin: 0;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--linen);
}

@media (min-width: 900px) {
  .promises__list {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

/* ---------------------------------------------------- services as tiles */

.tiles {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  margin: clamp(40px, 6vw, 64px) 0 0;
  padding: 0;
  list-style: none;
}

/* Type on paper inside a label's two hairlines, until the work photographs
   exist (run 20, Q11). */
.tile {
  display: grid;
  align-content: center;
  justify-items: center;
  gap: 6px;
  min-height: 168px;
  height: 100%;
  padding: 22px 10px;
  border: 1px solid var(--line-strong);
  outline: 1px solid var(--line-strong);
  outline-offset: -6px;
  text-align: center;
  text-decoration: none;
  background: var(--surface-strong);
  transition: border-color 0.2s var(--ease), outline-color 0.2s var(--ease);
}

.tile:hover {
  border-color: var(--ink);
  outline-color: var(--ink);
}

.tile__name {
  font: 500 clamp(1.25rem, 1.05rem + 0.8vw, 1.7rem)/1.15 var(--font-display);
  text-wrap: balance;
}

.tile__from {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-3);
  font-variant-numeric: lining-nums;
}

.tile__go {
  margin-top: 6px;
  font-size: 0.875rem;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.3em;
}

@media (min-width: 900px) {
  .tiles {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 16px;
  }

  .tile {
    min-height: 200px;
  }
}

.services__body {
  margin-top: clamp(56px, 8vw, 96px);
}

.services__heading {
  margin: 0 0 20px;
  font-size: clamp(1.6rem, 1.3rem + 1.2vw, 2.2rem);
  text-align: center;
}

/* The chooser is three equal buttons the width of a phone, held at the top
   of the screen while the prices scroll under it. */
.price-chooser {
  position: sticky;
  z-index: 2;
  top: 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  margin: 0 auto 28px;
  padding: 12px 0;
  border: 0;
  background: var(--paper);
}

.price-chooser__legend {
  float: left;
  grid-column: 1 / -1;
  width: 100%;
  margin: 0 0 10px;
  padding: 0;
  font: 600 0.75rem/1.3 var(--font-body);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  text-align: center;
  color: var(--ink-3);
}

.price-chooser__input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.price-chooser__option {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  border: 1px solid var(--line-strong);
  font-weight: 600;
  cursor: pointer;
}

.price-chooser__option + .price-chooser__input + .price-chooser__option {
  border-left: 0;
}

.price-chooser__input:checked + .price-chooser__option {
  border-color: var(--ink);
  color: var(--paper);
  background: var(--ink);
}

.price-chooser__input:focus-visible + .price-chooser__option {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}

@media (min-width: 700px) {
  .price-chooser {
    grid-template-columns: repeat(3, 160px);
    justify-content: center;
  }
}

.services__list {
  display: grid;
  gap: clamp(40px, 6vw, 64px);
}

/* Two categories side by side on a wide screen, so a price is never far
   from its name. */
@media (min-width: 1100px) {
  .services__list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: 80px;
    align-items: start;
  }
}

.price-card {
  min-width: 0;
  scroll-margin-top: 96px;
}

.price-card__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px 24px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--ink);
}

.price-card__title {
  font-size: clamp(1.6rem, 1.35rem + 1vw, 2.2rem);
}

/* Book beside every category, smaller than the hero's and still brass. */
.price-card__book {
  min-height: 44px;
  padding: 0 18px;
  font-size: 0.9375rem;
}

.price-table {
  width: 100%;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
}

.price-table th,
.price-table td {
  padding: 14px 0;
  border-bottom: 1px solid var(--line);
  text-align: left;
  vertical-align: top;
}

.price-table thead th {
  padding-top: 12px;
  padding-bottom: 8px;
  font: 600 0.75rem/1.3 var(--font-body);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.price-table tbody th {
  padding-right: 16px;
  font-weight: 500;
}

/* A range may break after its diamond on a narrow screen; the low figure
   and the diamond stay together (.price-low). */
.price-table td[data-variant] {
  padding-left: 12px;
  text-align: right;
}

.price-table thead th[data-variant] {
  padding-left: 12px;
  text-align: right;
}

.price-table__note td {
  padding-top: 0;
  font-size: 0.9375rem;
  color: var(--ink-2);
}

.price-table tr:has(+ .price-table__note) > * {
  border-bottom: 0;
}

.price-low {
  white-space: nowrap;
}

/* The range dash, drawn as the diamond; it stays text without CSS. */
.range-sep {
  display: inline-block;
  width: 6px;
  height: 6px;
  margin: 0 6px 0.2em;
  overflow: hidden;
  color: transparent;
  vertical-align: middle;
  background: var(--diamond-deep);
  transform: rotate(45deg);
}

.services:has(#price-view-men:checked) [data-variant="women"],
.services:has(#price-view-women:checked) [data-variant="men"] {
  display: none;
}

.services:has(#price-view-men:checked) .price-card:not([data-variants~="men"]),
.services:has(#price-view-women:checked) .price-card:not([data-variants~="women"]) {
  display: none;
}

/* When only one column is left the figures are the row's, beside its name. */
.services:has(#price-view-men:checked, #price-view-women:checked) thead {
  display: none;
}

.services__note {
  max-width: 52ch;
  margin: 28px auto 0;
  font-size: 0.9375rem;
  text-align: center;
  color: var(--ink-2);
}

/* ------------------------------------------------------------- Khun Nuch */

.nuch__grid {
  display: grid;
  gap: clamp(28px, 5vw, 72px);
  align-items: center;
}

.nuch__photo img {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  object-position: 50% 30%;
}

.nuch__text {
  display: grid;
  justify-items: center;
  gap: 14px;
  text-align: center;
}

.nuch__text p {
  margin: 0;
}

.nuch__text h2 {
  max-width: 16ch;
  font-size: clamp(1.9rem, 1.4rem + 2vw, 3rem);
}

.nuch__text .turn__ja,
.nuch__text .eyebrow {
  color: var(--mist);
}

.nuch__text .turn__ja {
  margin-bottom: -6px;
}

.nuch__name {
  font: 500 clamp(1.3rem, 1.15rem + 0.6vw, 1.6rem)/1.2 var(--font-display);
}

.nuch__fact,
.nuch__bio {
  max-width: 40ch;
  color: var(--linen);
}

@media (min-width: 900px) {
  .nuch__grid {
    grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
  }

  .nuch__photo img {
    aspect-ratio: 4 / 5;
  }
}

/* -------------------------------------------------------------- the salon */

.salon__photos {
  display: grid;
  gap: clamp(28px, 4vw, 48px);
  margin-top: clamp(40px, 6vw, 64px);
}

.salon__photo img {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
}

.salon__photo figcaption {
  margin-top: 14px;
  font: 500 1.25rem/1.3 var(--font-display);
  text-align: center;
}

@media (min-width: 900px) {
  .salon__photos {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* ------------------------------------------------------------ the systems */

.systems__list {
  display: grid;
  gap: 10px;
  max-width: 760px;
  margin: clamp(40px, 6vw, 64px) auto 0;
  padding: 0;
  list-style: none;
}

.systems__item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  gap: 4px 16px;
  padding: 16px 18px;
  border: 1px solid var(--line-strong);
}

.systems__name {
  font-size: clamp(1.3rem, 1.15rem + 0.7vw, 1.75rem);
}

.systems__origin {
  margin: 0;
  font: 600 0.6875rem/1.3 var(--font-body);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.systems__text {
  grid-column: 1 / -1;
  max-width: 52ch;
  margin: 0;
  color: var(--ink-2);
}

/* ---------------------------------------------------------------- reviews */

.reviews__body {
  display: grid;
  justify-items: center;
  margin-top: clamp(24px, 4vw, 40px);
  text-align: center;
}

.reviews__rating {
  margin: 0;
  font: 500 clamp(4.5rem, 3rem + 6vw, 8rem)/0.9 var(--font-display);
  font-variant-numeric: lining-nums;
}

.reviews__count {
  max-width: 28ch;
  margin: 14px 0 0;
  color: var(--ink-2);
}

.reviews__link {
  margin: 28px 0 0;
}

/* ------------------------------------------------------------- membership */

.membership__body {
  display: grid;
  justify-items: center;
  margin-top: 24px;
  text-align: center;
}

.membership__body p {
  max-width: 44ch;
  margin: 0 0 8px;
  color: var(--linen);
}

.membership__body p:last-child {
  margin: 20px 0 0;
}

/* ---------------------------------------------------------------- find us */

.find__grid {
  display: grid;
  gap: clamp(32px, 5vw, 64px);
  margin-top: clamp(40px, 6vw, 64px);
}

/* The address, the hours and how to reach the salon, as one framed table. */
.facts {
  display: grid;
  gap: 1px;
  margin: 0 0 28px;
  border: 1px solid var(--line-strong);
  background: var(--line-strong);
}

.facts > div {
  padding: 16px 18px;
  background: var(--paper);
}

.facts > div > dt {
  margin: 0 0 6px;
  font: 600 0.6875rem/1.3 var(--font-body);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.facts > div > dd {
  margin: 0;
}

.find__address {
  font: 500 1.25rem/1.35 var(--font-display);
  font-variant-numeric: lining-nums;
}

.find__route p {
  max-width: 60ch;
  color: var(--ink-2);
}

.find__steps {
  margin: 0 0 24px;
  padding-left: 1.4em;
}

.find__steps li + li {
  margin-top: 8px;
}

.find__side {
  display: grid;
  gap: 24px;
  align-content: start;
}

.find__plan img {
  width: 100%;
  max-width: 520px;
  height: auto;
  border: 1px solid var(--line);
  background: #fffdf9;
}

.hours {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 6px 24px;
  margin: 0;
  font-variant-numeric: tabular-nums;
}

.hours dt {
  color: var(--ink-2);
}

.hours dd {
  grid-column: 2;
  margin: 0;
}

.find__contact p {
  margin: 0;
}

.find__contact a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

/* The map is a link until it is asked for; landing.js swaps it for Google's
   frame only on a press. */
.map {
  display: grid;
  gap: 14px;
  justify-items: start;
  padding: 24px;
  border: 1px solid var(--line-strong);
  background: var(--linen);
}

.map p {
  max-width: 52ch;
  margin: 0;
  font-size: 0.9375rem;
  color: var(--ink-2);
}

.map__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

.map__frame {
  width: 100%;
  height: 420px;
  border: 0;
  background: var(--paper);
}

@media (min-width: 900px) {
  .find__grid {
    grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  }

  .find__map {
    grid-column: 1 / -1;
  }
}

/* -------------------------------------------------------------- questions */

.faq__list {
  max-width: 780px;
  margin: clamp(32px, 5vw, 56px) auto 0;
  border-top: 1px solid var(--line);
}

.faq__item {
  border-bottom: 1px solid var(--line);
}

.faq__question {
  display: flex;
  align-items: center;
  gap: 16px;
  min-height: 64px;
  padding: 12px 0;
  font: 500 clamp(1.25rem, 1.1rem + 0.6vw, 1.55rem)/1.25 var(--font-display);
  list-style: none;
  cursor: pointer;
}

.faq__question::-webkit-details-marker {
  display: none;
}

.faq__question::before {
  content: "";
  flex: none;
  width: 8px;
  height: 8px;
  border: 1px solid var(--ink-3);
  transform: rotate(45deg);
}

.faq__item[open] .faq__question::before {
  background: var(--ink);
  border-color: var(--ink);
}

.faq__answer {
  max-width: 62ch;
  margin: 0;
  padding: 0 0 24px 24px;
  color: var(--ink-2);
}

/* --------------------------------------------------------- the closing Book */

.closing__body {
  display: grid;
  justify-items: center;
  margin-top: 24px;
  text-align: center;
}

.closing__text {
  max-width: 44ch;
  margin: 0 0 32px;
  color: var(--linen);
}

.closing__actions {
  display: grid;
  gap: 12px;
  width: min(100%, 420px);
}

.closing__actions .button--book {
  min-height: 60px;
  font-size: 1.0625rem;
}

/* ---------------------------------------------------------------------------
   Footer, on night.
   ------------------------------------------------------------------------ */

.footer {
  padding: clamp(72px, 10vw, 120px) 0 clamp(96px, 12vw, 120px);
  font-size: 0.9375rem;
  color: var(--mist);
  background: var(--night);
}

.footer--after-closing {
  margin-top: 0;
}

.site-main:not(.site-main--home) + .footer {
  margin-top: var(--section);
}

.footer__inner {
  display: grid;
  gap: 40px;
}

.footer__lockup {
  width: 120px;
  height: auto;
  color: var(--paper);
}

.footer a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--paper);
  text-decoration-color: rgb(246 241 233 / 0.4);
}

.footer p {
  margin: 0;
}

.footer__title {
  margin: 0 0 8px;
  font: 600 0.75rem/1.3 var(--font-body);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--mist);
}

/* The schematic's own date, under the plan (run 33). */
.find__updated {
  margin: 8px 0 0;
  font-size: 0.8125rem;
  color: var(--ink-3);
}

/* The release, small, at the foot of every page (run 33). */
.footer__version {
  max-width: var(--container);
  margin: 32px auto 0;
  padding: 0 var(--gutter);
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  color: var(--mist);
}

.footer__links {
  margin: 0;
  padding: 0;
  list-style: none;
}

@media (min-width: 900px) {
  .footer__inner {
    grid-template-columns: minmax(0, 1fr) repeat(3, minmax(0, 1fr));
  }
}

/* ---------------------------------------------------------------------------
   Book, fixed at the bottom of a phone once the hero's own Book has gone.
   ------------------------------------------------------------------------ */

.dock {
  position: fixed;
  z-index: 10;
  inset: auto 0 0;
  display: grid;
  padding: 12px 16px max(12px, env(safe-area-inset-bottom));
  border-top: 1px solid var(--line);
  background: rgb(246 241 233 / 0.96);
  visibility: hidden;
  transform: translateY(110%);
  transition: transform 0.32s var(--ease), visibility 0s 0.32s;
}

.dock .button--book {
  width: 100%;
}

/* Hidden, not only moved away, so the keyboard never lands on it unseen. */
.dock.is-shown {
  visibility: visible;
  transform: none;
  transition: transform 0.32s var(--ease);
}

@media (min-width: 900px) {
  .dock {
    display: none;
  }
}

/* ---------------------------------------------------------------------------
   Every page that is not the home page: booking, status, legal texts and
   error pages. One column, a phone's width first.
   ------------------------------------------------------------------------ */

.site-main:not(.site-main--home) {
  width: min(calc(100% - 2 * var(--gutter)), 760px);
  margin: clamp(48px, 8vw, 96px) auto 0;
}

.site-main:not(.site-main--home) h1 {
  margin-bottom: 0.5em;
  font-size: clamp(2.2rem, 1.6rem + 2.4vw, 3.4rem);
}

.site-main:not(.site-main--home) h2 {
  margin: 1.6em 0 0.5em;
  font-size: clamp(1.5rem, 1.3rem + 1vw, 2rem);
}

.site-main:not(.site-main--home) p {
  max-width: 66ch;
}

/* A legal text's section titles (session 29): a hairline above, in the
   display face, so a long notice can be scanned. */
.site-main .legal .legal__title {
  margin: 2em 0 0.6em;
  padding-top: 1.1em;
  border-top: 1px solid var(--line);
  font-size: clamp(1.35rem, 1.2rem + 0.6vw, 1.7rem);
}

/* The 404's ways on, one under the other on a phone. */
.lost__ways {
  display: grid;
  gap: 12px;
  max-width: 360px;
  margin: 28px 0 0;
  padding: 0;
  list-style: none;
}

.lost__ways .button {
  width: 100%;
}

/* ---------------------------------------------------------------------------
   The booking request, the status page and the member pages. 16px text in
   every field, so that focusing one does not zoom the page, and every
   control at least 48px tall.
   ------------------------------------------------------------------------ */

.booking {
  max-width: 36rem;
}

.booking__title {
  margin-bottom: 12px;
}

.booking__intro {
  color: var(--ink-2);
}

/* Where the request has got to: service, day, time, details, done, as a
   label's line of small capitals; the step reached in ink, underlined. */
.steps {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 18px;
  margin: 24px 0 8px;
  padding: 0 0 12px;
  border-bottom: 1px solid var(--line);
  list-style: none;
}

.steps li {
  padding-bottom: 4px;
  border-bottom: 1px solid transparent;
  font: 600 0.6875rem/1.3 var(--font-body);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.steps li.is-done {
  color: var(--ink-2);
}

.steps li[aria-current="step"] {
  border-bottom-color: var(--ink);
  color: var(--ink);
}

.booking__alert {
  padding: 14px 16px;
  border-left: 3px solid var(--danger);
  color: var(--danger);
  background: #f8e9e4;
}

.booking__form {
  display: grid;
  gap: 24px;
  margin-top: 24px;
}

.booking__step {
  display: grid;
  gap: 24px;
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.booking__step-title {
  padding: 0;
  font: 500 clamp(1.6rem, 1.3rem + 1.2vw, 2.2rem)/1.15 var(--font-display);
}

/* The guided flow, once booking.js runs: one step at a time. Without it,
   every step is on the page at once and the form still works. */
.is-guided .booking__step:not(.is-current) {
  display: none;
}

.booking__next {
  justify-self: stretch;
}

.booking__back {
  justify-self: start;
  min-height: 44px;
  padding: 0;
  border: 0;
  font: inherit;
  color: var(--ink-2);
  text-decoration: underline;
  text-decoration-color: var(--line-strong);
  text-underline-offset: 0.24em;
  background: none;
  cursor: pointer;
}

/* What is being asked for and how long it takes, framed like a label. */
/* The review before sending (run 32): what was chosen as a card at the
   top, the details as rows, one ink pill docked at the foot. The card is
   the summary above the form, carried over by the step's view transition:
   one of the two carries the name at a time, and the summary keeps its
   place, unseen, while the review shows, so nothing around it moves. */
.booking__summary {
  view-transition-name: chosen-services;
}

.is-reviewing .booking__summary {
  visibility: hidden;
  view-transition-name: none;
}

.is-reviewing .booking__review-card {
  view-transition-name: chosen-services;
}

.booking__review-card {
  display: grid;
  gap: 6px;
  margin: 0 0 20px;
  padding: 22px 20px;
  border: 1px solid var(--line-strong);
  border-radius: 14px;
  background: var(--surface-strong);
  box-shadow: 0 18px 30px -24px rgb(21 18 14 / 0.5);
}

.booking__review-card p {
  margin: 0;
}

.booking__review-what {
  font: 500 1.5rem/1.15 var(--font-display);
}

.booking__review-length {
  font-size: 0.9375rem;
  color: var(--ink-2);
}

.booking__review-rows {
  display: grid;
  margin: 0 0 8px;
}

.booking__review-rows div {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  padding: 12px 0;
  border-bottom: 1px solid var(--line);
}

.booking__review-rows dt {
  color: var(--ink-2);
}

.booking__review-rows dd {
  margin: 0;
  text-align: right;
  overflow-wrap: anywhere;
}

/* The one action, docked at the foot of the screen while the review is
   read. */
.booking__dock {
  position: sticky;
  bottom: 0;
  z-index: 1;
  margin: 12px calc(-1 * var(--gutter)) 0;
  padding: 12px var(--gutter) max(12px, env(safe-area-inset-bottom));
  background: var(--paper);
}

.button--pill {
  width: 100%;
  min-height: 52px;
  border: 0;
  border-radius: 999px;
  color: var(--paper);
  background: var(--ink);
}

.button--pill:hover {
  background: var(--night);
}

.booking__summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 4px 16px;
  padding: 10px 16px;
  border: 1px solid var(--line-strong);
  background: var(--surface-strong);
}

.booking__summary p {
  display: grid;
  margin: 0;
}

.booking__summary-what {
  font-weight: 600;
}

.booking__summary-length {
  font-size: 0.9375rem;
  color: var(--ink-3);
}

.booking__summary a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

.booking__field {
  display: grid;
  gap: 8px;
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

/* The field's own label and legend, not the labelled rows of a choice. */
.booking__field > label:not(.booking__choice, .booking__country-search-label),
.booking__field > legend {
  padding: 0;
  font: 600 1rem/1.3 var(--font-body);
}

.booking__field input[type="text"],
.booking__field input[type="tel"],
.booking__field input[type="date"],
.booking__field input[type="email"],
.booking__field input[type="password"],
.booking__field textarea,
.booking__field select,
.booking__field .booking__country-search {
  width: 100%;
  min-height: 52px;
  padding: 12px 14px;
  border: 1px solid var(--line-strong);
  border-radius: 2px;
  font: 400 max(16px, 1rem)/1.4 var(--font-body);
  color: var(--ink);
  background: #fffdf9;
}

.booking__field input:focus-visible,
.booking__field textarea:focus-visible,
.booking__field select:focus-visible {
  border-color: var(--ink);
  outline-offset: 1px;
}

/* Added by phone-country.js above the select; it reads as a hint to the
   select's own label rather than a second field. */
.booking__country-search-label {
  font-size: 0.9375rem;
  color: var(--ink-2);
}

.booking__name-grid {
  display: grid;
  gap: 14px;
}

@media (min-width: 560px) {
  .booking__name-grid {
    grid-template-columns: 1fr 1fr;
  }
}

.booking__subfield {
  display: grid;
  gap: 8px;
  align-content: start;
}

.booking__subfield > label {
  font: 600 1rem/1.3 var(--font-body);
}

.booking__field [aria-invalid="true"],
.booking__field[aria-invalid="true"] .booking__time span {
  border-color: var(--danger);
}

.booking__hint,
.booking__error {
  margin: 0;
  font-size: 0.9375rem;
  line-height: 1.5;
}

.booking__hint {
  color: var(--ink-3);
}

.booking__error {
  color: var(--danger);
}

/* The days around the one chosen, a strip to swipe; each a link that asks
   again for that day (session 29, direction C in B's colours). */
.booking__days {
  display: flex;
  gap: 8px;
  margin: 0 calc(-1 * var(--gutter));
  padding: 2px var(--gutter) 6px;
  overflow-x: auto;
  scroll-snap-type: x proximity;
  scrollbar-width: none;
}

.booking__days::-webkit-scrollbar {
  display: none;
}

.booking__day {
  display: grid;
  flex: none;
  justify-items: center;
  gap: 2px;
  width: 60px;
  padding: 10px 0;
  border: 1px solid var(--line-strong);
  text-decoration: none;
  background: var(--surface-strong);
  scroll-snap-align: start;
}

.booking__day-name,
.booking__day-note {
  font-size: 0.6875rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.booking__day-number {
  font: 500 1.5rem/1.1 var(--font-display);
  font-variant-numeric: lining-nums;
}

.booking__day[aria-current="date"] {
  border-color: var(--ink);
  color: var(--paper);
  background: var(--ink);
}

.booking__day[aria-current="date"] .booking__day-name,
.booking__day[aria-current="date"] .booking__day-note {
  color: var(--mist);
}

.booking__day--full {
  border-style: dashed;
  background: transparent;
}

.booking__day--full .booking__day-number {
  color: var(--ink-3);
}

/* The times in parts of the day, four across. */
.booking__part + .booking__part {
  margin-top: 18px;
}

.booking__part-title {
  display: flex;
  justify-content: space-between;
  margin: 0 0 10px;
  font: 600 0.75rem/1.3 var(--font-body);
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.booking__part-count {
  font-weight: 400;
  letter-spacing: 0.04em;
  text-transform: none;
  color: var(--ink-3);
}

.booking__time-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 8px;
}

/* A time is a radio drawn as a tile; the radio stays in the page, visually
   hidden, so the keyboard and screen readers use it as a radio. */
.booking__time {
  position: relative;
  display: block;
}

.booking__time input {
  position: absolute;
  inset: 0;
  margin: 0;
  opacity: 0;
}

.booking__time span {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  border: 1px solid var(--line-strong);
  font: 600 1rem/1 var(--font-body);
  font-variant-numeric: tabular-nums;
  background: #fffdf9;
  cursor: pointer;
}

.booking__time input:checked + span {
  border-color: var(--ink);
  color: var(--paper);
  background: var(--ink);
}

.booking__time input:focus-visible + span {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}

/* A full time offered on request: a dotted tile, its mark in words under
   the time, so the difference never rests on colour alone. */
.booking__time--on-request span {
  flex-direction: column;
  gap: 3px;
  border-style: dotted;
  background: transparent;
}

/* The mark sits inside the tile's span; it is words, not a second tile. */
.booking__time .booking__time-mark {
  display: block;
  min-height: 0;
  border: 0;
  font: 500 0.625rem/1 var(--font-body);
  letter-spacing: 0.02em;
  color: var(--ink-2);
  background: none;
}

.booking__time--on-request input:checked + span .booking__time-mark {
  color: inherit;
}

/* The time wanted is not free: the earliest that are, first, as two
   buttons in a frame. */
.booking__earliest {
  display: grid;
  gap: 12px;
  padding: 16px;
  border: 1px solid var(--walnut);
  background: var(--surface-strong);
}

.booking__earliest p {
  margin: 0;
}

.booking__earliest-choices {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: 8px;
}

.booking__earliest-choices .button {
  min-height: 48px;
  padding: 0 12px;
}

/* Continue with the time chosen, held at the foot of the screen while the
   guided form shows the time step; without booking.js it is not drawn. */
.booking__bar {
  display: none;
}

.is-guided .booking__bar {
  position: sticky;
  z-index: 2;
  bottom: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 12px;
  margin: 8px calc(-1 * var(--gutter)) 0;
  padding: 12px var(--gutter) max(12px, env(safe-area-inset-bottom));
  border-top: 1px solid var(--line-strong);
  background: var(--paper);
}

.booking__chosen {
  margin: 0;
  font-weight: 600;
  line-height: 1.3;
}

.is-guided .booking__bar .booking__next {
  justify-self: end;
  padding: 0 28px;
}

/* Quiet rows that become definite when chosen (decision 0032): a hairline
   at rest, the ink's own edge once ticked, never a fill of colour. Square
   corners, like the room's buttons; only the member pass is rounded,
   because it is drawn as an object. */
.booking__choice {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  min-height: 52px;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: 2px;
  background: #fffdf9;
  cursor: pointer;
}

.booking__choice:hover {
  border-color: var(--line-strong);
}

.booking__choice:has(input:checked) {
  border-color: var(--ink);
  background: #fff;
  box-shadow: inset 0 0 0 1px var(--ink);
}

.booking__choice input {
  flex: none;
  width: 20px;
  height: 20px;
  margin: 2px 0 0;
  accent-color: var(--ink);
}

.booking__consent {
  line-height: 1.5;
}

.booking__submit {
  width: 100%;
}

/* Who is signed in with LINE, on the web form (decision 0039: no LINE
   button above the form). */
.booking__line {
  margin: 24px 0 0;
  padding: 18px 20px;
  border: 1px solid var(--line);
  border-radius: 2px;
  background: #fffdf9;
}

.booking__line p {
  margin: 0;
}

.qr-code {
  display: block;
  width: 176px;
  height: auto;
}

.booking__notice {
  padding: 14px 16px;
  background: var(--linen);
}

.liff__status {
  color: var(--ink-2);
}

/* The member card (run 20): the code to read out and the code to scan. */
.member-card {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
  align-items: center;
  justify-content: space-between;
  margin: 20px 0 8px;
  padding: 20px;
  background: var(--surface-strong);
  border: 1px solid var(--line-strong);
}

.member-card__label {
  margin: 0;
  font-size: 0.8125rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.member-card__code {
  margin: 4px 0 6px;
  font: 500 clamp(2.2rem, 1.8rem + 2vw, 3rem)/1.1 var(--font-display);
  font-variant-numeric: lining-nums;
  letter-spacing: 0.1em;
}

.member-card .qr-code {
  width: 148px;
}

.member-upcoming {
  display: grid;
  gap: 16px;
  margin: 0 0 24px;
  padding: 0;
  list-style: none;
}

.member-upcoming li {
  padding: 16px;
  border: 1px solid var(--line);
}

.member-upcoming p {
  margin: 0 0 6px;
}

.member-upcoming__when {
  font-weight: 500;
}

.member-upcoming__reference {
  white-space: nowrap;
}

.member-upcoming .member-upcoming__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin: 10px 0 0;
}

/* The ticket as paper from a printer (run 32): a night slot, the paper
   under it in a monospace setting with a torn foot, and a stamp that says
   where the request stands. printer.js feeds the paper out of the slot and
   lands the stamp; without it, and for a reader who asked for less motion,
   it is the same ticket standing still. One column at every width: it is a
   slip of paper, not a panel. */
.printer {
  --mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
  max-width: 26rem;
  margin: 30px 0 18px;
}

.printer__slot {
  position: relative;
  z-index: 1;
  height: 22px;
  border-radius: 11px;
  background: linear-gradient(180deg, #2f2820 0%, var(--night) 55%, #000 100%);
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.06), 0 10px 18px -12px rgb(21 18 14 / 0.6);
}

/* The mouth the paper comes out of. */
.printer__slot::after {
  content: "";
  position: absolute;
  right: 14px;
  bottom: 6px;
  left: 14px;
  height: 3px;
  border-radius: 2px;
  background: #000;
  box-shadow: 0 1px 0 rgb(255 255 255 / 0.07);
}

/* The paper is clipped at the mouth, so it is seen only once it is out. */
.printer__out {
  margin: -8px 12px 0;
  padding: 0 0 16px;
  overflow: hidden;
}

.ticket {
  position: relative;
  display: grid;
  gap: 18px;
  padding: 30px 20px 34px;
  font: 400 0.875rem/1.5 var(--mono);
  color: var(--ink);
  background: var(--surface-strong);
  /* An edge drawn inside, since the torn foot's mask clips anything
     outside: a shadow there would be cut off. */
  box-shadow: inset 0 0 0 1px var(--line-strong);
  /* A torn foot. */
  -webkit-mask:
    linear-gradient(#000 0 0) top / 100% calc(100% - 7px) no-repeat,
    conic-gradient(from -45deg at bottom, #0000, #000 1deg 90deg, #0000 91deg) bottom / 14px 7px repeat-x;
  mask:
    linear-gradient(#000 0 0) top / 100% calc(100% - 7px) no-repeat,
    conic-gradient(from -45deg at bottom, #0000, #000 1deg 90deg, #0000 91deg) bottom / 14px 7px repeat-x;
}

.ticket__salon {
  margin: 0;
  font: 700 0.9375rem/1.35 var(--mono);
  letter-spacing: 0.22em;
  text-transform: uppercase;
}

/* Beside the stamp's corner; the page's own width for paragraphs would
   otherwise win. */
.printer .ticket .ticket__salon {
  max-width: 58%;
}

.ticket__kind {
  margin: 6px 0 0;
  padding-bottom: 14px;
  border-bottom: 1px dashed var(--line-strong);
  font-size: 0.6875rem;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.ticket__rows {
  display: grid;
  gap: 9px;
  margin: 14px 0 0;
}

.ticket__rows div {
  display: grid;
  grid-template-columns: 7.2em minmax(0, 1fr);
  gap: 12px;
}

.ticket__rows dt {
  padding-top: 0.2em;
  font-size: 0.6875rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.ticket__rows dd {
  margin: 0;
}

.ticket__reference {
  font-weight: 700;
  letter-spacing: 0.12em;
}

.ticket__note {
  margin: 14px 0 0;
  padding-top: 12px;
  border-top: 1px dashed var(--line-strong);
  font-size: 0.8125rem;
  color: var(--ink-2);
}

.ticket__code {
  display: grid;
  justify-items: center;
  gap: 6px;
}

.ticket__code .qr-code {
  width: 132px;
}

.ticket__code figcaption {
  font-size: 0.75rem;
  color: var(--ink-2);
}

/* A receipt's lines and its total (run 32): what was bought, left, its
   amount right, a dashed rule before the total. */
.ticket__lines {
  display: grid;
  gap: 6px;
  margin: 14px 0 0;
  padding: 12px 0 0;
  border-top: 1px dashed var(--line-strong);
  list-style: none;
}

.ticket__lines li,
.ticket__total {
  display: flex;
  justify-content: space-between;
  gap: 16px;
}

.ticket__lines li span:last-child,
.ticket__total span:last-child {
  flex: none;
  font-variant-numeric: tabular-nums;
}

.ticket__total {
  margin: 12px 0 0;
  padding-top: 10px;
  border-top: 1px dashed var(--line-strong);
  font-weight: 700;
  font-size: 1rem;
}

/* The stamp, inked over the paper's empty top corner, clear of the name
   and the code: ink, never brass. */
.ticket__stamp {
  position: absolute;
  top: 30px;
  right: 10px;
  margin: 0;
  padding: 7px 12px 6px;
  border: 4px double var(--ink);
  border-radius: 6px;
  font: 800 0.9375rem/1 var(--mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink);
  opacity: 0.8;
  mix-blend-mode: multiply;
  transform: rotate(-11deg);
  pointer-events: none;
}

.ticket__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 24px;
}

/* A signed-in member adds an earlier visit's points (run 34). */
.ticket__claim {
  display: grid;
  gap: 8px;
  justify-items: start;
  margin-bottom: 24px;
}

.ticket__claim p {
  margin: 0;
}

.booking__line-link {
  margin: 24px 0;
  padding: 16px;
  background: var(--linen);
}

.booking__line-link p:last-child {
  margin-bottom: 0;
}

.booking__reference strong {
  font: 500 clamp(2rem, 1.6rem + 2vw, 2.8rem)/1.1 var(--font-display);
  font-variant-numeric: lining-nums;
  letter-spacing: 0.08em;
}

.booking__subtitle {
  margin: 32px 0 10px;
  font-size: 1.5rem;
}

/* Wide enough for three columns on a phone; scrolls sideways inside itself
   rather than widening the page if a service name is very long. */
.booking__prices-wrap {
  margin: 12px 0 24px;
  overflow-x: auto;
}

.booking__prices {
  width: 100%;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
}

.booking__prices th,
.booking__prices td {
  padding: 12px 12px 12px 0;
  border-bottom: 1px solid var(--line);
  text-align: left;
  vertical-align: top;
}

.booking__prices thead th {
  font: 600 0.8125rem/1.3 var(--font-body);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-2);
}

.booking__prices tbody th {
  font-weight: 500;
}

.booking__prices td {
  white-space: nowrap;
}

.booking__result {
  display: grid;
  gap: 4px 0;
  margin: 0 0 24px;
}

.booking__result dt {
  margin-top: 14px;
  font: 600 0.8125rem/1.3 var(--font-body);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-2);
}

.booking__result dd {
  margin: 0;
}

.booking__lost {
  margin-top: 16px;
}

/* ---------------------------------------------------------------------------
   Motion. What moves below the hero is set out at the end of this file
   (session 30, decision 0036); all of it, and every transition elsewhere,
   stops for a reader who asked for less motion.
   ------------------------------------------------------------------------ */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition: none !important;
    animation: none !important;
  }
}

/* ---------------------------------------------------------------------------
   Forced colours (Windows contrast themes) replace author backgrounds with
   the page colour, which would erase the diamonds drawn as backgrounds.
   ------------------------------------------------------------------------ */

@media (forced-colors: active) {
  .range-sep,
  .faq__item[open] .faq__question::before,
  .button__mark {
    forced-color-adjust: none;
    background: CanvasText;
  }

  .booking__time input:checked + span,
  .price-chooser__input:checked + .price-chooser__option {
    forced-color-adjust: none;
    color: HighlightText;
    background: Highlight;
  }
}

/* The phones signed in to a membership, on its own page (session 23). */
.member-devices {
  list-style: none;
  margin: 0;
  padding: 0;
}

.member-devices li {
  padding-block: 12px;
  border-top: 1px solid var(--line);
}

/* One-button forms on the member page, each apart from the last; signing
   out further apart, so it is not taken for part of the section above. */
.booking__action {
  margin-top: 16px;
}

.booking__action--apart {
  margin-top: 40px;
}

/* A birthday as day and month, side by side, on the counter registration. */
.booking__birthday {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}

.booking__birthday label {
  display: grid;
  gap: 4px;
  font: 400 0.95rem/1.3 var(--font-body);
}

/* ---------------------------------------------------------------------------
   Below the member card (session 24, decision 0030): Book, Link LINE and
   the way to the settings. The card itself is at the end of this file
   (session 30, decision 0036).
   ------------------------------------------------------------------------ */
.mbook {
  max-width: 24rem;
  margin: 0 0 16px;
}

.mbook .button--book {
  width: 100%;
  justify-content: center;
}

/* Quiet beside the pass: one dark thing on the page is enough. */
.mline {
  max-width: 24rem;
  margin: 0 0 20px;
  padding: 18px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: #fffdf8;
}

.site-main .mline h2 {
  margin: 0 0 6px;
  font: 500 1.625rem/1.1 var(--font-display);
}

.mline p {
  margin: 0 0 14px;
  color: var(--ink-2);
}

.mline form {
  margin: 0;
}

.mline__button {
  width: 100%;
  min-height: 52px;
  border-color: var(--night);
  color: var(--paper);
  background: var(--night);
}

.mmore {
  display: grid;
  max-width: 24rem;
  margin: 0 0 16px;
  border-top: 1px solid var(--line);
}

.mmore a {
  display: grid;
  min-height: 60px;
  padding: 10px 2px;
  border-bottom: 1px solid var(--line);
  font-weight: 600;
  text-decoration: none;
  color: var(--ink);
}

.mmore span {
  font-size: 0.875rem;
  font-weight: 400;
  color: var(--ink-3);
}

.msettings__back {
  margin: 0;
}

.msettings__back a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--ink);
}

.msettings__sec {
  display: grid;
  gap: 12px;
  margin-top: 24px;
  padding-top: 16px;
  border-top: 1px solid var(--line);
}

.msettings__h3 {
  margin: 8px 0 0;
  font: 600 1rem/1.3 var(--font-body);
}

/* A PIN: the phone's number pad, the digits spaced so six are counted. */
.booking__pin {
  max-width: 14rem;
  letter-spacing: 0.4em;
  font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------------------------------
   The PIN pad on a member's phone (decision 0033), in the room's palette:
   the heading, six dots, large round keys, one quiet link. The dots shake
   at a wrong PIN, and not when the phone asks for less motion.
   ------------------------------------------------------------------------ */
.mpin__intro {
  max-width: 24rem;
  color: var(--ink-2);
}

/* What the pad's script hides (the fallback fields once the keys are
   drawn) stays hidden whatever its own display says. */
.pinpad [hidden] {
  display: none !important;
}

.pinpad {
  display: grid;
  justify-items: center;
  gap: 18px;
  width: 100%;
  max-width: 24rem;
  margin: 8px 0 0;
}

.pinpad__label {
  margin: 0;
  font: 500 1.75rem/1.15 var(--font-display);
  text-align: center;
}

.pinpad__note {
  margin: -8px 0 0;
  text-align: center;
  color: var(--ink-2);
}

.pinpad__dots {
  display: flex;
  gap: 16px;
  padding: 6px 0;
}

.pinpad__dots span {
  width: 14px;
  height: 14px;
  border: 1.5px solid var(--ink);
  border-radius: 50%;
}

.pinpad__dots span.is-on {
  background: var(--ink);
}

.pinpad__dots.is-wrong {
  animation: pinpad-shake 0.36s linear;
}

.pinpad__dots.is-wrong span {
  border-color: var(--danger);
}

@keyframes pinpad-shake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-10px); }
  40% { transform: translateX(9px); }
  60% { transform: translateX(-6px); }
  80% { transform: translateX(4px); }
}

@media (prefers-reduced-motion: reduce) {
  .pinpad__dots.is-wrong {
    animation: none;
  }
}

.pinpad__message {
  max-width: 100%;
  min-height: 1.6em;
  margin: 0;
  font-weight: 600;
  text-align: center;
  color: var(--danger);
}

.pinpad__keys {
  display: grid;
  grid-template-columns: repeat(3, 76px);
  gap: 14px 24px;
}

.pinpad__key {
  display: grid;
  place-items: center;
  width: 76px;
  height: 76px;
  border: 1px solid var(--line-strong);
  border-radius: 50%;
  font: 400 1.75rem/1 var(--font-body);
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  background: #fffdf9;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-user-select: none;
  user-select: none;
}

.pinpad__key:active {
  background: var(--linen);
}

.pinpad__key--delete {
  border-color: transparent;
  background: none;
}

.pinpad__key--delete svg {
  width: 28px;
  height: 28px;
}

.pinpad.is-sending .pinpad__keys {
  opacity: 0.5;
  pointer-events: none;
}

.pinpad__fields {
  display: grid;
  gap: 12px;
  width: 100%;
}

.pinpad__field {
  display: grid;
  gap: 6px;
  font-weight: 600;
}

.pinpad__field input {
  min-height: 56px;
  padding: 0 12px;
  border: 1px solid var(--line-strong);
  border-radius: 2px;
  font: 400 1.75rem/1 var(--font-body);
  letter-spacing: 0.4em;
  text-align: center;
  background: #fffdf9;
}

.pinpad__submit {
  min-height: 52px;
  border: 0;
  border-radius: 2px;
  font: 600 1rem/1 var(--font-body);
  color: var(--paper);
  background: var(--ink);
  cursor: pointer;
}

.pinpad__alt {
  margin: 0;
}

.pinpad__alt a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--ink-2);
}

/* ---------------------------------------------------------------------------
   The member card with two sides (session 30, decision 0036), the
   proportions of a credit card: night, a quiet sheen like the room's
   lacquer, and brass only as its hairline frame and the rule under the
   mark, never a fill and never text (0017 as amended). Without card.js the
   sides stand one above the other; with it the card turns in place, at
   once when less motion is asked for.
   ------------------------------------------------------------------------ */

.mcard {
  max-width: 25rem;
  margin: 0 0 18px;
  perspective: 1600px;
}

.mcard__inner {
  display: grid;
  gap: 16px;
}

.mcard__face {
  position: relative;
  display: grid;
  aspect-ratio: 1.586;
  padding: 7% 7.5%;
  overflow: hidden;
  border-radius: 16px;
  color: var(--paper);
  background:
    radial-gradient(120% 90% at 15% 0%, rgb(246 241 233 / 0.07), transparent 60%),
    repeating-linear-gradient(0deg, rgb(246 241 233 / 0.025) 0 1px, transparent 1px 3px),
    repeating-linear-gradient(0deg, rgb(0 0 0 / 0.07) 0 1px, transparent 1px 7px),
    linear-gradient(150deg, #2a231c 0%, var(--night-2) 45%, var(--night) 100%);
  box-shadow: 0 1px 2px rgb(21 18 14 / 0.3), 0 28px 50px -30px rgb(21 18 14 / 0.75);
}

/* The brass hairline, set in from the edge. */
.mcard__face::before {
  content: "";
  position: absolute;
  inset: 9px;
  border: 1px solid var(--brass);
  border-radius: 10px;
  opacity: 0.75;
  pointer-events: none;
}

.mcard__front {
  grid-template-rows: auto 1fr auto;
}

.mcard__mark {
  display: grid;
  justify-items: start;
}

.mcard__lockup {
  width: clamp(64px, 22vw, 84px);
  height: auto;
  color: var(--paper);
}

.mcard__rule {
  display: block;
  width: 34px;
  height: 1px;
  margin-top: 10px;
  background: var(--brass);
}

.mcard__kind {
  position: absolute;
  top: 7.5%;
  right: 7.5%;
  margin: 0;
  font: 600 0.625rem/1 var(--font-body);
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--mist);
}

.mcard__number {
  align-self: center;
  margin: 0;
  font: 500 clamp(1.35rem, 0.9rem + 3vw, 2rem)/1 var(--font-body);
  letter-spacing: 0.3em;
  font-variant-numeric: tabular-nums lining-nums;
  white-space: nowrap;
  /* Set like a card's number: pressed into the card, lit from above. */
  text-shadow: 0 1px 0 rgb(0 0 0 / 0.5), 0 -1px 0 rgb(255 255 255 / 0.08);
}

.mcard__name {
  font: 500 clamp(1.05rem, 0.9rem + 1vw, 1.3rem)/1.15 var(--font-display);
  letter-spacing: 0.01em;
}

/* A light sheen across the card, placed by the finger or the pointer
   (card.js), and still where it starts for a reader who asked for less
   motion. The back is the front turned over, so its light is mirrored. */
.mcard__sheen {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(180deg, transparent calc(var(--sy, 18%) - 18%), rgb(246 241 233 / 0.06) var(--sy, 18%), transparent calc(var(--sy, 18%) + 18%)),
    radial-gradient(70% 60% at var(--sx, 28%) var(--sy, 18%), rgb(246 241 233 / 0.11), transparent 70%);
}

.mcard__back .mcard__sheen {
  background: radial-gradient(70% 60% at calc(100% - var(--sx, 28%)) var(--sy, 18%), rgb(246 241 233 / 0.08), transparent 70%);
}

.mcard__foot {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 12px;
}

.mcard__field {
  display: grid;
  gap: 3px;
  margin: 0;
}

.mcard__field--end {
  text-align: right;
}

.mcard__label {
  font: 600 0.5625rem/1.2 var(--font-body);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--mist);
}

.mcard__value {
  margin: 0;
  font-size: 0.8125rem;
  line-height: 1.35;
}

.mcard__back {
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: 6%;
}

/* The code on a light panel, so a counter's scanner reads it at once. */
.mcard__qr {
  display: grid;
  justify-items: center;
  padding: 10px 10px 8px;
  border-radius: 8px;
  color: var(--ink);
  background: #fffdf9;
}

.mcard__qr .qr-code {
  width: clamp(92px, 30vw, 118px);
  height: auto;
}

.mcard__qr-code {
  margin: 5px 0 0;
  font: 600 0.6875rem/1 var(--font-body);
  letter-spacing: 0.14em;
  font-variant-numeric: tabular-nums;
}

.mcard__qr-hint {
  margin: 4px 0 0;
  font: 500 0.5625rem/1.2 var(--font-body);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.mcard__facts {
  display: grid;
  gap: 9px;
  margin: 0;
}

.mcard__facts div {
  display: grid;
  gap: 2px;
}

.mcard__facts dd {
  margin: 0;
}

.mcard__points {
  font: 500 1.6rem/1 var(--font-display);
  font-variant-numeric: lining-nums;
}

/* Turnable: the two sides share one place and the card turns about its
   upright. */
.mcard.is-turnable .mcard__inner {
  gap: 0;
  transform-style: preserve-3d;
  transition: transform 0.75s cubic-bezier(0.2, 0.7, 0.2, 1);
  cursor: pointer;
}

.mcard.is-turnable .mcard__face {
  grid-area: 1 / 1;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
}

.mcard.is-turnable .mcard__back {
  transform: rotateY(180deg);
}

.mcard.is-turned .mcard__inner {
  transform: rotateY(180deg);
}

/* Each side also hides itself as the card passes edge-on, half way
   through the turn, so a browser that ignores backface-visibility never
   shows a side mirrored. */
.mcard.is-turnable .mcard__face {
  transition: visibility 0s linear 0.375s;
}

.mcard.is-turnable:not(.is-turned) .mcard__back,
.mcard.is-turned .mcard__front {
  visibility: hidden;
}

.mcard__turn {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  margin-top: 6px;
  padding: 0;
  border: 0;
  font: 500 0.9375rem/1.3 var(--font-body);
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: var(--line-strong);
  text-underline-offset: 0.3em;
  background: none;
  cursor: pointer;
}

/* What the back cannot hold: the rule for points, a package's last day,
   and the next appointment's links. */
.mnotes {
  max-width: 25rem;
  margin: 4px 0 24px;
  font-size: 0.9375rem;
  color: var(--ink-2);
}

.mnotes p {
  margin: 0 0 8px;
}

.mnotes__next {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 16px;
}

.mnotes__next a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

/* A member's packages as cards to swipe (run 32): the row scrolls at the
   member's own speed and snaps a card to the middle, where it stands full
   size; the others ease smaller by the row's own scroll. Scale only, so
   nothing reflows, and none of it for a reader who asked for less motion
   or a browser without scroll-driven animation, where all stand full
   size. */
.mpacks {
  max-width: 25rem;
  margin: 4px 0 28px;
}

.mpacks__title {
  margin: 0 0 8px;
  font: 500 1.4rem/1.2 var(--font-display);
}

.mpacks__row {
  display: flex;
  gap: 12px;
  margin: 0;
  padding: 8px 11% 16px;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  list-style: none;
}

.mpacks__row::-webkit-scrollbar {
  display: none;
}

.mpacks__row:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

.mpack {
  display: grid;
  flex: 0 0 78%;
  align-content: space-between;
  aspect-ratio: 1.586;
  padding: 18px 20px;
  border: 1px solid var(--line-strong);
  border-radius: 14px;
  background: var(--surface-strong);
  box-shadow: 0 18px 30px -24px rgb(21 18 14 / 0.5);
  scroll-snap-align: center;
}

.mpack p {
  margin: 0;
}

.mpack__name {
  font: 500 1.25rem/1.15 var(--font-display);
}

.mpack__left {
  display: flex;
  align-items: baseline;
  gap: 8px;
}

.mpack__count {
  /* Inter, where Cormorant's figure one reads as a capital I. */
  font: 500 2.25rem/1 var(--font-body);
  font-variant-numeric: tabular-nums lining-nums;
  letter-spacing: -0.01em;
}

.mpack__until {
  font-size: 0.8125rem;
  color: var(--ink-2);
}

@keyframes mpack-centre {
  0% { scale: 0.86; }
  50% { scale: 1; }
  100% { scale: 0.86; }
}

@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view(inline)) {
    .mpack {
      animation: mpack-centre linear both;
      animation-timeline: view(inline);
    }
  }
}

@media (prefers-reduced-motion: reduce) {
  .mcard.is-turnable .mcard__inner,
  .mcard.is-turnable .mcard__face {
    transition: none;
  }
}

/* ---------------------------------------------------------------------------
   Motion on the customer pages (session 30, decision 0036, amending 0035):
   the browser's own tools and no library; the page always scrolls at the
   visitor's speed; parallax small and on photographs only; a reveal once,
   short, and never on the price list or a form field; nothing that moves
   the layout, only transforms; and all of it off for a reader who asked
   for less motion, which the rule under "Motion" above enforces.
   ------------------------------------------------------------------------ */

/* Press feedback: a pressed control answers at once, by colour for
   everyone and by a slight give where motion is welcome. */
.button:active {
  filter: brightness(0.92);
}

.booking__day:active,
.booking__time:active span,
.booking__choice:active {
  border-color: var(--ink);
  background: var(--linen);
}

@media (prefers-reduced-motion: no-preference) {
  .button {
    transition: background-color 0.2s var(--ease), border-color 0.2s var(--ease), color 0.2s var(--ease), scale 0.12s ease-out;
  }

  .booking__day,
  .booking__time span,
  .booking__choice {
    transition: scale 0.12s ease-out;
  }

  .button:active,
  .booking__day:active,
  .booking__time:active span,
  .booking__choice:active {
    scale: 0.97;
    transition-duration: 0s;
  }

  /* The photographs drift a little against the page as it scrolls, driven
     by the scroll itself, so they can never lag or lead it. Each frame
     clips its photograph, which is scaled just enough that the drift never
     shows an edge. */
  @supports (animation-timeline: view()) {
    .nuch__photo,
    .salon__photo picture,
    .find__side picture,
    .portfolio__photo picture {
      display: block;
      overflow: hidden;
    }

    .nuch__photo img,
    .salon__photo img,
    .find__side picture img,
    .portfolio__photo img {
      scale: 1.08;
      animation: photo-drift linear both;
      animation-timeline: view();
      animation-range: cover;
    }
  }

  @keyframes photo-drift {
    from {
      translate: 0 -3%;
    }

    to {
      translate: 0 3%;
    }
  }

  /* A section's heading and its first lines rise into place the first time
     they reach the screen. landing.js marks only what is still below the
     screen when the page opens, so nothing already read ever moves. Text
     rises and never fades: a fading line is a faint line for a moment. */
  .is-waiting {
    translate: 0 18px;
  }

  .is-waiting .turn__rule {
    scale: 0 1;
  }

  .is-revealed {
    translate: 0 0;
    transition: translate 0.7s cubic-bezier(0.2, 0.7, 0.2, 1);
  }

  .is-revealed .turn__rule {
    scale: 1 1;
    transition: scale 0.9s cubic-bezier(0.2, 0.7, 0.2, 1) 0.15s;
  }

  /* The booking steps change in place: the step leaving gives way to the
     next rising, in browsers with view transitions. */
  .is-guided .booking__step.is-current {
    view-transition-name: booking-step;
  }

  ::view-transition-old(booking-step) {
    animation: 0.18s ease-in both step-out;
  }

  ::view-transition-new(booking-step) {
    animation: 0.32s cubic-bezier(0.2, 0.7, 0.2, 1) 0.06s both step-in;
  }

  @keyframes step-out {
    to {
      opacity: 0;
    }
  }

  @keyframes step-in {
    from {
      opacity: 0;
      translate: 0 14px;
    }
  }

  /* Between pages, a day chosen on the time step above all, the page
     crossfades rather than blinks, in browsers that do this. */
  @view-transition {
    navigation: auto;
  }

  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation-duration: 0.22s;
  }
}

/* While another day's times are asked for, the times stand as quiet
   blocks in their own places, so nothing moves when they arrive. */
.booking__times.is-loading .booking__time span,
.booking__times.is-loading .booking__part-title span {
  border-color: transparent;
  color: transparent;
  background: var(--linen);
}

.booking__times.is-loading .booking__time span > span {
  visibility: hidden;
}

@media (prefers-reduced-motion: no-preference) {
  .booking__times.is-loading .booking__time span,
  .booking__times.is-loading .booking__part-title span {
    animation: skeleton 1.2s ease-in-out infinite alternate;
  }

  @keyframes skeleton {
    to {
      background: #e6dccb;
    }
  }
}

/* ---------------------------------------------- Google's route to the salon */

.find__directions {
  margin: 0 0 28px;
}

/* ------------------------------------------- the route, drawn as it is read */

.find__walk {
  grid-column: 1 / -1;
}

/* The plan beside the steps; on a narrow screen it stays in view above
   them while they pass, at a size that leaves the step being read. */
.walk {
  display: grid;
  gap: clamp(20px, 4vw, 56px);
}

.walk__map {
  position: sticky;
  top: 12px;
  z-index: 1;
  align-self: start;
  padding: 8px;
  border: 1px solid var(--line);
  background: #fffdf9;
}

.walk__drawing {
  display: block;
  width: 100%;
  max-height: 38vh;
  height: auto;
}

.walk__leg {
  fill: none;
  stroke: var(--ink);
  stroke-width: 4;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 1;
  stroke-dashoffset: 0;
}

.walk.is-walking .walk__leg {
  stroke-dashoffset: 1;
  transition: stroke-dashoffset 1s cubic-bezier(0.4, 0, 0.2, 1);
}

.walk.is-walking .walk__leg.is-drawn {
  stroke-dashoffset: 0;
}

.walk__steps {
  display: grid;
  gap: clamp(28px, 8vh, 72px);
  margin: 0;
  padding: 0 0 0 1.4em;
}

.walk__photo img {
  width: 100%;
  aspect-ratio: 4 / 3;
  height: auto;
  object-fit: cover;
}

.walk__text {
  max-width: 48ch;
  margin: 12px 0 0;
}

@media (min-width: 900px) {
  .walk {
    grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
  }

  .walk__map {
    top: 24px;
  }

  .walk__drawing {
    max-height: 80vh;
  }
}

/* --------------------------------------------------------- the salon's work */

/* Two across on a phone, three on a wide screen; each photograph framed
   to one shape so the grid reads as one piece (session 30). */
.portfolio__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(8px, 2vw, 20px);
  margin-top: clamp(40px, 6vw, 64px);
  margin-bottom: 0;
  padding: 0;
  list-style: none;
}

.portfolio__photo img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 5;
  object-fit: cover;
}

@media (min-width: 900px) {
  .portfolio__grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* ------------------------------------------------- the salon's mark, drawn */

/* In place of the signboard's photograph (session 31): night, the mark in
   paper, a mist hairline set in from the edge, and no brass. */
.plaque {
  margin: 0;
  max-width: 520px;
}

.plaque__drawing {
  display: block;
  width: 100%;
  height: auto;
}

.plaque__ground {
  fill: var(--night);
}

.plaque__line {
  fill: none;
  stroke: var(--mist);
  stroke-width: 1.5;
  opacity: 0.6;
}

.plaque__mark {
  color: var(--paper);
}

/* -------------------------------------- under the member card (session 31) */

.magain {
  max-width: 25rem;
  margin: 0 0 16px;
}

.magain__button {
  width: 100%;
}

.mwallet {
  max-width: 25rem;
  margin: 0 0 16px;
}

.mwallet__button {
  width: 100%;
}

.magain__title {
  margin: 0 0 8px;
  font: 600 0.6875rem/1.3 var(--font-body);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* The visits and the points behind the card, as quiet ruled lists. */
.mhistory {
  max-width: 25rem;
  margin: 28px 0;
}

.mhistory__title {
  margin: 0 0 10px;
  font: 500 1.25rem/1.25 var(--font-display);
}

.mhistory__none {
  margin: 0;
  color: var(--ink-2);
}

.mhistory__list {
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--line);
}

.mhistory__list li {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 2px 12px;
  padding: 12px 0;
  border-bottom: 1px solid var(--line);
}

.mhistory__day {
  grid-column: 1;
  font-size: 0.8125rem;
  color: var(--ink-3);
}

.mhistory__what {
  grid-column: 1;
}

.mhistory__points {
  grid-column: 2;
  grid-row: 1 / span 2;
  align-self: center;
  font-weight: 600;
  font-variant-numeric: tabular-nums lining-nums;
}

/* --------------------------------- the booking form, knowing who it is for */

/* Each service with how long it takes and what it costs. */
.booking__service-text {
  display: grid;
  gap: 3px;
}

.booking__service-meta {
  font-size: 0.875rem;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums lining-nums;
}

.booking__service-part {
  white-space: nowrap;
}

.booking__range-note {
  margin-top: 4px;
}

/* Book again: a member's last service, one tap from the day. */
.booking__again {
  display: grid;
  gap: 8px;
  margin: 0 0 22px;
  padding: 16px;
  border: 1px solid var(--line-strong);
  background: #fffdf9;
}

.booking__again-title {
  margin: 0;
  font: 600 0.6875rem/1.3 var(--font-body);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.booking__again p:last-child {
  margin: 0;
}

/* The person the salon knows, in place of their name and number. */
.booking__known {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 4px 16px;
  margin: 0 0 18px;
  padding: 14px 16px;
  border: 1px solid var(--line-strong);
  background: #fffdf9;
}

.booking__known p {
  display: grid;
  gap: 2px;
  margin: 0;
}

.booking__known-as {
  font-weight: 600;
}

.booking__known-phone {
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}

.booking__known-change {
  min-height: 44px;
  padding: 0;
  border: 0;
  font: 500 0.9375rem/1.3 var(--font-body);
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 0.3em;
  background: none;
  cursor: pointer;
}

/* ---------------------------------------------------------------- Joker */

/* The questions in the page, as the old questions were drawn, beside his
   portrait (session 31, decision 0037). No brass: Book and the member
   card's frame keep it. */
.joker__body {
  display: grid;
  gap: 24px;
  justify-items: center;
  margin-top: clamp(32px, 5vw, 56px);
}

.joker__portrait {
  width: 120px;
  height: 120px;
  border-radius: 50%;
  background: var(--linen);
}

.joker__list {
  width: 100%;
  max-width: 780px;
  border-top: 1px solid var(--line);
}

.joker__item {
  border-bottom: 1px solid var(--line);
}

.joker__question {
  display: flex;
  align-items: center;
  gap: 16px;
  min-height: 64px;
  padding: 12px 0;
  font: 500 clamp(1.2rem, 1.05rem + 0.6vw, 1.45rem)/1.25 var(--font-display);
  list-style: none;
  cursor: pointer;
}

.joker__question::-webkit-details-marker {
  display: none;
}

.joker__question::before {
  content: "";
  flex: none;
  width: 8px;
  height: 8px;
  border: 1px solid var(--ink-3);
  transform: rotate(45deg);
}

.joker__item[open] .joker__question::before {
  border-color: var(--ink);
  background: var(--ink);
}

.joker__answer {
  max-width: 62ch;
  padding: 0 0 20px 24px;
  color: var(--ink-2);
}

.joker__answer p {
  margin: 0 0 8px;
}

.joker__links {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 18px;
}

.joker__links a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

/* The floating button: night, his face and two words, above the Book bar
   on a phone. */
.joker-fab {
  position: fixed;
  z-index: 11;
  right: 16px;
  bottom: calc(88px + env(safe-area-inset-bottom));
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-height: 52px;
  padding: 6px 18px 6px 6px;
  border: 1px solid rgb(246 241 233 / 0.18);
  border-radius: 999px;
  font: 600 0.9375rem/1 var(--font-body);
  color: var(--paper);
  background: var(--night);
  box-shadow: 0 10px 28px -12px rgb(21 18 14 / 0.6);
  cursor: pointer;
}

.joker-fab__face {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--linen);
}

@media (min-width: 900px) {
  .joker-fab {
    right: 24px;
    bottom: 24px;
  }
}

/* The panel: paper, his answers on linen, the visitor's taps on ink. */
.joker-panel {
  width: min(420px, calc(100vw - 24px));
  max-height: min(640px, calc(100dvh - 24px));
  margin: auto 12px 12px auto;
  padding: 0;
  border: 1px solid var(--line-strong);
  border-radius: 14px;
  color: var(--ink);
  background: var(--paper);
  box-shadow: 0 24px 60px -24px rgb(21 18 14 / 0.55);
}

.joker-panel[open] {
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
}

.joker-panel::backdrop {
  background: rgb(21 18 14 / 0.35);
}

.joker-panel__head {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 12px 12px 16px;
  border-bottom: 1px solid var(--line);
}

.joker-panel__face {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--linen);
}

.joker-panel__title {
  flex: 1;
  margin: 0;
  font: 500 1.35rem/1.1 var(--font-display);
}

.joker-panel__close {
  min-height: 44px;
  padding: 0 12px;
  border: 0;
  font: 500 0.9375rem/1 var(--font-body);
  color: var(--ink);
  background: none;
  text-decoration: underline;
  text-underline-offset: 0.3em;
  cursor: pointer;
}

.joker-panel__log {
  display: grid;
  align-content: start;
  gap: 10px;
  padding: 16px;
  overflow-y: auto;
  overscroll-behavior: contain;
}

.joker-bubble {
  max-width: 88%;
  margin: 0;
  padding: 10px 14px;
  border-radius: 14px;
  line-height: 1.45;
}

.joker-bubble p {
  margin: 0 0 6px;
}

.joker-bubble p:last-child {
  margin: 0;
}

.joker-bubble--joker {
  justify-self: start;
  border-bottom-left-radius: 4px;
  background: var(--linen);
}

.joker-bubble--visitor {
  justify-self: end;
  border-bottom-right-radius: 4px;
  color: var(--paper);
  background: var(--ink);
}

.joker-bubble .joker__links a {
  min-height: 44px;
}

.joker-panel__choices {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  max-height: 40vh;
  padding: 12px 16px 16px;
  overflow-y: auto;
  border-top: 1px solid var(--line);
}

.joker-choice {
  min-height: 44px;
  padding: 0 14px;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  font: 500 0.9375rem/1.2 var(--font-body);
  color: var(--ink);
  background: #fffdf9;
  cursor: pointer;
}

.joker-choice:active {
  border-color: var(--ink);
  background: var(--linen);
}

/* ---------------------------------------------------- LINE's own buttons */

/* Every LINE button on the customer side in LINE's green with LINE's mark
   in white, as LINE's login button is drawn (run 30, decision 0038). The
   label is night, not LINE's white: white on this green is 2.3 to 1, under
   what WCAG asks of text. Hover and press darken by LINE's own steps. The
   mark never moves on its own. */
.button--line {
  gap: 10px;
  border-color: #06c755;
  color: var(--night);
  background: #06c755;
}

.button--line:hover {
  border-color: #05b34c;
  color: var(--night);
  background: #05b34c;
}

.button--line:active {
  border-color: #048b3b;
  background: #048b3b;
  filter: none;
}

.button--line .line-mark {
  flex: none;
  width: 22px;
  height: 22px;
  color: #fff;
}

/* At most one gentle lift, the first time the button is seen (line.js),
   never again and never for a reader who asked for less motion. */
@media (prefers-reduced-motion: no-preference) {
  .button--line.is-nudged {
    animation: line-nudge 0.7s cubic-bezier(0.2, 0.7, 0.2, 1) 1;
  }

  @keyframes line-nudge {
    40% {
      translate: 0 -3px;
    }
  }
}

/* --------------------------------------------------- the room, full bleed */

/* The page's one cinematic moment (run 30), within decision 0036's limits:
   the photograph holds still behind (sticky, which never takes the scroll
   over), a short line scrolls up across it, and the photograph eases a
   little in scale on the scroll's own timeline. Under reduced motion it is
   a still photograph with the line over it. */
.scene {
  position: relative;
  display: grid;
  color: var(--paper);
  background: var(--night);
  view-timeline-name: --scene;
}

.scene__media,
.scene__text {
  grid-area: 1 / 1;
}

.scene__media {
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: hidden;
  align-self: start;
}

.scene__media picture,
.scene__media img {
  display: block;
  width: 100%;
  height: 100%;
}

.scene__media img {
  object-fit: cover;
}

/* A wash of night so the line reads over any part of the photograph. */
.scene__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgb(21 18 14 / 0.5) 0%, rgb(21 18 14 / 0.72) 100%);
}

.scene__text {
  position: relative;
  z-index: 1;
  display: grid;
  align-content: start;
  justify-items: center;
  gap: 14px;
  padding: 72svh var(--gutter) 48svh;
  text-align: center;
}

.scene__text .eyebrow {
  margin: 0;
  color: var(--mist);
}

.scene__line {
  max-width: 18ch;
  margin: 0;
  font: 500 clamp(2rem, 1.4rem + 3vw, 3.4rem)/1.12 var(--font-display);
  color: var(--paper);
  text-shadow: 0 1px 24px rgb(21 18 14 / 0.45);
}

@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    .scene__media img {
      animation: scene-ease linear both;
      animation-timeline: --scene;
      animation-range: contain;
    }

    @keyframes scene-ease {
      from {
        scale: 1;
      }

      to {
        scale: 1.06;
      }
    }
  }
}

@media (prefers-reduced-motion: reduce) {
  .scene__media {
    position: relative;
    height: auto;
    align-self: stretch;
  }

  .scene__text {
    padding-block: 30svh;
  }
}

/* The membership agreement a member signed at the counter (run 34). */
.agreement__rows {
  display: grid;
  gap: 8px;
  margin: 16px 0;
}

.agreement__rows div {
  display: grid;
  grid-template-columns: minmax(8rem, 1fr) 2fr;
  gap: 12px;
}

.agreement__rows dt {
  color: var(--ink-3);
}

.agreement__rows dd {
  margin: 0;
}

.agreement__signature {
  margin: 16px 0;
}

.agreement__signature img {
  display: block;
  width: 100%;
  max-width: 600px;
  height: auto;
  border: 1px solid var(--line);
  background: #fff;
}

/* Special dates (run 35): under the week's hours, and on the booking form. */
.hours__special-title {
  margin: 16px 0 4px;
  font-weight: 600;
}

.hours__special {
  margin: 0;
  padding-left: 1.1em;
}

.booking__special {
  margin: 0 0 12px;
  padding: 10px 14px;
  border-left: 3px solid var(--ink);
  background: var(--linen);
}

/* Flags beside the systems' countries (run 35), drawn by us; a hairline so
   Japan's white field shows on paper. */
.flag {
  display: inline-block;
  height: 0.9em;
  width: auto;
  margin-right: 0.45em;
  vertical-align: -0.08em;
  box-shadow: 0 0 0 1px var(--line-strong);
}

/* The nearest stations as line-coloured badges (run 35, amending 0017 for
   these badges alone): the line's colour, white words, Lucide's train. */
.transit {
  display: grid;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.transit__badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px 3px 8px;
  border-radius: 999px;
  font-weight: 600;
  color: #fff;
}

.transit__badge--bts-silom {
  background: var(--line-bts-silom);
}

.transit__badge--mrt-blue {
  background: var(--line-mrt-blue);
}

.transit__icon {
  width: 1em;
  height: 1em;
}

.transit__note {
  color: var(--ink-3);
}

/* The Google reviews row (run 35): swiped, or moved slowly by reviews.js
   with Pause; never under reduced motion. */
.reviews__row {
  display: grid;
  gap: 12px;
  margin-top: 24px;
}

.reviews__pause {
  justify-self: end;
}

.reviews__track {
  display: flex;
  gap: 16px;
  margin: 0;
  padding: 4px 0 12px;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  list-style: none;
}

.review {
  flex: 0 0 min(320px, 82vw);
  display: grid;
  align-content: start;
  gap: 8px;
  padding: 18px;
  border: 1px solid var(--line);
  background: var(--paper);
}

.review p {
  margin: 0;
}

.review__stars {
  letter-spacing: 0.1em;
  color: var(--ink);
}

.review__text {
  display: -webkit-box;
  -webkit-line-clamp: 8;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.review__who {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  color: var(--ink-3);
}

.review__initial {
  display: inline-grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  font-weight: 600;
  color: var(--paper);
  background: var(--ink-2);
}

.review__name {
  font-weight: 600;
  color: var(--ink);
}

.reviews__attribution {
  margin: 0;
  color: var(--ink-3);
}
