/* Feel Ink, Sant Andreu - site stylesheet.
   The only stylesheet written by hand for this site. ds.css, booking.css and
   media.css are shared and load AFTER this file, so anything that has to win
   against them is written at a higher specificity and says why in a comment.

   Design read: a replacement-site pitch for an established, high-traffic
   studio with a walk-in gallery front, with a curated, gallery-quiet language,
   leaning toward light turquoise-on-plaster hung like a picture wall.

   THE SYSTEM, in one sentence: a 1px rule runs the full width at the top of
   every section and the content hangs beneath it at deliberately unequal
   depths, on a 1px wire, from a small square hook. Every photograph sits in a
   mat of exactly the same width inside a 1px frame. That repeated mat is the
   signature and no other site in the set gets a rule-and-hang system.

   NOT DONE HERE, ON PURPOSE. No dark ground, no grain, no distressed texture,
   no blackletter, no skulls used as decoration: the shop is bright, glazed and
   curated and its own photographs prove it. The wall turquoise itself
   (#65BAB7, sampled from the lit wall in g1 and g4) is 1.94:1 on this ground
   and is therefore never used for type or for a rule; it stays inside the
   photographs, where it belongs, and the page carries its darkened sibling. */

/* ---------------------------------------------------------------- tokens --
   :root would lose to booking.css and ds.css, which load later and declare on
   :root themselves. html:root is one specificity step higher, so these values
   hold wherever they have to. */
html:root {
  /* Palette. Nothing is pure black or pure white. Measured contrast against
     the ground is recorded beside each value. */
  --ground: #E9EFEE;      /* pale plaster with a turquoise cast */
  --bg: #E9EFEE;          /* alias read by media.css */
  --ink: #1B2220;         /* 13.92:1 on the ground - body text */
  --text: #1B2220;        /* alias read by media.css */
  --muted: #4C5654;       /* 6.52:1 - captions, hours, the address line */
  --accent: #0E6E6B;      /* 5.21:1, so it is legal at body size as link text */
  --accent-ink: #F7FAF9;  /* 5.78:1 on the accent - the CTA label */

  --mat: #F4F8F7;         /* the mat inside every picture frame */
  --bg-2: #DFE7E6;        /* read by media.css for photo frames */
  --bg-3: #F4F8F7;        /* read by booking.css for input fills */
  --line: #78827F;        /* 3.40:1 on the ground: the rail, the frames, the
                             input borders. One rule weight everywhere. */

  /* Error text. booking.css declares --bad on a bare :root and then swaps it
     to a light salmon under prefers-color-scheme: dark. This page is light
     whatever the system setting is, and that salmon lands at 1.71:1 here, so
     the value is pinned at a specificity a bare :root inside a media query
     cannot beat. 5.61:1 on the ground. */
  --bad: #B3261E;

  /* One radius system, held everywhere, because every edge on this page is a
     frame edge and a frame edge is not round. */
  --r: 2px;

  /* The mat width. It is the same on every photograph on the page. */
  --mat-w: clamp(10px, 2.2vw, 20px);

  /* Measured: the language switcher is the tallest thing in the header (44px
     links inside a 2px-padded, 1px-bordered shell) and the row adds 0.55rem
     top and bottom, which comes to 68.6px. The hero subtracts this so the
     first screen is exactly header plus hero, and ds.css uses it to keep a
     focused control from landing under the sticky header. */
  --nav-h: 69px;
  --wrap: 76rem;
  --gutter: clamp(1.15rem, 4vw, 3rem);

  /* Interaction dials, read by ds.css. A hung panel lifts off its hook; it
     does not bounce. */
  --ds-lift: 2px;
  --ds-dur: 0.2s;

  --font-display: "Instrument Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body: "Karla", system-ui, -apple-system, "Segoe UI", sans-serif;
}

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

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

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 1.0625rem;
  line-height: 1.65;
  font-weight: 400;
  /* Nothing on this page may cause a sideways scroll at 360px. */
  overflow-x: hidden;
}

h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 700;
  margin: 0;
}

h1 {
  font-size: clamp(2.4rem, 1.9rem + 2.4vw, 4rem);
  line-height: 1.02;
  letter-spacing: -0.02em;
}

h2 {
  font-size: clamp(1.5rem, 1.32rem + 0.9vw, 2.1rem);
  line-height: 1.12;
  letter-spacing: -0.015em;
}

h3 {
  font-size: 1.0625rem;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -0.005em;
}

