/* Bob's Barbers - site styles */

/* ---------------------------------------------------------------------------
   Design tokens
   ---------------------------------------------------------------------------
   Three decisions doing most of the work here, all of them things that separate
   a site that looks paid-for from one that does not:

   1. ONE ACCENT. The palette was carrying red, gold AND green as accents, which
      is what colour chaos looks like. Red is the barber pole and does every
      action on the site; gold is reserved for small marks of quality (stars,
      the price figure, section rules); green now only ever means "open", which
      is information rather than decoration.

   2. A REAL TYPE SCALE. Sizes were picked one at a time. They now come off a
      1.25 ratio, fluid between phone and monitor, so headings relate to each
      other instead of merely differing.

   3. SPACE ON A SCALE. Whitespace is the fastest thing that reads as premium,
      and the quickest way to lose it is inventing a new margin every time.
   --------------------------------------------------------------------------- */

:root {
  /* Ink and paper */
  --ink:        #17181c;
  --ink-soft:   #4a4d57;
  --paper:      #ffffff;
  --cream:      #f7f4ef;
  --line:       #e4dfd6;

  /* The one accent, and its pressed state */
  --red:        #b02a2a;
  --red-dark:   #8c2020;

  /* Small marks of quality only - never a button, never a whole panel */
  --gold:       #b08733;

  /* Strictly informational: this means "open", nothing else */
  --green:      #1f7a4d;

  /* Type scale, 1.25 ratio, fluid. Line heights come with the sizes because a
     50px heading and an 18px heading must not share one. */
  --t-sm:   clamp(.86rem, .84rem + .1vw, .92rem);
  --t-base: clamp(1.02rem, 1rem + .12vw, 1.09rem);
  --t-md:   clamp(1.16rem, 1.1rem + .3vw, 1.32rem);
  --t-lg:   clamp(1.45rem, 1.3rem + .75vw, 1.95rem);
  --t-xl:   clamp(1.9rem, 1.6rem + 1.5vw, 2.9rem);
  --t-2xl:  clamp(2.4rem, 1.9rem + 2.4vw, 3.9rem);

  /* Space scale */
  --sp-1: .5rem;
  --sp-2: 1rem;
  --sp-3: 1.5rem;
  --sp-4: 2.25rem;
  --sp-5: 3.5rem;
  --sp-6: 5.5rem;

  --radius:     10px;
  --shadow:     0 2px 14px rgba(23, 24, 28, .09);
  --shadow-lg:  0 14px 40px rgba(23, 24, 28, .14);
  --wrap:       1080px;

  /* Comfortable line length. Anything longer is tiring to read. */
  --measure:    68ch;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: "Segoe UI", system-ui, -apple-system, Helvetica, Arial, sans-serif;
  font-size: var(--t-base);
  line-height: 1.62;
  color: var(--ink);
  background: var(--paper);
}

h1, h2, h3 {
  font-family: Georgia, "Times New Roman", serif;
  color: var(--ink);
  margin: 0 0 .5em;
  /* A shade of negative tracking stops large serif headings looking loose. */
  letter-spacing: -.011em;
  /* Headings wrap on sensible words rather than leaving one word stranded. */
  text-wrap: balance;
}

/* Line height falls as the size rises - the same 1.2 on a 50px headline and an
   18px sub-heading makes one look airy and the other cramped. */
h1 { font-size: var(--t-2xl); line-height: 1.08; }
h2 { font-size: var(--t-xl);  line-height: 1.15; }
h3 { font-size: var(--t-md);  line-height: 1.32; letter-spacing: -.004em; }

/* Long-form text stays within a comfortable measure. One paragraph on the home
   page was running to 122 characters a line; 60-75 is the readable range. */
.measure { max-width: var(--measure); }
p { text-wrap: pretty; }

a { color: var(--red); }

.wrap {
  max-width: var(--wrap);
  margin: 0 auto;
  padding-inline: 20px;
}

