/* ============================================================
   ARLO — Site-wide furniture
   Footer, paper grain, scroll progress, and the live open/closed
   badge. Loaded on every page.
   ============================================================ */

/* ---------- Paper grain ----------
   A barely-there film of SVG noise over the whole page warms the
   flat surfaces — the same warmth the paper textures give the map
   and the ticket. Purely decorative, never intercepts input, and
   sits just below the modals so dialogs stay crisp. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 1990; /* below every modal (2000/2500/3000), above the page content */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)' opacity='0.55'/%3E%3C/svg%3E");
  background-size: 180px 180px;
  opacity: 0.045;
  pointer-events: none;
}

/* ---------- Scroll progress ----------
   A thin terracotta line across the very top that fills as the page
   scrolls. Purely decorative (aria-hidden), transform-based so it
   costs almost nothing. */
.site-progress {
  position: fixed;
  top: 0;
  inset-inline: 0;
  height: 2px;
  z-index: 300;
  pointer-events: none;
}
.site-progress span {
  display: block;
  width: 100%;
  height: 100%;
  /* The tinted terracotta, because the line rides over the dark
     masthead — the deeper roast reads as a smudge there. */
  background: var(--color-accent-soft);
  transform: scaleX(0);
  transform-origin: left;
  will-change: transform;
}

/* ---------- Page loader ----------
   Opens every page on the masthead's night — espresso ground, warm bloom,
   steam, drifting beans and one eased pass of determinate progress
   (--loader-dur). Only the percentage needs a script (js/site.js);
   the veil, bar, steam and dots are CSS, so the page still opens without
   JavaScript.
   The veil starts hidden and only the keyframes reveal it, so a visitor can
   never be stranded behind a dark screen. */