p { margin: 0; max-width: 66ch; }

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

img { max-width: 100%; }

address { font-style: normal; }

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

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

/* The museum label. Small, wide, uppercase: the one permitted eyebrow and
   every caption on the page are set identically, because on a picture wall a
   label is a label. */
.eyebrow, figcaption, .cap, .aside {
  font-size: 0.75rem;
  line-height: 1.5;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--muted);
  font-weight: 500;
  max-width: 46ch;
}
figcaption { margin-top: 0.7rem; }

/* Icons from assets/social.svg. Always beside a word, never instead of one. */
.si { flex: none; width: 1em; height: 1em; fill: currentColor; }

/* ---------------------------------------------------------------- reveal --
   The floor under motion.js. If Motion never loads this transition is what
   reveals the page; ds.css switches it off when motion.js takes over. Rise is
   10px to match data-ds-rise: a settle, not a slide. */
.rv {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 0.6s cubic-bezier(0.22, 0.75, 0.3, 1),
              transform 0.6s cubic-bezier(0.22, 0.75, 0.3, 1);
}
.rv.in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .rv { opacity: 1; transform: none; transition: none; }
}

/* ------------------------------------------------------- the picture rail --
   .hang draws the rule. .hung drops from it: a 1px wire and a small square
   hook at the top, with the drop depth set per element so no two blocks in a
   row hang at the same height. */
.hang {
  border-top: 1px solid var(--line);
  padding-bottom: clamp(3.5rem, 7vw, 7rem);
}
/* The sticky header already draws a rule along its bottom edge, and it is the
   rail the hero hangs from. A second one here would be a 2px line. */
.hang.opening { border-top: 0; }

/* .hung is always a wrapper and never carries padding of its own, because the
   drop is empty wall between the rail and the thing hanging on it. Anything
   with its own padding (the ledger card, the consultation frame, a mat) goes
   INSIDE a .hung, never on one. */

.hung {
  position: relative;
  padding-top: var(--drop, 3rem);
  min-width: 0;
}
.hung::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
  width: 1px;
  height: max(0px, calc(var(--drop, 3rem) - 1rem));
  background: var(--line);
}
.hung::after {
  content: "";
  position: absolute;
  inset-block-start: -2px;
  inset-inline-start: -2px;
  width: 5px;
  height: 5px;
  background: var(--ink);
}

.drop-1 { --drop: clamp(1.9rem, 4vw, 3rem); }
.drop-2 { --drop: clamp(2.8rem, 6vw, 4.75rem); }
.drop-3 { --drop: clamp(3.9rem, 8vw, 6.75rem); }
.drop-4 { --drop: clamp(4.8rem, 10vw, 9rem); }

/* ------------------------------------------------------------ the frames --
   Every photograph on this page sits in a mat of exactly --mat-w inside a 1px
   frame. Nothing else on the page is allowed to look like a frame. */
.frame { margin: 0; }
.plate {
  background: var(--mat);
  padding: var(--mat-w);
  border: 1px solid var(--line);
  border-radius: var(--r);
}
.plate img {
  display: block;
  width: 100%;
  height: auto;
  object-fit: cover;
  background: var(--bg-2);
}

/* --------------------------------------------------------------- buttons -- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-height: 48px;
  padding: 0.7rem 1.4rem;
  border: 1px solid transparent;
  border-radius: var(--r);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1rem;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  background: none;
  color: var(--ink);
}
.btn-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);   /* 5.78:1 */
}
.btn-ghost {
  border-color: var(--line);
  color: var(--ink);
  background: var(--mat);
}
.btn:disabled { opacity: 0.6; cursor: default; }

.actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.8rem;
  margin-top: clamp(1.4rem, 3vw, 2rem);
}
.actions .btn { flex: 0 1 auto; }

/* ---------------------------------------------------------------- header -- */
.site-head {
  position: sticky;
  inset-block-start: 0;
  z-index: 30;
  background: var(--ground);
  border-bottom: 1px solid var(--line);
}
.head-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem clamp(0.75rem, 2vw, 1.75rem);
  min-height: var(--nav-h);
  padding-block: 0.55rem;
}
.brand {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  margin-inline-end: auto;
  text-decoration: none;
  color: var(--ink);
}
.brand b {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.1rem;
  letter-spacing: -0.015em;
}
.brand span {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--muted);
}
.head-nav { display: flex; gap: 0.25rem; }
.head-nav a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding-inline: 0.55rem;
  font-size: 0.9rem;
  color: var(--ink);
  text-decoration: none;
  border-bottom: 1px solid transparent;
}
.head-nav a:hover { border-bottom-color: var(--accent); }

