/* ============================================================
   Customer site template — shopfront theme.

   Light by default, because the people reading these sites are the
   general public and often not young. Dark mode is offered only when
   the visitor's OS asks for it.

   Self-contained: no web fonts, no icon set, no framework. Colours come
   from two places — the neutral palette picked by `data-surface` on
   <html>, and the four accent variables Base.astro injects from
   site.config.ts.

   Contrast: every neutral/accent pairing here is checked against WCAG AA
   by `npm run check:contrast`. If you change a colour, re-run it.
   ============================================================ */

/* ---------- Neutral palettes ----------
   --paper  page background
   --panel  cards and raised surfaces
   --ink    body text
   --muted  secondary text (still AA on both paper and panel)
   --line   hairline borders
   --sink   recessed bands that break up the page                     */

:root,
[data-surface="stone"] {
  --paper: #f8f8f6;
  --panel: #ffffff;
  --ink: #1b1b19;
  --muted: #56564f;
  --line: #e4e3de;
  --sink: #f0f0ec;
}

[data-surface="warm"] {
  --paper: #fbf8f3;
  --panel: #ffffff;
  --ink: #201c16;
  --muted: #5d5449;
  --line: #e7dfd3;
  --sink: #f4efe6;
}

[data-surface="cool"] {
  --paper: #f7f9fb;
  --panel: #ffffff;
  --ink: #161b21;
  --muted: #4f5b66;
  --line: #dde4ec;
  --sink: #eef2f7;
}

@media (prefers-color-scheme: dark) {
  :root,
  [data-surface="stone"] {
    --paper: #131312;
    --panel: #1b1b19;
    --ink: #eeeeea;
    --muted: #a3a39c;
    --line: #2b2b27;
    --sink: #191917;
  }

  [data-surface="warm"] {
    --paper: #16130e;
    --panel: #1e1a14;
    --ink: #f2ece2;
    --muted: #a9a094;
    --line: #322b21;
    --sink: #1c1811;
  }

  [data-surface="cool"] {
    --paper: #0e1318;
    --panel: #151c22;
    --ink: #e7eef5;
    --muted: #9aa7b3;
    --line: #232e39;
    --sink: #121920;
  }

  /* Base.astro sets both; dark mode swaps which one is live. */
  :root {
    --accent-ink: var(--accent-ink-dark);
    --on-accent: var(--paper);
  }
}

:root {
  /* Text that sits on an --accent-ink fill. Flipped above in dark mode. */
  --on-accent: #ffffff;

  --sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue",
    Arial, sans-serif;
  --serif: Georgia, "Iowan Old Style", "Palatino Linotype", Palatino,
    "Times New Roman", serif;
  --friendly: "Trebuchet MS", Verdana, Geneva, system-ui, sans-serif;
  --mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;

  /* Overridden by [data-type] below. */
  --font-head: var(--sans);
  --font-body: var(--sans);

  --maxw: 1120px;
  --measure: 68ch;
  --radius: 12px;
  --radius-lg: 18px;
  --radius-btn: 10px;
  --radius-pill: 999px;
  --shadow: 0 1px 2px rgba(0, 0, 0, 0.05), 0 8px 24px -16px rgba(0, 0, 0, 0.25);
}

/* ---------- Type styles ----------
   All system fonts, so nothing is fetched. `typeStyle` in site.config.ts
   picks one; this is the biggest lever on a site's character after colour. */

[data-type="serif"] {
  --font-head: var(--serif);
  --font-body: var(--serif);
}

/* Serif headings over a sans body — the editorial pairing. */
[data-type="editorial"] {
  --font-head: var(--serif);
  --font-body: var(--sans);
}

[data-type="friendly"] {
  --font-head: var(--friendly);
  --font-body: var(--friendly);
}

/* Georgia and Trebuchet run larger than system-ui at the same px, so the
   body size is trimmed to keep the measure comparable across styles. */
[data-type="serif"] body,
[data-type="editorial"] body {
  font-size: 1.05rem;
}

[data-type="friendly"] body {
  font-size: 1rem;
}

@media (min-width: 700px) {
  [data-type="serif"] body,
  [data-type="editorial"] body {
    font-size: 1.1rem;
  }
  [data-type="friendly"] body {
    font-size: 1.06rem;
  }
}

