/* ==========================================================================
   Arch House Australia - components
   ========================================================================== */

/* --------------------------------------------------------------------------
   Header
   -------------------------------------------------------------------------- */
/* No backdrop-filter here, deliberately. An element with backdrop-filter
   becomes the containing block for its position:fixed descendants, which
   trapped the off-canvas mobile nav inside the 77px header instead of letting
   it fill the viewport. A blurred translucent bar is also a look this
   brand does not want, so the opaque ground is correct twice over. */
.site-header {
  position: sticky; top: 0; z-index: 60;
  background: var(--plaster);
  border-bottom: 1px solid transparent;
  transition: border-color .3s var(--ease);
}
.site-header.is-stuck { border-bottom-color: var(--sand); }
/* The logo is 880x460, so a width-driven size of 158px rendered 82.6px tall
   inside a 76px min-height header: it could not fit, and it touched the ribbon
   above it. Drive the HEIGHT instead and let the row grow to content plus
   padding, so the mark can never collide with the edges at any viewport. */
.header-row {
  display: flex; align-items: center; gap: var(--sp-4);
  padding-block: 1.15rem;
}
.brand { flex: 0 0 auto; line-height: 0; }
.brand img { height: clamp(42px, 4.4vw, 56px); width: auto; }

.site-nav { margin-left: auto; }
.site-nav ul {
  display: flex; align-items: center; gap: clamp(.9rem, 1.9vw, 1.9rem);
  list-style: none; margin: 0; padding: 0;
}
.site-nav li { margin: 0; }
.site-nav a {
  text-decoration: none;
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: .01em;
  color: var(--espresso-soft);
  padding-block: .4rem;
  position: relative;
  transition: color .25s var(--ease);
}
.site-nav a::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0;
  height: 1px; background: var(--oak);
  transform: scaleX(0); transform-origin: left;
  transition: transform .35s var(--ease);
}
.site-nav a:hover { color: var(--espresso); }
.site-nav a:hover::after,
.site-nav a[aria-current="page"]::after { transform: scaleX(1); }
.site-nav a[aria-current="page"] { color: var(--espresso); }

.header-cta { display: flex; align-items: center; gap: var(--sp-3); }
.header-phone {
  text-decoration: none; font-size: var(--step--1); font-weight: 600;
  white-space: nowrap;
  display: inline-block; padding-block: .2rem;  /* 23px -> 29px target */
}
.header-phone:hover { text-decoration: underline; }

.nav-toggle, .nav-close { display: none; }

@media (max-width: 60rem) {
  .nav-toggle {
    display: inline-flex; align-items: center; gap: .5rem;
    margin-left: auto;
    background: none; border: 1px solid var(--sand);
    border-radius: var(--r-sm);
    padding: .5rem .8rem; cursor: pointer;
    font-size: var(--step--1); font-weight: 600;
  }
  .site-nav {
    position: fixed; inset: 0 0 0 auto;
    width: min(21rem, 84vw);
    background: var(--gesso);
    border-left: 1px solid var(--sand);
    padding: 5.5rem var(--sp-4) var(--sp-4);
    box-shadow: var(--sh-3);
    overflow-y: auto;
    /* Closed state does NOT rely on transform alone. visibility:hidden takes
       the panel out of the accessibility tree and the tab order, so its links
       are not focusable while the menu is shut. A purely translated panel is
       off-screen but still reachable by keyboard, which a11y-gate treats as a
       failure and which strands a keyboard user in an invisible menu. */
    transform: translateX(101%);
    visibility: hidden;
    pointer-events: none;
    transition: transform .4s var(--ease), visibility 0s linear .4s;
  }
  .site-nav.is-open {
    transform: none;
    visibility: visible;
    pointer-events: auto;
    transition: transform .4s var(--ease), visibility 0s;
  }
  .site-nav ul { flex-direction: column; align-items: stretch; gap: 0; }
  .site-nav li + li { border-top: 1px solid var(--sand-dim); }
  .site-nav a { display: block; padding: .95rem 0; font-size: var(--step-0); }
  .site-nav a::after { display: none; }
  .nav-close {
    display: block; position: absolute; top: 1.15rem; right: 1.15rem;
    background: none; border: 0; cursor: pointer;
    font-size: 1.8rem; line-height: 1; padding: .2rem .5rem;
  }
  .header-cta .btn { display: none; }
}