.lang {
  display: flex;
  gap: 2px;
  padding: 2px;
  border: 1px solid var(--line);
  border-radius: var(--r);
}
.lang a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  border-radius: var(--r);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-decoration: none;
  color: var(--muted);
}
.lang a[aria-current="true"] { background: var(--ink); color: var(--ground); }

.nav-cta {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding-inline: 1rem;
  border: 1px solid var(--accent);
  border-radius: var(--r);
  background: var(--accent);
  color: var(--accent-ink);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.9rem;
  text-decoration: none;
}

@media (max-width: 720px) {
  /* Measured at 390px: brand, section links, switcher and CTA together need
     about 480px and wrap onto a second row, which makes a sticky header 122px
     tall and costs a seventh of the screen on every scroll. The language
     switcher is the one that stays, because three languages are the point of
     this site. The section links are one scroll away and the booking CTA is
     the first button in the hero, 398px down a 844px screen. */
  .head-nav,
  .nav-cta { display: none; }
}
@media (max-width: 420px) {
  .brand span { display: none; }
}

/* ------------------------------------------------- family 1: the opening --
   Type hangs left from the rail; one tall matted photograph hangs right, and
   deeper. Four text elements, headline on one line, and the booking CTA is
   inside the first screen at every width because the copy column comes first
   in source order. */
.opening { min-height: calc(100dvh - var(--nav-h)); }
.opening-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.08fr) minmax(0, 0.92fr);
  gap: clamp(1.75rem, 4vw, 4rem);
  align-items: start;
}
.opening-copy .eyebrow { display: block; margin-bottom: clamp(0.9rem, 2vw, 1.4rem); }
.opening-copy h1 { margin-bottom: clamp(1rem, 2.2vw, 1.6rem); }
.opening-copy .lede {
  font-size: clamp(1.0625rem, 1rem + 0.35vw, 1.3rem);
  max-width: 34ch;
  color: var(--ink);
}
.opening-plate img { aspect-ratio: 3 / 4; max-height: 68vh; }

@media (max-width: 880px) {
  .opening-grid { grid-template-columns: 1fr; }
  .opening-plate { --drop: clamp(2.2rem, 6vw, 3.5rem); }
  .opening-plate img { aspect-ratio: 4 / 5; max-height: 62vh; }
}

/* --------------------------------------------- family 2: the hung ledger --
   The facts that are actually verified: the rating, the review count and the
   week. They hang on a card of their own, deeper than the text beside them. */
.ledger-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.85fr);
  gap: clamp(1.75rem, 4vw, 4rem);
  align-items: start;
}
.ledger-note h2 { margin-bottom: clamp(0.9rem, 2vw, 1.3rem); }
.ledger-note p + p { margin-top: 1rem; }
.ledger-note .qualifier { color: var(--muted); font-size: 0.98rem; }

.ledger {
  background: var(--mat);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: clamp(1.25rem, 3vw, 2rem);
}
.score {
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  flex-wrap: wrap;
  padding-bottom: clamp(1rem, 2.5vw, 1.5rem);
  margin-bottom: clamp(1rem, 2.5vw, 1.5rem);
  border-bottom: 1px solid var(--line);
  max-width: none;
}
.score b {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2.6rem, 2rem + 2.2vw, 3.4rem);
  line-height: 0.95;
  letter-spacing: -0.03em;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}
.score span { color: var(--muted); font-size: 0.95rem; }

.hours {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.4rem 1.5rem;
  margin: 0;
  font-size: 0.98rem;
}
.hours dt { color: var(--muted); }
.hours dd { margin: 0; font-variant-numeric: tabular-nums; }
/* Closed is a word, never a colour on its own. */
.hours .off { color: var(--muted); }

/* ------------------------------------ family 3: full bleed, margin label --
   The photograph runs off the left edge of the wall and the label sits in the
   margin beside it, the way a wall text does. On the bleeding edge the mat
   and the frame are dropped, so the picture genuinely leaves the page. */
.corridor {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr);
  gap: clamp(1.5rem, 3vw, 3rem);
  /* The photograph escapes to the left viewport edge; the label does not. On
     a wide screen its right edge lands on the same line as the rest of the
     page, so the wall text stays on the grid the picture has left. */
  padding-inline-end: max(var(--gutter), calc((100vw - var(--wrap)) / 2));
  align-items: start;
}
.corridor-plate img { aspect-ratio: 3 / 4; max-height: 84vh; }
.corridor-label h2 { margin-bottom: clamp(0.9rem, 2vw, 1.3rem); }
.corridor-label p + .cap { margin-top: 1.1rem; display: block; }

