/* ==========================================================================
   Header states

   .p-header             transparent, overlays the hero (position: absolute)
   .p-header.inner       in-flow layout (position: relative) - LAYOUT ONLY, set per page
   .p-header.is-solid    solid paint - static on inner pages, added on scroll on hero pages
   .p-header.is-sticky   compact bar - added on scroll on both page types

   Replaces the per-element modifiers from the original export
   (.inner / .with-bg / .white-bg / .inner-link / .inner-nav-btn / .is-hide).
   Lives here, not in pepers-cc0900.webflow.css, which is overwritten on re-export.
   ========================================================================== */

/* Transitions go on the base elements so the state animates in BOTH directions.
   Putting them inside .is-solid / .is-sticky would make removal snap. */
.p-header {
  transition: background-color .25s ease;
}

.p-nav-container {
  transition: all .25s ease;
}

.p-nav-wrapper {
  transition: background-color .25s ease, border-radius .25s ease,
              height .25s ease, padding .25s ease;

  max-width: 1320px;
  margin-left: auto;
  margin-right: auto;
}

.p-nav-logo-block {
  transition: background-color .25s ease, border-radius .25s ease,
              height .25s ease, padding .25s ease;
}

.p-nav-logo-white,
.p-nav-logo-black {
  transition: max-height .25s ease;
}

.p-navbar {
  transition: all .25s ease;
}

.p-nav-link,
.p-nav-btn {
  transition: background-color .25s ease, color .25s ease;
}

/* --- solid state --- */
/* No background on .p-header itself. Inner pages still read yellow because
   .p-header.inner paints it in pepers-cc0900.webflow.css; hero pages stay
   transparent and only the nav pill and logo badge carry colour. */

.p-header.is-solid .p-nav-wrapper {
  background-color: var(--white);
}

.p-header.is-solid .p-nav-link {
  color: #000;
}

.p-header.is-solid .p-nav-btn {
  background-color: var(--black);
  box-shadow: none;
  color: var(--white);
}

.p-header.is-solid .p-nav-btn:hover {
  color: var(--hover);
}

.p-header.is-solid .p-nav-logo-block {
  background-color: var(--brand-color);
}

/* --- logo swap: both logos always in the DOM, state decides --- */
.p-nav-logo-black {
  display: none;
}

.p-header.is-solid .p-nav-logo-white {
  display: none;
}

.p-header.is-solid .p-nav-logo-black {
  display: block;
}

/* --- solid state: tablet / mobile inverts the palette ---
   AT REST only. Inner pages carry .is-solid from page load, so nothing here
   may describe the scrolled look - that lives in the .is-sticky block below. */
@media screen and (max-width: 991px) {
  .p-header.is-solid .p-navbar {
    background-color: var(--brand-color);
  }

  .p-header.is-solid .p-nav-wrapper {
    background-color: #0000;
  }

  /* The export already makes the logo badge transparent below 991px; the
     .is-solid rule further up overrides it back to yellow. Harmless while the
     bar is also yellow, but wrong the moment it is not. */
  .p-header.is-solid .p-nav-logo-block {
    background-color: #0000;
  }

  .p-header.is-solid .p-nav-link {
    color: var(--white);
  }

  .p-header.is-solid .p-nav-btn {
    background-color: var(--brand-color);
    height: 50px;
    color: var(--black);
    font-size: 28px;
  }

  .p-header.is-solid .p-nav-btn:hover {
    background-color: var(--hover);
  }

  .menu-btn-wrap {
    width: auto;
    padding-right: 16px;
    padding-left: 16px;
  }
}

/* --- sticky state: compact, square, full-bleed ---
   Added on scroll on BOTH page types (see include/javascript.php).
   At rest the nav is a floating rounded pill inside a 1360px container;
   scrolled it becomes an edge-to-edge bar. The logo block is 90px at rest
   and has to come down with it or it overhangs a 60px bar.

   Note there is deliberately no `.p-header { min-height: 60px }` here.
   .p-navbar is position:fixed, so on inner pages .p-header is purely the
   spacer reserving its place in flow - shrinking it 148px -> 60px would pull
   every following element up 88px mid-scroll. The bar is moved instead. */

/* 100% rather than none so the width animates instead of snapping */
.p-header.is-sticky .p-nav-container {
  max-width: 100%;
  padding-left: 0;
  padding-right: 0;
  background-color: var(--white);
  box-shadow: 0px 5px 0px 0px rgba(0, 0, 0, 0.2);
}

.p-header.is-sticky .p-nav-wrapper {
  border-radius: 0;
  height: 60px;
  padding-top: 0;
  padding-bottom: 0;
  padding-left: 0;
}


.p-header.is-sticky .p-nav-logo-block {
  border-radius: 0;
  height: 60px;
  padding-top: 0;
  padding-bottom: 0;
  background: none;
}


.p-header.is-sticky .p-nav-logo-white,
.p-header.is-sticky .p-nav-logo-black {
  max-height: 44px;
}

/* --- no hover on touch ---
   On a touch screen :hover fires on tap and sticks until you tap elsewhere, so
   .p-nav-link:hover (background-color: #febe10, in the export) flashes a yellow
   pill on every tap - very visible against the black mobile panel.

   This is gated on pointer capability, not a breakpoint: recursivePagesOnFrontEnd()
   emits the same "p-nav-link w-nav-link" for the desktop bar AND the panel, so a
   media width query cannot tell them apart. Devices with a real pointer keep the
   hover. Same specificity as the export rule (0,2,0), and site-custom.css loads
   last, so this wins. */