/* ---------- header ---------- */
.site-header {
  background: var(--ink);
  color: #fff;
  /* Sticking is done by .site-top, which wraps this and the bar above it. */
  z-index: 50;
}
.site-header .wrap {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding-block: 14px;
  flex-wrap: wrap;
}
.brand {
  display: flex;
  align-items: center;
  gap: 16px;
  color: #fff;
  text-decoration: none;
  font-family: Georgia, serif;
  font-size: 2.7rem;          /* doubled from 1.35rem */
  line-height: 1.1;
  letter-spacing: .3px;
}
/* The pole is scaled with the text so the two still read as one mark. */
.pole {
  width: 24px;
  height: 68px;
  border-radius: 12px;
  background: repeating-linear-gradient(
    -45deg, var(--red) 0 12px, #fff 12px 24px, #2a63b5 24px 36px
  );
  border: 1px solid rgba(255, 255, 255, .5);
  flex: none;
}
.nav {
  display: flex;
  gap: 20px;
  align-items: center;
  flex-wrap: wrap;
}
.nav a {
  color: #ddd;
  text-decoration: none;
  font-size: .97rem;
}
.nav a:hover, .nav a.active { color: #fff; text-decoration: underline; }

/* ---------- buttons ---------- */
.btn {
  display: inline-block;
  background: var(--red);
  color: #fff;
  padding: 13px 26px;
  border: 0;
  border-radius: var(--radius);
  font-size: 1rem;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  transition: background .15s;
}
.btn:hover { background: var(--red-dark); }
.btn:active { transform: translateY(1px); }
.btn { transition: background .15s, transform .08s, box-shadow .15s; }
.btn-light {
  background: #fff;
  color: var(--ink);
  border: 1px solid var(--line);
}
.btn-light:hover { background: var(--cream); }
.btn-lg { padding: 16px 34px; font-size: 1.1rem; }

/* ---------- hero ---------- */
.hero {
  background: var(--ink);
  color: #fff;
  text-align: center;
  padding-block: var(--sp-6);
  position: relative;
  overflow: hidden;
}
/* A faint grid, faded away at the edges. Depth without a stock photograph and
   without introducing another colour. */
.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(rgba(255, 255, 255, .05) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, .05) 1px, transparent 1px);
  background-size: 58px 58px;
  mask-image: radial-gradient(120% 85% at 50% 0%, #000 8%, transparent 68%);
  pointer-events: none;
}
.hero .wrap { position: relative; z-index: 1; }
.hero h1 { color: #fff; }
.hero p.lead {
  font-size: var(--t-md);
  color: #ded9d1;
  max-width: 52ch;
  margin: 0 auto var(--sp-3);
}
.hero .btn-row { display: flex; gap: var(--sp-2); justify-content: center; flex-wrap: wrap; }

.open-flag {
  display: inline-block;
  font-size: .85rem;
  font-weight: 600;
  letter-spacing: .5px;
  text-transform: uppercase;
  padding: 5px 14px;
  border-radius: 99px;
  margin-bottom: 18px;
}
.open-flag.open   { background: var(--green); color: #fff; }
.open-flag.closed { background: #5a5d66; color: #fff; }

/* ---------- sections ---------- */
section { padding-block: var(--sp-5); }
@media (min-width: 900px) { section { padding-block: var(--sp-6); } }
section.cream { background: var(--cream); }
.section-head { text-align: center; max-width: 54ch; margin: 0 auto var(--sp-4); }
.section-head h2 { margin-bottom: .35em; }
.section-head p { color: var(--ink-soft); }

.grid {
  display: grid;
  gap: var(--sp-2);
  grid-template-columns: 1fr;
}

/* Two up as soon as there is room for two, and no more than two after that.
   With four cards that is two even rows rather than three and a leftover. */
@media (min-width: 620px) {
  .grid { grid-template-columns: repeat(2, 1fr); }
}

.card {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--sp-3);
  box-shadow: var(--shadow);
}
.card { transition: transform .18s ease, box-shadow .18s ease; }
.grid .card:hover { transform: translateY(-3px); box-shadow: var(--shadow-lg); }
@media (prefers-reduced-motion: reduce) {
  .card, .btn { transition: none; }
  .grid .card:hover { transform: none; }
}
.card h3 { margin-bottom: .35em; }
.card p { margin: 0; color: var(--ink-soft); }

/* Long-form pages - privacy, terms and the like. The wrap can stay wide for
   headings and tables while the running text keeps to a readable measure. */
.prose p,
.prose li { max-width: var(--measure); }

/* Small print under a form should not run the full card width either. */
.form-card > p { max-width: var(--measure); }

/* Notices and alerts carry running text, so they get a measure as well. */
.alert p { max-width: var(--measure); }

/* Centred running text, kept to a readable width. */
.note-center {
  max-width: 58ch;
  margin-inline: auto;
  text-align: center;
  color: var(--ink-soft);
}

/* ---------- hours ---------- */
.hours { width: 100%; border-collapse: collapse; }
.hours th, .hours td {
  text-align: left;
  padding: 11px 6px;
  border-bottom: 1px solid var(--line);
}
.hours th { font-weight: 600; }
.hours td { text-align: right; color: var(--ink-soft); }
.hours tr.today { background: #fffbef; }
.hours tr.today th::after {
  content: " (today)";
  color: var(--gold);
  font-weight: 400;
  font-size: .85rem;
}
/* 2.85:1 before - and "Closed" is the row people are actually looking for. */
.hours .shut { color: #6f6660; }

/* ---------- two column ---------- */
.cols {
  display: grid;
  gap: 34px;
  grid-template-columns: repeat(auto-fit, minmax(290px, 1fr));
  align-items: start;
}

.contact-list { list-style: none; margin: 0; padding: 0; }
.contact-list li { padding: 9px 0; border-bottom: 1px solid var(--line); }
.contact-list strong { display: block; font-size: .82rem; text-transform: uppercase;
  letter-spacing: .6px; color: var(--ink-soft); }

/* ---------- reviews ---------- */
/* Gold manages 3.0:1 on white, which is under AA at this size. Darkened just
   enough to clear it while still reading as gold. */
.stars { color: #8a6820; font-size: 1.3rem; letter-spacing: 3px; }
.review { font-style: italic; color: var(--ink-soft); }
.review cite { display: block; font-style: normal; font-weight: 600;
  color: var(--ink); margin-top: 10px; font-size: .92rem; }

/* ---------- advertise page ---------- */
.price-box {
  background: var(--ink);
  color: #fff;
  border-radius: var(--radius);
  padding: 32px;
  text-align: center;
}
.price-box .amount {
  font-family: Georgia, serif;
  font-size: 3.4rem;
  display: block;
  line-height: 1;
  color: var(--gold);
}
.price-box .per { color: #cfcac2; }

.steps { counter-reset: step; list-style: none; padding: 0; margin: 0; }
.steps li {
  counter-increment: step;
  position: relative;
  padding-left: 52px;
  margin-bottom: 22px;
}
.steps li::before {
  content: counter(step);
  position: absolute;
  left: 0; top: 0;
  width: 34px; height: 34px;
  border-radius: 50%;
  background: var(--red);
  color: #fff;
  font-weight: 700;
  display: grid;
  place-items: center;
}
.steps strong { display: block; }

/* ---------- forms ---------- */
.form-card {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: clamp(22px, 4vw, 38px);
  box-shadow: var(--shadow);
}
.field { margin-bottom: 20px; }
.field label {
  display: block;
  font-weight: 600;
  margin-bottom: 6px;
  font-size: .95rem;
}
.field .hint { font-weight: 400; color: var(--ink-soft); font-size: .85rem; }
.field input, .field select, .field textarea {
  width: 100%;
  padding: 12px 14px;
  border: 1px solid #c9c3ba;
  border-radius: 8px;
  font: inherit;
  font-size: 1rem;
  background: #fff;
}
.field input:focus, .field select:focus, .field textarea:focus {
  outline: 2px solid var(--red);
  outline-offset: 1px;
  border-color: var(--red);
}
.field textarea { min-height: 110px; resize: vertical; }
.field-row {
  display: grid;
  gap: 0 20px;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
}
.req { color: var(--red); }

.alert {
  padding: 14px 18px;
  border-radius: 8px;
  margin-bottom: 22px;
  border: 1px solid;
}
.alert-error   { background: #fdeceb; border-color: #e9b4b0; color: #7d1f1a; }
.alert-success { background: #e9f6ef; border-color: #a9d8c0; color: #14573a; }
.alert-info    { background: #eef3fb; border-color: #b9cbe8; color: #1c3f74; }
.alert ul { margin: 8px 0 0; padding-left: 20px; }

/* honeypot - hidden from people, visible to bots */
.hp { position: absolute; left: -9999px; opacity: 0; height: 0; }

/* ---------- footer ---------- */
.site-footer {
  background: var(--ink);
  color: #b9b5ae;
  padding-block: 38px;
  font-size: .92rem;
}
.site-footer a { color: #fff; }
.site-footer .cols { gap: 26px; }
.site-footer h3 { color: #fff; font-size: 1rem; }

/* ---------- admin ---------- */
.admin-body { background: var(--cream); }
.table-wrap { overflow-x: auto; background: #fff; border: 1px solid var(--line);
  border-radius: var(--radius); }
table.data { width: 100%; border-collapse: collapse; font-size: .93rem; }
table.data th, table.data td {
  padding: 11px 13px;
  text-align: left;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
table.data th { background: #f0ece5; font-size: .8rem; text-transform: uppercase;
  letter-spacing: .5px; }
table.data tr:last-child td { border-bottom: 0; }
.pill {
  display: inline-block;
  padding: 3px 11px;
  border-radius: 99px;
  font-size: .78rem;
  font-weight: 600;
}
.pill.new      { background: #fdf0d8; color: #7a5713; }
.pill.approved { background: #e0f2e8; color: #14573a; }
.pill.live     { background: #dfeafb; color: #1c3f74; }
.pill.paused   { background: #eceaea; color: #56514f; }
.logo-thumb { height: 34px; width: auto; max-width: 90px; object-fit: contain;
  background: #fff; border: 1px solid var(--line); border-radius: 4px; }

@media (max-width: 640px) {
  .site-header .wrap { justify-content: center; text-align: center; }
  .nav { gap: 14px; font-size: .9rem; justify-content: center; }

  /* With the big logo the header runs to a couple of hundred pixels, and the
     menu wraps over several lines. Sticking that to the top would eat a quarter
     of a phone screen for the whole visit, so on small screens it scrolls away
     like any other block. */
  .site-header { position: static; }
}

/* ---------- cookie consent ---------- */
.cookie-banner {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 200;
  background: var(--ink);
  color: #ddd8d0;
  border-top: 3px solid var(--gold);
  transform: translateY(105%);
  transition: transform .35s ease;
  box-shadow: 0 -4px 22px rgba(0, 0, 0, .28);
}
.cookie-banner.visible { transform: translateY(0); }

.cookie-inner {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 18px 20px;
  display: flex;
  gap: 20px;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
}
.cookie-text {
  margin: 0;
  font-size: .95rem;
  flex: 1 1 340px;
  line-height: 1.5;
}
.cookie-text a { color: var(--gold); }

.cookie-buttons { display: flex; gap: 10px; flex: 0 0 auto; }

/* Equal visual weight on accept and reject, as the ICO asks for. */
.cookie-btn {
  padding: 11px 26px;
  font-size: .95rem;
  min-width: 120px;
}
.cookie-btn-reject {
  background: transparent;
  color: #ddd8d0;
  border: 1px solid #55575f;
}
.cookie-btn-reject:hover { background: #24262d; }

/* ---------- map, held back until consent ---------- */
.map-holder { min-height: 330px; }
.map-placeholder {
  min-height: 330px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  text-align: center;
  padding: 26px;
  background: var(--cream);
  border: 1px dashed #c9c1b4;
  border-radius: var(--radius);
}
.map-placeholder p { margin: 0; color: var(--ink-soft); font-size: .95rem; }
.map-placeholder p strong { color: var(--ink); font-size: 1.05rem; }

@media (max-width: 560px) {
  .cookie-inner { flex-direction: column; align-items: stretch; }
  .cookie-buttons { justify-content: stretch; }
  .cookie-btn { flex: 1; }
}

/* ---------- price list ---------- */
.price-group { margin-bottom: 38px; }
.price-group h2 {
  font-size: 1.4rem;
  padding-bottom: 10px;
  margin-bottom: 0;
  border-bottom: 2px solid var(--gold);
  letter-spacing: -.008em;
}
.price-table { width: 100%; border-collapse: collapse; }
.price-table th,
.price-table td {
  padding: 13px 4px;
  border-bottom: 1px solid var(--line);
  vertical-align: baseline;
}
.price-table th {
  text-align: left;
  font-weight: 400;
}
.price-table td {
  text-align: right;
  font-weight: 700;
  white-space: nowrap;
  padding-left: 18px;
}
/* Dotted leader between the name and the price, like a proper menu board. */
.price-table th span.leader {
  display: inline-block;
  width: 100%;
}
.price-note {
  max-width: var(--measure);
  color: var(--ink-soft);
  font-size: .93rem;
  border-left: 3px solid var(--line);
  padding-left: 16px;
  margin-top: 28px;
}

/* ---------- gallery ---------- */
.gallery-grid {
  display: grid;
  gap: 16px;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
}
.gallery-grid figure { margin: 0; }
.gallery-grid > figure > label:first-of-type { cursor: zoom-in; display: block; }
.gallery-grid img {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border-radius: var(--radius);
  display: block;
  background: var(--cream);
  transition: transform .18s ease;
}
.gallery-grid > figure > label:first-of-type:hover img { transform: scale(1.02); }
.gallery-grid figcaption {
  font-size: .88rem;
  color: var(--ink-soft);
  margin-top: 8px;
}

/* Lightbox driven by a hidden checkbox, so it needs no JavaScript. */
.shot-full {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: none;
  place-items: center;
  background: rgba(10, 11, 14, .93);
  padding: 24px;
  cursor: zoom-out;
}
.shot-toggle:checked ~ .shot-full { display: grid; }
.shot-full img {
  max-width: min(94vw, 1000px);
  max-height: 82vh;
  width: auto;
  aspect-ratio: auto;
  object-fit: contain;
  border-radius: var(--radius);
}
.shot-full span {
  display: block;
  color: #ddd8d0;
  text-align: center;
  margin-top: 14px;
  font-size: .95rem;
}

@media (max-width: 480px) {
  .gallery-grid { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 12px; }
}

/* ---------- repeating rows (services, prices, links, hours) ---------- */
.repeat-row {
  display: grid;
  grid-template-columns: 1fr 1.6fr auto;
  gap: 12px;
  align-items: end;
  padding: 12px;
  margin-bottom: 10px;
  background: #fbfaf8;
  border: 1px solid var(--line);
  border-radius: 8px;
}
/* Price rows carry a third field: section, item, amount. */
.repeat-row-3 { grid-template-columns: .9fr 1.5fr .7fr auto; }

.repeat-row .field label {
  font-size: .78rem;
  text-transform: uppercase;
  letter-spacing: .5px;
  color: var(--ink-soft);
  margin-bottom: 4px;
}
.repeat-row .field input { padding: 9px 11px; font-size: .95rem; }

.repeat-row .remove-row {
  padding: 9px 14px;
  font-size: 1.1rem;
  line-height: 1;
  align-self: end;
  color: var(--ink-soft);
}
.repeat-row .remove-row:hover { color: var(--red); border-color: #e9b4b0; }

@media (max-width: 620px) {
  .repeat-row,
  .repeat-row-3 {
    grid-template-columns: 1fr;
    gap: 10px;
  }
  .repeat-row .remove-row { justify-self: start; }
}

/* Screen-content rows carry a type dropdown as well as the two text fields. */
.repeat-row-slide { grid-template-columns: .8fr 1.4fr 1.4fr auto; }
.repeat-row-slide select { padding: 9px 11px; font-size: .95rem; }
@media (max-width: 720px) {
  .repeat-row-slide { grid-template-columns: 1fr; }
}

/* ---------- menu dropdowns ---------- */
.has-drop { position: relative; }

.drop-toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  font-size: .97rem;
  color: #ddd;
  cursor: pointer;
}
.drop-toggle:hover,
.has-drop.open .drop-toggle { color: #fff; }
.drop-toggle svg { width: 14px; height: 14px; transition: transform .15s; }
.has-drop.open .drop-toggle svg { transform: rotate(180deg); }

.drop {
  position: absolute;
  top: calc(100% + 12px);
  left: 50%;
  transform: translateX(-50%);
  z-index: 60;
  min-width: 190px;
  margin: 0;
  padding: 8px 0;
  list-style: none;
  background: #23252c;
  border: 1px solid #383b44;
  border-radius: var(--radius);
  box-shadow: 0 10px 30px rgba(0, 0, 0, .35);
}
/* A little pointer up at the button it belongs to. */
.drop::before {
  content: "";
  position: absolute;
  top: -6px;
  left: 50%;
  margin-left: -6px;
  width: 11px;
  height: 11px;
  background: #23252c;
  border-left: 1px solid #383b44;
  border-top: 1px solid #383b44;
  transform: rotate(45deg);
}
.drop li { margin: 0; }
.drop a {
  display: block;
  padding: 9px 18px;
  color: #ddd;
  font-size: .95rem;
  text-decoration: none;
  white-space: nowrap;
}
.drop a:hover { background: #2e313a; color: #fff; text-decoration: none; }

@media (max-width: 640px) {
  /* Stacked on a phone: the panel sits in the flow rather than floating, so it
     cannot end up off the side of a narrow screen. */
  .has-drop { width: 100%; text-align: center; }
  .drop-toggle { justify-content: center; width: 100%; padding-block: 4px; }

  .drop {
    position: static;
    transform: none;
    min-width: 0;
    margin: 6px 0 2px;
    background: #20222a;
    box-shadow: none;
  }
  .drop::before { display: none; }
  .drop a { padding: 8px; }
}

/* ---------- trade type-to-find ---------- */
/* The real <select> stays in the form but out of sight once the combobox above
   it is running. Not display:none, so the browser still treats it as a field. */
select.tradepick-hidden,
.tradepick-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
}

.tradepick { position: relative; }

.tradepick-input {
  width: 100%;
  padding: 12px 14px;
  border: 1px solid #c9c3ba;
  border-radius: 8px;
  font: inherit;
  font-size: 1rem;
  background: #fff;
}
.tradepick-input:focus {
  outline: 2px solid var(--red);
  outline-offset: 1px;
  border-color: var(--red);
}

.tradepick-list {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  z-index: 40;
  max-height: 17rem;
  overflow-y: auto;
  margin: 0;
  padding: 6px 0;
  list-style: none;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: var(--shadow-lg);
}

.tradepick-group {
  padding: 8px 14px 4px;
  font-size: .72rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.tradepick-group:not(:first-child) {
  border-top: 1px solid var(--line);
  margin-top: 4px;
}

.tradepick-option {
  padding: 9px 14px;
  cursor: pointer;
  font-size: .97rem;
}
.tradepick-option:hover,
.tradepick-option.is-active { background: var(--cream); }
.tradepick-option mark {
  background: #fdf0d8;
  color: inherit;
  font-weight: 700;
  padding: 0 1px;
  border-radius: 2px;
}

/* Why a row is in the list when the letters typed are nowhere in its name -
   "sparky" finding Electrician. Quiet, because the trade name is the answer
   and this is only the reasoning. */
.tradepick-why {
  margin-left: 8px;
  font-size: .82rem;
  color: var(--ink-soft);
}

.tradepick-note {
  margin: 6px 0 0;
  font-size: .85rem;
  color: var(--ink-soft);
}

/* ---------- reusable page furniture ----------
   Added because the advertise page had drifted: 34 inline styles against 5-7
   on the other pages, and two different card treatments side by side. Every
   feature that got added brought its own bespoke spacing, which is exactly how
   a page stops looking like the rest of a site. These are the named versions. */

/* A card that wants picking out from its neighbours. ONE highlight treatment,
   used deliberately - not a new border colour each time. */
.panel-note {
  border-left: 4px solid var(--gold);
}

/* A heading that opens a box needs no gap above it - the box's padding is
   the gap. Saves repeating margin-top:0 on every card on every page. */
.card > :first-child,
.form-card > :first-child,
.price-box > :first-child,
.alert > :first-child { margin-top: 0; }

/* A button that fills its column - the shape used at the end of a form and
   at the foot of a panel. */
.btn-block {
  display: block;
  width: 100%;
}

/* Quiet supporting text: fine print, captions, the line under a field. */
.small-soft {
  font-size: .86rem;
  color: var(--ink-soft);
}

/* Standard vertical gaps, so nothing invents its own margin. */
.mt-1 { margin-top: var(--sp-1); }
.mt-2 { margin-top: var(--sp-2); }
.mt-3 { margin-top: var(--sp-3); }
.mt-4 { margin-top: var(--sp-4); }
.mb-0 { margin-bottom: 0; }
.mb-2 { margin-bottom: var(--sp-2); }
.mb-3 { margin-bottom: var(--sp-3); }

/* Content widths used repeatedly across the site. */
.narrow  { max-width: 760px; margin-inline: auto; }
.narrower{ max-width: 640px; margin-inline: auto; }
.wide    { max-width: 900px; margin-inline: auto; }

/* A checkbox sitting beside its label, which several forms need. */
.check-row {
  display: flex;
  gap: var(--sp-2);
  align-items: flex-start;
  font-weight: 400;
  margin: 0;
}
.check-row input[type="checkbox"] {
  width: auto;
  flex: none;
  margin-top: .35em;
}

/* The rule inside the dark price box. */
.price-box hr {
  border: 0;
  border-top: 1px solid #3a3c44;
  margin-block: var(--sp-3);
}
.price-box .small-print {
  margin: var(--sp-2) 0 0;
  text-align: left;
  font-size: var(--t-sm);
  color: #cfcac2;
}
.price-box .includes { margin: 0; text-align: left; }

/* ---------- home page photo slider ----------
   A CSS scroll-snap strip. With scripting off it is still a scrollable,
   snapping row of photos that swipes on a phone; the buttons appear only once
   slider.js confirms it is running. It never advances on its own - an
   auto-rotating carousel moves content out from under people who read slowly,
   and the photo somebody wanted is always the one that just slid away. */

.slider { position: relative; }

.slider-track {
  display: flex;
  gap: var(--sp-2);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  /* No scroll-behavior here on purpose: slider.js does the animating, because
     native smooth scrolling is silently unavailable in some browsers and in any
     backgrounded tab. Swiping and trackpad scrolling are native regardless. */
  /* Room for the focus ring, which the scroller would otherwise clip. */
  padding: 4px;
  margin: -4px;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.slider-track::-webkit-scrollbar { display: none; }
.slider-track:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: 2px;
  border-radius: var(--radius);
}

.slider-slide {
  flex: 0 0 100%;
  scroll-snap-align: start;
  margin: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--paper);
}
@media (min-width: 720px)  { .slider-slide { flex-basis: 58%; } }
@media (min-width: 1040px) { .slider-slide { flex-basis: 44%; } }

/* The ratio is declared here so the row reserves its height before a single
   photo has loaded and nothing below it jumps. */
.slider-art {
  aspect-ratio: 3 / 2;
  background: var(--cream);
  overflow: hidden;
}
.slider-art img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.slider-caption {
  padding: var(--sp-2);
  border-top: 1px solid var(--line);
  font-size: var(--t-sm);
  color: var(--ink-soft);
  margin: 0;
}

/* ---------- controls: only once the script is running ---------- */
.slider-controls { display: none; }
.slider-ready .slider-controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  margin-top: var(--sp-3);
}

.slider-btn {
  width: 48px;
  height: 48px;
  flex: none;
  display: grid;
  place-items: center;
  background: var(--paper);
  border: 2px solid var(--line);
  border-radius: 50%;
  cursor: pointer;
  color: var(--ink);
  transition: border-color .15s, color .15s;
}
.slider-btn:hover:not(:disabled) { border-color: var(--red); color: var(--red); }
.slider-btn:disabled { opacity: .35; cursor: default; }
.slider-btn svg { width: 20px; height: 20px; }

.slider-dots { display: flex; gap: .55rem; align-items: center; }
.slider-dot {
  width: 10px;
  height: 10px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--line);
  cursor: pointer;
  transition: background .15s, transform .15s;
}
.slider-dot[aria-current="true"] { background: var(--red); transform: scale(1.35); }
.slider-dot:hover { background: var(--red); }

/* Announced to screen readers as the slide changes; never shown. */
.slider-status {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

/* For people with no JavaScript, who get a plain scroller and no buttons. */
.slider-hint {
  font-size: var(--t-sm);
  color: var(--ink-soft);
  margin-top: var(--sp-2);
  text-align: center;
}
.slider-ready .slider-hint { display: none; }

/* ---------- services page ----------
   Rows rather than a grid of cards. The home page already shows these four as
   cards; repeating them adds nothing, and for a short list of similar things a
   visitor is comparing, a row reads faster than a card - the eye runs down one
   column of names instead of tracking round a grid. */

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

.service-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--sp-1) var(--sp-3);
  align-items: baseline;
  padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--line);
}

.service-row h2 {
  font-size: var(--t-md);
  margin: 0;
  /* The name is the thing being scanned, so nothing else competes with it. */
  line-height: 1.25;
}

.service-row p {
  grid-column: 1 / -1;
  margin: 0;
  color: var(--ink-soft);
  max-width: 60ch;
}

/* Only rendered when the shop has said how long something takes. */
.service-mins {
  justify-self: end;
  white-space: nowrap;
  font-size: var(--t-sm);
  color: var(--ink-soft);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 3px 12px;
  background: var(--paper);
}

@media (max-width: 520px) {
  .service-row { grid-template-columns: 1fr; }
  .service-mins { justify-self: start; }
}

/* ---------- numbered steps, services page ----------
   Named apart from .steps, which is the red-circle list on the thank-you page
   and two admin screens. Same word, different component. */
.service-steps {
  display: grid;
  gap: var(--sp-3);
  grid-template-columns: 1fr;
  counter-reset: step;
  margin: 0;
  padding: 0;
  list-style: none;
}

@media (min-width: 680px) {
  .service-steps { grid-template-columns: repeat(3, 1fr); }
}

.service-steps li {
  counter-increment: step;
  padding-top: var(--sp-2);
  border-top: 2px solid var(--ink);
}

.service-steps li::before {
  content: counter(step);
  display: block;
  font-size: var(--t-sm);
  font-weight: 700;
  letter-spacing: .04em;
  color: var(--ink);
  margin-bottom: 6px;
}

.service-steps p { margin: 0; color: var(--ink-soft); }

/* ---------- photographs behind the page header ----------
   A backdrop, not a banner of things to click. Nothing in here is interactive:
   the heading, the wording and the buttons sit still while the picture behind
   them changes, so there is no click-through to lose and nothing moves out from
   under anybody mid-sentence. */

.hero-media {
  position: absolute;
  inset: 0;
  overflow: hidden;
  background: var(--ink);
}

.hero-shot {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 1.4s ease-in-out;
}
.hero-shot.is-on { opacity: 1; }

/* The scrim is what makes white text safe over a photograph somebody uploaded
   without thinking about contrast. At .74 even a completely white picture
   leaves the heading at 7:1 and the lead paragraph at 5:1 - both clear of AA.
   Anything lighter fails the lead text, which is the paler of the two. */
.hero-media::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg, rgba(23, 24, 28, .82) 0%, rgba(23, 24, 28, .68) 45%, rgba(23, 24, 28, .82) 100%),
    rgba(23, 24, 28, .74);
}

/* The drawn grid was there to give a flat colour some depth. With a photograph
   behind the text it is just noise on top of noise. */
.hero.has-media::after { display: none; }

.hero.has-media { background: var(--ink); }
.hero.has-media .wrap { position: relative; z-index: 2; }

@media (prefers-reduced-motion: reduce) {
  .hero-shot { transition: none; }
}

/* ---------- terms page ----------
   Numbered sections so a clause can be pointed at over the phone: "have a look
   at section four". The number sits in the margin on a wide screen and inline
   on a phone, where there is no margin to put it in. */

.terms-section {
  padding-block: var(--sp-3);
  border-bottom: 1px solid var(--line);
}
.terms-section:last-of-type { border-bottom: 0; }

.terms-section h2 {
  font-size: var(--t-md);
  margin: 0 0 .4em;
  position: relative;
}

.terms-section p {
  margin: 0;
  color: var(--ink-soft);
  max-width: 68ch;
}

.terms-number {
  display: inline-block;
  min-width: 1.6em;
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
}

@media (min-width: 900px) {
  .terms-section h2 { padding-left: 0; }
  .terms-number {
    position: absolute;
    left: -2.2em;
    min-width: 0;
    text-align: right;
    width: 1.6em;
  }
}

/* The three steps to moving the site onto their own name. A list rather than
   prose because it is three figures being compared, not something read through. */
.buyout-ladder {
  margin: var(--sp-2) 0;
  padding-left: 1.1em;
  font-size: var(--t-sm);
  /* This list only ever sits inside the dark price box. The same light tone
     the rest of that box uses - 10.9:1 - rather than the grey meant for
     white backgrounds, which measured 2.1:1 here. */
  color: #cfcac2;
  text-align: left;
}
.buyout-ladder li { margin-bottom: 8px; }
.buyout-ladder li:last-child { margin-bottom: 0; }
/* The three figures are the point of the list, so they get full contrast. */
.buyout-ladder strong { color: #fff; }
.buyout-ladder ::marker { color: var(--gold); }

/* A link on the dark price box cannot use the page's red - that is 2.7:1
   against near-black. Underlined and light, so it still reads as a link. */
.price-box a {
  color: #e6e1d9;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.price-box a:hover { color: #fff; }

/* Tells somebody filling the form in what is already included, rather than
   asking them whether they want it. */
.panel-included {
  background: var(--cream);
  border: 1px solid var(--line);
  border-left: 4px solid var(--gold);
  border-radius: var(--radius);
  padding: 20px;
}

/* ---------- the business card split ----------
   500 / 500 shown as two figures rather than written into a sentence. It is the
   part people repeat back, so it gets to be the thing they look at. */
.card-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-2);
  margin: var(--sp-2) 0;
  text-align: center;
}
.card-split > div {
  padding: var(--sp-2) 6px;
  border: 1px solid rgba(255, 255, 255, .18);
  border-radius: var(--radius);
}
.card-split strong {
  display: block;
  font-size: var(--t-lg);
  line-height: 1;
  color: var(--gold);
  font-variant-numeric: tabular-nums;
}
.card-split span {
  display: block;
  margin-top: 6px;
  font-size: var(--t-sm);
  color: #cfcac2;
}

/* ---------- visitor stats ----------
   A bar per day and a track per row. No charting library for what is one number
   per day - it would be more bytes than the whole page. */

.stat-chart {
  display: flex;
  align-items: flex-end;
  gap: 2px;
  height: 90px;
  margin-top: var(--sp-2);
  padding: 0 1px;
  border-bottom: 1px solid var(--line);
}
.stat-bar {
  flex: 1;
  display: flex;
  align-items: flex-end;
  height: 100%;
  min-width: 3px;
}
.stat-bar > span {
  display: block;
  width: 100%;
  background: var(--red);
  border-radius: 2px 2px 0 0;
  transition: background .15s;
}
.stat-bar:hover > span { background: var(--red-dark); }

.stat-table { width: 100%; border-collapse: collapse; }
.stat-table th {
  text-align: left;
  font-weight: 600;
  padding: 7px 10px 7px 0;
  border-bottom: 1px solid var(--line);
  font-size: var(--t-sm);
}
.stat-table td {
  padding: 7px 0;
  border-bottom: 1px solid var(--line);
  font-size: var(--t-sm);
}
.stat-num {
  text-align: right;
  padding-right: 12px !important;
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  white-space: nowrap;
}
/* The bar is the comparison; the number is the fact. Both, because a bar alone
   cannot be read out over the phone. */
.stat-track {
  width: 45%;
  min-width: 80px;
}
.stat-track > span {
  display: block;
  height: 8px;
  background: var(--gold);
  border-radius: 4px;
  min-width: 2px;
}

/* ---------- icons ----------
   Drawn to the same stroke as the navigation chevrons so they read as part of
   the site rather than dropped in from an icon set. They inherit colour, so a
   dark panel needs no special case. */

.icon {
  width: 1.5em;
  height: 1.5em;
  flex: none;
  vertical-align: -0.3em;
}

/* On a service card the icon sits above the name, in the quality gold - it is
   a small mark, which is what gold is for on this site. */
.card-icon .card-mark {
  width: 34px;
  height: 34px;
  color: var(--gold);
  margin-bottom: 10px;
  display: block;
}

/* In a list row it sits beside the name, quieter, so the name still leads. */
.service-row h2 {
  display: flex;
  align-items: center;
  gap: 12px;
}
.service-row .row-mark {
  width: 26px;
  height: 26px;
  color: var(--gold);
  vertical-align: baseline;
}

@media (max-width: 520px) {
  .service-row .row-mark { width: 22px; height: 22px; }
}

/* ---------- opening status bar ----------
   The one thing people want from a barber's website: can I walk in now. It
   names the time as well as the state, because "open" on its own sends somebody
   off to find the opening times anyway.

   Colour follows the site's accent policy - green only ever means open, and the
   amber and red are used nowhere else, so they carry meaning rather than
   decoration. */

.topbar {
  background: var(--ink);
  color: #ded9d1;
  font-size: var(--t-sm);
  line-height: 1.3;
  border-bottom: 1px solid rgba(255, 255, 255, .08);
}
.topbar .wrap {
  display: flex;
  align-items: center;
  gap: 8px;
  padding-block: 8px;
}
.topbar strong { color: #fff; font-weight: 600; }
.topbar-sep { opacity: .5; }
.topbar-spacer { flex: 1; }

.topbar-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex: none;
  background: currentColor;
}

/* Open: the same green the open flag uses, and nothing else on the site does. */
.topbar-open .topbar-dot   { background: #35c17a; }
/* Closing: amber, used here and nowhere else. */
.topbar-closing .topbar-dot { background: #e0a32e; }
.topbar-closing strong      { color: #ffd98a; }
/* Opening soon: the same amber, because it is the same "not quite" state. */
.topbar-opening .topbar-dot { background: #e0a32e; }
/* Closed: no colour at all - an absence, not an alarm. */
.topbar-closed .topbar-dot { background: #7b7972; }

.topbar-link {
  color: #ded9d1;
  text-decoration: underline;
  text-underline-offset: 2px;
  white-space: nowrap;
}
.topbar-link:hover { color: #fff; }

@media (max-width: 560px) {
  /* The link is the first thing to go - the status is the point. */
  .topbar-link { display: none; }
  .topbar .wrap { justify-content: center; }
  .topbar-spacer { display: none; }
}

/* ---------------------------------------------------------------------------
   Directory of advertisers (/business/)
   Cards sit two-up on a desktop and stack on a phone. The logo is fixed height
   so a tall logo and a wide one do not make neighbouring cards different sizes.
   --------------------------------------------------------------------------- */
.directory-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 18px;
  margin-top: 14px;
}

.directory-card {
  display: flex;
  gap: 16px;
  align-items: flex-start;
  margin: 0;
}

.directory-logo {
  width: 64px;
  height: 64px;
  object-fit: contain;
  flex: none;
  border-radius: 8px;
  background: #fff;
}

.directory-body { flex: 1; min-width: 0; }

.directory-trade {
  margin: 0 0 6px;
  font-size: .87rem;
  color: var(--ink-soft);
}

.directory-areas {
  margin-top: 6px;
  font-size: .85rem;
  color: var(--ink-soft);
}

@media (max-width: 420px) {
  .directory-card { flex-direction: column; }
}

/* ---------------------------------------------------------------------------
   The top bar and header stick together

   The opening status lives in the top bar and nowhere else - it was briefly in
   the header too, which just showed the same words twice. Sticking the pair as
   one block keeps the status on screen while scrolling without repeating it,
   and without hard-coding the top bar height as a header offset.
   --------------------------------------------------------------------------- */
.site-top {
  position: sticky;
  top: 0;
  z-index: 60;
}

@media (max-width: 640px) {
  /* With the big logo the header runs to a couple of hundred pixels. Pinning
     all of that would eat a quarter of a phone screen for the whole visit, so
     only the slim top bar stays - which is the half carrying the status. */
  .site-top { position: static; }
  .topbar {
    position: sticky;
    top: 0;
    z-index: 60;
  }
}

/* ---------------------------------------------------------------------------
   Five star reviews, scrolling at the foot of every page

   The track holds the list twice and slides exactly -50%, so the moment it
   wraps, the copy coming in sits where the copy going out was - no jump. All
   the timing is on one animation so there is nothing to keep in sync.
   --------------------------------------------------------------------------- */
.reviews-strip {
  background: var(--cream, #f6f3ee);
  border-top: 1px solid var(--line);
  padding: 26px 0 30px;
  overflow: hidden;
}

.reviews-strip-head {
  margin: 0 0 16px;
  text-align: center;
  font-size: var(--t-sm);
  color: var(--ink-soft);
}
.reviews-strip-head strong { color: var(--ink); }

.reviews-marquee {
  overflow: hidden;
  /* Fades the ends so quotes arrive and leave rather than being chopped. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
}

.reviews-track {
  display: flex;
  width: max-content;
  animation: reviews-scroll 46s linear infinite;
}

.reviews-marquee:hover .reviews-track,
.reviews-track:focus-within { animation-play-state: paused; }

.reviews-run {
  display: flex;
  align-items: stretch;
  gap: 16px;
  margin: 0;
  padding: 0 8px 0 0;
  list-style: none;
}

.reviews-item {
  flex: 0 0 auto;
  width: 310px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius, 10px);
  padding: 16px 18px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.reviews-stars {
  color: #e0a32e;
  font-size: .95rem;
  letter-spacing: 2px;
  line-height: 1;
}

.reviews-quote {
  margin: 0;
  font-size: .94rem;
  line-height: 1.45;
}

.reviews-who {
  margin: auto 0 0;
  font-size: .85rem;
  color: var(--ink-soft);
}

.reviews-src::before { content: "\00b7"; margin: 0 5px; }

@keyframes reviews-scroll {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}

/* A strip that cannot be stopped is an accessibility problem, not a style
   choice. Asked for less motion: it stands still and scrolls by hand. */
@media (prefers-reduced-motion: reduce) {
  .reviews-track { animation: none; }
  .reviews-marquee { overflow-x: auto; }
  .reviews-track > .reviews-run[aria-hidden="true"] { display: none; }
}

/* ---------------------------------------------------------------------------
   Street View under the whole find-us block

   Full width, under both the shop details and the map, rather than stacked in
   the map column. Half a column is enough for a doorway and not enough for the
   parade either side of it, which is what somebody is actually navigating by.
   --------------------------------------------------------------------------- */
.streetview-wide { margin-top: 26px; }

.streetview-wide .map-holder,
.streetview-wide .map-placeholder { min-height: 380px; }

/* cookies.js sets a height attribute on the iframe; a CSS rule beats it, so
   the panorama can shrink on a phone without the script needing to know. */
.streetview-wide iframe { height: 380px; }

.streetview-note {
  margin: 10px 0 0;
  font-size: var(--t-sm);
  color: var(--ink-soft);
}

@media (max-width: 640px) {
  /* A wide panorama at full height eats a phone screen; shorter still reads. */
  .streetview-wide .map-holder,
  .streetview-wide .map-placeholder { min-height: 260px; }
  .streetview-wide iframe { height: 260px; }
}

/* ---------------------------------------------------------------------------
   Directory filter

   Hidden in the markup and revealed by the script, so a visitor without
   JavaScript never sees a search box that cannot search.
   --------------------------------------------------------------------------- */
.directory-search { margin-bottom: 8px; }

.directory-search label {
  display: block;
  font-size: .82rem;
  text-transform: uppercase;
  letter-spacing: .6px;
  color: var(--ink-soft);
  margin-bottom: 6px;
}

.directory-search-row {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}

.directory-search input {
  flex: 1;
  min-width: 220px;
  padding: 11px 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  font: inherit;
  background: #fff;
}
.directory-search input:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 1px;
}

/* The Clear button is only worth its space once there is something to clear. */
.directory-search [data-directory-clear] { display: none; }
.directory-search.is-filtering [data-directory-clear] { display: inline-block; }

.directory-count {
  margin: 8px 0 0;
  font-size: var(--t-sm);
  color: var(--ink-soft);
  min-height: 1.2em;
}

.directory-empty { margin-top: 18px; }
