/* mobile-frame.css — phone framing for the food photography. Loaded last.
   Phones only (max-width:740px). Desktop is deliberately untouched.

   Why this file exists: type-floor.css sets a 16px readability floor, which
   made every copy block taller. readability-finish.css then bought that room
   out of the pictures, twice over — it pushed the planes down
   (.dinner-plane top:max(285px,34svh), .brunch-plane top:max(328px,39svh))
   and grew .dish-photo figcaption from 54px to min-height:94px while shrinking
   the image to calc(100% - 94px). On a 360x698 phone the result was a
   193px dinner frame holding a 119x99 photo (33% of the screen), and a 150px
   brunch frame holding roughly 67x56 (19%). Meanwhile .chapter-image on the
   room and street chapters runs edge to edge.

   The food is what the restaurant sells, so it gets the same treatment the
   room already has. The type floor is left alone — the height comes back from
   the caption bar and the letterboxing instead. */

@media (max-width: 740px) {

  /* 1 — The photograph fills its frame, the way .chapter-image already does,
     instead of letterboxing inside it.

     :not(.dish-still) because these rules are for the PHOTOGRAPHS. The still
     behind a clip is not one - it is that clip's own poster frame, and its job
     is to sit at exactly the crop the clip uses so the reader cannot see the
     swap. The clip's object-position does not change at phone width; this
     block's does, and it would out-specify the still's rule and slide the
     fallback 9 points off the footage it stands in for. */
  .motion-ready:not(.reduced) .dish-photo img:not(.dish-still),
  .motion-ready:not(.reduced) .pour-plane img {
    height: 100%;
    object-fit: cover;
    object-position: 50% 50%;
  }

  /* Hold each dish in its crop. */
  .motion-ready:not(.reduced) .dinner-plane .photo-main img:not(.dish-still) { object-position: 50% 47%; }
  .motion-ready:not(.reduced) .dinner-plane .photo-next img { object-position: 50% 52%; }
  .motion-ready:not(.reduced) .brunch-plane .photo-third img { object-position: 50% 10%; } /* garnish sits at the top of this shot - it moved to dish three */
  .motion-ready:not(.reduced) .brunch-plane .photo-next img { object-position: 50% 46%; }
  .motion-ready:not(.reduced) .pour-plane img            { object-position: 50% 42%; }

  /* 2 — The caption rides on the photograph instead of taking a bite out of
     it. Reclaims the full 94px, and stays readable on the light brunch plane
     because it now sits on the picture rather than the plane's background.
     Same scrim recipe as .room-image:after. */
  .motion-ready:not(.reduced) .dish-photo figcaption,
  .motion-ready:not(.reduced) .pour-plane figcaption {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: auto;
    min-height: 0;
    padding: 34px 20px 13px;
    background: linear-gradient(0deg, #0e100fee 0%, #0e100fa6 46%, #0e100f00 100%);
    color: #fffaf0;
    z-index: 3;
    pointer-events: none;
  }
  .motion-ready:not(.reduced) .brunch-plane figcaption { color: #fffaf0; }
  .motion-ready:not(.reduced) .dish-photo figcaption > span:last-child,
  .motion-ready:not(.reduced) .brunch-plane figcaption > span:last-child { color: #d9d3c7; }

  /* 3 — Give the reclaimed height back to the frame. The svh terms carry the
     gap on taller phones, where the vw-scaled copy block grows; the px floors
     carry it on short ones. Both keep >=20px below the copy and >=13px above
     the menu picks row at 360x698 and 390x844 — headroom, not two pixels,
     because this copy is measured before the webfonts land. */
  .motion-ready:not(.reduced) .dinner-plane { top: max(262px, 33svh); bottom: 152px; }
  .motion-ready:not(.reduced) .brunch-plane { top: max(305px, 38svh); bottom: 152px; }

  /* 4 — The burger gets the same edges, and its caption stops being an opaque
     bar laid across the bottom of the picture. */
  .motion-ready:not(.reduced) .burger-visual { top: 35%; bottom: 48px; }
  .motion-ready:not(.reduced) .burger-visual figcaption {
    background: linear-gradient(0deg, #0e100fee 0%, #0e100fa8 60%, #0e100f00 100%);
    padding: 40px 0 12px;
    pointer-events: none;
  }
}

/* ---------------------------------------------------------------------------
   5 — The chapter rail stops being a box.

   On a phone the rail was spending 58px to show one word. Every link but the
   current one is already clipped to 1px there, so the 40px min-height was a
   tap target on something nobody can tap, sitting inside a bordered,
   blurred-backdrop panel directly under the picture.

   What stays is what earns the space: the chapter name that changes as you
   scroll, and the hairline progress fill beside it. Both ride on the imagery
   with a text shadow instead of a panel. The hidden chapter links keep their
   44px target when focused, so keyboard navigation is unchanged.

   That returns ~36px per chapter, and 3-4 below cascade it into the pictures.
   --------------------------------------------------------------------------- */

@media (max-width: 740px) {

  .motion-ready:not(.reduced) .chapter-rail {
    bottom: 12px;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: none;
    backdrop-filter: none;
    gap: 14px;
    text-shadow: 0 1px 7px #0e100fd9, 0 0 2px #0e100f80;
  }
  /* min-height:0 is correct here and needs no tap-target overlay. journey-v4.css
     visually hides every link but the current one - width:1px, overflow:hidden,
     clip-path:inset(50%) - so this is a progress label with a screen-reader nav
     behind it, not a touch control. An ::after was tried and removed: generated
     inside a 1px clipped box it is clipped away with its parent, so it enlarged
     only the current chapter's link, which leads where the reader already is,
     while swallowing taps over the photograph underneath. The :focus-visible
     rule below is what actually serves keyboard and screen-reader users. */
  .motion-ready:not(.reduced) .chapter-rail a { min-height: 0; }
  /* Keyboard users still get a full-size target when they reach it. */
  .motion-ready:not(.reduced) .chapter-rail a:not([aria-current]):focus-visible { min-height: 44px; }
  .motion-ready:not(.reduced) .rail-hint { display: none; }
  /* brand-palette.css forces `background:#f7f3eae8 !important` on the brunch
     chapter's rail. This file's `background:none` is not !important and loses,
     while its `padding:0` and `border:0` win - so brunch alone got a cream
     panel with no padding inside it. Kill the panel on that chapter too; the
     on-light colour change stays, because that chapter's imagery is light. */
  .motion-ready:not(.reduced) .chapter-rail.on-light {
    background: none !important;
    border-color: transparent !important;
    text-shadow: none;
  }

  /* The freed height, handed down the stack. */
  .motion-ready:not(.reduced) .menu-picks,
  .motion-ready:not(.reduced) .morning-chapter .menu-picks { bottom: 46px; }

  .motion-ready:not(.reduced) .dinner-plane,
  .motion-ready:not(.reduced) .brunch-plane { bottom: 128px; }

  .motion-ready:not(.reduced) .pour-plane { bottom: 56px; }

  /* The hero takes its share from both ends. Growing upward is safe because
     the intro copy has faded out by p=0.082, while the sequence does not
     really start until p=0.073 - so the headline only ever sits over the
     assembled frame, whose top bands measure 46-53 luminance. */
  .motion-ready:not(.reduced) .burger-visual { top: 31%; bottom: 42px; }
}

/* ---- 6. Tap targets (pre-owner-review mobile pass) -------------------------
   A 21px-tall "Call to confirm" is a conversion action, not decoration. Give it
   touch area through an overlay with no layout box so the type and rule stay
   exactly as designed. */

@media (max-width: 740px) {
  .hours-call { position: relative; }
  .hours-call::after {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    top: 50%;
    transform: translateY(-50%);
    height: 44px;
  }
}

/* ---- 7. BLOCKER: menu dialog close control ---------------------------------
   .close-button is authored `position: sticky; top: 16px`, but
   readability-finish.css sets `.menu-top, .menu-header { position: static }`,
   and sticky is bounded by its containing block - an 88px header that scrolls
   away. The dialog is the scroller and runs to 5224px, so the button measured
   -2434px at scrollTop 2500 with elementFromPoint null, while the sticky tab
   bar stayed pinned and made the screen look complete. Backdrop-click dismiss
   is dead code here because the dialog is full-bleed.

   The dialog is exactly innerWidth x innerHeight at this width, so `fixed`
   pins it to the dialog. z-index clears .menu-tabs (z-index 2), and the tab
   bar gets right padding so "Drinks" no longer runs underneath the button. */

@media (max-width: 740px) {
  #menu-close {
    position: fixed;
    top: 16px;
    right: 18px;
    z-index: 40;
  }
  .menu-tabs { padding-right: 62px; }
}

/* Section 7 side effects, caught at the 320 floor and at the top of the sheet.

   .menu-tabs is a 276px flex row whose buttons are flex:1, so they divide
   whatever the container's content box gives them - the right padding is
   exactly what holds them off the fixed button. At 320 the 48px button lands
   at 254 while the row still reaches 280, covering 26px of "Drinks"; the
   dialog h2 runs under it too, and even at 360 the h2 cleared by only 3px.

   So: give the heading real room at every phone width, and at the 320 floor
   use a smaller button, tighter button padding, and MORE right padding on the
   row, not less. (A first attempt set that padding to 0 on the theory that it
   was inert; it is not - that widened the row to 298 and made the overlap
   worse.) */

@media (max-width: 740px) {
  .menu-top { padding-right: 58px; }
}

@media (max-width: 359px) {
  #menu-close { width: 40px; height: 40px; top: 12px; right: 10px; }
  .menu-tabs { padding-right: 48px; }
  .menu-tabs button { padding-left: 9px; padding-right: 9px; }
}

/* ---- 8. The storefront crop cuts the business name -------------------------
   venue-exterior.webp is 1800x966. On a 390-wide phone `object-fit: cover`
   scales it to 1573x844 - the full height, but only 447 of the 1800 source
   pixels across. journey-v4.css puts that window at `object-position: 58%`,
   which spans source x 785-1232. The sign runs 680-1120, so the window opened
   105px inside it: the name rendered as "HE VICTORY TAP" and the phone decal
   on the door was cut mid-digits.

   The sign is 440px wide and the window is 447px, so it fits - but only when
   the window is centred on it. 50% spans 676-1123 and takes the whole sign,
   the decal and both lamps. This is the one chapter whose photograph has to
   carry the business's name, so it is worth the eight points. */
@media (max-width: 740px) {
  .street-image img { object-position: 50% center; }
}

/* ---- 9. The brunch chapter's moving dish ----------------------------------
   .photo-third holds a <video>, not an <img>, and seven stylesheets style
   `.dish-photo img` without ever mentioning video. Rather than chase that
   cascade through all of them, the video is positioned to fill its figure
   outright and the caption is lifted above it. The caption already carries a
   solid background on desktop and a gradient scrim on phones, so it reads the
   same over moving footage as it does over a still.

   object-fit:cover is deliberate. journey-v4.css sets `contain` for the stills;
   this clip is 720x1280 and the frame is close to square, so a centred cover
   crop lands the plate edge-to-edge and drops the empty counter above and
   below it. Verified against the real box (350x371 at 390 wide). */
.dish-photo video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* 62%, not centre. The real frame is 360x282 at 360 wide - wider than it is
     tall - so a centred crop of a 720x1280 source cuts the sauce pool off at
     the bottom edge. Biasing down keeps the plate rim and the whole pour in
     frame. Per-dish object-position is already how this sheet frames the
     stills above; this is the same treatment.

     Moved 54% -> 44% on 2026-09-18, when the clips were replaced with
     watermarked masters. The "DGENIUS PREVIEW" overlay DOES NOT SIT STILL: it
     cycles through fixed positions across the clip, appearing and vanishing
     rather than staying put. On this clip those are y 158-217, 309-367,
     529-602 and 809-867. At 54% the window opened at y 362 and sliced the
     309-367 position in half along its top edge, which reads as a broken
     render rather than as a watermark. 44% opens at y ~295: that position now
     clears, 529-602 and 809-867 stay inside, and 158-217 falls wholly above
     the window - absent for that stretch of the loop, which is fine, where a
     half-cut line is not. The plate still carries the frame.

     Measure every position before touching these numbers. A single-frame check
     passes a page that is slicing a different position - that is exactly how
     the 54% value survived its first review. tools/watermark.mjs checks all of
     them. Every .dish-still rule below moves with this or the still and the
     clip stop being pixel-aligned and the swap visibly jumps. */
  object-position: 50% 44%;
  filter: saturate(.96) contrast(1.025);
}
.dish-photo figcaption { z-index: 2; }

/* Reduced motion and the no-JS fallback lay the stack out as a grid of
   flowed figures, so the video has to stop filling an absolute box and
   become an ordinary block - the same thing journey-v4.css does for img.
   It is never played in that mode; readers see the poster frame, which is
   the correct still for a reader who asked not to be moved. */
.reduced .dish-photo video,
html:not(.motion-ready) .dish-photo video {
  position: relative;
  inset: auto;
  height: auto;
  /* The stills beside them are 1.33 and 1.20 wide-to-tall; both clips are
     720x1280, i.e. 0.56. In the fallback's two-column grid `height:auto` lets
     the intrinsic aspect drive layout, so a clip cell came out well over twice
     the height of the photograph next to it and stretched its grid row with a
     column of dead space beside it. Pin the tile to 5/4 - between the two
     neighbouring stills - and let cover crop to it, which is what the moving
     version does anyway. */
  aspect-ratio: 5 / 4;
  object-fit: cover;
}

/* journey-v4.css gives .photo-next `z-index:2` so it can slide over
   .photo-main. A positioned z-index:2 paints above a positioned z-index:auto
   whatever the DOM order, so dish two was covering dish three even with dish
   three seated at translateY(0) and its clip decoding and playing. It looked
   exactly like a video that would not render. Dish three sits one layer up.

   Its starting transform has to be declared here too: v4 sets
   `transform:translateX(102%)` on .photo-next only, so before the first frame
   of script runs, .photo-third would sit at translateY(0) - on top of dish
   one - rather than parked below the frame. */
.photo-main  { z-index: 1; }
.photo-third { z-index: 3; transform: translateY(102%); }

/* With all three figures carrying an explicit z-index, each one is its own
   stacking context, so a figcaption's z-index competes only inside its own
   figure - against that figure's video - instead of against the other dishes.
   Raising the caption globally instead would have put dish one's and dish
   two's captions back over dish three: the same bug one layer up. */

/* The cheesesteak clip is 720x1280, and the frame it plays in is 360x325 at
   360 wide, 390x372 at 390, 414x407 at 414 - close to square every time. Cover
   therefore shows only about 650 of the source's 1280 rows, so where that
   window sits decides the shot. Rendered at the tightest of the three boxes at
   30 / 38 / 46 / 54%: below 38 the top of the hoagie roll is cut, above it the
   frame fills with fries and tray. 38% keeps the roll whole, puts the sauce
   pour across the middle, and brings the red-checkered liner in at the bottom
   by the last second - the same liner S5's photograph is shot on. */
/* 40%, not 38%. The watermark on these clips does not sit still - it cycles
   through fixed positions over the clip rather than staying put. On the
   cheesesteak those are y 169-227, y 809-867 and y 448-522. At 38% the window
   opened at y 225 on a 390-wide phone, so the first of those cleared the edge
   by two pixels and left a hairline of letter-bottoms pinned to the top of the
   figure. 40% opens at y ~237 and drops it cleanly out of view, while keeping
   the other two positions fully inside at 360, 390 and 1280. */
.dinner-plane .photo-main video { object-position: 50% 40%; }

/* ---- 10. The clip fails open ----------------------------------------------
   Reported on Chrome/Linux: the cheesesteak showed for about half a second in
   six, and the rest of the time the figure was empty. Measured off the
   screencast, the dish area sat at a flat rgb(36,41,49) with a standard
   deviation of 0.3 and 22 distinct colours - that is .dish-photo's own
   background, not a dark frame of footage (a real frame measures 72,084
   colours). So the element was painting NOTHING and the page showed through.

   The cause is downstream of us - hardware H.264 presentation on that machine,
   which a software-rendered headless Chromium cannot reproduce - but the hole
   is ours: once play() runs the poster attribute is gone for good, so any
   failure to present leaves the figure empty with readyState 4, no error
   fired, and currentTime still advancing. Nothing in the element's own API
   says "you are showing the reader a blank box".

   So invert it. The still is the default and always painted; the clip is laid
   over it and revealed only on PROOF that a frame reached the screen
   (site.js, watchPresentation). No proof, or proof that stops arriving
   mid-play, and the reader sees the photograph instead of a hole. The still
   is the clip's own poster frame, so the swap is the same dish at the same
   crop rather than a different picture appearing.

   The geometry below mirrors `.dish-photo video` exactly - same cover, same
   per-dish object-position, same filter - so the two are pixel-aligned and
   nothing shifts when one replaces the other. It needs its own class because
   `.dish-photo img` is styled by seven stylesheets with object-fit:contain,
   and a contained still under a covered clip would letterbox on the swap. */
.dish-photo .dish-still {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 44%;
  filter: saturate(.96) contrast(1.025);
}
.dinner-plane .photo-main .dish-still { object-position: 50% 40%; }  /* mirrors the video above */

.dish-photo video { opacity: 0; transition: opacity .18s linear; }
.dish-photo video.is-presenting { opacity: 1; }

/* Reduced motion and the no-JS fallback already showed a still - the poster
   frame - so with a real <img> present the video element has no job at all
   there. Hiding it outright is simpler than keeping two elements in one grid
   cell, and the still inherits the 5/4 tile the clip used to carry. */
.reduced .dish-photo video,
html:not(.motion-ready) .dish-photo video { display: none; }
.reduced .dish-photo .dish-still,
html:not(.motion-ready) .dish-photo .dish-still {
  position: relative;
  inset: auto;
  height: auto;
  aspect-ratio: 5 / 4;
  object-fit: cover;
}

/* ---- 11. Give the dish back the height the label was taking ---------------
   Reported: "for the French toast we can't see the whole thing." Measured at
   390 wide, the brunch dish figure is 390x330 and its caption was **123px** of
   that - 37% of the picture spent on a label, leaving 207px of clear dish. The
   clip is 720x1280, so at cover scale .54 that is 382 of its 1280 rows: the
   reader got a third of the plate.

   readability-finish.css is what makes it three lines - it floors the caption
   at 94px, forces the counter onto its own line, and raises the type. That pass
   is right about body copy and wrong here: a dish caption is a label, not
   something anyone reads at length, and this is the one element on the page
   whose whole job is the photograph. Same shape as the hero-shrinking that pass
   has caused before.

   The clip already fills the figure with the caption riding over it, so every
   pixel the caption gives up is a pixel of dish - no other rule has to change. */
@media (max-width: 740px) {
  .motion-ready:not(.reduced) .dish-photo figcaption {
    min-height: 0;
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: 4px 12px;
    padding: 9px 16px;
    line-height: 1.3;
  }
  .motion-ready:not(.reduced) .dish-photo figcaption > span:first-child {
    font-size: .8125rem;
    letter-spacing: .02em;
  }
  /* back onto the title's line, where it costs nothing */
  .motion-ready:not(.reduced) .dish-photo figcaption > span:last-child {
    display: inline;
    margin-top: 0;
    white-space: nowrap;
    font-size: .75rem;
  }
}

/* ---- 12. Short phones were crushing the dish ------------------------------
   Reported from a real phone with a picture, after the caption fix had already
   shipped: the French toast was still a tight band. Measured, the frame on that
   phone is about 1.78 wide-to-tall; every width tested here rendered it at
   1.10-1.28. The difference is viewport HEIGHT, which nothing in the test matrix
   varied - 360x780 and 390x844 are both generous.

   At 360x690 the brunch dish figure comes out 360x192 and shows 231 of the
   clip's 1280 rows - 18%, against 30-43% on a taller phone. readability-finish
   floors the plane at `top:max(328px,39svh)`, and journey-v4 holds it off the
   bottom by 160px; on a 690px screen those two fixed numbers take 488 of it and
   the picture lives on what is left. The floor is there to protect the copy, so
   it cannot simply be removed - the copy has to give the pixels back first.

   Everything below the dish is immovable: the menu picks start 6px under the
   plane and the rail and dock are behind them. So the dish grows UPWARD only,
   out of the copy block and its own caption. Held to short viewports, because
   on a tall phone the current spacing is right and the dish already has room. */
@media (max-width: 740px) and (max-height: 800px) {

  /* Tighten the copy first - the plane cannot move up into space that is
     still occupied. Margins only; no type is shrunk, so nothing gets harder
     to read, which is the trade readability-finish was making in reverse. */
  .morning-copy h2 { margin-bottom: 8px; }
  .morning-copy .lede { margin-bottom: 8px; }
  .brunch-hours { margin-top: 9px; line-height: 1.5; }

  /* Then take the space. clamp() instead of max(): the old floor could only
     push the plane DOWN on a short screen, which is the wrong direction. */
  .motion-ready:not(.reduced) .brunch-plane { top: clamp(272px, 36svh, 305px); }
  /* The dinner plane is deliberately NOT moved. Tried it, and it put the food
     chapter's copy 28px underneath its own dish at 360x690 - the plane carries
     z-index 2, so the copy goes under the picture. That chapter's dish already
     gets 31-52% of its clip and is not the one that was reported. */

  /* And the caption, which was 77px of a 192px figure - 40% of the picture.
     One line of title where it fits, and the counter stays on it. */
  .motion-ready:not(.reduced) .dish-photo figcaption {
    padding: 6px 14px;
    line-height: 1.25;
  }
  .motion-ready:not(.reduced) .dish-photo figcaption > span:first-child {
    font-size: .6875rem;
    letter-spacing: .015em;
  }
  .motion-ready:not(.reduced) .dish-photo figcaption > span:last-child {
    font-size: .625rem;
  }
}

/* ---- 13. The brunch clip leads the chapter --------------------------------
   The French toast moved from .photo-third to .photo-main so that tapping
   Brunch lands on it. Measured before the move: at 390 wide a reader scrolling
   normally had it on screen and playing for 0.6s, because dish three arrives as
   the chapter is already ending. The chapter's only moving picture, and the one
   with the strongest first-party quote behind it, was the one nobody saw.

   The slots are machinery, not content - .photo-main is the base layer,
   .photo-next slides over it, .photo-third rises last - so only the content
   swapped. But two sheets crop `.brunch-plane .photo-main img` for the savoury
   photograph that used to sit there, and at (0,2,1) they out-specify the
   `.dish-photo .dish-still` rule that keeps a clip's fallback aligned to the
   clip. Left alone, the toast's still would jump to `center top` on the swap -
   the same cascade trap as section 11, one slot over. */
.brunch-plane .photo-main .dish-still,
.motion-ready:not(.reduced) .brunch-plane .photo-main .dish-still {
  object-position: 50% 44%;
}

/* ---------------------------------------------------------------------------
   14. Still mode: no plane keeps a motion-layout offset

   journey-v4 already resets the planes for Still with
   `.reduced .photo-plane{position:relative;inset:auto;...}`, which is correct.
   But brand-palette.css:249 carries `.morning-chapter .brunch-plane{top:35svh}`
   with no `:not(.reduced)` guard - the only plane-top rule in the build without
   one - and it sits in a later sheet at equal specificity (0,2,0), so it wins.

   In Still that computed to `position:relative; top:295.4px` at 390x844. A
   relative offset moves paint but not layout, so it produced BOTH halves of the
   defect at once: a 359px band of nothing between the brunch copy and the first
   dish, and `.menu-picks` flowing at the plane's un-offset position, i.e. on top
   of the photos it should follow.

   Fixed here rather than by adding `:not(.reduced)` in brand-palette, because
   that selector would become (0,4,0) and out-specify the motion tuning in
   section 12 of this file, which is meant to win. `html.reduced` is (0,2,1),
   so it beats the ungated rule on specificity alone and does not depend on
   sheet order. Applies to every plane, so a later sheet repeating the mistake
   on the dinner plane is covered too. Motion mode is untouched.            */
html.reduced .photo-plane,
html:not(.motion-ready) .photo-plane { top: auto; bottom: auto; }

/* ---------------------------------------------------------------------------
   15. Still mode: the brunch dish counters were invisible

   Reported: "where it says 01, you can barely see those numbers."

   The brunch caption is the only one on a light panel. journey-v4 handles that
   correctly - `.brunch-plane figcaption{background:#e5e0d4;color:#34352f}` with
   `>span:last-child{color:#59564e}`, a muted grey-brown for the counter so it
   reads as secondary to the dish name. brand-palette.css:84 then sets

       .dish-photo figcaption > span:last-child,
       .menu-picks p, .bite-footer { color: #d0c9bd; }

   which is the right colour for the DARK food captions and wrong for this one.
   Both selectors are (0,2,2); brand-palette is the later sheet, so it wins and
   repaints the counter light-on-cream. Measured: 1.29:1. Effectively invisible,
   which is exactly what was reported.

   Motion mode is NOT affected and must not be touched: there the caption is
   transparent over a dark gradient scrim (section 2 of this file), so the light
   #d9d3c7 counter is correct there. Hence the `html.reduced` scope.

   Restores journey-v4's intended value rather than inventing one: 5.74:1 on the
   cream, against 11.40:1 for the dish name above it, so the hierarchy the
   design wanted survives. A darker 7.3:1 was rendered and rejected - it reads
   as a second title rather than a counter.                                  */
html.reduced .brunch-plane figcaption > span:last-child,
html:not(.motion-ready) .brunch-plane figcaption > span:last-child { color: #59564e; }

/* ---------------------------------------------------------------------------
   16. The last three tap targets under 44px

   Found while auditing Still, but none of these are Still-only - the visit
   block and the footer sit outside .experience and render in both modes, so
   this section is deliberately NOT scoped to .reduced.

   Measured by hit-testing outward from each control's centre in 1px steps.
   (2px steps under-report by up to 4px and previously reported the already-
   fixed .hours-call, "Enable motion" and "Back to top" as failures. They are
   44px and always were - see section 6.)

     .menu-picks a        43px - one pixel short
     .hours-note a             22px - an inline tel: link inside a sentence
     .brunch-hours a           22px - the same, in the brunch chapter
     .site-footer .footer-top a  38px

   The inline phone link gets touch area the same way section 6 gives it to
   .hours-call: an overlay with no layout box, so the sentence keeps its exact
   line breaks and rhythm. Its ::after is bounded by the link's own inline box,
   so it is ~107px wide rather than the full column, and the only thing it can
   overlap is body text of the same paragraph - which is not itself tappable. */

@media (max-width: 740px) {
  .menu-picks a { min-height: 44px; }

  .hours-note a,
  .brunch-hours a { position: relative; }
  .hours-note a::after,
  .brunch-hours a::after {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    top: 50%;
    transform: translateY(-50%);
    height: 44px;
  }

  .site-footer .footer-top a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }
}

/* 17. A phone number must never break across lines.
 *
 * "512-358-6150" carries two hyphens, and a hyphen is a line-break
 * opportunity. At 360px (a folded Z Fold, among others) the number inside
 * .hours-note wrapped, so the link's bounding box spanned two lines - and its
 * CENTRE landed in the leading between them, on the paragraph rather than on
 * either fragment of the link. The 44px ::after from 16 is positioned against
 * that same box, so it sat in the gap too: the hit test found P.hours-note and
 * the control measured 1px. It looked perfectly fine at 390px, which is why
 * this only shows up on the narrow rung.
 *
 * Holding the number together fixes the tap target and the typography in one
 * go, and it is right at every width, so it is not scoped to a breakpoint. */
a[href^="tel:"] { white-space: nowrap; }

/* Phone gate, 2026-09-23 */
/* 200% text: the visit grid's columns took the width of the unbreakable e-mail address and pushed the
   address and the party line past the screen edge inside an overflow:hidden section; the menu dialog
   scrolled sideways on a nowrap line and a non-wrapping tab row. */
.visit-grid > * { min-width: 0; }
.visit-grid a[href^="mailto:"] { overflow-wrap: anywhere; }
.menu-meta > p:last-child { white-space: normal; }
.menu-tabs { flex-wrap: wrap; }
/* Reduced motion: the first chapter's eyebrow sat behind the fixed header. */
html.reduced .journey-stage .chapter:first-child { padding-top: 150px; }
@media (max-width: 740px) { html.reduced .journey-stage .chapter:first-child { padding-top: 124px; } }
/* Narrow dock: keep every label on one line so the dock stays inside its 65px strip; 44px close. */
@media (max-width: 330px) {
  .mobile-dock > a, .mobile-dock > button { white-space: nowrap; padding: 10px 4px !important; font-size: 14px !important; }
}
@media (max-width: 359px) { #menu-close { width: 44px; height: 44px; } }
/* The caption band runs edge to edge like the photograph under it; the 22px stays as inner padding
   so the text still lines up with the chapter copy. */
@media (max-width: 740px) {
  .motion-ready:not(.reduced) .burger-visual figcaption { left: 0; right: 0; padding-left: 22px; padding-right: 22px; }
}
