/* ============================================================================
   Frisco Eye Source — visual direction pass
   ----------------------------------------------------------------------------
   Loaded LAST. Built from the four references in "Visual Directions":

     Eyes in Disguise  stacked full-width colour bands, serif display type
     Clinica Gatti     alternating warm bands; contact info as a BAND, not a
                       sidebar — the model for the relocated .visit-band
     Acuity Eye Group  edge-to-edge hero, colour gradient bleeding into photo
     Sandhurst         dark hero, GOLD accent on the headline, full-width
                       strip beneath the hero

   All four stack full-bleed colour blocks. Frisco's measured palette already
   has what that needs — lilac #f4edf4, gold #ffd700, deep 26/24/36, plus
   violet and orchid channels — so nothing is borrowed from the references but
   structure.

   Technique: bands are full-bleed without any wrapper markup, using
   padding-inline: max(gutter, (100% - measure)/2). The background runs edge to
   edge; the content stays centred and readable.
   ========================================================================= */

:root {
  --band-max: 1180px;
  --band-gutter: 24px;
  --band-pad: clamp(56px, 7vw, 104px);

  --deep:    rgb(var(--ch-deep));
  --lilac:   rgb(var(--ch-lilac));
  --violet:  rgb(var(--ch-violet));
  --orchid:  rgb(var(--ch-orchid));
  --gold-c:  rgb(var(--ch-gold));
}

/* The blob canvas fought the solid bands for the same surface. Bands are the
   colour story now, so the canvas steps back rather than being deleted — it
   still warms the gaps between bands. */
.bg-blobs { opacity: 0.55; }

/* ---- the band primitive -------------------------------------------------- */
.page > .shell,
.page-grid { max-width: none; width: 100%; padding: 0; margin: 0; display: block; }

.page > .shell > .page-grid > .prose { max-width: none; }

.prose > section.panel,
.visit-band,
.cta-band {
  /* full-bleed background, centred content, no wrapper needed */
  padding-block: var(--band-pad);
  padding-inline: max(var(--band-gutter), calc((100% - var(--band-max)) / 2));
  margin: 0;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  background-image: none;
}

