/* Taqueria Chihuahua. Built to the dusk hero: lifted blacks, indigo sky, ember
   horizon, amber service window. Nothing here goes to pure black, same as the
   grade on the clip. */

:root {
  --ink:      #0e0c14;   /* deepest value on the page, still lifted off true black */
  --ink-2:    #15131f;
  --indigo:   #1c2040;
  --band-2:   #16172c;   /* the menu band. Flat, not a gradient, so a contrast
                            sweep can composite text against it instead of
                            skipping every label behind a background-image. */
  --ember:    #c2552a;   /* rules and dividers only. 4.22 to 1 on cream, which
                            is fine for a 2px line and not for a label. */
  --ember-deep: #b44c24; /* button fill. 4.88 to 1 under #fff5ec. */
  --ember-lit:  #e07a4e; /* ember as TEXT. 6.53 on ink, and still 4.71 against the
                            brightest pixel the .atmos wash can physically make,
                            which is why it is lighter than the ember rule colour. */
  --amber:    #e8a44c;
  --cream:    #f4ead9;
  --cream-2:  #cfc3b2;
  --line:     rgba(244,234,217,.16);
  --maxw:     1120px;
}

* { box-sizing: border-box; }

html, body { margin: 0; padding: 0; }

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  background: var(--ink);
  color: var(--cream);
  font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  font-size: 17px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

img, video { display: block; max-width: 100%; height: auto; }

a { color: var(--amber); }
a:hover { color: var(--cream); }

:focus-visible {
  outline: 3px solid var(--amber);
  outline-offset: 3px;
  border-radius: 2px;
}

.skiplink {
  position: absolute; left: -9999px; top: 0; z-index: 99;
  background: var(--amber); color: #161008;
  padding: .7rem 1.1rem; font-weight: 700; text-decoration: none;
}
.skiplink:focus { left: .6rem; top: .6rem; }

/* ---------------------------------------------------------------- hero

   The hero pins and the page is dragged up over it. Pure scroll position,
   no script: the hero is sticky, every band below it is opaque and sits on
   a higher layer. :not() nothing here, main is the only sibling that moves. */

.hero {
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: hidden;
  background: var(--ink);
  display: grid;
  place-items: center;
}