/* --------------------------------------------------------------------------
   Buttons. One reserved accent: walnut, CTA only.
   -------------------------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: .55rem;
  padding: .85rem 1.5rem;
  border-radius: var(--r-sm);
  border: 1px solid transparent;
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: .01em;
  text-decoration: none;
  cursor: pointer;
  transition: background-color .25s var(--ease), color .25s var(--ease),
              border-color .25s var(--ease), transform .25s var(--ease);
}
.btn:active { transform: translateY(1px); }

.btn-primary { background: var(--walnut); color: var(--gesso); }
.btn-primary:hover { background: var(--walnut-deep); }

.btn-ghost {
  background: transparent; color: var(--espresso);
  border-color: var(--espresso);
}
.btn-ghost:hover { background: var(--espresso); color: var(--gesso); }

.band-dark .btn-ghost { color: var(--gesso); border-color: var(--sand); }
.band-dark .btn-ghost:hover { background: var(--gesso); color: var(--espresso); }

.btn-lg { padding: 1.05rem 1.9rem; font-size: var(--step-0); }

.link-arrow {
  display: inline-flex; align-items: center; gap: .45rem;
  font-weight: 600; font-size: var(--step--1);
  text-decoration: none; color: var(--walnut);
  padding-block: .2rem;  /* 23px -> 29px target */
}
.link-arrow span { transition: transform .3s var(--ease); }
.link-arrow:hover span { transform: translateX(4px); }
.band-dark .link-arrow { color: var(--sand); }

/* --------------------------------------------------------------------------
   THE RIPPLE PORTAL - the signature.
   His 3-piece hollow arch, rendered as interface: an arch-topped frame with
   two concentric hairline outlines stepped out 10px and 20px. On hover the
   outlines nest apart, so the product demonstrates itself. Transform only.
   -------------------------------------------------------------------------- */
.portal { position: relative; isolation: isolate; }
.portal img {
  border-radius: var(--arch);
  width: 100%;
  object-fit: cover;
  position: relative; z-index: 1;
}
.portal::before,
.portal::after {
  content: "";
  position: absolute;
  border: 1px solid var(--sand);
  border-radius: var(--arch);
  pointer-events: none;
  transition: transform var(--dur) var(--ease), opacity var(--dur) var(--ease);
}
.portal::before { inset: -10px -10px 0; }
.portal::after  { inset: -20px -20px 0; opacity: .6; }
.portal:hover::before,
a:hover > .portal::before { transform: translate(-4px, -4px) scale(1.006); }
.portal:hover::after,
a:hover > .portal::after  { transform: translate(-8px, -8px) scale(1.012); }

/* Rectangular frame = commercial joinery. Portal = event props.
   The two frame languages are how one home page routes two audiences. */
.framed { position: relative; }
.framed img { border-radius: var(--r-sm); width: 100%; object-fit: cover; }
.framed::before {
  content: ""; position: absolute; inset: -10px;
  border: 1px solid var(--sand); border-radius: var(--r-sm);
  pointer-events: none;
  transition: transform var(--dur) var(--ease);
}
.framed:hover::before,
a:hover > .framed::before { transform: translate(-4px, -4px); }

/* --------------------------------------------------------------------------
   Hero
   -------------------------------------------------------------------------- */
.hero { padding-block: clamp(1.8rem, 1.2rem + 2.6vw, 3.2rem) var(--sp-7); }
.hero-head { margin-bottom: var(--sp-4); }
/* max-width in em, NOT ch. `ch` on the wrapper resolves against the body
   font and collapses the measure to a fraction of the intended width. em on
   the heading itself resolves against the display font and scales with the
   clamp, which is the behaviour we actually want. */
.hero h1 { font-size: var(--step-5); max-width: 13em; }
.hero .lede { max-width: 52ch; }
.hero-actions {
  display: flex; flex-wrap: wrap; gap: var(--sp-3);
  margin-top: var(--sp-4);
}
.hero-media {
  display: grid; gap: var(--sp-5);
  grid-template-columns: 1.32fr 1fr;
  align-items: end;
  margin-top: var(--sp-6);
}
/* Crop the hero pair so the fold shows the work, not the ceiling above it.
   aspect-ratio is set on both, so neither can shift layout while decoding. */
