/* ============================================================================
   ASTROVE — AFTERLIGHT
   ----------------------------------------------------------------------------
   The closing chapter, in its own file. It used to be sixteen lines scattered
   across four places in landing.css — a base block, a mobile block that hid the
   entire footer nav below 720px, a touch-target patch and a stray gradient
   1900 lines further down. Those four are gone; this is the whole footer.

   MOTION CONTRACT. Nothing here is autonomous. Two custom properties carry
   every scroll-authored value, both written by footer-afterlight.js:

     --afterlight   0 -> 1 raw progress through the closing region
     --wipe         0 -> 1 the monument reveal, remapped from --afterlight

   Both DEFAULT TO 1. If the module never loads, or the user prefers reduced
   motion, or IntersectionObserver is missing, the footer is already in its
   finished state: mark fully revealed, index fully legible, nothing waiting to
   be rescued by JavaScript. That is the same rule the rest of the site follows.
   ========================================================================== */

.site-footer {
  --afterlight: 1;
  --wipe: 1;
  position: relative;
  isolation: isolate;
  overflow: hidden;
  padding: clamp(3.5rem, 7vw, 6rem) var(--gutter-right) 1.6rem var(--gutter-left);
  border-top: 1px solid rgba(255, 255, 255, .1);
  background: #050508;
  color: var(--moon);
}

/* --- the spectral field ----------------------------------------------------
   Jamun-black left, forest-black right, a barely-warm neutral between them.
   The alphas are 3-6%: the test is that you should read DEPTH and not be able
   to name a hue. The old footer ran `linear-gradient(110deg, #04020a, #120626
   58%, #03140f)` and at 58% that midpoint was legibly violet.

   Oversized by 12% and translated a few percent with scroll, which is the
   cheapest of the permitted movements — no filter, no blur animation, no
   backdrop-filter over a full-width surface. It stops when progress reaches 1
   because progress is clamped, so the final state is genuinely still. */
.site-footer__field {
  position: absolute;
  z-index: -1;
  inset: -6% -6% -6% -6%;
  background:
    radial-gradient(120% 92% at 6% 42%, rgba(122, 45, 255, .055), transparent 60%),
    radial-gradient(115% 88% at 50% 58%, rgba(255, 165, 10, .026), transparent 55%),
    radial-gradient(120% 92% at 95% 46%, rgba(0, 212, 122, .042), transparent 60%);
  transform: translate3d(0, calc(var(--afterlight) * -1.6%), 0);
}

/* --- act 01/02 — utility + index ----------------------------------------- */
.footer-index {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  /* Controlled asymmetry: the columns are not equal weight. Shop and The House
     carry four entries each and get the room; Service and Trade sit tighter and
     further right, so the block reads as an archive index rather than as four
     identical ecommerce columns. */
  gap: clamp(1.5rem, 4vw, 4.5rem);
  align-items: start;
  max-width: 92rem;
}

.footer-group { min-width: 0; }

.footer-group__head {
  display: flex;
  gap: .85rem;
  align-items: baseline;
  margin: 0 0 1.25rem;
  padding: 0 0 .8rem;
  border-bottom: 1px solid rgba(255, 255, 255, .13);
  font-family: var(--font-ui);
  font-size: .58rem;
  font-weight: 500;
  letter-spacing: .18em;
  text-transform: uppercase;
}
.footer-group__head i {
  font-style: normal;
  color: rgba(255, 255, 255, .34);
  font-variant-numeric: tabular-nums;
}
.footer-group__head span { color: var(--moon-soft); }

.footer-group__list {
  margin: 0;
  padding: 0;
  list-style: none;
}
.footer-group__list li {
  /* The reveal mask. `clip` rather than `hidden` so this never becomes an
     accidental scroll container — a scrollable footer list is a focus trap
     waiting to happen. The padding keeps the hover hairline inside the box. */
  overflow: clip;
  padding-bottom: .22rem;
}

.footer-group__list a {
  position: relative;
  display: inline-block;
  padding: .34rem 0;
  color: rgba(255, 255, 255, .62);
  font-size: .74rem;
  letter-spacing: .04em;
  text-decoration: none;
  transition: color 220ms var(--ease-out);
}

/* ONE hover gesture, not four. A hairline draws in from the left under the
   label; the text warms very slightly to confirm it is the live one. No lift,
   no glow, no underline swap. */
.footer-group__list a::after {
  content: "";
  position: absolute;
  right: 0;
  bottom: .1rem;
  left: 0;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 260ms var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .footer-group__list a:hover { color: var(--moon); }
  .footer-group__list a:hover::after { transform: scaleX(1); }
}
.footer-group__list a:focus-visible {
  color: var(--moon);
  outline: 1px solid var(--nectar);
  outline-offset: 4px;
}
.footer-group__list a:active { color: var(--moon); }