/* Serif headings don't want the tight tracking a grotesque does. */
[data-type="serif"] h1,
[data-type="serif"] h2,
[data-type="serif"] h3,
[data-type="editorial"] h1,
[data-type="editorial"] h2,
[data-type="editorial"] h3 {
  letter-spacing: -0.005em;
}

/* ---------- Shape ----------
   `shape` in site.config.ts. Sharp reads as trade or industrial, round as
   café or salon, soft as the neutral middle. */

[data-shape="sharp"] {
  --radius: 0px;
  --radius-lg: 0px;
  --radius-btn: 0px;
  --radius-pill: 0px;
}

[data-shape="round"] {
  --radius: 18px;
  --radius-lg: 28px;
  --radius-btn: 999px;
  --radius-pill: 999px;
}

* {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
  /* Anchored sections clear the sticky header, which is two rows tall on
     narrow screens and one row from 860px up. */
  scroll-padding-top: calc(var(--testbar-h, 0px) + 112px);
  -webkit-text-size-adjust: 100%;
}

@media (min-width: 860px) {
  html {
    scroll-padding-top: calc(var(--testbar-h, 0px) + 88px);
  }
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  /* Comfortable for older eyes without being cartoonish. */
  font-size: 1.0625rem;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  /* Keeps the footer at the bottom on short pages — a new site with an
     empty blog has several of those. */
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}

main {
  flex: 1 0 auto;
}

@media (min-width: 700px) {
  body {
    font-size: 1.125rem;
  }
}

a {
  color: var(--accent-ink);
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}

img {
  max-width: 100%;
}

h1,
h2,
h3,
.brand__name,
.hero__tagline {
  font-family: var(--font-head);
}

h1,
h2,
h3 {
  line-height: 1.2;
  letter-spacing: -0.015em;
  /* `pretty` only avoids orphans. `balance` is reserved for the few short
     display headings below, where evening out the lines actually helps —
     on a list of blog titles it just produces odd early breaks. */
  text-wrap: pretty;
}

.hero__title,
.section__title,
.post__title {
  text-wrap: balance;
}

.muted {
  color: var(--muted);
}

/* ---------- Layout primitives ---------- */

.wrap {
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: clamp(18px, 5vw, 40px);
}

.section {
  padding-block: clamp(40px, 7vw, 76px);
}

/* Recessed band, used to separate a section from its neighbours. */
.section--sunk {
  background: var(--sink);
  border-block: 1px solid var(--line);
}

.section__head {
  margin: 0 0 clamp(20px, 3vw, 32px);
}

.section__title {
  font-size: clamp(1.5rem, 4vw, 2rem);
  margin: 0;
}

/* Small caps label above a section title. Mono is used here and in the
   footer only — as an accent, never for body copy. */
.eyebrow {
  display: block;
  font-family: var(--mono);
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent-ink);
  margin: 0 0 0.5rem;
}

/* ---------- Header ----------
   The banner and the nav stick together as one block. Sticking them
   individually means guessing the banner's height, and the banner wraps to
   two lines on a narrow screen — so the nav would ride up over it. */
.topbar {
  position: sticky;
  top: 0;
  z-index: 20;
}

/* Test-site banner. Only rendered when SITE_MODE=test (the Cloudflare Pages
   Preview environment). Full-bleed on purpose — deliberately not inside the
   .wrap container. --testbar-h is the minimum height it reserves, and the
   same value pads anchor scrolling below. */
.testbar {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: var(--testbar-h, 34px);
  padding: 5px 12px;
  background: #ffb020;
  color: #1a1200;
  font-family: var(--mono);
  font-size: 0.75rem;
  font-weight: 700;
  line-height: 1.35;
  letter-spacing: 0.03em;
  text-align: center;
  text-transform: uppercase;
}

.nav {
  background: var(--panel);
  border-bottom: 1px solid var(--line);
}

.nav__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding-block: 10px;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  color: var(--ink);
  text-decoration: none;
  min-width: 0;
}

.brand__mark {
  display: grid;
  place-items: center;
  flex: none;
  width: 2.2em;
  height: 2.2em;
  border-radius: var(--radius-btn);
  background: linear-gradient(140deg, var(--accent), var(--accent-2));
  color: #fff;
  /* The badge is decorative; the business name beside it carries the
     meaning, so a mid-tone gradient under white is acceptable here. */
  font-size: 0.9rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
}