@media (hover: none) {
  .p-nav-link:hover {
    background-color: #0000;
  }
}

/* --- sticky state on mobile: the compact white bar ---
   Everything here is SCROLLED-only. At rest an inner page keeps the yellow
   band from .p-header.inner; white would show a white bar with the remainder
   of that band as a yellow strip underneath it. */
@media screen and (max-width: 991px) {
  .p-header.is-sticky .p-navbar {
    background-color: var(--white);
    min-height: 60px;
  }

  .p-header.is-sticky .p-nav-logo-block {
    height: 60px;
    background-color: #0000;
  }

  /* Black bars on the white sticky bar */
  .p-header.is-sticky .menu-btn-icon {
    color: var(--black);
  }

  /* Only the black logo is targeted: .is-sticky always arrives alongside
     .is-solid, which hides the white one. Must sit after the shared
     .is-sticky max-height rule above to win the tie. */
  .p-header.is-sticky .p-nav-logo-black {
    max-height: 40px;
    width: auto;
    padding-left: 20px;
  }
}

/* Only above 991px does .p-header carry the 2.5rem top padding that the fixed
   .p-navbar sits below; at 991px and under that padding is already 0, so the
   bar is at the viewport edge and must not be lifted again.
   .p-navbar already ships transition: transform .3s, so this animates free. */
@media screen and (min-width: 992px) {
  .p-header.is-sticky .p-navbar {
    transform: translateY(-2.5rem);
  }
}


/* ==========================================================================
   Content pages - terms / privacy-policy / allergens

   No Peppers design exists for these yet. This is a readable baseline built
   from the existing tokens: Rocgrotesk for display, Libre Franklin for body,
   brand yellow for accents. Replace wholesale when a real design lands.
   The classes come from the original build; their rules lived in a
   stylesheet that is no longer loaded.
   ========================================================================== */

.pp-hero-section {
  padding-top: 3.5rem;
  padding-bottom: 2rem;
}

.franchise_hero-heading {
  margin: 0;
  font-family: Rocgrotesk, Arial, sans-serif;
  font-size: 3rem;
  font-weight: 900;
  line-height: .9;
  text-transform: uppercase;
}

.pp_section {
  padding-bottom: 5rem;
}

/* .container is 1360px - far too wide to read long-form copy against */
.pp-content-wrapper {
  max-width: 820px;
  margin: 0 auto;
}

.pp-title {
  margin-bottom: .75rem;
  font-family: Rocgrotesk, Arial, sans-serif;
  font-size: 1.5rem;
  font-weight: 700;
  line-height: 1.2;
  text-transform: uppercase;
}

.pp-body-text {
  margin: 0 0 1rem;
  font-family: Libre Franklin, sans-serif;
  font-size: 1rem;
  line-height: 1.7;
}

.pp-body-text:last-child {
  margin-bottom: 0;
}

/* Underline is always present, so colour is never the only affordance */
.link-text {
  color: var(--black);
  text-decoration: underline;
  transition: color .2s ease;
}

.link-text:hover {
  color: var(--hover);
}

/* Scoped, not global: .mb-2 is live on careers/franchise as a no-op and must stay one */
.pp-content-wrapper .mb-4 {
  margin-bottom: 1.5rem;
}

.pp-content-wrapper .mb-5 {
  margin-bottom: 3rem;
}

@media screen and (max-width: 767px) {
  .pp-hero-section {
    padding-top: 2.5rem;
    padding-bottom: 1.5rem;
  }

  .franchise_hero-heading {
    font-size: 2.125rem;
  }

  .pp_section {
    padding-bottom: 3rem;
  }
}


/* ==========================================================================
   404 - pageNotFound.php

   No design exists for this page. Built from the same tokens as everything
   else: Rocgrotesk display, Libre Franklin body, brand yellow field, and the
   existing .p-primary-btn (white, black border, offset shadow) which reads
   well against the yellow.
   ========================================================================== */

.p-404-section {
  display: flex;
  align-items: center;
  min-height: 46vh;
  padding-top: 4rem;
  padding-bottom: 6rem;
}

/* .container becomes a flex item here and would otherwise shrink to content */
.p-404-section > .container {
  width: 100%;
}

.p-404-block {
  max-width: 760px;
  margin-left: auto;
  margin-right: auto;
  text-align: center;
}

.p-404-code {
  font-family: Rocgrotesk, Arial, sans-serif;
  font-size: 11rem;
  font-weight: 900;
  line-height: .8;
  letter-spacing: -.02em;
}

.p-404-heading {
  margin: 1.5rem 0 0;
  font-family: Rocgrotesk, Arial, sans-serif;
  font-size: 3rem;
  font-weight: 900;
  line-height: .9;
  text-transform: uppercase;
}

.p-404-text {
  margin: 1rem 0 0;
  font-family: Libre Franklin, sans-serif;
  font-size: 1.125rem;
  line-height: 1.5;
}

.p-404-actions {
  flex-wrap: wrap;
  justify-content: center;
  gap: 1rem;
  margin-top: 2.5rem;
  display: flex;
}