.page-loader {
  position: fixed;
  inset: 0;
  z-index: 9500; /* above the custom scrollbar (9000) */
  display: grid;
  place-items: center;
  overflow: hidden;
  isolation: isolate;
  color: var(--color-paper-dim);
  /* The masthead's night band: fine diamond weave, a warm bloom from the
     reading end, a deeper terracotta rise from the floor, and espresso
     falling into near-black. */
  background-image:
    url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='28' height='28' viewBox='0 0 28 28'><path d='M0 28 28 0' stroke='%23d9a77e' stroke-opacity='0.09'/><path d='M0 0 28 28' stroke='%23d9a77e' stroke-opacity='0.045'/><circle cx='7' cy='21' r='0.9' fill='%23fdf9f2' fill-opacity='0.13'/><ellipse cx='21' cy='7' rx='1.7' ry='1.1' transform='rotate(-32 21 7)' fill='%23d9a77e' fill-opacity='0.15'/></svg>"),
    radial-gradient(85% 240% at 100% 0%, rgba(217, 167, 126, 0.2), transparent 62%),
    radial-gradient(70% 200% at 0% 100%, rgba(154, 91, 50, 0.34), transparent 60%),
    linear-gradient(180deg, #2b2116 0%, #20170f 58%, #150e08 100%);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  /* The bar is full at the 75% keyframe, so progress takes the first three
     quarters of --loader-dur and the lift the last quarter — the length
     itself, which every entrance animation on the page waits on (the gate
     lives in js/site.js).
     Eased, so the veil settles off the page instead of cutting away.
     Promoted to its own layer: the veil is a full-viewport wash of
     gradients and a weave, and fading it as a composited layer costs a
     blend per frame, where an unpromoted fade would repaint the whole
     viewport for the length of the lift. The node is dropped once it is
     out of sight (js/site.js), so the layer is short-lived. */
  will-change: opacity;
  animation: page-loader-play var(--loader-dur) var(--ease-out) both;
}

@keyframes page-loader-play {
  0%      { opacity: 1; visibility: visible; }
  75%     { opacity: 1; visibility: visible; } /* 2.55s — the bar is full */
  100%    { opacity: 0; visibility: hidden; }
}

/* ---- Ambient backdrop (decorative, behind the content) ---- */
.page-loader__bg {
  position: absolute;
  inset: 0;
  z-index: -1; /* above the veil's own background, below the content */
  overflow: hidden;
  pointer-events: none;
}

.page-loader__glow {
  position: absolute;
  top: 50%;
  left: 50%;
  width: min(130vw, 46rem);
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  background: radial-gradient(circle, rgba(154, 91, 50, 0.3), rgba(154, 91, 50, 0) 62%);
  /* Painted once and left alone. This bloom used to breathe as a
     promoted layer, but a bloom this large animating underneath a
     full-viewport veil is pure fill rate — the one cost a modest GPU
     feels most, exactly while the veil is also being faded. The light
     is still now: the loader reads as one steady room. */
}

/* Rising steam — the footer's curl, on a loader timescale */
.page-loader__steam {
  position: absolute;
  bottom: 4%;
  width: clamp(2.1rem, 5.6vw, 3.5rem);
  height: clamp(3rem, 7.6vw, 5.2rem);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='72' viewBox='0 0 48 72'%3E%3Cpath d='M24 70 C 8 60, 40 52, 24 42 C 8 32, 40 24, 24 14 C 18 9, 19 6, 24 2' fill='none' stroke='%23d9a77e' stroke-width='3' stroke-linecap='round' opacity='0.8'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-size: contain;
  background-position: center;
  opacity: 0;
  /* Loops are short next to the veil, so a curl lives out a whole rise and
     fade every time instead of being cut off halfway up. */
  animation: page-loader-steam 1.4s var(--ease-in-out) infinite;
}
.page-loader__steam--1 { inset-inline-start: 33%; animation-delay: 0s; }
.page-loader__steam--2 { inset-inline-start: 41%; animation-delay: 0.26s; }
.page-loader__steam--3 { inset-inline-start: 49%; animation-delay: 0.52s; }
.page-loader__steam--4 { inset-inline-start: 57%; animation-delay: 0.78s; }
.page-loader__steam--5 { inset-inline-start: 65%; animation-delay: 1.04s; }
@keyframes page-loader-steam {
  0%   { opacity: 0;    transform: translate3d(0, 1.4rem, 0) scale(0.9); }
  35%  { opacity: 0.85; }
  70%  { opacity: 0.48; transform: translate3d(0.3rem, -1.6rem, 0) scale(1.04); }
  100% { opacity: 0;    transform: translate3d(-0.3rem, -3.6rem, 0) scale(1.1); }
}

/* Drifting beans — the footer's bean, lifted at loader speed */
.page-loader__bean {
  position: absolute;
  width: clamp(0.7rem, 1.55vw, 1rem);
  height: clamp(1rem, 2.2vw, 1.4rem);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='20' viewBox='0 0 14 20'%3E%3Cellipse cx='7' cy='10' rx='6' ry='9' fill='%23d9a77e'/%3E%3Cpath d='M7 1.5 C 3 5, 3 15, 7 18.5' stroke='%232b2116' stroke-width='1.4' fill='none' stroke-linecap='round' opacity='0.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-size: contain;
  opacity: 0;
  animation: page-loader-bean 1.35s linear infinite;
}
.page-loader__bean--1 { inset-inline-start: 12%; bottom: 18%; animation-delay: 0.04s; animation-duration: 1.3s; }
.page-loader__bean--2 { inset-inline-start: 26%; bottom: 30%; animation-delay: 0.3s; }
.page-loader__bean--3 { inset-inline-start: 64%; bottom: 24%; animation-delay: 0.55s; animation-duration: 1.4s; }
.page-loader__bean--4 { inset-inline-start: 80%; bottom: 34%; animation-delay: 0.8s; animation-duration: 1.25s; }
.page-loader__bean--5 { inset-inline-start: 45%; bottom: 12%; animation-delay: 1.05s; animation-duration: 1.45s; }
.page-loader__bean--6 { inset-inline-start: 38%; bottom: 44%; animation-delay: 1.3s; animation-duration: 1.4s; }
.page-loader__bean--7 { inset-inline-start: 92%; bottom: 28%; animation-delay: 1.55s; animation-duration: 1.3s; }
.page-loader__bean--8 { inset-inline-start: 57%; bottom: 46%; animation-delay: 1.8s; animation-duration: 1.45s; }
@keyframes page-loader-bean {
  0%   { opacity: 0;    transform: translate3d(0, 0, 0) rotate(0deg); }
  18%  { opacity: 0.95; }
  70%  { opacity: 0.7; }
  100% { opacity: 0;    transform: translate3d(0, -9rem, 0) rotate(300deg); }
}

/* ---- Content: mark, colophon, progress ---- */
.page-loader__stage {
  display: grid;
  justify-items: center;
  gap: clamp(0.6rem, 2vh, 0.95rem);
  padding-inline: clamp(1.25rem, 5vw, 2rem);
  text-align: center;
  /* The content leaves a beat before the veil does, so the last thing
     seen is the dark screen lifting off the page. */
  animation: page-loader-lift var(--loader-dur) var(--ease-out) both;
}
@keyframes page-loader-lift {
  0%      { opacity: 1; transform: none; }
  75%     { opacity: 1; transform: none; }
  100%    { opacity: 0; transform: translateY(-0.8rem); }
}

.page-loader__brand {
  display: flex;
  align-items: center;
  gap: clamp(0.7rem, 3vw, 1.5rem);
}

.page-loader__mark {
  font-family: var(--font-brand);
  font-size: clamp(2.5rem, 2rem + 3vw, 4.25rem);
  font-weight: 500;
  line-height: 1;
  letter-spacing: var(--wordmark-ls);
  text-transform: uppercase;
  color: var(--color-accent-ink);
  margin-inline-end: calc(-1 * var(--wordmark-ls));
  text-shadow: 0 0 2.6rem rgba(217, 167, 126, 0.5);
}

/* Hairlines that draw out of the wordmark towards each edge */
.page-loader__rule {
  width: clamp(1.25rem, 6vw, 4rem);
  height: 1px;
  background: linear-gradient(90deg, rgba(217, 167, 126, 0.9), transparent);
  transform: scaleX(0);
  transform-origin: left;
  animation: page-loader-rule 0.45s var(--ease-out) 0.08s both;
}
.page-loader__rule:last-child {
  background: linear-gradient(270deg, rgba(217, 167, 126, 0.9), transparent);
  transform-origin: right;
}
@keyframes page-loader-rule {
  to { transform: scaleX(1); }
}

.page-loader__kicker {
  font-family: var(--font-latin);
  font-size: clamp(0.6rem, 0.55rem + 0.25vw, 0.7rem);
  letter-spacing: 0.42em;
  text-transform: uppercase;
  color: rgba(217, 167, 126, 0.72);
}

/* ---- Progress: one determinate bar, lit along its own length ---- */
.page-loader__progress {
  width: min(78vw, 22rem);
  display: grid;
  gap: clamp(0.7rem, 2vh, 0.9rem);
  margin-top: clamp(1.4rem, 4vh, 2.25rem);
}

.page-loader__track {
  position: relative;
  display: block;
  height: 3px;
  border-radius: 999px;
  background: rgba(253, 249, 242, 0.13);
  /* The bar's halo is painted here, once, on the track. It used to sit on
     the fill, where it had to be redrawn as a blur on every frame the
     width grew — the single most expensive thing in the loader. */
  box-shadow:
    inset 0 0 0 1px rgba(217, 167, 126, 0.08),
    0 0 0.9rem rgba(217, 167, 126, 0.18);
}

/* Fills from the reading start (right) towards the left. Width, not a
   transform, so the bar's own gradient is never squashed by the scale.
   No shadow of its own, so growing the width only ever repaints the bar
   itself. */
.page-loader__fill {
  position: absolute;
  inset-inline-start: 0;
  top: 0;
  height: 100%;
  width: 0;
  border-radius: 999px;
  background: linear-gradient(90deg, #fdf9f2 0%, #d9a77e 42%, #9a5b32 100%);
}

/* Without JavaScript the bar still fills itself, once, over the same
   window the script drives it over — and on the same eased curve, so both
   walk up together and arrive together. */html:not(.js-loader) .page-loader__fill {
  animation: page-loader-fill 2.55s cubic-bezier(0.35, 0, 0.25, 1) both;
}
@keyframes page-loader-fill {
  to { width: 100%; }
}



.page-loader__readout {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  font-size: clamp(0.75rem, 0.7rem + 0.2vw, 0.8125rem);
  font-weight: 300;
  color: var(--color-paper-muted);
}

/* The digits need the script; without it the line stands alone.
   Tabular figures, so every digit occupies the same advance: the count
   walks up without the number shuffling its own width frame to frame as
   it passes 9, 10, 99, 100 — which is most of what makes a counter feel
   untidy. The percent sign is the number's baseline and never moves. */
.page-loader__percent {
  display: none;
  align-items: baseline;
  gap: 0.1rem;
  font-family: var(--font-num);
  font-variant-numeric: lining-nums tabular-nums;
  font-size: clamp(1rem, 0.85rem + 0.7vw, 1.3rem);
  font-weight: 500;
  color: var(--color-accent-soft);
}
html.js-loader .page-loader__percent {
  display: inline-flex;
}

.page-loader__dots {
  display: inline-flex;
  margin-inline-start: 0.1rem;
}
.page-loader__dots span {
  animation: page-loader-dot 0.95s var(--ease-in-out) infinite;
}
.page-loader__dots span:nth-child(2) { animation-delay: 0.12s; }
.page-loader__dots span:nth-child(3) { animation-delay: 0.24s; }
@keyframes page-loader-dot {
  0%, 100% { opacity: 0.15; }
  50%      { opacity: 1; }
}

.site-notice {
  position: fixed;
  inset: 0;
  z-index: 9600;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(0.75rem, 3vw, 2rem);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition:
    opacity var(--dur-med) var(--ease-out),
    visibility 0s linear 0.35s;
}
.site-notice.is-open {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition:
    opacity var(--dur-med) var(--ease-out),
    visibility 0s linear 0s;
}
.site-notice__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(16, 11, 7, 0.74);
}
.site-notice__card {
  position: relative;
  display: grid;
  justify-items: center;
  gap: clamp(0.7rem, 1.6vw, 1rem);
  width: min(94vw, 32rem);
  padding: clamp(1.5rem, 3.5vw, 2.25rem);
  border: 1px solid rgba(217, 167, 126, 0.2);
  border-radius: 14px;
  text-align: center;
  color: #efe4d0;
  background:
    radial-gradient(120% 110% at 0% 0%, rgba(154, 91, 50, 0.24), transparent 58%),
    linear-gradient(170deg, #241b13 0%, #150e08 100%);
  box-shadow: 0 1.75rem 4rem rgba(10, 6, 4, 0.6);
  opacity: 0;
  transform: translateY(0.75rem) scale(0.99);
  transition:
    opacity var(--dur-med) var(--ease-out),
    transform var(--dur-med) var(--ease-out);
}
.site-notice.is-open .site-notice__card {
  opacity: 1;
  transform: none;
}
.site-notice__card:focus-visible {
  outline: none;
}
.site-notice__kicker {
  font-size: clamp(0.6875rem, 0.625rem + 0.3125vw, 0.8125rem);
  font-weight: 500;
  color: var(--color-accent-soft);
}
.site-notice__title {
  font-size: clamp(1.25rem, 1rem + 1.2vw, 1.75rem);
  font-weight: 500;
  line-height: 1.5;
  text-wrap: balance;
  color: #f5ecdb;
}
.site-notice__text {
  font-size: clamp(0.9375rem, 0.875rem + 0.3125vw, 1.0625rem);
  font-weight: 300;
  line-height: 2;
  color: rgba(239, 228, 208, 0.76);
}
.site-notice__close {
  margin-top: clamp(0.35rem, 1.2vw, 0.6rem);
}
body.is-notice-open {
  overflow: hidden;
}

/* ---------- Footer ----------
   A night-coffeehouse band: deep espresso base, warm terracotta glow,
   slow rising steam, drifting coffee beans, and a shimmering hairline
   across the top edge. Every animation moves only transform/opacity,
   so it composites cheaply even on modest hardware; the backdrop is
   purely decorative (aria-hidden, pointer-events: none). */
.site-footer {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  color: var(--color-paper-dim);
  background:
    radial-gradient(130% 100% at 50% 120%, rgba(154, 91, 50, 0.3) 0%, rgba(154, 91, 50, 0) 58%),
    linear-gradient(180deg, #251b12 0%, #191109 100%);
}

/* Shimmering terracotta hairline — a soft light sweep crosses the top */
.site-footer::before {
  content: "";
  position: absolute;
  top: 0;
  inset-inline: 0;
  height: 1px;
  z-index: 2;
  pointer-events: none;
  background: linear-gradient(90deg, transparent 20%, rgba(217, 167, 126, 0.8) 50%, transparent 80%);
  background-size: 200% 100%;
  background-repeat: no-repeat;
  animation: footer-sheen var(--dur-sheen) var(--ease-in-out) infinite;
}
@keyframes footer-sheen {
  0%, 100% { background-position: 100% 0; }
  50%      { background-position: 0% 0; }
}

/* ---- Animated backdrop (steam + beans + breathing glow) ---- */
.site-footer__bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}
/* Warm glow near the floor of the band.
   It used to breathe, and that was the most expensive thing on the page:
   a band-wide bloom animating its opacity directly behind the frosted
   glass panes, which forces the backdrop to be re-filtered on every
   frame of the pulse. The light is still now — the same warm floor, no
   per-frame fill rate — and the footer's life comes from the steam, the
   beans and the glints crossing the glass instead. */
.site-footer__bg::after {
  content: "";
  position: absolute;
  inset: auto 0 -35%;
  height: 130%;
  background: radial-gradient(55% 65% at 50% 100%, rgba(154, 91, 50, 0.25), transparent 70%);
}

/* Rising steam curls */
.site-footer__steam {
  position: absolute;
  bottom: -8%;
  width: clamp(2.2rem, 4vw, 3.4rem);
  height: clamp(3.6rem, 7vw, 5.6rem);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='72' viewBox='0 0 48 72'%3E%3Cpath d='M24 70 C 8 60, 40 52, 24 42 C 8 32, 40 24, 24 14 C 18 9, 19 6, 24 2' fill='none' stroke='%23d9a77e' stroke-width='2.5' stroke-linecap='round' opacity='0.45'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-size: contain;
  background-position: center;
  opacity: 0;
  animation: footer-steam var(--dur-steam) var(--ease-in-out) infinite;
}
.site-footer__steam--1 { inset-inline-start: 10%; animation-delay: 0s; }
.site-footer__steam--2 { inset-inline-start: 44%; animation-delay: 3.4s; }
.site-footer__steam--3 { inset-inline-start: 76%; animation-delay: 6.8s; }
@keyframes footer-steam {
  0%   { opacity: 0; transform: translate3d(0, 26px, 0) scale(0.92); }
  30%  { opacity: 0.5; }
  65%  { opacity: 0.28; transform: translate3d(7px, -30px, 0) scale(1.04); }
  100% { opacity: 0; transform: translate3d(-5px, -64px, 0) scale(1.1); }
}

/* Drifting coffee beans */
.site-footer__bean {
  position: absolute;
  width: clamp(0.7rem, 1.4vw, 0.95rem);
  height: clamp(1rem, 2vw, 1.35rem);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='20' viewBox='0 0 14 20'%3E%3Cellipse cx='7' cy='10' rx='6' ry='9' fill='%239a5b32'/%3E%3Cpath d='M7 1.5 C 3 5, 3 15, 7 18.5' stroke='%23fbf8f3' stroke-width='1.3' fill='none' stroke-linecap='round' opacity='0.45'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-size: contain;
  opacity: 0;
  animation: footer-bean var(--dur-bean) linear infinite;
}
.site-footer__bean--1 { inset-inline-start: 7%;  bottom: 16%; animation-delay: 0s; }
.site-footer__bean--2 { inset-inline-start: 22%; bottom: 34%; animation-delay: 3.2s; animation-duration: 19s; }
.site-footer__bean--3 { inset-inline-start: 63%; bottom: 22%; animation-delay: 6.4s; }
.site-footer__bean--4 { inset-inline-start: 84%; bottom: 40%; animation-delay: 9.6s; animation-duration: 14s; }
.site-footer__bean--5 { inset-inline-start: 38%; bottom: 10%; animation-delay: 12.8s; animation-duration: 21s; }
@keyframes footer-bean {
  0%   { opacity: 0; transform: translate3d(0, 0, 0) rotate(0deg); }
  18%  { opacity: 0.65; }
  72%  { opacity: 0.45; }
  100% { opacity: 0; transform: translate3d(0, -13rem, 0) rotate(340deg); }
}

/* ---- Content layer (above the backdrop) ---- */
.site-footer__inner {
  position: relative;
  z-index: 1;
}

/* Entrance — columns rise into view, staggered, via the shared reveal
   utility (data-reveal-section in the HTML) */
.site-footer.js-reveal .site-footer__inner > * {
  opacity: 0;
  transform: translateY(26px);
  transition:
    opacity var(--dur-reveal) var(--ease-out),
    transform var(--dur-reveal) var(--ease-out);
}
.site-footer.js-reveal.is-visible .site-footer__inner > * {
  opacity: 1;
  transform: translateY(0);
}
.site-footer.js-reveal.is-visible .site-footer__inner > *:nth-child(2) { transition-delay: 0.12s; }
.site-footer.js-reveal.is-visible .site-footer__inner > *:nth-child(3) { transition-delay: 0.24s; }

.site-footer__inner {
  /* ---- Pane proportions — the only numbers to touch.
     The row is one balanced line: the three panes divide the whole width
     between them, so the footer is always fully occupied and no air is
     stranded at the edges or pushed between the columns. These are
     weights, not widths, so the row fills whatever container it is given
     — narrow or wide — with the same balance. */
  --footer-pane-1: 1.3fr; /* brand */
  --footer-pane-2: 1fr;   /* index */
  --footer-pane-3: 1.1fr; /* visit */
  display: grid;
  grid-template-columns:
    var(--footer-pane-1)
    var(--footer-pane-2)
    var(--footer-pane-3);
  /* Glass corner — one number for the slab, its clip and its shine. */
  --footer-glass-radius: 14px;
  /* The three panes share one height, and each pane spreads its own
     content to its edges (see the proportion block below), so a taller
     pane is never a pane that is half empty. */
  align-items: stretch;
  /* Air between the panes, and the band's own margin above and below the
     row. Kept small on purpose: the breathing room lives inside each
     pane's own padding, not in the gutter. */
  gap: clamp(0.85rem, 1.4vw, 1.25rem);
  padding-block: clamp(2.25rem, 5vh, 3rem);
  max-width: var(--footer-pane-max, 1120px);
  margin-inline: auto;
}

/* ---------- Column panels ----------
   Each column is a pane of glass: a frosted slab (::before) blurring the
   steam and glow behind the footer, a lit rim with a terracotta bloom, a
   moving streak (::after), and the column's content on top. Both layers are
   inset: 0 inside the pane box. --footer-glass-tint sets the tint's
   strength: raise it for a more solid sheet, drop it to 0 for glass you
   only notice from the rim. */

.site-footer__brand,
.site-footer__nav,
.site-footer__visit {
  position: relative;
  /* One controlled box per pane: it fills its track exactly, and the
     padding below is the glass's own breathing room — the same rectangle
     as the glass, on every side. */
  padding: var(--footer-pane-pad-y, 1.5rem) var(--footer-pane-pad-x, 1.4rem);
  /* One transparency knob for the whole pane — the slab behind it, and
     the nav's cards on top of it, all read this number. Just over half:
     the panes stay clearly transparent (the steam, beans and glow behind
     them read through) while the rim still holds the shape. Push it
     towards 1 for a more solid sheet, towards 0 for glass you only
     notice from the rim. */
  --footer-glass-tint: 0.55;
  /* The pane carries the glass corner itself, so overflow: hidden trims
     the slab and the streak to the same rounded rectangle — no square
     edges and no light in the corners. */
  border-radius: var(--footer-glass-radius, 14px);
  overflow: hidden;
}

/* ---- How each pane fills its own height ----
   The row stretches all three to one height, so instead of leaving a
   void at the bottom of a short column, every pane distributes its own
   content: the wordmark and the credo bookend the brand pane, the nav's
   six cards stretch to fill their pane, and the status pill rests on the
   floor of the visit pane. */
.site-footer__brand { justify-content: space-between; }
.site-footer__nav {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}
/* The nav's own gap spaces the heading, so the title drops its own bottom
   margin here — no double gutter under "Explore" — and it centres over
   the deck of cards below it. */
.site-footer__nav .site-footer__nav-title {
  margin-bottom: 0;
  text-align: center;
}
.site-footer__visit .site-footer__status { margin-top: auto; }

.site-footer__brand::before,
.site-footer__nav::before,
.site-footer__visit::before {
  content: "";
  position: absolute;
  /* Flush with the pane box: the glass is exactly the rectangle of the
     column, so it never overhangs on any side. To tighten it further,
     inset it positively (e.g. inset: 0.4rem) instead of pulling it out. */
  inset: 0;
  z-index: -1;
  pointer-events: none;
  border-radius: var(--footer-glass-radius, 14px);
  /* Layered glass, lit from the reading-start corner:
       · a broad diagonal stroke of light across the slab
       · a vertical wash that keeps the top bright and lets the tint
         settle into the warm floor of the band */
  background:
    linear-gradient(
      115deg,
      rgba(253, 249, 242, calc(0.105 * var(--footer-glass-tint))) 0%,
      rgba(253, 249, 242, calc(0.03 * var(--footer-glass-tint))) 36%,
      rgba(253, 249, 242, 0) 60%
    ),
    linear-gradient(
      180deg,
      rgba(253, 249, 242, calc(0.09 * var(--footer-glass-tint))) 0%,
      rgba(253, 249, 242, calc(0.03 * var(--footer-glass-tint))) 45%,
      rgba(154, 91, 50, calc(0.07 * var(--footer-glass-tint))) 100%
    ),
    linear-gradient(
      180deg,
      color-mix(in srgb, var(--color-accent-ink) 6%, transparent),
      color-mix(in srgb, var(--color-accent-ink) 2%, transparent)
    );
  /* The rim of the slab: a light hairline all the way round that thins to
     terracotta towards the floor of the band. */
  border: 1px solid rgba(253, 249, 242, 0.14);
  /* Inner lights read the edge as thickness (a bright top bevel, a faint
     terracotta bottom bevel), then two outer shadows seat the pane on the
     band: a soft cast below it and a warm bloom around it. */
  box-shadow:
    inset 0 1px 0 rgba(253, 249, 242, 0.3),
    inset 0 -1px 0 rgba(217, 167, 126, 0.16),
    inset 1px 0 0 rgba(253, 249, 242, 0.06),
    inset -1px 0 0 rgba(253, 249, 242, 0.04),
    0 20px 42px -24px rgba(0, 0, 0, 0.8),
    0 0 36px -12px rgba(217, 167, 126, 0.25);
  /* Actual frost: the footer's steam, beans and glow carry on moving and
     are softly blurred through the slab. Kept modest (8px) so the blur
     stays cheap over the animated backdrop. */
  /* The frost radius is deliberately modest. Everything behind these
     panes — the steam, the beans, the glints — is animated, so the
     backdrop has to be re-filtered on every frame; blur cost climbs
     steeply with radius, and 6px reads the same as 7px here. */
  backdrop-filter: blur(6px) saturate(1.12) brightness(1.02);
  -webkit-backdrop-filter: blur(6px) saturate(1.12) brightness(1.02);
}

/* The moving shine — one oblique bar of light that sweeps across the pane
   and off the far edge. The bar is a rotated gradient strip, not an
   animated background, so the pass costs a transform and nothing else;
   the pane's overflow: hidden trims it to the glass. */
.site-footer__brand::after,
.site-footer__nav::after,
.site-footer__visit::after {
  content: "";
  position: absolute;
  inset-block: -30%;
  inset-inline-start: 0;
  width: 40%;
  z-index: -1;
  pointer-events: none;
  /* Follows the slab's rounding, so no light spills into the corners. */
  border-radius: var(--footer-glass-radius, 14px);
  background: linear-gradient(
    100deg,
    rgba(253, 249, 242, 0) 0%,
    rgba(253, 249, 242, 0.07) 42%,
    rgba(253, 249, 242, 0.15) 50%,
    rgba(253, 249, 242, 0.07) 58%,
    rgba(253, 249, 242, 0) 100%
  );
  filter: blur(7px);
  transform: translateX(115%);
  animation: footer-glass-shine var(--dur-sheen) var(--ease-in-out) infinite;
}
.site-footer__nav::after   { animation-delay: 1.2s; }
.site-footer__visit::after { animation-delay: 2.4s; }
@keyframes footer-glass-shine {
  0%   { transform: translateX(115%); }
  /* The sweep occupies a fifth of the loop; the rest is the pane at rest,
     so the shine reads as a passing reflection, not a blinking light. */
  12%  { transform: translateX(-215%); }
  100% { transform: translateX(-215%); }
}

.site-footer__brand {
  display: flex;
  flex-direction: column;
  align-items: flex-start; /* RTL: starts from the right */
  gap: 1.1rem;
}
/* Brand wordmark pops in terracotta on the dark band */
.site-footer .brand__wordmark {
  color: var(--color-accent-soft);
  font-size: clamp(1.75rem, 1.25rem + 1.8vw, 2.4rem);
}
.site-footer .brand:hover .brand__wordmark,
.site-footer .brand:focus-visible .brand__wordmark {
  color: var(--color-paper-dim);
}
.site-footer__tagline {
  font-size: clamp(0.8125rem, 0.75rem + 0.3125vw, 0.9375rem);
  font-weight: 300;
  line-height: 2;
  color: var(--color-paper-muted);
}
/* Quiet Latin flourish under the tagline */
.site-footer__credo {
  font-family: var(--font-latin);
  font-size: clamp(0.625rem, 0.5625rem + 0.25vw, 0.6875rem);
  font-weight: 500;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: rgba(217, 167, 126, 0.55);
}

/* ---- The cup at the reading end of the brand pane ----
   A drawn cup (never fetched) with a warm bloom, two curls of steam, a lit
   surface and a slow breath. Absolutely placed so the pane's text layout
   stays untouched, and every animation moves only transform or opacity.
   Decorative and aria-hidden; the words beside it carry the meaning. */
.site-footer__cup {
  position: absolute;
  inset-inline-end: clamp(0.75rem, 3vw, 1.75rem);
  inset-block-end: clamp(0.75rem, 2.5vh, 1.5rem);
  inline-size: clamp(4.5rem, 26%, 6.5rem);
  aspect-ratio: 120 / 132;
  color: var(--color-accent-soft);
  pointer-events: none;
}

/* The bloom behind the cup — the footer's floor glow, in miniature */
.site-footer__cup-glow {
  position: absolute;
  inset: -22%;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(217, 167, 126, 0.3), rgba(217, 167, 126, 0) 68%);
  animation: footer-cup-glow var(--dur-glow) var(--ease-in-out) infinite alternate;
}
@keyframes footer-cup-glow {
  from { opacity: 0.45; }
  to   { opacity: 1; }
}

.site-footer__cup-art {
  position: relative;
  z-index: 1; /* above its own bloom */
  inline-size: 100%;
  block-size: 100%;
  stroke: currentColor;
  stroke-width: 1.4;
  opacity: 0.9;
  transition: opacity var(--dur-med) var(--ease-out);
  animation: footer-cup-float var(--dur-sheen) var(--ease-in-out) infinite;
}
@keyframes footer-cup-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-3px); }
}