.brand__name {
  font-size: 1.05rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Tap-to-call, pinned to the header. Most phone visitors want exactly
   this, so it never scrolls away. */
.nav__call {
  flex: none;
}

.nav__call .btn {
  padding-inline: 0.9em;
}

/* On narrow screens the button shows just "Call"; the number appears once
   there is room for it. */
.nav__call-number {
  display: none;
}

@media (min-width: 560px) {
  .nav__call-number {
    display: inline;
  }
}

.nav__links {
  display: flex;
  flex-wrap: wrap;
  gap: 2px 18px;
  padding-block: 0 8px;
  font-size: 0.92rem;
}

.nav__links a {
  color: var(--muted);
  text-decoration: none;
  padding: 4px 0;
  border-bottom: 2px solid transparent;
}

.nav__links a:hover {
  color: var(--ink);
  border-bottom-color: var(--accent);
}

.nav__links a[aria-current="page"] {
  color: var(--ink);
  font-weight: 600;
  border-bottom-color: var(--accent);
}

/* One row from here up: the brand sits left, the links and the call button
   are pushed to the right. `display: contents` dissolves the mobile
   brand+call row so all three become siblings in one flex line. */
@media (min-width: 860px) {
  .nav__inner {
    display: flex;
    align-items: center;
    gap: 28px;
    padding-block: 12px;
  }
  .nav__bar {
    display: contents;
  }
  .brand {
    order: 0;
  }
  .nav__links {
    order: 1;
    margin-left: auto;
    padding-block: 0;
    gap: 26px;
    font-size: 0.95rem;
  }
  .nav__call {
    order: 2;
  }
  .brand__name {
    font-size: 1.15rem;
  }
}

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

.hero {
  padding-block: clamp(28px, 5vw, 56px) clamp(32px, 5vw, 64px);
}

.hero__grid {
  display: grid;
  gap: clamp(24px, 4vw, 44px);
}

.hero__title {
  font-size: clamp(2rem, 7vw, 3.4rem);
  margin: 0;
  font-weight: 800;
}

.hero__tagline {
  font-size: clamp(1.15rem, 3.2vw, 1.5rem);
  font-weight: 600;
  color: var(--accent-ink);
  margin: 0.5rem 0 0;
  text-wrap: balance;
}

.hero__blurb {
  max-width: 52ch;
  color: var(--muted);
  margin: 1rem 0 0;
}

/* Remaining taglines — the customer's own words, so they read as
   "what we do" rather than invented marketing copy. */
.hero__chips {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding: 0;
  margin: 1.2rem 0 0;
}

.hero__chips li {
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--ink);
  background: color-mix(in srgb, var(--accent-2) 10%, var(--panel));
  border: 1px solid color-mix(in srgb, var(--accent-2) 28%, var(--line));
  border-radius: var(--radius-pill);
  padding: 0.3em 0.9em;
}

.hero__cta {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin: 1.6rem 0 0;
}

.hero__photo {
  margin: 0;
}

.hero__photo img {
  display: block;
  width: 100%;
  height: auto;
  /* Wide and short on a phone, so hours and address stay one short scroll
     away rather than a screen and a half. */
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: var(--radius-lg);
  border: 1px solid var(--line);
  box-shadow: var(--shadow);
  background: var(--sink);
}

/* ---------- Grid mode ----------
   The page is assembled from Blogger pages named by position. A row with
   two cells splits; a row with one cell takes the full width, which is the
   whole point of `auto-fit` here rather than a fixed two-column track. A
   row with nothing in it is never rendered, so it leaves no gap. */

.layout {
  display: flex;
  flex-direction: column;
  gap: clamp(28px, 5vw, 52px);
}

.layout__row {
  display: grid;
  gap: clamp(20px, 4vw, 36px);
}