@media (min-width: 881px) {
  .corridor-plate .plate {
    border-inline-start: 0;
    padding-inline-start: 0;
    border-start-start-radius: 0;
    border-end-start-radius: 0;
  }
}
@media (max-width: 880px) {
  .corridor {
    grid-template-columns: 1fr;
    padding-inline: var(--gutter);
  }
  .corridor-plate img { aspect-ratio: 4 / 5; }
  .corridor-label { --drop: clamp(1.9rem, 5vw, 3rem); }
}

/* ------------------------------------------- family 4: the flash-sheet grid --
   Three frames of three different widths at three different depths, read left
   to right along the rail. Never three equal cards: that is the point of the
   section. motion.js staggers the children of .gallery, which is the only
   stagger on the page, and it is hierarchy: it teaches the eye to walk the
   wall the way the shop is walked. */
.sec-head { margin-bottom: clamp(2rem, 4.5vw, 3.5rem); }
.sec-head h2 { margin-bottom: 0.9rem; }
.sec-head p { color: var(--muted); }

.gallery {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: clamp(1rem, 2.2vw, 2rem);
  align-items: start;
  /* Its own rail. Without it the three frames hang from nothing and the wires
     read as floating rather than as hung. */
  border-top: 1px solid var(--line);
}
.gallery > * { min-width: 0; }
.g-a { grid-column: span 5; }
.g-b { grid-column: span 3; }
.g-c { grid-column: span 4; }
.g-a img { aspect-ratio: 3 / 4; }
.g-b img { aspect-ratio: 480 / 848; }
.g-c img { aspect-ratio: 1 / 1; }

@media (max-width: 960px) {
  .gallery { grid-template-columns: repeat(6, 1fr); }
  .g-a { grid-column: span 6; }
  .g-b { grid-column: span 3; }
  .g-c { grid-column: span 3; }
  .g-a img { aspect-ratio: 4 / 3; }
}
@media (max-width: 620px) {
  .gallery { grid-template-columns: 1fr; }
  .g-a, .g-b, .g-c { grid-column: 1 / -1; }
  .g-b { --drop: clamp(1.5rem, 5vw, 2.25rem); }
  .g-c { --drop: clamp(1.5rem, 5vw, 2.25rem); }
  .g-a img { aspect-ratio: 4 / 5; }
}

/* --------------------------------------------- family 5: the three notes --
   The rail motif at small scale: each note has its own rule and hangs from it
   at its own depth, and the three columns are deliberately unequal. This is
   where the page says plainly that it publishes no price. */
.notes {
  display: grid;
  grid-template-columns: 1.15fr 1fr 0.92fr;
  gap: clamp(1.5rem, 3.5vw, 3.5rem);
}
.note {
  border-top: 1px solid var(--line);
  min-width: 0;
}
.note h3 { margin-bottom: 0.6rem; }
.note p { color: var(--muted); font-size: 0.98rem; }

@media (max-width: 820px) {
  .notes { grid-template-columns: 1fr; gap: 1.75rem; }
  .note { --drop: clamp(1.5rem, 5vw, 2.25rem); }
}

/* ------------------------------------------- family 6: the ruled consult --
   One frame around the whole thing, inset. The form sits inside it; nothing
   else on the page is boxed like this, so the booking route is the one place
   the eye is drawn to. */
.book-frame {
  display: grid;
  grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.25fr);
  gap: clamp(1.75rem, 4vw, 3.5rem);
  padding: clamp(1.25rem, 3.5vw, 2.75rem);
  background: var(--mat);
  border: 1px solid var(--line);
  border-radius: var(--r);
}
.book-aside h2 { margin-bottom: 0.9rem; }
.book-aside p { color: var(--muted); }
.tel-big {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 48px;
  margin-top: 1.2rem;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.25rem, 1.1rem + 0.6vw, 1.6rem);
  color: var(--accent);
  text-decoration: none;
  border-bottom: 2px solid var(--accent);
  font-variant-numeric: tabular-nums;
}