.hero-media .framed img { aspect-ratio: 5 / 4; object-fit: cover; object-position: 50% 62%; }
.hero-media .portal img { aspect-ratio: 3 / 4; object-fit: cover; object-position: 50% 40%; }
/* Column-ratio variants live HERE, as classes, never as inline styles: an
   inline grid-template-columns beats the mobile collapse below and pins two
   columns onto a 360px screen. Class + source order keeps the collapse. */
.hero-media-even { grid-template-columns: 1fr 1fr; align-items: start; }
.hero-media-swap { grid-template-columns: 1fr 1.1fr; }
@media (max-width: 54rem) {
  .hero-media,
  .hero-media-even,
  .hero-media-swap { grid-template-columns: 1fr; gap: var(--sp-6); }
  .hero-media .portal { max-width: 20rem; }
}
.media-cap {
  margin-top: var(--sp-3);
  font-size: var(--step--2);
  letter-spacing: var(--tr-caps);
  text-transform: uppercase;
  font-weight: 600;
  color: var(--espresso-mute);
}

/* --------------------------------------------------------------------------
   The two doors - the audience fork
   -------------------------------------------------------------------------- */
.doors { display: grid; gap: var(--sp-5); grid-template-columns: repeat(auto-fit, minmax(min(20rem,100%), 1fr)); }
.door {
  display: block; text-decoration: none;
  background: var(--gesso);
  border: 1px solid var(--sand);
  border-radius: var(--r-md) var(--r-md) var(--r-sm) var(--r-sm);
  padding: var(--sp-5);
  position: relative; overflow: hidden;
  transition: border-color .3s var(--ease), box-shadow .3s var(--ease),
              transform .3s var(--ease);
}
.door::before {
  content: ""; position: absolute; inset: 0 0 auto; height: 9px;
  background-image: var(--flute); background-size: 14px 100%;
  background-color: var(--sand-dim);
}
.door:hover { border-color: var(--oak); box-shadow: var(--sh-2); transform: translateY(-3px); }
.door h3 { margin-bottom: var(--sp-2); font-size: var(--step-2); }
.door p { color: var(--espresso-soft); font-size: var(--step--1); }
.door-list {
  list-style: none; padding: 0; margin: var(--sp-3) 0 var(--sp-4);
  font-size: var(--step--1); color: var(--espresso-soft);
}
.door-list li { padding-left: 1.1rem; position: relative; }
.door-list li::before {
  content: ""; position: absolute; left: 0; top: .62em;
  width: 7px; height: 4px;
  border: 1px solid var(--oak); border-bottom: 0;
  border-radius: var(--arch-full);
}

/* --------------------------------------------------------------------------
   Capability tiles
   -------------------------------------------------------------------------- */
.cap {
  background: var(--gesso);
  border: 1px solid var(--sand);
  border-radius: var(--r-md);
  padding: var(--sp-4);
  transition: border-color .3s var(--ease), transform .3s var(--ease);
}
.cap:hover { border-color: var(--oak); transform: translateY(-2px); }
.cap h3 { font-size: var(--step-1); margin-bottom: var(--sp-2); }
.cap p { font-size: var(--step--1); color: var(--espresso-soft); }

/* Photo tile inside a capability grid. Full row on narrow grids (1/-1 never
   creates an implicit overflow track the way span 2 does on a one-column
   grid), span 2 of the pinned 3 tracks on desktop. */
.cap-media { grid-column: 1 / -1; padding: 0; border: 0; background: none; }
.cap-media:hover { transform: none; }
@media (min-width: 64rem) {
  .cap-media { grid-column: span 2; }
}

/* --------------------------------------------------------------------------
   Process steps
   -------------------------------------------------------------------------- */
.steps { counter-reset: step; }
.step { position: relative; padding-top: var(--sp-4); }
.step::before {
  counter-increment: step;
  content: "0" counter(step);
  font-family: var(--font-display);
  font-size: var(--step-2);
  color: var(--sand);
  display: block; margin-bottom: var(--sp-2);
}
.step::after {
  content: ""; position: absolute; inset: 0 0 auto; height: 1px;
  background: var(--sand);
}
.step h3 { font-size: var(--step-1); margin-bottom: var(--sp-2); }
.step p { font-size: var(--step--1); color: var(--espresso-soft); }