/* --- the reveal ------------------------------------------------------------
   Run once, on entry, and never replayed. Held in the pre-state only while the
   module is present and motion is allowed: `[data-reveal-armed]` is set by the
   script itself, so a page without the script never hides anything. */
.site-footer[data-reveal-armed] .footer-group__head,
.site-footer[data-reveal-armed] .footer-group__list li > * {
  transform: translateY(17px);
  opacity: 0;
  transition:
    transform 480ms var(--ease-out) calc(var(--i, 0) * 55ms),
    opacity 480ms var(--ease-out) calc(var(--i, 0) * 55ms);
}
.site-footer[data-reveal-armed].is-revealed .footer-group__head,
.site-footer[data-reveal-armed].is-revealed .footer-group__list li > * {
  transform: none;
  opacity: 1;
}

/* --- the house record -----------------------------------------------------
   A ledger, not a card: no panel, no border box, no heading. It sits between
   the index and the threshold so the last thing read before the monument is
   evidence that a real, licensed food business is behind it.

   Set at .68rem against the index's .74rem and dimmed to 48% -- present and
   legible, but never competing with the mark. */
.footer-house {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 1.5rem 2.5rem;
  max-width: 92rem;
  margin: clamp(2.6rem, 5vw, 4rem) 0 0;
  padding-top: clamp(1.6rem, 3vw, 2.2rem);
  border-top: 1px solid rgba(255, 255, 255, .09);
}
.footer-house__item { min-width: 0; }
.footer-house__label {
  margin: 0 0 .45rem;
  color: rgba(255, 255, 255, .3);
  font-size: .53rem;
  letter-spacing: .2em;
  text-transform: uppercase;
}
.footer-house__value {
  margin: 0;
  color: rgba(255, 255, 255, .48);
  font-size: .68rem;
  font-style: normal;
  line-height: 1.62;
}
/* The trademark line is a footnote to the entity name, not a peer of it. */
.footer-house__value span { color: rgba(255, 255, 255, .32); }

.footer-house__value a {
  color: rgba(255, 255, 255, .62);
  text-decoration: none;
  border-bottom: 1px solid rgba(255, 255, 255, .2);
  transition: color 200ms var(--ease-out), border-color 200ms var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .footer-house__value a:hover { color: var(--moon); border-bottom-color: var(--nectar); }
}
.footer-house__value a:focus-visible { outline: 1px solid var(--nectar); outline-offset: 3px; }

/* --- act 03 — the threshold ---------------------------------------------- */
.footer-threshold {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem 2rem;
  justify-content: space-between;
  align-items: center;
  margin-top: clamp(3rem, 6vw, 5rem);
  padding-top: 1.4rem;
  border-top: 1px solid rgba(255, 255, 255, .1);
}
.footer-threshold p {
  margin: 0;
  color: var(--moon-soft);
  font-size: .62rem;
  letter-spacing: .16em;
}

.footer-return {
  position: relative;
  display: inline-flex;
  min-height: 44px;
  align-items: center;
  color: rgba(255, 255, 255, .55);
  font-size: .62rem;
  letter-spacing: .16em;
  text-decoration: none;
  transition: color 220ms var(--ease-out);
}
.footer-return::after {
  content: "";
  position: absolute;
  right: 0;
  bottom: .7rem;
  left: 0;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 260ms var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .footer-return:hover { color: var(--moon); }
  .footer-return:hover::after { transform: scaleX(1); }
}
.footer-return:focus-visible {
  color: var(--moon);
  outline: 1px solid var(--nectar);
  outline-offset: 4px;
}

/* --- act 04 — the monument ----------------------------------------------- */
.footer-monument {
  margin: clamp(3.5rem, 8vw, 7rem) 0 clamp(2.5rem, 5vw, 4rem);
  /* Desktop depth only, and only 5px of it. Above that the mark stops sitting
     in the page and starts floating over it. Mobile gets none — see the query
     at the bottom of this file. */
  transform: translate3d(0, calc((1 - var(--afterlight)) * 5px), 0);
}