/* .p-primary-btn is flex:1 in its normal context - stop it stretching here */
.p-404-actions .p-primary-btn {
  flex: 0 0 auto;
}

@media screen and (max-width: 767px) {
  .p-404-section {
    min-height: 0;
    padding-top: 2.5rem;
    padding-bottom: 4rem;
  }

  .p-404-code {
    font-size: 6.5rem;
  }

  .p-404-heading {
    font-size: 2.125rem;
  }

  .p-404-text {
    font-size: 1rem;
  }

  .p-404-actions {
    gap: .75rem;
  }
}


/* ==========================================================================
   Home slider
   ========================================================================== */

/* The CTA lives inside each slide now, so the slider is 57px taller
   (.p-btn = 20px line + 33px padding + 4px border). Pull the dots back by
   the same amount to keep them where the export put them. */
.p-slide-nav {
  bottom: -55px;
}


/* ==========================================================================
   Form validation state

   Driven off aria-invalid on the offending field, never off a state class:
     - #home-location-query : index.php showError()/clearError() already set it
     - #postcode            : locations.php showError()/clearError()
     - newsletter email     : include/javascript.php setInvalid()
   Screen readers get the same signal for free. Any form added later only has
   to keep aria-invalid in step with its error box to pick this up.
   ========================================================================== */

/* Feedback pills.

   The export ships .w-form-fail as a full-width #ffdede block and .w-form-done as
   a full-width centred #dddddd block, both in normal flow. These override that.
   position:absolute with no offsets keeps each box at its static position but
   out of flow, so showing a message overlays what follows instead of reflowing
   the section around the form.

   The newsletter boxes carry no id. The success box is still a sibling of the
   form; the error box is moved INSIDE the form by include/javascript.php (see
   there for why), hence the descendant selector for one and the sibling
   combinator for the other.

   Geometry is shared so success and error land in exactly the same place;
   only the palette differs. margin-top is set explicitly because the export gives
   .w-form-fail 10px and .w-form-done none, which would offset them by 10px. */
#home-location-feedback,
.js-newsletter-form .w-form-fail,
.js-newsletter-form ~ .w-form-done {
  position: absolute;
  margin-top: 10px;
  border-radius: 20px;
  padding: 10px 16px 10px 16px;
  text-align: left;
  font-weight: 600;
}

/* Anchor the moved error box to the form rather than to its static position,
   which after the move would be mid-row between the field and the button. */
.js-newsletter-form {
  position: relative;
}

.js-newsletter-form .w-form-fail {
  top: 100%;
  left: 0;
}

/* Black, not white: white on #ff6e6e is 2.7:1 and fails WCAG AA, and error copy
   is the last thing that should be hard to read. Black gives 7.7:1 and matches
   the success pill below. */
#home-location-feedback,
.js-newsletter-form .w-form-fail {
  background: #ff6e6e;
  color: var(--black);
  background: none;
  color: #ff6e6e;
}

/* Match .p-form, which the export drops to 8px here */
@media screen and (max-width: 767px) {
  #home-location-feedback,
  .js-newsletter-form .w-form-fail,
  .js-newsletter-form ~ .w-form-done {
    border-radius: 8px;
    width: 100%;
  }
}

/* At 479px the export stacks .p-form into a transparent column, so an
   out-of-flow error still lands below the submit button. Let it take flow
   between the field and the button instead.
   (The matching outline change lives after the outline rules below - it has
   to, or the later base rule wins the specificity tie.) */
@media screen and (max-width: 479px) {
  .js-newsletter-form .w-form-fail {
    position: static;
    margin-top: 0;
  }
}

/* Both newsletter forms sit on black - .p-footer is #000 and the home signup
   section is covered by bottom_black_shape.svg - so brand yellow is the
   strongest reading here, and it is the site's own pairing (ORDER button,
   logo badge). Black on #febe10 is 12.6:1. */
/* In flow, unlike the error box. It already sits after the form in the DOM, so
   static puts it under the whole form and lets it push what follows down -
   which is fine for a message that dismisses itself a few seconds later. */
.js-newsletter-form ~ .w-form-done {
  position: static;
  background: var(--brand-color);
  color: var(--black);
  transition: opacity .3s ease;
  background: none;
  color: #fff;
}

/* Auto-dismiss fade. .is-dismissing is added ~7s after a successful subscribe
   by include/javascript.php, which then sets display:none once this finishes -
   keep the duration and the FADE constant there in step. */
.js-newsletter-form ~ .w-form-done.is-dismissing {
  opacity: 0;
}

/* Transparent outline at rest so the error fades in rather than snapping.
   Outlines take no layout space, so this shifts nothing.
   .js-newsletter-form covers both #home-newsletter-form and
   #footer-newsletter-form - one component, one shared handler. */
#home-location-search,
#email-form-2,
.js-newsletter-form {
  outline: 3px solid #0000;
  outline-offset: 0px;
  transition: outline-color .2s ease;
}

#home-location-search:has(#home-location-query[aria-invalid="true"]),
#email-form-2:has(#postcode[aria-invalid="true"]),
.js-newsletter-form:has([aria-invalid="true"]) {
  outline-color: #ff6e6e;
}