/* --------------------------------------------------------------------------
   Locations
   -------------------------------------------------------------------------- */
.loc {
  border-top: 1px solid rgba(217,203,184,.28);
  padding-top: var(--sp-3);
}
.loc h3 {
  font-family: var(--font-body);
  font-size: var(--step--2);
  letter-spacing: var(--tr-caps);
  text-transform: uppercase;
  font-weight: 600;
  color: var(--sand);
  margin-bottom: var(--sp-2);
}
.loc p { font-size: var(--step--1); line-height: 1.5; color: var(--plaster); }

/* --------------------------------------------------------------------------
   Projects grid. Frame languages interleave deliberately: proof that one
   workshop makes both the boardroom desk and the wedding arch.
   -------------------------------------------------------------------------- */
.proj-grid {
  display: grid; gap: var(--sp-6) var(--sp-5);
  grid-template-columns: repeat(auto-fit, minmax(min(17rem,100%), 1fr));
}
.proj { display: block; text-decoration: none; }
.proj h3 { font-size: var(--step-1); margin-top: var(--sp-4); }
.proj p { font-size: var(--step--1); color: var(--espresso-soft); margin-top: var(--sp-1); }
.proj .media-cap { margin-top: var(--sp-2); }

/* --------------------------------------------------------------------------
   Full-bleed showpiece band. Reserved for the one landscape photograph that
   carries the desk, the arch motif and a real install in a single frame.
   -------------------------------------------------------------------------- */
.showpiece { position: relative; }
.showpiece img {
  /* The source is 1289px wide. Full-bleed on a 1920 monitor stretched it to
     1.5x and it went visibly soft, which is the first thing anyone notices on
     a section-width photograph. Capped to the content wrap so the browser can
     always serve a variant at or above the displayed size: no upscale at any
     viewport, and the caption below now aligns with the image edge. */
  width: min(100%, var(--wrap));
  margin-inline: auto;
  aspect-ratio: 2 / 1;
  object-fit: cover;
  object-position: 50% 42%;
  display: block;
  border-radius: var(--r-sm);
}
@media (max-width: 46rem) {
  .showpiece img { aspect-ratio: 5 / 4; border-radius: 0; }
}
.showpiece-cap {
  border-top: 1px solid var(--sand);
  padding-top: var(--sp-3);
  margin-top: var(--sp-3);
  display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-5);
  justify-content: space-between; align-items: baseline;
}
.showpiece-cap p { font-size: var(--step--1); color: var(--espresso-soft); max-width: 54ch; }
.showpiece-cap span {
  font-size: var(--step--2); letter-spacing: var(--tr-caps);
  text-transform: uppercase; font-weight: 600; color: var(--espresso-mute);
  white-space: nowrap;
}

/* --------------------------------------------------------------------------
   Gallery. The workhorse for showing a lot of work without turning the page
   into a contact sheet. Square frames read commercial, arch frames read
   events, and the two interleave so one grid proves one workshop makes both.
   -------------------------------------------------------------------------- */
.gallery {
  /* Exact 3 columns from tablet up. Every gallery on this site carries a
     multiple of three, so no row is ever left with one or two orphan tiles
     beside empty space. Three columns also make each tile roughly 390px at
     1440 instead of 259px, which the photographs need. */
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-5) var(--sp-4);
}
@media (min-width: 40rem) {
  .gallery { grid-template-columns: repeat(3, 1fr); }
}
.gallery figure { margin: 0; position: relative; }
.gallery img {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border-radius: var(--r-sm);
  background: var(--limewash);
}
.gallery .is-arch img { border-radius: var(--arch); }