/* The steam: each curl rises out of the cup, thins, and is gone — the
   second one on its own beat so the pair never moves in lockstep.
   transform-box keeps the scaling anchored to the curl's own foot. */
.site-footer__cup-steam {
  transform-box: fill-box;
  transform-origin: 50% 100%;
  opacity: 0;
  animation: footer-cup-steam var(--dur-steam) var(--ease-in-out) infinite;
}
.site-footer__cup-steam--2 {
  animation-delay: 2.6s;
}
@keyframes footer-cup-steam {
  0%   { opacity: 0;    transform: translateY(4px)   scaleY(0.86); }
  35%  { opacity: 0.55; }
  70%  { opacity: 0.28; transform: translateY(-7px)  scaleY(1.06); }
  100% { opacity: 0;    transform: translateY(-14px) scaleY(1.12); }
}

/* The brew under the steam, catching the light */
.site-footer__cup-brew {
  animation: footer-cup-brew var(--dur-sheen) var(--ease-in-out) infinite;
}
@keyframes footer-cup-brew {
  0%, 100% { opacity: 0.45; }
  50%      { opacity: 0.85; }
}

/* Hovering the pane brings the cup up to full warmth */
.site-footer__brand:hover .site-footer__cup-art,
.site-footer__brand:focus-within .site-footer__cup-art {
  opacity: 1;
}

