/* Hero scroller. Loaded by the ofs_hero module only, via addStyle(), so it
   costs nothing on pages without a hero. */

/* ---------- hero ---------- */
.hero{position:relative; overflow:hidden; border-bottom:1px solid var(--ink-700)}
.hero__glow{position:absolute; inset:auto -20% -55% auto; width:820px; height:820px; right:-8%;
  background:radial-gradient(circle,rgba(168,96,240,.22) 0%,rgba(60,180,252,.14) 42%,transparent 68%);
  filter:blur(120px); pointer-events:none}
/* ---- hero scroller ----
   Slide 1 is statically rendered and carries the page's only <h1>, so it stays the
   LCP element. Slides 2+ use a <p> styled as display type: alternate messaging for
   the same page region should not add competing headings to the outline. */
.hero__slider{position:relative}
.hero__track{display:flex; overflow-x:auto; scroll-snap-type:x mandatory;
  outline-offset:-2px;
  scrollbar-width:none; -ms-overflow-style:none; overscroll-behavior-x:contain}
.hero__track::-webkit-scrollbar{display:none}
.slide{flex:0 0 100%; min-width:100%; scroll-snap-align:start; scroll-snap-stop:always}
.slide__inner{position:relative; display:grid; gap:var(--s-6); padding-block:52px}
@media(min-width:1024px){
  .slide__inner{grid-template-columns:minmax(0,1fr) minmax(0,.92fr); align-items:center; gap:var(--s-8); padding-block:76px; min-height:530px}
}
/* Room at the foot of the slide for the controls now laid over it: exactly the
   height of the foot — one 44px control plus its padding above and below — and
   s-5 of clear air between it and the last line of small print.

   This replaces the slide's own bottom padding rather than adding to it. The
   first version kept the 52/76px band as well, which put 184px under the type on
   a desktop against 76px above it, and read as a hole. */
/* The slide reserves the height of the foot laid over it, plus s-5 of clear
   air. The foot is the control row and the towns strip, and both change with
   the viewport, so each is named rather than folded into one number: the towns
   are two rows below 640px and one above it, and the control row's lower
   padding steps up at 768px. The 143px and 76px are the measured heights of
   the towns block itself — two rows of name-plus-state, and one. */
.hero--paged{
  --ofs-ctrl:  calc(44px + var(--s-4) + var(--s-6));
  --ofs-towns: calc(var(--s-5) + 143px);
}
@media(min-width:640px){ .hero--paged{--ofs-towns:calc(var(--s-5) + 76px)} }
@media(min-width:768px){ .hero--paged{--ofs-ctrl:calc(44px + var(--s-4) + var(--s-7))} }

.hero--paged .slide__inner{
  padding-bottom:calc(var(--ofs-ctrl) + var(--ofs-towns) + var(--s-5))}
.slide__title{font-family:var(--font-display); font-weight:700; text-transform:uppercase;
  font-size:clamp(2.75rem,1.5rem + 5vw,4.5rem); line-height:.95; letter-spacing:.01em;
  margin:0 0 var(--s-5)}
.slide__title em{font-style:normal; color:var(--spark-cyan)}
.hero__actions{display:flex; flex-wrap:wrap; gap:var(--s-3); margin-top:var(--s-6)}
/* The controls sit over the bottom of the picture rather than in a band below
   it, so a slide's background image reaches the full height of the hero. The
   slide reserves the room for them (.hero--paged below) so nothing collides. */
.hero__foot{position:absolute; left:0; right:0; bottom:0; z-index:2;
  padding-bottom:var(--s-6); pointer-events:none}
.hero__foot .dot-btn, .hero__foot .arrow{pointer-events:auto}
@media(min-width:768px){
  .hero__foot{padding-bottom:var(--s-7)}
}
.hero__ctrl{display:flex; align-items:center; gap:var(--s-2); padding-top:var(--s-4)}
.dots{display:flex; gap:2px; margin-right:auto}
.dot-btn{width:40px; height:44px; display:grid; place-items:center; background:none;
  border:0; padding:0; cursor:pointer}
.dot-btn::after{content:""; width:28px; height:3px; border-radius:2px;
  background:var(--ink-600); transition:background var(--t-micro) ease-out}