.footer-monument__mark {
  position: relative;
  width: min(74rem, 88vw);
  margin: 0 auto;
  /* THE ARC DRAW. The mark is one approved raster; the arc and the star are
     inside it and are never cut out of it. This wipe travels left to right,
     which is the direction the arc itself was drawn, so the arc appears to
     complete into the star — the last thing uncovered at 84.4% of the width.
     Geometry untouched, nothing traced, nothing redrawn. */
  clip-path: inset(0 calc((1 - var(--wipe)) * 100%) 0 0);
}
.footer-monument__mark picture { display: block; }
.footer-monument__mark img {
  display: block;
  width: 100%;
  height: auto;
}

/* Measured off logo-white-1126.webp: the star's centre sits at x 950/1126 and
   y 163/408. This element never draws a star — it is a light event over the
   one already in the raster. */
.footer-monument__flare {
  position: absolute;
  top: 39.95%;
  left: 84.37%;
  width: 26%;
  aspect-ratio: 1;
  translate: -50% -50%;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 255, 255, .5), rgba(255, 247, 230, .13) 34%, transparent 62%);
  opacity: 0;
  pointer-events: none;
}
/* ONE event, ~290ms, then gone. Latched in JS so drifting back and forth across
   the threshold cannot re-fire it. No loop, no twinkle, no breathing. */
.footer-monument.is-ignited .footer-monument__flare {
  animation: afterlight-ignite 290ms var(--ease-out) forwards;
}
@keyframes afterlight-ignite {
  0%   { opacity: 0;   scale: .55; }
  38%  { opacity: 1;   scale: 1; }
  100% { opacity: 0;   scale: 1.18; }
}

/* --- act 05 — the final plate -------------------------------------------- */
.footer-plate {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem 1.5rem;
  justify-content: space-between;
  color: rgba(255, 255, 255, .36);
  font-size: .55rem;
  letter-spacing: .12em;
  opacity: 0;
  transition: opacity 520ms var(--ease-out);
}
.site-footer.is-settled .footer-plate,
.site-footer:not([data-reveal-armed]) .footer-plate { opacity: 1; }

/* ==========================================================================
   MOBILE — indexed disclosures.

   Below 720px the four lists are collapsed behind real buttons rather than
   stacked into a fourteen-link wall. The <button> is injected by the script,
   so the markup carries no control that does nothing on desktop.
   ========================================================================== */