/* Side by side once there is room; stacked on a phone regardless. */
@media (min-width: 760px) {
  .layout__row[data-cells="2"] {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .layout__row[data-cells="3"] {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
  .layout__row[data-cells="4"] {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

.layout__cell > :first-child {
  margin-top: 0;
}

.layout__cell > :last-child {
  margin-bottom: 0;
}

/* A lone cell shouldn't run the full width of a wide screen as unbroken
   prose — the measure would be unreadable. */
.layout__row[data-cells="1"] .layout__cell {
  max-width: var(--measure);
}

/* The address under the name in the grid hero. */
.hero__address {
  margin-top: 0.8rem;
  color: rgba(255, 255, 255, 0.92);
}

.hero__address p {
  margin: 0 0 0.2em;
}

/* ---------- Overlay hero ----------
   The photo runs full-bleed and the words sit on top of it. This is the
   arrangement most small-business sites already use, so a rebuild reads as
   the same business rather than a different one.

   Contrast is handled by construction rather than luck. The scrim never
   drops below 0.62 opacity, so even a pure-white photo leaves an effective
   background of about #666668 — 5.7:1 under white text, clearing AA for
   body copy anywhere in the hero. A lighter wash looks better on a dark
   photo and becomes unreadable on a bright one, which is exactly the trap
   these overlay heroes usually fall into. */

.hero--overlay {
  position: relative;
  isolation: isolate;
  display: grid;
  padding-block: 0;
}

/* Both children occupy the same cell; the scrim stacks above the photo. */
.hero--overlay > * {
  grid-area: 1 / 1;
}

.hero--overlay .hero__photo {
  margin: 0;
  min-height: clamp(340px, 62vw, 560px);
}

.hero--overlay .hero__photo img,
.hero--overlay .gallery__item img {
  width: 100%;
  height: 100%;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  object-fit: cover;
}

.hero--overlay .hero__photo > img {
  aspect-ratio: auto;
}

.hero--overlay .gallery,
.hero--overlay .gallery__frame {
  height: 100%;
  aspect-ratio: auto;
}

/* The scrim sits on the element that *contains* the text. Putting it on a
   separate layer would leave the accessibility checker measuring the words
   against the page background instead of the photo, and reporting a false
   failure. */
.hero--overlay .hero__over {
  display: flex;
  align-items: flex-end;
  z-index: 1;
  padding-block: clamp(64px, 14vw, 120px) clamp(26px, 5vw, 48px);
  background: linear-gradient(
    180deg,
    rgba(8, 8, 10, 0.62) 0%,
    rgba(8, 8, 10, 0.74) 45%,
    rgba(8, 8, 10, 0.88) 100%
  );
}

.hero--overlay .hero__grid {
  width: 100%;
  grid-template-columns: minmax(0, 44rem);
}

.hero--overlay .hero__title,
.hero--overlay .hero__tagline {
  color: #fff;
}

.hero--overlay .hero__blurb {
  color: rgba(255, 255, 255, 0.9);
}

.hero--overlay .hero__chips li {
  color: #fff;
  background: rgba(255, 255, 255, 0.16);
  border-color: rgba(255, 255, 255, 0.45);
}

/* Over a photo, the outlined button needs a solid ground of its own. */
.hero--overlay .btn--secondary {
  background: var(--panel);
  border-color: var(--panel);
}

/* Clear of the words, and clear of the sticky header. */
.hero--overlay .gallery__toggle {
  top: 12px;
  right: 12px;
  bottom: auto;
  z-index: 2;
}

/* Promoted Blogger sections keep prose to a readable measure. */
.prose {
  max-width: var(--measure);
}

/* ---------- Hero gallery ----------
   Several images in the Blogger "Hero" page crossfade in the photo slot.
   Entirely CSS: the images are stacked, each runs the same animation offset
   by one slide, and the whole thing pauses via a checkbox rather than a
   script. Auto-rotating content a visitor cannot stop fails WCAG 2.2.2, so
   the pause control is not optional. */

.gallery {
  position: relative;
  --gallery-slide: 5s;
}

.gallery__frame {
  list-style: none;
  margin: 0;
  padding: 0;
  position: relative;
  /* Matches the single-photo aspect so a gallery and a photo occupy the
     same space and nothing shifts as images load. */
  aspect-ratio: 16 / 9;
}

.gallery__item {
  position: absolute;
  inset: 0;
  opacity: 0;
  animation-duration: calc(var(--gallery-count) * var(--gallery-slide));
  animation-delay: calc(var(--i) * var(--gallery-slide));
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
}

.gallery__item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: var(--radius-lg);
  border: 1px solid var(--line);
  box-shadow: var(--shadow);
  background: var(--sink);
}

/* Each image holds for one slide, then crossfades with the next. The
   percentages are 18/n, 100/n and 118/n — fixed seconds expressed as a
   share of an n-slide cycle — so they have to be written out per count. */
.gallery__frame[data-count="2"] .gallery__item { animation-name: gallery-2; }
.gallery__frame[data-count="3"] .gallery__item { animation-name: gallery-3; }
.gallery__frame[data-count="4"] .gallery__item { animation-name: gallery-4; }
.gallery__frame[data-count="5"] .gallery__item { animation-name: gallery-5; }
.gallery__frame[data-count="6"] .gallery__item { animation-name: gallery-6; }
.gallery__frame[data-count="7"] .gallery__item { animation-name: gallery-7; }
.gallery__frame[data-count="8"] .gallery__item { animation-name: gallery-8; }

@keyframes gallery-2 {
  0% { opacity: 0 } 9% { opacity: 1 } 50% { opacity: 1 } 59% { opacity: 0 } 100% { opacity: 0 }
}
@keyframes gallery-3 {
  0% { opacity: 0 } 6% { opacity: 1 } 33.333% { opacity: 1 } 39.333% { opacity: 0 } 100% { opacity: 0 }
}
@keyframes gallery-4 {
  0% { opacity: 0 } 4.5% { opacity: 1 } 25% { opacity: 1 } 29.5% { opacity: 0 } 100% { opacity: 0 }
}
@keyframes gallery-5 {
  0% { opacity: 0 } 3.6% { opacity: 1 } 20% { opacity: 1 } 23.6% { opacity: 0 } 100% { opacity: 0 }
}
@keyframes gallery-6 {
  0% { opacity: 0 } 3% { opacity: 1 } 16.667% { opacity: 1 } 19.667% { opacity: 0 } 100% { opacity: 0 }
}
@keyframes gallery-7 {
  0% { opacity: 0 } 2.571% { opacity: 1 } 14.286% { opacity: 1 } 16.857% { opacity: 0 } 100% { opacity: 0 }
}
@keyframes gallery-8 {
  0% { opacity: 0 } 2.25% { opacity: 1 } 12.5% { opacity: 1 } 14.75% { opacity: 0 } 100% { opacity: 0 }
}

/* The checkbox is the control; the label is what you see. It stays in the
   accessibility tree and keeps keyboard focus — it is only visually hidden. */
.gallery__pause {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.gallery__pause:checked ~ .gallery__frame .gallery__item {
  animation-play-state: paused;
}

.gallery__toggle {
  position: absolute;
  right: 10px;
  bottom: 10px;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  min-height: 40px;
  padding: 0.35em 0.9em;
  border-radius: var(--radius-pill);
  background: var(--panel);
  border: 1px solid var(--line);
  color: var(--ink);
  font-size: 0.85rem;
  font-weight: 600;
  cursor: pointer;
}

.gallery__toggle:hover {
  border-color: var(--accent-ink);
  color: var(--accent-ink);
}

.gallery__pause:focus-visible ~ .gallery__toggle {
  outline: 3px solid var(--accent-ink);
  outline-offset: 2px;
}

/* Only one of the two labels is ever shown, so the control always says what
   pressing it will do. */
.gallery__label--play,
.gallery__pause:checked ~ .gallery__toggle .gallery__label--pause {
  display: none;
}

.gallery__pause:checked ~ .gallery__toggle .gallery__label--play {
  display: inline;
}

@media (prefers-reduced-motion: reduce) {
  .gallery__item {
    animation: none;
  }
  .gallery__item:first-child {
    opacity: 1;
  }
  /* Nothing is moving, so there is nothing to pause. */
  .gallery__toggle,
  .gallery__pause {
    display: none;
  }
}

@media (min-width: 900px) {
  .hero__grid {
    grid-template-columns: 1.05fr 0.95fr;
    align-items: center;
  }
  .hero:not(.hero--overlay) .gallery__frame {
    aspect-ratio: 5 / 4;
  }
  /* Photo first in the source would hurt the heading order, so it is
     moved visually instead. Scoped away from the overlay hero, where both
     layers deliberately share one grid cell. */
  .hero:not(.hero--overlay) .hero__photo {
    grid-column: 2;
    grid-row: 1;
  }
  .hero__photo img {
    aspect-ratio: 5 / 4;
  }
  .hero--nophoto .hero__grid {
    grid-template-columns: minmax(0, 44rem);
  }
}

/* ---------- Buttons ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.45em;
  /* 44px minimum tap target. */
  min-height: 44px;
  padding: 0.6em 1.3em;
  border: 1px solid transparent;
  border-radius: var(--radius-btn);
  font: inherit;
  font-size: 1rem;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.15s ease, border-color 0.15s ease,
    color 0.15s ease;
}

.btn--primary {
  background: var(--accent-ink);
  color: var(--on-accent);
}

.btn--primary:hover {
  background: color-mix(in srgb, var(--accent-ink) 85%, var(--ink));
}

.btn--secondary {
  background: var(--panel);
  color: var(--ink);
  border-color: var(--line);
}

.btn--secondary:hover {
  border-color: var(--accent-ink);
  color: var(--accent-ink);
}

.btn--sm {
  min-height: 38px;
  padding: 0.35em 0.9em;
  font-size: 0.92rem;
}

/* ---------- Cards ---------- */

.card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: clamp(18px, 3vw, 26px);
}

.card__title {
  font-size: 1.2rem;
  margin: 0 0 0.6rem;
}

/* ---------- Visit: hours & location ----------
   Sits directly below the hero so a phone visitor reaches hours and
   address after one short scroll. */

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

@media (min-width: 720px) {
  .visit__grid {
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  }
}

.visit__card .post-body {
  font-size: 1rem;
}

.visit__card .post-body > :first-child {
  margin-top: 0;
}

.visit__card .post-body > :last-child {
  margin-bottom: 0;
}

.visit__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 20px;
}

/* ---------- About ---------- */

.about__body {
  max-width: var(--measure);
}

/* ---------- Contact ---------- */

.contact__list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 12px;
  max-width: 620px;
}