.dot-btn:hover::after{background:var(--text-tertiary)}
.dot-btn[aria-current="true"]::after{background:var(--spark-cyan)}
.arrow{width:44px; height:44px; display:grid; place-items:center; cursor:pointer;
  background:transparent; border:1px solid var(--ink-700); border-radius:var(--r-control);
  color:var(--text-secondary); transition:all var(--t-micro) ease-out}
.arrow:hover{border-color:var(--spark-cyan); color:var(--text-primary)}
.arrow[disabled]{opacity:.35; cursor:default}
.arrow[disabled]:hover{border-color:var(--ink-700); color:var(--text-secondary)}
.hero__pause{display:none}

.hero__slider[data-autoplay] .hero__pause{display:grid}
/* ---- offer slide: product trio ---- */
.trio{position:relative; height:330px; max-width:520px; margin-inline:auto; width:100%}
@media(min-width:1024px){
  .trio{height:410px; max-width:560px}
}
.trio__card{position:absolute; width:47%; background:var(--paper);
  border-radius:var(--r-card); padding:12px; box-shadow:0 20px 44px rgba(0,0,0,.5)}
.trio__card img{width:100%; aspect-ratio:1; object-fit:contain}
.trio__card:nth-child(1){left:0; top:12%; transform:rotate(-7deg)}
.trio__card:nth-child(2){left:26.5%; top:0; transform:rotate(2deg); z-index:2}
.trio__card:nth-child(3){left:53%; top:16%; transform:rotate(8deg)}
.trio__p{display:block; text-align:center; font-weight:700; color:var(--ink-900);
  font-size:.9375rem; padding-top:6px}
.trio__tag{position:absolute; right:0; top:0; z-index:3;
  background:var(--magenta); color:var(--text-on-accent); border-radius:var(--r-chip);
  font-size:.8125rem; font-weight:700; text-transform:uppercase; letter-spacing:.06em;
  padding:9px 13px; transform:rotate(4deg)}
.hero__terms{margin-top:var(--s-5); font-size:.875rem; color:var(--text-tertiary);
  display:flex; flex-wrap:wrap; gap:6px 16px}
.hero__terms span{white-space:nowrap}
/* ---- the four towns ----
   These rules came over with the hero when it was first built, from the
   concept, where the strip sat on flat dark ground below the picture. It now
   sits over the bottom of a photograph, which changes three things: the
   hairline is a translucent white instead of ink-700, which would disappear on
   a light frame; the state line is text-secondary rather than tertiary; and the
   links need pointer-events back, since the foot they sit in has them off.
   It is a <ul>, so the list styling is reset here too. */
.towns{list-style:none; margin:var(--s-5) 0 0; padding:var(--s-5) 0 0;
  border-top:1px solid rgba(255,255,255,.16);
  display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:var(--s-4)}
/* Four across from 900px rather than 640. With a logo beside each town, a
   column needs about 190px — the logo, a gap and "Open until 8pm" — and between
   640 and 900 four columns came to 138px each, leaving a logo about 23px. Two
   across in that range gives each town nearly 300px. */
@media(min-width:900px){
  .towns{grid-template-columns:repeat(4,minmax(0,1fr))}
}
.town{display:block; color:var(--text-primary); pointer-events:auto}
.town:hover{text-decoration:none; color:var(--text-primary)}
.town__name{display:block; font-family:var(--font-display); font-weight:700; font-size:1.5rem;
  text-transform:uppercase; letter-spacing:.02em; line-height:1;
  transition:color var(--t-micro) ease-out}
.town:hover .town__name{color:var(--spark-cyan)}
.town__state{display:flex; align-items:center; gap:6px; margin-top:6px;
  font-size:.8125rem; color:var(--text-secondary)}
/* A logo to the left of the town name and open state.

   The words never wrap and the logo gives way instead. A phone column is
   152-160px and "Open until 8pm" alone is 105px, so at a fixed size the widest
   logo pushed the open state onto two lines at 360px, one of the most common
   phone widths. Here the text keeps its full width and the logo shrinks into
   what is left, keeping its proportions through height:auto. A logo only gets
   smaller when its column is genuinely short of room, so a wide phone or a
   tablet shows it at full size. Only a town with a logo becomes a flex row, so
   one without renders as before. */