@media (max-width: 720px) {
  .footer-index {
    grid-template-columns: 1fr;
    gap: 0;
  }

  .footer-group__head {
    margin: 0;
    padding: 0;
    border-bottom: 0;
  }

  .footer-group__toggle {
    display: flex;
    gap: .85rem;
    align-items: center;
    width: 100%;
    min-height: 52px;
    padding: 0;
    border: 0;
    border-bottom: 1px solid rgba(255, 255, 255, .11);
    /* No card, no rounding, no fill. A rule and a row. */
    background: none;
    color: inherit;
    font: inherit;
    letter-spacing: .18em;
    text-align: left;
    text-transform: uppercase;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }
  .footer-group__toggle i {
    font-style: normal;
    color: rgba(255, 255, 255, .34);
    font-variant-numeric: tabular-nums;
  }
  .footer-group__toggle span { color: var(--moon-soft); }
  .footer-group__toggle:active { opacity: .6; }

  /* THE DISCLOSURE INSTRUMENT.

     Two 1px rules drawn with the button's own pseudo-elements: no Unicode + or
     minus, no icon font, no SVG file, no package. Closed reads as a plus;
     opening rotates the vertical rule onto the horizontal one, so the control
     resolves into a minus rather than swapping to a different glyph.

     Pseudo-elements are not exposed to assistive technology, so this is
     decorative by construction -- the state a screen reader hears is
     aria-expanded on the button, which is the real one. The WHOLE row stays
     the touch target; this only marks where the row leads. */
  .footer-group__toggle {
    position: relative;
    padding-right: 1.6rem;
  }
  .footer-group__toggle::before,
  .footer-group__toggle::after {
    content: "";
    position: absolute;
    right: 0;
    top: 50%;
    width: 13px;
    height: 1px;
    background: rgba(255, 255, 255, .5);
    transition: transform 200ms var(--ease-out), opacity 200ms var(--ease-out);
  }
  /* Horizontal: constant. It is the through-line of both states. */
  .footer-group__toggle::before { transform: translateY(-50%); }
  /* Vertical: the part that moves. */
  .footer-group__toggle::after { transform: translateY(-50%) rotate(90deg); }
  .footer-group__toggle[aria-expanded="true"]::after {
    transform: translateY(-50%) rotate(0deg);
    opacity: 0;
  }
  .footer-group__toggle[aria-expanded="true"]::before { background: var(--nectar); }
  .footer-group__toggle:focus-visible {
    outline: 1px solid var(--nectar);
    outline-offset: -2px;
  }

  /* grid-template-rows 0fr -> 1fr is the only height animation that needs no
     measured pixel value, so nothing here reads layout on open. 180ms: enough
     to see the panel belongs to the row it came from, not a performance.

     THE COLLAPSE IS PER ROW, NOT PER LIST. Putting `grid-template-rows: 0fr` on
     the <ul> looked right and was not: it defines ONE track, so only the first
     <li> was governed by it and the other three landed in implicit `auto` rows
     that never collapsed. Every closed group still held roughly 380px of empty
     space at 390 -- the exact vertical wall this treatment exists to avoid.

     Each <li> is its own single-child grid instead. One row, one child, so the
     0fr is always the track the anchor is actually in, and the group collapses
     to nothing because all four of its rows do.

     And the track is written minmax(0, Nfr), not the usual bare `0fr`. Probed
     in Chromium 152: bare `0fr` resolved to 20px -- the item's content height --
     whether the item carried overflow:clip, overflow:hidden or neither, because
     a bare fr keeps an `auto` MIN track function and auto there is the content.
     minmax(0, 0fr) states the minimum explicitly and measures 0. */
  .footer-group__list {
    padding-bottom: 0;
    border-bottom: 1px solid rgba(255, 255, 255, .11);
    transition: padding-bottom 180ms var(--ease-out);
  }
  .footer-group__list > li {
    display: grid;
    grid-template-rows: minmax(0, 0fr);
    overflow: clip;
    padding: 0;
    transition: grid-template-rows 180ms var(--ease-out);
  }
  .footer-group__list[data-open] > li { grid-template-rows: minmax(0, 1fr); }
  .footer-group__list[data-open] { padding-bottom: .7rem; }
  /* SERVICE carries five entries. At the old .62rem padding that group alone
     ran past 200px, which is the vertical wall again by another route. Tighter
     interior rhythm, still a comfortable in-panel row -- the 52px target is
     the indexed row itself, not each link inside an opened panel. */
  .footer-group__list a {
    display: block;
    /* BOTH of these, on the ITEM. A grid item's automatic minimum size is its
       content, which is why the 0fr track measured 19.81px instead of 0 and
       every closed group still held one line of padding per link. min-height
       alone does not clear it -- the overflow is what actually makes the
       automatic minimum zero, and it has to sit here rather than on the <li>,
       where it only clipped what was already taking up the space. */
    min-height: 0;
    overflow: clip;
    padding: .5rem 0 .5rem 2rem;
    font-size: .82rem;
  }

  /* A collapsed panel must not hold focusable links, or tabbing runs invisibly
     through fourteen anchors inside three closed rows. The delay matters: on
     CLOSE, visibility must wait out the 180ms collapse instead of blanking the
     links on frame one, which would read as the panel vanishing rather than
     folding. On OPEN it is immediate. */
  .footer-group__list:not([data-open]) {
    visibility: hidden;
    transition: padding-bottom 180ms var(--ease-out), visibility 0s linear 180ms;
  }
  .footer-group__list[data-open] {
    visibility: visible;
    transition: padding-bottom 180ms var(--ease-out), visibility 0s linear 0s;
  }

  /* Mobile monument: no parallax, and sized to the viewport rather than to a
     desktop rem ceiling. 86vw keeps the E clear of the right edge on 390. */
  /* Two columns at 390 rather than four: the address is four lines and would
     wrap to six in a quarter-width column. Entity and address take the full
     row; the two short records pair up. */
  .footer-house { grid-template-columns: 1fr 1fr; gap: 1.3rem 1.5rem; }
  .footer-house__item:first-child,
  .footer-house__item:nth-child(3) { grid-column: 1 / -1; }

  .footer-monument { transform: none; }
  .footer-monument__mark { width: 86vw; }
  .footer-threshold { margin-top: 2.6rem; }
}

/* ==========================================================================
   REDUCED MOTION — the design must be complete without any of the above.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  .site-footer[data-reveal-armed] .footer-group__head,
  .site-footer[data-reveal-armed] .footer-group__list li > * {
    transform: none;
    opacity: 1;
    transition: none;
  }
  /* Mark complete, field motionless, plate present, no ignition. */
  .site-footer { --afterlight: 1; --wipe: 1; }
  .site-footer__field { transform: none; }
  .footer-monument { transform: none; }
  .footer-monument.is-ignited .footer-monument__flare { animation: none; opacity: 0; }
  .footer-plate { opacity: 1; transition: none; }
  .footer-group__list,
  .footer-group__list > li,
  .footer-group__toggle::before,
  .footer-group__toggle::after { transition: none; }
}