/* Leave the reading end of the pane to the cup: the tagline stops short
   of it instead of running underneath. */
.site-footer__brand .site-footer__tagline {
  max-width: min(22rem, 62%);
}

.site-footer__nav-title {
  margin-bottom: 1rem;
  font-family: var(--font-latin);
  font-size: clamp(0.6875rem, 0.625rem + 0.3125vw, 0.75rem);
  font-weight: 500;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--color-accent-soft);
}
.site-footer__nav ul {
  /* Five tiles rather than a list: two columns and three rows, every card
     the same size as the next, and the rows stretch to fill whatever
     height the pane is given — so the deck occupies the column instead
     of leaving a tail of empty glass under it. */
  flex: 1;
  align-content: stretch;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(0.5rem, 0.9vw, 0.7rem);
  list-style: none;
  padding: 0;
  margin: 0;
}
/* The cell is only a holder: the card inside fills it on both axes. */
.site-footer__nav li { display: grid; }

/* Five cards over two columns leaves the last one alone on its row, with
   an empty cell of glass beside it. It takes the whole row instead, so
   the deck closes as a solid band and nothing sits open at the edge. */
.site-footer__nav li:last-child {
  grid-column: 1 / -1;
}

/* Each link is its own little pane of glass, and its label sits dead
   centre in it — the card is the target, not the word. */