.towns > li{container-type:inline-size}
.town__text{display:block}
.town--logo{display:flex; align-items:center; gap:var(--s-2)}
@media(min-width:640px){ .town--logo{gap:var(--s-3)} }
.town--logo .town__text{flex:none; white-space:nowrap}
.town__logo{display:block; flex:0 1 auto; min-width:0;
  width:var(--lw); height:auto}
/* Below 140px a column has room for the words and not much else: a logo would
   be squeezed to under 20px and read as a smudge, so it steps out. */
@container (max-width:140px){ .town__logo{display:none} }
.burst{width:100%; height:auto; max-width:720px; margin-inline:auto; display:block}
.tr{fill:none; stroke-linecap:round}
.dt{opacity:0}
.cr{opacity:0}
@media(prefers-reduced-motion:no-preference){
  .tr{stroke-dasharray:340; stroke-dashoffset:340; animation:draw .9s var(--ease-out) forwards; animation-delay:var(--d)}
  .dt{animation:pop .5s ease-out forwards; animation-delay:var(--d)}
  .cr{animation:fade .7s ease-out forwards; animation-delay:var(--d)}
}
@media(prefers-reduced-motion:reduce){
  .dt{opacity:.9}
  .cr{opacity:1}
}

/* ---------- slide backgrounds ----------
   A slide with an image of its own drops the two-column layout: the text sits
   over the picture instead, and the burst is not rendered at all. Slides with
   no image keep the original arrangement, so nothing changes until an image is
   chosen in the admin. */
.slide--bg{position:relative; isolation:isolate; overflow:hidden}
.slide--bg .slide__bg{
  position:absolute; inset:0; width:100%; height:100%;
  object-fit:cover; z-index:-2}

/* ---- Ken Burns ----
   A slow push into the picture. It only ever zooms in: the class is on the
   slide that is on screen, so the return to scale(1) happens while the slide is
   out of view and is never seen. Held at the end (forwards) for a hero that is
   left alone, so a single-slide hero settles rather than snapping back.

   transform only, so it composites on the GPU and never triggers layout. The
   slide clips it, which is what the overflow above is for. */
@keyframes ofs-kenburns{
  from{transform:scale(1)}
  to  {transform:scale(1.12)}
}
.slide--bg.is-current .slide__bg{
  animation:ofs-kenburns 24s ease-out both;
  transform-origin:60% 45%;
  will-change:transform}

@media(prefers-reduced-motion:reduce){
  .slide--bg.is-current .slide__bg{animation:none; transform:none}
}
/* Legibility over a photograph. Dark from the left, where the type is, and a
   little from the bottom so the small print and the controls hold up too.
   Without this the heading fails contrast on a bright image.

   Below 1024px the words run the full width of the slide, so the scrim has to
   hold its weight the whole way across. The hero photograph is bright smoke at
   the top, and on a phone `cover` crops to the middle of it and scales it up,
   which puts the lightest part of the picture directly behind the heading. */
.slide--bg .slide__scrim{
  position:absolute; inset:0; z-index:-1; pointer-events:none;
  background:
    linear-gradient(90deg, rgba(5,3,26,.92) 0%, rgba(5,3,26,.78) 38%, rgba(5,3,26,.42) 68%, rgba(5,3,26,.30) 100%),
    linear-gradient(0deg, rgba(5,3,26,.58) 0%, transparent 34%)}
/* From 1024px the text is capped at 60ch and stops well before the right edge,
   so from about two thirds across there is nothing to protect and the scrim was
   only draining the picture's own colour. It keeps its full weight to 38%,
   which is where the type actually sits. */
@media(min-width:1024px){
  .slide--bg .slide__scrim{
    background:
      linear-gradient(90deg, rgba(5,3,26,.92) 0%, rgba(5,3,26,.76) 38%, rgba(5,3,26,.28) 68%, rgba(5,3,26,.07) 100%),
      linear-gradient(0deg, rgba(5,3,26,.58) 0%, transparent 34%)}
}
@media(min-width:1024px){
  /* one column, and the words stop before the middle so the picture is visible */
  .slide--bg .slide__inner{grid-template-columns:minmax(0,1fr); min-height:530px}
  .slide--bg .slide__inner > div{max-width:60ch}
}
