/* Layout idea: one dark steel plate. Every section sets its label and heading in the left five columns and a hairline-ruled board in the right seven; on phones the same two parts stack in that order. */
:root {
  color-scheme: dark;

  /* Surfaces: charcoal matched to the logo's own plate, with its very slight cool bias */
  --ground: #191b1b;
  --ground-deep: #111313;
  --surface: #202323;
  --glow-core: #373a39;      /* the light pool the logo sits in, sampled from the image */
  --glow-near: #333635;
  --glow-mid: #2c2f2e;
  --glow-edge: #242727;

  /* Rules */
  --line: #2f3333;
  --line-strong: #5c6262;
  --line-control: #727878;   /* the outline of a button: light enough to be seen as an edge (3:1 on the page) */

  /* Text */
  --text: #eceeee;
  --text-muted: #a9aeae;
  --text-dim: #8b9191;
  --ink: #111313;
  --ink-soft: #2c3030;

  /* Brushed steel: used on the hero headline and the top price row only.
     The headline's runs top to bottom inside each line of letters, as the chrome in the logo does. */
  --steel-type: linear-gradient(180deg, #ffffff 0%, #f4f5f5 34%, #d3d7d7 62%, #b9bebe 100%);
  --steel-plate: linear-gradient(98deg, #eef0f0 0%, #d9dcdc 36%, #c2c6c6 68%, #d5d8d8 100%);
  --steel-grain: repeating-linear-gradient(0deg, rgba(17, 19, 19, 0.045) 0 1px, rgba(17, 19, 19, 0) 1px 3px);
  --plate: #d9dcdc;          /* the same pale steel, flat: today's row in the hours */

  /* Type: two families, four weights in all. The font files and their stand-ins are set up in fonts.css.
     The "Fallback" names are faces already on the device, sized to match, for the moment before
     the real fonts arrive. */
  --font-display: "Big Shoulders Display", "Display Fallback Apple", "Display Fallback Narrow", "Display Fallback Android", "Display Fallback Impact", "Arial Narrow", sans-serif-condensed, Impact, "Helvetica Neue", Arial, sans-serif;
  --font-body: "Barlow", "Text Fallback", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --w-regular: 400;
  --w-medium: 500;
  --w-semi: 600;
  --w-display: 800;

  --size-label: 0.75rem;
  --size-small: 0.875rem;
  --size-note: 0.9375rem;
  --size-body: 1.0625rem;
  --size-row: 1.375rem;
  --size-h2: clamp(2rem, 9.2vw, 2.25rem);     /* phones: a step below the headline */
  --size-h1: clamp(2.25rem, 10.4vw, 3rem);

  /* Space */
  --gutter: clamp(1.25rem, 4vw, 3rem);
  --frame: 75rem;
  --section-space: clamp(3.25rem, 2rem + 5vw, 6rem);
  --board-pad: 0.875rem;
  --header-h: 3.75rem;
  --bar-h: 4.0625rem;
  --map-h: 25rem;            /* the tallest the map is ever shown */

  /* One corner for every boxed thing: buttons, tags, the picked-out price, today's hours. A slight curve, not a pill. */
  --radius: 6px;
  --ease: 150ms ease;
}

/* ---------- Base ---------- */

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

[hidden] { display: none !important; }

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  background: var(--ground-deep);
}

body {
  margin: 0;
  background-color: var(--ground);
  color: var(--text);
  font-family: var(--font-body);
  font-weight: var(--w-regular);
  font-size: var(--size-body);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

h1, h2, h3, p, ul, dl, dd, address, table { margin: 0; }
h1, h2, h3, th { font-size: inherit; font-weight: inherit; }
ul { padding: 0; list-style: none; }
address { font-style: normal; }
img, svg { display: block; }
img { max-width: 100%; height: auto; }
a { color: inherit; }

:focus-visible {
  outline: 2px solid #ffffff;
  outline-offset: 3px;
}
/* For anyone moving through the page with the Tab key. On a phone the action bar is fixed over the bottom
   of the screen, so every link in the page asks for the bar's height below it, and 1rem more: the browser
   then scrolls a link that takes focus clear of the bar. From 700px the header is kept clear instead. */
main a,
.site-footer a { scroll-margin-bottom: calc(var(--bar-h) + env(safe-area-inset-bottom, 0px) + 1rem); }

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

.frame {
  width: min(100% - 2 * var(--gutter), var(--frame));
  margin-inline: auto;
}

.icon { flex: none; fill: currentColor; }
.icon-sprite { position: absolute; }

/* ---------- The shop's notice (set in shop-details.txt; hidden when there is none) ---------- */

.notice {
  padding: 0.5625rem max(var(--gutter), (100% - var(--frame)) / 2);
  border-bottom: 1px solid var(--line);
  background: var(--surface);
  color: var(--text);
  font-size: var(--size-small);
  font-weight: var(--w-medium);
  line-height: 1.35;
  overflow-wrap: anywhere;   /* a long word or web address folds onto the next line */
}

.skip-link {
  position: absolute;
  left: var(--gutter);
  top: 0.5rem;
  z-index: 40;
  padding: 0.75rem 1rem;
  border-radius: var(--radius);
  background: var(--text);
  color: var(--ink);
  font-weight: var(--w-semi);
  text-decoration: none;
  transform: translateY(-300%);
}
.skip-link:focus { transform: none; }

/* ---------- Shared type ---------- */

.eyebrow {
  display: block;
  font-family: var(--font-body);
  font-size: var(--size-label);
  font-weight: var(--w-semi);
  line-height: 1.3;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.tag {
  display: inline-block;
  padding: 0.3125rem 0.625rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  font-size: var(--size-label);
  font-weight: var(--w-semi);
  line-height: 1.2;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* ---------- Buttons and links ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 3rem;
  padding: 0.25rem 1.375rem;
  border: 1px solid var(--line-control);
  border-radius: var(--radius);
  background: transparent;
  color: var(--text);
  font-family: var(--font-display);
  font-size: 1.125rem;
  font-weight: var(--w-display);
  line-height: 1;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  transition: background-color var(--ease), border-color var(--ease), color var(--ease);
}
.btn:hover {
  border-color: var(--text);
  background: var(--surface);
}

.btn--primary {
  border-color: var(--text);
  background: var(--text);
  color: var(--ink);
}
.btn--primary:hover {
  border-color: #ffffff;
  background: #ffffff;
}

.btn--compact {
  min-height: 2.75rem;
  padding-inline: 1rem;
  font-size: 1rem;
}

.text-link {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 2.75rem;
  font-weight: var(--w-semi);
  text-decoration: underline;
  text-decoration-color: var(--line-strong);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.3em;
  transition: text-decoration-color var(--ease);
}
.text-link:hover { text-decoration-color: var(--text); }
.icon--arrow { fill: none; }

.inline-link {
  display: inline-block;
  padding-block: 0.625rem;
  white-space: nowrap;
  font-weight: var(--w-medium);
  color: var(--text);
  text-decoration: underline;
  text-decoration-color: var(--line-strong);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.3em;
  transition: text-decoration-color var(--ease);
}
.inline-link:hover { text-decoration-color: var(--text); }

/* ---------- Header ---------- */

.site-header {
  background: var(--ground);
  border-bottom: 1px solid var(--line);
}

.site-header__inner {
  display: flex;
  flex-wrap: wrap;            /* only ever wraps on a very narrow screen with enlarged text */
  align-items: center;
  justify-content: space-between;
  gap: 0 0.5rem;
  min-height: var(--header-h);
}

/* The name in type, echoing the logo: heavy condensed BLADE, wide-tracked BARBER */
.wordmark {
  display: inline-flex;
  align-items: baseline;
  gap: 0.4375rem;
  padding-block: 0.625rem;
  color: var(--text);
  text-decoration: none;
  text-transform: uppercase;
  white-space: nowrap;
}
.wordmark__blade {
  font-family: var(--font-display);
  font-size: 1.625rem;
  font-weight: var(--w-display);
  line-height: 1;
  letter-spacing: 0.02em;
}
.wordmark__barber {
  font-size: 0.6875rem;
  font-weight: var(--w-semi);
  line-height: 1;
  letter-spacing: 0.3em;
  color: var(--text-muted);
}

.site-nav {
  display: flex;
  flex-wrap: wrap;            /* as the header: only with enlarged text on a very narrow screen */
  margin-right: -0.5rem;
}
.site-nav a {
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  padding-inline: 0.5rem;
  font-size: 1rem;
  font-weight: var(--w-medium);
  color: var(--text-muted);
  text-decoration: none;
  white-space: nowrap;
  transition: color var(--ease);
}
.site-nav a:hover { color: var(--text); }

/* Phones: the menu closes up a little, so it stays on one line beside the name */
@media (max-width: 24rem) {
  .site-nav { margin-right: -0.375rem; }
  .site-nav a { padding-inline: 0.375rem; }
}
@media (max-width: 22rem) {
  .site-header__inner { gap: 0 0.25rem; }
  .site-nav { margin-right: -0.25rem; }
  .site-nav a {
    padding-inline: 0.25rem;
    font-size: 0.9375rem;
  }
}

/* On phones the Book button lives in the bottom bar instead */
.site-header__book { display: none; }

/* ---------- Hero ---------- */

.hero {
  position: relative;
  overflow: hidden;
  border-bottom: 1px solid var(--line);
}

.hero__inner {
  display: grid;
  padding-block: 0 2.25rem;
}

/* The logo is a raster on its own charcoal plate. The edges are masked away and a matching
   pool of light sits behind it, so it reads as part of the page and not as a pasted rectangle. */
.hero__mark {
  position: relative;
  justify-self: center;
  /* As large as the screen allows, up to 300px: on a short screen it gives way so the Book button stays in view */
  width: min(18.75rem, 72vw, max(11rem, 34vh));
  width: min(18.75rem, 72vw, max(11rem, 34svh));
  margin-block: -0.25rem -0.5rem;
}
.hero__mark::before {
  content: "";
  position: absolute;
  inset: -45%;
  /* Centred low, like the light in the image itself, and faded out before the hero's own edges */
  background: radial-gradient(ellipse closest-side at 50% 58%,
    var(--glow-core) 0%,
    var(--glow-near) 30%,
    var(--glow-mid) 55%,
    var(--glow-edge) 76%,
    rgba(25, 27, 27, 0) 100%);
  -webkit-mask-image: linear-gradient(to bottom, transparent 24%, #000 46%, #000 70%, transparent 90%);
  mask-image: linear-gradient(to bottom, transparent 24%, #000 46%, #000 70%, transparent 90%);
  pointer-events: none;
}
.hero__emblem {
  position: relative;
  width: 100%;
  -webkit-mask-image:
    linear-gradient(to right, transparent 0%, #000 19%, #000 81%, transparent 100%),
    linear-gradient(to bottom, transparent 0%, #000 12%, #000 90%, transparent 100%);
  -webkit-mask-composite: source-in;
  mask-image:
    linear-gradient(to right, transparent 0%, #000 19%, #000 81%, transparent 100%),
    linear-gradient(to bottom, transparent 0%, #000 12%, #000 90%, transparent 100%);
  mask-composite: intersect;
}

.hero__copy { position: relative; }

/* The one line that says where the shop is: a size up from the other small labels */
.hero__eyebrow {
  margin-bottom: 0.625rem;
  font-size: var(--size-small);
  letter-spacing: 0.18em;
}

.hero__headline {
  display: block;
  color: var(--text);
}
.hero__line {
  display: block;
  font-family: var(--font-display);
  font-size: var(--size-h1);
  font-weight: var(--w-display);
  line-height: 0.94;
  letter-spacing: 0.012em;
  text-transform: uppercase;
}
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .hero__line {
    background-image: var(--steel-type);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
  }
}

/* Open or closed. The line holds its height before script.js fills it in, so the buttons below never jump. */
.status {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  min-height: 1.3em;
  margin-top: 1.125rem;
  font-size: 1rem;
  font-weight: var(--w-medium);
  line-height: 1.3;
  color: var(--text);
}
.status__dot {
  flex: none;
  width: 0.625rem;
  height: 0.625rem;
  border: 2px solid var(--text);
  border-radius: 50%;
  background: var(--text);
}
/* Open is a solid dot, closed is a hollow ring: no colour needed to tell them apart */
.status[data-state="closed"] .status__dot {
  border-color: var(--text-muted);
  background: transparent;
}
.status:not([data-state]) .status__dot { visibility: hidden; }
.status--quiet {
  margin-top: 1.25rem;
  color: var(--text-muted);
}

/* Walk-ins: a quiet line under the hero status, lined up with its text */
.hero__walkins {
  margin-top: 0.25rem;
  padding-left: 1.25rem;
  font-size: var(--size-note);
  font-weight: var(--w-medium);
  line-height: 1.35;
  color: var(--text-muted);
}

/* With JavaScript switched off there is no open/closed line, so its space closes up */
@media (scripting: none) {
  .status { display: none; }
  .hero__walkins {
    margin-top: 1.125rem;
    padding-left: 0;
  }
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 1.125rem;
}
/* Book takes the full width; Call and Directions share the line below, and stack if they cannot both fit */
.hero__actions .btn {
  flex: 1 1 auto;
  padding-inline: 0.75rem;
}
.hero__actions .hero__call { flex-grow: 2; }
.hero__actions .hero__book {
  flex-basis: 100%;
  min-height: 3.25rem;
  font-size: 1.25rem;
}

.socials {
  display: flex;
  gap: 0.25rem;
}
.socials a {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: var(--radius);
  color: var(--text-muted);
  transition: color var(--ease);
}
.socials a:hover { color: var(--text); }
.hero__socials {
  margin-top: 0.75rem;
  margin-left: -0.75rem;
}

/* ---------- Sections ---------- */

.section { scroll-margin-top: 0.5rem; }

.section__grid {
  display: grid;
  gap: 1.75rem;
  padding-block: var(--section-space);
}
.section + .section .section__grid { border-top: 1px solid var(--line); }

.section__title,
.closing__title {
  font-family: var(--font-display);
  font-size: var(--size-h2);
  font-weight: var(--w-display);
  line-height: 0.96;
  letter-spacing: 0.012em;
  text-transform: uppercase;
  text-wrap: balance;
}
.section__head .eyebrow { margin-bottom: 0.625rem; }
.section__lede {
  margin-top: 0.875rem;
  color: var(--text-muted);
}
.section__after { margin-top: 1.125rem; padding-inline: var(--board-pad); }

/* ---------- Boards: the price list, the hours and the details share one ruled pattern ---------- */

.board {
  width: 100%;
  border-top: 1px solid var(--line-strong);
}

/* Prices: four groups, each a small tracked label over its own board */
.price-group + .price-group { margin-top: 2.25rem; }
.price-group__title {
  padding: 0 var(--board-pad) 0.6875rem;
  color: var(--text);
}

.price {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  column-gap: 1rem;
  padding: 0.875rem var(--board-pad) 0.8125rem;
  border-bottom: 1px solid var(--line);
}
.price__name {
  font-family: var(--font-display);
  font-size: var(--size-row);
  font-weight: var(--w-display);
  line-height: 1.1;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  overflow-wrap: anywhere;   /* a word too long for the line folds, so it can never run under the price */
}
/* A long name breaks into two even lines. Names with a qualifier are left alone, so the qualifier drops as one piece. */
.price__name:not(:has(.price__qualifier)) { text-wrap: balance; }
/* Keeps a short hyphenated word such as line-up in one piece when a name wraps */
.price__keep { white-space: nowrap; }
.price__qualifier {
  font-family: var(--font-body);
  font-size: var(--size-small);
  font-weight: var(--w-medium);
  letter-spacing: 0;
  text-transform: none;
  color: var(--text-muted);
  white-space: nowrap;
}
/* On phones every qualifier sits on its own line under the name, so neighbouring rows match */
@media (max-width: 26rem) {
  .price__qualifier {
    display: block;
    margin-top: 0.25rem;
    line-height: 1.35;
  }
}
.price__amount {
  font-family: var(--font-display);
  font-size: 1.625rem;
  font-weight: var(--w-display);
  line-height: 1;
  letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
}
.price__note {
  grid-column: 1 / -1;
  margin-top: 0.25rem;
  font-size: var(--size-note);
  font-weight: var(--w-medium);
  line-height: 1.35;
  color: var(--text-muted);
  text-wrap: pretty;
}

/* The top package, set as a plate of brushed steel with dark lettering */
.price--top {
  margin-block: 0.75rem;
  padding-block: 1.125rem 1rem;
  border-bottom: 0;
  border-radius: var(--radius);
  background-color: var(--plate);
  background-image: var(--steel-grain), var(--steel-plate);
  color: var(--ink);
}
.price--top .price__amount { font-size: 2rem; }
/* On the pale plate the small print and the description are dark, like the name */
.price--top .price__qualifier,
.price--top .price__note { color: var(--ink-soft); }
.price--top:last-child { margin-bottom: 0; }
/* The plate has no rule of its own, so the row after it brings one */
.price--top + .price { border-top: 1px solid var(--line); }

/* Hours */
.hours {
  border-collapse: separate;   /* separate, not collapsed, so today's bar can have curved corners */
  border-spacing: 0;
  font-variant-numeric: tabular-nums;
}
.hours th,
.hours td {
  padding: 0.9375rem var(--board-pad);
  border-bottom: 1px solid var(--line);
  font-weight: var(--w-medium);
  line-height: 1.3;
  color: var(--text);
}
.hours th {
  padding-right: 0.5rem;
  text-align: left;
}
/* The times stay on one line wherever they fit, which is everywhere at the usual text size.
   With the device's text size turned up on a small phone they fold, and the page still fits the screen. */
.hours td {
  padding-left: 0;
  text-align: right;
}
.hours .hours__closed { color: var(--text-dim); }

/* Today: a pale bar with dark lettering, the same steel as the picked-out price. script.js adds the "Today" tag. */
.hours .is-today th,
.hours .is-today td {
  border-bottom-color: transparent;
  background: var(--plate);
  color: var(--ink);
  font-weight: var(--w-semi);
}
.hours .is-today th { border-radius: var(--radius) 0 0 var(--radius); }
.hours .is-today td { border-radius: 0 var(--radius) var(--radius) 0; }
/* The hairline above today's bar steps aside, so the curved corners stay clean */
.hours tr:has(+ .is-today) th,
.hours tr:has(+ .is-today) td { border-bottom-color: transparent; }
.tag--today {
  margin-left: 0.5rem;
  padding: 0.1875rem 0.4375rem;
  border-color: var(--ink-soft);
  color: var(--ink);
  vertical-align: 0.125em;
}
/* The smallest phones have no room for the tag beside a long day name: the pale bar alone marks today.
   The word stays in the page for screen readers. */
@media (max-width: 22rem) {
  .tag--today {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }
}

/* Details */
.detail {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  column-gap: 1rem;
  padding: 1rem var(--board-pad);
  border-bottom: 1px solid var(--line);
}
.detail dt {
  grid-column: 1;
  margin-bottom: 0.25rem;
  font-size: var(--size-label);
  font-weight: var(--w-semi);
  line-height: 1.3;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.detail dd {
  grid-column: 1;
  font-size: 1.125rem;
  font-weight: var(--w-medium);
  line-height: 1.35;
}
.detail address span { display: inline-block; }
/* A plain value that wraps breaks into two even lines, so no word is left alone. The address sets its own breaks. */
.detail dd:not(:has(address)) { text-wrap: balance; }
.detail .detail__action {
  grid-column: 2;
  grid-row: 1 / span 2;
}
.detail__action .btn { min-width: 6.75rem; }
/* The smallest phones: Directions drops under the address, which then has the full width to itself
   and folds evenly, so the postcode is never split */
@media (max-width: 22rem) {
  .detail .detail__action {
    grid-column: 1;
    grid-row: auto;
    margin-top: 0.75rem;
  }
  .detail address span { text-wrap: balance; }
}
/* The phone number and the Booksy line are links in their own right, with room around them for a thumb */
.detail__link {
  display: inline-block;
  padding-block: 0.625rem;
  margin-block: -0.625rem;
  white-space: nowrap;
  color: var(--text);
  text-decoration: underline;
  text-decoration-color: var(--line-control);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.3em;
  transition: text-decoration-color var(--ease);
}
.detail__link:hover { text-decoration-color: var(--text); }

/* ---------- Map ---------- */

/* A stored picture, 856 by 536, with the shop and its pin at the exact centre. The frame is the full width
   of the column, five wide to four tall on a phone and never taller than --map-h. The picture keeps a
   sensible scale and is trimmed evenly around its centre to fit, so the pin stays on the shop at every width. */
.map { margin-top: 1.75rem; }
.map__link {
  position: relative;
  display: block;
  overflow: hidden;
  width: 100%;               /* stated, so the height limit below cannot narrow the frame */
  aspect-ratio: 5 / 4;
  max-height: var(--map-h);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  background: var(--surface);
}
/* Browsers too old to know aspect-ratio get a plain fixed height */
@supports not (aspect-ratio: 1) {
  .map__link { height: 17.5rem; }
}
.map__link:hover { border-color: var(--text); }
.map__img {
  position: absolute;
  top: 50%;
  left: 0;
  width: 100%;
  max-width: none;
  height: var(--map-h);
  margin-top: calc(var(--map-h) / -2);
  object-fit: cover;
  object-position: 50% 50%;
}
/* A faint ripple around the foot of the pin. It only shows while it moves (see Motion, at the end). */
.map__pulse {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 2.75rem;
  height: 1.125rem;
  margin: -0.5625rem 0 0 -1.375rem;
  border: 2px solid var(--text);
  border-radius: 50%;
  opacity: 0;
  pointer-events: none;
}
/* The credit the map data's licence asks for */
.map__credit {
  font-size: var(--size-label);
  line-height: 1.3;
  text-align: right;
  color: var(--text-dim);
}
/* The link is 44px tall for a thumb. The extra height is below the words, in the empty space under the map,
   and the margin takes it back out so nothing around it moves. */
.map__credit a {
  display: inline-block;
  padding-block: 0.5rem 1.375rem;
  margin-bottom: -0.875rem;
  text-decoration: underline;
  text-decoration-color: var(--line-strong);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.3em;
}
.map__credit a:hover { color: var(--text); }

/* ---------- Reviews ---------- */

/* The rating on Google: a large numeral, five stars and the number of reviews, on one ruled row.
   script.js hides the whole block when shop-details.txt gives no sensible rating or number of reviews. */
.rating {
  display: flex;
  align-items: center;
  gap: 1rem 1.25rem;
  padding: 1.25rem var(--board-pad) 1.125rem;
  border-bottom: 1px solid var(--line);
}
.rating__score {
  font-family: var(--font-display);
  font-size: 4.5rem;
  font-weight: var(--w-display);
  line-height: 0.8;
  letter-spacing: 0.01em;
  font-variant-numeric: tabular-nums;
}
.rating__detail {
  display: grid;
  justify-items: start;
  gap: 0.4375rem;
}
.rating__count {
  font-size: var(--size-note);
  font-weight: var(--w-medium);
  line-height: 1.3;
  color: var(--text-muted);
}

/* Five stars in the page's greys: a dim row, with a pale row on top of it cut off at the rating.
   "--rating" is set on the element, in index.html and by script.js: 4.6 lights 92% of the row. */
.stars {
  position: relative;
  display: inline-flex;
  color: var(--line-strong);
}
.stars__row { display: flex; }
.stars__row--lit {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  overflow: hidden;
  width: calc(var(--rating, 0) / 5 * 100%);
  color: var(--text);
}

/* The quotes: rows of one board on a phone, three boards side by side on a wide screen (see "From 900px") */
.quote {
  display: flex;
  flex-direction: column;
  margin: 0;
  padding: 1.25rem var(--board-pad) 1.125rem;
  border-bottom: 1px solid var(--line);
}
.quote__text {
  margin: 0;
  font-size: 1.125rem;
  font-weight: var(--w-medium);
  line-height: 1.45;
  text-wrap: pretty;
  overflow-wrap: anywhere;   /* a long word or web address folds onto the next line */
}
/* The quotation marks belong to the page, not to the words in reviews.txt.
   The opening mark hangs in the margin, so the first letter lines up with the lines under it. */
.quote__text p { text-indent: -0.3em; }
.quote__text p::before { content: "\201C"; }
.quote__text p::after { content: "\201D"; }
/* The name sits at the foot of its quote behind a short rule, so three names line up when the quotes differ in length */
.quote__by {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  margin-top: auto;
  padding-top: 0.875rem;
  font-size: var(--size-label);
  font-weight: var(--w-semi);
  line-height: 1.3;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--text-muted);
  overflow-wrap: anywhere;
}
.quote__by::before {
  content: "";
  flex: none;
  width: 1.25rem;
  height: 1px;
  background: var(--line-control);
}
.section--reviews .section__after { margin-top: 1.5rem; }
/* The button's one unbroken line never sets the width of the boards above it: on a 320px phone they stay
   as wide as every other board, and the button still fits inside them. */
.reviews__wide { min-width: 0; }

/* Below 900px the rating and the quotes are rows of one board: the 1.75rem gap that .section__grid
   would leave between them is closed, and the quotes give up their own top rule. With the rating
   hidden, the quotes are a board by themselves. */
@media not all and (min-width: 900px) {
  [data-rating]:not([hidden]) + .reviews__wide { margin-top: -1.75rem; }
  [data-rating]:not([hidden]) + .reviews__wide .quotes { border-top: 0; }
}

/* ---------- About the owner ---------- */

/* The portrait. Any picture can be put in place of assets/owner-photo.jpg, so nothing here depends on
   the file: the frame is always four wide to five tall, and the picture fills it and is trimmed to fit,
   never stretched, keeping the upper middle, where a face usually is. Whatever is put there is shown in
   black and white, with a touch more contrast. On a phone the frame is 240px wide: large enough to see
   him properly, small enough that the heading above and his words below share the screen with it. */
.portrait {
  position: relative;
  overflow: hidden;
  align-self: start;         /* beside the words it keeps its own height and is never stretched to theirs */
  width: min(100%, 15rem);
  margin: 0;
  aspect-ratio: 4 / 5;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  background: var(--surface);
}
/* Browsers too old to know aspect-ratio get the same shape from padding */
@supports not (aspect-ratio: 1) {
  .portrait::before {
    content: "";
    display: block;
    padding-top: 125%;
  }
}
.portrait__img {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  max-width: none;
  height: 100%;
  border-radius: calc(var(--radius) - 1px);   /* the frame's inner curve */
  object-fit: cover;
  object-position: 50% 25%;
  filter: grayscale(1) contrast(1.05);
  /* Only seen if the picture is missing: the description, set quietly */
  color: var(--text-muted);
  font-size: var(--size-small);
}

/* A long name in the heading folds, so it can never push the page wider than the screen */
.section--about .section__title { overflow-wrap: anywhere; }

/* His own words, set as one board: the strong rule on top and the hairline underneath, like a price list.
   The first paragraph is the introduction and is set a little stronger; the rest is quieter. */
.bio {
  padding: 1.25rem var(--board-pad) 1.375rem;
  border-bottom: 1px solid var(--line);
  color: var(--text-muted);
  overflow-wrap: anywhere;   /* a long word or web address folds onto the next line */
}
.bio p { text-wrap: pretty; }
.bio p + p { margin-top: 0.875rem; }
.bio p:first-child {
  color: var(--text);
  font-size: 1.125rem;
  font-weight: var(--w-medium);
  line-height: 1.4;
}

/* ---------- Closing prompt ---------- */

.closing {
  background: var(--surface);
  border-block: 1px solid var(--line);
}
.closing__inner {
  display: grid;
  gap: 1.5rem;
  padding-block: clamp(3rem, 2rem + 4vw, 5rem);
}
.closing__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1.25rem;
}
.closing__or { color: var(--text-muted); text-wrap: balance; }
/* Two pieces that are never split when the line folds: the phone number with its full stop, and "Walk-ins welcome." */
.closing__call { white-space: nowrap; }

/* ---------- Footer ---------- */

.site-footer {
  background: var(--ground-deep);
  color: var(--text-muted);
  font-size: 1rem;
  /* Room for the fixed action bar on phones, so it never covers the footer */
  padding-bottom: calc(var(--bar-h) + env(safe-area-inset-bottom, 0px));
}
.site-footer__inner {
  display: grid;
  gap: 1.5rem;
  padding-block: 2.75rem 2rem;
}
.wordmark--footer { padding-block: 0; }
.wordmark--footer .wordmark__blade { font-size: 2.25rem; }
.wordmark--footer .wordmark__barber { font-size: 0.8125rem; }
.site-footer__est {
  margin-top: 0.5rem;
  font-size: var(--size-label);
  font-weight: var(--w-semi);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.site-footer__contact address span { display: inline-block; }
.site-footer__socials { margin-left: -0.75rem; }
.site-footer__legal {
  padding-top: 1.25rem;
  border-top: 1px solid var(--line);
  font-size: var(--size-small);
  color: var(--text-dim);
}

/* ---------- Phone action bar ---------- */

.action-bar {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 30;
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(0, 0.8fr) minmax(0, 1.1fr);
  gap: 0.5rem;
  padding: 0.5rem max(0.75rem, env(safe-area-inset-right, 0px)) calc(0.5rem + env(safe-area-inset-bottom, 0px)) max(0.75rem, env(safe-area-inset-left, 0px));
  background: var(--ground-deep);
  border-top: 1px solid var(--line-strong);
}
.action-bar__link {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 3rem;
  border: 1px solid var(--line-control);
  border-radius: var(--radius);
  color: var(--text);
  font-family: var(--font-display);
  font-size: min(1.125rem, 5vw);   /* the 5vw cap keeps "Directions" inside its button on the narrowest phones */
  font-weight: var(--w-display);
  line-height: 1;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
}
.action-bar__link--book {
  border-color: var(--text);
  background: var(--text);
  color: var(--ink);
}

/* ---------- From 700px: no action bar, two-column hero, header Book button ---------- */

@media (min-width: 700px) {
  :root {
    --size-h1: clamp(2.5rem, 5.7vw, 5.125rem);
    --size-h2: clamp(2.25rem, 0.2rem + 4.5vw, 4.25rem);
    --size-row: 1.5rem;
  }

  .site-footer { padding-bottom: 0; }
  .action-bar { display: none; }

  .site-header {
    position: sticky;
    top: env(safe-area-inset-top, 0px);
    z-index: 20;
  }
  .site-header__inner { gap: 1.5rem; }
  .site-nav {
    gap: 0.75rem;
    margin-left: auto;
    margin-right: 0;
  }
  .site-header__book { display: inline-flex; }

  .section { scroll-margin-top: var(--header-h); }
  /* No bar to keep clear of now. The header stays at the top of the screen instead, so a link reached
     with the Tab key asks for the header's height above it, and 1rem more. */
  main a,
  .site-footer a {
    scroll-margin-top: calc(var(--header-h) + env(safe-area-inset-top, 0px) + 1rem);
    scroll-margin-bottom: 0;
  }

  .hero__inner {
    grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
    align-items: center;
    column-gap: clamp(1.5rem, 4vw, 4rem);
    padding-block: clamp(2rem, 4.5vw, 4.5rem);
  }
  .hero__copy { grid-column: 1; grid-row: 1; }
  .hero__mark {
    grid-column: 2;
    grid-row: 1;
    width: min(21.25rem, 100%);   /* never wider than 340px: the source image is small */
    margin-block: 0;
  }
  /* Beside the headline the pool of light is a plain round glow. It reaches no further than the
     space to the edge of the screen, so the edge never cuts it off. */
  .hero__mark::before {
    inset: calc(-1 * min(32%, max(var(--gutter), (100vw - var(--frame)) / 2)));
    background: radial-gradient(ellipse closest-side,
      var(--glow-core) 0%,
      var(--glow-near) 30%,
      var(--glow-mid) 55%,
      var(--glow-edge) 76%,
      rgba(25, 27, 27, 0) 100%);
    -webkit-mask-image: none;
    mask-image: none;
  }
  .hero__eyebrow { margin-bottom: 0.875rem; }
  .status { margin-top: 1.5rem; font-size: 1.0625rem; }
  @media (scripting: none) {
    .hero__walkins { margin-top: 1.5rem; }
  }
  .hero__actions {
    max-width: 24rem;
    margin-top: 1.5rem;
  }
  .hero__socials { margin-top: 1rem; }

  .closing__inner {
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    column-gap: 2rem;
  }

  .site-footer__inner {
    /* The name never gives up its width: when room is short, the address folds onto two lines instead */
    grid-template-columns: minmax(max-content, 1fr) minmax(0, auto) auto;
    align-items: start;
    column-gap: clamp(2rem, 6vw, 5rem);
    padding-block: 3.5rem 2rem;
  }
  .site-footer__socials { margin-left: 0; margin-top: -0.625rem; margin-right: -0.75rem; }
  .site-footer__legal { grid-column: 1 / -1; }

  .detail {
    grid-template-columns: 7rem minmax(0, 1fr) auto;
    padding-block: 1.125rem;
  }
  .detail dt { margin-bottom: 0; }
  .detail dd { grid-column: 2; }
  .detail .detail__action { grid-column: 3; grid-row: 1; }

  /* About, from here until the two columns at 900px: the photo sits beside his words, under the heading */
  @media not all and (min-width: 900px) {
    .section--about .section__grid {
      grid-template-columns: 15rem minmax(0, 1fr);
      column-gap: 2rem;
    }
    .section--about .section__head { grid-column: 1 / -1; }
  }
}

/* ---------- From 1100px: the three hero actions sit on one line ---------- */

@media (min-width: 1100px) {
  .hero__actions {
    gap: 0.625rem;
    max-width: none;
  }
  .hero__actions .btn {
    flex: 0 1 auto;
    padding-inline: 1.375rem;
  }
  .hero__actions .hero__book { padding-inline: 1.75rem; }
}

/* ---------- From 900px: label and heading on the left, board on the right ---------- */

@media (min-width: 900px) {
  .section__grid {
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    column-gap: clamp(2.5rem, 6vw, 6rem);
    align-items: start;
  }
  /* The price list runs long, so its heading stays beside it on the way down.
     Not on short, wide screens such as a phone held sideways, where it would crowd the view. */
  @media (min-height: 30rem) {
    .section__head--follow {
      position: sticky;
      top: calc(var(--header-h) + 2.5rem);
    }
  }
  .price-group + .price-group { margin-top: 2.75rem; }
  .price { padding-block: 1rem 0.9375rem; }
  .hours th,
  .hours td { padding-block: 1.0625rem; }

  /* About: the photo goes under the heading, on the left, and his words sit beside them on the right like
     every other board. The second row takes whatever height is left over, so the photo stays close under
     the heading however long the words run. */
  .section--about .section__grid { grid-template-rows: auto 1fr; }
  .section--about .section__head {
    grid-column: 1;
    grid-row: 1;
  }
  .portrait {
    grid-column: 1;
    grid-row: 2;
    width: min(100%, 17.5rem);
  }
  .section--about .section__body {
    grid-column: 2;
    grid-row: 1 / span 2;
  }
  .bio { padding-block: 1.5rem; }
  /* 17px in the narrowest column, up to 20px once there is room, as the review quotes are; the introduction a step above */
  .bio p { font-size: clamp(1.0625rem, 0.6rem + 0.85vw, 1.25rem); }
  .bio p:first-child { font-size: clamp(1.1875rem, 0.7rem + 0.9vw, 1.375rem); }
  .bio p + p { margin-top: 1rem; }

  /* Reviews: the rating sits beside the heading like every other board; the quotes run the full width
     below, three across, each a small board of its own. One or two quotes share the width instead. */
  .reviews__wide {
    grid-column: 1 / -1;
    margin-top: 1.25rem;
  }
  .rating {
    gap: 1.5rem;
    padding-block: 1.5rem 1.375rem;
  }
  .rating__score { font-size: 6rem; }
  .quotes {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    column-gap: clamp(1.5rem, 3vw, 2.5rem);
    border-top: 0;
  }
  .quotes[data-count="2"] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .quotes[data-count="1"] { grid-template-columns: minmax(0, 44rem); }
  .quote {
    padding-block: 1.5rem 1.25rem;
    border-top: 1px solid var(--line-strong);
  }
  /* 17px in the narrowest three columns, up to 20px once there is room */
  .quote__text { font-size: clamp(1.0625rem, 0.6rem + 0.85vw, 1.25rem); line-height: 1.4; }
  .quote__by { padding-top: 1.25rem; }
  .section--reviews .section__after { margin-top: 2rem; }

  /* The footer keeps the same two columns as the sections above it */
  .site-footer__inner {
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    column-gap: clamp(2.5rem, 6vw, 6rem);
  }
  .site-footer__brand { grid-column: 1; grid-row: 1; }
  .site-footer__contact {
    grid-column: 2;
    grid-row: 1;
    padding-left: var(--board-pad);
    /* Keeps the address clear of the social icons, which share this column */
    padding-right: 9rem;
  }
  .site-footer__socials {
    grid-column: 2;
    grid-row: 1;
    justify-self: end;
  }
}

/* ---------- Page not found (404.html) ---------- */

/* The page colour runs to the bottom of the screen, however short the message */
.notfound-page { background: var(--ground); }
.notfound {
  display: grid;
  gap: 1.5rem;
  justify-items: start;
  padding-block: var(--section-space);
}
.notfound .eyebrow { margin-bottom: -0.875rem; }
.notfound__text {
  max-width: 34rem;
  color: var(--text-muted);
}
.notfound__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

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

/* ==========================================================================
   MOTION
   Everything on the site that moves is inside this one block, and the block applies only to visitors
   who have not asked their device for reduced motion. TO SWITCH ALL ANIMATION OFF, delete from the
   "@media" line below to the line marked END OF MOTION. Nothing else needs changing: the page is
   complete and fully visible without it.

   Movement is "transform" and "opacity" only, and a hover fades a colour. Nothing that sets the size
   or position of anything is ever animated, so nothing here can move the layout.
   Nothing repeats except two faint pulses (the "open now" dot and the map pin).
   Parts of the page are hidden ahead of a reveal only under ".js-motion", a class script.js adds to
   <html> once it knows it can show them again. No script, no class, nothing hidden.
   ========================================================================== */

@media (prefers-reduced-motion: no-preference) {
  :root {
    --ease-out: cubic-bezier(0.22, 0.61, 0.36, 1);   /* quick to start, gentle to stop */
    --ease-sweep: cubic-bezier(0.45, 0, 0.55, 1);    /* even: as slow to arrive as to set off */
    --tap: 180ms;        /* answers to a pointer or a finger */
    --reveal: 600ms;     /* a section fading in */
    --row: 500ms;        /* one row of a list fading in */
    --step: 55ms;        /* the gap between rows: seven steps, 385ms in all */
  }

  /* In-page links (Prices, Hours, Find us, the name in the header) glide instead of jumping */
  html { scroll-behavior: smooth; }

  /* ----- 1. Hero entrance: runs once when the page opens, with no script, and is over in about 1.2 seconds ----- */

  @keyframes settle {
    from { opacity: 0; transform: scale(1.04); }
    to { opacity: 1; transform: none; }
  }
  @keyframes rise {
    from { opacity: 0; transform: translateY(0.875rem); }
    to { opacity: 1; transform: none; }
  }

  .hero__mark { animation: settle 700ms var(--ease-out) both; }

  .hero__eyebrow,
  .hero__line,
  .hero .status,
  .hero__walkins,
  .hero__actions,
  .hero__socials { animation: rise 600ms var(--ease-out) both; }
  .hero__eyebrow { animation-delay: 80ms; }
  .hero__line:nth-child(1) { animation-delay: 150ms; }
  .hero__line:nth-child(2) { animation-delay: 220ms; }
  .hero .status { animation-delay: 320ms; }
  .hero__walkins { animation-delay: 370ms; }
  .hero__actions { animation-delay: 440ms; }
  .hero__socials { animation-delay: 540ms; }

  /* ----- 2. The steel sheen: one soft band of light, crossing once ----- */

  /* Each band fades in as it sets off and out as it arrives, so it never pops on or off */
  @keyframes sheen {
    0%, 10% { opacity: 0; }
    38%, 62% { opacity: 1; }
    90%, 100% { opacity: 0; }
    0% { transform: translateX(var(--sheen-from)) skewX(-14deg); }
    100% { transform: translateX(var(--sheen-to)) skewX(-14deg); }
  }

  /* Across the logo as the page opens. The band is grey on black and blended with "color-dodge":
     black changes nothing and grey brightens in proportion, so the bright metal of the logo catches
     the light and the dark plate around it barely does. It is at full strength only while it is over
     the emblem in the middle of the picture, and it thins out towards the top and bottom. */
  .hero__mark::after {
    --sheen-from: -43%;
    --sheen-to: 277%;
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: 30%;
    background: linear-gradient(90deg, #000000 0%, #545454 50%, #000000 100%);
    -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 16%, #000 84%, transparent 100%);
    mask-image: linear-gradient(to bottom, transparent 0%, #000 16%, #000 84%, transparent 100%);
    mix-blend-mode: color-dodge;
    opacity: 0;
    pointer-events: none;
    animation: sheen 1200ms var(--ease-sweep) 300ms both;
  }

  /* Across the picked-out price row, the first time it is on screen: script.js adds "is-lit" then.
     The band runs behind the lettering, and the row trims it at its own edges. */
  .price--top {
    position: relative;
    overflow: hidden;
    isolation: isolate;
  }
  .price--top::before {
    --sheen-from: -130%;
    --sheen-to: 560%;
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    z-index: -1;
    width: 22%;
    background: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 50%, rgba(255, 255, 255, 0) 100%);
    opacity: 0;
    pointer-events: none;
  }
  .price--top.is-lit::before { animation: sheen 1200ms var(--ease-sweep) 350ms both; }

  /* ----- 3. Reveals: each part below the first screen fades in and rises 16px, once ----- */

  .js-motion .reveal:not(.is-in) {
    opacity: 0;
    transform: translateY(1rem);
  }
  .js-motion .reveal.is-in {
    transition: opacity var(--reveal) var(--ease-out), transform var(--reveal) var(--ease-out);
  }
  .js-motion .closing__actions.reveal.is-in { transition-delay: 90ms; }

  /* Rows of the prices, the hours, the reviews and the details follow one after another, 8px further down to start with */
  .js-motion .reveal:not(.is-in) .price,
  .js-motion .reveal:not(.is-in) .detail,
  .js-motion .reveal:not(.is-in) .quote,
  .js-motion .reveal:not(.is-in) tbody > tr > * {
    opacity: 0;
    transform: translateY(0.5rem);
  }
  .js-motion .reveal.is-in .price,
  .js-motion .reveal.is-in .detail,
  .js-motion .reveal.is-in .quote,
  .js-motion .reveal.is-in tbody > tr > * {
    transition: opacity var(--row) var(--ease-out), transform var(--row) var(--ease-out);
  }
  .js-motion .reveal.is-in .price:nth-child(2),
  .js-motion .reveal.is-in .detail:nth-child(2),
  .js-motion .reveal.is-in .quote:nth-child(2),
  .js-motion .reveal.is-in tbody > tr:nth-child(2) > * { transition-delay: calc(var(--step) * 1); }
  .js-motion .reveal.is-in .price:nth-child(3),
  .js-motion .reveal.is-in .detail:nth-child(3),
  .js-motion .reveal.is-in .quote:nth-child(3),
  .js-motion .reveal.is-in tbody > tr:nth-child(3) > * { transition-delay: calc(var(--step) * 2); }
  .js-motion .reveal.is-in .price:nth-child(4),
  .js-motion .reveal.is-in .detail:nth-child(4),
  .js-motion .reveal.is-in .quote:nth-child(4),
  .js-motion .reveal.is-in tbody > tr:nth-child(4) > * { transition-delay: calc(var(--step) * 3); }
  .js-motion .reveal.is-in .price:nth-child(5),
  .js-motion .reveal.is-in .detail:nth-child(5),
  .js-motion .reveal.is-in .quote:nth-child(5),
  .js-motion .reveal.is-in tbody > tr:nth-child(5) > * { transition-delay: calc(var(--step) * 4); }
  .js-motion .reveal.is-in .price:nth-child(6),
  .js-motion .reveal.is-in .detail:nth-child(6),
  .js-motion .reveal.is-in .quote:nth-child(6),
  .js-motion .reveal.is-in tbody > tr:nth-child(6) > * { transition-delay: calc(var(--step) * 5); }
  .js-motion .reveal.is-in .price:nth-child(7),
  .js-motion .reveal.is-in .detail:nth-child(7),
  .js-motion .reveal.is-in .quote:nth-child(7),
  .js-motion .reveal.is-in tbody > tr:nth-child(7) > * { transition-delay: calc(var(--step) * 6); }
  /* A longer list stops counting here, so the last row never waits more than 385ms */
  .js-motion .reveal.is-in .price:nth-child(n + 8),
  .js-motion .reveal.is-in .detail:nth-child(n + 8),
  .js-motion .reveal.is-in .quote:nth-child(n + 8),
  .js-motion .reveal.is-in tbody > tr:nth-child(n + 8) > * { transition-delay: calc(var(--step) * 7); }

  /* ----- 4. Answers to a pointer or a finger ----- */

  /* Buttons press down a little under a finger or a click */
  .btn,
  .action-bar__link {
    transition: background-color var(--ease), border-color var(--ease), color var(--ease), transform var(--tap) var(--ease-out);
  }
  .socials .icon,
  .text-link .icon--arrow { transition: transform var(--tap) var(--ease-out); }

  /* Only where there is a real pointer, so nothing is left "stuck" lifted on a touch screen */
  @media (hover: hover) {
    .btn:hover { transform: translateY(-2px); }
    .socials a:hover .icon { transform: translateY(-2px) scale(1.08); }
    .text-link:hover .icon--arrow { transform: translateX(0.25rem); }

    /* Menu links: a hairline draws in underneath */
    .site-nav a { position: relative; }
    .site-nav a::after {
      content: "";
      position: absolute;
      right: 0.5rem;
      bottom: 0.5rem;
      left: 0.5rem;
      height: 1px;
      background: currentColor;
      transform: scaleX(0);
      transform-origin: left center;
      transition: transform 220ms var(--ease-out);
    }
    .site-nav a:hover::after { transform: scaleX(1); }

    /* Price rows: a slightly lighter band fades in behind the row under the pointer */
    .price {
      position: relative;
      isolation: isolate;
    }
    .price:not(.price--top)::before {
      content: "";
      position: absolute;
      inset: 0;
      z-index: -1;
      background: var(--surface);
      opacity: 0;
      pointer-events: none;
      transition: opacity var(--tap) linear;
    }
    .price:not(.price--top):hover::before { opacity: 1; }

    /* The map lightens a touch */
    .map__link::after {
      content: "";
      position: absolute;
      inset: 0;
      background: #ffffff;
      opacity: 0;
      pointer-events: none;
      transition: opacity var(--tap) linear;
    }
    .map__link:hover::after { opacity: 0.05; }
  }

  .btn:active,
  .action-bar__link:active { transform: translateY(1px) scale(0.985); }
  .socials a:active .icon { transform: scale(0.92); }

  /* ----- 5. The two pulses: slow (2.5 seconds) and faint ----- */

  @keyframes pulse {
    0% { opacity: 0.4; transform: scale(1); }
    70%, 100% { opacity: 0; transform: scale(2.6); }
  }
  @keyframes ripple {
    0% { opacity: 0; transform: scale(0.2); }
    15% { opacity: 0.5; }
    70%, 100% { opacity: 0; transform: scale(1); }
  }

  /* A soft halo breathes out from the dot in the hero while the shop is open.
     The quieter copy of the line, beside the hours, stays still. */
  .hero .status[data-state="open"] .status__dot { position: relative; }
  .hero .status[data-state="open"] .status__dot::after {
    content: "";
    position: absolute;
    inset: -2px;
    border-radius: 50%;
    background: var(--text);
    opacity: 0;
    animation: pulse 2500ms ease-out infinite;
  }

  /* A ring spreads from the foot of the map pin */
  .map__pulse { animation: ripple 2500ms ease-out infinite; }

  /* ----- Printing: everything is on the page, nothing mid-move ----- */

  @media print {
    *,
    *::before,
    *::after {
      animation: none !important;
      transition: none !important;
    }
    .js-motion .reveal,
    .js-motion .reveal .price,
    .js-motion .reveal .detail,
    .js-motion .reveal .quote,
    .js-motion .reveal tbody > tr > * {
      opacity: 1 !important;
      transform: none !important;
    }
  }
}

/* END OF MOTION */