.site-footer__nav a {
  display: grid;
  place-items: center;
  min-block-size: 2.6rem;
  padding: 0.7rem 0.6rem;
  text-align: center;
  font-size: clamp(0.9375rem, 0.875rem + 0.375vw, 1.0625rem);
  color: var(--color-paper-muted);
  border: 1px solid rgba(253, 249, 242, 0.1);
  border-radius: 10px;
  /* A lighter cut of the pane's own glass, so the cards sit inside the
     slab rather than on top of it. */
  background: linear-gradient(
    180deg,
    rgba(253, 249, 242, calc(0.13 * var(--footer-glass-tint))),
    rgba(253, 249, 242, calc(0.04 * var(--footer-glass-tint)))
  );
  box-shadow:
    inset 0 1px 0 rgba(253, 249, 242, 0.14),
    0 8px 16px -12px rgba(0, 0, 0, 0.75);
  transition:
    color var(--dur-fast) var(--ease-out),
    border-color var(--dur-med) var(--ease-out),
    background var(--dur-med) var(--ease-out),
    transform var(--dur-med) var(--ease-out);
}
/* Hover lifts the card a hair and warms its rim — the glass catching light
   instead of an underline sliding under the word. */
.site-footer__nav a:hover,
.site-footer__nav a:focus-visible {
  color: var(--color-paper-dim);
  border-color: rgba(217, 167, 126, 0.42);
  background: linear-gradient(
    180deg,
    rgba(253, 249, 242, calc(0.24 * var(--footer-glass-tint))),
    rgba(253, 249, 242, calc(0.09 * var(--footer-glass-tint)))
  );
  transform: translateY(-2px);
}