/* Stacked and transparent at 479px, so an outline on the form rings the submit
   button as well as the field. Ring the field instead. Same specificity as the
   rule above (0,2,0), so this must come after it.
   .p-search-from (locations.php) goes flex-flow: column at this same breakpoint
   in pepers-cc0900.webflow.css, so it needs the identical treatment. */
@media screen and (max-width: 479px) {
  #email-form-2:has(#postcode[aria-invalid="true"]),
  .js-newsletter-form:has([aria-invalid="true"]) {
    outline-color: #0000;
  }

  .js-newsletter-form .p-search-input,
  #email-form-2 .p-hero-search-input {
    outline: 3px solid #0000;
    outline-offset: 0;
    transition: outline-color .2s ease;
  }

  .js-newsletter-form:has([aria-invalid="true"]) .p-search-input,
  #email-form-2 .p-hero-search-input[aria-invalid="true"] {
    outline-color: #ff6e6e;
  }
}

/* Franchise / careers enquiry forms.

   Same intent as the pills above, different state marker: those two pages
   already record "this field is wrong" by un-hiding the inline message inside
   its .form_input-item, so the border reads that message's own visibility
   rather than a second flag that could drift out of step with it. #db1515 is
   the colour .form-input-message.error already uses for the text and icon
   directly beneath the field.

   (0,5,0), so it beats .form_input-field:focus (0,2,0) and the border stays
   red while the visitor is fixing the field. The page script hides the message
   - and with it the border - the moment the value validates. */
.form_input-item:has(> .form-input-message.error:not(.d-none)) .form_input-field {
  border-color: #db1515;
}

/* The two dropdowns are Select2, which hides the real <select> and paints its
   own box, so the rule above lands on something invisible. .select2-selection
   --single is that box, rendered as a sibling of the select. !important
   because the border being overridden is itself !important (the Select2 skin
   at the foot of include/javascript.php); at (0,5,0) against that rule's
   (0,3,0) this wins the important-vs-important comparison. */
.form_input-item:has(> .form-input-message.error:not(.d-none)) .select2-selection--single {
  border-color: #db1515 !important;
}

.form_input-field,
.select2-container--default .select2-selection--single {
  transition: border-color .2s ease;
}

/* Submit feedback on those same two forms.

   The export's own blocks were never restyled here: .w-form-done keeps its #ddd
   grey and .w-form-fail its #ffdede pink, and the export set only the text
   colour over the top - #fcb32c and #ffb889. Measured, that is 1.33:1 and
   1.34:1. Both messages were effectively invisible.

   Same palette as the newsletter pills, so the site says "done" and "wrong" in
   one voice: black on brand yellow (12.6:1) and black on #ff6e6e (7.7:1).
   Square corners, because everything else in these two forms is square.

   The compound selectors are deliberate - the newsletter and postcode forms
   use bare .w-form-done / .w-form-fail and are styled as pills further up. */
.success-message.w-form-done,
.error-message.w-form-fail {
  text-align: center;
  background: none !important;
  text-transform: none;
  letter-spacing: 0.2px;
}
.form-input-message.error {
  /* color: #ff6e6e; */
  color: #db1515;
}
.success-message.w-form-done {
  color: var(--black);
}
.error-message {
  text-transform: none;
  letter-spacing: 0.2px;
}

.error-message.w-form-fail {
  /* color: #ff6e6e; */
  color: #db1515;
}


/* ==========================================================================
   Back to top - include/backToTop.php

   The export ships this element with no styling at all; its only rules lived
   in a stylesheet that is no longer loaded. Built here
   from the existing tokens, square per the brief, using the same hard offset
   shadow language as .p-btn / .p-primary-btn.

   --btt-lift is written by the scroll handler in include/javascript.php to
   park the button above the footer. It drives `bottom` rather than transform
   so it tracks the scroll exactly, while transform stays free to animate the
   show/hide without the lift rubber-banding behind the page.
   ========================================================================== */

.back-top-block {
  --btt-lift: 0px;

  z-index: 90;
  position: fixed;
  right: 1.5rem;
  bottom: calc(1.5rem + var(--btt-lift));

  justify-content: center;
  align-items: center;
  width: 56px;
  height: 56px;
  display: flex;

  background-color: var(--black);
  border: 2px solid var(--black);
  border-radius: 0;
  box-shadow: -4px 4px var(--brand-color);
  color: var(--white);

  opacity: 0;
  visibility: hidden;
  transform: translateY(.75rem);
  transition: opacity .25s ease, transform .25s ease, visibility .25s,
              background-color .2s ease, box-shadow .2s ease, color .2s ease;
}