.contact__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  min-height: 56px;
  padding: 0.7em 1.1em;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--ink);
  text-decoration: none;
}

a.contact__item:hover {
  border-color: var(--accent-ink);
}

.contact__key {
  color: var(--muted);
  font-size: 0.85rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  flex: none;
}

.contact__val {
  font-weight: 600;
  text-align: right;
  overflow-wrap: anywhere;
}

a.contact__item .contact__val {
  color: var(--accent-ink);
}

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

.foot {
  background: var(--panel);
  border-top: 1px solid var(--line);
  margin-top: clamp(32px, 6vw, 64px);
}

.foot__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding-block: 28px;
  color: var(--muted);
  font-size: 0.9rem;
}

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

/* ---------- Blog index ---------- */

.posts {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 16px;
  max-width: 780px;
}

.post-card__meta {
  display: block;
  font-size: 0.88rem;
  color: var(--muted);
  margin-bottom: 0.35rem;
}

.post-card__title {
  font-size: clamp(1.2rem, 3vw, 1.45rem);
  margin: 0 0 0.5rem;
}

.post-card__title a {
  color: var(--ink);
  text-decoration: none;
}

.post-card__title a:hover {
  color: var(--accent-ink);
  text-decoration: underline;
}

.post-card__snippet {
  color: var(--muted);
  margin: 0;
  font-size: 1rem;
}