.site-footer__visit {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.5rem;
}
.site-footer__line {
  font-size: clamp(0.8125rem, 0.75rem + 0.3125vw, 0.9375rem);
  color: var(--color-paper-muted);
}
.site-footer__line span {
  font-family: var(--font-num);
  font-variant-numeric: lining-nums;
  font-weight: 500;
  color: var(--color-paper-dim);
}

/* Live open/closed badge — a small pill with a status dot */
.site-footer__status {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.75rem;
  align-self: flex-start;
  font-size: clamp(0.75rem, 0.6875rem + 0.3125vw, 0.8125rem);
  font-weight: 500;
  color: var(--color-paper-muted);
  border: 1px solid rgba(217, 167, 126, 0.28);
  border-radius: 999px;
  padding: 0.3rem 0.85rem;
  transition: color var(--dur-med) var(--ease-out), border-color var(--dur-med) var(--ease-out);
}
.site-footer__status::before {
  content: "";
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--color-muted);
  transition: background var(--dur-med) var(--ease-out), box-shadow var(--dur-med) var(--ease-out);
}
.site-footer__status.is-open {
  color: var(--color-accent-soft);
  border-color: rgba(217, 167, 126, 0.55);
}
.site-footer__status.is-open::before {
  background: #d9a77e;
  box-shadow: 0 0 0 3px rgba(217, 167, 126, 0.16);
}