.back-top-block.is-visible {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

/* Shadow collapses on hover, same as .p-btn, and the palette flips */
.back-top-block:hover {
  background-color: var(--brand-color);
  box-shadow: 0 0 var(--brand-color);
  color: var(--black);
}

.back-top-block:focus-visible {
  outline: 3px solid var(--brand-color);
  outline-offset: 3px;
}

/* The exported SVG is a RIGHT-pointing arrow with a hard-coded white fill.
   Rotate the wrapper instead of swapping the asset, and let the path inherit
   colour so the hover flip works - a CSS fill beats the presentation attr. */
.back-top-block .arrow-top {
  display: flex;
  transform: rotate(-90deg);
}

.back-top-block .arrow-top svg path {
  fill: currentColor;
}

@media screen and (max-width: 767px) {
  .back-top-block {
    right: 1rem;
    bottom: calc(1rem + var(--btt-lift));
    width: 48px;
    height: 48px;
  }
}


/* ==========================================================================
   Franchise
   ========================================================================== */

/* The three .p-franchisee-menu-icon images are sized by their HTML width
   attribute (67 / 85 / 67), which has no breakpoint. A CSS width beats the
   attribute; height follows the SVG's intrinsic ratio since none is set.
   767px is where .p-franchisee-item goes fully stacked. */
@media screen and (max-width: 767px) {
  .p-franchisee-menu-icon {
    width: 44px;
  }
}


/* ==========================================================================
   Mobile menu

   The burger is three spans, not the .w-icon-nav-menu glyph, so it can morph
   into a close X. They use currentColor, so .menu-btn-icon{color:...} still
   controls them. body.is-menu-open is set by include/javascript.php.
   ========================================================================== */

.menu-btn-icon {
  position: relative;
  width: 28px;
  height: 20px;
}

.menu-btn-icon span {
  position: absolute;
  left: 0;
  width: 100%;
  height: 3px;
  background-color: currentColor;
  transition: transform .3s ease, opacity .15s ease;
}

.menu-btn-icon span:nth-child(1) { top: 0; }
.menu-btn-icon span:nth-child(2) { top: 8.5px; }
.menu-btn-icon span:nth-child(3) { top: 17px; }

/* Bars converge on the middle and cross */
body.is-menu-open .menu-btn-icon span:nth-child(1) {
  transform: translateY(8.5px) rotate(45deg);
}

body.is-menu-open .menu-btn-icon span:nth-child(2) {
  opacity: 0;
}

body.is-menu-open .menu-btn-icon span:nth-child(3) {
  transform: translateY(-8.5px) rotate(-45deg);
}

/* The panel is fixed and full-height, so the page behind it must not scroll */
body.is-menu-open {
  overflow: hidden;
}

/* Panel sits under the header (z-index 90 vs 100), so the bar stays readable.
   Keep the burger black against it once the bar is white. */
body.is-menu-open .p-header.is-solid .menu-btn-icon {
  color: var(--black);
}


/* --- the panel itself ---
   Export gave it padding-top:25vh and left the bottom third empty. Now it is a
   flex column: nav takes the free space and centres in it, utility block pins
   to the bottom. Panel sits under the header (z-index 90 vs 100), so the logo
   and close X stay visible and the top padding clears the bar. */
@media screen and (max-width: 991px) {
  .menu-items-wrapper {
    flex-direction: column;
    padding-top: 8rem;
    padding-bottom: 2rem;
    display: flex;
    overflow-y: auto;
  }

  .menu-items {
    flex: 1;
    justify-content: center;
    grid-row-gap: .25rem;
  }
}

/* Active page in brand yellow. recursivePagesOnFrontEnd() already emits
   w--current, so this needs no PHP. */
.menu-items-wrapper .p-nav-link.w--current {
  color: var(--brand-color);
}

/* --- stagger ---
   Delays live on .is-open only, so opening cascades but closing goes as one
   piece - a staggered exit reads as lag, not polish. */
.menu-items-wrapper .p-nav-link,
.menu-items-wrapper .p-nav-btn,
.menu-items-wrapper .menu-panel-foot {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity .35s ease, transform .35s ease;
}

.menu-items-wrapper.is-open .p-nav-link,
.menu-items-wrapper.is-open .p-nav-btn,
.menu-items-wrapper.is-open .menu-panel-foot {
  opacity: 1;
  transform: none;
}

.menu-items-wrapper.is-open .menu-items > :nth-child(1) { transition-delay: .16s; }
.menu-items-wrapper.is-open .menu-items > :nth-child(2) { transition-delay: .22s; }
.menu-items-wrapper.is-open .menu-items > :nth-child(3) { transition-delay: .28s; }
.menu-items-wrapper.is-open .menu-items > :nth-child(4) { transition-delay: .34s; }
.menu-items-wrapper.is-open .menu-items > :nth-child(5) { transition-delay: .40s; }
.menu-items-wrapper.is-open .menu-items > :nth-child(6) { transition-delay: .46s; }
.menu-items-wrapper.is-open .menu-items > :nth-child(7) { transition-delay: .52s; }
.menu-items-wrapper.is-open .menu-items > :nth-child(8) { transition-delay: .58s; }
.menu-items-wrapper.is-open .menu-panel-foot { transition-delay: .62s; }

/* --- utility block --- */
.menu-panel-foot {
  border-top: 1px solid #ffffff26;
  margin-top: 2rem;
  padding-top: 1.5rem;
}

.menu-panel-social {
  justify-content: center;
  align-items: center;
  display: flex;
}

.menu-panel-legal {
  grid-column-gap: 1.75rem;
  justify-content: center;
  align-items: center;
  margin-top: .75rem;
  display: flex;
}

.menu-panel-legal a {
  color: #ffffffa6;
  letter-spacing: .08em;
  text-transform: uppercase;
  font-family: Libre Franklin, sans-serif;
  font-size: 12px;
  font-weight: 600;
  text-decoration: none;
  transition: color .2s ease;
}

.menu-panel-legal a:hover {
  color: var(--brand-color);
}

/* Nothing to reveal, so skip the whole entrance for reduced-motion users */
@media (prefers-reduced-motion: reduce) {
  .menu-items-wrapper .p-nav-link,
  .menu-items-wrapper .p-nav-btn,
  .menu-items-wrapper .menu-panel-foot {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* Back to top is desktop only */
@media screen and (max-width: 991px) {
  .back-top-block {
    display: none;
  }
}


/* ==========================================================================
   Location detail - "BACK TO STORES" breadcrumb

   The chevron slides left on hover to point at where the link goes. Gated on
   pointer capability as well as width: on touch :hover sticks after a tap and
   would leave the arrow parked off-centre until you tap elsewhere.
   Transition sits on the base element so it eases back on mouse-out too.
   ========================================================================== */
@media screen and (min-width: 992px) and (hover: hover) {
  .p-breadcrumb-link .p-icon {
    transition: transform .2s ease;
  }

  .p-breadcrumb-link:hover .p-icon {
    transform: translateX(-5px);
  }
}

/* A 5px nudge is decorative - drop it rather than animate it */
@media (prefers-reduced-motion: reduce) {
  .p-breadcrumb-link:hover .p-icon {
    transform: none;
    transition: none;
  }
}


/* --- the map embed ---
   The Google iframe is sized by `.p-map-wrapper iframe { width/height: 100% }`
   in the page's own <style> block (locations-inner.php, .global-css w-embed).

   Down to 768px .p-map-main-wrap is a flex ROW - the export turns it column at
   991px and the 768-991 rule at the bottom of this file puts it back - so the
   wrapper's height is the stretched cross axis: definite, and the 100%
   resolves. height:400px pins the box to one size across that band; the
   export's min-height alone would let it grow with the column beside it.

   Below 768px the container is genuinely COLUMN, so height becomes the MAIN
   axis - which the export's `flex: 1 1 0%` then owns. A flex-basis of 0
   overrides the wrapper's own `height`, so its height is whatever flex layout
   produces, and that is indefinite to a percentage child: the iframe's 100%
   falls back to auto and collapses to the 150px default for a replaced element.
   The min-height still props the wrapper open, which is why the result is a
   strip of map floating in a 400px bordered box.

   `flex: none` drops the wrapper out of flex sizing so its own height:400px is
   the used height. Definite, so the 100% resolves to the 388px content box.
   box-sizing is border-box site-wide, so 400px still measures the same box the
   min-height did, borders included.

   Keep that below 768px only. In the row band flex-basis is the WIDTH, and
   `flex: none` there shrinks the map to its content width instead of letting it
   fill the space beside the address.

   It also has to be fixed on the WRAPPER, not the iframe. A `height` on
   `.p-map-wrapper iframe` from this file cannot win: it ties on specificity with
   the page's own rule, which sits in a <style> in <body> and so comes later in
   document order. (`display: block` below is safe only because nothing else
   declares it.) */
@media screen and (max-width: 991px) {
  .p-map-wrapper {
    height: 400px;
  }
}

@media screen and (max-width: 767px) {
  .p-map-wrapper {
    flex: none;
  }
}

/* An inline-level iframe sits on the text baseline, so a full-height one
   overflows its box by the descender gap. Desktop has the same gap. */
.p-map-wrapper iframe {
  display: block;
}

.p-search-form-block {
  position: relative;
}


/* ==========================================================================
   Home hero - mobile video sizing

   The mobile hero video is 576x720 (4:5 portrait) and carries its text burnt
   into the frame, close to the edges. The hero was a fixed 80dvh, which is
   taller than the video's natural full-width height on a phone, so
   w-background-video's object-fit:cover scaled the video up to fill and
   cropped the sides - taking the text with it.

   The brief is full width, uncropped. That makes the height a dependent
   value rather than a free one: at full width an uncropped 4:5 video is
   125vw tall. So the hero is sized by aspect-ratio and the video box is
   pinned to it, instead of either carrying a dvh height.

   Works out around 55-63dvh on current phones (450px on a 360px-wide screen,
   538px on a 430px one), so it does not read as a short strip.

   Scoped to <=479px - the only breakpoint where .p-hero-video.mobile is the
   visible one. Above it the 16:9 desktop video still fills a dvh-based hero.
   ========================================================================== */
@media screen and (max-width: 479px) {
  .p-home-hero {
    height: auto;
    aspect-ratio: 576 / 720;
  }

  /* .p-hero-video carries min-height: 80dvh at this breakpoint, which would
     push the video box past the hero and reinstate the crop. Two classes
     beats the one there, so this wins regardless of source order. */
  .p-hero-video.mobile {
    min-height: 0;
    height: 100%;
  }
}


/* ==========================================================================
   Menu page - mobile image overflow

   The product shots were being clipped at the viewport edges on phones.
   Three rules stack up, none of which affect layout - transforms and
   relative offsets paint outside the element's box, and both
   .p-inner-page-warpper.bg-light and .p-menu-section clip with
   overflow:hidden, so the excess reads as a hard crop rather than scroll:

     .p-menu-img-block     transform: scale(1.1)   <=767px
     .p-menu-img           transform: scale(1.2)   <=479px
     .p-menu-img.is-right  right: -32px            <=991px

   The first two are nested, so they multiply: 1.1 x 1.2 = 1.32. On a 390px
   phone .container leaves 350px of usable width, so the image paints 462px
   wide - about 36px past each edge of the screen. is-right then shoves one
   of them a further 32px sideways.

   No extra padding is needed: .container already carries 1.25rem (20px) each
   side. Dropping the transforms is enough to bring the images back inside it.
   ========================================================================== */
@media screen and (max-width: 767px) {
  .p-menu-img-block {
    transform: none;
  }

  .p-menu-img,
  .p-menu-img.is-scale {
    transform: none;
  }

  /* -32px comes from the <=991px block. On a phone that clears the 20px
     gutter and puts the image 12px outside the viewport. */
  .p-menu-img.is-right {
    right: 0;
  }
}


/* ==========================================================================
   Offers page - mobile stacking order

   Brief is image first, then heading and copy. The markup already has that
   order - .p-offer-left (image) precedes .p-offer-right (text) - but the
   export carries a deliberate reorder that flips it once .p-offer-block
   collapses to a single column at <=767px:

     #w-node-cf28ed2a-...-05316d1f,
     #w-node-_497e92dd-...-05316d1f { order: -9999 }

   Resetting order to 0 hands the grid back to DOM order, which is what the
   designer asked for. It only exists inside the <=767px block, so nothing
   above that breakpoint changes.

   !important is needed rather than nicer: those are ID selectors (1,0,0)
   and no realistic class selector outbids them. Targeting the class instead
   of repeating the two node hashes also keeps this working if the offers
   markup is re-exported with fresh IDs, or if a third offer block is added.
   ========================================================================== */
@media screen and (max-width: 767px) {
  .p-offer-right {
    order: 0 !important;
  }
}

@media (max-width: 1200px) and (min-width: 992px) {
  .p-footer-center {
    flex-direction: column;
    margin-bottom: 40px;
    gap: 40px;
    justify-content: flex-start;
    align-items: flex-start;
  }
  .p-newslatter-wrap {
    width: 100%;
    justify-content: space-between;
  }
  .p-newslatter-form {
    max-width: 500px;
  }
}

@media (min-width: 992px) {
  .js-newsletter-form ~ .w-form-done {
    position: absolute;
  }
}
@media screen and (max-width: 991px) {
  .p-footer-center {
    gap: 80px;
    margin-bottom: 0;
    padding-bottom: 60px;
  }
  .js-newsletter-form ~ .w-form-done {
      text-align: center;
  }
} 


/* ==========================================================================
   Homepage burger parallax

   The movement itself lives in include/javascript.php - it writes a
   translate3d onto each layer on scroll. Only two things are needed here.

   isolation:isolate gives the two layers their own stacking context, so the
   promoted (composited) transform layers cannot end up painting over the
   flavour pills that follow them in the section.

   The reduced-motion rule is a hard stop rather than a nicety: the script
   already clears its inline transform when the query matches, but the query
   can flip mid-scroll and this guarantees the frame in between is static.
   ========================================================================== */
.p-parallax-block {
  isolation: isolate;
}

@media (prefers-reduced-motion: reduce) {
  .parallax-bg-layer,
  .parallax-forground-layer {
    transform: none !important;
  }
}

@media (min-width: 768px) {
  .js-newsletter-form ~ .w-form-done,
  .js-newsletter-form .w-form-fail {
    padding-left: 28px;
    padding-right: 28px;
  }
}

.p-hero-search-block .w-form-fail {
  color: #ff6e6e;
  background: none;
  padding: 0;
  position: absolute;
  font-weight: 600;
}

/* ---------------------------------------------------------------------------
   Postcode autocomplete (js/postcode-suggest.js)
   Replaces the browser's native <datalist> popup, which cannot be styled.
   The panel is appended to <body> and positioned in script, so it is never
   clipped by the hero's overflow:hidden.
   --------------------------------------------------------------------------- */

.pc-suggest {
  position: absolute;
  z-index: 9999;
  background-color: var(--white, #fff);
  border: 2px solid var(--black, #000);
  opacity: 0;
  transform: translateY(-6px);
  transition: opacity .16s ease, transform .16s ease;
  text-align: left;
  overflow: hidden;
}

.pc-suggest--above {
  transform: translateY(6px);
}

.pc-suggest--visible {
  opacity: 1;
  transform: translateY(0);
}

.pc-suggest__status {
  color: #6b6b6b;
  letter-spacing: .09em;
  text-transform: uppercase;
  background-color: #f4f4f4;
  border-bottom: 2px solid var(--black, #000);
  padding: 9px 16px;
  font-size: .6875rem;
  font-weight: 700;
  line-height: 1.2;
}

.pc-suggest__status--empty {
  color: #b4342b;
}

.pc-suggest__status--loading:after {
  content: "";
  vertical-align: middle;
  background-color: currentColor;
  width: 18px;
  height: 2px;
  margin-left: 8px;
  animation: pc-suggest-scan 1s ease-in-out infinite;
  display: inline-block;
}

@keyframes pc-suggest-scan {
  0%, 100% { opacity: .2; transform: scaleX(.3); }
  50%      { opacity: 1;  transform: scaleX(1); }
}

.pc-suggest__list {
  scrollbar-width: thin;
  scrollbar-color: var(--black, #000) #ededed;
  max-height: 296px;
  margin: 0;
  padding: 0;
  list-style: none;
  overflow-y: auto;
}

.pc-suggest__list::-webkit-scrollbar {
  width: 10px;
}

.pc-suggest__list::-webkit-scrollbar-track {
  background-color: #ededed;
}

.pc-suggest__list::-webkit-scrollbar-thumb {
  background-color: var(--black, #000);
  border: 3px solid #ededed;
}

.pc-suggest__item {
  grid-column-gap: .75rem;
  color: #4a4a4a;
  cursor: pointer;
  border-bottom: 1px solid #e4e4e4;
  align-items: center;
  padding: 11px 16px;
  font-family: Rocgrotesk, Arial, sans-serif;
  font-size: 1rem;
  font-weight: 400;
  line-height: 1.25;
  display: flex;
}

.pc-suggest__item:last-child {
  border-bottom: none;
}

.pc-suggest__item--active {
  color: var(--black, #000);
  background-color: var(--brand-color, #febe10);
  box-shadow: inset 5px 0 0 0 var(--black, #000);
}

.pc-suggest__pin {
  color: #b9b9b9;
  flex: none;
  width: 12px;
  height: 16px;
}

.pc-suggest__item--active .pc-suggest__pin {
  color: var(--black, #000);
}

.pc-suggest__text {
  letter-spacing: .04em;
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* One notch up from the 400 body, not three. Rocgrotesk declares 400/700/800/900
   (pepers-cc0900.webflow.css) - 900 is the display face and reads as a blob at
   16px, and the colour step to black is already carrying most of the emphasis. */
.pc-suggest__text b {
  color: var(--black, #000);
  font-weight: 700;
}

.pc-suggest__hint {
  color: var(--black, #000);
  opacity: 0;
  flex: none;
  font-size: .875rem;
  line-height: 1;
}

.pc-suggest__item--active .pc-suggest__hint {
  opacity: .6;
}

@media (hover: none) {
  .pc-suggest__hint {
    display: none;
  }
}

@media (max-width: 767px) {
  .pc-suggest__list {
    max-height: 232px;
  }

  .pc-suggest__item {
    padding-top: 13px;
    padding-bottom: 13px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .pc-suggest {
    transition: none;
    transform: none;
  }

  .pc-suggest__status--loading:after {
    animation: none;
  }
}

/* Footer social icons, mobile.
   The row now carries up to six networks. At the exported sizes (27-31px wide,
   plus .875rem padding each side) six icons need ~340px, which overflows a
   320-375px viewport. Below 600px: icons ~20% smaller and normalised to one
   height, gap ~20% tighter.
   The SVGs carry their own width/height attributes at 28x31, 27x28, 31x31 and
   28x28, so they were never visually consistent. Setting height with width:auto
   scales each from its own viewBox and evens them up at the same time. */
@media screen and (max-width: 600px) {
  .p-social-wrap.mobile .p-social-link {
    padding-left: .7rem;
    padding-right: .7rem;
  }

  .p-social-wrap.mobile .social-icon svg {
    width: auto;
    height: 23px;
  }
}


/* ==========================================================================
   Store detail - address and action buttons (locations-inner.php)

   The export lays .p-shop-info-wrapper out as a two-column grid (1fr 1.25fr):
   address on the left, button stack on the right. Inside .p-shop-info-block's
   548px cap that leaves the address 236px, which is too narrow for a line like
   "233-235 Alum Rock Rd" - it wraps mid-line ("...Alum Rock / Rd").

   The button column has a second problem. Grid stretches it to the address's
   height and .p-shop-contact-info spreads its children with
   justify-content: space-between, so the spacing between buttons is only ever
   whatever height the address happened to leave over. Stores missing an Order
   Online link or a phone number render fewer than three buttons, and that
   leftover collapses into a ~125px hole in the middle of the stack (West
   Bromwich has two buttons; Kidderminster has one, floated to the top).

   Stacking the two gives the address the full 548px, where none of the current
   store addresses wrap, and gives the buttons a fixed gap and their own
   content width.

   Scoped to >=768px deliberately: below that the export already drops the grid
   to a single column and makes the buttons full-width and centred, which is
   the intended mobile treatment. */
@media screen and (min-width: 768px) {
  .p-shop-info-wrapper {
    grid-template-columns: 1fr;
    grid-row-gap: 1.5rem;
  }

  .p-shop-contact-info {
    grid-row-gap: .75rem;
    justify-content: flex-start;
    align-items: flex-start;
  }

  /* .p-tertriary-btn is padded .5rem .5rem .5rem 1.25rem - the short right side
     reserves room for the arrow that slides in on hover (.p-arrow-icon), which
     the buttons in this block do not have. Invisible while they were stretched
     to a shared column width; once each pill hugs its own label the lopsided
     padding shows, so even it up here only. */
  .p-shop-contact-info .p-tertriary-btn {
    padding-right: 1.25rem;
  }
}

@media (max-width: 991px) and (min-width: 768px) {
  .p-shop-info-block {
    max-width: 360px;
  }
  .p-map-main-wrap {
    flex-flow: row;
  }
}

@media (min-width: 992px) {
  #home-location-feedback {
    margin-top: 24px;
  }
}
@media (max-width: 550px) {
  #home-location-feedback {
    margin-top: 0px;
  }
}
@media (max-width: 767px) {
  #home-location-feedback,
  .js-newsletter-form .w-form-fail {
    padding-left: 0;
  }
}