.labels {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 0;
  margin: 0.9rem 0 0;
}

.labels li {
  font-size: 0.8rem;
  color: var(--muted);
  background: var(--sink);
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  padding: 0.2em 0.7em;
}

.notice {
  max-width: 640px;
  padding: 20px 24px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-left: 4px solid var(--accent);
  border-radius: var(--radius);
  color: var(--muted);
}

.notice p {
  margin: 0;
}

.pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  max-width: 780px;
  margin-top: 32px;
}

.pager__status {
  font-size: 0.9rem;
  color: var(--muted);
}

/* ---------- Single post / Blogger page ---------- */

.post {
  max-width: 780px;
  margin-inline: auto;
}

.post__back {
  display: inline-block;
  font-size: 0.95rem;
  font-weight: 600;
  text-decoration: none;
  margin-bottom: 1.2rem;
}

.post__back:hover {
  text-decoration: underline;
}

.post__title {
  font-size: clamp(1.75rem, 5.5vw, 2.6rem);
  margin: 0;
}

.post__meta {
  font-size: 0.95rem;
  color: var(--muted);
  margin: 0.7rem 0 0;
}

.post__head {
  margin-bottom: 2rem;
  padding-bottom: 1.5rem;
  border-bottom: 1px solid var(--line);
}

/* ---------- Blogger-authored HTML ----------
   The customer writes this in Blogger, so it has to look right without
   any classes of ours on it. */

.post-body {
  overflow-wrap: break-word;
}