.form {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1rem 1.1rem;
}
.field {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  min-width: 0;
  /* booking.css gives the textarea `border-radius: inherit`, so the radius
     system reaches it through the field rather than through a second value. */
  border-radius: var(--r);
}
.field.full { grid-column: 1 / -1; }
.form label {
  font-family: var(--font-display);
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--ink);
}
.form input,
.form select {
  font: inherit;
  font-size: 1rem;
  width: 100%;
  min-height: 48px;
  padding: 0.65rem 0.8rem;
  background: var(--bg-3);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--r);
}
/* The native select keeps its own caret on purpose. Stripping `appearance`
   and drawing a chevron is how a select stops looking like a select on the
   one platform nobody tested, and this form is filled in one-handed on a
   phone outside the shop. */
.form textarea { min-height: 4.5em; }

.form-error, .form-ok {
  grid-column: 1 / -1;
  margin: 0;
  display: none;
  font-size: 0.97rem;
  max-width: none;
}
.form-error.show, .form-ok.show { display: block; }
.form-error {
  color: var(--bad);              /* 5.61:1 */
  font-weight: 500;
  border-inline-start: 3px solid var(--bad);
  padding-inline-start: 0.7rem;
}
.form-error a { color: inherit; }
.form-ok {
  color: var(--ink);
  border-inline-start: 3px solid var(--accent);
  padding-inline-start: 0.7rem;
}
.book-note {
  grid-column: 1 / -1;
  color: var(--muted);
  font-size: 0.88rem;
  margin: 0;
}
.book-result { border-radius: var(--r); margin-top: 1rem; }

@media (max-width: 880px) {
  .book-frame { grid-template-columns: 1fr; }
}
@media (max-width: 560px) {
  .form { grid-template-columns: 1fr; }
  .field.full { grid-column: 1 / -1; }
}

/* ---------------------------------------------- family 7: how to find it --
   Address, the one telephone number that is confirmed, and an honest list of
   the routes that are not. site.js strips the href from anything unconfirmed,
   so every label here has to read correctly as plain text. */
.visit-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(1.75rem, 4vw, 4rem);
  align-items: start;
}
.visit-grid h2 { margin-bottom: clamp(0.9rem, 2vw, 1.3rem); }
.addr { font-size: 1.1rem; line-height: 1.7; }
.addr .street { font-weight: 500; }
.addr .district { color: var(--muted); }

.contact-list { list-style: none; margin: 1.5rem 0 0; padding: 0; }
.contact-list li + li { margin-top: 0.5rem; }
.contact-list a {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  min-height: 44px;
  font-weight: 500;
}

.pending { margin-top: clamp(1.5rem, 3vw, 2.25rem); }
.pending h3 {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--muted);
  font-weight: 600;
  padding-top: 0.9rem;
  border-top: 1px solid var(--line);
}
.pending ul { list-style: none; margin: 0.8rem 0 0; padding: 0; }
.pending li { margin-bottom: 0.9rem; }
.pending li > * { display: block; }
.pending a {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  min-height: 44px;
  color: var(--ink);
  font-weight: 500;
}
.pending .aside { text-transform: none; letter-spacing: 0; font-size: 0.88rem; }

/* ---------------------------------------------------------------- footer -- */
.site-foot {
  border-top: 1px solid var(--line);
  padding-block: clamp(2.5rem, 5vw, 4rem) clamp(2rem, 4vw, 3rem);
}
.foot-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem 2rem;
  align-items: flex-start;
  justify-content: space-between;
}
.foot-brand {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.1rem;
  letter-spacing: -0.015em;
}
.site-foot address { color: var(--muted); font-size: 0.95rem; margin-top: 0.3rem; }
.foot-links { display: flex; flex-wrap: wrap; gap: 0.25rem 1rem; }
.foot-links a {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  min-height: 44px;
  font-size: 0.95rem;
}
.demo-notes {
  margin-top: clamp(2rem, 4vw, 3rem);
  padding-top: clamp(1.25rem, 3vw, 2rem);
  border-top: 1px solid var(--line);
  color: var(--muted);
  font-size: 0.85rem;
  line-height: 1.7;
}
.demo-notes p { max-width: 82ch; }
.demo-notes p + p { margin-top: 0.5rem; }

/* ----------------------------------------------------------- narrow view --
   Declared here rather than assumed: every multi-column layout on this page
   collapses to one column, and the rail and the mat survive the collapse
   because they are the site. */
@media (max-width: 880px) {
  .visit-grid,
  .ledger-grid { grid-template-columns: 1fr; }
  .ledger-hang { --drop: clamp(1.9rem, 5vw, 3rem); }
}