.hero .shot,
.hero .still {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* The still is the resting state. The clip replaces it once it is actually
   playing, so a blocked or failed autoplay leaves a finished looking hero
   rather than a black box.

   Every layer in here is positioned, so every layer needs a stated z-index.
   Left on auto they paint in DOM order, which put the still ON TOP of the
   clip and made the opacity swap below a silent no-op. The clip was never
   visible on any viewport. Stating all four means the next person to reorder
   the markup cannot reintroduce that. */
.hero .still { z-index: 0; }
.hero .shot  { z-index: 1; opacity: 0; transition: opacity .5s ease; }
.hero.rolling .shot { opacity: 1; }

.grain {
  position: absolute; inset: 0; pointer-events: none; z-index: 2;
  opacity: .5; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml;utf8,\
<svg xmlns='http://www.w3.org/2000/svg' width='140' height='140'>\
<filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/>\
<feColorMatrix type='saturate' values='0'/></filter>\
<rect width='140' height='140' filter='url(%23n)' opacity='.38'/></svg>");
}

.cue {
  position: absolute; left: 50%; bottom: 2.2rem; transform: translateX(-50%); z-index: 3;
  width: 1px; height: 54px; background: rgba(244,234,217,.25);
}
.cue span {
  display: block; width: 1px; height: 18px; background: var(--amber);
  animation: drift 2.6s ease-in-out infinite;
}
@keyframes drift { 0%,100% { transform: translateY(0); } 50% { transform: translateY(36px); } }
@media (prefers-reduced-motion: reduce) { .cue span { animation: none; } }

/* ---------------------------------------------------------------- shell */

main {
  position: relative;
  z-index: 1;
  background: var(--ink);
}

/* ---------------------------------------------------------------- atmosphere

   The page carries the same dusk the clip does, so scrolling off the hero is a
   continuation rather than a cut to a flat dark page. Three soft washes, none of
   them black, all of them ADDED light:

     - the indigo sky bleeds a little way down past the hero
     - an ember horizon warms the bottom of the page
     - one off centre amber pool keeps the long middle from going dead flat

   This sits in .atmos, a SIBLING of the sections, never a wrapper. Everything
   that holds text is a child of main, whose background stays a flat --ink, so a
   contrast sweep composites against a solid instead of skipping every label
   behind a background-image. The washes are bounded for that reason: the
   brightest pixel any of them can produce over --ink is measured, not assumed. */

.atmos {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    linear-gradient(to bottom, rgba(28,32,64,.60) 0, rgba(28,32,64,0) 620px),
    linear-gradient(to top,    rgba(194,85,42,.14) 0, rgba(194,85,42,0) 520px),
    radial-gradient(900px 520px at 85% 42%, rgba(232,164,76,.05), rgba(232,164,76,0) 70%);
}

/* The same film grain as the hero, at about a third of the strength. Overlay on
   a near black ground is almost all texture and almost no value shift. */
.atmos::after {
  content: "";
  position: absolute; inset: 0;
  opacity: .18; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml;utf8,\
<svg xmlns='http://www.w3.org/2000/svg' width='140' height='140'>\
<filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/>\
<feColorMatrix type='saturate' values='0'/></filter>\
<rect width='140' height='140' filter='url(%23n)' opacity='.38'/></svg>");
}

/* Everything with content rides above the wash. Without this the sections paint
   underneath it and the page looks exactly as flat as it did before. */
main > nav,
main > section { position: relative; z-index: 1; }

/* The slabs stay opaque on purpose. Solid band, wash, solid band, wash gives the
   page a rhythm, and the two bands that carry the most text are the solid ones. */

.band {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 5.5rem 1.4rem;
}

h1, h2, h3 { line-height: 1.15; margin: 0 0 .6rem; }

h2 {
  font-size: clamp(1.8rem, 4vw, 2.6rem);
  letter-spacing: -.01em;
}
h2::after {
  content: ""; display: block; width: 54px; height: 2px;
  background: var(--ember); margin: 1rem 0 1.4rem;
}

h3 {
  font-size: .82rem; text-transform: uppercase; letter-spacing: .14em;
  color: var(--amber); font-weight: 700;
}

.lede { font-size: 1.12rem; color: var(--cream-2); max-width: 54ch; margin: 0 0 2rem; }

.kicker {
  margin: 0 0 1.2rem; font-size: .76rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .22em; color: var(--ember-lit);
}

/* ---------------------------------------------------------------- nav */

.nav {
  display: flex; flex-wrap: wrap; gap: 1rem 1.6rem;
  align-items: center; justify-content: space-between;
  max-width: var(--maxw); margin: 0 auto;
  padding: 1.1rem 1.4rem;
  border-bottom: 1px solid var(--line);
}
.nav ul { display: flex; flex-wrap: wrap; gap: 1.4rem; list-style: none; margin: 0; padding: 0; }
.nav a { color: var(--cream); text-decoration: none; font-size: .9rem;
  letter-spacing: .06em; text-transform: uppercase; }
.nav a:hover { color: var(--amber); }
.nav-call { font-weight: 700; color: var(--amber) !important; }

/* ---------------------------------------------------------------- intro */

.intro { padding-top: 4rem; text-align: center; }
.intro .kicker { margin-bottom: 1.6rem; }
.intro h1 { margin: 0 0 1.8rem; }
.wordmark { width: min(560px, 86%); height: auto; margin: 0 auto; }
.intro .lede { margin-left: auto; margin-right: auto; text-align: center; }

.cta { margin: 2.2rem 0 0; display: flex; flex-wrap: wrap; gap: .8rem; }
.intro .cta { justify-content: center; }

.btn {
  display: inline-block; padding: .85rem 1.5rem;
  background: var(--ember-deep); color: #fff5ec; text-decoration: none;
  font-weight: 700; font-size: .88rem;
  letter-spacing: .1em; text-transform: uppercase;
  border: 1px solid var(--ember-deep);
}
.btn:hover { background: #9c3f1d; border-color: #9c3f1d; color: #fff5ec; }
.btn.ghost { background: transparent; color: var(--cream); border-color: var(--line); }
.btn.ghost:hover { background: rgba(244,234,217,.08); color: var(--cream); border-color: var(--cream-2); }

/* ---------------------------------------------------------------- food grid

   One frame shape, one ratio, all the variation in the crop. Column count
   follows the rendered size of the photo, not how many there are. */

.grid {
  display: grid;
  gap: 1.1rem;
  grid-template-columns: 1fr;
}
@media (min-width: 620px) { .grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 900px) { .grid { grid-template-columns: repeat(3, 1fr); } }

.shotframe { margin: 0; }
.shotframe img {
  display: block; width: 100%; height: auto;
  aspect-ratio: 3 / 4; object-fit: cover;
  border: 1px solid var(--line);
}
.shotframe figcaption {
  margin-top: .7rem; font-size: .84rem; color: var(--cream-2);
  letter-spacing: .02em;
}

/* ---------------------------------------------------------------- plates */

.plate { position: relative; background: var(--ink-2); }
.plate img { width: 100%; height: auto; display: block; }
.plate-cap {
  max-width: var(--maxw); margin: 0 auto; padding: 2.4rem 1.4rem 3rem;
}
.plate-cap p { color: var(--cream-2); max-width: 56ch; margin: 0; }
/* The second plate is the one the ember horizon reaches, so it is left open to
   the wash rather than painted back over with a solid. */
.plate.dark { background: transparent; }

@media (min-width: 900px) {
  .plate { display: grid; grid-template-columns: 1.25fr 1fr; align-items: center; }
  .plate img { height: 100%; object-fit: cover; }
  .plate-cap { padding: 3rem 3rem 3rem 2.6rem; }
}

/* ---------------------------------------------------------------- menu */

.menuband {
  background: var(--band-2);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

.menu {
  display: grid; gap: 1.6rem;
  grid-template-columns: 1fr;
}
@media (min-width: 760px) { .menu { grid-template-columns: repeat(3, 1fr); } }

.card {
  background: rgba(244,234,217,.04);
  border: 1px solid var(--line);
  padding: 1.5rem 1.4rem;
}
.card ul { list-style: none; margin: 1rem 0 0; padding: 0; }
.card li {
  padding: .75rem 0;
  border-top: 1px solid var(--line);
  font-weight: 600;
}
.card li:first-child { border-top: 0; padding-top: 0; }
.card li span {
  display: block; font-weight: 400; font-size: .88rem;
  color: var(--cream-2); margin-top: .18rem; line-height: 1.5;
}

.menuband .cta { justify-content: flex-start; margin-top: 2.4rem; }

/* ---------------------------------------------------------------- visit */

.visit-grid { display: grid; gap: 2.2rem; grid-template-columns: 1fr; }
@media (min-width: 760px) { .visit-grid { grid-template-columns: repeat(3, 1fr); } }

.vcol h3 { margin-bottom: .9rem; }
.addr, .hours, .contact { margin: 0 0 1.2rem; }
.hours .day { display: inline-block; min-width: 11.5rem; color: var(--cream-2); }
.hours .hrs { font-weight: 600; }

/* ---------------------------------------------------------------- footer */

.foot {
  position: relative; z-index: 1;
  background: var(--ink-2);
  border-top: 1px solid var(--line);
  text-align: center;
  padding: 3.2rem 1.4rem calc(3.2rem + env(safe-area-inset-bottom));
}
.foot-mark { width: min(320px, 72%); height: auto; margin: 0 auto 1.4rem; opacity: .9; }
.foot-line { margin: 0 0 1rem; color: var(--cream-2); font-size: .92rem; }
.foot-links { margin: 0; display: flex; gap: 1.4rem; justify-content: center; }
.foot-links a { color: var(--cream-2); font-size: .88rem; }
.foot-links a:hover { color: var(--amber); }

/* ---------------------------------------------------------------- call bar

   Phones only. The desktop page already has the number in the nav. */

.callbar { display: none; }

@media (max-width: 700px) {
  .callbar {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
    display: grid; grid-template-columns: 1fr 1fr;
    background: var(--ink-2);
    border-top: 1px solid var(--line);
    padding-bottom: env(safe-area-inset-bottom);
  }
  .callbar a {
    padding: .95rem .6rem; text-align: center; text-decoration: none;
    font-weight: 700; font-size: .9rem; letter-spacing: .1em;
    text-transform: uppercase; color: var(--cream);
  }
  /* .callbar a is more specific than .callbar-order, so the colour has to be
     set at matching weight or the generic cream wins and drops this to 4.4. */
  .callbar a.callbar-order { background: var(--ember-deep); color: #fff5ec; }
  .foot { padding-bottom: calc(5.5rem + env(safe-area-inset-bottom)); }
}

/* ---------------------------------------------------------------- portrait

   A 16:9 frame cover cropped into a portrait viewport keeps only
   viewportAspect / (16/9) of its width, so the taller the window the less of
   the shot survives. The wordmark is burned into the clip at 59% of frame
   width, which sets a hard floor: below about 1.25:1 the crop keeps under 70%
   and starts eating the lettering from both ends. Measured: 1024x768 keeps
   75% and is fine, 768x1024 keeps 42% and cuts the name in half.

   So this is keyed to ASPECT, not width. A 601px wide window on a tall screen
   is just as wrong as a phone, and the first cut of this rule, which only
   looked at max-width 600px, let every tablet in portrait through. Below the
   floor the hero stops pinning and letterboxes in its own ratio instead.

   This is a CROP rule and nothing more. The first cut of it also carried
   display:none on the video, which took the clip away from every window
   narrower than 5/4 including ordinary desktop ones. The clip stays here and
   is letterboxed alongside the still. Who gets the clip at all is a bandwidth
   question, and that lives in the two rules below plus main.js. */

@media (max-width: 600px), (max-aspect-ratio: 5 / 4) {
  .hero {
    position: relative;   /* unpins the sticky, still contains .grain */
    height: auto;
    padding: 0;
  }
  /* Both media share the one grid cell, so the hero is the height of a single
     16:9 frame rather than two stacked on top of each other. */
  .hero .shot,
  .hero .still {
    grid-area: 1 / 1;
    position: relative;
    inset: auto;
    width: 100%;
    height: auto;
    object-fit: contain;
    aspect-ratio: 16 / 9;
  }
  .cue { display: none; }
}

/* Spacing stays a WIDTH question. A tablet in portrait is letterboxed by the
   rule above but still has room for the desktop gutters.

   A phone is also where a 3 MB clip is worth the least and costs the most, so
   it is the one width that drops the video. main.js gates on this exact query,
   and the two agreeing is what keeps the element out of the layout instead of
   leaving an invisible one sitting over the still. */
@media (max-width: 600px) {
  .hero .shot { display: none; }
  .band { padding: 3.4rem 1.2rem; }
  .plate-cap { padding: 1.8rem 1.2rem 2.4rem; }
}

/* ---------------------------------------------------------------- legal pages */

.doc {
  max-width: 740px;
  margin: 0 auto;
  padding: 4rem 1.4rem 6rem;
}
.doc h1 { margin: 0 0 .4rem; font-size: clamp(1.9rem, 5vw, 2.7rem); }
.doc h2 { margin: 2.4rem 0 .7rem; font-size: 1.3rem; color: var(--amber); }
.doc h2::after { content: none; }
.doc p, .doc li { color: var(--cream-2); line-height: 1.75; }
.doc ul { padding-left: 1.2rem; }
.doc li { margin-bottom: .85rem; }
.doc strong { color: var(--cream); }
.doc-updated { font-size: .88rem; color: var(--ember-lit); }

.doc-back {
  display: inline-block; margin-top: 2.6rem;
  padding: .85rem 1.4rem;
  border: 1px solid var(--line); color: var(--cream);
  text-decoration: none; font-weight: 700; font-size: .88rem;
  letter-spacing: .1em; text-transform: uppercase;
}
.doc-back:hover { background: rgba(244,234,217,.08); color: var(--cream); border-color: var(--cream-2); }

/* Reduced motion is the one place the clip genuinely should not exist. Relative
   and not static, so .grain stays inside the hero instead of escaping to the
   page and laying film grain over the whole document. */
@media (prefers-reduced-motion: reduce) {
  .hero { position: relative; height: auto; }
  .hero .shot { display: none; }
  .hero .still { position: relative; inset: auto; width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: contain; }
  .cue { display: none; }
}