.post-body h1,
.post-body h2,
.post-body h3,
.post-body h4 {
  color: var(--ink);
  margin: 1.8em 0 0.5em;
  line-height: 1.25;
}

.post-body h2 {
  font-size: 1.4rem;
}

.post-body h3 {
  font-size: 1.2rem;
}

.post-body p {
  margin: 0 0 1.1em;
}

.post-body a {
  color: var(--accent-ink);
}

/* A button written into Blogger HTML — which the "full" level invites —
   would otherwise be repainted by the rule above and end up brown on
   brown. Its own colours win back. */
.post-body a.btn {
  text-decoration: none;
}

.post-body a.btn--primary {
  color: var(--on-accent);
}

.post-body a.btn--secondary {
  color: var(--ink);
}

.post-body img,
.post-body iframe {
  height: auto;
  border-radius: var(--radius);
  border: 1px solid var(--line);
}

.post-body img {
  display: block;
  margin: 1.4em 0;
}

.post-body iframe {
  aspect-ratio: 16 / 9;
  width: 100%;
  margin: 1.4em 0;
}

.post-body blockquote {
  margin: 1.4em 0;
  padding: 0.2em 0 0.2em 1.2em;
  border-left: 3px solid var(--accent);
  color: var(--ink);
  font-style: italic;
}

.post-body code {
  font-family: var(--mono);
  font-size: 0.9em;
  background: var(--sink);
  border: 1px solid var(--line);
  border-radius: 5px;
  padding: 0.1em 0.35em;
}

.post-body pre {
  background: var(--sink);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 16px 18px;
  overflow-x: auto;
}

.post-body pre code {
  background: none;
  border: none;
  padding: 0;
}

.post-body ul,
.post-body ol {
  margin: 0 0 1.1em;
  padding-left: 1.4em;
}

.post-body li {
  margin-bottom: 0.35em;
}

.post-body hr {
  border: 0;
  border-top: 1px solid var(--line);
  margin: 2em 0;
}

/* Tables scroll rather than forcing the page sideways on a phone. */
.post-body table {
  border-collapse: collapse;
  width: 100%;
  margin: 1.4em 0;
  font-size: 0.98rem;
}

.post-body th,
.post-body td {
  border: 1px solid var(--line);
  padding: 0.5em 0.8em;
  text-align: left;
}

.post-body th {
  background: var(--sink);
  font-weight: 700;
}

/* ---------- Accessibility ---------- */

.skip-link {
  position: absolute;
  left: 12px;
  top: -100px;
  z-index: 50;
  padding: 0.7em 1.1em;
  background: var(--accent-ink);
  color: var(--on-accent);
  font-weight: 600;
  text-decoration: none;
  border-radius: 8px;
  transition: top 0.15s ease;
}

.skip-link:focus {
  top: 12px;
}

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

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

/* ---------- Reduced motion ---------- */

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  * {
    animation: none !important;
    transition: none !important;
  }
}

/* ---------- Print ----------
   People print hours and directions, so those survive and the
   navigation, buttons and blog chrome do not. */

@media print {
  /* !important because Base.astro injects the accent variables in an inline
     <style> after this file, which would otherwise win on source order. */
  :root {
    --paper: #fff !important;
    --panel: #fff !important;
    --sink: #fff !important;
    --ink: #000 !important;
    --muted: #333 !important;
    --line: #999 !important;
    --accent: #000 !important;
    --accent-ink: #000 !important;
  }

  body {
    font-size: 11pt;
    line-height: 1.4;
    background: #fff;
    color: #000;
  }

  .nav__links,
  .nav__call,
  .skip-link,
  .testbar,
  .hero__cta,
  .visit__actions,
  .pager,
  .post__back,
  .hero__chips {
    display: none !important;
  }

  .nav {
    position: static;
    border-bottom: 1px solid #999;
  }

  .section {
    padding-block: 12pt;
    break-inside: avoid;
  }

  .card,
  .contact__item {
    border: 1px solid #999;
    break-inside: avoid;
  }

  .hero__photo,
  .gallery,
  .post-body img,
  .post-body iframe {
    display: none;
  }

  /* A printed page can't be clicked, so spell the destination out. */
  .contact__item[href^="http"]::after {
    content: " (" attr(href) ")";
    font-size: 9pt;
    color: #333;
  }

  a {
    text-decoration: none;
  }
}