/* Hairline frame echoing the hero. Transform only, so no layout shift. */
.gallery figure::before {
  content: ""; position: absolute; inset: -8px;
  border: 1px solid var(--sand); border-radius: var(--r-sm);
  pointer-events: none; opacity: 0;
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.gallery .is-arch::before { border-radius: var(--arch); inset: -8px -8px 0; }
.gallery figure:hover::before { opacity: 1; transform: translate(-3px, -3px); }

.gallery figcaption {
  margin-top: var(--sp-2);
  font-size: var(--step--2);
  letter-spacing: var(--tr-caps);
  text-transform: uppercase;
  font-weight: 600;
  color: var(--espresso-mute);
}
.band-dark .gallery figcaption { color: var(--sand); }

/* Photo slot: where his real photography belongs. Honest, not a fake image. */
.slot {
  position: relative;
  aspect-ratio: 4 / 5;
  background-color: var(--limewash);
  background-image: var(--flute);
  background-size: 18px 100%;
  border: 1px dashed var(--oak);
  display: grid; place-content: center; text-align: center;
  padding: var(--sp-4);
  color: var(--espresso-mute);
}
.slot.is-arch { border-radius: var(--arch); }
.slot.is-wide { aspect-ratio: 16 / 10; }
.slot span {
  font-size: var(--step--2); letter-spacing: var(--tr-caps);
  text-transform: uppercase; font-weight: 600;
  background: var(--gesso); padding: .5rem .8rem; border-radius: var(--r-sm);
}

/* --------------------------------------------------------------------------
   Facts strip
   -------------------------------------------------------------------------- */
.facts { display: grid; gap: var(--sp-4); grid-template-columns: repeat(auto-fit, minmax(min(11rem,100%), 1fr)); }
.fact { text-align: center; }
.fact b {
  display: block; font-family: var(--font-display);
  font-size: var(--step-3); font-weight: 400; line-height: 1;
}
.fact span {
  display: block; margin-top: var(--sp-2);
  font-size: var(--step--2); letter-spacing: var(--tr-caps);
  text-transform: uppercase; color: var(--espresso-mute);
}
.band-dark .fact span { color: var(--sand); }

/* --------------------------------------------------------------------------
   Forms
   -------------------------------------------------------------------------- */
/* Contact page split: form beside the direct-contact aside, stacked on
   anything narrower than a laptop. */
.contact-split { grid-template-columns: 1.25fr 1fr; gap: var(--sp-7); }
@media (max-width: 60rem) {
  .contact-split { grid-template-columns: 1fr; gap: var(--sp-6); }
}

.form { display: grid; gap: var(--sp-3); }
.field { display: grid; gap: .4rem; }
.field label { font-size: var(--step--1); font-weight: 600; }
.field .hint { font-size: var(--step--2); color: var(--espresso-mute); font-weight: 400; }
.field input, .field select, .field textarea {
  width: 100%;
  padding: .8rem .9rem;
  background: var(--gesso);
  border: 1px solid var(--oak);
  border-radius: var(--r-sm);
  font-size: var(--step-0);
  transition: border-color .2s var(--ease), box-shadow .2s var(--ease);
}
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none;
  border-color: var(--walnut);
  box-shadow: 0 0 0 3px rgba(91,58,38,.14);
}
.field textarea { min-height: 8rem; resize: vertical; }
.field-row { display: grid; gap: var(--sp-3); grid-template-columns: repeat(auto-fit, minmax(min(13rem,100%), 1fr)); }
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* --------------------------------------------------------------------------
   Footer
   -------------------------------------------------------------------------- */
.site-footer { background: var(--espresso); color: var(--plaster); }
.site-footer a { color: var(--plaster); }
.footer-top {
  display: grid; gap: var(--sp-5);
  grid-template-columns: repeat(auto-fit, minmax(min(14rem,100%), 1fr));
  padding-block: var(--sp-7) var(--sp-5);
}
.footer-brand img { width: 150px; margin-bottom: var(--sp-3); }
.footer-col h2 {
  font-family: var(--font-body);
  font-size: var(--step--2); letter-spacing: var(--tr-caps);
  text-transform: uppercase; color: var(--sand);
  margin-bottom: var(--sp-3);
}
.footer-col ul { list-style: none; padding: 0; margin: 0; }
.footer-col li + li { margin-top: var(--sp-1); }
.footer-col a {
  text-decoration: none; font-size: var(--step--1); opacity: .88;
  display: inline-block; padding-block: .3rem;  /* 18px text -> 27px target, WCAG 2.2 SC 2.5.8 */
}
.footer-col a:hover { opacity: 1; text-decoration: underline; }

/* Tap targets. Footer links rendered 32-33px tall and the Pixelate credit 28px,
   under the 44px house minimum, on every page. Inline-block plus padding gives
   the anchor a real box without moving the visual rhythm. */
.footer-col a, .footer-trust a {
  display: inline-block;
  min-height: 44px;
  line-height: 44px;
  padding-inline: 2px;
}