/* ---- Motion only once the band is on screen ----
   The footer sits below the fold, so its ambient loops wait for the band
   (data-reveal-section, see js/reveal.js) instead of ticking through the
   read above it. Scoped to `.js-reveal:not(.is-visible)`, so with
   JavaScript off every loop simply runs as before. */
.site-footer.js-reveal:not(.is-visible)::before,
.site-footer.js-reveal:not(.is-visible) .site-footer__steam,
.site-footer.js-reveal:not(.is-visible) .site-footer__bean,
.site-footer.js-reveal:not(.is-visible) .site-footer__brand::after,
.site-footer.js-reveal:not(.is-visible) .site-footer__nav::after,
.site-footer.js-reveal:not(.is-visible) .site-footer__visit::after,
.site-footer.js-reveal:not(.is-visible) .site-footer__cup-glow,
.site-footer.js-reveal:not(.is-visible) .site-footer__cup-art,
.site-footer.js-reveal:not(.is-visible) .site-footer__cup-steam,
.site-footer.js-reveal:not(.is-visible) .site-footer__cup-brew {
  animation-play-state: paused;
}

/* ============================================================
   Responsive
   ============================================================ */
/* Tablet — the brand spans the top row, the two columns sit below */
@media (max-width: 59.99rem) {
  .site-footer__inner {
    /* Still fractional: the index and the visit pane share the line, and
       the brand takes the whole width above them — two full rows, no
       stranded air. */
    grid-template-columns: 1.1fr 1fr;
  }
  .site-footer__brand {
    grid-column: 1 / -1;
  }
  /* Two panes on the lower line share a smaller pad. */
  .site-footer__brand,
  .site-footer__nav,
  .site-footer__visit {
    --footer-pane-pad-x: 1.15rem;
    --footer-pane-pad-y: 1.35rem;
  }
  /* The brand pane now spans the full width, so the cup may grow and the
     tagline may use the room it has again. */
  .site-footer__cup {
    inline-size: min(7.5rem, 18%);
  }
  .site-footer__brand .site-footer__tagline {
    max-width: min(22rem, 100%);
  }
}