/* ---- the colour sequence -------------------------------------------------- */
/* 1 intro · 2 Request Appointment · 3 Meet Our Eye Doctor · 4 Optical Shop */
.prose > section.panel:nth-of-type(1) { background-color: var(--lilac); }
.prose > section.panel:nth-of-type(2) { background-color: #fff; }
.prose > section.panel:nth-of-type(3) {
  background-color: rgb(var(--ch-violet) / 0.10);
  border-top: 1px solid rgb(var(--ch-violet) / 0.16);
  border-bottom: 1px solid rgb(var(--ch-violet) / 0.16);
}
.prose > section.panel:nth-of-type(4) { background-color: var(--lilac); }

/* ---- hero: edge to edge, gradient into the photograph --------------------- */
.hero { position: relative; isolation: isolate; padding: 0; }
.hero > .shell { max-width: none; width: 100%; padding: 0; }

.hero-inner {
  position: relative;
  min-height: clamp(540px, 72vh, 760px);
  display: grid;
  align-content: center;
  /* the glass pane is dropped here — the references put hero type straight
     onto the image, carried by a gradient rather than a panel */
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  padding-block: var(--band-pad);
  padding-inline: max(var(--band-gutter), calc((100% - var(--band-max)) / 2));
}

.hero-media {
  position: absolute; inset: 0; z-index: 0; margin: 0; border-radius: 0;
  overflow: hidden;
}
.hero-media img { width: 100%; height: 100%; object-fit: cover; object-position: center 40%; }

/* Acuity bleeds a solid colour across the left of the photo; Sandhurst does the
   same in near-black. This is Frisco's own deep tone doing that job. */
.hero-media::after {
  content: "";
  position: absolute; inset: 0;
  background:
    linear-gradient(96deg,
      rgb(var(--ch-deep) / 0.94) 0%,
      rgb(var(--ch-deep) / 0.80) 34%,
      rgb(var(--ch-deep) / 0.42) 62%,
      rgb(var(--ch-deep) / 0.14) 100%);
}

.hero-copy { position: relative; z-index: 2; max-width: 44rem; }
.hero-copy h1 { color: #fff; }
/* Sandhurst sets the last line of the headline in gold. Here the emphasis lands
   on the place name, which is also what the page is optimised for. */
.hero-copy h1::after {
  content: "";
  display: block;
  width: 72px; height: 4px;
  background: var(--gold-c);
  border-radius: 2px;
  margin-top: clamp(18px, 2vw, 26px);
}
.hero-copy .hero-lede { color: rgb(var(--ch-paper) / 0.92); }
.hero-copy .hero-lede a { color: var(--gold-c); }
.hero-copy .eyebrow { color: rgb(var(--ch-paper) / 0.86); }

/* ---- images edge to edge inside their bands -------------------------------- */
.prose > section.panel img.wide,
.prose > section.panel > figure img {
  width: 100%;
  border-radius: 0;
}
/* The opening photograph spans the band, not the text measure. */
.prose > section.panel:nth-of-type(1) img.wide {
  width: 100vw;
  max-width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-block: 0 clamp(28px, 4vw, 48px);
  height: clamp(320px, 42vw, 560px);
  object-fit: cover;
}

.figgrid { gap: 2px; }
.figgrid figure { border-radius: 0; overflow: hidden; }
.figgrid img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }

/* ---- the relocated sidebar, now a dark band ------------------------------- */
.visit-band {
  background-color: var(--deep);
  color: rgb(var(--ch-paper) / 0.88);
}
.visit-inner {
  display: grid;
  grid-template-columns: 1.25fr 1fr 1fr;
  gap: clamp(28px, 4vw, 64px);
  align-items: start;
}
.visit-band h2 {
  color: #fff;
  font-size: clamp(1.7rem, 2.8vw, 2.5rem);
  line-height: 1.18;
  margin: 0 0 var(--sp-12, 14px);
}
.visit-band h2 em { font-style: normal; color: var(--gold-c); }
.visit-band h3 {
  color: #fff;
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 2px;
  margin: 0 0 18px;
  padding-bottom: 12px;
  border-bottom: 2px solid rgb(var(--ch-gold) / 0.65);
}
.visit-addr { color: rgb(var(--ch-paper) / 0.78); margin-bottom: 26px; }
.visit-band .eyebrow { color: var(--gold-c); }

.visit-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 11px; font-size: 0.95rem; }
.visit-list li {
  display: flex; justify-content: space-between; gap: 18px;
  padding-bottom: 10px;
  border-bottom: 1px solid rgb(var(--ch-paper) / 0.14);
}
.visit-list li:last-child { border-bottom: 0; }
.visit-list b { color: #fff; font-weight: 600; }
.visit-list a { color: var(--gold-c); text-decoration: none; }
.visit-list a:hover { text-decoration: underline; text-underline-offset: 3px; }
.visit-list span { color: rgb(var(--ch-paper) / 0.76); }
/* 0.45 measured 4.48 against the deep band — two hundredths under AA. 0.52
   still reads as "this day is closed" without failing. */
.visit-list .closed { color: rgb(var(--ch-paper) / 0.52); }

.visit-band .btn-ghost { border-color: rgb(var(--ch-paper) / 0.5); color: #fff; }
.visit-band .btn-ghost:hover { background: #fff; color: var(--deep); }

/* ---- CTA band: gold, the one saturated block ------------------------------ */
.cta-band {
  background-color: var(--gold-c);
  background-image: none;
  color: rgb(var(--ch-deep));
  text-align: center;
}
.cta-band h2 { color: rgb(var(--ch-deep)); }
.cta-band p { color: rgb(var(--ch-deep) / 0.80); max-width: 46rem; margin-inline: auto; }
.cta-band .btn-row { justify-content: center; }
.cta-band .btn-primary { background: rgb(var(--ch-deep)); color: #fff; border-color: transparent; }
.cta-band .btn-ghost { border-color: rgb(var(--ch-deep) / 0.42); color: rgb(var(--ch-deep)); }
.cta-band .btn-ghost:hover { background: rgb(var(--ch-deep)); color: #fff; }

/* ---- reviews sit on their band, not on glass ------------------------------ */
.reviews { gap: 16px; }
.review { border-radius: var(--r-md); }

/* ---- footer closes the stack in the deep tone ----------------------------- */
/* background-image must be cleared explicitly: site.css:629 paints a 135deg white
   sheen (--glass-sheen-deep) over the footer, and overriding background-color alone
   leaves it on top. Measured, it lifted the footer's top-left to rgb(62,60,70) while
   the visit band directly above sat at rgb(26,24,36) — two bands meant to be the same
   tone reading visibly different. The blur is a live compositing cost behind an opaque
   colour, so it goes too. */
.site-footer {
  background-color: var(--deep); border-top: 0;
  background-image: none;
  -webkit-backdrop-filter: none; backdrop-filter: none;
}

/* ---- responsive ----------------------------------------------------------- */
@media (max-width: 960px) {
  .visit-inner { grid-template-columns: 1fr 1fr; }
  .visit-lead { grid-column: 1 / -1; }
}
@media (max-width: 640px) {
  :root { --band-gutter: 18px; }
  .visit-inner { grid-template-columns: 1fr; gap: 34px; }
  .hero-inner { min-height: clamp(460px, 74vh, 620px); }
  .hero-media::after {
    background: linear-gradient(180deg,
      rgb(var(--ch-deep) / 0.72) 0%,
      rgb(var(--ch-deep) / 0.88) 62%,
      rgb(var(--ch-deep) / 0.95) 100%);
  }
  .prose > section.panel:nth-of-type(1) img.wide { height: clamp(220px, 52vw, 320px); }
}

@media (prefers-reduced-motion: reduce) {
  .bg-blobs { opacity: 0.4; }
}

/* ============================================================================
   Hero — panel removed, gradient carries the type instead
   ----------------------------------------------------------------------------
   site.css:308 put the copy on a frosted panel deliberately. Its comment records
   why: the bare photograph measured 5.93 worst-case — a nominal AA pass that was
   still hard to read, because the backdrop is shelving and signage rather than a
   flat field. Removing the panel is therefore only safe if something else
   flattens that area, so the scrim below holds a near-solid plateau across the
   whole text column before falling away to reveal the room.
   ========================================================================= */

/* .hero-inner.glass is 0-2-0; a bare .hero-inner rule loses to it. */
.hero-inner.glass { box-shadow: none; background: none; }

.hero-copy {
  padding: 0;
  margin-inline: 0;
  background-color: transparent;
  background-image: none;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}

/* The plateau: flat to 46%, so every line of copy sits on one value. */
.hero-media::after {
  background:
    linear-gradient(100deg,
      rgb(var(--ch-deep) / 0.95) 0%,
      rgb(var(--ch-deep) / 0.93) 30%,
      rgb(var(--ch-deep) / 0.90) 46%,
      rgb(var(--ch-deep) / 0.52) 68%,
      rgb(var(--ch-deep) / 0.10) 100%);
}

/* ::before carried a second scrim plus a gold glow; the scrim would now double
   up, so only the glow is kept. */
.hero-inner::before { background: var(--hero-glow); }

/* ============================================================================
   Bento — four stacked full-width photos become one compact grid
   ----------------------------------------------------------------------------
   The OPTOS banner and three 1280x853 photographs ran at full column width, one
   under another, which is the scrolling problem. Same images, same captions,
   same links — laid out as a banner across the top and a neat three-up row, with
   every photo cropped to one aspect so the row reads as a single block.
   ========================================================================= */
.bento-wrap { margin-block: clamp(28px, 4vw, 48px); }

.bento-head {
  font-size: clamp(1.35rem, 2.2vw, 1.9rem);
  margin: 0 0 clamp(18px, 2.2vw, 28px);
  padding-bottom: 12px;
  border-bottom: 2px solid rgb(var(--ch-gold) / 0.55);
}

.bento {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(12px, 1.4vw, 20px);
}

.bento-item {
  display: flex;
  flex-direction: column;
  background: #fff;
  border-radius: var(--r-md);
  overflow: hidden;
  box-shadow: 0 1px 2px rgb(var(--ch-deep) / 0.06), 0 8px 24px rgb(var(--ch-deep) / 0.07);
  transition: transform 260ms var(--ease, ease), box-shadow 260ms var(--ease, ease);
}
.bento-item:hover { transform: translateY(-3px); box-shadow: 0 2px 4px rgb(var(--ch-deep) / 0.08), 0 16px 38px rgb(var(--ch-deep) / 0.13); }

.bento-media { margin: 0; overflow: hidden; }
.bento-media img {
  display: block;
  width: 100%;
  height: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: 0;
  margin: 0;
  max-width: none;
}

/* The banner is a wide 1280x480 graphic; cropping it to 4:3 would cut the
   product art, so it keeps its own ratio and spans the full row. */
.bento-banner { grid-column: 1 / -1; }
.bento-banner .bento-media img {
  aspect-ratio: 1280 / 480;
  object-fit: contain;
  background: #0b5ed7;
}

.bento-body { padding: clamp(14px, 1.6vw, 20px); display: flex; flex-direction: column; gap: 8px; }
.bento-body h4 { margin: 0; font-size: 1.02rem; line-height: 1.3; }
.bento-body h4 a { text-decoration: none; }
.bento-body h4 a:hover { text-decoration: underline; text-underline-offset: 3px; }
.bento-body p { margin: 0; font-size: 0.9rem; color: var(--ink-muted); }

@media (max-width: 860px) {
  .bento { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
  .bento { grid-template-columns: 1fr; }
  .bento-media img { aspect-ratio: 16 / 9; }
}
@media (prefers-reduced-motion: reduce) {
  .bento-item, .bento-item:hover { transform: none; transition: none; }
}

/* .prose > section.panel img.wide is 0-3-1 and outranks .bento-media img
   (0-1-1). The bento images still carry class="wide" from the source markup, so
   the crop is restated at matching weight rather than relying on order. */
.prose > section.panel .bento-media img.wide,
.prose > section.panel .bento-media img {
  width: 100%;
  max-width: none;
  margin: 0;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: 0;
  height: auto;
}
.prose > section.panel .bento-banner .bento-media img {
  aspect-ratio: 1280 / 480;
  object-fit: contain;
}

/* ============================================================================
   Layout & hierarchy pass — the remaining sections
   ----------------------------------------------------------------------------
   Applying what the bento pass established: loose content gets a container, and
   anything that repeats down the page becomes a row instead of a stack.

   What the heading audit turned up (37 headings, 0 level skips, but):
     - four primary CTAs sat as bare <a> tags after the opening photo and read
       as one run-on line of underlined text            -> .quick-actions
     - "What's New?" and the two posts were buried at h4/h5 inside the optical
       shop section                                      -> .postlist row
     - Contact Us / Locate Us / Hours also live down there, now that the same
       facts head the .visit-band; they are kept but laid out as a row so the
       repetition reads as a summary, not a second directory
   ========================================================================= */

/* ---- quick actions: four patient tasks, not a sentence -------------------- */
.quick-actions {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(10px, 1.2vw, 16px);
  margin-block: clamp(22px, 3vw, 34px);
}
.qa-item {
  display: flex;
  align-items: center;
  min-height: 74px;
  padding: 14px 18px;
  background: #fff;
  border: 1px solid rgb(var(--ch-deep) / 0.10);
  border-left: 3px solid var(--gold-c);
  border-radius: var(--r-sm);
  color: var(--ink-strong);
  font-weight: 600;
  font-size: 0.95rem;
  line-height: 1.3;
  text-decoration: none;
  transition: transform 220ms var(--ease, ease), box-shadow 220ms var(--ease, ease), border-color 220ms var(--ease, ease);
}
/* Gold works on the deep bands but measures 1.40 against white — the arrow was
   effectively invisible. It carries the affordance, so it takes the ink colour;
   gold stays on the left stripe, where it is decoration rather than signal. */
.qa-item::after {
  content: "\2192";
  margin-left: auto;
  padding-left: 12px;
  color: rgb(var(--ch-deep) / 0.7);
  font-weight: 700;
  transition: transform 220ms var(--ease, ease), color 220ms var(--ease, ease);
}
.qa-item:hover::after { color: rgb(var(--ch-deep)); }
.qa-item:hover {
  transform: translateY(-2px);
  box-shadow: 0 10px 26px rgb(var(--ch-deep) / 0.12);
  border-color: rgb(var(--ch-deep) / 0.18);
}
.qa-item:hover::after { transform: translateX(4px); }

/* ---- posts: a row of two, not a stack ------------------------------------- */
.postlist {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(16px, 2vw, 26px);
  margin-block: clamp(18px, 2.4vw, 28px);
}
.post {
  background: #fff;
  border-radius: var(--r-md);
  padding: clamp(18px, 2vw, 26px);
  border-top: 3px solid var(--gold-c);
  box-shadow: 0 1px 2px rgb(var(--ch-deep) / 0.05), 0 8px 22px rgb(var(--ch-deep) / 0.06);
  display: flex; flex-direction: column; gap: 10px;
}
.post h5, .post h4 { margin: 0; font-size: 1.06rem; line-height: 1.3; }
.post-date {
  order: -1;
  font-size: 0.74rem; text-transform: uppercase; letter-spacing: 1.6px;
  color: var(--ink-muted);
}
.post-excerpt { margin: 0; font-size: 0.93rem; }
.post-more { align-self: flex-start; font-weight: 600; text-decoration: none; border-bottom: 2px solid var(--gold-c); padding-bottom: 2px; }

/* ---- section rhythm: one consistent vertical scale ------------------------ */
.prose > section.panel > :first-child { margin-top: 0; }
.prose h2 {
  font-size: clamp(1.9rem, 3vw, 2.7rem);
  line-height: 1.16;
  margin-bottom: clamp(18px, 2.2vw, 28px);
}
/* A gold rule under every h2 repeats the hero's cue, so each band opens the
   same way instead of each one inventing its own entrance. */
.prose > section.panel > h2::after,
.prose > section.panel > h2 + p::before { content: none; }
.prose > section.panel > h2 {
  padding-bottom: 14px;
  border-bottom: 2px solid rgb(var(--ch-gold) / 0.5);
}
.prose h3 { font-size: clamp(1.18rem, 1.7vw, 1.44rem); margin-top: clamp(26px, 3vw, 40px); }
.prose h4 { font-size: 1.02rem; margin-top: clamp(20px, 2.2vw, 28px); }
.prose p { max-width: 74ch; }

/* ---- the doctor bio ------------------------------------------------------- */
.bio { display: grid; grid-template-columns: 240px minmax(0, 1fr); gap: clamp(22px, 3vw, 44px); align-items: start; }
.bio-photo { margin: 0; }
.bio-photo img { width: 100%; border-radius: var(--r-md); }
.bio-body > :last-child { margin-bottom: 0; }

/* ---- brand logo strip ----------------------------------------------------- */
.figgrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: clamp(10px, 1.2vw, 16px);
  margin-block: clamp(18px, 2.2vw, 28px);
}
.figgrid figure { margin: 0; background: #fff; border-radius: var(--r-sm); overflow: hidden; }
.figgrid figcaption { padding: 10px 14px; font-size: 0.86rem; color: var(--ink-muted); }

@media (max-width: 900px) {
  .quick-actions { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 720px) {
  .postlist { grid-template-columns: 1fr; }
  .bio { grid-template-columns: 1fr; }
  .bio-photo { max-width: 200px; }
}
@media (max-width: 480px) {
  .quick-actions { grid-template-columns: 1fr; }
  .qa-item { min-height: 58px; }
}
@media (prefers-reduced-motion: reduce) {
  .qa-item, .qa-item:hover, .qa-item:hover::after { transform: none; transition: none; }
}

/* ============================================================================
   Two-column blocks, contact card, and a tint override
   ----------------------------------------------------------------------------
   "Eye Exams for the Whole Family" shipped TWICE on the source site — verified
   in audit/raw/index.html, which also contains it twice. The reforge copied the
   defect faithfully. The second copy is now dropped; this is the one place the
   page deliberately departs from the source, because rendering the same block
   twice is not fidelity worth keeping.
   ========================================================================= */

/* ---- .split : heading + lede left, detail + CTA right --------------------- */
.split {
  display: grid;
  grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr);
  gap: clamp(24px, 4vw, 64px);
  align-items: start;
  margin-block: clamp(24px, 3vw, 40px);
}
.split-a > h3 { margin-top: 0; }
.split-a > p { font-size: clamp(1.02rem, 1.25vw, 1.16rem); color: var(--ink-strong); }
.split-b > p { margin-top: 0; }
.split .split-cta { margin-bottom: 0; }
.split .split-cta a {
  display: inline-flex; align-items: center; gap: 8px;
  font-weight: 600; text-decoration: none;
  border-bottom: 2px solid var(--gold-c); padding-bottom: 2px;
}
.split .split-cta a::after { content: "\2192"; transition: transform 200ms var(--ease, ease); }
.split .split-cta a:hover::after { transform: translateX(4px); }

/* ---- contact + map, side by side ------------------------------------------ */
.contact-locate {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: clamp(18px, 2.4vw, 32px);
  align-items: stretch;
  margin-block: clamp(22px, 3vw, 36px);
}
.cl-card {
  background: #fff;
  border-radius: var(--r-md);
  padding: clamp(20px, 2.4vw, 30px);
  border-left: 3px solid var(--gold-c);
  box-shadow: 0 1px 2px rgb(var(--ch-deep) / 0.05), 0 8px 22px rgb(var(--ch-deep) / 0.06);
  /* the street address is a bare text node in the source markup, so the line
     height and colour have to come from the container */
  line-height: 1.7;
  color: var(--ink-body);
}
.cl-card > h4 {
  margin: 0 0 6px;
  font-size: 0.78rem; text-transform: uppercase; letter-spacing: 2px;
  color: var(--ink-muted);
}
.cl-card > h5 { margin: 0 0 10px; font-size: 1.12rem; }
.cl-card > h5 a { text-decoration: none; }
.cl-card > h5 a:hover { text-decoration: underline; text-underline-offset: 3px; }
.cl-card ul {
  list-style: none; margin: 16px 0 0; padding: 16px 0 0;
  border-top: 1px solid rgb(var(--ch-deep) / 0.10);
  display: grid; gap: 10px;
}
.cl-card li { display: flex; flex-wrap: wrap; gap: 8px; font-size: 0.95rem; }
.cl-card li strong { min-width: 58px; color: var(--ink-strong); }
.cl-card li a { text-decoration: none; border-bottom: 1px solid rgb(var(--ch-gold) / 0.8); }
.cl-card li br + * , .cl-card li br { font-size: 0.85rem; }

.cl-map { display: flex; flex-direction: column; min-height: 320px; }
.cl-map > h4 {
  margin: 0 0 6px;
  font-size: 0.78rem; text-transform: uppercase; letter-spacing: 2px;
  color: var(--ink-muted);
}
.cl-map iframe {
  flex: 1 1 auto;
  width: 100%;
  min-height: 300px;
  border: 0;
  border-radius: var(--r-md);
  display: block;
}

/* ---- post tint: site.css:534 is 0-3-0 and outranked the flat white --------- */
.postlist .post,
.postlist .post:nth-child(even),
.postlist .post:nth-child(odd) {
  background-color: #fff;
  background-image: none;
}

@media (max-width: 860px) {
  .split { grid-template-columns: 1fr; gap: clamp(14px, 2vw, 22px); }
  .contact-locate { grid-template-columns: 1fr; }
  .cl-map { min-height: 280px; }
}

/* ============================================================================
   Compaction pass — measured, not eyeballed
   ----------------------------------------------------------------------------
   Resolved at a 1440px viewport, the page was spending:

     --band-pad          100.8px top AND bottom, across 6 bands   = 1210px
     .hero-inner          648px min-height
     intro photo          560px fixed height
     component margins    96 / 80 / 72 / 68 / 56 / 56px blocks

   Band padding alone was more than a full viewport of empty space. Everything
   below is a reduction of an existing value — no layout is restructured, so
   nothing can break that was working a moment ago.
   ========================================================================= */

:root {
  /* 100.8px -> 54.7px at 1440. Six bands: 1210px -> 656px. */
  --band-pad: clamp(34px, 3.8vw, 64px);
}

/* 648 -> 470 at 1440; still a full-bleed hero, one less screen of scroll. */
.hero-inner { min-height: clamp(400px, 46vh, 520px); }

/* 560 -> 380. The photograph still spans the viewport, just less tall. */
.prose > section.panel:nth-of-type(1) img.wide {
  height: clamp(220px, 26vw, 380px);
  margin-block: 0 clamp(18px, 2.2vw, 30px);
}

/* Component rhythm: every block halved, kept proportional to each other. */
.bento-wrap     { margin-block: clamp(20px, 2.2vw, 34px); }
.split          { margin-block: clamp(16px, 1.8vw, 28px); }
.contact-locate { margin-block: clamp(16px, 1.8vw, 26px); }
.quick-actions  { margin-block: clamp(16px, 1.8vw, 26px); }
.postlist       { margin-block: clamp(14px, 1.6vw, 22px); }
.figgrid        { margin-block: clamp(14px, 1.6vw, 22px); }

/* Heading spacing was set for a roomier page than this one now is. */
.prose h2 { margin-bottom: clamp(14px, 1.6vw, 22px); padding-bottom: 10px; }
.prose h3 { margin-top: clamp(18px, 1.8vw, 26px); margin-bottom: 10px; }
.prose h4 { margin-top: clamp(14px, 1.4vw, 20px); margin-bottom: 8px; }
.prose p  { margin-bottom: clamp(12px, 1.1vw, 16px); }

/* Paragraphs were capped at 74ch, which makes long copy tall in a 1180px band.
   80ch fills more of the measure without pushing past comfortable reading. */
.prose p { max-width: 80ch; }

.bento { gap: clamp(10px, 1.1vw, 14px); }
.bento-body { padding: clamp(12px, 1.3vw, 16px); gap: 6px; }
.bento-head { margin-bottom: clamp(12px, 1.5vw, 18px); padding-bottom: 9px; }

.cl-map { min-height: 260px; }
.cl-map iframe { min-height: 240px; }
.cl-card { padding: clamp(16px, 1.9vw, 24px); line-height: 1.6; }

.visit-inner { gap: clamp(20px, 2.6vw, 44px); }
.visit-addr { margin-bottom: 18px; }
.visit-band h3 { margin-bottom: 13px; padding-bottom: 9px; }

.post { padding: clamp(14px, 1.6vw, 20px); gap: 7px; }
.qa-item { min-height: 62px; padding: 12px 16px; }

.site-footer { padding-block: clamp(34px, 4vw, 60px) clamp(20px, 2vw, 30px); }
.footer-bottom { margin-top: clamp(22px, 2.6vw, 36px); padding-top: 18px; }

/* The reviews rail and the form both sat inside the old rhythm. */
.reviews { gap: 14px; }
.appt-form { gap: clamp(14px, 1.6vw, 20px); }

@media (max-width: 640px) {
  :root { --band-pad: clamp(28px, 6vw, 40px); }
  .hero-inner { min-height: clamp(360px, 54vh, 440px); }
}

/* site.css:386 puts aspect-ratio:16/9 and height:auto on every .prose iframe.
   In the .cl-map column that fights `flex: 1 1 auto`, so the map either
   overshoots its card or collapses. The map is a fixed-height panel here, not a
   video, so the ratio is released and the flex height governs. */
.cl-map iframe {
  aspect-ratio: auto;
  height: 100%;
  box-shadow: none;
}

/* ── session 4: defects found by actually looking at the rendered page ──── */

/* The Red Cross graphic is a bare <img> sibling of the "Eye Emergencies"
   heading — no wrapper, so it rendered at its full 113px above the text and
   inherited `.prose img` (site.css:365), which put a white rounded card and a
   glass shadow around it. A lone red icon in a floating pane, with the rest of
   the row empty. It is now wrapped in .emerg-head and sits on the heading line.
   Selectors are .prose-qualified (0-2-1) to beat `.prose img` and `.prose h3`
   (both 0-1-1) on weight rather than on source order. */
.prose .emerg-head {
  display: flex;
  align-items: center;
  gap: clamp(12px, 1.3vw, 18px);
  margin-top: clamp(18px, 2vw, 28px);
  margin-bottom: clamp(10px, 1.1vw, 14px);
}
.prose .emerg-head img {
  width: clamp(38px, 3.4vw, 50px);
  height: auto;
  flex: none;
  margin: 0;
  border-radius: 0;
  box-shadow: none;
}
.prose .emerg-head h3 { margin: 0; }

/* .footer-grid is `repeat(auto-fit, minmax(210px, 1fr))`. Five children, but
   only four fit across 1180px — so the appointment form wrapped onto a row of
   its own and rendered as three narrow fields with two thirds of the row empty.
   It spans the full row now, and the fields run across it instead of down. */
.footer-grid > div:last-child { grid-column: 1 / -1; }
.site-footer .footer-form {
  grid-template-columns: repeat(3, minmax(0, 1fr)) auto;
  align-items: end;
  gap: clamp(12px, 1.4vw, 18px);
}
/* site.css:610 sets `.footer-form button { width: 100% }` for the stacked
   layout; in a row it only needs its own width. */
.site-footer .footer-form button { width: auto; }

@media (max-width: 760px) {
  .site-footer .footer-form {
    grid-template-columns: minmax(0, 1fr);
    align-items: stretch;
  }
  .site-footer .footer-form button { width: 100%; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   SESSION 5 — defects found by measuring the rendered page, not by eye.
   Scope is deliberately SKIN ONLY: no content removed, no markup re-ordered,
   no heading levels changed. Every rule below wins on SPECIFICITY where it can,
   because four separate bugs in this project came from writing a low-specificity
   override against a higher-specificity V1 rule and assuming source order saved it.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── 1. 302px of page canvas leaking between the full-bleed bands ────────────
   The V2 direction is an uninterrupted sequence of coloured bands, but three V1
   rules were never reset, so a strip of page background shows between each pair.
   Pixel-scanned down column x=8 of the 1440 capture:
     .page padding-top    (site.css:350, --sp-20)  =  30px under the hero
     .prose row gap       (site.css:359, --sp-19)  =  28px x 4 seams = 112px
     .page padding-bottom (site.css:350, --sp-23)  =  80px before the visit band
     .site-footer margin  (site.css:627, --sp-23)  =  80px (renders 62px) before the footer
   The last one is the worst: a PALE strip wedged between two near-black bands,
   which reads as a failed background rather than a designed gap. Total 302px of
   dead scroll on a page whose owner asked twice for less scrolling.
   All three selectors match the V1 rule's specificity exactly (0-1-0); direction.css
   is the later sheet, so these win on order. Band separation is already carried by
   --band-pad and by the colour change itself, so nothing collapses. */
.page { padding-block: 0; }
.prose { row-gap: 0; }
.site-footer { margin-top: 0; }

/* ── 2. The mobile hero scrim was dead, leaving text on the bare photo ───────
   direction.css:226 sets .hero-media::after inside @media (max-width:640px), but
   direction.css:266 restates the SAME selector unconditionally 40 lines later.
   @media adds nothing to specificity, so the unconditional rule won at every width
   and the mobile scrim never applied anywhere. Measured on the 390px capture, the
   hero lede's first line ran 2.86:1 against the photo behind it and the gold link
   glyphs 4.16:1 — both below the 4.5:1 body-text threshold.
   Qualified as .hero .hero-media::after (0-2-1) so it beats the (0-1-1) rule on
   WEIGHT, and cannot be silently undone by future reordering. */
@media (max-width: 640px) {
  .hero .hero-media::after {
    background: linear-gradient(180deg,
      rgb(var(--ch-deep) / 0.72) 0%,
      rgb(var(--ch-deep) / 0.88) 62%,
      rgb(var(--ch-deep) / 0.95) 100%);
  }
}

/* ── 3. The page had no keyboard focus indicator at all ─────────────────────
   tokens.css:236 defines --focus-ring as a COLOUR; modern.css:32 redefines the same
   property on :root as a four-value BOX-SHADOW. modern.css loads later, so
   site.css:95 `outline: 3px solid var(--focus-ring)` computed to
   `outline: 3px solid 0 0 0 3px rgb(255 215 0 / 0.55)` — invalid at computed-value
   time, which per the CSS Variables spec makes the whole shorthand `unset`, i.e.
   outline-style:none. modern.css:60-78 hands an explicit gold ring to seven selector
   groups (inputs, .btn, nav links); every OTHER focusable element — including all 39
   footer anchors — was left with no visible focus state whatsoever.
   Restated here at (0-1-0), identical weight to site.css:95, winning on source order.
   Deliberately NOT escalated above (0-1-0): modern.css's intentional `outline:none`
   on its seven groups is (0-2-0) and must keep winning, so their gold ring survives. */
:focus-visible {
  outline: 3px solid rgb(var(--ch-violet) / 0.95);
  outline-offset: 3px;
}
/* Give the collision a non-colliding name so it cannot recur. */
:root { --focus-shadow: 0 0 0 3px rgb(var(--ch-gold) / 0.55); }

/* ── 4. Form fields had effectively invisible boundaries ────────────────────
   Measured from the capture: the light form's 1px border rendered #e1e1e3 on #ffffff
   = 1.31:1, and the footer form's #3c3b45 on #26242f = 1.38:1. WCAG 2.1 SC 1.4.11
   requires 3:1 to identify a control's boundary — both fail by more than half.
   Recomputed values: slate at 0.60 over white = rgb(144,143,151) = 3.20:1;
   paper at 0.40 over the footer ground = rgb(125,124,130) = 3.69:1.
   Every selector is scoped :not(:focus-visible):not(:focus) — WITHOUT that guard
   these static border-colours outrank modern.css:60-68's and site.css:602's focused
   border-colour and the gold focus border silently disappears. */
.prose .field input:not(:focus-visible):not(:focus),
.prose .field select:not(:focus-visible):not(:focus),
.prose .field textarea:not(:focus-visible):not(:focus),
form.appt-form input[type="text"]:not(:focus-visible):not(:focus),
form.appt-form input[type="tel"]:not(:focus-visible):not(:focus),
form.appt-form input[type="email"]:not(:focus-visible):not(:focus),
form.appt-form textarea:not(:focus-visible):not(:focus) {
  border-color: rgb(var(--ch-slate) / 0.60);
}
.site-footer .footer-form input:not(:focus-visible):not(:focus),
.site-footer .footer-form select:not(:focus-visible):not(:focus),
.site-footer .footer-form textarea:not(:focus-visible):not(:focus) {
  border-color: rgb(var(--ch-paper) / 0.40);
}

/* ── 5. The main appointment form never stacked on mobile ───────────────────
   site.css:565 sets .appt-form to two columns with no width-based override anywhere.
   The rule meant to stack it — site.css:689 `.appt-form .field.two` — targets a class
   that does not exist in this markup (`grep -o "field two" index.html` returns 0), so
   it has never matched. At 390px each column computes to (354 - 14) / 2 = 170px, so
   "Name/First" sits beside "Last" and "Phone" beside "Email" in 170px boxes.
   .panel .appt-form is (0-2-0) and beats site.css:565's (0-1-0) on weight.
   Note this ADDS roughly 375px of mobile scroll, which pulls against the standing
   "less scrolling" instruction — paid for by items 1 and 7. */
@media (max-width: 640px) {
  .panel .appt-form { grid-template-columns: minmax(0, 1fr); }
}

/* ── 6. The bento heading rendered at 54% of its intended size ──────────────
   .bento-head (0-1-0) loses to .prose h4 (0-1-1) on weight regardless of source
   order, so the largest block on the page was titled at 16.32px instead of the
   intended 30.4px — the same cap height as the body copy beside it. It also
   inherited a gold ::before bar from site.css:516 on top of its own gold
   border-bottom, giving one heading two competing gold cues.
   .prose .bento-head is (0-2-0) and beats .prose h4 on b=2 > b=1. */
.prose .bento-head {
  font-size: clamp(1.35rem, 2.2vw, 1.9rem);
  margin-top: 0;
  margin-bottom: clamp(12px, 1.5vw, 18px);
}
.prose .bento-head::before { content: none; }

/* ── 7. Footer top inset was 2.5x the page rhythm ───────────────────────────
   The compaction pass reduced .site-footer's own padding but left .footer-grid's
   80px, so the footer opened on 140px of nothing while every other band opens on
   ~55px. .site-footer .footer-grid is (0-2-0) against site.css's (0-1-0). */
.site-footer .footer-grid { padding-top: 0; }

/* ===========================================================================
   SESSION 5 - BRAND RETHEME: teal + warm neutrals
   From the client palette "Inspired by Eye Source Interior".

   Done at the CHANNEL level on purpose. tokens.css derives every semantic token
   (--ink-*, --accent*, --glass-*, --rule) from a handful of raw "R G B" channels,
   and site.css is 100% var()-driven by design, so redefining the channels here
   re-skins the entire system - every panel, button, rule, shadow and glass
   surface - instead of needing ~200 edits.

   Glassmorphism is preserved: the glass tokens keep their alpha and blur, they
   just refract teal and ivory now instead of lilac and violet.

   Measured WCAG ratios for the pairs actually used:
     charcoal on soft-ivory ....... 9.48     charcoal on warm-white .. 10.75
     teal headings on soft-ivory .. 7.18     teal on warm-white ....... 8.14
     warm-white on main teal ...... 8.14     white on main teal ....... 9.18
     champagne accent on teal ..... 4.71     charcoal on champagne .... 6.23
   DO NOT use blue-gray (2.76), greige (3.89) or oak (3.86) for text on teal -
   all three fail AA body. Muted text on teal uses white at reduced alpha.
   ======================================================================== */

:root {
  /* ---- the client palette, as raw channels ------------------------------- */
  --ch-teal:       41 77 85;      /* #294D55  MAIN TEAL      feature wall / brand */
  --ch-teal-2:     62 93 96;      /* #3E5D60  SLATE TEAL     secondary walls      */
  --ch-bluegray:  123 145 148;    /* #7B9194  BLUE GRAY      accent walls         */
  --ch-warmwhite: 244 241 233;    /* #F4F1E9  WARM WHITE     cabinetry/reception  */
  --ch-ivory:     232 227 216;    /* #E8E3D8  SOFT IVORY     background           */
  --ch-greige:    170 169 159;    /* #AAA99F  WARM GREIGE    neutral accents      */
  --ch-charcoal:   52 54 56;      /* #343638  CHARCOAL       furniture / text     */
  --ch-walnut:    121 106 56;     /* #796A38  MEDIUM WALNUT  flooring             */
  --ch-oak:       185 165 141;    /* #B9A58D  LIGHT OAK      sunlit wood          */
  --ch-champagne: 211 181 143;    /* #D3B58F  WARM CHAMPAGNE lighting / metallic  */

  /* ---- remap the V1 channels onto the new palette ------------------------ */
  /* Every derived token in tokens.css follows automatically. */
  --ch-deep:   var(--ch-teal);        /* dark bands, hero scrim, visit band, footer */
  --ch-lilac:  var(--ch-ivory);       /* the light band colour                      */
  --ch-slate:  var(--ch-charcoal);    /* body text, hairlines                       */
  --ch-gold:   var(--ch-champagne);   /* the warm accent that replaces gold         */
  --ch-violet: var(--ch-teal-2);      /* focus ring + glass tint                    */
  --ch-orchid: var(--ch-bluegray);    /* backdrop orbs                              */
  --ch-amber:  var(--ch-oak);         /* backdrop orbs / accent gradient end        */

  /* ---- aliases used by the new components -------------------------------- */
  --teal:       rgb(var(--ch-teal));
  --teal-2:     rgb(var(--ch-teal-2));
  --ivory:      rgb(var(--ch-ivory));
  --warm-white: rgb(var(--ch-warmwhite));
  --champagne:  rgb(var(--ch-champagne));

  /* direction.css bound these to the old channels earlier in the file; the
     later declaration wins, so they are rebound rather than edited in place. */
  --deep:   rgb(var(--ch-teal));
  --lilac:  rgb(var(--ch-ivory));
  --gold-c: rgb(var(--ch-champagne));
}

/* The one literal white band in the colour sequence becomes warm white, so the
   page reads as two warm neutrals rather than neutral-plus-clinical-white. */
.prose > section.panel:nth-of-type(2) { background-color: var(--warm-white); }
body { background-color: var(--warm-white); }

/* Headings carry the brand colour on light bands. */
.prose h2, .prose h3 { color: var(--teal); }

/* ---- HERO --------------------------------------------------------------- */
/* Full desktop viewport, as asked. svh rather than vh so mobile browser chrome
   does not push the CTAs below the fold on first paint. */
.hero-inner { min-height: min(100svh, 920px); }

/* The old scrim was a hard 4-stop ramp in near-black (0.94 -> 0.14 over 96deg)
   which read as a black box with an edge. Same idea in the brand teal, with a
   gentler curve and more stops so it fades gradually into the photograph
   instead of stopping. The second layer keeps the top edge readable under the
   sticky header without darkening the whole frame. */
.hero-media::after {
  background:
    linear-gradient(100deg,
      rgb(var(--ch-teal) / 0.94)  0%,
      rgb(var(--ch-teal) / 0.90) 18%,
      rgb(var(--ch-teal) / 0.78) 34%,
      rgb(var(--ch-teal) / 0.60) 48%,
      rgb(var(--ch-teal) / 0.40) 62%,
      rgb(var(--ch-teal) / 0.22) 76%,
      rgb(var(--ch-teal) / 0.10) 88%,
      rgb(var(--ch-teal) / 0.04) 100%),
    linear-gradient(180deg,
      rgb(var(--ch-teal) / 0.34) 0%,
      rgb(var(--ch-teal) / 0.00) 38%);
}
/* Mobile: the copy fills almost the whole hero (eyebrow ~5% down to the
   buttons ~95%), so the ramp must hold >=0.86 from the TOP. It started at 0.74,
   and at 390px that measured 3.26-4.07:1 on the inner pages and 4.46:1 on the
   homepage lede — all under the 4.5:1 body-text line (herocontrast.mjs,
   2026-09-23; the failures predate that session's hero resize). 0.86 over a
   pure-white pixel still yields ~5.5:1, so this is the floor, not a guess. */
@media (max-width: 640px) {
  .hero .hero-media::after {
    background: linear-gradient(180deg,
      rgb(var(--ch-teal) / 0.86) 0%,
      rgb(var(--ch-teal) / 0.90) 45%,
      rgb(var(--ch-teal) / 0.95) 100%);
  }
}

/* Eyebrow: the filled pill is removed, leaving letter-spaced champagne type.
   Qualified .hero .hero-copy (0-3-0) to beat site.css:324 .hero-inner .eyebrow
   (0-2-0) on weight rather than on source order. */
.hero .hero-copy .eyebrow {
  background: none;
  background-image: none;
  border: 0;
  box-shadow: none;
  padding: 0;
  border-radius: 0;
  color: var(--champagne);
  letter-spacing: 0.18em;
}
.hero-copy h1 { color: var(--warm-white); }
.hero-copy h1::after { background: var(--champagne); }
.hero-copy .hero-lede { color: rgb(var(--ch-warmwhite) / 0.92); }
.hero-copy .hero-lede a { color: var(--champagne); }

/* ---- MEGA MENU ---------------------------------------------------------- */
/* Two faults. It was translucent (0.86-alpha pane over a backdrop blur), so the
   gold band and footer read straight through the link text. And the Eye Care
   Services menu puts SEVEN .mega-col blocks into a 4-column grid: 4 in row one,
   3 in row two, leaving an empty cell and very uneven column heights.
   Opaque fixes the first. CSS column-flow fixes the second - the seven blocks
   pack into three balanced columns with no empty cell. */
.mega {
  background-color: var(--warm-white);
  background-image: none;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  border: 1px solid rgb(var(--ch-teal) / 0.22);
  box-shadow: 0 24px 60px rgb(var(--ch-teal) / 0.22), 0 2px 8px rgb(var(--ch-teal) / 0.12);
}
.mega[data-cols="4"] { width: min(760px, 94vw); }
.mega[data-cols="4"] .mega-cols {
  display: block;
  columns: 3;
  column-gap: clamp(20px, 2vw, 30px);
}
.mega[data-cols="4"] .mega-col {
  break-inside: avoid;
  -webkit-column-break-inside: avoid;
  display: inline-block;
  width: 100%;
  margin-bottom: clamp(16px, 1.6vw, 22px);
}
.mega[data-cols="2"] { width: min(500px, 92vw); }

/* Section titles in the brand teal so the groups are scannable. */
.mega h3, .mega h3 a {
  color: var(--teal);
  font-weight: 700;
  border-bottom-color: rgb(var(--ch-teal) / 0.30);
}
.mega a { color: rgb(var(--ch-charcoal) / 0.92); }
.mega a:hover { background: rgb(var(--ch-teal) / 0.10); color: var(--teal); }
.mega-foot a { color: var(--teal); }

@media (max-width: 900px) { .mega[data-cols="4"] .mega-cols { columns: 2; } }
@media (max-width: 640px) { .mega[data-cols="4"] .mega-cols { columns: 1; } }

/* The topbar and sticky header sit over scrolling content too, so they are made
   opaque for the same reason as the mega panel. */
.topbar {
  background-color: var(--teal);
  background-image: none;
  -webkit-backdrop-filter: none; backdrop-filter: none;
}
.site-header {
  background-color: var(--warm-white);
  background-image: none;
  -webkit-backdrop-filter: none; backdrop-filter: none;
  border-bottom: 1px solid rgb(var(--ch-teal) / 0.16);
}

/* ---- QUICK-ACTION ICON STRIP -------------------------------------------- */
/* Was four text-only cards inside the first prose panel. Now a full-bleed strip
   directly under the hero, modelled on the reference: line icon above a short
   label, in an outlined tile. Outlines are 2px, per "a bit thicker outlines".
   Icons are inline SVG rather than generated raster: they stay crisp at any
   size, recolour from the teal token on hover, and cost ~1KB total instead of
   four image requests. */
.qa-strip {
  background: var(--ivory);
  padding-block: clamp(26px, 3.2vw, 44px);
  padding-inline: max(var(--band-gutter), calc((100% - var(--band-max)) / 2));
}
.qa-strip-inner {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(14px, 1.6vw, 22px);
}
.qa-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: 12px;
  text-align: center;
  padding: clamp(18px, 2vw, 26px) clamp(10px, 1.4vw, 18px);
  background: transparent;
  border: 2px solid rgb(var(--ch-teal) / 0.45);
  border-radius: 10px;
  text-decoration: none;
  color: var(--teal);
  font-weight: 600;
  font-size: clamp(0.92rem, 1.05vw, 1rem);
  line-height: 1.35;
  min-height: 0;
  box-shadow: none;
  transition: border-color var(--dur, 0.2s) var(--ease-out, ease),
              background-color var(--dur, 0.2s) var(--ease-out, ease),
              transform var(--dur, 0.2s) var(--ease-out, ease);
}
.qa-item:hover {
  border-color: var(--teal);
  background: rgb(var(--ch-teal) / 0.07);
  transform: translateY(-2px);
}
.qa-ico {
  display: block;
  width: clamp(30px, 3vw, 38px);
  height: clamp(30px, 3vw, 38px);
  color: var(--teal);
}
.qa-ico svg { width: 100%; height: 100%; display: block; }
/* The old card used a gold left stripe and a trailing arrow; neither belongs in
   the icon-tile treatment. Cleared at matching-or-higher weight. */
.qa-strip .qa-item::before,
.qa-strip .qa-item::after { content: none; }

@media (max-width: 860px) {
  .qa-strip-inner { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 460px) {
  .qa-strip-inner { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  .qa-item { padding: 16px 8px; font-size: 0.86rem; }
}

/* ---- FULL-BLEED BRAND BANNER -------------------------------------------- */
.brand-banner {
  margin: 0;
  padding: 0;
  display: block;
  line-height: 0;
  background: var(--teal);
}
.brand-banner img {
  width: 100%;
  height: clamp(220px, 26vw, 420px);
  object-fit: cover;
  object-position: center;
  display: block;
  border-radius: 0;
  box-shadow: none;
  margin: 0;
}

/* ---- INTRO COPY: centred, wider measure --------------------------------- */
/* It read like a Word paragraph: left-aligned at an 80ch measure inside a
   1180px band, so lines were short and the block was tall. Centred, and the
   measure opened to 96ch so lines run longer and the block is shorter.
   .prose > section.panel:nth-of-type(1) > p is (0-2-2) and beats .prose p
   (0-1-1) on weight. */
.prose > section.panel:nth-of-type(1) > p {
  max-width: 96ch;
  margin-inline: auto;
  text-align: center;
  text-wrap: pretty;
}
@media (max-width: 720px) {
  .prose > section.panel:nth-of-type(1) > p { text-align: left; max-width: none; }
}

/* ---- HERO CONTRAST CORRECTION ------------------------------------------
   Measured on the first build of the teal hero, sampling the real backdrop
   under each text box with the copy hidden:
       eyebrow    3.53 (needs 4.5)   FAIL
       h1         3.94 (needs 3.0)   pass
       lede       3.09 (needs 4.5)   FAIL
       lede link  3.28 (needs 4.5)   FAIL
   Two independent causes, both fixed here.

   1. The ramp fell off too early. The hero copy column is 44rem wide, so text
      can reach ~58% of the viewport, but the gradient was already down to 0.60
      alpha at 48% and 0.40 at 62%. Over the bright reception-desk area of the
      photo that composites to rgb(120,141,146) - far too light. The ramp now
      holds >=0.86 until 58% and only then falls away. It is still an eight-stop
      gradual fade, not a hard-edged box: the right 40% of the photograph is
      barely tinted.

   2. Champagne (#D3B58F, relative luminance 0.489) cannot carry SMALL text on
      a mid-teal backdrop at any alpha this scrim can reasonably reach - it
      would need the backdrop below 0.07 luminance, which means an almost opaque
      panel and loses the photograph. Champagne stays where it has the room -
      the h1 underline rule - while the eyebrow and the lede link move to warm
      white, with the link keeping a champagne underline so the accent still
      reads. Buttons are unaffected: they sit on their own solid fills.
   ------------------------------------------------------------------------ */

.hero-media::after {
  background:
    linear-gradient(100deg,
      rgb(var(--ch-teal) / 0.95)  0%,
      rgb(var(--ch-teal) / 0.94) 30%,
      rgb(var(--ch-teal) / 0.90) 46%,
      rgb(var(--ch-teal) / 0.86) 58%,
      rgb(var(--ch-teal) / 0.68) 68%,
      rgb(var(--ch-teal) / 0.44) 78%,
      rgb(var(--ch-teal) / 0.22) 88%,
      rgb(var(--ch-teal) / 0.06) 100%),
    linear-gradient(180deg,
      rgb(var(--ch-teal) / 0.30) 0%,
      rgb(var(--ch-teal) / 0.00) 34%);
}

/* Small text on the hero goes to warm white. */
.hero .hero-copy .eyebrow { color: var(--warm-white); }
.hero .hero-copy .hero-lede { color: var(--warm-white); }
.hero .hero-copy .hero-lede a {
  color: var(--warm-white);
  text-decoration: underline;
  text-decoration-color: var(--champagne);
  text-decoration-thickness: 2px;
  text-underline-offset: 4px;
}
.hero .hero-copy .hero-lede a:hover { text-decoration-color: var(--warm-white); }

/* ---- footer field border, re-tuned for the teal ground ------------------
   The session-5 accessibility pass set this to white @ 0.40, which measured
   3.69:1 against the OLD near-black footer (38,36,47). The retheme moved the
   footer to the main teal (41,77,85), whose own luminance is higher, and the
   same border dropped to 2.89:1 - just under the 3:1 that WCAG 1.4.11 requires
   to identify a control boundary. Raised to 0.55, which measures 4.27:1 on the
   teal. A reminder that a contrast fix is only valid against the background it
   was measured on: re-measure whenever the ground changes.
   ---------------------------------------------------------------------- */
.site-footer .footer-form input:not(:focus-visible):not(:focus),
.site-footer .footer-form select:not(:focus-visible):not(:focus),
.site-footer .footer-form textarea:not(:focus-visible):not(:focus) {
  border-color: rgb(var(--ch-paper) / 0.55);
}

/* ---- visit-band action links: real tap targets --------------------------
   The Phone and Email entries in the visit band are standalone tel:/mailto:
   actions in a list, and both measured 26px tall. WCAG 2.5.8 wants 44px for a
   target like this. (The other ~28 sub-32px links the metrics flag are INLINE
   links inside prose - "eye care services", "Read More" - which the success
   criterion explicitly exempts, so they are deliberately left alone.)
   .visit-band .visit-list a is (0-2-1) and beats direction.css:186
   .visit-list a (0-1-1) on weight. Only two of the three rows contain an
   anchor - Fax is a plain <span> - so this adds about 36px, not 54px.
   min-height rather than padding: the li carries a border-bottom, which padding
   would push away from the text.
   ---------------------------------------------------------------------- */
.visit-band .visit-list a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}
.visit-band .visit-list li { align-items: center; }

/* ---- doctor bio: close the dead quadrant --------------------------------
   Measured at 1440: .bio-body ends at y3055 but .bio runs to y3265, because the
   row height is driven by the portrait, not the copy. site.css:458 gives the
   photo aspect-ratio 3/4, so a 240px lane makes it 320px tall while the bio
   text only fills 149px - leaving roughly 210px x 897px of empty band to the
   right of the photo before the reviews heading.

   Squaring the portrait takes it 320px -> 240px and removes ~100px of that.
   object-position is biased upward so the crop keeps the face rather than
   centring on the shoulders.
   .prose .bio-photo img is (0-2-1), beating both site.css:458 and
   direction.css:484 .bio-photo img (each 0-1-1), so it wins on weight.

   NOT fixing the residual ~110px by narrowing the photo lane: that needs
   .prose .bio { grid-template-columns: ... } at (0-2-0), which would outrank
   BOTH direction.css:502 and site.css:465 - two (0-1-0) rules inside media
   queries that stack the bio on small screens - and the bio would stop
   stacking on mobile. Not worth the regression for 110px.
   ---------------------------------------------------------------------- */
.prose .bio-photo img {
  aspect-ratio: 1 / 1;
  object-fit: cover;
  object-position: center 22%;
}

/* ===========================================================================
   SESSION 6 - SECTION ARCHITECTURE
   The "Our Designer Optical Shop" panel was carrying eight unrelated topics and
   37% of the page height under one h2, and the doctor panel carried the bio and
   the reviews together. Both are now split into discrete <section>s so each can
   own its background, and the page reads as an alternating rhythm:

     hero IMAGE -> ivory -> banner IMAGE -> warm white -> beige (form)
     -> doctor IMAGE -> ivory (reviews) -> warm white (optical)
     -> exams IMAGE -> ivory (sharp) -> warm white (featuring)
     -> white (emergency) -> ivory (blog) -> warm white (contact)
     -> teal (visit) -> champagne (CTA) -> teal (footer)

   Content was MOVED, not rewritten: no copy edited, no heading level changed,
   every link and alt attribute carried across verbatim.
   ======================================================================== */

/* The old nth-of-type colour sequence assumed four panels. There are now
   eleven, so colour is assigned by CLASS instead. These are (0-3-1) against
   the old (0-2-1) rules, so they win on weight rather than source order. */
.prose > section.panel.sec-reviews,
.prose > section.panel.sec-sharp,
.prose > section.panel.sec-blog      { background-color: var(--ivory); }

.prose > section.panel.sec-optical,
.prose > section.panel.sec-featuring,
.prose > section.panel.sec-contact   { background-color: var(--warm-white); }

.prose > section.panel.sec-emergency { background-color: #fff; }

.prose > section.panel.sec-doctor,
.prose > section.panel.sec-exams     { background-color: var(--teal); }

/* ---- section headings: centred everywhere except hero + Meet the Doctor -- */
.prose > section.panel > h2,
.prose > section.panel > h3,
.prose > section.panel > h4,
.prose > section.panel > .bento-head,
.prose > section.panel > .sec-title {
  text-align: center;
}
/* the gold/champagne rule under a centred heading has to centre with it */
.prose > section.panel > h2::after,
.prose > section.panel > .bento-head::after { margin-inline: auto; }
/* explicit opt-out, per the brief */
.prose > section.panel.sec-doctor h2,
.prose > section.panel.sec-doctor h3,
.prose > section.panel.sec-doctor p,
.prose > section.panel.sec-emergency h3,
.prose > section.panel.sec-emergency h4,
.prose > section.panel.sec-emergency p { text-align: left; }

/* Sub-heads inside cards stay centred with their section, but body copy in a
   card stays left - centred paragraphs inside a small card are hard to read. */
.sec-sharp .bento-body h4, .sec-sharp .bento-body h4 a { text-align: center; display: block; }

/* ---- 1. OPTICAL SHOP: full desktop width ------------------------------- */
/* The brief asks this one to cover the whole desktop area rather than sit in
   the 1180px measure, so the band max widens and the tiles spread. */
.prose > section.panel.sec-optical {
  padding-inline: max(var(--band-gutter), calc((100% - 1560px) / 2));
}
.sec-optical .figgrid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(14px, 1.6vw, 26px);
}
.sec-optical .figgrid figure { margin: 0; }
.sec-optical .figgrid img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }
.sec-optical .figgrid figcaption { text-align: center; }
@media (max-width: 860px) { .sec-optical .figgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* ---- 2. EYE EXAMS: copy over a background photograph, set right --------- */
.prose > section.panel.sec-exams {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  min-height: clamp(380px, 40vw, 560px);
  display: grid;
  align-content: center;
}
.sec-exams-media {
  position: absolute; inset: 0; z-index: -2;
  background-image: url('../assets/eye-exams-family.jpg');
  background-size: cover;
  background-position: 30% center;
}
/* The photograph is bright on its right side, which is exactly where the copy
   sits, so a teal wash runs right-to-left to carry the text. Measured below. */
.sec-exams-media::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(270deg,
    rgb(var(--ch-teal) / 0.94)  0%,
    rgb(var(--ch-teal) / 0.90) 26%,
    rgb(var(--ch-teal) / 0.78) 42%,
    rgb(var(--ch-teal) / 0.52) 58%,
    rgb(var(--ch-teal) / 0.24) 74%,
    rgb(var(--ch-teal) / 0.06) 100%);
}
.sec-exams-copy { position: relative; z-index: 1; display: flex; justify-content: flex-end; }
.sec-exams .split {
  display: block;
  max-width: 46rem;
  margin: 0;
  text-align: left;
}
.sec-exams .split-a, .sec-exams .split-b { margin: 0; }
.sec-exams h3 {
  color: var(--warm-white);
  text-align: left;
  font-size: clamp(1.6rem, 2.6vw, 2.3rem);
  margin-top: 0;
}
.sec-exams p { color: rgb(var(--ch-warmwhite) / 0.94); text-align: left; max-width: none; }
.sec-exams .split-cta a { color: var(--champagne); }
@media (max-width: 860px) {
  .sec-exams-copy { justify-content: flex-start; }
  .sec-exams-media { background-position: 60% center; }
  .sec-exams-media::after {
    background: linear-gradient(180deg, rgb(var(--ch-teal) / 0.80) 0%, rgb(var(--ch-teal) / 0.93) 60%);
  }
}

/* ---- 3. MEET THE DOCTOR: copy left over the teal portrait --------------- */
/* No scrim: the artwork is already a flat teal field on its left two-thirds,
   so off-white type sits on it cleanly. Verified by measurement, not by eye. */
.prose > section.panel.sec-doctor {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  min-height: clamp(360px, 36vw, 520px);
  display: grid;
  align-content: center;
}
.sec-doctor-media {
  position: absolute; inset: 0; z-index: -1;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: center right;
  margin: 0; border-radius: 0; box-shadow: none;
}
.sec-doctor-copy { position: relative; z-index: 1; max-width: 42rem; }
.sec-doctor h2 {
  color: var(--warm-white);
  text-align: left;
  margin-top: 0;
}
.sec-doctor h2::after { margin-inline: 0; background: var(--champagne); }
.sec-doctor .bio-body h3, .sec-doctor .bio-body h3 a { color: var(--champagne); text-align: left; }
.sec-doctor .bio-body p { color: rgb(var(--ch-warmwhite) / 0.94); text-align: left; }
.sec-doctor .bio-body a { color: var(--champagne); }
@media (max-width: 860px) {
  .sec-doctor-media { object-position: 72% center; }
  .sec-doctor::before {
    content: ""; position: absolute; inset: 0; z-index: 0;
    background: linear-gradient(180deg, rgb(var(--ch-teal) / 0.72) 0%, rgb(var(--ch-teal) / 0.92) 70%);
  }
}

/* ---- 4. REVIEWS: teal cards, white type, dots instead of a scrollbar ---- */
.sec-reviews .review {
  background-color: var(--teal);
  background-image: none;
  -webkit-backdrop-filter: none; backdrop-filter: none;
  border-color: rgb(var(--ch-teal) / 0.5);
}
/* The four decorative tints read as "card 1 is highlighted" rather than as a
   rhythm; on a single teal fill they are noise. Cleared at matching weight. */
.sec-reviews .reviews .review:nth-child(4n+1),
.sec-reviews .reviews .review:nth-child(4n+2),
.sec-reviews .reviews .review:nth-child(4n+3),
.sec-reviews .reviews .review:nth-child(4n+4) { background-image: none; }
.sec-reviews .review blockquote { color: var(--warm-white); }
.sec-reviews .review blockquote::before { color: var(--champagne); }
.sec-reviews .review cite { color: #fff; }
.sec-reviews .review footer { border-top-color: rgb(var(--ch-paper) / 0.28); }
.sec-reviews .review footer span { color: rgb(var(--ch-paper) / 0.82); }

/* Hide the native rail scrollbar; the dots below replace it. */
.sec-reviews .reviews { scrollbar-width: none; padding-bottom: 0; }
.sec-reviews .reviews::-webkit-scrollbar { height: 0; width: 0; }

.reviews-dots {
  display: flex;
  justify-content: center;
  gap: 10px;
  margin-top: clamp(18px, 2vw, 26px);
}
.reviews-dots button {
  appearance: none;
  width: 10px; height: 10px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid rgb(var(--ch-teal) / 0.45);
  background: transparent;
  cursor: pointer;
  transition: background-color 0.18s ease, transform 0.18s ease;
}
.reviews-dots button[aria-current="true"] {
  background: var(--teal);
  transform: scale(1.25);
}
/* 10px is far below a comfortable target, so the hit area is padded out to 44px
   with a transparent ::before rather than by growing the visible dot. */
.reviews-dots button { position: relative; }
.reviews-dots button::before {
  content: ""; position: absolute;
  top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: 44px; height: 44px;
}

/* ---- 5. SHARP VISION + focus cards ------------------------------------- */
.sec-sharp .bento-focus {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(16px, 2vw, 28px);
}
.sec-sharp .bento-item { margin: 0; }
.sec-sharp .bento-media img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }
@media (max-width: 860px) { .sec-sharp .bento-focus { grid-template-columns: 1fr; } }

/* ---- 6. NOW FEATURING --------------------------------------------------- */
.sec-featuring .bento-feature { display: block; }
.sec-featuring .bento-item { margin: 0; }
.sec-featuring .bento-media img {
  width: 100%; height: auto; display: block;
  border-radius: var(--r-md);
}

/* ---- 7. EYE EMERGENCIES: white, subtle neutral wash, copy left ---------- */
.prose > section.panel.sec-emergency {
  background-image:
    radial-gradient(120% 90% at 12% 0%, rgb(var(--ch-teal) / 0.05) 0%, rgb(var(--ch-teal) / 0) 60%),
    radial-gradient(90% 80% at 96% 100%, rgb(var(--ch-greige) / 0.16) 0%, rgb(var(--ch-greige) / 0) 62%);
}
.emerg-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
  gap: clamp(26px, 3.4vw, 56px);
  align-items: center;
}
.emerg-copy { min-width: 0; }
.emerg-copy p { max-width: none; }
.sec-emergency .emerg-head h3 { font-size: clamp(1.7rem, 2.8vw, 2.4rem); }
/* Art slot: fades left into the page so it reads as part of the band, not a
   pasted rectangle. Currently a neutral wash - see note in the handover. */
.emerg-art {
  min-height: clamp(220px, 24vw, 340px);
  border-radius: var(--r-md);
  background-color: rgb(var(--ch-greige) / 0.14);
  background-size: cover;
  background-position: center;
  -webkit-mask-image: linear-gradient(90deg, transparent 0%, #000 22%, #000 100%);
  mask-image: linear-gradient(90deg, transparent 0%, #000 22%, #000 100%);
}
@media (max-width: 860px) {
  .emerg-grid { grid-template-columns: 1fr; }
  .emerg-art { display: none; }
}

/* ---- 8. WHAT'S NEW: real blog cards ------------------------------------ */
.sec-blog .postlist {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(18px, 2.2vw, 30px);
}
.sec-blog .post {
  background: #fff;
  border: 1px solid rgb(var(--ch-teal) / 0.14);
  border-radius: var(--r-md);
  padding: clamp(22px, 2.4vw, 32px);
  display: flex;
  flex-direction: column;
  box-shadow: 0 2px 10px rgb(var(--ch-teal) / 0.06);
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.sec-blog .post:hover { transform: translateY(-3px); box-shadow: 0 12px 28px rgb(var(--ch-teal) / 0.12); }
.sec-blog .post-date {
  font-size: 0.78rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--teal);
  font-weight: 700;
  margin: 0 0 10px;
}
.sec-blog .post h5 { margin: 0 0 10px; font-size: clamp(1.05rem, 1.35vw, 1.25rem); }
.sec-blog .post h5 a { color: var(--teal); text-decoration: none; }
.sec-blog .post h5 a:hover { text-decoration: underline; text-underline-offset: 3px; }
.sec-blog .post p { margin: 0 0 18px; }
.sec-blog .post .btn, .sec-blog .post a.more { margin-top: auto; align-self: flex-start; }
@media (max-width: 760px) { .sec-blog .postlist { grid-template-columns: 1fr; } }

/* ---- 9. CONTACT + LOCATE: its own section, edges aligned ---------------- */
.sec-contact .contact-locate {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
  gap: clamp(20px, 2.4vw, 36px);
  align-items: stretch;
}
.sec-contact .cl-card, .sec-contact .cl-map { min-width: 0; }
.sec-contact .cl-map iframe {
  width: 100%;
  height: 100%;
  min-height: clamp(260px, 26vw, 380px);
  border: 0;
  border-radius: var(--r-md);
  display: block;
}
/* The hours table sat loose under the two cards and did not line up with
   either edge. It now shares the same grid, so its rules end where the cards
   end - which is what the annotation was pointing at. */
.sec-contact .daylist {
  margin-top: clamp(24px, 2.6vw, 38px);
  columns: 2;
  column-gap: clamp(24px, 3vw, 48px);
}
.sec-contact .daylist li { break-inside: avoid; }
.sec-contact > h4 { margin-top: clamp(26px, 3vw, 40px); }
@media (max-width: 860px) {
  .sec-contact .contact-locate { grid-template-columns: 1fr; }
  .sec-contact .daylist { columns: 1; }
}

/* ---- 10. REQUEST APPOINTMENT: beige, narrower measure ------------------ */
/* The form ran the full 1180px band, so label/field pairs were stranded far
   apart. Beige ground, and the form itself constrained and centred. */
.prose > section.panel:nth-of-type(2) { background-color: rgb(var(--ch-oak) / 0.20); }
.prose > section.panel:nth-of-type(2) > h2 { text-align: center; }
.appt-form, .prose > section.panel:nth-of-type(2) > .form-note {
  max-width: 860px;
  margin-inline: auto;
}
.prose > section.panel:nth-of-type(2) > .form-note { text-align: center; }

/* ---- centring section titles that are flex containers -------------------
   site.css:516 sets `.prose h4 { display:flex; align-items:center }` and gives
   it a 4px accent bar via ::before. On a flex container `text-align: center`
   does nothing - the flex LINE has to be centred with justify-content - and a
   left-hand bar on a centred title reads as a misalignment. Both handled here
   for section-level h4s only; card labels inside .cl-card / .post keep the bar
   and stay left, which is what distinguishes a section title from a sub-label.
   -------------------------------------------------------------------- */
.prose > section.panel > h4 { justify-content: center; }
.prose > section.panel > h4::before { content: none; }

/* h2/h3 are not flex, so text-align is enough - but their rule/underline has
   to centre with them. */
.prose > section.panel > h2,
.prose > section.panel > h3 { text-align: center; }

/* Explicit opt-outs, per the brief: hero and Meet the Doctor stay left, and
   the emergency band keeps its left-justified format. */
.prose > section.panel.sec-doctor > h2 { text-align: left; }
.prose > section.panel.sec-emergency h3,
.prose > section.panel.sec-emergency h4 { justify-content: flex-start; text-align: left; }
.prose > section.panel.sec-emergency h4::before { content: ""; }

/* ---- doctor bio: the copy is a BARE TEXT NODE ---------------------------
   .bio-body holds an <h3> followed by a loose text node - there is no <p> to
   target, which is why `.sec-doctor .bio-body p` matched nothing and the bio
   rendered in body ink on the teal portrait. Colour goes on the container so
   the text node inherits it. (Same source quirk as the street address, which
   is also a bare text node in this markup.)
   -------------------------------------------------------------------- */
.sec-doctor .bio-body { color: rgb(var(--ch-warmwhite) / 0.94); }
.sec-doctor .bio-body a { color: var(--champagne); }
.sec-doctor .bio-body h3 a { color: var(--champagne); }

/* ---- one section-title size across the whole page ----------------------
   Titles were running at three different sizes: h2 43.2px, .bento-head
   30.4px, and the "What's New?" h4 at 16.32px - the same visual rank as body
   copy, which is why that section did not read as a section at all.
   All section-level titles now share one scale. This is the rule to carry to
   the other 286 pages.
   -------------------------------------------------------------------- */
.prose > section.panel > h2,
.prose > section.panel > h3,
.prose > section.panel > h4 {
  font-size: clamp(1.9rem, 3vw, 2.7rem);
  line-height: 1.14;
  letter-spacing: -0.02em;
  margin-bottom: clamp(20px, 2.4vw, 34px);
}
/* The emergency headline sits inside .emerg-head, so it needs the size too. */
.sec-emergency .emerg-head h3 {
  font-size: clamp(1.9rem, 3vw, 2.7rem);
  line-height: 1.14;
  letter-spacing: -0.02em;
}
/* "What's New?" is a link inside its h4; inherit the new size rather than the
   h4 default, and drop the underline that made it read as body copy. */
.sec-blog > h4 a { font: inherit; color: var(--teal); text-decoration: none; }
.sec-blog > h4 a:hover { text-decoration: underline; text-underline-offset: 4px; }

/* ---- optical shop tiles: full-width band, but no upscaling --------------
   Widening this section to 1560px pushed the four brand tiles to 331px each,
   and their sources are only 250px wide (1.32x, visibly soft). I probed the
   source CDN for larger originals the way I did for the intro photo:
     sites/2391/2018/04/prada.jpg           403
     images/product_images/ray-ban.jpg      302
     images/product_images/coach_2.jpg      302
   Only the 250px variants are served, so there is nothing sharper to fetch.
   The band still spans the full desktop width; the tiles are capped at 300px
   (1.20x) and distributed across it instead of being stretched to fill.
   -------------------------------------------------------------------- */
.sec-optical .figgrid {
  grid-template-columns: repeat(4, minmax(0, 300px));
  justify-content: space-between;
}
@media (max-width: 860px) {
  .sec-optical .figgrid { grid-template-columns: repeat(2, minmax(0, 300px)); justify-content: space-around; }
}

/* ---- emergency band: no placeholder holes ------------------------------
   The right-hand art slot is specified as a generated eye-procedure image
   (no faces, fading left). fal is unavailable in this environment, and an
   empty tinted rectangle reads as a BROKEN IMAGE, which is worse than not
   having the slot. So the band is laid out to look finished without it:
   copy runs at a contained measure against the subtle neutral wash, and the
   emergency phone number is promoted, which is what the section is actually
   for.

   TO ENABLE THE ART once the image exists, set its URL on the element and the
   two-column layout restores itself - no other change needed:
       <div class="emerg-art" style="--art:url('assets/eye-procedure.jpg')">
   -------------------------------------------------------------------- */
.emerg-grid { grid-template-columns: minmax(0, 1fr); }
.emerg-art { display: none; }

.emerg-grid:has(.emerg-art[style*="--art"]) {
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
}
.emerg-art[style*="--art"] {
  display: block;
  background-image: var(--art);
}

/* Copy holds a readable measure instead of running the full band. */
.sec-emergency .emerg-copy { max-width: 62rem; }
.sec-emergency .emerg-copy p { max-width: none; }

/* The phone number is the point of an emergency band - give it weight. */
.sec-emergency .emerg-copy a[href^="tel:"] {
  font-weight: 700;
  color: var(--teal);
  text-decoration-color: var(--champagne);
  text-decoration-thickness: 2px;
  text-underline-offset: 4px;
}

/* ---- Now Featuring: let the new artwork keep its own proportions --------
   direction.css:375 pins `.prose > section.panel .bento-banner .bento-media img`
   to `aspect-ratio: 1280 / 480` - the dimensions of the OLD Optos banner. The
   replacement artwork is 2171x724 (ratio 3.00, not 2.67), so at 1180px wide it
   was being forced to 1180 x 480/1280 = 442.5px against a natural 393px: a
   12.6% vertical stretch that fattened the device.
   That rule is (0-4-1); this is (0-5-1), so it wins on weight rather than order.
   aspect-ratio:auto means any future replacement keeps ITS proportions too,
   instead of inheriting whatever the previous image happened to be.
   -------------------------------------------------------------------- */
.prose > section.panel.sec-featuring .bento-banner .bento-media img {
  aspect-ratio: auto;
  height: auto;
  object-fit: fill;
}

/* ===========================================================================
   SESSION 7 — alignment and polish pass
   ======================================================================== */

/* ---- 1. HERO: larger headline, buttons aligned to the copy column -------
   The h1 was clamped to 2.7rem and the CTA row sat loose under it. The
   headline grows, and the button row is pinned to the same left edge and
   given a consistent gap so it reads as part of the copy block. */
.hero-copy h1 {
  font-size: clamp(2.4rem, 4.4vw, 4rem);
  line-height: 1.06;
  letter-spacing: -0.025em;
  max-width: 18ch;
}
.hero-copy .hero-lede { font-size: clamp(1.02rem, 1.25vw, 1.2rem); max-width: 44ch; }
.hero-copy .btn-row {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: clamp(12px, 1.2vw, 18px);
  margin-top: clamp(22px, 2.4vw, 34px);
}
.hero-copy .btn-row .btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 56px;
  padding-inline: clamp(24px, 2.4vw, 34px);
  margin: 0;
}

/* ---- 2. APPOINTMENT FORM: re-flow without touching the markup ----------
   Requested order is Reason full-width, then Name/Last, Phone/Email, then the
   two radio groups side by side. CORRECTION 2026-09-23: this comment used to
   claim the tab order still followed the visual order. It did not — `order`
   moves the boxes but not the tab sequence (WCAG 2.4.3), and it did nothing on
   phones. The "New Or Returning" fieldset now sits in the DOM where it is shown
   (working/index.html), so DOM, visual and tab order agree; these rules only
   size the columns.
   div.field:nth-of-type() counts only the DIVs, so the two <fieldset>s and the
   sr-only <span> do not shift the numbering:
     1 Reason · 2 First · 3 Last · 4 Phone · 5 Email · 6 Comments · 7 actions
   -------------------------------------------------------------------- */
.appt-form > div.field:nth-of-type(1) { grid-column: 1 / -1; order: 1; }  /* Reason  */
.appt-form > div.field:nth-of-type(2) { order: 2; }                       /* First   */
.appt-form > div.field:nth-of-type(3) { order: 3; }                       /* Last    */
.appt-form > div.field:nth-of-type(4) { order: 4; }                       /* Phone   */
.appt-form > div.field:nth-of-type(5) { order: 5; }                       /* Email   */
.appt-form > fieldset.field:not(.full) { order: 6; grid-column: auto; }   /* New or returning */
.appt-form > fieldset.field.full { order: 7; grid-column: auto; }         /* Best way to reach */
.appt-form > div.field:nth-of-type(6) { order: 8; grid-column: 1 / -1; }  /* Comments */
.appt-form > div.field.appt-actions { order: 9; grid-column: 1 / -1; }

/* Radio groups now sit in a column beside a text field, so they need the same
   vertical box as an input or the row looks ragged. */
.appt-form fieldset.field { margin: 0; padding: 0; border: 0; min-width: 0; }
.appt-form fieldset.field legend { padding: 0; }
.appt-form fieldset.field .opts {
  display: flex;
  align-items: center;
  gap: clamp(18px, 2vw, 32px);
  min-height: 52px;
}
@media (max-width: 640px) {
  .panel .appt-form > * { order: unset !important; grid-column: 1 / -1 !important; }
}

/* ---- 3. REVIEWS: momentum, snap and drag ------------------------------ */
.sec-reviews .reviews {
  scroll-behavior: smooth;
  scroll-snap-type: x mandatory;
  cursor: grab;
}
.sec-reviews .reviews.is-dragging {
  cursor: grabbing;
  scroll-behavior: auto;      /* smooth fights a live drag */
  scroll-snap-type: none;     /* let the finger lead; snap re-applies on release */
}
.sec-reviews .reviews.is-dragging .review { pointer-events: none; }
.sec-reviews .review {
  transition: transform 0.35s cubic-bezier(0.22, 0.61, 0.36, 1),
              box-shadow 0.35s cubic-bezier(0.22, 0.61, 0.36, 1);
  will-change: transform;
}
@media (prefers-reduced-motion: reduce) {
  .sec-reviews .reviews { scroll-behavior: auto; }
  .sec-reviews .review { transition: none; }
}

/* ---- 4. OPTICAL SHOP: close the gaps ---------------------------------- */
/* Capping the tiles at 300px and using space-between left ~120px holes
   between them. The row is centred with a normal gap instead. */
.sec-optical .figgrid {
  grid-template-columns: repeat(4, minmax(0, 300px));
  justify-content: center;
  gap: clamp(12px, 1.2vw, 20px);
}
@media (max-width: 860px) {
  .sec-optical .figgrid { grid-template-columns: repeat(2, minmax(0, 300px)); justify-content: center; }
}

/* ---- 5. NOW FEATURING: edge to edge ----------------------------------- */
/* Full-bleed like the hero and doctor bands. A fixed band height with
   object-fit: cover crops the flat blue top and bottom of the artwork, which
   is a continuous gradient in the file - there is no hard edge to trim, so it
   has to be cropped by the frame. */
.prose > section.panel.sec-featuring { padding-bottom: 0; }
.sec-featuring .bento-feature,
.sec-featuring .bento-item,
.sec-featuring .bento-media { margin: 0; border-radius: 0; box-shadow: none; }
.prose > section.panel.sec-featuring .bento-media img {
  width: 100vw;
  max-width: 100vw;
  margin-left: calc(50% - 50vw);
  height: clamp(300px, 34vw, 520px);
  object-fit: cover;
  object-position: center center;
  border-radius: 0;
  display: block;
}

/* ---- 6. EYE EMERGENCIES: photograph behind the copy ------------------- */
.prose > section.panel.sec-emergency {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background-color: #fff;
  background-image: none;
  min-height: clamp(360px, 34vw, 520px);
  display: grid;
  align-content: center;
}
.sec-emergency::before {
  content: "";
  position: absolute; inset: 0; z-index: -2;
  background-image: url('../assets/eye-emergency-exam.jpg');
  background-size: cover;
  background-position: 68% center;
}
/* The photograph is near-white on its left half, so the copy needs a wash to
   sit on rather than raw white-on-white. Kept very light so the image reads. */
.sec-emergency::after {
  content: "";
  position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(90deg,
    rgb(255 255 255 / 0.97)  0%,
    rgb(255 255 255 / 0.95) 34%,
    rgb(255 255 255 / 0.82) 52%,
    rgb(255 255 255 / 0.42) 70%,
    rgb(255 255 255 / 0.10) 88%,
    rgb(255 255 255 / 0.00) 100%);
}
.sec-emergency .emerg-grid { grid-template-columns: minmax(0, 1fr); }
.sec-emergency .emerg-copy { max-width: 40rem; position: relative; z-index: 1; }
.sec-emergency .emerg-art { display: none; }
@media (max-width: 860px) {
  .sec-emergency::after {
    background: linear-gradient(180deg, rgb(255 255 255 / 0.96) 0%, rgb(255 255 255 / 0.90) 70%);
  }
  .sec-emergency::before { background-position: 78% center; }
}

/* ---- 7. CONTACT + LOCATE: aligned, larger labels, lifted -------------- */
.sec-contact .contact-locate { align-items: stretch; }
.sec-contact .cl-card,
.sec-contact .cl-map {
  background: #fff;
  border-radius: var(--r-md);
  padding: clamp(22px, 2.4vw, 32px);
  box-shadow: 0 10px 30px rgb(var(--ch-teal) / 0.10), 0 2px 6px rgb(var(--ch-teal) / 0.06);
  display: flex;
  flex-direction: column;
}
/* Both labels start on the same baseline and read as section sub-heads. */
.sec-contact .cl-card > h4,
.sec-contact .cl-map > h4 {
  margin: 0 0 clamp(14px, 1.6vw, 20px);
  font-size: clamp(1rem, 1.15vw, 1.15rem);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--teal);
  justify-content: flex-start;
  text-align: left;
  min-height: 1.6em;
}
.sec-contact .cl-map iframe {
  flex: 1 1 auto;
  min-height: clamp(280px, 26vw, 400px);
  border-radius: var(--r-sm);
  box-shadow: 0 1px 4px rgb(var(--ch-teal) / 0.10);
}

/* ---- 8. FOOTER: tighter, ruled, rounded ------------------------------- */
.site-footer .footer-grid {
  gap: clamp(20px, 2.2vw, 34px);
  padding-block: 0;
}
.site-footer { padding-block: clamp(40px, 4vw, 64px) clamp(26px, 2.6vw, 40px); }
.site-footer .footer-grid h3 {
  margin: 0 0 12px;
  padding-bottom: 10px;
  border-bottom: 1px solid rgb(var(--ch-paper) / 0.16);
}
.site-footer .footer-grid ul { display: grid; gap: 7px; }
.site-footer .footer-grid li { margin: 0; }
.site-footer .footer-grid a { padding-block: 2px; }
.site-footer .footer-grid p { margin: 0 0 8px; line-height: 1.5; }
.site-footer .footer-form { margin-top: clamp(22px, 2.4vw, 32px); padding-top: clamp(20px, 2.2vw, 28px); border-top: 1px solid rgb(var(--ch-paper) / 0.16); }
.site-footer > .shell > h3,
.site-footer .footer-form + * { margin-top: 0; }
/* Buttons match the CTA pill. */
.site-footer .btn,
.site-footer button,
.site-footer .footer-form button {
  border-radius: var(--r-pill);
}

/* ---- close the visit-band -> footer gap --------------------------------
   Both bands are the same teal now, so the padding between them reads as one
   large empty block rather than as two sections. Measured ~130px of dead teal
   between the last visit-band element and the first footer column. Trimmed
   from both sides, and a hairline carries the division instead of whitespace.
   -------------------------------------------------------------------- */
.visit-band { padding-bottom: clamp(26px, 2.8vw, 40px); }
.site-footer { padding-top: clamp(26px, 2.8vw, 40px); }
.site-footer .footer-grid { border-top: 1px solid rgb(var(--ch-paper) / 0.14); padding-top: clamp(26px, 2.8vw, 38px); }

/* The visit band's three columns end at different heights; aligning their
   tops and letting the shortest stop early is normal for an info band, but the
   band itself no longer needs to reserve height beyond its tallest column. */
.visit-inner { align-items: start; }

/* Footer contact/hours lists were spaced for a taller band. */
.site-footer .visit-list { gap: 7px; }
.site-footer .visit-list li { padding-bottom: 7px; }

/* ---- hero copy: sit further left than the centred band -----------------
   The hero copy inherited the shared band inset, (100% - 1180px) / 2, which at
   a 1901px browser puts it 360px in. The requested position is ~222px.

   A fixed shift would not survive narrower screens - at 1440 the whole inset is
   only 130px, so subtracting 138px would slam the copy into the 24px gutter.
   The inset is scaled instead: 0.62 of the band inset, floored at the gutter.

     W      band inset -> hero inset
     1280      50          31
     1440     130          81
     1901     361         224   <- matches the marked position
     1920     370         229

   Hero MEDIA is untouched; only the copy column moves.
   -------------------------------------------------------------------- */
.hero .hero-inner {
  padding-inline: max(var(--band-gutter), calc((100% - var(--band-max)) / 2 * 0.62));
}

/* ---- Now Featuring: the real reason it was not edge to edge ------------
   The <img> was already width:100vw with a negative margin - its BOX measured
   the full viewport. But direction.css:324 gives .bento-media `overflow:hidden`
   and .bento-item clips too, so at a 1860px viewport the box ran 0-1860 while
   only 340-1520 was ever PAINTED: exactly the 1180px band.
   getBoundingClientRect returns the box, not the painted area, which is why my
   earlier check reported "1440px, full bleed" and was wrong.
   The hero, doctor and exams bands are full-bleed because the SECTION spans the
   viewport; here it was the image inside a clipping container. Unclip it.
   -------------------------------------------------------------------- */
.sec-featuring .bento-item,
.sec-featuring .bento-media {
  overflow: visible;
}

/* ---- Reviews rail: line the edges up with the tiles below --------------
   Measured at 1860: the optical tile row runs 300 -> 1560 (four 300px tiles +
   three 20px gaps = 1260px, centred in the 1560px band), while the rail ran
   340 -> 1520 because it inherited the 1180px band. Different bands, so the
   edges could never agree.
   The rail now uses the same 1560px band and is capped at exactly four tiles
   plus three gaps, so its edges match the row beneath it AND four whole cards
   fit - which is what stops the fourth one being sliced.
   -------------------------------------------------------------------- */
.prose > section.panel.sec-reviews {
  padding-inline: max(var(--band-gutter), calc((100% - 1560px) / 2));
}
.sec-reviews .reviews {
  --rev-gap: clamp(12px, 1.2vw, 20px);
  grid-auto-columns: 300px;
  gap: var(--rev-gap);
  max-width: calc(300px * 4 + var(--rev-gap) * 3);
  margin-inline: auto;
  scroll-padding-inline: 0;
}
.sec-reviews .reviews-dots { max-width: calc(300px * 4 + var(--rev-gap, 20px) * 3); margin-inline: auto; }

/* ===========================================================================
   INNER PAGES — the V1 contact aside
   The homepage replaced these three sidebar cards with .visit-band. The other
   286 pages still emit <aside class="aside"> with .card children, and the band
   primitive strips .page-grid's width/padding, so nothing re-applied a measure:
   they rendered as full-bleed grey slabs with text hard against the viewport
   edge. They get the same deep-teal band treatment as the homepage instead.
   ======================================================================== */
.page-grid > .aside {
  background-color: var(--teal);
  color: rgb(var(--ch-warmwhite) / 0.88);
  padding-block: var(--band-pad);
  padding-inline: max(var(--band-gutter), calc((100% - var(--band-max)) / 2));
  margin: 0;
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(22px, 3vw, 56px);
  align-items: start;
}
.page-grid > .aside > .card {
  background: none;
  background-image: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  -webkit-backdrop-filter: none; backdrop-filter: none;
  padding: 0;
  margin: 0;
  min-width: 0;
}
/* The location strapline is an h2 in the source and must stay an h2, but at the
   section-title scale it would dwarf the band. Sized as a band lead instead. */
.page-grid > .aside .card h2 {
  color: var(--warm-white);
  font-size: clamp(1.5rem, 2.2vw, 2.1rem);
  line-height: 1.16;
  letter-spacing: -0.02em;
  margin: 0;
  text-align: left;
}
.page-grid > .aside .card h3 {
  color: #fff;
  font-size: 0.82rem;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  margin: 0 0 16px;
  padding-bottom: 11px;
  border-bottom: 2px solid rgb(var(--ch-champagne) / 0.65);
  text-align: left;
  justify-content: flex-start;
}
.page-grid > .aside .card h3::before { content: none; }

.page-grid > .aside .fact-list {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: 9px; font-size: 0.95rem;
}
.page-grid > .aside .fact-list li {
  display: flex; justify-content: space-between; gap: 18px;
  padding-bottom: 9px;
  border-bottom: 1px solid rgb(var(--ch-paper) / 0.14);
  margin: 0;
}
.page-grid > .aside .fact-list li:last-child { border-bottom: 0; }
.page-grid > .aside .fact-list b { color: #fff; font-weight: 600; }
.page-grid > .aside .fact-list span { color: rgb(var(--ch-paper) / 0.78); text-align: right; }
/* Champagne on teal measures 4.71:1 — the only accent that clears AA here. */
.page-grid > .aside .fact-list a {
  color: var(--champagne);
  text-decoration: none;
  display: inline-flex; align-items: center; min-height: 44px;
}
.page-grid > .aside .fact-list a:hover { text-decoration: underline; text-underline-offset: 3px; }

@media (max-width: 960px) {
  .page-grid > .aside { grid-template-columns: 1fr 1fr; }
  .page-grid > .aside > .card:first-child { grid-column: 1 / -1; }
}
@media (max-width: 640px) {
  .page-grid > .aside { grid-template-columns: 1fr; gap: 32px; }
  .page-grid > .aside > .card:first-child { grid-column: auto; }
}

/* ---- Now Featuring as a full-bleed STRIP -------------------------------
   Previously the section kept its band padding and the image escaped it with
   width:100vw + margin-left:calc(50% - 50vw). That only worked once two
   `overflow:hidden` containers (direction.css:324) were unclipped — a fragile
   chain where any future overflow rule silently re-clips the art back to the
   1180px band, which is exactly the bug that was reported.

   Making the SECTION full-bleed, the way .hero / .sec-doctor / .sec-exams
   already work, removes the dependency: the image is plain width:100% of a
   full-width parent. No viewport units, no negative margin, nothing to unclip.
   Only the heading keeps the band inset so it stays aligned with every other
   section title.
   ---------------------------------------------------------------------- */
.prose > section.panel.sec-featuring {
  padding-inline: 0;
}
.prose > section.panel.sec-featuring > .bento-head {
  padding-inline: max(var(--band-gutter), calc((100% - var(--band-max)) / 2));
}
.prose > section.panel.sec-featuring .bento-banner .bento-media img {
  width: 100%;
  max-width: none;
  margin-left: 0;
  height: clamp(300px, 34vw, 520px);
  object-fit: cover;
  aspect-ratio: auto;
  border-radius: 0;
  display: block;
}

/* ---- visit band: the address is part of the heading (SEO freeze) ---------
   The source's location heading is the full line "Located in the same
   building as Wayback Burgers 8049 Preston Road Suite 200, Frisco, TX, 75034".
   The homepage redesign had cut it to the landmark and moved the address into
   a <p>, which changed a frozen heading. The address is back inside the h2 as
   a span; these rules make that span render exactly as the <p> did.
   Weights: .visit-band h2 .visit-addr (0-2-1) beats .visit-band h2 (0-1-1),
   which the span would otherwise inherit 40px/700 type from, and the old
   .visit-addr (0-1-0) margin rules above. Values are the <p>'s computed ones:
   body type (--fs-11, --fs-10 under 640px, 1.68 line-height), 0.78 paper, the
   h2's old 11.9px bottom margin now above the span, and the <p>'s 18px bottom
   margin now under the h2 — so nothing below it moves.
   ---------------------------------------------------------------------- */
.visit-band h2 .visit-addr {
  display: block;
  margin: var(--sp-12, 14px) 0 0;
  font-size: var(--fs-11);
  font-weight: 400;
  line-height: 1.68;
  letter-spacing: normal;
}
.visit-band h2:has(.visit-addr) { margin-bottom: 18px; }
@media (max-width: 640px) {
  .visit-band h2 .visit-addr { font-size: var(--fs-10); }
}

/* ---- inner-page hero: the doctor band's dimensions ------------------------
   The owner's brief for the other pages (2026-09-23): "each page to have a hero
   image at the very top, with the same dimensions as the image of the dentist"
   — and the art supplied for them is 3:1, the doctor artwork's ratio. The
   full-viewport hero at direction.css:931 was asked for on the HOMEPAGE only,
   but because this sheet ships site-wide every inner page inherited a
   900px-tall hero, cover-cropping the 3:1 art down to its middle half and
   cutting off the right-hand subject the scrim was composed around.
   Inner pages now take the doctor band's own sizing (.sec-doctor min-height,
   518px at 1440). It is a MIN height: a long source lede still fits, because
   the copy is frozen and must not be clipped.
   body.home marks the designed homepage; every other page — including any
   added later — gets the inner hero by default.
   Weight: body:not(.home) .hero-inner (0-2-1) beats .hero-inner (0-1-0) at
   :931 and the three earlier @media .hero-inner min-heights (0-1-0).
   ---------------------------------------------------------------------- */
body:not(.home) .hero-inner { min-height: clamp(360px, 36vw, 520px); }
/* On a phone the 3:1 inner-hero art shows only ~20-30% of its width, and a
   centred crop lands on the empty wall the art leaves for the desktop copy.
   Bias the crop right onto the subject, as the doctor band does under 860px
   (.sec-doctor-media, object-position 72%).
   Weight: body:not(.home) .hero-media img (0-2-2) beats .hero-media img (0-1-1). */
@media (max-width: 860px) {
  body:not(.home) .hero-media img { object-position: 76% center; }
}
/* ...and on a phone the gold --hero-glow (tokens.css:271, a 40rem radial at
   88% 18%, 0.30 alpha) is wider than the screen, so it lies over the copy and
   lifts the scrimmed backdrop: measured worst pixel rgb(111,124,118) = teal@0.86
   plus gold@0.30, which held the inner-page lede at 3.86-4.10:1 even after the
   mobile scrim fix. On desktop it sits right of the copy column and is harmless.
   The homepage's taller hero keeps its copy clear of the glow (5.12:1), so the
   approved homepage keeps it.
   Weight: body:not(.home) .hero-inner::before (0-2-2) beats direction.css:288
   .hero-inner::before (0-1-1). */
@media (max-width: 860px) {
  body:not(.home) .hero-inner::before { background: none; }
}

/* ==========================================================================
   INNER PAGES — fixes from the 2026-09-23 audit
   Six auditors measured 12 representative inner pages at 1440 and 390 against
   the homepage; two independent verifiers re-measured each finding. Every rule
   names what was measured and the weight it needs. The homepage (body.home) is
   untouched except where a rule says "site-wide".
   ========================================================================== */

/* ---- 1. Band colour by CLASS (contract §2) ---------------------------------
   The homepage's :nth-of-type colours landed on inner pages by position: an
   ivory band beside a near-identical oak band (dRGB <= 4, read as one 2,400px
   band), and an off-palette cool grey (rgb 224,224,218). build.mjs now tags
   inner panels band-a / band-b alternately.
   Weight: 0-4-2 beats the nth-of-type rules (0-3-1). */
body:not(.home) .prose > section.panel.band-a { background-color: var(--ivory); border-block: 0; }
body:not(.home) .prose > section.panel.band-b { background-color: var(--warm-white); border-block: 0; }
/* Forms sit on the homepage form's beige (0-5-2 beats the band rules). */
body:not(.home) .prose > section.panel.band-a.sec-form,
body:not(.home) .prose > section.panel.band-b.sec-form { background-color: rgb(var(--ch-oak) / 0.20); }

/* ---- 2. Images --------------------------------------------------------------
   Only the page's MAIN image (build marks it .lead) runs edge to edge, as a band
   like the homepage's photo bands, framed high so faces are not cropped away
   (the old 374px band showed 39% of a 3:2 photo and cut the subject's head).
   Every other wide image now shows at its own size instead of being stretched:
   the doctor portrait (480x640) had been blown up 2.46x to 1573px tall.
   Weights: non-lead 0-4-3 and lead 0-5-3 beat the old first-panel bleed rule
   (0-3-2) and .prose img (0-1-1). */
body:not(.home) .prose > section.panel img.wide {
  width: auto; max-width: 100%; height: auto;
  margin-left: auto; margin-right: auto; display: block;
  box-shadow: none;
}
body:not(.home) .prose > section.panel img.wide.lead {
  width: 100vw; max-width: 100vw;
  height: clamp(300px, 30vw, 460px);
  margin-left: calc(50% - 50vw); margin-right: 0;
  margin-block: 0 clamp(18px, 2.2vw, 30px);
  object-fit: cover; object-position: 50% 30%;
  border-radius: 0; box-shadow: none;
}
/* The breakout maths needs the image's paragraph to span the band's content box. */
body:not(.home) .prose > section.panel > p:has(> img.wide.lead) { max-width: none; margin-inline: 0; }

/* ---- 3. One reading column --------------------------------------------------
   The measure depended on PANEL POSITION: first-panel paragraphs centred at 96ch
   (a rule written for the homepage intro), later panels left-aligned at 822px
   with 358px dead on the right, and lists at the full 1180px, 140+ characters a
   line. Everything now shares one centred 96ch column, per contract §4: body
   paragraphs centred on desktop, left below 720px; lists, tables and quotes keep
   left-aligned text inside that same column so bullets still line up.
   Weights: the column rule 0-4-2 and the paragraph rules 0-3-3 beat
   .prose > section.panel:nth-of-type(1) > p (0-3-2) and .prose p (0-1-1). */
body:not(.home) .prose > section.panel > :is(p, ul, ol, dl, table, blockquote, .daylist) {
  max-width: 96ch;
  margin-inline: auto;
}
body:not(.home) .prose > section.panel > :is(ul, ol, dl, table, blockquote) { text-align: left; }
@media (min-width: 721px) {
  body:not(.home) .prose > section.panel > p { text-align: center; text-wrap: pretty; }
}
@media (max-width: 720px) {
  body:not(.home) .prose > section.panel > p { text-align: left; }
}
/* A SECTION TITLE that is a link reads as a title (it was underlined like body
   text). Only h2 section titles: a link inside a sub-head's running words (the
   404 page's "Visit our home page or") must still look like a link. */
body:not(.home) .prose > section.panel > h2 > a { color: inherit; text-decoration: none; }
body:not(.home) .prose > section.panel > h2 > a:hover { text-decoration: underline; text-underline-offset: 6px; }
/* Site-wide: balanced title lines ("... & So Much More!" left "More!" alone). */
.prose > section.panel > :is(h2, h3, h4) { text-wrap: balance; }
/* Source markup nests <b> in <b> on one list item, bolding its whole line. */
.prose li > b:has(> b) { font-weight: inherit; }
.prose li > b > b { font-weight: 700; }

/* Sub-heads carried from the source's heading-h3 blocks (build: p.subhead):
   the homepage's card-label style, uppercase, tracked, champagne rule. They
   follow the paragraph alignment (centred on desktop, as the contract centres
   sub-heads). 0-5-3 beats the column rule above. */
body:not(.home) .prose > section.panel > p.subhead {
  margin: clamp(26px, 3vw, 40px) auto 12px;
  padding-bottom: 9px;
  border-bottom: 2px solid rgb(var(--ch-champagne) / 0.65);
  font-size: 0.82rem; font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--teal);
}
/* An article's date, wrapped by the build: the homepage blog card's date. */
body:not(.home) .prose > section.panel > p.post-date {
  font-size: 0.78rem; font-weight: 700;
  letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--teal);
  margin-bottom: clamp(12px, 1.4vw, 18px);
}
/* Embedded maps and video inside page content: in the column, shadowed like
   the homepage map. Maps ran 1180x664 with no frame. */
body:not(.home) .prose > section.panel iframe {
  display: block; width: 100%; max-width: 96ch;
  margin: 0 auto clamp(18px, 2vw, 26px);
  height: clamp(260px, 30vw, 420px);
  border: 0; border-radius: 12px;
  box-shadow: 0 10px 30px rgb(var(--ch-teal) / 0.10), 0 2px 6px rgb(var(--ch-teal) / 0.06);
}
body:not(.home) .prose > section.panel iframe[src*="youtube"] { height: auto; aspect-ratio: 16 / 9; }

/* ---- 4. CTA band paragraph, site-wide ---------------------------------------
   Teal @0.80 on champagne measured 3.35:1 on every page, homepage included;
   body text needs 4.5. Full teal is the pair the band's own h2 uses: 4.71:1.
   Weight: div.cta-band p (0-1-2) beats .cta-band p (0-1-1). */
div.cta-band p { color: rgb(var(--ch-deep)); }

/* ---- 5. Contact band on inner pages = the homepage visit band ---------------
   The strapline h2 was 31.68px with the whole address at heading size, four
   lines tall, leaving a 410x255px empty block beside the hours. It now carries
   the homepage markup (landmark in champagne, address as a lighter line, same
   words) at the homepage's 40px, spans the band, and contact + hours sit side
   by side beneath it. Weights 0-3-3 / 0-3-2 beat the 0-3-1 / 0-2-0 originals. */
main .page-grid > aside.aside { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
main .page-grid > aside.aside > .card:first-child,
main .page-grid > aside.aside > .card-map { grid-column: 1 / -1; }
main .page-grid > aside.aside .card h2 { font-size: clamp(1.7rem, 2.8vw, 2.5rem); line-height: 1.18; }
main .page-grid > aside.aside .card h2 em { font-style: normal; color: var(--gold-c); }
main .page-grid > aside.aside .card h2 .visit-addr {
  display: block;
  margin: var(--sp-12, 14px) 0 0;
  font-size: var(--fs-11); font-weight: 400; line-height: 1.68; letter-spacing: normal;
  color: rgb(var(--ch-paper) / 0.78);
}
/* Phone and Email values sat 9-10px below their labels: the value link is a
   44px tap box centring its text, the label sat at the top of the row. */
main .page-grid > aside.aside .fact-list li { align-items: baseline; }
/* The Contact page's Locate Us map, framed like the homepage map. */
main .page-grid > aside.aside > .card-map {
  border-radius: 12px; overflow: hidden;
  box-shadow: 0 10px 30px rgb(0 0 0 / 0.18), 0 2px 6px rgb(0 0 0 / 0.12);
}
main .page-grid > aside.aside > .card-map iframe { display: block; width: 100%; height: clamp(260px, 28vw, 380px); border: 0; }
@media (max-width: 640px) {
  main .page-grid > aside.aside { grid-template-columns: minmax(0, 1fr); }
  main .page-grid > aside.aside .card h2 .visit-addr { font-size: var(--fs-10); }
}

/* ---- 6. Breadcrumbs lead the hero copy (moved by the build) -----------------
   The trail sat in its own 43px strip (65-123px on phones) above the hero, so
   the hero did not start at the top. On the teal scrim it takes warm white.
   Weights: .hero .crumbs ... (0-2-1+) beat .crumbs ... (0-1-1) and .shell (0-1-0). */
.hero .crumbs { padding: 0 0 clamp(10px, 1.2vw, 16px); font-size: var(--fs-6); color: rgb(var(--ch-paper) / 0.86); }
.hero .crumbs > .shell { width: auto; max-width: none; margin: 0; padding: 0; }
.hero .crumbs a, .hero .crumbs span, .hero .crumbs li::after { color: rgb(var(--ch-paper) / 0.86); }
.hero .crumbs a:hover { color: #fff; }
/* On phones the 44px link boxes and the plain current-page label sat 11px apart. */
nav.crumbs ol { align-items: center; }

/* ---- 7. Hero lede fills its column ------------------------------------------
   Held to 44ch inside a 704px column it left 219px of slack and ran ten lines,
   pushing inner heroes to 658-725px against the doctor band's 518.
   Weight: 0-4-2 beats .hero-copy .hero-lede (0-2-0). */
body:not(.home) .hero .hero-copy .hero-lede { max-width: 60ch; }

/* ---- 8. Phones: a list item that starts with a link -------------------------
   The link became a 44px inline-flex box, inflating that item's first line to
   35-44px against a 26px rhythm. Links inside running text take vertical padding
   instead (site.css's own rule for in-sentence links), so the hit area stays
   >= 44px without touching the line box. Weight 0-1-3 beats .prose li > a (0-1-2). */
@media (max-width: 1100px) {
  body .prose li > a { display: inline; min-height: 0; min-width: 0; padding-block: 12px; }
}

/* ---- 9. News listings as the homepage's blog cards --------------------------
   What's New shipped as 87 full-bleed bands, each post title at section scale.
   The build now emits the homepage card markup; titles keep their h2 level.
   Weight: .sec-blog .post h2.post-title (0-3-1) beats .prose h2 (0-1-1). */
.sec-blog .post h2.post-title {
  margin: 0 0 10px; padding: 0; border: 0;
  font-size: clamp(1.05rem, 1.35vw, 1.25rem); line-height: 1.3;
  text-align: left;
}
.sec-blog .post h2.post-title::before,
.sec-blog .post h2.post-title::after { content: none; }
.sec-blog .post h2.post-title a { color: var(--teal); text-decoration: none; }
.sec-blog .post h2.post-title a:hover { text-decoration: underline; text-underline-offset: 3px; }
.sec-blog .post .post-excerpt { margin: 0 0 18px; }

/* ---- 10. Logo walls ----------------------------------------------------------
   Rows ended in half-empty last lines (7 logos in 4 columns, 21 in 4), logos
   were shrunk to 0.56x (133px art at 75px, the small marks unreadable), and the
   tiles wore the heavy V1 glass shadow and lifted on hover though not links.
   Now: centred last rows, logos at their own size, the homepage's white card.
   Weights 0-3-2 beat site.css .logo-grid rules (0-1-0 / 0-1-1). */
body:not(.home) .prose .logo-grid { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--sp-14); }
body:not(.home) .prose .logo-grid > li {
  flex: 0 0 calc((100% - 3 * var(--sp-14)) / 4);
  min-height: 140px;
  background: #fff; background-image: none;
  border: 1px solid rgb(var(--ch-teal) / 0.10);
  border-radius: 12px;
  box-shadow: 0 2px 10px rgb(var(--ch-teal) / 0.06);
}
body:not(.home) .prose .logo-grid > li:hover { transform: none; box-shadow: 0 2px 10px rgb(var(--ch-teal) / 0.06); }
body:not(.home) .prose .logo-grid img { max-height: 110px; border-radius: 0; }
/* The plan names listed under a logo wall flow into columns instead of one
   405px-tall single column beside 980px of empty band. */
body:not(.home) .prose .logo-grid + ul { columns: 3; column-gap: var(--sp-16); }
body:not(.home) .prose .logo-grid + ul > li { break-inside: avoid; }
@media (max-width: 900px) {
  body:not(.home) .prose .logo-grid > li { flex-basis: calc((100% - 2 * var(--sp-14)) / 3); }
}
@media (max-width: 560px) {
  body:not(.home) .prose .logo-grid > li { flex-basis: calc((100% - var(--sp-14)) / 2); min-height: 120px; }
  body:not(.home) .prose .logo-grid + ul { columns: 2; }
}

/* ---- 11. Footer, site-wide ----------------------------------------------------
   Its content edge sat 10px (4px on phones) outside the bands above it, the
   fifth grid track stood empty (a 215x339px hole), two hairlines ran 33px apart
   under "Request an appointment", and on phones it was 1,784px tall.
   Weights: .site-footer > .shell (0-2-0) beats .shell (0-1-0); the others are
   stated inline. */
.site-footer > .shell { width: min(var(--band-max), 100% - (var(--band-gutter) * 2)); }
.site-footer .footer-grid > div:last-child .footer-form { border-top: 0; margin-top: 0; padding-top: 14px; } /* 0-4-1 > 0-2-0 */
@media (min-width: 961px) {
  /* The first column carries the hours line ("Tuesday–Thursday: 9:00 AM – 6:00 PM"),
     which broke before "PM" at an even quarter; it gets the extra width. */
  footer.site-footer .footer-grid { grid-template-columns: minmax(0, 1.3fr) repeat(3, minmax(0, 1fr)); } /* 0-2-1 > 0-2-0 */
}
@media (max-width: 640px) {
  footer.site-footer .footer-grid ul { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: 16px; } /* 0-2-2 > 0-2-1 */
}

/* ---- 12. Primary nav: the section you are in -------------------------------
   The homepage shows a pill on "Home"; inner pages showed nothing. data-current
   (set by the build) takes the same pill as site.css:186 a[aria-current]. */
.primary-nav [data-current] {
  background-color: var(--glass-pane-strong);
  border-color: var(--glass-border);
  box-shadow: var(--glass-shadow);
}

/* ---- 13. Real forms rebuilt from the source's Gravity Forms (build) ---------
   They share .appt-form's look, but the homepage form's field ORDER rules
   (.appt-form > div.field:nth-of-type(n), 0-3-1) would shuffle any other form,
   so they are reset here at 0-3-2 / 0-4-2. */
body form.appt-form.gf-form > .field { order: 0; grid-column: auto; }
body form.appt-form.gf-form > .field.full { grid-column: 1 / -1; }
.gf-form .form-section {
  grid-column: 1 / -1;
  margin: clamp(14px, 1.6vw, 24px) 0 0;
  padding: clamp(14px, 1.6vw, 20px) 0 0;
  border-top: 1px solid rgb(var(--ch-teal) / 0.18);
  font-size: clamp(1.2rem, 1.6vw, 1.45rem); line-height: 1.25;
  color: var(--teal); text-align: left;
}
.gf-form .form-intro p, .gf-form .form-section-desc { margin: 0 0 6px; max-width: none; text-align: left; }
.gf-form .field-desc { margin: 2px 0 0; font-size: 0.86rem; color: rgb(var(--ch-charcoal) / 0.78); max-width: none; }
.gf-form .opts.many { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 0 18px; }
.gf-form .sub { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px 14px; }
.gf-form .subfield { display: grid; gap: 4px; align-content: start; min-width: 0; }
.gf-form .subfield.wide { grid-column: 1 / -1; }
/* An address block has full-width lines (Street, Line 2) spanning every track, so
   auto-fit could not collapse the unused 5th track: City/State/ZIP/Country ran
   four-across with a ~170px empty column after them. Explicit tracks instead. */
.gf-form .sub:has(> .subfield.wide) { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 640px) { .gf-form .sub:has(> .subfield.wide) { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.gf-form .subfield label { font-weight: 400; font-size: 0.84rem; color: rgb(var(--ch-charcoal) / 0.82); }
.gf-form :is(select, input[type="number"], input[type="date"], input[type="url"]) {
  width: 100%; padding: var(--sp-13) var(--sp-16);
  font: inherit; font-size: var(--fs-9); color: var(--ink-strong);
  background: var(--glass-pane-strong);
  border: 1px solid rgb(var(--ch-slate) / 0.60); border-radius: var(--r-md);
}
/* Selects rendered 46px and date fields 53.2px beside 51.2px text fields, so the
   sub-labels under side-by-side fields sat 5-7px out of line (measured). All take
   the text field's height: one line box + its padding + its 1px borders. */
.gf-form :is(select, input[type="date"]) { box-sizing: border-box; line-height: inherit; height: calc(1lh + (var(--sp-13) * 2) + 2px); }
.gf-form .opt { padding-left: 0; }
.gf-form .opt input[type="checkbox"] { width: 20px; height: 20px; margin: 12px 2px; flex: none; accent-color: var(--teal); }

/* ---- 14. Contact / Locate cards on inner pages -------------------------------
   Hours & Location stacked a bulleted contact list, bare address text and an
   unframed 1180x664 map. The build now wraps them in the homepage's
   .contact-locate markup; these rules give them the homepage .sec-contact
   treatment (side by side, white, lifted, map framed).
   Weights: 0-3-2 / 0-4-3 beat the global .cl-card / .cl-map rules (0-1-0 /
   0-1-1) and the in-content iframe rule (0-3-3). */
body:not(.home) .prose .contact-locate {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
  gap: clamp(20px, 2.4vw, 36px);
  align-items: stretch;
  max-width: 96ch;
  margin: 0 auto clamp(22px, 2.4vw, 34px);
}
body:not(.home) .prose .contact-locate > :is(.cl-card, .cl-map) {
  background: #fff;
  border-left: 0;
  border-radius: var(--r-md);
  padding: clamp(22px, 2.4vw, 32px);
  box-shadow: 0 10px 30px rgb(var(--ch-teal) / 0.10), 0 2px 6px rgb(var(--ch-teal) / 0.06);
  display: flex; flex-direction: column;
  min-width: 0; text-align: left;
}
body:not(.home) .prose .contact-locate p.subhead {
  margin: 0 0 12px; padding-bottom: 9px;
  border-bottom: 2px solid rgb(var(--ch-champagne) / 0.65);
  font-size: 0.82rem; font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--teal); text-align: left; max-width: none;
}
body:not(.home) .prose .contact-locate ul + p.subhead { margin-top: clamp(18px, 2vw, 26px); }
body:not(.home) .prose .contact-locate .cl-card ul { margin: 0; padding: 0; border-top: 0; }
body:not(.home) .prose .contact-locate .cl-addr { margin: 0; max-width: none; text-align: left; }
body:not(.home) .prose > section.panel .contact-locate .cl-map iframe {
  flex: 1 1 auto;
  width: 100%; max-width: none; height: auto;
  min-height: clamp(280px, 26vw, 400px);
  margin: 0;
  border-radius: var(--r-sm);
  box-shadow: 0 1px 4px rgb(var(--ch-teal) / 0.10);
}
@media (max-width: 860px) {
  body:not(.home) .prose .contact-locate { grid-template-columns: minmax(0, 1fr); }
}

/* ---- 15. Pictures the source put inside headings ------------------------------
   The source's page builder wrapped photo modules in <h2> (Kids Optical: three
   photos; Eye Emergencies: the lead photo). A build filter had been silently
   DROPPING such picture-only sections; they are back (their alts are content),
   and render as a picture row, not as a 43px section title with a gold rule.
   Weights: 0-4-3 / 0-4-4 beat .prose > section.panel > h2 (0-2-2) and the
   non-lead image rule (0-4-3) by coming later at >= the same weight. */
body:not(.home) .prose > section.panel > h2:has(> img) {
  display: flex; flex-wrap: wrap; justify-content: center; align-items: center;
  gap: clamp(12px, 1.4vw, 18px);
  margin: 0; padding: 0; border: 0;
  font-size: inherit; line-height: 0;
}
body:not(.home) .prose > section.panel > h2:has(> img) > img:not(.lead) {
  display: block; width: auto; height: auto;
  max-width: min(100%, 420px); max-height: 320px;
  margin: 0; border-radius: 12px;
  box-shadow: 0 2px 10px rgb(var(--ch-teal) / 0.06);
}
/* A heading that holds the LEAD photo is not a picture row: as a flex item the
   100vw photo first shrank to the row (130px short on the right), then was
   centred on top of its full-bleed margin (65px off to the left). As a block it
   bleeds exactly like the paragraph-wrapped lead photos. 0-4-4 > 0-4-3. */
body:not(.home) .prose > section.panel > h2:has(> img.lead) { display: block; }
/* A lead photo that is its section's only content is the band: no ivory strip
   above or below it (owner principle: no solid strips around photographs). */
body:not(.home) .prose > section.panel:has(> :only-child > img.lead:only-child) { padding-block: 0; }
body:not(.home) .prose > section.panel:has(> :only-child > img.lead:only-child) img.lead { margin-block: 0; }

/* ---- 16. Archive post lists (category / tag / author) ------------------------
   The build wraps each archive's run of post-title links in ul.linklist; they
   had rendered as one paragraph of ten jammed-together links. Two columns of
   titles with hairlines, the blog cards' teal title style; one column on phones.
   Weight 0-4-3 beats the reading-column list rule (0-4-2) where they overlap. */
body:not(.home) .prose > section.panel > ul.linklist {
  list-style: none; padding: 0;
  columns: 2; column-gap: clamp(24px, 3vw, 48px);
}
body:not(.home) .prose > section.panel > ul.linklist > li {
  break-inside: avoid; margin: 0;
  padding: 12px 0; border-bottom: 1px solid rgb(var(--ch-teal) / 0.12);
}
body:not(.home) .prose > section.panel > ul.linklist a {
  color: var(--teal); font-weight: 600; text-decoration: none;
}
body:not(.home) .prose > section.panel > ul.linklist a:hover { text-decoration: underline; text-underline-offset: 3px; }
@media (max-width: 720px) {
  body:not(.home) .prose > section.panel > ul.linklist { columns: 1; }
}

/* ---- 17. Final-verification fixes (2026-09-23) ------------------------------
   From the revision-ledger checkers, each re-measured before being fixed. */

/* Bold paragraphs the source uses as sub-headings (build: p.pseudo-head; 143 on
   38 pages) read as sub-heads, not body text. Sub-head scale rather than the 43px
   section-title scale: many are full-sentence FAQ questions. 0-5-3. */
body:not(.home) .prose > section.panel > p.pseudo-head {
  margin: clamp(22px, 2.6vw, 34px) auto 10px;
  font-size: clamp(1.2rem, 1.7vw, 1.5rem); line-height: 1.3;
  color: var(--teal);
}
body:not(.home) .prose > section.panel > p.pseudo-head > :is(strong, b) { font-weight: 700; }

/* Free-standing source sub-heads ("Hours", "Payment Information") head their
   own blocks, so they take the section-title scale; those inside a Contact card
   keep the card-label style (rule 14). Spans the band like an h2. 0-5-3. */
body:not(.home) .prose > section.panel > p.subhead {
  max-width: none; margin: clamp(30px, 3.4vw, 48px) 0 clamp(14px, 1.6vw, 22px);
  padding-bottom: 14px; border-bottom: 2px solid rgb(var(--ch-gold) / 0.5);
  font-size: clamp(1.9rem, 3vw, 2.7rem); font-weight: 700; line-height: 1.16;
  letter-spacing: normal; text-transform: none; text-align: center;
  color: var(--teal);
}

/* Lead photos: framed higher (15%) so tall subjects near the top — the
   storefront's sign, faces — are not sliced by the band's top edge. */
body:not(.home) .prose > section.panel img.wide.lead { object-position: 50% 15%; }
/* On a phone the band would show under half the width of a wide image and cut
   lettered artwork mid-word; the lead shows whole there, still edge to edge. */
@media (max-width: 640px) {
  body:not(.home) .prose > section.panel img.wide.lead { height: auto; object-fit: initial; }
}
/* No colour strip between the hero photo and a lead photo that opens its
   section (location page: 54px). */
body:not(.home) .prose > section.panel:has(> :first-child > img.lead:only-child) { padding-top: 0; }
/* An article's date sat alone in a 92px strip between the hero and the lead
   photo; the photo now opens the section and the date labels it below. Visual
   order only — the DOM keeps the source order. */
body:not(.home) .prose > section.panel:has(> p.post-date:first-child + p > img.lead:only-child) {
  display: flex; flex-direction: column; padding-top: 0;
}
body:not(.home) .prose > section.panel:has(> p.post-date:first-child + p > img.lead:only-child) > * { order: 3; }
body:not(.home) .prose > section.panel:has(> p.post-date:first-child + p > img.lead:only-child) > p:has(> img.lead) { order: 1; }
body:not(.home) .prose > section.panel:has(> p.post-date:first-child + p > img.lead:only-child) > p.post-date { order: 2; margin-top: 0; }

/* A small picture placed directly in a section sat at the left edge of a centred
   column (the eye diagram on "How Do We See?"). */
body:not(.home) .prose > section.panel > img:not(.wide) { display: block; margin-inline: auto; }

/* Six payment marks (51x32 each) in 4-wide 236x140 tiles made a 4+2 layout with
   two holes and mostly empty tiles: one row of six small tiles instead (three
   per row on phones). */
body:not(.home) .prose .logo-grid:has(> li:nth-child(6):last-child) > li {
  flex-basis: calc((100% - 5 * var(--sp-14)) / 6); min-height: 88px;
}
@media (max-width: 900px) {
  body:not(.home) .prose .logo-grid:has(> li:nth-child(6):last-child) > li { flex-basis: calc((100% - 2 * var(--sp-14)) / 3); }
}

/* Contact card rows: in a flex row the phone link is blockified with its 12px
   tap padding, so the value sat 15px below its label on phones. */
body:not(.home) .prose .contact-locate .cl-card li { align-items: baseline; }

/* Phones: a wrapped breadcrumb trail had 43px holes between its rows — 44px tap
   boxes. Vertical padding keeps the tap area without growing the rows. */
@media (max-width: 1100px) {
  .hero .crumbs li a { display: inline; min-height: 0; min-width: 0; padding-block: 12px; }
  .hero .crumbs ol { row-gap: 4px; }
}

/* Phones, site-wide: the topbar centred one line and left-aligned the others. */
@media (max-width: 640px) {
  .topbar .topbar-facts { justify-content: center; text-align: center; width: 100%; }
}

/* Phones, site-wide: the CTA band's two stacked pills were 209px and 152px wide;
   the hero's are equal. */
@media (max-width: 640px) {
  div.cta-band .btn-row { flex-direction: column; align-items: center; }
  div.cta-band .btn-row .btn { width: min(100%, 260px); justify-content: center; }
}

/* ---- 18. Revision-ledger fixes, homepage (2026-09-23) --------------------- */

/* The intro band and the appointment-form band measured 1.017:1 — the same
   colour — right after the banner, breaking the owner's alternating rhythm.
   Contract §2 has the intro on warm white. 0-4-2 beats nth-of-type (0-3-1). */
body.home .prose > section.panel:nth-of-type(1) { background-color: var(--warm-white); }

/* Eye Exams band: the right-to-left wash fell to ~0.5 at x=605 while the copy
   column starts at x=574, so the first third of the text sat on bright photo —
   body copy 2.4:1, the CTA 1.5-1.9:1. Hold >=0.86 across the whole copy column
   (the right 62%), then fade over the photo's left side — the hero's rule.
   The CTA goes to warm white with a champagne underline, as the hero lede link
   did. Weights 0-4-2 / 0-4-3 beat .sec-exams-media::after (0-1-1). */
body.home .prose > section.panel.sec-exams .sec-exams-media::after {
  background: linear-gradient(270deg,
    rgb(var(--ch-teal) / 0.94)  0%,
    rgb(var(--ch-teal) / 0.92) 30%,
    rgb(var(--ch-teal) / 0.88) 55%,
    rgb(var(--ch-teal) / 0.86) 62%,
    rgb(var(--ch-teal) / 0.62) 72%,
    rgb(var(--ch-teal) / 0.30) 84%,
    rgb(var(--ch-teal) / 0.08) 100%);
}
body.home .prose > section.panel.sec-exams .split-cta a {
  color: var(--warm-white);
  text-decoration: underline; text-decoration-color: var(--champagne);
  text-decoration-thickness: 2px; text-underline-offset: 5px;
}
@media (max-width: 860px) {
  body.home .prose > section.panel.sec-exams .sec-exams-media::after {
    background: linear-gradient(180deg, rgb(var(--ch-teal) / 0.88) 0%, rgb(var(--ch-teal) / 0.93) 60%);
  }
}

/* Doctor band: .prose img (0-1-1) was rounding the full-bleed artwork's
   corners (0-1-0), leaving a lighter wedge at each corner. On phones the band
   needs its scrim (the copy covers the face there), and the champagne "Read
   More" on it measured 3.83:1 — warm white with a champagne underline. */
body.home .prose > section.panel.sec-doctor .sec-doctor-media { border-radius: 0; }
@media (max-width: 860px) {
  body.home .prose > section.panel.sec-doctor .bio-body a {
    color: var(--warm-white);
    text-decoration: underline; text-decoration-color: var(--champagne); text-underline-offset: 4px;
  }
}

/* Reviews: the rail clipped its cards' shadows into a straight edge along the
   bottom — which reads like the old scrollbar line. Room for the shadow. */
body.home .prose > section.panel.sec-reviews .reviews { padding-bottom: 18px; }

/* Phones: the Optos artwork (lettered) was cropped to its middle 43%, cutting its
   text mid-word; the emergency photo sat under a 90-96% white wash and could not
   be seen. The Optos shows whole; the photo becomes an unwashed band above the
   copy. Weights 0-7-3 / 0-5-3 beat the 0-5-2 / 0-1-1 originals. */
@media (max-width: 640px) {
  body.home .prose > section.panel.sec-featuring .bento-banner .bento-media img { height: auto; object-fit: initial; }
}
@media (max-width: 860px) {
  body.home .prose > section.panel.sec-emergency { padding-top: calc(clamp(200px, 52vw, 320px) + 28px); }
  body.home .prose > section.panel.sec-emergency::before { bottom: auto; height: clamp(200px, 52vw, 320px); background-position: 78% center; }
  body.home .prose > section.panel.sec-emergency::after { top: clamp(200px, 52vw, 320px); background: #fff; }
}

/* Contact / Locate: the labels (16.56px) were smaller than the line under them
   (17.92px) — the owner asked for bigger text. And, site-wide, a card row's
   value link is blockified in its flex row with 12px tap padding, dropping it
   15px below its label on phones. */
body.home .prose > section.panel.sec-contact .cl-card > h4,
body.home .prose > section.panel.sec-contact .cl-map > h4 { font-size: clamp(1.15rem, 1.5vw, 1.35rem); }
.contact-locate .cl-card li { align-items: baseline; }
/* The hours rows ran full width under the two cards, so they started 35-45px
   off the cards' inner edges. Same two tracks as the cards, same inset. */
@media (min-width: 861px) {
  body.home .prose > section.panel.sec-contact .daylist {
    columns: auto; display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
    grid-template-rows: repeat(4, auto); grid-auto-flow: column;
    column-gap: clamp(20px, 2.4vw, 36px);
  }
  body.home .prose > section.panel.sec-contact .daylist > li { padding-inline: clamp(22px, 2.4vw, 32px); }
}

/* ---- 19. Revision-ledger fixes, inner pages ------------------------------- */

/* A sub-section heading sat closer to the text BEFORE it (26px) than to its own
   (34px), so it read as attached to the wrong block. More above, less below. */
body:not(.home) .prose > section.panel > :is(h3, h4):not(:first-child) {
  margin-top: clamp(36px, 4vw, 56px);
  margin-bottom: clamp(12px, 1.4vw, 18px);
}
/* Short lists hugged the left of the 96ch column under centred copy, leaving
   600px holes. The list block now fits its text and centres; its text stays
   left-aligned so bullets line up. Full-width on phones. Not the plan names
   after a logo wall: they flow in columns, and fit-content squeezed the columns
   until names ran into the next column's bullets. */
body:not(.home) .prose > section.panel > :is(ul, ol):not(.logo-grid):not(.linklist):not(.daylist):not(.logo-grid + ul) { width: fit-content; }
@media (max-width: 720px) {
  body:not(.home) .prose > section.panel > :is(ul, ol):not(.logo-grid):not(.linklist):not(.daylist):not(.logo-grid + ul) { width: auto; }
}
/* Picture rows (Kids Optical): three photos at three sizes, a ragged stack on
   phones. One shared height; widths follow each photo; one row even at 390. */
body:not(.home) .prose > section.panel > h2:has(> img) > img:not(.lead) {
  height: clamp(110px, 18vw, 260px); width: auto;
  max-height: none; max-width: 100%;
  object-fit: cover;
}
/* A small photo that opens a paragraph sat flush left above centred text. */
body:not(.home) .prose > section.panel > p > img:not(.wide) { margin-inline: auto; }

/* ---- 20. Revision-ledger fixes, site chrome (2026-09-23) -------------------- */

/* Primary button (header, hero, forms — site-wide): teal label on a champagne ->
   light-oak gradient measured 4.0:1 at its dark end (computed 3.86 on oak); a
   16.8px/600 label needs 4.5. The gradient now runs from a lighter champagne TO
   champagne, so every point holds >= 4.71:1 (teal on champagne). */
:root { --accent-grad: linear-gradient(135deg, rgb(226 204 174) 0%, rgb(var(--ch-champagne)) 100%); }

/* Phones: the owner asked for every menu to be OPAQUE; the mobile nav panel was
   still the V1 glass pane (0.86 white + 34px blur). And direction.css:1001 set
   the 4-column mega to min(760px, 94vw) — which beat site.css's mobile width:100%
   on source order — so at 390 two menus ran 33-41px wider than the nav and the
   open menu scrolled sideways. Weights: 0-2-0 > .primary-nav (0-1-0);
   0-3-0 > .mega[data-cols="4"] (0-2-0). */
@media (max-width: 1100px) {
  .site-header .primary-nav {
    background-color: var(--warm-white); background-image: none;
    -webkit-backdrop-filter: none; backdrop-filter: none;
  }
  .primary-nav .mega[data-cols] { width: 100%; max-width: 100%; }
}

/* Phones: the family banner's centred cover crop removed the daughter that its
   alt text describes; it shows whole, still edge to edge. 0-2-2 > 0-1-1. */
@media (max-width: 640px) {
  body.home .brand-banner img { height: auto; }
}

/* Phones, site-wide: links inside running text had 2px side padding (a tap-
   target tweak), which read as double spaces around them and detached a full
   stop. Vertical padding (the actual tap area) is kept. 0-1-3 > 0-1-2. */
@media (max-width: 1100px) {
  body .prose p a, body .hero-lede a { padding-inline: 0; }
}

/* ---- 21. Error-hunt fixes (2026-09-23) --------------------------------------- */

/* Tablet (641-1100px), inner pages: the lede, opened to 60ch, now runs past the
   dark part of the side-to-side scrim onto bright photo — 1.85-2.61:1 at 768.
   Tablets take the phone's top-to-bottom ramp (>=0.86 everywhere) and lose the
   gold glow, as phones do. Weights 0-4-2 / 0-2-2 beat .hero-media::after (0-1-1)
   and .hero-inner::before (0-1-1). */
@media (min-width: 641px) and (max-width: 1100px) {
  body:not(.home) .hero .hero-media::after {
    background: linear-gradient(180deg,
      rgb(var(--ch-teal) / 0.86) 0%,
      rgb(var(--ch-teal) / 0.90) 45%,
      rgb(var(--ch-teal) / 0.95) 100%);
  }
  body:not(.home) .hero-inner::before { background: none; }
}

/* Contact band rows: Phone and Email rows were 62px against 44px for every other
   row (the value link is a 44px box, baseline-aligned), so the two columns'
   hairlines never lined up. The link keeps its tap area through padding; every
   row is the same 44px. Weights 0-3-3 / 0-3-4 beat the 0-3-1 / 0-3-2 originals. */
main .page-grid > aside.aside .fact-list li { min-height: 44px; align-items: center; }
main .page-grid > aside.aside .fact-list li > a { display: inline; min-height: 0; padding-block: 12px; }

/* Contact / Locate card rows: a flex row ignores <br>, so at tablet width the
   privacy note ran on beside the email address. Rows are blocks; the label keeps
   its column. Site-wide (the homepage card has the same markup). */
.contact-locate .cl-card li { display: block; }
.contact-locate .cl-card li strong { display: inline-block; min-width: 58px; }

/* Blog cards: the tap-target rule made every title link a 44px box centred on its
   text, so one-line titles floated lower than two-line ones and the cards lost
   their rhythm. Inline, with padding for the tap area. 0-3-2 > 0-1-2. */
.sec-blog .post :is(h2, h5) a { display: inline; min-height: 0; min-width: 0; padding-block: 10px; }

/* Footer: the copyright and the legal links sat 12px apart on one row at tablet
   width; at 768 the Practice column dropped to a row of its own, leaving a hole.
   Two balanced columns from 641 to 960px. Site-wide. */
.site-footer .footer-bottom { align-items: center; }
@media (min-width: 641px) and (max-width: 960px) {
  footer.site-footer .footer-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Primary nav: the dropdown buttons used line-height:normal (33px pills) against
   the links' inherited 21.84px (40px) — uneven pills on desktop, and 33px tap
   targets in the phone menu; the menu's group headings were 16px targets. */
.primary-nav .mega-trigger { line-height: inherit; }
@media (max-width: 1100px) {
  .primary-nav .mega-trigger { min-height: 44px; }
  .primary-nav .mega h3 a { display: inline-flex; align-items: center; min-height: 44px; }
}

/* Review dots: each 10px dot carried a 44px invisible tap area centred on it, and
   dots sit 20px apart — so the areas overlapped and clicking dot 2 hit dot 3. The
   button itself is now the 44px target and the dot is drawn inside it; nothing
   overlaps. Weights 0-2-1 / 0-3-1 beat the 0-1-1 / 0-2-1 originals. */
.sec-reviews .reviews-dots { gap: 0; }
.sec-reviews .reviews-dots button {
  width: 44px; height: 44px; border: 0; border-radius: 0; background: transparent;
  display: grid; place-items: center; transform: none;
}
.sec-reviews .reviews-dots button::before {
  position: static; transform: none;
  width: 10px; height: 10px; border-radius: 50%;
  border: 1px solid rgb(var(--ch-teal) / 0.45); background: transparent;
  transition: background-color 0.18s ease, transform 0.18s ease;
}
.sec-reviews .reviews-dots button[aria-current="true"] { background: transparent; transform: none; }
.sec-reviews .reviews-dots button[aria-current="true"]::before { background: var(--teal); transform: scale(1.25); }

/* Keyboard focus: the ring was teal-2, 1.27:1 on the teal bands, and modern.css's
   champagne rings measured 1.24-1.33:1. Teal on light surfaces, warm white on
   dark ones — 8.14:1 either way. html :is(...):focus-visible (0-2-1) beats
   modern.css's outline:none (0-2-0) on its seven groups. */
html :is(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 3px solid var(--teal); outline-offset: 3px;
}
html :is(.topbar, .site-footer, .page-grid > .aside, .visit-band, .hero, .sec-doctor, .sec-exams) :is(a, button, input, select, textarea):focus-visible {
  outline-color: var(--warm-white);
}
/* The unwired-form notice (site.js). On the teal footer it takes warm white. */
.form-status { grid-column: 1 / -1; margin: 12px 0 0; padding: 12px 16px; border-left: 3px solid var(--champagne); background: rgb(var(--ch-teal) / 0.06); color: var(--teal); font-weight: 600; }
.site-footer .form-status { background: rgb(var(--ch-paper) / 0.08); color: var(--warm-white); }

/* ---- 22. Words too long for a phone (2026-09-23) --------------------------- */
/* A run of text wider than the column (a long word in a 30px section title, a URL
   in the copy) pushed the whole page sideways on phones. These break such a run
   only when it cannot fit; ordinary wrapping is unchanged. Headings are flex boxes
   here, so they need "anywhere" (which also lowers their min-content width); body
   copy is plain block text, where "break-word" is enough and cannot squeeze an
   auto-sized grid track. No overflow-wrap is set elsewhere on these elements. */
body:not(.home) main :is(h1, h2, h3, h4, h5, h6, .subhead, .pseudo-head) { overflow-wrap: anywhere; }
main :is(p, li, dd, dt, td, th, blockquote, figcaption) { overflow-wrap: break-word; }

/* ---- 23. Re-check fixes on the final build (2026-09-23) --------------------- */
/* Contact / Locate card, phones: the tap-area rule (section 8, padding-block 12px on
   .prose li > a) moved the gold underline, drawn as a border-bottom, 13px below the
   link. It floated between Phone and Fax, and struck through the privacy note under
   Email. A real text underline stays with the text while the padding keeps the tap
   area. Weight 0-2-2 beats .cl-card li a (0-1-2). */
.contact-locate .cl-card li a {
  border-bottom: 0;
  text-decoration: underline;
  text-decoration-color: rgb(var(--ch-gold) / 0.8);
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
}
/* Visit band: the Phone and Email links were 44px inline-flex boxes, so their rows
   ran 61px against 37px for Fax and the hours, and the two columns' hairlines never
   lined up. The row is a flex box, so the link is blockified and "display: inline"
   would do nothing; instead 12px of padding is cancelled by -12px of margin: the tap
   area stays 44px, the row keeps the text's height. Weight 0-2-2 beats
   .visit-band .visit-list a (0-2-1). */
.visit-band .visit-list li > a { min-height: 0; padding-block: 12px; margin-block: -12px; }
/* Reviews: the cards' 0 20px 44px shadow reaches 64px below them, but the rail
   (overflow auto) leaves 18px, so the shadow ended on a hard straight edge. A
   shadow that fits in 18px, at rest and when a card lifts 3px on hover.
   Weights 0-3-0 / 0-3-1 beat .review / .review:hover (0-1-0 / 0-2-0). */
.sec-reviews .reviews .review {
  box-shadow: 0 1px 2px rgb(52 54 56 / 0.10), 0 8px 14px -8px rgb(52 54 56 / 0.30), var(--glass-inset);
}
.sec-reviews .reviews .review:hover {
  box-shadow: 0 1px 2px rgb(52 54 56 / 0.10), 0 10px 16px -8px rgb(52 54 56 / 0.34), var(--glass-inset);
}

/* ---- 24. Final-build re-check fixes, round 2 (2026-09-23) ------------------ */
/* Mega menus. The linked group titles drew two lines: the anchor's own 1px teal
   border (from ".mega h3, .mega h3 a") 8px above the h3's hairline. Only the h3
   keeps it. 0-2-2 beats 0-1-2. */
.mega .mega-col h3 a { border-bottom-color: transparent; }
/* Eye Care Services: five groups flowed into three columns (section 12's column
   flow) cannot balance, so column three ended 160-200px short, a 459px-wide blank.
   On the desktop menu, five groups get five columns in one row, all starting at the
   same top. 1000px keeps the panel, centred on its button (x 519-661), inside the
   screen from 1101px up. The phone menu keeps its stack.
   Weights 0-5-0 / 0-6-0 beat .mega[data-cols="4"] / .mega[data-cols="4"] .mega-cols (0-2-0 / 0-3-0). */
@media (min-width: 1101px) {
  .mega[data-cols="4"]:has(> .mega-cols > .mega-col:nth-child(5):last-child) { width: min(1000px, 94vw); }
  .mega[data-cols="4"] .mega-cols:has(> .mega-col:nth-child(5):last-child) { display: grid; columns: auto; grid-template-columns: repeat(5, minmax(0, 1fr)); }
  /* one-line and two-line group titles: the same two-line box, text on its hairline */
  .mega[data-cols="4"] .mega-cols:has(> .mega-col:nth-child(5):last-child) .mega-col > h3 { display: flex; align-items: flex-end; min-height: calc(2lh + var(--sp-6)); box-sizing: border-box; }
}

/* Inner contact band: Phone and Email rows were 68px against 44px (section 21's
   "display: inline" does nothing to a flex item), and centring against the
   two-line address left the Address label 12.8px off its value on phones. Rows
   take their text height on a shared baseline; the links keep a 44px tap area
   through padding cancelled by margin. 0-3-4 / 0-3-5 beat 0-3-3 / 0-3-4. */
main .page-grid > aside.aside ul.fact-list li { min-height: 0; align-items: baseline; }
main .page-grid > aside.aside ul.fact-list li > a { min-height: 0; padding-block: 12px; margin-block: -12px; }

/* A phone number in the copy split "214-" / "872-2400" on phones. 0-2-1. */
.prose a[href^="tel:"] { white-space: nowrap; }

/* Logo walls with no orphan row: four logos go 2 x 2 below 900px (they broke
   3 + 1), and Designer Frames' 21 go 7 per row (3 rows) on desktop and 3 per row
   below 900px (7 rows), instead of 4 + ... + 1. The :has() weights beat section
   9's 0-3-2 per-width rules. */
@media (max-width: 900px) {
  body:not(.home) .prose .logo-grid:has(> li:nth-child(4):last-child) > li { flex-basis: calc((100% - var(--sp-14)) / 2); }
}
body:not(.home) .prose .logo-grid:has(> li:nth-child(21):last-child) > li {
  flex-basis: calc((100% - 6 * var(--sp-14)) / 7); min-height: 110px;
}
@media (max-width: 900px) {
  body:not(.home) .prose .logo-grid:has(> li:nth-child(21):last-child) > li { flex-basis: calc((100% - 2 * var(--sp-14)) / 3); min-height: 96px; }
}

/* Breadcrumbs in the hero: the "/" was drawn AFTER each item, so on phones a line
   could end on a dangling "/" with the current page alone below it; at 60% opacity
   it also measured 2.99-3.50:1. Drawn BEFORE the next item it wraps with that item,
   at the crumbs' own colour (5.2:1 or better). 0-2-3 beats .crumbs li:last-child::after (0-2-2). */
.hero .crumbs ol > li::after { content: none; }
.hero .crumbs ol > li + li::before { content: "/"; margin-right: var(--sp-7); color: rgb(var(--ch-paper) / 0.86); }

/* Bold-paragraph sub-heads centre on phones like every other head (section titles
   and p.subhead already do); body copy stays left. 0-4-3 beats 0-3-3. */
@media (max-width: 720px) {
  body:not(.home) .prose > section.panel > p.pseudo-head { text-align: center; }
}

/* Lead photos show whole on phones and tablets (section 17), so the source JPEG's
   own top row shows: a 1px olive line under the hero on Pink/Red Eyes. The top
   pixel row is clipped and the photo shifted up 1px, so the hero shows through
   there (a margin would lose to the lead's margin-block: 0 rules; the 1px freed
   at the bottom is the band's own colour, as below it). */
@media (max-width: 1100px) {
  body:not(.home) .prose > section.panel img.wide.lead { clip-path: inset(1px 0 0 0); transform: translateY(-1px); }
}

/* Homepage section heads matched to their content's edges. The appointment form's
   title rule ran 1180px over an 860px form; the optical title rule 24-1416 over a
   94-1346 tile row; the Now Featuring rule ran the full width, because it was
   inset with padding (the border spans the padding box). Weights 0-4-2 / 0-5-2
   beat 0-3-1 / 0-4-1. */
body.home .prose > section.panel:nth-of-type(2) > h2 { max-width: 860px; margin-inline: auto; }
body.home .prose > section.panel.sec-optical > h2 { max-width: calc(300px * 4 + clamp(12px, 1.2vw, 20px) * 3); margin-inline: auto; }
body.home .prose > section.panel.sec-featuring > .bento-head {
  padding-inline: 0;
  margin-inline: max(var(--band-gutter), calc((100% - var(--band-max)) / 2));
}
/* The phone link in the form note was a 46px tap box inside a sentence, opening
   an uneven gap in the wrapped line. Inline, with padding for the tap area. */
body.home .prose > section.panel:nth-of-type(2) > .form-note a { display: inline; min-height: 0; min-width: 0; padding-block: 12px; }
/* Eye Exams on phones: under a 0.88-0.93 teal wash the supplied family photo was
   invisible (1.34:1 across the whole band), a flat teal block. As the emergency
   section does below 860px: the photo becomes an unwashed band across the top and
   the copy sits under it on the section's solid teal. Weights 0-4-2 / 0-5-3 /
   0-5-4 beat 0-3-1 / 0-1-0 / 0-5-3. */
@media (max-width: 860px) {
  body.home .prose > section.panel.sec-exams { padding-top: calc(clamp(200px, 52vw, 320px) + 28px); min-height: 0; align-content: start; }
  body.home .prose > section.panel.sec-exams .sec-exams-media { bottom: auto; height: clamp(200px, 52vw, 320px); background-position: 8% center; }
  body.home .prose > section.panel.sec-exams div.sec-exams-media::after { background: none; }
}

/* ---- 25. Final-build re-check fixes, round 3 (2026-09-23) ------------------ */
/* Pictures never past their own size. A 324px figure photo rendered 1180px wide
   (3.64x, blocky: 8 Tips for Winter Dry Eyes), and a heading holding one 200px
   picture took the picture-row height, ~2x (Anti-Reflective), with the next line
   touching it. Weights 0-5-4 / 0-5-5 beat 0-2-3 (.prose > section.panel > figure img)
   and the picture-row rule (0-4-5). */
body:not(.home) .prose > section.panel > figure img:not(.wide) { width: auto; height: auto; max-width: 100%; display: block; margin-inline: auto; }
body:not(.home) .prose > section.panel > h2:has(> img:only-child) > img:not(.lead) { width: auto; height: auto; max-width: 100%; max-height: none; object-fit: initial; }
body:not(.home) .prose > section.panel > h2:has(> img:only-child:not(.lead)) { margin-bottom: var(--sp-14); }

/* Section-level h4s were flex boxes (site.css) only to centre them, so a mixed
   heading ("<strong>Important!</strong> Never stop ...") split into two side-by-side
   flex items. A centred block reads the same and cannot split. 0-3-3 beats 0-2-2. */
body:not(.home) .prose > section.panel > h4 { display: block; text-align: center; }

/* A band's first heading adds no top margin to the band's own padding: Keratoconus
   opened 63% deeper than every other band, and the bands now split at each title. */
body:not(.home) .prose > section.panel > :is(h2, h3, h4, p.subhead, p.pseudo-head):first-child { margin-top: 0; }

/* A photo that is its band's only content, placed without a wrapping paragraph
   (the slideshow pages), still had the band's padding: ivory slivers above and
   below. Section 17 covers the wrapped case. */
body:not(.home) .prose > section.panel:has(> img.lead:only-child) { padding-block: 0; }
body:not(.home) .prose > section.panel:has(> img.lead:only-child) > img.lead { margin-block: 0; }

/* Archive lists (tag, author, category): as CSS columns, a title that wrapped put
   the two columns' hairlines out of step at tablet width. A two-column grid gives
   each row one height. One column on phones, as before. The doubled class
   (0-5-3) beats section 16's ul.linklist rules (0-4-3). */
body:not(.home) .prose > section.panel > ul.linklist.linklist { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); columns: auto; column-gap: clamp(24px, 3vw, 48px); }
@media (max-width: 720px) {
  body:not(.home) .prose > section.panel > ul.linklist.linklist { grid-template-columns: minmax(0, 1fr); }
}

/* The office photo on the location page (sign lettering at the top): the shared
   15% framing cut the top of the blue eye logo off at desktop width. */
body:not(.home) .prose > section.panel img.wide.lead[src*="876cabff-IMG_0481"] { object-position: 50% 6%; }

/* Registration form checkbox groups flowed like running text (ragged, 29px gaps)
   because ".appt-form fieldset.field .opts" (0-3-1, display:flex) beat the grid
   rule (0-3-0). On phones every checkbox also carried the 44px input minimum, so
   rows ran 86px apart. The whole label is the 44px target instead. */
.appt-form.gf-form fieldset.field .opts.many { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 0 18px; align-items: start; min-height: 0; }
.appt-form.gf-form fieldset.field .opt { display: flex; align-items: center; gap: 8px; min-height: 44px; }
.appt-form.gf-form fieldset.field .opt input[type="checkbox"] { min-height: 0; margin: 0 2px; }

/* Phone chrome. The open menu sat inside the header's 22px inset, so page text
   showed at its left edge: it now spans the screen (body clips overflow-x).
   Breadcrumb links were 39px tall; 14.5px of padding makes 44. The phone number's
   44px tap box put 30px between it and the address against 4px between the
   address's lines: the box's surplus below the text is cancelled. */
@media (max-width: 1100px) {
  .site-header .primary-nav.primary-nav { left: calc((100% - 100vw) / 2); right: calc((100% - 100vw) / 2); }
  .hero .crumbs ol > li > a { padding-block: 14.5px; }
}
@media (max-width: 640px) {
  .topbar .topbar-facts > a { margin-bottom: -11px; }
}
/* The one heading that is a bold lead-in plus a whole sentence (build:
   h4.lead-in-head, Are You Ignoring Your Dry Eyes?) ran 296px tall at title
   scale. Sub-head scale in a readable column, as p.pseudo-head. 0-5-3. */
body:not(.home) .prose > section.panel > h4.lead-in-head {
  font-size: clamp(1.2rem, 1.7vw, 1.5rem); line-height: 1.35;
  max-width: 60ch; margin-inline: auto;
}
/* Visit band: the owner's rule is "centre every section head, except Meet the
   Doctor and the hero", and "Located in the same building as Wayback Burgers" sat
   left in the first of three columns. The lead (eyebrow, head, address, buttons)
   now centres across the band above the two lists at every width, as it already
   did below 960px. The lists' labels stay left, like every card label (section 4).
   Weights 0-2-0 / 0-2-1 beat .visit-inner / .visit-lead (0-1-0). */
.visit-band .visit-inner { grid-template-columns: 1fr 1fr; }
.visit-band .visit-lead { grid-column: 1 / -1; text-align: center; }
.visit-band .visit-lead h2 { max-width: 30ch; margin-inline: auto; }
.visit-band .visit-lead .btn-row { justify-content: center; }
@media (max-width: 640px) { .visit-band .visit-inner { grid-template-columns: 1fr; } }
/* Reviews: a card lifts 3px on hover, and the rail (overflow auto) clipped its top
   edge. 6px of room above, cancelled outside. Same weight as section 18's rail rule,
   different properties. */
body.home .prose > section.panel.sec-reviews .reviews { padding-top: 6px; margin-top: -6px; }
/* Contact card links on phones: 12px padding made a 43px target. 0-2-2 > 0-1-3. */
@media (max-width: 1100px) { .contact-locate .cl-card li > a { padding-block: 13px; } }
/* "Visit us" eyebrow: gold on its pill measured 3.04:1 at 12px (needs 4.5). Warm
   white, as the hero's eyebrow; "Wayback Burgers" keeps the gold. 0-3-0 > 0-2-0. */
.visit-band .visit-lead .eyebrow { color: var(--warm-white); }