/* The rest of the sub-44px targets, measured under true 390x844x3 mobile
   emulation (a plain window resize clamps at 502px in this environment and
   reports the wrong numbers). inline-flex rather than a height, so the box
   grows around the existing type instead of moving the header rhythm.
   .link-arrow is sized because it always sits alone in its own paragraph as a
   CTA; genuinely inline links inside a sentence are exempt under WCAG 2.5.8. */
.brand,
.header-phone,
.link-arrow {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}
.nav-toggle,
.nav-close {
  min-height: 44px;
  min-width: 44px;
}

/* Phone and email links are always an action, never decoration, so they always
   get a real target. Verified first that none of them sit inline inside a
   sentence, where growing the line box would be wrong. */
a[href^="tel:"],
a[href^="mailto:"] {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

.footer-trust {
  border-top: 1px solid rgba(217,203,184,.22);
  padding-block: var(--sp-4);
  font-size: var(--step--2);
  color: var(--sand);
  display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-4);
  justify-content: space-between; align-items: center;
}
/* The Pixelate credit measured 45x17, under the 24px WCAG 2.2 target minimum. */
.footer-trust a {
  color: var(--sand);
  display: inline-block;
  padding-block: .25rem;
}

/* --------------------------------------------------------------------------
   Sticky mobile call bar
   -------------------------------------------------------------------------- */
.call-bar { display: none; }
@media (max-width: 46rem) {
  .call-bar {
    display: grid; grid-template-columns: 1fr 1fr;
    position: fixed; inset: auto 0 0; z-index: 70;
    background: var(--gesso);
    border-top: 1px solid var(--sand);
    box-shadow: 0 -4px 18px rgba(43,33,24,.10);
  }
  .call-bar a {
    padding: .95rem .6rem; text-align: center; text-decoration: none;
    font-size: var(--step--1); font-weight: 600; white-space: nowrap;
  }
  .call-bar a + a { background: var(--walnut); color: var(--gesso); }
  body { padding-bottom: 3.6rem; }
}

/* --------------------------------------------------------------------------
   Concept notice bar.
   -------------------------------------------------------------------------- */
.demo-note {
  background: var(--walnut); color: var(--gesso);
  font-size: var(--step--2); text-align: center;
  padding: .5rem var(--sp-3);
}
.demo-note a { color: var(--gesso); }

/* --------------------------------------------------------------------------
   Utilities. These exist so the markup carries no style= attributes: the
   preship gate rejects them, and with none present the CSP can drop
   'unsafe-inline' from style-src instead of keeping the demo concession.
   -------------------------------------------------------------------------- */
.mt-3 { margin-top: var(--sp-3); }
.mt-4 { margin-top: var(--sp-4); }
.mt-5 { margin-top: var(--sp-5); }
.mt-6 { margin-top: var(--sp-6); }
.tc { text-align: center; }
.jc-center { justify-content: center; }
.gap-3 { gap: var(--sp-3); }
.gap-4 { gap: var(--sp-4); }
.pair { gap: var(--sp-7); align-items: center; }
.pair-top { align-items: start; }
.h-sm { font-size: var(--step-2); }
.note { font-size: var(--step--1); color: var(--espresso-soft); }
.note-plain { font-size: var(--step--1); }
.note-mute { font-size: var(--step--1); color: var(--espresso-mute); }
.note-mute-xs { font-size: var(--step--2); color: var(--espresso-mute); }
.on-dark { color: var(--plaster); }
.on-dark-mute { color: var(--sand); }

/* Dark-band body copy. --espresso-soft on --espresso measures 1.79:1, well under
   the 4.5:1 WCAG 2.2 AA floor, so a lede dropped into a dark band rendered close
   to unreadable. Six of them shipped that way on 18 August. Fixing it on the band
   rather than per element means the next dark section cannot reintroduce it. */
.band-dark .lede,
.band-dark p { color: var(--sand); }
.band-dark h1, .band-dark h2, .band-dark h3 { color: var(--plaster); }
.foot-blurb { font-size: var(--step--1); color: var(--sand); max-width: 26ch; }
.foot-hours { font-size: var(--step--2); color: var(--sand); }

/* A text column left alone after its image pair was removed will run the full
   77rem wrap, which measured 110+ characters a line. 62ch is a readable measure. */
.measure { max-width: 62ch; }