/* Mobile — everything stacks; a couple of beans stand down */
@media (max-width: 39.99rem) {
  .site-footer__inner {
    grid-template-columns: 1fr;
    gap: 0.85rem;
    padding-block: clamp(2rem, 5vh, 2.75rem);
  }
  /* Stacked columns: each pane fills the single column edge to edge, so
     the stack is a solid run of glass with one gutter between panes. */
  .site-footer__brand,
  .site-footer__nav,
  .site-footer__visit {
    --footer-pane-pad-x: 1rem;
    --footer-pane-pad-y: 1.25rem;
  }
  .site-footer__bean--4,
  .site-footer__bean--5 {
    display: none;
  }
  /* Single column: the cup steps in a little and keeps clear of the
     credo on the narrowest panes. */
  .site-footer__cup {
    inline-size: min(6rem, 26%);
    inset-inline-end: clamp(0.6rem, 2.5vw, 1rem);
  }
}

/* ============================================================
   Band decor — the quiet layer behind the paper sections
   Opt in with .band-decor: a warm dot grid that thins at the bottom of the
   band, and a terracotta bloom out of one corner, both behind the content.
     .band-decor--flip   the bloom moves to the reading-start corner
     .band-decor--dark   light-tone veils for the dark bands
   The section keeps its own stacking context (isolation), so the veils
   paint above its background but below every child.
   ============================================================ */
.band-decor {
  position: relative;
  isolation: isolate;
  overflow: hidden;
}

.band-decor::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: 0.5;
  background-image: radial-gradient(rgba(116, 106, 89, 0.17) 0.8px, transparent 0.9px);
  background-size: 22px 22px;
  mask-image: linear-gradient(180deg, black 0%, black 28%, transparent 88%);
}

.band-decor::after {
  content: "";
  position: absolute;
  z-index: -1;
  inset-inline-end: -15rem;
  top: -15rem;
  width: min(62vw, 42rem);
  aspect-ratio: 1;
  border-radius: 50%;
  pointer-events: none;
  background: radial-gradient(circle, rgba(154, 91, 50, 0.11), rgba(154, 91, 50, 0) 68%);
}

.band-decor--flip::after {
  inset-inline-end: auto;
  inset-inline-start: -15rem;
}

.band-decor--dark::before {
  opacity: 0.4;
  background-image: radial-gradient(rgba(253, 249, 242, 0.16) 0.8px, transparent 0.9px);
}

.band-decor--dark::after {
  background: radial-gradient(circle, rgba(217, 167, 126, 0.14), rgba(217, 167, 126, 0) 68%);
}
