/* ===========================================================================
   Shop bridge
   ---------------------------------------------------------------------------
   Reconciles WooCommerce and Divi markup with the design package. Enqueued
   after every design stylesheet, so rules here win the cascade without
   !important except in two places: where Divi applies inline styles, and where
   a plugin's own stylesheet declares !important (WooCommerce Bookings paints
   calendar availability that way - see 13.3.1).

   Corrections go here rather than in /design, which is vendored and replaced
   wholesale when an updated package arrives.

   Each block names the WooCommerce or Divi selector it is reconciling.
   =========================================================================== */


/* ---------------------------------------------------------------------------
   1. Divi layout chrome
   --------------------------------------------------------------------------- */

/* Divi: body:not(.et-tb) #main-content .container { padding-top: 58px }
   That selector outranks the design's bare .container, so every section would
   inherit 58px of dead space at the top. Matched here at equal specificity and
   loaded later, so the design's own spacing applies. */
body:not(.et-tb) #main-content .container,
body:not(.et-tb-has-header) #main-content .container {
	padding-top: 0;
}

/* Divi: .container { width: 80%; max-width: 1080px }
   The design caps width on the body and gutters the container instead. */
#main-content .container,
.site-header .container,
.site-footer .container {
	width: 100%;
	max-width: 100%;
}

/* Divi applies top padding to #page-container inline, via JS, to clear its own
   fixed header. That header is replaced on shop surfaces, so the offset is
   dead space. Inline styles require !important. */
body.et_fixed_nav #page-container {
	padding-top: 0 !important;
}

/* Divi's content wrappers carry their own background and padding. */
#main-content,
#et-main-area {
	background: transparent;
}


/* ---------------------------------------------------------------------------
   2. Product cards — WooCommerce output inside .bike-card
   --------------------------------------------------------------------------- */

/* wc_product_class() adds WooCommerce's own list classes to the card. Reset
   the float/width grid rules Woo ships for ul.products li.product so the
   design's CSS grid governs placement. */
.rental__grid .bike-card {
	float: none;
	width: auto;
	margin: 0;
	clear: none;
}

/* The card's image and title are links; the design draws them as plain text. */
.bike-card__media a,
.bike-card__title a {
	display: block;
	color: inherit;
	text-decoration: none;
}

.bike-card__title a:hover {
	text-decoration: underline;
}

/* get_price_html() emits .woocommerce-Price-amount, and <del>/<ins> on sale.
   The design styles a single price string, so normalise what Woo returns. */
.bike-card__price .woocommerce-Price-amount {
	font-weight: inherit;
}

.bike-card__price del {
	opacity: 0.6;
	margin-right: 0.5em;
}

.bike-card__price ins {
	text-decoration: none;
}

/* Bookable products render a price range prefixed by Woo, not by the design.
   Keep the prefix on its own baseline rather than letting it wrap oddly. */
.bike-card__price .from {
	display: inline;
}

/* Out-of-stock and non-purchasable products render no CTA at all — this
   theme's override of woocommerce_template_loop_add_to_cart() suppresses it.
   Stop the shorter card body from collapsing the grid row. */
.bike-card__body {
	display: flex;
	flex-direction: column;
}

.bike-card__cta {
	margin-top: auto;
}

/* Woo's AJAX "added to cart" affordances have no design equivalent. */
.bike-card .added_to_cart {
	display: inline-block;
	margin-top: 0.5rem;
	font-size: 0.8rem;
}


/* ---------------------------------------------------------------------------
   3. Category filters
   --------------------------------------------------------------------------- */

/* The design draws these as <button>; they are rendered as <a> so each
   category keeps a real, indexable URL. Restore the button presentation. */
a.rental-filters__btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	text-decoration: none;
}

a.rental-filters__btn:hover {
	text-decoration: none;
}


/* ---------------------------------------------------------------------------
   4. WooCommerce notices
   --------------------------------------------------------------------------- */

/* The design package has no notice styling, and cart/checkout messaging must
   stay legible. Deliberately plain rather than invented: this inherits the
   design's type and spacing without asserting a visual language the client
   has not approved. */
.woocommerce-notices-wrapper .woocommerce-message,
.woocommerce-notices-wrapper .woocommerce-info,
.woocommerce-notices-wrapper .woocommerce-error {
	margin: 0 0 1.5rem;
	padding: 1rem 1.25rem;
	border-left: 3px solid currentColor;
	list-style: none;
}

.woocommerce-notices-wrapper .woocommerce-error {
	color: #b3261e;
}


/* ---------------------------------------------------------------------------
   5. Archive head
   --------------------------------------------------------------------------- */

/* The archive renders the page title as <h1> where the design used <h2>.
   .rental__title already carries the design's 3.25rem scale and beats Divi's
   bare h1 rule on specificity, so the size is left alone here - an earlier
   font-size:inherit was collapsing the title to body size. Only the browser's
   default h1 margin needs resetting. */
h1.rental__title {
	margin: 0;
}


/* ---------------------------------------------------------------------------
   6. Divi sidebar layout
   --------------------------------------------------------------------------- */

/* The Store page's Divi layout is et_left_sidebar, which stays on the body
   class after the content wrappers are swapped. #left-area and #sidebar are no
   longer emitted on designed surfaces, so those rules match nothing — but if a
   plugin reintroduces either element, keep it from floating the design into a
   79% column. */
body.et_left_sidebar #main-content #left-area,
body.et_right_sidebar #main-content #left-area {
	float: none;
	width: 100%;
	padding: 0;
}

body.et_left_sidebar #main-content #sidebar,
body.et_right_sidebar #main-content #sidebar {
	display: none;
}


/* ---------------------------------------------------------------------------
   7. Accessibility
   ---------------------------------------------------------------------------
   The design package already ships :focus-visible, a prefers-reduced-motion
   block and a .visually-hidden helper, so none of that is repeated here.
   What remains are colour pairs that do not reach WCAG AA (4.5:1 for normal
   text), and the skip link.

   Each token below is darkened along its own hue so the design reads the same;
   measured ratios are against the surface the design actually uses it on.
   --------------------------------------------------------------------------- */

:root {
	/* --text  #888888 on #ffffff = 3.54:1 -> #767676 = 4.54:1
	   Body copy across every section. This is the single most widespread
	   failure in the package. */
	--text: #767676;

	/* --s2  #4eadaa = 2.66:1 as text on white, and 2.66:1 behind the white
	   text of .btn--teal -> #3a817f = 4.54:1 in both roles.
	   Also used for hairlines and ghost-button borders, where the darkening is
	   barely perceptible. */
	--s2: #3a817f;
}

/* .btn--sand renders var(--p1) #3959ba on --s3 #d6c6b2 = 3.80:1. The button's
   label is small uppercase text, so it needs the full 4.5:1.
   #2f4a9e is the same hue one step darker = 4.85:1. */
.btn--sand {
	color: #2f4a9e;
}

/* Skip link. Divi ships a .screen-reader-text rule that includes display:none,
   which would stop a skip link ever revealing itself, so this is styled
   independently of that class. */
.p30a-skip-link {
	position: absolute;
	left: -9999px;
	top: 0;
	z-index: 100000;
	padding: 0.75rem 1.25rem;
	background: var(--white, #fff);
	color: var(--p1, #3959ba);
	text-decoration: underline;
}

.p30a-skip-link:focus {
	left: 0;
}

/* #main-content is the skip link's target and is not natively focusable. */
#main-content:focus {
	outline: none;
}


/* ---------------------------------------------------------------------------
   8. Corrections from the first staging render
   --------------------------------------------------------------------------- */

/* Divi draws the sidebar divider as an absolutely positioned 1px pseudo
   element on .container:
     #main-content .container:before { background:#e2e2e2; width:1px; ... }
   The design's sections use .container too, so that rule painted a full-height
   vertical rule down the page at the old sidebar boundary. There is no sidebar
   on these templates. */
#main-content .container::before,
#main-content .container::after {
	display: none;
}

/* WooCommerce floats the result count left and the ordering select right.
   .rental__grid is a grid container and therefore its own formatting context,
   and such a box shrinks to avoid floats instead of flowing beneath them - the
   grid was rendering ~1229px wide inside a 1536px content box. The toolbar
   wrapper (archive-product.php) contains and clears them. */
.shop-toolbar {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
	flex-wrap: wrap;
	margin-bottom: 1.5rem;
}

.shop-toolbar::after {
	content: "";
	display: table;
	clear: both;
	width: 100%;
}

.shop-toolbar .woocommerce-result-count,
.shop-toolbar .woocommerce-ordering {
	float: none;
	margin: 0;
}

.shop-toolbar .woocommerce-result-count {
	color: var(--text);
	font-size: var(--fs-body-xs);
}

/* Belt and braces: even if a plugin adds another float before the loop, the
   grid should occupy the full content width. */
.rental__grid {
	clear: both;
	width: 100%;
}

/* The card's image sits inside an anchor added for keyboard and screen reader
   users. The design sets .bike-card__media img { height: 100% }, and a
   percentage height needs a definite containing block - an auto-height anchor
   in between made it indefinite, so images fell back to their intrinsic ratio
   (292x208 inside a 292x292 box) and left the figure's #f7f7f7 background
   showing as a grey band. Giving the anchor the figure's dimensions restores
   object-fit: cover. */
.bike-card__media > a {
	display: block;
	width: 100%;
	height: 100%;
}


/* ---------------------------------------------------------------------------
   9. Reconciliation against the approved category.html
   ---------------------------------------------------------------------------
   Measured by rendering the vendor mockup and the live archive at the same
   viewport and diffing computed values. Only the differences are corrected;
   everything already matching is left alone.
   --------------------------------------------------------------------------- */

/* Divi sets a tight line-height on headings, and the archive renders the page
   title as <h1> and product names as <h2> where the mockup used <h2>/<h3>.
   Mockup: title 71.72/44.82 and card title 42.75/26.72 - both ratio 1.6, the
   design's body line-height. The element sizes and weights already match. */
h1.rental__title,
.bike-card__title {
	line-height: 1.6;
}

/* Mockup title margin-top is 8.62px (0.625rem) from .rental__title; an earlier
   blanket margin:0 removed it. Only the browser's default h1 top/bottom margin
   needs neutralising. */
h1.rental__title {
	margin: 0.625rem 0 0;
}

/* --- Card CTA -------------------------------------------------------------
   The button arrives as a bare class="button" wearing Divi's styling
   (20px text, 6px/20px padding, 3px radius, #2ea3f2). The design's classes are
   now added in PHP; these rules win against Divi's .woocommerce a.button
   family, which sits around (0,2,1).

   Mockup target: 17.24px text, 11.21/17.24 padding, min-height 2.875rem,
   uppercase, transparent, 1px border.

   Colour is the one deliberate departure. The design uses --p2 (#62b1ea),
   which is 2.33:1 on white - well under AA. #447ba3 is the same hue darkened
   until it passes at 4.56:1, and gives 4.56:1 for white text on the hover
   fill. --p2 itself is NOT overridden: it is correct where the design uses it
   on dark backgrounds. */
.woocommerce .bike-card a.button.bike-card__cta,
.bike-card a.button.bike-card__cta {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 100%;
	min-height: 2.875rem;
	margin-top: auto;
	padding: 0.8125rem 1.25rem;
	border: 1px solid #447ba3;
	border-radius: var(--radius, 0);
	background: transparent;
	color: #447ba3;
	font-family: var(--font-body);
	font-size: 1.25rem;
	font-weight: 400;
	letter-spacing: 0;
	text-transform: uppercase;
	text-decoration: none;
	white-space: nowrap;
}

.woocommerce .bike-card a.button.bike-card__cta:hover,
.woocommerce .bike-card a.button.bike-card__cta:focus-visible,
.bike-card a.button.bike-card__cta:hover,
.bike-card a.button.bike-card__cta:focus-visible {
	background: #447ba3;
	color: var(--white);
}

/* Divi declares line-height: 1.7em !important on .woocommerce a.button, which
   no amount of selector specificity can beat. The design sets line-height: 1
   on .bike-card__cta; left unmatched the button rendered 53.71px tall against
   the mockup's 41.64px. This is the only property Divi forces on this element,
   and the only !important in the card CSS. */
.woocommerce .bike-card a.button.bike-card__cta,
.bike-card a.button.bike-card__cta {
	line-height: 1 !important;
}

/* Divi adds an ::after glyph to its buttons that the design has no room for. */
.bike-card a.button.bike-card__cta::after {
	display: none;
}


/* ---------------------------------------------------------------------------
   10. Rentals landing page
   ---------------------------------------------------------------------------
   The comp styles its closing CTA with inline attributes rather than a class,
   which cannot survive into a template. The same treatment is expressed here
   against a real class, using the design's own tokens.
   --------------------------------------------------------------------------- */

.closing-cta {
	background: var(--p1);
	padding: 4rem 0;
	text-align: center;
}

.closing-cta__title {
	margin: 0 0 1rem;
	font-family: var(--font-body);
	font-weight: 700;
	font-size: 2.25rem;
	line-height: 1.3;
	color: var(--white);
}

.closing-cta__copy {
	max-width: 40rem;
	margin: 0 auto 2rem;
	color: var(--white);
	opacity: 0.9;
}

.closing-cta__actions {
	display: flex;
	justify-content: center;
	gap: 1.5rem;
	flex-wrap: wrap;
}

.closing-cta__call {
	background: transparent;
	color: var(--white);
	border: 1px solid rgba(255, 255, 255, 0.6);
	padding: 0.8rem 2.5rem;
}

.closing-cta__call:hover,
.closing-cta__call:focus-visible {
	background: var(--white);
	color: var(--p1);
}

/* The rentals page renders inside #main-content like the archive, so it needs
   the same reset of Divi's container padding. Covered by section 1. */


/* ---------------------------------------------------------------------------
   11. WooCommerce's blanket image rule
   ---------------------------------------------------------------------------
   woocommerce-layout.css ships:

     .woocommerce img, .woocommerce-page img { max-width: 100%; height: auto }

   at specificity (0,1,1). The design sizes most of its imagery with
   single-class selectors at (0,1,0), which that rule outranks on every
   WooCommerce page regardless of load order. Around 20 of the design's image
   rules sit below it.

   Most survive by accident: .btn__icon sets an explicit width and its source is
   square, so height:auto lands on the right number, and .media-cover is backed
   up by .bike-card__media img at (0,1,1), which ties and wins on order.

   .rental-process__icon does not. It asks for a 45px-wide, 72px-tall box; Woo's
   max-width:100% stretched it to the full width of its step and height:auto
   took the intrinsic ratio, rendering it roughly 256x288 instead of 39x62.
   The design's own values are restored here at (0,2,0).

   .closing__bg does not either, and it is the category archive's closing CTA.
   sections.css asks for a full-bleed cover photograph:

     .closing__bg { position:absolute; inset:0; width:100%; height:100%;
                    object-fit:cover }

   at (0,1,0). Woo's height:auto wins, so the height falls back to the image's
   own ratio: measured 1497x998 inside a 403px section, which is overflow
   hidden - the photograph rendered as its own top crop at the wrong scale
   instead of covering the band. Confirmed by setting height:100% inline, which
   snapped it to 1497x403. The comp's standalone HTML loads no WooCommerce
   stylesheet, which is why it looks right there and wrong here.

   Restored below at (0,2,1), which outranks (0,1,1) on specificity alone - no
   !important needed.

   Anything added later that sizes an <img> with a single class needs the same
   treatment.
   --------------------------------------------------------------------------- */

.woocommerce .rental-process__icon,
.woocommerce-page .rental-process__icon {
	width: 100%;
	max-width: 2.8125rem;
	height: 4.5rem;
	object-fit: contain;
}

.closing img.closing__bg {
	width: 100%;
	height: 100%;
	object-fit: cover;
}


/* ---------------------------------------------------------------------------
   12. Tightening pass
   ---------------------------------------------------------------------------
   Everything below is scoped to body.p30a-design, which is added only on the
   surfaces this design governs. Nothing here reaches the cart, the checkout,
   the account pages or any other WooCommerce screen.
   --------------------------------------------------------------------------- */

/* --- 12.1 Divi's blanket heading and paragraph declarations ----------------
   Divi's stylesheet carries, on the bare element selectors:

     h1..h6 { padding-bottom: 10px; line-height: 1em }
     p      { padding-bottom: 1em }

   at (0,0,1). The design sets neither, so both land on every heading and
   every paragraph in the design and nothing in the design outranks them.
   Measured against the comp this was adding 10px under thirteen headings and
   10-21px under every paragraph, and collapsing the line-height of the six
   headings whose leading the design inherits from the body.

   These resets sit at (0,1,1), which clears Divi's element selectors while
   still losing to any design rule that names a class - so the headings that
   do declare their own line-height (the hero, the process and section titles)
   keep it. */
body.p30a-design h1,
body.p30a-design h2,
body.p30a-design h3,
body.p30a-design h4,
body.p30a-design h5,
body.p30a-design h6 {
	padding-bottom: 0;
}

body.p30a-design p {
	padding-bottom: 0;
}

/* The six headings whose leading the design takes from the body (1.6) rather
   than declaring. Restored explicitly so Divi's line-height: 1em cannot
   reclaim them. Measured comp values: 69.85/43.66, 41.64/26.03, 26.87/16.79
   and 24.18/15.11 - every one of them ratio 1.6. */
body.p30a-design .rental__title,
body.p30a-design .testimonials__title,
body.p30a-design .faq__title,
body.p30a-design .contact__title,
body.p30a-design .site-footer__heading,
body.p30a-design .rental-process__step-title,
body.p30a-design .pricing-card__name {
	line-height: 1.6;
}


/* --- 12.2 Product tile framing --------------------------------------------
   The approved design uses a square 1:1 tile on all three product surfaces -
   rentals catalogue, category archive and related products - and fills it with
   object-fit: cover. That works in the comp because the vendor's own
   photography is 1920x2560 portrait, so cover trims height and the bike still
   reads whole.

   The live catalogue is the opposite shape: 18 of 21 product photos are
   300x214 landscape from 2100x1500 originals (ratio 1.40), one is square, two
   are 1.59 and 1.91. Cover in a square box cut 28.6% off the width and scaled
   the remainder up 1.2x - the magnified, cropped tiles reported on staging.

   The vendor's square rhythm is preserved. Only the fill changes:

     - 1:1 is restored, so the grid keeps the approved card proportions and
       every row lines up exactly as the comp draws it;
     - contain replaces cover, so no bike is cropped at any of the four source
       ratios present;
     - inset padding on the design's own #f7f7f7 field gives the letterboxed
       landscape sources a deliberate frame rather than a stranded gap.

   DOCUMENTED DEVIATION: a 1.40 source contained in a 1:1 frame letterboxes by
   roughly 47px top and bottom at desktop width. That is a consequence of the
   live photography being landscape where the vendor's was portrait, not a
   layout change. It resolves completely if the client supplies square or
   portrait product photography - no CSS change would be needed.

   The card also asks for woocommerce_single (600px) rather than
   woocommerce_thumbnail (300px), so the tile downsamples instead of upscaling.
   See p30a_card_image_size(). */
body.p30a-design .rental__grid .bike-card__media,
body.p30a-design .relate-products .bike-card__media,
body.p30a-design .cross-sells .bike-card__media,
body.p30a-design .up-sells .bike-card__media {
	aspect-ratio: 1 / 1;
	padding: 1.25rem;
}

/* WooCommerce ships `.woocommerce img { max-width: 100%; height: auto }` at
   (0,1,1) - the hazard documented in section 11 - so the sizing has to be
   restated above it, not just the fit. */
body.p30a-design .bike-card__media img,
.woocommerce body.p30a-design .bike-card__media img {
	width: 100%;
	height: 100%;
	object-fit: contain;
}


/* --- 12.3 Pavilion map ----------------------------------------------------
   The map is a third-party iframe stretched to the height of a two-column
   grid row. It can fail to paint - the keyless Google embed returns its place
   panel and then a grey canvas - and a cross-origin frame exposes nothing to
   a screen reader either way.

   The address link sits underneath it at the foot of the figure, so it is
   read by assistive technology, and shows through as a legible caption on the
   design's own field if the embed never arrives. */
body.p30a-design .contact__map {
	position: relative;
	background: var(--s1, #efefef);
}

body.p30a-design .contact__map-fallback {
	position: absolute;
	z-index: 0;
	inset: auto 0 0 0;
	padding: 1rem 1.25rem;
	color: var(--p1, #3959ba);
	font-size: 0.95rem;
	text-decoration: none;
}

body.p30a-design .contact__map iframe {
	position: relative;
	z-index: 1;
	display: block;
}


/* ---------------------------------------------------------------------------
   13. Single product
   ---------------------------------------------------------------------------
   The design draws the product hero as two equal flex columns - photograph on
   the left, a sand panel on the right holding everything else.

   WooCommerce draws the same page as two FLOATS. woocommerce.css ships

     .woocommerce div.product div.images  { float: left;  width: 48% }
     .woocommerce div.product div.summary { float: right; width: 48% }

   so inside the design's 748px media column the gallery floated to 359px, and
   inside the 847px panel the summary floated to 359px and sat off to one side.
   Nearly every complaint about this page traces back to those two rules: the
   small photograph, the stranded panel content, the whitespace between them.

   The floats are cleared here and the design's flex columns are allowed to do
   the work. Nothing is removed from the PHP side - every WooCommerce callback
   still runs, so Product/Offer structured data and the Bookings form are
   untouched by any of this.
   --------------------------------------------------------------------------- */

body.p30a-design.single-product div.product .woocommerce-product-gallery,
body.p30a-design.single-product div.product .summary,
body.p30a-design.single-product div.product div.images,
body.p30a-design.single-product div.product div.summary {
	float: none;
	width: 100%;
	margin: 0;
}

/* --- 13.1 Media column ----------------------------------------------------
   The comp's media column is one full-bleed lifestyle photograph filling the
   column edge to edge. This catalogue's photography is a different kind of
   picture: 2100x1500 studio cut-outs of a single bike on white. Cropping one of
   those to the column's portrait proportion would cut the bike off at both
   ends, so the photograph is sized to the column's full WIDTH and centred in
   its height instead - the comp's visual weight, without destroying the
   subject.

   The column's field is white rather than the panel's sand, and that is what
   makes it read as full-bleed: the cut-out's own white background runs into the
   column, so the bike appears to sit directly on the page with the sand panel
   beside it, as the comp is composed. Two sand columns side by side are what
   made the previous pass read as one flat grey slab.
   -------------------------------------------------------------------------- */

body.p30a-design .product-hero__media {
	display: flex;
	flex-direction: column;
	justify-content: center;
	background: var(--white, #fff);
	overflow: hidden;
}

body.p30a-design .product-hero__media .woocommerce-product-gallery {
	position: relative;
	width: 100%;
	padding: 0;
}

body.p30a-design .product-hero__media .woocommerce-product-gallery__wrapper,
body.p30a-design .product-hero__media .woocommerce-product-gallery__image {
	margin: 0;
}

/* Woo's blanket `.woocommerce img { max-width:100%; height:auto }` at (0,1,1)
   is the hazard from section 11 again: it has to be out-specified, not just
   restated.

   The previous pass capped this at 37.5rem because woocommerce_single is
   registered at 600px here and a full-width image was being enlarged past its
   own resolution. That cap is gone because the cause is: the gallery is now
   served at `large` (see p30a_product_gallery_image_size), so filling the
   column is a downscale. */
body.p30a-design .product-hero__media .woocommerce-product-gallery__image img,
.woocommerce body.p30a-design .product-hero__media .woocommerce-product-gallery__image img {
	display: block;
	width: 100%;
	max-width: 100%;
	height: auto;
	margin: 0;
	object-fit: contain;
}

/* The gallery thumbnails sit as a centred row under the photograph rather than
   Woo's floated list. woocommerce.css sizes these with
     .woocommerce div.product div.images .flex-control-thumbs li { width: 25% }
   at (0,3,2), which outranked a plain class rule and left four thumbnails at
   148px wrapping onto a second row 403px tall. Matched at (0,4,2) here.

   On the white field they need a tile of their own to be visible at all, so
   each sits on the panel's sand and the active one takes a teal edge. */
body.p30a-design .product-hero__media .flex-control-thumbs {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 0.75rem;
	margin: 1.875rem 0 0;
	padding: 0 1.875rem;
	list-style: none;
}

body.p30a-design.single-product div.product div.images .flex-control-thumbs li,
body.p30a-design .product-hero__media .flex-control-thumbs li {
	float: none;
	width: 5rem;
	margin: 0;
}

body.p30a-design.single-product div.product div.images .flex-control-thumbs img,
body.p30a-design .product-hero__media .flex-control-thumbs img {
	width: 100%;
	height: 5rem;
	object-fit: contain;
	background: var(--s1, #efefef);
	border: 1px solid transparent;
	opacity: 0.6;
	cursor: pointer;
	transition: opacity var(--dur, 320ms) var(--ease, ease), border-color var(--dur, 320ms) var(--ease, ease);
}

body.p30a-design .product-hero__media .flex-control-thumbs img.flex-active,
body.p30a-design .product-hero__media .flex-control-thumbs img:hover {
	opacity: 1;
	border-color: var(--p2);
}

/* Woo's zoom trigger overlaps the design's framing.

   This rule did nothing until now. woocommerce.css carries

     .woocommerce div.product div.images .woocommerce-product-gallery__trigger

   at (0,4,2), and the selector here was (0,3,1) - so the trigger kept Woo's
   own z-index of 99 and painted straight through the date bar's popovers, a
   magnifying glass sitting on top of the list of end dates. Answered at (0,4,3)
   - note that `.woocommerce body` cannot work here, because the body IS the
   element carrying .woocommerce - rather than by raising everything else: 99 is a strange height
   for a zoom icon on a product photograph, and leaving it there means the next
   thing that overlaps the image has the same argument again. */
body.p30a-design .product-hero__media div.woocommerce-product-gallery a.woocommerce-product-gallery__trigger,
body.p30a-design .product-hero__media .woocommerce-product-gallery__trigger {
	top: 1.5rem;
	right: 1.5rem;
	z-index: 2;
}

/* --- 13.2 Panel ----------------------------------------------------------- */

/* The comp's panel column is .product-hero__inner at 52.5rem with a 1.875rem
   rhythm. WooCommerce writes the same element as a float:
     .woocommerce div.product div.summary { float: right; width: 48% }
   and the reset at the head of this section answers it at (0,4,2) with
   width:100% - which also outranked the design's own width. Restated here at
   (0,5,2) so the panel column is the design's, not Woo's and not the reset's. */
body.p30a-design.single-product div.product .product-hero__panel .summary,
body.p30a-design .product-hero__panel .summary {
	display: flex;
	flex-direction: column;
	align-items: center;
	text-align: center;
	gap: 1.875rem;
	float: none;
	width: 100%;
	max-width: 52.5rem;
	margin: 0 auto;
}

body.p30a-design .product-hero__panel .product_title {
	font-family: var(--font-body);
	font-weight: 500;
	font-size: 3.25rem;
	line-height: normal;
	color: var(--p1);
	margin: 0;
	padding-bottom: 0;
}

/* The design pairs a small "FROM" label with a large figure. WooCommerce
   Bookings prints that prefix as a BARE TEXT NODE - `From: <span class="amount">`
   - with no element to style, so the container carries the label treatment and
   the amount is scaled back up inside it.

   THE !important ON font-size AND color IS LOAD-BEARING. Measured on staging,
   both of these rules were losing, and had been since this section was written:

     .woocommerce div.product p.price            (0,3,2)  color: #2ea3f2
     .entry-summary p.price span   font-size: 26px !important   (0,2,2)

   both from Divi's style-static.min.css. The container rule below counts
   (0,3,1) - body.p30a-design, .product-hero__footer, .price, one type - so
   Divi's extra type selector outranked it and the label rendered as Divi's
   accent blue at 15.75px instead of the comp's grey at 1rem. The figure rule
   counts (0,4,1), which does outrank (0,2,2), but Divi marks that one
   !important, and !important beats specificity outright - so the figure
   rendered at Divi's 26px, not the comp's 3.0625rem. Marking these !important
   at higher specificity is what actually wins; dropping it silently restores
   Divi's values, which is how this went unnoticed in the first place.

   Verified on staging after the change: label 12.6px, figure 38.59px (= the
   comp's 3.0625rem on the fluid 12.6px root), one line box, no overflow, and
   the panel's own height unchanged at 699px.

   LABEL COLOUR. The comp uses --text (#888888), which measures 3.08:1 on the
   panel's --s1 (#efefef) - short of the 4.5:1 this 12.6px label needs. What it
   was actually rendering, Divi's #2ea3f2, is worse at 2.39:1. Darkened to
   #6b6b6b, measured 4.63:1 on #efefef and 5.33:1 on white, so it passes
   wherever the panel sits. The token itself is left alone: --text is used
   site-wide and whether to move it is not this rule's call. */
body.p30a-design .product-hero__panel .summary > .price,
body.p30a-design .product-hero__footer > .price {
	font-family: var(--font-body);
	font-size: 1rem !important;
	line-height: 1.4;
	letter-spacing: 0.0625rem;
	text-transform: uppercase;
	color: #6b6b6b !important;
	margin: 0;
}

body.p30a-design .product-hero__panel .summary > .price .amount,
body.p30a-design .product-hero__footer > .price .amount {
	display: block;
	margin-top: 0.25rem;
	font-size: 3.0625rem !important;
	line-height: 1.1;
	letter-spacing: normal;
	text-transform: none;
	font-weight: inherit;
	color: var(--p3) !important;
}

/* Same !important, same reason, and now for a second one: without it this
   rule loses twice over - to Divi's 26px !important, and to the 3.0625rem
   !important above, which outranks a plain declaration however specific. A
   struck-through was-price would come out at full figure size. */
body.p30a-design .product-hero__panel .summary > .price del .amount,
body.p30a-design .product-hero__footer > .price del .amount {
	display: inline-block;
	font-size: 1.75rem !important;
	opacity: 0.6;
}

body.p30a-design .product-hero__panel .woocommerce-product-details__short-description {
	font-size: 1.75rem;
	line-height: normal;
	color: var(--text);
	margin: 0;
}

body.p30a-design .product-hero__panel .woocommerce-product-details__short-description p {
	margin: 0;
	padding-bottom: 0;
}

/* The design's category pills. The product meta below them repeats the same
   list in Woo's own wording, so that half of it is hidden rather than deleted -
   the markup stays for anything reading the page for taxonomy. */
body.p30a-design .product-hero__pills-wrap {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 0.75rem;
	width: 100%;
}

body.p30a-design .product-hero__pill a {
	color: inherit;
	text-decoration: none;
}

body.p30a-design .product-hero__pill a:hover {
	text-decoration: underline;
}

body.p30a-design .product-hero__pill:last-child {
	border-right: 0;
}

body.p30a-design .product-hero__panel .product_meta .posted_in {
	display: none;
}

body.p30a-design .product-hero__panel .product_meta {
	font-size: 0.95rem;
	color: var(--text);
}

/* --- 13.3 The booking form ------------------------------------------------
   The comp's control is a date bar: two bordered pills side by side, then the
   price and a Book Now button. This site's control is the WooCommerce Bookings
   form, and it is not being replaced - a working rental booking, its cost
   calculation and its EasyRent handoff are worth more than a pixel match.

   What IS done is the arrangement. Bookings renders four things into
   #wc-bookings-booking-form:

     p.wc_bookings_field_persons      a number input
     p.wc_bookings_field_duration     a number input + a bare "Day(s)" text node
     p.wc_bookings_field_resource     a select, on products that have resources
     fieldset.wc-bookings-date-picker the month grid
     div.wc-bookings-booking-cost     the running total

   so the form becomes a two-column grid: the small numeric controls pair off on
   the top row as the comp's two pills, the month grid spans the full width
   below them, and the total spans below that. Their ORDER is set server-side
   through Bookings' own booking_form_fields filter rather than with CSS, so the
   tab order still matches what is on screen.

   No field is moved out of the form, renamed, hidden, replaced or wired to
   anything. This is framing and paint.
   -------------------------------------------------------------------------- */

body.p30a-design .product-hero__panel form.cart {
	width: 100%;
	max-width: 34rem;
	margin: 0;
}

body.p30a-design .product-hero__panel form.cart .wc-bookings-booking-form {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 1.25rem;
	margin-bottom: 1.25rem;
	text-align: left;
}

/* The month grid and the running total are full-width rows. */
body.p30a-design .product-hero__panel form.cart .wc-bookings-date-picker,
body.p30a-design .product-hero__panel form.cart .wc-bookings-booking-cost {
	grid-column: 1 / -1;
}

/* Each numeric control is a labelled field box. The "Day(s)" suffix after the
   duration input is a BARE TEXT NODE, like the "From:" prefix in section 13.2 -
   there is no element to target - so the field is laid out as a flex row and
   the suffix becomes an anonymous flex item beside the input. */
body.p30a-design .product-hero__panel form.cart .form-field {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.5rem;
	margin: 0;
	padding: 0;
	font-size: max(1rem, 14px);
	color: var(--text-1, #666);
}

body.p30a-design .product-hero__panel form.cart .form-field > label {
	flex: 0 0 100%;
	margin-bottom: 0.25rem;
}

body.p30a-design .product-hero__panel form.cart label {
	display: block;
	font-family: var(--font-body);
	font-size: max(1rem, 13px);
	letter-spacing: 0.0625rem;
	text-transform: uppercase;
	color: var(--p1);
}

body.p30a-design .product-hero__panel form.cart input[type="number"],
body.p30a-design .product-hero__panel form.cart input[type="text"],
body.p30a-design .product-hero__panel form.cart select {
	flex: 1 1 4rem;
	min-width: 0;
	min-height: max(3rem, 44px);
	padding: 0 0.875rem;
	border: 1px solid rgba(57, 89, 186, 0.35);
	border-radius: var(--radius, 0);
	background: var(--white, #fff);
	font-family: var(--font-body);
	font-size: max(1rem, 16px);
	color: var(--p1);
}

body.p30a-design .product-hero__panel form.cart input[type="number"]:focus-visible,
body.p30a-design .product-hero__panel form.cart input[type="text"]:focus-visible,
body.p30a-design .product-hero__panel form.cart select:focus-visible {
	outline: 2px solid var(--p3);
	outline-offset: 2px;
	border-color: var(--p1);
}

body.p30a-design .product-hero__panel form.cart .wc-bookings-booking-cost {
	font-family: var(--font-body);
	font-size: 1.5rem;
	color: var(--p3);
	background: transparent;
	border: 0;
	border-top: 1px solid rgba(136, 136, 136, 0.5);
	padding: 0.75rem 0 0;
	text-align: left;
}


/* --- 13.3.1 The month grid ------------------------------------------------
   Bookings paints availability straight onto the jQuery UI datepicker, and it
   does so with !important:

     td.bookable a      { background-color:#2ecc71 !important; color:#fff !important }
     td.fully_booked a  { background-color:#c0392b !important; color:#fff !important }
     td.bookable-range  { background:#239e57 !important; color:#fff }

   White on #2ecc71 is 2.10:1. Every date on an available day is currently below
   the 4.5:1 minimum - and below the 3:1 floor for large text too - so this is a
   correction, not only a repaint. Each !important below exists solely to answer
   one of the three above; they are the only ones in this section.

   The green is kept as a SHAPE - available days stay a solid block, because
   that is what makes a month scannable at a glance - and only its value
   changes: --s2 (#4eadaa) darkened to #2f7f7d, the least it can be darkened and
   still carry white. A light tint was tried first and rejected: anything pale
   enough to hold blue numerals at 4.5:1 sat within 1.3:1 of the unavailable
   cell, so available and unavailable stopped being distinguishable at a glance.

   Availability reads four ways, and never by colour alone: an available day is
   an <a> (focusable, with hover and focus states), an unavailable day is a
   <span>, a chosen day is darker still, and a fully booked day keeps a red fill
   AND takes a strike through its numeral.

     available     #fff on #2f7f7d  4.72:1
     hover / focus --s1 on --p1     5.51:1
     chosen        #fff on --p3    14.31:1
     unavailable   --text-1 on --s1 4.99:1
     fully booked  #fff on #8c2f26  8.24:1
   -------------------------------------------------------------------------- */

body.p30a-design .product-hero__panel .wc-bookings-date-picker {
	margin: 0;
	padding: 0;
	border: 0;
}

body.p30a-design .product-hero__panel .picker,
body.p30a-design .product-hero__panel .ui-datepicker-inline {
	width: 100%;
	max-width: 100%;
	border: 1px solid rgba(136, 136, 136, 0.35);
	border-radius: var(--radius, 0);
	background: var(--white, #fff);
	font-family: var(--font-body);
}

body.p30a-design .product-hero__panel .ui-datepicker .ui-datepicker-header {
	background: var(--p1);
	border: 0;
	border-radius: 0;
	color: var(--s1, #efefef);
	padding: 0.625rem 0;
}

body.p30a-design .product-hero__panel .ui-datepicker .ui-datepicker-title {
	font-family: var(--font-body);
	font-size: max(1rem, 14px);
	letter-spacing: 0.0625rem;
	text-transform: uppercase;
	color: var(--s1, #efefef);
}

body.p30a-design .product-hero__panel .ui-datepicker .ui-datepicker-prev,
body.p30a-design .product-hero__panel .ui-datepicker .ui-datepicker-next {
	top: 50%;
	transform: translateY(-50%);
	width: 2.75rem;
	height: 2.75rem;
	border: 0;
	background: transparent;
	cursor: pointer;
}

body.p30a-design .product-hero__panel .ui-datepicker .ui-datepicker-prev.ui-state-disabled {
	opacity: 0.45;
	cursor: default;
}

body.p30a-design .product-hero__panel .ui-datepicker th {
	font-family: var(--font-body);
	font-weight: 400;
	font-size: max(0.875rem, 12px);
	letter-spacing: 0.0625rem;
	color: var(--text-1, #666);
	padding: 0.5rem 0;
}

body.p30a-design .product-hero__panel .ui-datepicker td {
	padding: 1px;
	border: 0;
}

body.p30a-design .product-hero__panel .ui-datepicker td a,
body.p30a-design .product-hero__panel .ui-datepicker td span {
	display: block;
	padding: 0.625rem 0;
	border: 1px solid transparent;
	border-radius: var(--radius, 0);
	background: var(--s1, #efefef);
	font-family: var(--font-body);
	font-size: max(0.9375rem, 13px);
	text-align: center;
	text-shadow: none;
	color: var(--text-1, #666);
}

/* Available. */
body.p30a-design .product-hero__panel .wc-bookings-date-picker .ui-datepicker td.bookable a {
	background-color: #2f7f7d !important;
	background-image: none !important;
	border-color: #2f7f7d !important;
	color: var(--white, #fff) !important;
	text-shadow: none;
	cursor: pointer;
}

body.p30a-design .product-hero__panel .wc-bookings-date-picker .ui-datepicker td.bookable a:hover,
body.p30a-design .product-hero__panel .wc-bookings-date-picker .ui-datepicker td.bookable a:focus-visible {
	background-color: var(--p1) !important;
	border-color: var(--p1) !important;
	color: var(--s1, #efefef) !important;
}

/* Chosen day, and every day inside a chosen range. */
body.p30a-design .product-hero__panel .wc-bookings-date-picker .ui-datepicker td.bookable-range .ui-state-default,
body.p30a-design .product-hero__panel .wc-bookings-date-picker .ui-datepicker td.ui-datepicker-current-day a {
	background: var(--p3) !important;
	border-color: var(--p3) !important;
	color: var(--white, #fff) !important;
}

/* Fully booked: still red, dark enough to read, and struck through so the
   state does not depend on colour. */
body.p30a-design .product-hero__panel .wc-bookings-date-picker .ui-datepicker td.fully_booked:not(.not_bookable_by_rules) a,
body.p30a-design .product-hero__panel .wc-bookings-date-picker .ui-datepicker td.fully_booked:not(.not_bookable_by_rules) span {
	background-color: #8c2f26 !important;
	background-image: none !important;
	border-color: #8c2f26 !important;
	color: var(--white, #fff) !important;
	text-shadow: none;
	text-decoration: line-through;
}

/* Days outside this month are context, not options. */
body.p30a-design .product-hero__panel .ui-datepicker td.ui-datepicker-other-month a,
body.p30a-design .product-hero__panel .ui-datepicker td.ui-datepicker-other-month span {
	opacity: 0.45;
}


/* The booking button, in the comp's Book Now treatment with three deliberate
   departures from it, all of them accessibility.

   COLOUR. The comp's .product-hero__book-btn is --p2 (#62b1ea) on --p1
   (#3959ba), which is 2.7:1 - short of 4.5:1 for text this size, and short even
   of the 3:1 allowed for large text. The design system's own .btn--primary
   already answers this with --s1 (#efefef) on --p1 at 5.5:1, so the button
   takes the system's pairing rather than this one comp's. The --p2 edge stays:
   it is decoration, not text, and it is what makes the button read as the
   comp's.

   SIZE. The comp's padding comes to about 43px tall at this site's root size,
   just under the 44px minimum target. The rem padding is kept so the button
   still scales with the design, with an absolute 44px floor under it. The type
   gets the same treatment: 1rem as drawn, never below 14px.

   FOCUS. The comp has no focus state. One is added, because the hover colour
   alone is not a focus indicator.

   Divi forces line-height: 1.7em !important on .woocommerce a.button and
   friends - the same fight as the card CTA in section 9 - so that one line is
   !important. The only others in section 13 are the availability colours in
   13.3.1, which answer Bookings' own !important declarations. */
body.p30a-design .product-hero__panel form.cart button.single_add_to_cart_button,
.woocommerce body.p30a-design .product-hero__panel form.cart button.single_add_to_cart_button {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 100%;
	min-height: max(3.5rem, 44px);
	padding: 1.3125rem 3.0625rem;
	border: 1px solid var(--p2);
	border-radius: var(--radius, 0);
	background: var(--p1);
	color: var(--s1, #efefef);
	font-family: var(--font-body);
	font-size: max(1rem, 14px);
	font-weight: 400;
	letter-spacing: 0.20625rem;
	text-transform: uppercase;
	line-height: 1 !important;
}

body.p30a-design .product-hero__panel form.cart button.single_add_to_cart_button:hover {
	background: var(--p3);
	border-color: var(--p3);
}

body.p30a-design .product-hero__panel form.cart button.single_add_to_cart_button:focus-visible {
	background: var(--p3);
	border-color: var(--p3);
	outline: 2px solid var(--p3);
	outline-offset: 3px;
}

body.p30a-design .product-hero__panel form.cart button.single_add_to_cart_button::after {
	display: none;
}

/* WooCommerce Bookings disables this button until a date is chosen - which is
   its state on arrival - and drops it to opacity 0.5. That read as a broken
   control, and at 0.65 alpha the previous answer here was still only 2.8:1 on
   the sand panel. Full-strength --p1 on --s1 is 5.5:1, so the waiting state is
   now legible: an outline rather than a solid, which is a difference in shape
   and not only in colour. The disabled attribute is Bookings' own and is what
   assistive technology announces; nothing here touches it. */
body.p30a-design .product-hero__panel form.cart button.single_add_to_cart_button.disabled,
body.p30a-design .product-hero__panel form.cart button.single_add_to_cart_button:disabled,
.woocommerce body.p30a-design .product-hero__panel form.cart button.single_add_to_cart_button.disabled {
	opacity: 1;
	background: transparent;
	border-color: var(--p1);
	color: var(--p1);
	cursor: not-allowed;
}

/* --- 13.4 Lower sections -------------------------------------------------- */

body.p30a-design .p30a-product__lower {
	clear: both;
}

/* The tabs hold the full description. WooCommerce gives them no container, so
   on this layout they ran the full width of the viewport. */
body.p30a-design .woocommerce-tabs {
	width: min(112.5rem, 100% - 7.5rem);
	margin: 0 auto;
	padding: 3.75rem 0 0;
}

/* The grey slab and the box around the description are Woo's own, written as
   `.woocommerce div.product .woocommerce-tabs ul.tabs` at (0,3,2). The previous
   pass cleared them at (0,2,1) and lost. Matched at (0,4,2) here.

   The design has no tab furniture at all - the description is simply contained
   prose - so the chrome is removed rather than restyled, while the tabs markup
   itself stays in place for any plugin that adds a panel. */
body.p30a-design.single-product div.product .woocommerce-tabs,
body.p30a-design .woocommerce-tabs {
	border: 0;
	padding-top: 3.75rem;
}

body.p30a-design.single-product div.product .woocommerce-tabs ul.tabs,
body.p30a-design .woocommerce-tabs ul.tabs {
	margin: 0 0 1.5rem;
	padding: 0;
	background: transparent;
	border: 0;
	border-bottom: 1px solid rgba(136, 136, 136, 0.35);
	box-shadow: none;
}

body.p30a-design.single-product div.product .woocommerce-tabs .panel,
body.p30a-design .woocommerce-Tabs-panel {
	border: 0;
	padding: 0;
	margin: 0;
}

/* A single tab is a label for one block of prose, not a control - and the comp
   has no label there at all, it has centred prose under the hero. The tab is
   hidden when it is the only one, leaving its rule as the divider; a second tab
   from any plugin brings the whole strip back as a working control. */
body.p30a-design.single-product div.product .woocommerce-tabs ul.tabs li:only-child,
body.p30a-design .woocommerce-tabs ul.tabs li:only-child {
	display: none;
}

body.p30a-design .woocommerce-tabs ul.tabs::before {
	display: none;
}

body.p30a-design .woocommerce-tabs ul.tabs li {
	background: transparent;
	border: 0;
	border-radius: 0;
	margin: 0 1.875rem 0 0;
	padding: 0 0 0.75rem;
	box-shadow: none;
}

body.p30a-design .woocommerce-tabs ul.tabs li::before,
body.p30a-design .woocommerce-tabs ul.tabs li::after {
	display: none;
}

body.p30a-design .woocommerce-tabs ul.tabs li a {
	font-family: var(--font-body);
	font-size: 1rem;
	letter-spacing: 0.0625rem;
	text-transform: uppercase;
	color: var(--text);
	font-weight: 400;
	padding: 0;
}

body.p30a-design .woocommerce-tabs ul.tabs li.active a {
	color: var(--p1);
}

body.p30a-design .woocommerce-Tabs-panel h2 {
	display: none;
}

/* A measured column, centred as a BLOCK but set left.

   The previous pass centred the text itself, which reads well for the two or
   three lines most of these descriptions carry - and falls apart the moment one
   has a feature list. Only <p> was styled, so a <ul> kept the panel's full
   1175px width and 12px type while inheriting text-align: center: every bullet
   marker sat against the left edge of the page with its sentence floating in the
   middle. The whole flow is styled here, and the measure does the centring.

   The comp's own centred prose is still on the page - it is the local
   introduction below, which this no longer competes with. */
/* --text (#888) is the design's body grey and it is 3.54:1 on white - under the
   4.5:1 minimum for body copy. --text-1 (#666), the design's own darker body
   grey, is 5.74:1. Scoped to this panel; the token itself is left alone where
   the design uses it for labels and captions. */
body.p30a-design .woocommerce-Tabs-panel {
	max-width: 72ch;
	margin: 0 auto;
	text-align: left;
	font-size: 1.5rem;
	line-height: 1.6;
	color: var(--text-1, #666);
}

body.p30a-design .woocommerce-Tabs-panel > :first-child {
	margin-top: 0;
}

body.p30a-design .woocommerce-Tabs-panel > :last-child {
	margin-bottom: 0;
}

body.p30a-design .woocommerce-Tabs-panel p {
	font-size: inherit;
	line-height: inherit;
	max-width: none;
	margin: 0 0 1.25rem;
}

body.p30a-design .woocommerce-Tabs-panel ul,
body.p30a-design .woocommerce-Tabs-panel ol {
	margin: 0 0 1.25rem;
	padding-left: 1.5rem;
	list-style-position: outside;
	text-align: left;
}

body.p30a-design .woocommerce-Tabs-panel ul {
	list-style-type: disc;
}

body.p30a-design .woocommerce-Tabs-panel ol {
	list-style-type: decimal;
}

body.p30a-design .woocommerce-Tabs-panel li {
	margin: 0 0 0.5rem;
	padding: 0;
	font-size: inherit;
	line-height: 1.5;
}

body.p30a-design .woocommerce-Tabs-panel li:last-child {
	margin-bottom: 0;
}

/* --- 13.4.1 Detail: the description, and a short up-sell list beside it ----
   A measured column of prose is about 72 characters wide whatever the screen
   is, so on a 1492px display the description used 818px of a 1399px row and
   left the rest blank - and a one-card up-sell rail further down left a second
   gap. One or two up-sells move up into the first gap and close the second.

   Three or more stay in their own rail below: a four-up grid does not belong in
   a 500px column. p30a_product_relocate_tabs() only unhooks the up-sells when
   this layout will actually draw them.

   With no aside the section is a plain block and the measured column centres
   itself - which it was not doing: section 13.4 zeroes the panel's margins at
   (0,4,2) to clear WooCommerce's own box, and that also killed the auto margins
   the measure needs. Restated below at (0,5,3). */

/* This row carries no field of its own, and the stray rule that used to open it
   is gone with it.

   Both were tried. A full-width band was the obvious answer to two white
   sections touching, but neither value in the palette works here: --s1 is the
   hero panel's own sand and ends directly above this row, so it ran into it
   seamlessly on the right while stepping from white on the left; --cream is
   warm where --s1 is neutral, and two near-identical lightnesses of different
   temperature stacked on each other read as a mismatch rather than a choice.

   The aside carries the colour instead. It sits in the same column and the same
   sand as the hero panel directly above it, so the right-hand side of the page
   reads as one continuing track - panel, then aside - and the description keeps
   the white it is easiest to read on. Nothing is drawn to separate the row,
   because the hero's own panel edge already does it. */
body.p30a-design .p30a-detail {
	clear: both;
	padding: 3.75rem 0;
}

/* With the row carrying its own field, a solitary tab label leaves nothing
   worth drawing. Its <li> is already hidden; the strip goes with it. */
body.p30a-design.single-product div.product .p30a-detail .woocommerce-tabs ul.tabs:has(li:only-child),
body.p30a-design .p30a-detail .woocommerce-tabs ul.tabs:has(li:only-child) {
	display: none;
}

/* Standing alone the tabs block supplies its own width and gutter. Inside
   .container it already has both, and the design's own padding above. Matched
   at (0,5,3) against section 13.4's own (0,4,2). */
body.p30a-design.single-product div.product .p30a-detail .woocommerce-tabs,
body.p30a-design .p30a-detail .woocommerce-tabs {
	width: 100%;
	margin: 0;
	padding: 0;
}

body.p30a-design.single-product div.product .p30a-detail .woocommerce-Tabs-panel,
body.p30a-design .p30a-detail .woocommerce-Tabs-panel {
	margin-inline: auto;
}

/* The columns are proportional rather than measured in ch: `ch` on the grid
   resolves against the CONTAINER's font-size, not the panel's, so a 72ch track
   came out 545px where the prose inside it wants about 820. 1.55fr against 1fr
   puts the copy column at roughly 72 characters at every width the split
   applies to, and the aside takes what is left. */
/* The description and the add-ons shared a row for one build. It solved the
   right-hand void and created a left-hand one: these descriptions are often four
   lines, and three add-ons beside four lines leaves most of the copy column
   empty. Each is a full-width row of its own now, sized by its own content, so
   neither can squeeze the other - and the measure still does the centring. */

body.p30a-design .relate-products--addons {
	background: var(--s1, #efefef);
	padding: 3.75rem 0;
}

/* Sand is safe here where it was not for the detail row: the white description
   sits between this band and the hero's own sand panel, so there is no seam. */

body.p30a-design .relate-products--addons .relate-products__head {
	display: block;
	margin: 0 0 2.5rem;
}

body.p30a-design .relate-products--addons .why__title {
	font-size: 2.25rem;
}

body.p30a-design .relate-products--addons .relate-products__grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(18rem, 100%), 1fr));
	gap: 1.875rem;
}

/* Lying on their side, and on their own plate.

   Upright cards here would have made this a near-copy of the related-products
   rail further down the page - same shape, same size, two screens apart. Side-on
   is both more compact and a different read: add these to the rental, rather
   than browse another bike. */
/* Top-aligned, not centred: one of these names wraps to two lines and the
   others do not, and centring each card's contents against its own height left
   the three titles sitting at three different heights across the row. */
body.p30a-design .relate-products--addons .bike-card {
	display: grid;
	grid-template-columns: 7rem minmax(0, 1fr);
	align-items: start;
	gap: 1.25rem;
	padding: 1.25rem;
	background: var(--white, #fff);
}

body.p30a-design .relate-products--addons .bike-card__media {
	aspect-ratio: 1 / 1;
	margin: 0;
	padding: 0.5rem;
	background: transparent;
}

body.p30a-design .relate-products--addons .bike-card__title {
	margin-top: 0;
}

/* Section 9 pushes the catalogue button to the bottom and stretches it edge to
   edge at (0,4,2). On its side there is no bottom to push to - see 13.6. */
.woocommerce body.p30a-design .relate-products--addons .bike-card a.button.bike-card__cta,
body.p30a-design .relate-products--addons .bike-card a.button.bike-card__cta {
	width: auto;
	margin-top: 0.75rem;
	align-self: flex-start;
	padding-left: 1.75rem;
	padding-right: 1.75rem;
}

@media (max-width: 560px) {
	body.p30a-design .relate-products--addons .bike-card {
		grid-template-columns: minmax(0, 1fr);
		gap: 1rem;
	}

	.woocommerce body.p30a-design .relate-products--addons .bike-card a.button.bike-card__cta,
	body.p30a-design .relate-products--addons .bike-card a.button.bike-card__cta {
		width: 100%;
		align-self: stretch;
	}
}


/* --- 13.5 Mobile ---------------------------------------------------------- */

@media (max-width: 900px) {
	body.p30a-design .product-hero__grid {
		flex-direction: column;
		min-height: 0;
	}

	/* The design package pins the stacked media column to a fixed 20rem, which
	   is right for a cover photograph and clips a contained one - at 900px the
	   product shot is 643px tall inside a 320px box. Released here so the
	   photograph keeps its own proportion down the whole range. */
	body.p30a-design .product-hero__media {
		height: auto;
		padding: 2.5rem 0;
	}

	body.p30a-design .product-hero__panel {
		padding: 2.5rem 1.25rem;
	}

	body.p30a-design .product-hero__panel .product_title {
		font-size: 2.25rem;
	}

	body.p30a-design .product-hero__panel .summary > .price {
		font-size: 2.25rem;
	}

	body.p30a-design .woocommerce-tabs {
		width: calc(100% - 2.5rem);
	}
}


/* --- 13.6 Related and up-sell rails ---------------------------------------
   The comp draws this rail as four cards filling the row, and the related rail
   now has four to draw (p30a_related_products_fill). The up-sell rail often has
   one: it is a list the shop curates by hand, and padding it with category
   filler would misrepresent an editorial choice.

   So each rail is laid out by how many cards it actually has, and its template
   says which it is:

     three or more  the catalogue grid - auto-fit with 1fr tracks, so a track
                    that stays empty collapses and the rest stretch to fill.
     one or two     p30a-rail--few: a sand band with the heading held left and
                    the cards to the right, lying on their side. A single $5
                    bike basket then reads as a deliberate recommendation
                    rather than as a four-up with three holes in it - and a
                    stretched 1fr track would have given that one card a 675px
                    square photograph.
   -------------------------------------------------------------------------- */

body.p30a-design .relate-products__grid {
	grid-template-columns: repeat(auto-fit, minmax(min(21.875rem, 100%), 1fr));
}

@media (max-width: 760px) {
	body.p30a-design .relate-products__grid {
		grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
	}
}

/* One or two cards: the editorial band. */
body.p30a-design .p30a-rail--few {
	background: var(--s1, #efefef);
}

body.p30a-design .p30a-rail--few .container {
	display: grid;
	grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
	gap: 3.75rem;
	align-items: center;
}

body.p30a-design .p30a-rail--few .relate-products__head {
	display: block;
	margin: 0;
}

body.p30a-design .p30a-rail--few .relate-products__grid {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: 1.25rem;
}

/* The card turns on its side: square photograph, then the name, the price and
   the button beside it. */
/* One plate, not three. The first pass put a white card round the product, the
   catalogue's own #f7f7f7 tile inside that, and the cut-out's white background
   inside that again - a box in a box in a box, sitting on the band. The card
   loses its own fill and padding, and the photograph's plate is the only
   surface left. */
body.p30a-design .p30a-rail--few .bike-card {
	display: grid;
	grid-template-columns: 14rem minmax(0, 1fr);
	align-items: center;
	gap: 2.5rem;
	padding: 0;
	background: transparent;
}

body.p30a-design .p30a-rail--few .bike-card__media,
body.p30a-design .p30a-rail--few .relate-products .bike-card__media {
	aspect-ratio: 1 / 1;
	margin: 0;
	padding: 1.25rem;
	background: var(--white, #fff);
}

body.p30a-design .p30a-rail--few .bike-card__body {
	justify-content: center;
}

body.p30a-design .p30a-rail--few .bike-card__title {
	margin-top: 0;
}

/* The catalogue card pushes its button to the bottom and stretches it edge to
   edge - section 9 writes that at (0,4,2):
     .woocommerce .bike-card a.button.bike-card__cta { width:100%; margin-top:auto }
   Lying on its side there is no bottom to push to, and a button the full width
   of the body reads as the card's main event rather than its end. Matched at
   (0,6,2) so the button hugs its own label. */
.woocommerce body.p30a-design .p30a-rail--few .bike-card a.button.bike-card__cta,
body.p30a-design .p30a-rail--few .bike-card a.button.bike-card__cta,
body.p30a-design .p30a-rail--few .bike-card__cta {
	width: auto;
	margin-top: 1rem;
	align-self: flex-start;
	padding-left: 2.5rem;
	padding-right: 2.5rem;
}

@media (max-width: 900px) {
	body.p30a-design .p30a-rail--few .container {
		grid-template-columns: minmax(0, 1fr);
		gap: 2.5rem;
	}
}

@media (max-width: 520px) {
	body.p30a-design .p30a-rail--few .bike-card {
		grid-template-columns: minmax(0, 1fr);
		gap: 1rem;
	}

	.woocommerce body.p30a-design .p30a-rail--few .bike-card a.button.bike-card__cta,
	body.p30a-design .p30a-rail--few .bike-card a.button.bike-card__cta,
	body.p30a-design .p30a-rail--few .bike-card__cta {
		width: 100%;
		align-self: stretch;
	}
}


/* ---------------------------------------------------------------------------
   14. Breadcrumb
   ---------------------------------------------------------------------------
   WooCommerce prints its breadcrumb on woocommerce_before_main_content, which
   is outside every .container on these templates - so it sat flush against the
   left edge of the window as 11px of grey body text with nothing around it.

   It is styled rather than removed. WC_Structured_Data builds the page's
   BreadcrumbList from this same markup, so dropping the nav would drop the
   schema with it, and these links are also the only crawl path from a product
   back up to its category. Gutter-aligned and given the design's smallest label
   treatment, it reads as the quiet navigation strip the comp puts under the
   header.
   --------------------------------------------------------------------------- */

body.p30a-design .woocommerce-breadcrumb {
	width: 100%;
	margin: 0;
	padding: 1.875rem var(--gutter, 3.75rem);
	background: var(--white, #fff);
	font-family: var(--font-body);
	font-size: var(--fs-label-xs, 1rem);
	letter-spacing: var(--tracking-wider, 0.15rem);
	line-height: 1.4;
	text-transform: uppercase;
	color: var(--text);
}

body.p30a-design .woocommerce-breadcrumb a {
	color: var(--p1);
	text-decoration: none;
}

body.p30a-design .woocommerce-breadcrumb a:hover,
body.p30a-design .woocommerce-breadcrumb a:focus-visible {
	text-decoration: underline;
}

/* --- 14.1 Product pages only ----------------------------------------------
   The breadcrumb is wanted under a product, where it is the crawl path back up
   to the category and the source of the page's BreadcrumbList. It is not wanted
   on a category archive, where the hero already names the category and the strip
   reads as a stray line of grey text above it.

   Hidden rather than unhooked. WC_Structured_Data::generate_breadcrumb_data()
   runs on the woocommerce_breadcrumb action inside woocommerce_breadcrumb(), so
   removing the action would take the category's BreadcrumbList schema with it.
   The markup stays, costs nothing, and keeps WooCommerce's own SEO output intact.

   Only two surfaces ever render it - single product and product category. Cart,
   checkout, the storefront landing page and 404 emit no breadcrumb at all.
   -------------------------------------------------------------------------- */

body.p30a-design:not(.single-product) .woocommerce-breadcrumb {
	display: none;
}


/* --- 13.7 Panel footer ----------------------------------------------------
   The comp closes the panel with one row: a small FROM label over a large
   figure on the left, a Book Now button on the right.

   The control on this site is not a button. It is the WooCommerce Bookings
   form - a quantity, a month calendar, a duration and a submit - and changing
   it is out of scope. So the design's framing is kept and the control inside it
   stays Woo's: a rule-topped band with the price held left and the booking form
   to its right, stacking below 1100px where the calendar wants the full width.
   Nothing in the form is moved, renamed or hidden by any of this; only the box
   around it belongs to the design.
   -------------------------------------------------------------------------- */

body.p30a-design .product-hero__footer {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 1.5rem;
	width: 100%;
	padding-top: 1.875rem;
	border-top: 1px solid rgba(136, 136, 136, 0.5);
}

@media (min-width: 1100px) {
	/* The comp centres this row. With a Book Now button on the right that reads
	   as a baseline; with a 500px booking form it is what keeps the price from
	   being stranded at the top of 200px of empty panel. */
	body.p30a-design .product-hero__footer {
		flex-direction: row;
		align-items: center;
		justify-content: space-between;
		gap: 2.5rem;
		text-align: left;
	}

	body.p30a-design .product-hero__footer > .price {
		flex: 0 0 auto;
		text-align: left;
	}

	body.p30a-design .product-hero__footer form.cart {
		flex: 0 1 auto;
		margin: 0;
	}
}


/* --- 13.8 Rail header -----------------------------------------------------
   The arrows only render when a rail holds more than four products, which the
   default related-products query never does - but Divi styles every <button>,
   so they are neutralised here rather than left to appear as grey chrome the
   first time a shop raises that limit. */

body.p30a-design .relate-products__nav .carousel-nav__btn {
	padding: 0;
	background: transparent;
	border: 0;
	cursor: pointer;
}

body.p30a-design .relate-products__nav .carousel-nav__btn::after {
	display: none;
}


/* ---------------------------------------------------------------------------
   15. Footer
   ---------------------------------------------------------------------------
   The design's footer brand column opens with a wide wordmark. This site's only
   logo asset is the stacked header lockup - 961x1012, very nearly square - and
   the design sizes the mark by WIDTH:

     .site-footer__logo img { width: 15rem; height: auto }

   so the square mark rendered 180x190 and towered over the three link columns
   beside it. It is capped by HEIGHT here instead, which is what a square mark
   needs and what a wordmark will never reach.

   The real fix is the wordmark itself, which is a content question rather than
   a CSS one: Shop > Peddlers Design > Footer now takes a footer logo of its
   own, and this rule sizes whichever mark is supplied.
   --------------------------------------------------------------------------- */

body.p30a-design .site-footer__logo img {
	width: auto;
	max-width: 15rem;
	max-height: 10rem;
	height: auto;
	object-fit: contain;
}

/* The design package styles hover on every footer link and the social circles
   but never focus, so none of them were reachable to look at by keyboard. */
body.p30a-design .site-footer__logo:focus-visible,
body.p30a-design .site-footer__contact a:focus-visible,
body.p30a-design .site-footer__cols a:focus-visible {
	outline: 2px solid var(--p1);
	outline-offset: 3px;
}

body.p30a-design .site-footer__social a:focus-visible {
	background: var(--p1);
	color: var(--white, #fff);
	outline: 2px solid var(--p1);
	outline-offset: 3px;
}


/* ---------------------------------------------------------------------------
   16. Pavilion banner
   ---------------------------------------------------------------------------
   The comp lays this out as one row: the copy on the left, five badges on the
   right. Here it stacked instead, and the arithmetic says why. The design fixes
   the badge gap at 5.625rem and the circles at 8rem, so the row is

     5 x 8rem + 4 x 5.625rem = 62.5rem

   which at the comp's own 1920px canvas is 1000px inside an 1800px container -
   comfortable. At 1251px the root drops to 12px but the container drops faster:
   750px of badges plus 440px of copy plus the 36px gap is 1226px inside 1155px,
   so flex-wrap did what it was told and broke the row.

   Rather than pick new fixed numbers that break at some other width, the badge
   row is made the flexible track: it takes whatever is left, spaces its five
   badges across it, and the circles scale with the viewport. The 90px gap the
   comp draws at 1920 falls out of that arithmetic rather than being declared.
   --------------------------------------------------------------------------- */

@media (min-width: 769px) {
	body.p30a-design .day-banner__inner {
		flex-wrap: nowrap;
	}

	body.p30a-design .day-banner__content {
		flex: 0 1 36.6875rem;
	}

	body.p30a-design .day-banner__badges {
		flex: 1 1 auto;
		flex-wrap: nowrap;
		justify-content: space-between;
		gap: 1.25rem;
		max-width: 62.5rem;
		margin-left: auto;
	}

	body.p30a-design .day-badge__circle {
		width: clamp(3.5rem, 6.7vw, 8rem);
		height: clamp(3.5rem, 6.7vw, 8rem);
	}

	body.p30a-design .day-badge__circle img {
		width: clamp(1.75rem, 3.35vw, 4rem);
		height: clamp(1.75rem, 3.35vw, 4rem);
	}
}

/* The banner's button repeats the comp's own contrast problem: .day-banner__btn
   is --p2 (#62b1ea) on the --p1 field, which is 2.72:1 - the same failing pair
   as the comp's Book Now button, and answered the same way. --s1 on --p1 is
   5.51:1, and the hover fills to --s1 with --p1 text at the same ratio. */
body.p30a-design .day-banner__btn {
	border-color: var(--s1, #efefef);
	color: var(--s1, #efefef);
}

body.p30a-design .day-banner__btn:hover,
body.p30a-design .day-banner__btn:focus-visible {
	background: var(--s1, #efefef);
	border-color: var(--s1, #efefef);
	color: var(--p1);
}

body.p30a-design .day-banner__btn:focus-visible {
	outline: 2px solid var(--white, #fff);
	outline-offset: 3px;
}

/* The design package sets text-transform: none here because its own markup was
   already typed in capitals. The copy is editable now, so the capitals belong
   to the stylesheet rather than to whatever the client types. */
body.p30a-design .day-badge__label {
	text-transform: uppercase;
	letter-spacing: 0.0625rem;
}


/* ---------------------------------------------------------------------------
   17. Header and primary nav
   ---------------------------------------------------------------------------
   Two problems, one cause: the design was drawn around a WIDE WORDMARK and
   short one-word labels, and this site has a square lockup and longer ones.

   1. The logo box is fixed:

        .site-header__logo img { width: 15rem; height: 3rem; object-fit: contain }

      For the comp's wordmark that is the mark's own shape. For this site's
      961x1012 lockup, `contain` letterboxes it to about 34px wide inside a
      152px box - roughly 118px of reserved empty space, in the one row on the
      page that has none to spare. Width released to auto, capped at the
      design's 15rem so a wordmark still gets its full width.

   2. The labels here are "Rent Bikes", "Shop & Eat", "Contact Us" where the
      comp has "RENTALS", "PRODUCTS", "CONTACT" - and there are seven of them,
      one a duplicate. The row overflowed, and because flex items shrink by
      default the links absorbed it by BREAKING THEIR OWN TEXT: "Rent Bikes"
      rendered on two lines 44px wide, which is what made the nav look ragged.

      Labels are pinned nowrap so a link is never split mid-name, the spacing
      is fluid so the row tightens before anything gives, and the nav wraps as
      whole links if it still runs out of room. Two tidy rows of real labels
      beats one ragged row of broken ones.

   The duplicate "Rent Bikes" item is menu content, not CSS; removing it frees
   about 110px on its own.
   --------------------------------------------------------------------------- */

body.p30a-design .site-header__logo img {
	width: auto;
	max-width: 15rem;
	height: 3rem;
	object-fit: contain;
}

body.p30a-design .site-header__inner {
	gap: clamp(1rem, 2.6vw, 2.25rem);
}

body.p30a-design .site-nav {
	flex-wrap: wrap;
	justify-content: center;
	gap: clamp(0.75rem, 1.9vw, 2.25rem);
	row-gap: 0.5rem;
}

body.p30a-design .site-nav__link {
	flex: 0 0 auto;
	white-space: nowrap;
}

/* The cart link, which renders only when the cart has something in it (see
   p30a_header_cart). It sits before the phone button so the two CTAs the design
   drew keep their order and their weight. */

body.p30a-design .site-header__cart {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.5rem;
	min-width: 44px;
	min-height: max(3.5rem, 44px);
	padding: 0 1rem;
	border: 1px solid rgba(57, 89, 186, 0.35);
	border-radius: var(--radius, 0);
	color: var(--p1);
	font-family: var(--font-body);
	font-size: max(1rem, 14px);
	line-height: 1;
	text-decoration: none;
	flex: 0 0 auto;
}

body.p30a-design .site-header__cart:hover {
	background: var(--p1);
	border-color: var(--p1);
	color: var(--s1, #efefef);
}

body.p30a-design .site-header__cart svg {
	width: 1.375rem;
	height: 1.375rem;
	flex: none;
}

body.p30a-design .site-header__cart-count {
	font-variant-numeric: tabular-nums;
}

/* The header is tight at mid widths - see section 17 - so below the point where
   the nav starts wrapping, the cart keeps its icon and count and drops its box
   rather than pushing anything off the row. */
@media (max-width: 1100px) {
	body.p30a-design .site-header__cart {
		padding: 0 0.5rem;
		border-color: transparent;
	}
}

/* The design package styles hover on these but never focus. */
body.p30a-design .site-nav__link:focus-visible,
body.p30a-design .site-header__logo:focus-visible,
body.p30a-design .site-header__actions .btn:focus-visible {
	outline: 2px solid var(--p1);
	outline-offset: 3px;
}


/* ---------------------------------------------------------------------------
   18. Cart, checkout and 404
   ---------------------------------------------------------------------------
   These surfaces were already receiving the design package's global rules - the
   root font scale from base.css, the typography, the button and image rules -
   because its stylesheets load on every page of the site. What they were not
   receiving was the body class every rule in this file is scoped to, so none of
   the reconciliation reached them. The cart's cross-sell rendering a
   1,400px-tall product image is that gap in one picture: the grid fix exists in
   13.6 and could not apply.

   p30a_is_designed_surface() now includes them, which switches the whole file
   on here. Everything below is presentation.

   NOTHING FUNCTIONAL IS TOUCHED. Checkout carries the billing and pickup
   columns, the gratuity selector, the Delivery-or-Pickup radio inside the
   totals, the liability waiver and the signature pad. No field, no hook, no
   template and no order of anything is changed by any rule here.
   --------------------------------------------------------------------------- */

/* --- 18.1 The cart's cross-sell ------------------------------------------
   Woo's loop has no grid of its own, so a single card stretched to the width of
   the page and took its 1:1 tile with it. */

body.p30a-design .cross-sells ul.products,
body.p30a-design .up-sells ul.products {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(21.875rem, 100%), 1fr));
	gap: 1.875rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

body.p30a-design .cross-sells ul.products > *,
body.p30a-design .up-sells ul.products > * {
	float: none;
	width: auto;
	max-width: none;
	margin: 0;
	clear: none;
}

body.p30a-design .cross-sells ul.products::before,
body.p30a-design .cross-sells ul.products::after {
	display: none;
}


/* --- 18.2 Tables ----------------------------------------------------------
   The cart table and the order review. WooCommerce ships these with rounded
   corners and a heavy border; the design has neither. */

body.p30a-design .woocommerce table.shop_table {
	border: 0;
	border-radius: 0;
	border-collapse: collapse;
	font-family: var(--font-body);
	font-size: max(1rem, 15px);
	color: var(--text-1, #666);
}

body.p30a-design .woocommerce table.shop_table th {
	padding: 1rem 0.75rem;
	border: 0;
	border-bottom: 1px solid rgba(136, 136, 136, 0.5);
	background: transparent;
	font-family: var(--font-body);
	font-size: max(1rem, 13px);
	font-weight: 400;
	letter-spacing: 0.0625rem;
	text-transform: uppercase;
	color: var(--p1);
}

body.p30a-design .woocommerce table.shop_table td {
	padding: 1.25rem 0.75rem;
	border: 0;
	border-bottom: 1px solid rgba(136, 136, 136, 0.25);
}

body.p30a-design .woocommerce table.shop_table tfoot th,
body.p30a-design .woocommerce table.shop_table tfoot td {
	border-bottom: 1px solid rgba(136, 136, 136, 0.25);
}

body.p30a-design .woocommerce table.shop_table .order-total th,
body.p30a-design .woocommerce table.shop_table .order-total td {
	border-bottom: 0;
	border-top: 1px solid rgba(136, 136, 136, 0.5);
	font-size: max(1.25rem, 17px);
	color: var(--p3);
}

body.p30a-design .woocommerce table.shop_table td.product-name a,
body.p30a-design .woocommerce table.shop_table .product-name a {
	color: var(--p1);
	text-decoration: none;
}

/* The booking metadata under each line - dates, duration, ends on. */
body.p30a-design .woocommerce table.shop_table dl.variation,
body.p30a-design .woocommerce table.shop_table .wc-item-meta {
	margin: 0.5rem 0 0;
	font-size: max(0.9375rem, 13px);
	line-height: 1.5;
}

body.p30a-design .woocommerce table.shop_table .product-thumbnail img {
	width: 4.5rem;
	height: auto;
}

/* Woo's remove link is a bare red x. Given a target and a hover. */
body.p30a-design .woocommerce a.remove {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 1.75rem;
	height: 1.75rem;
	color: var(--p1) !important;
	font-size: 1.5rem;
	line-height: 1;
}

body.p30a-design .woocommerce a.remove:hover {
	background: var(--p1) !important;
	color: var(--white, #fff) !important;
}


/* --- 18.3 Fields ----------------------------------------------------------
   The same treatment the booking form gets in 13.3: a real target, 16px text so
   iOS does not zoom the page on focus, and a visible focus ring. */

body.p30a-design .woocommerce form .form-row label,
body.p30a-design .woocommerce-billing-fields label,
body.p30a-design .woocommerce-shipping-fields label,
body.p30a-design .woocommerce-additional-fields label {
	font-family: var(--font-body);
	font-size: max(1rem, 13px);
	letter-spacing: 0.0625rem;
	text-transform: uppercase;
	color: var(--p1);
}

body.p30a-design .woocommerce form .form-row input.input-text,
body.p30a-design .woocommerce form .form-row textarea,
body.p30a-design .woocommerce form .form-row select,
body.p30a-design .woocommerce .select2-container .select2-selection--single {
	min-height: max(3rem, 44px);
	padding: 0.5rem 0.875rem;
	border: 1px solid rgba(57, 89, 186, 0.35);
	border-radius: var(--radius, 0);
	background: var(--white, #fff);
	font-family: var(--font-body);
	font-size: max(1rem, 16px);
	color: var(--p1);
}

body.p30a-design .woocommerce form .form-row textarea {
	min-height: 6rem;
}

body.p30a-design .woocommerce form .form-row input.input-text:focus-visible,
body.p30a-design .woocommerce form .form-row textarea:focus-visible,
body.p30a-design .woocommerce form .form-row select:focus-visible {
	outline: 2px solid var(--p3);
	outline-offset: 2px;
	border-color: var(--p1);
}

body.p30a-design .woocommerce form .form-row.woocommerce-invalid input.input-text {
	border-color: #8c2f26;
}


/* --- 18.4 Headings and notices -------------------------------------------- */

body.p30a-design .woocommerce-billing-fields h3,
body.p30a-design .woocommerce-shipping-fields h3,
body.p30a-design #order_review_heading,
body.p30a-design .cart_totals h2,
body.p30a-design .cross-sells h2,
body.p30a-design .woocommerce-column__title {
	font-family: var(--font-body);
	font-weight: 500;
	font-size: max(2rem, 24px);
	line-height: normal;
	color: var(--p1);
	margin: 0 0 1.25rem;
	padding-bottom: 0;
}

/* Divi paints these #2ea3f2 with white text, which is 2.6:1. The design's own
   navy carries white at 6.34:1. */
body.p30a-design .woocommerce-info,
body.p30a-design .woocommerce-message,
body.p30a-design .woocommerce .woocommerce-info,
body.p30a-design .woocommerce .woocommerce-message {
	background: var(--p1);
	border: 0;
	border-radius: var(--radius, 0);
	color: var(--white, #fff);
	font-family: var(--font-body);
	font-size: max(1rem, 15px);
}

/* Inline links in the bar, and ONLY inline links.

   This rule used to read `.woocommerce-message a`, which also caught the two
   buttons WooCommerce puts in the add-to-cart bar. Divi paints those white -
   `.woocommerce-message a.button.wc-forward { background: #fff }` at (0,3,1),
   written for its own blue bar where Divi's `a.button` colour still showed
   through. Forcing the link colour to white on top of that made them white
   text on a white background: measured 1:1, both buttons invisible, which is
   exactly what they looked like.
   
   The buttons are answered below instead of being swept up here. */
body.p30a-design .woocommerce-info a:not(.button),
body.p30a-design .woocommerce-message a:not(.button) {
	color: var(--white, #fff);
	text-decoration: underline;
}

/* The bar's buttons: one solid, one ghost, the same pairing the 404 and the
   Pavilion banner already use.
   
   (0,3,2) against Divi's (0,3,1), so it wins on weight rather than on source
   order - Divi's stylesheet can move and this still holds.
   
   Measured on the bar's own navy, #3959ba:
     navy on white          6.34:1
     white on navy          6.34:1
     navy on sand (hover)   5.52:1
     70% white border       4.01:1 against the bar
   All above AA, the borders above the 3:1 a UI boundary needs. */
body.p30a-design .woocommerce-info a.button,
body.p30a-design .woocommerce-message a.button,
body.p30a-design .woocommerce-error a.button {
	background: var(--white, #fff);
	color: var(--p1);
	border: 1px solid var(--white, #fff);
	text-decoration: none;
	font-family: var(--font-body);
	font-weight: 500;
}

body.p30a-design .woocommerce-info a.button:hover,
body.p30a-design .woocommerce-message a.button:hover,
body.p30a-design .woocommerce-error a.button:hover {
	background: var(--s1, #efefef);
	border-color: var(--s1, #efefef);
	color: var(--p1);
}

/* "Continue shopping" is the way back, not the way on, so it steps down to a
   ghost. Both the button this theme appends to the message and Divi's own
   backward button are covered. */
body.p30a-design .woocommerce-info a.button.continue-shopping,
body.p30a-design .woocommerce-message a.button.continue-shopping,
body.p30a-design .woocommerce-info a.button.wc-backward,
body.p30a-design .woocommerce-message a.button.wc-backward {
	background: transparent;
	color: var(--white, #fff);
	border-color: rgba(255, 255, 255, 0.7);
}

body.p30a-design .woocommerce-info a.button.continue-shopping:hover,
body.p30a-design .woocommerce-message a.button.continue-shopping:hover,
body.p30a-design .woocommerce-info a.button.wc-backward:hover,
body.p30a-design .woocommerce-message a.button.wc-backward:hover {
	background: var(--white, #fff);
	border-color: var(--white, #fff);
	color: var(--p1);
}

body.p30a-design .woocommerce-error,
body.p30a-design .woocommerce .woocommerce-error {
	background: #8c2f26;
	border: 0;
	border-radius: var(--radius, 0);
	color: var(--white, #fff);
}


/* --- 18.5 Buttons ---------------------------------------------------------
   One language instead of three. The cart had a grey Divi "Continue shopping",
   a ghost "Update cart" and a thin blue "Proceed to checkout" on one screen.

   Primary is --s1 on --p1 at 5.51:1, the same pairing as the booking button and
   the design system's own .btn--primary. Divi forces line-height: 1.7em
   !important on .woocommerce a.button and friends, which is the only reason
   !important appears here - the same fight as section 9 and 13.3. */

body.p30a-design .woocommerce #place_order,
body.p30a-design .woocommerce .checkout-button,
body.p30a-design .woocommerce .wc-proceed-to-checkout a.button,
body.p30a-design .woocommerce a.button.alt,
body.p30a-design .woocommerce button.button.alt,
body.p30a-design .woocommerce input.button.alt {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-height: max(3.5rem, 44px);
	padding: 1rem 2.5rem;
	border: 1px solid var(--p2);
	border-radius: var(--radius, 0);
	background: var(--p1);
	color: var(--s1, #efefef);
	font-family: var(--font-body);
	font-size: max(1rem, 14px);
	font-weight: 400;
	letter-spacing: 0.125rem;
	text-transform: uppercase;
	text-decoration: none;
	line-height: 1 !important;
}

body.p30a-design .woocommerce #place_order:hover,
body.p30a-design .woocommerce .checkout-button:hover,
body.p30a-design .woocommerce a.button.alt:hover,
body.p30a-design .woocommerce button.button.alt:hover {
	background: var(--p3);
	border-color: var(--p3);
	color: var(--white, #fff);
}

body.p30a-design .woocommerce .cart .actions .button,
body.p30a-design .woocommerce .cart .actions a.button,
body.p30a-design .woocommerce .return-to-shop a.button,
body.p30a-design .woocommerce button[name="update_cart"] {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-height: max(3rem, 44px);
	padding: 0.875rem 2rem;
	border: 1px solid var(--p1);
	border-radius: var(--radius, 0);
	background: transparent;
	color: var(--p1);
	font-family: var(--font-body);
	font-size: max(1rem, 14px);
	letter-spacing: 0.125rem;
	text-transform: uppercase;
	text-decoration: none;
	line-height: 1 !important;
}

body.p30a-design .woocommerce .cart .actions .button:hover,
body.p30a-design .woocommerce .cart .actions a.button:hover,
body.p30a-design .woocommerce button[name="update_cart"]:hover {
	background: var(--p1);
	color: var(--s1, #efefef);
}

body.p30a-design .woocommerce .button:focus-visible,
body.p30a-design .woocommerce button:focus-visible,
body.p30a-design .woocommerce #place_order:focus-visible {
	outline: 2px solid var(--p3);
	outline-offset: 3px;
}

/* Divi adds an ::after glyph these have no room for. */
body.p30a-design .woocommerce #place_order::after,
body.p30a-design .woocommerce .checkout-button::after,
body.p30a-design .woocommerce .cart .actions .button::after {
	display: none;
}

/* Woo disables Update cart until something changes. Same reasoning as the
   booking button: legible while inactive rather than a washed-out ghost. */
body.p30a-design .woocommerce button[name="update_cart"]:disabled,
body.p30a-design .woocommerce button[name="update_cart"][disabled] {
	opacity: 1;
	border-color: rgba(57, 89, 186, 0.35);
	color: rgba(57, 89, 186, 0.75);
	cursor: not-allowed;
}


/* --- 18.6 Checkout's own blocks -------------------------------------------
   The waiver and the signature pad come from the site's own checkout code. Only
   the frame is touched - the canvas, its control and everything that reads or
   writes it are left exactly as they are. */

body.p30a-design .woocommerce-checkout .signature-pad,
body.p30a-design .woocommerce-checkout canvas {
	border-radius: var(--radius, 0);
}

body.p30a-design #payment {
	background: var(--s1, #efefef);
	border-radius: var(--radius, 0);
}

body.p30a-design #payment div.form-row {
	padding: 1.25rem;
}


/* --- 18.7 404 -------------------------------------------------------------
   Divi's "No Results Found" put a storefront visitor in a blog layout with no
   route anywhere. See 404.php. */

body.p30a-design .p30a-404 {
	padding: 6rem 0;
}

body.p30a-design .p30a-404__inner {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 1.5rem;
	max-width: 60ch;
	text-align: center;
}

body.p30a-design .p30a-404__title {
	font-family: var(--font-body);
	font-weight: 500;
	font-size: 3.25rem;
	line-height: normal;
	color: var(--p1);
	margin: 0;
	padding-bottom: 0;
}

body.p30a-design .p30a-404__lead {
	font-size: 1.5rem;
	line-height: 1.6;
	color: var(--text-1, #666);
	margin: 0;
}

body.p30a-design .p30a-404__actions {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 1rem;
	margin-top: 0.5rem;
}

body.p30a-design .p30a-404__btn {
	min-height: max(3.5rem, 44px);
	display: inline-flex;
	align-items: center;
	justify-content: center;
	padding: 1rem 2.5rem;
	line-height: 1 !important;
}

body.p30a-design .p30a-404__search {
	width: 100%;
	max-width: 28rem;
	margin-top: 1rem;
}

/* The secondary action, which used to carry .btn--ghost and was therefore
   invisible: components.css draws that modifier for photography - white label
   on a white border - and this page is white. Measured 1:1 against its own
   background at rest, legible only while hovered, so a keyboard or touch user
   never saw it at all.

   It carries .p30a-404__btn--secondary now and is drawn here rather than by
   overriding the vendor modifier, because .btn--outline - the obvious
   alternative - ships `color: #ffffff !important` on its hover state, and
   fighting an !important for a button that appears on exactly one page is not
   worth the rule it would take.

   --p1 measures 6.34:1 on white for both the label and the border, and the
   hover state inverts to filled so the affordance is unambiguous. */
body.p30a-design .p30a-404__btn--secondary {
	background: transparent;
	border: 1px solid var(--p1);
	color: var(--p1);
}

body.p30a-design .p30a-404__btn--secondary:hover,
body.p30a-design .p30a-404__btn--secondary:focus-visible {
	background: var(--p1);
	border-color: var(--p1);
	color: var(--s1, #efefef);
}

/* WooCommerce's product search form arrives as a bare input with a text
   submit under it - measured 39x20, 12.6px, no background and no border, which
   does not read as a control at all. Laid out as one row in the design's
   language, with the submit given the primary button's treatment.

   The input's border was rgba(57,89,186,0.35), which resolves to about 1.55:1
   against white - under the 3:1 a form field's boundary needs. Taken to the
   solid ink. */
body.p30a-design .p30a-404__search .woocommerce-product-search {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 0.75rem;
}

body.p30a-design .p30a-404__search input[type="search"] {
	flex: 1 1 16rem;
	min-width: 0;
	min-height: max(3rem, 44px);
	padding: 0.5rem 0.875rem;
	border: 1px solid var(--p1);
	border-radius: var(--radius, 0);
	font-family: var(--font-body);
	font-size: max(1rem, 16px);
	color: var(--p1);
	background: var(--white, #fff);
}

body.p30a-design .p30a-404__search button[type="submit"] {
	flex: 0 0 auto;
	min-height: max(3rem, 44px);
	padding: 0.5rem 2rem;
	border: 1px solid var(--p1);
	border-radius: var(--radius, 0);
	background: var(--p1);
	color: var(--s1, #efefef);
	font-family: var(--font-body);
	font-size: 0.875rem;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	cursor: pointer;
}

body.p30a-design .p30a-404__search button[type="submit"]:hover,
body.p30a-design .p30a-404__search button[type="submit"]:focus-visible {
	background: var(--white, #fff);
	color: var(--p1);
}

@media (max-width: 900px) {
	body.p30a-design .p30a-404 {
		padding: 3.75rem 0;
	}

	body.p30a-design .p30a-404__title {
		font-size: 2.25rem;
	}
}


/* --- 19 Approved product content -----------------------------------------
   The vendor's October 2026 briefs brought three things this stylesheet had no
   rules for: an inclusions row with real wording in it, the shop's first
   non-bookable products, and portrait photography.
   -------------------------------------------------------------------------- */

/* 19.1 The inclusions row.

   Section 13 took the comp's pills as given: two or three word category names
   at 1.9375rem, in a single non-wrapping row. The approved inclusions are
   longer than a category name - "White Embroidered Logo", "One Size Fits Most",
   three of them - and at the comp's size three of those overrun the panel on
   anything narrower than a very wide display.

   Sized to the panel's own body scale and allowed to wrap, so the row holds
   its shape at every width instead of pushing the panel out. The divider
   between pills has to be restated for a wrapped row: the comp hides it on
   :last-child only, which leaves a stray rule at the end of every line but the
   last one. */
body.p30a-design .product-hero__pills {
	flex-wrap: wrap;
	justify-content: center;
	gap: 0 1.25rem;
}

body.p30a-design .product-hero__pill {
	padding: 0.25rem 0.75rem;
	font-size: 1.375rem;
	line-height: 1.4;
}

/* 19.2 Portrait photography.

   Every photograph in the rental catalogue is a 2100x1500 landscape cut-out,
   and section 13.1 sizes the media column's picture to the column's full width
   on that basis. The merch photographs are 3:4 portraits, and at the column's
   full width one of those stands about a third taller than the panel beside
   it, which drags the whole hero down.

   Capped here rather than in 13.1 because the cap must not reach the rentals:
   a landscape photograph in this column is already shorter than this ceiling
   at every width the design covers, so a shared rule would do nothing for them
   today and quietly change their layout the moment a wider display appeared.
   WooCommerce writes product-type-simple on the product wrapper, which is the
   honest hook - this is about what the product IS, not what it is called. */
body.p30a-design .product-type-simple .product-hero__media .woocommerce-product-gallery__image img,
.woocommerce body.p30a-design .product-type-simple .product-hero__media .woocommerce-product-gallery__image img {
	max-height: 40rem;
	object-fit: contain;
}

/* 19.3 The in-store panel.

   Where a rental has the Bookings form, a merch item has this: the same
   bordered footer row, with the price on the left and where to buy it on the
   right. It occupies the slot the add-to-cart would occupy and matches its
   alignment at every breakpoint, so the panel keeps one shape across the
   catalogue whether or not a product can be added to a cart. */
body.p30a-design .product-hero__instore {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 0.5rem;
	text-align: center;
}

body.p30a-design .product-hero__instore-label {
	margin: 0;
	font-size: var(--fs-label-md, 1rem);
	letter-spacing: var(--tracking-wider, 0.08em);
	text-transform: uppercase;
	color: var(--p1);
}

body.p30a-design .product-hero__instore-place {
	margin: 0;
	font-family: var(--font-display, inherit);
	font-size: 1.75rem;
	line-height: 1.2;
	color: var(--s2);
}

body.p30a-design .product-hero__instore-address {
	margin: 0;
	font-size: 1.125rem;
	line-height: 1.5;
	color: var(--text-1, #666);
}

body.p30a-design .product-hero__instore-btn {
	margin-top: 0.75rem;
}

@media (min-width: 1100px) {
	body.p30a-design .product-hero__instore {
		align-items: flex-end;
		text-align: right;
		flex: 0 1 auto;
	}
}


/* --- 20 Category filter chips: contrast and states ------------------------
   The filter row is the main way into the catalogue, and it was the one
   control in the design with neither a hover nor a readable active state.

   20.1 The active chip.

   sections.css paints it `background: var(--p1); color: var(--p2)` - the
   design system's light blue on its navy. Measured on the live page:

     #62b1ea on #3959ba = 2.72:1

   which is the same failure already corrected on the comp's booking button
   and the Pavilion banner's button, and it is the chip a visitor reads first.
   The remedy is the one those two use: the off-white the design system puts on
   every other navy fill, which is what .btn--primary already does.

     #efefef on #3959ba = 5.51:1

   The light-blue rim stays. It is 2.33:1 against the page, which would matter
   if it were the only thing marking the control - but the chip is a filled
   navy block whose own edge against white is 6.34:1, so the rim is decoration,
   not the boundary.

   (0,2,1) to clear sections.css's `.rental-filters__btn.is-active` at (0,2,0).
   -------------------------------------------------------------------------- */

body.p30a-design a.rental-filters__btn.is-active {
	color: var(--s1, #efefef);
}

/* 20.2 Hover and keyboard focus.

   There was no hover rule at all beyond `text-decoration: none`, so the row
   gave no feedback on any of its six controls. One state for all of them: the
   chip lifts to the light field with navy text and a navy rim, which reads as
   "about to be chosen" and stays clearly distinct from the active chip's solid
   navy - rather than previewing the active look and leaving two chips looking
   alike mid-gesture.

     #3959ba on #efefef = 5.52:1 text
     #3959ba on #ffffff = 6.34:1 edge

   :focus-visible is included so the same change answers the keyboard. The
   design's global `:focus-visible { outline: 2px solid var(--p1) }` already
   draws the ring at 6.34:1; this adds the fill underneath it, so a chip
   reached by Tab looks the same as one under the pointer.

   (0,3,1) so it clears 20.1 above and the active rule beneath it. */
body.p30a-design a.rental-filters__btn:hover,
body.p30a-design a.rental-filters__btn:focus-visible,
body.p30a-design a.rental-filters__btn.is-active:hover,
body.p30a-design a.rental-filters__btn.is-active:focus-visible {
	background: var(--s1, #efefef);
	border-color: var(--p1);
	color: var(--p1);
	text-decoration: none;
}


/* --- 21 The booking form's start-date control -----------------------------
   Section 13.3 laid the Bookings form out as a two-column grid: the two
   numeric fields pair off on the top row, the month grid spans below. The
   comp's top line has three things on it, and now there is a third - see
   assets/js/shop-bridge.js, which adds a select built from, and wired to, the
   calendar beneath it.

   Three columns rather than two, with the date column widest because it holds
   a date and the other two hold a number. Below 30rem of panel the row would
   put "Number of this bike:" over about 140px, so it steps back to the old
   two-column shape with the date on its own full-width line - the same
   information, one line further down, rather than three cramped columns.

   The select itself needs no colours of its own: section 13.3 already styles
   every input and select inside form.cart, including the focus ring, so this
   control looks like the two beside it by inheritance rather than by repeating
   the paint.
   -------------------------------------------------------------------------- */

body.p30a-design .product-hero__panel form.cart .wc-bookings-booking-form {
	grid-template-columns: minmax(0, 1.3fr) minmax(0, 1.15fr) minmax(0, 0.9fr);
}

/* 21.1 The comp's shape, this panel's palette.

   The comp draws these as wide bordered pills with centred text and a chevron:
   .date-selector__btn, 21rem across, 1.3125rem of vertical padding. The shape
   and the proportion are taken; the colour is not.

   The comp paints that pill `border: 1px solid var(--s2); color: var(--s2)` -
   teal on white, which measures 2.67:1. That is below 4.5:1 for the text and
   below even the 3:1 a UI boundary needs, so teal would make the whole row
   fail in both directions at once. The panel's own navy carries the same shape
   at 6.34:1 on white, and it is what every other control in this form already
   uses, so the row stays one family rather than introducing a second.

   Centred text and a little more height are the parts of the comp that do
   carry over. */
body.p30a-design .product-hero__panel form.cart .wc-bookings-booking-form > .form-field input[type="number"],
body.p30a-design .product-hero__panel form.cart .p30a-start-date__select {
	min-height: max(3.25rem, 46px);
	text-align: center;
	text-align-last: center;
}

/* The three labels sit on one baseline whatever their length, so the controls
   below them line up. "Starting Date" is one line, "Duration" is one line, and
   "Bikes" is why the persons label was shortened - at a third of the panel,
   "Number of this Bike:" wrapped to three. */
body.p30a-design .product-hero__panel form.cart .wc-bookings-booking-form > .form-field > label {
	min-height: 2.5em;
	display: flex;
	align-items: flex-end;
	font-size: max(0.9375rem, 12px);
	letter-spacing: 0.05rem;
}

/* The "Day(s)" suffix is a bare text node beside the duration input. On a
   third of the panel it has to sit under the field rather than beside it, or
   it squeezes the input to about 40px.

   Which is also why the three fields have to stop stretching. A grid item
   fills its row by default, and section 13.3 centres each field's contents, so
   the duration field - alone in having a third line under its input - centred
   itself against the other two and sat its box about 40px higher than theirs.
   Sized to its own content and set at the top of the row, all three labels
   share a baseline and all three inputs start on the same line. */
body.p30a-design .product-hero__panel form.cart .wc-bookings-booking-form > .form-field {
	align-self: start;
	align-content: start;
}

body.p30a-design .product-hero__panel form.cart .wc_bookings_field_duration {
	position: relative;
}

body.p30a-design .product-hero__panel form.cart .wc_bookings_field_duration input[type="number"] {
	flex: 1 1 100%;
}

body.p30a-design .product-hero__panel form.cart .p30a-start-date[hidden] {
	display: none;
}

body.p30a-design .product-hero__panel form.cart .p30a-start-date__select {
	flex: 1 1 100%;
	width: 100%;
}

@media (max-width: 36rem) {
	body.p30a-design .product-hero__panel form.cart .wc-bookings-booking-form {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}

	body.p30a-design .product-hero__panel form.cart .p30a-start-date {
		grid-column: 1 / -1;
	}
}


/* --- 22 The date bar above the hero ---------------------------------------
   The markup reuses the comp's own class names - .date-selector,
   .date-selector__field, .date-selector__btn, .date-picker - so the shape,
   the sizing and the layout come straight from design/assets/css/sections.css
   rather than being restated here. What follows is only what the comp gets
   wrong for this site, plus the parts that are ours.

   22.1 The teal.

   The comp paints the pill and the popover border with --s2, #4eadaa, on
   white. Measured: 2.67:1. That is below 4.5:1 for the text and below even the
   3:1 a UI boundary needs, so the comp's own colour fails the control in both
   directions.

   #2f7f7d is 4.72:1 on white and is not a new colour: it is the exact teal
   this project already darkened --s2 to, for the same reason, when the
   calendar's available days could not carry white at #2ecc71. Same hue, same
   family, legible.
   -------------------------------------------------------------------------- */

body.p30a-design .p30a-date-bar .date-selector__btn {
	border-color: #2f7f7d;
	color: #2f7f7d;
}

body.p30a-design .p30a-date-bar .date-selector__btn:hover:not(:disabled),
body.p30a-design .p30a-date-bar .date-selector__btn:focus-visible:not(:disabled) {
	background: #2f7f7d;
	color: var(--white, #fff);
}

/* A chosen date is the panel's navy, as the comp's own .has-value state is. */
body.p30a-design .p30a-date-bar .date-selector__btn.has-value {
	border-color: var(--p1);
	color: var(--p1);
}

body.p30a-design .p30a-date-bar .date-selector__btn.has-value:hover,
body.p30a-design .p30a-date-bar .date-selector__btn.has-value:focus-visible {
	background: var(--p1);
	color: var(--s1, #efefef);
}

/* Ending Date before a start date is chosen. Not just faded - disabled, so it
   is skipped by the keyboard rather than being a tab stop that does nothing. */
body.p30a-design .p30a-date-bar .date-selector__btn[disabled] {
	opacity: 0.45;
	cursor: not-allowed;
}

/* 22.2 The real calendar, as a popover.

   The grid stays inside its fieldset - see the note in inc/product-page.php -
   and is positioned by script. Everything here is the chrome the comp draws
   around it: the white card, the teal edge, the shadow. The calendar's own
   availability colours are untouched; they were measured and corrected in
   section 13.3.1 and they are what tells a customer which days are free. */
/* 200 is chosen against what is actually on the page, not picked out of the
   air: the sticky header sits at 50 and Woo's gallery trigger at 99, so a
   popover has to clear both; the PhotoSwipe lightbox is at 999999, the admin
   bar at 100001 and a Popup Maker overlay higher still, and all three SHOULD
   cover a popover. 200 is the only band that satisfies both ends. */
body.p30a-design.p30a-has-date-bar .wc-bookings-date-picker .picker {
	background: var(--white, #fff);
	border: 1px solid #2f7f7d;
	box-shadow: 0 0.625rem 1.875rem rgba(0, 0, 0, 0.15);
	padding: 1.25rem;
	z-index: 200;
	min-width: 20rem;
}

body.p30a-design.p30a-has-date-bar .wc-bookings-date-picker .picker[hidden] {
	display: none;
}

/* With the calendar lifted out of the flow the fieldset has nothing left to
   occupy, so it stops reserving a row in the panel's grid. */
body.p30a-design.p30a-has-date-bar .product-hero__panel form.cart .wc-bookings-date-picker {
	margin: 0;
	padding: 0;
	border: 0;
}

/* 22.3 The ending-date list.

   The comp draws a second month grid here. This is a list instead, and
   deliberately: the choice is never more than fourteen consecutive days, and a
   list can say what a grid cannot - how many days each choice actually books,
   which is the number that sets the price. */
body.p30a-design .p30a-date-bar__panel {
	max-height: 20rem;
	overflow-y: auto;
	z-index: 200;
}

body.p30a-design .p30a-date-bar__list {
	margin: 0;
	padding: 0;
	list-style: none;
}

body.p30a-design .p30a-date-bar__choice {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 1rem;
	width: 100%;
	padding: 0.625rem 0.75rem;
	background: transparent;
	border: 0;
	font-family: var(--font-body);
	font-size: max(1rem, 14px);
	color: var(--p1);
	text-align: left;
	cursor: pointer;
}

body.p30a-design .p30a-date-bar__choice:hover,
body.p30a-design .p30a-date-bar__choice:focus-visible {
	background: var(--s1, #efefef);
}

/* --text-1 on --s1 is 4.99:1, the same pairing the unavailable calendar day
   uses, so the secondary figure stays readable on the hover fill too. */
body.p30a-design .p30a-date-bar__nights {
	flex: none;
	font-size: max(0.875rem, 12px);
	color: var(--text-1, #666);
}

@media (max-width: 48rem) {
	body.p30a-design .p30a-date-bar .date-selector__inner {
		gap: 1rem;
	}

	body.p30a-design .p30a-date-bar .date-selector__field,
	body.p30a-design .p30a-date-bar .date-selector__btn {
		width: 100%;
	}
}


/* --- 23 Bikes on the bar, Duration absorbed ------------------------------
   The bar now carries the three things a person actually decides, in the order
   they decide them: when it starts, when it ends, how many bikes. The panel
   below keeps what the comp's panel keeps - the specs, the price and Book Now.

   Duration has no control of its own any more. Ending Date writes it, and the
   ending-date list names the day count beside every option, so the number is
   still visible at the moment it is chosen. Two controls for one value, side by
   side, would have been the worst of both.

   What is hidden here is only the PRESENTATION of those two fields. The inputs
   stay in the form, inside .wc-bookings-booking-form, because that is where
   Bookings' delegated change handler listens and where the posted data comes
   from - display:none does not stop a field submitting, and moving it would
   stop both. If the bar never initialises, p30a-has-date-bar is never set and
   this whole section does nothing, so the panel keeps its own controls.
   -------------------------------------------------------------------------- */

body.p30a-design.p30a-has-date-bar .product-hero__panel form.cart .wc_bookings_field_duration,
body.p30a-design.p30a-has-date-bar .product-hero__panel form.cart .wc_bookings_field_persons {
	display: none;
}

/* Three fields now, so they share the row rather than each claiming the
   comp's fixed 21rem - which at three across would overrun the container
   below about 1500px. */
body.p30a-design .p30a-date-bar .date-selector__field {
	flex: 1 1 14rem;
	width: auto;
	max-width: 21rem;
}

/* The quantity pill.

   The first pass put a bordered number input inside the bordered pill, which
   read as a box in a box and sat oddly beside two controls that are a label
   and a chevron. This is a stepper instead: the label on the left, minus and
   plus either side of the figure on the right, no inner border. Quantity is
   almost always nudged by one rather than typed, and the figure stays a real
   number input underneath, so it can still be typed into, still reports its
   bounds, and still works with a screen reader.

   The pill itself is not a button - there is nothing to press about it - so it
   takes none of the button hover treatment; only the two steppers do.

     label, figure   --p1 on white     6.34:1
     steppers        #2f7f7d on white  4.72:1
     stepper hover   white on #2f7f7d  4.72:1
   -------------------------------------------------------------------------- */

body.p30a-design .p30a-date-bar .date-selector__btn--count {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
	cursor: default;
}

body.p30a-design .p30a-date-bar .date-selector__field--count .date-selector__value {
	color: var(--p1);
	cursor: default;
}

/* 22.1's hover fills a pill with teal and turns its text white. That is right
   for the two date buttons, which ARE buttons. This pill is not - it is a
   label, a figure and two small steppers - so filling it on hover left navy
   text on teal at 1.34:1 and made the figure you are about to change the
   hardest thing on the row to read.
   
   Written at (0,5,1) rather than relying on coming later in the file, because
   the rule it answers is (0,4,1) and source order is the kind of thing that
   quietly stops being true. Keyboard users get the border instead: the pill
   takes the panel's navy edge when anything inside it holds focus, which says
   the field is live without repainting it. */
body.p30a-design .p30a-date-bar .date-selector__field--count .date-selector__btn--count:hover,
body.p30a-design .p30a-date-bar .date-selector__field--count .date-selector__btn--count:focus-within {
	background: transparent;
	color: #2f7f7d;
}

body.p30a-design .p30a-date-bar .date-selector__field--count .date-selector__btn--count:focus-within {
	border-color: var(--p1);
}

body.p30a-design .p30a-stepper {
	display: inline-flex;
	align-items: center;
	gap: 0.25rem;
	flex: none;
}

body.p30a-design .p30a-stepper__btn {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 2rem;
	height: 2rem;
	padding: 0;
	background: transparent;
	border: 1px solid #2f7f7d;
	border-radius: var(--radius, 0);
	font-family: var(--font-body);
	font-size: max(1.125rem, 16px);
	line-height: 1;
	color: #2f7f7d;
	cursor: pointer;
}

body.p30a-design .p30a-stepper__btn:hover:not(:disabled),
body.p30a-design .p30a-stepper__btn:focus-visible:not(:disabled) {
	background: #2f7f7d;
	color: var(--white, #fff);
}

body.p30a-design .p30a-stepper__btn:disabled {
	opacity: 0.35;
	cursor: not-allowed;
}

/* Divi styles every button on the site; this one is a 2rem square. */
body.p30a-design .p30a-stepper__btn::after {
	display: none;
}

body.p30a-design .p30a-date-bar__count {
	width: 2.75rem;
	min-width: 0;
	padding: 0;
	background: transparent;
	border: 0;
	font-family: var(--font-body);
	font-size: max(1.25rem, 17px);
	font-weight: 500;
	color: var(--p1);
	text-align: center;
	-moz-appearance: textfield;
}

/* The native spinners duplicate the two steppers beside them. */
body.p30a-design .p30a-date-bar__count::-webkit-outer-spin-button,
body.p30a-design .p30a-date-bar__count::-webkit-inner-spin-button {
	-webkit-appearance: none;
	margin: 0;
}

body.p30a-design .p30a-date-bar__count:focus-visible {
	outline: 2px solid var(--p1);
	outline-offset: 2px;
}


/* --- 24 The panel footer, once the calendar has left ----------------------
   With the dates in the bar and the two numeric fields hidden, Bookings'
   .wc-bookings-booking-form has nothing left to hold but the running total -
   and it was still drawing the chrome it draws around a full form:

     .wc-bookings-booking-form   1px solid #ddd, 12.6px padding, 15.75px below
     .wc-bookings-booking-cost   border-top, and margin: 0 -18.9px

   which rendered as an empty bordered strip with a second, wider box hanging
   out of its sides underneath. The negative side margins are Bookings pulling
   the total out to the edges of a padded container that no longer has padding.

   None of this is removed globally. It is all scoped to p30a-has-date-bar, the
   class the script only sets once the bar is actually running - so a page where
   the bar never initialises keeps Bookings' own framing around its own form.
   -------------------------------------------------------------------------- */

body.p30a-design.p30a-has-date-bar .product-hero__panel form.cart .wc-bookings-booking-form {
	display: block;
	border: 0;
	padding: 0;
	margin: 0;
	gap: 0;
}

/* The total is the only thing left in there, so it stops being a strip inside
   a box and becomes a line of type: no rule above it, no negative margins, and
   the panel's navy rather than the lighter --p3, because it is now the figure
   the customer is actually reading. */
body.p30a-design.p30a-has-date-bar .product-hero__panel form.cart .wc-bookings-booking-cost {
	margin: 0 0 1rem;
	padding: 0;
	border: 0;
	font-size: max(1.25rem, 17px);
	color: var(--p1);
	text-align: left;
}

/* The footer's two columns: the per-day rate on the left, the booking on the
   right. With the calendar gone the right column is a total and a button, so
   it no longer needs to be the wide one - the rate and the total sit on the
   same line instead of the rate floating in its own column of air. */
@media (min-width: 1100px) {
	body.p30a-design.p30a-has-date-bar .product-hero__footer {
		align-items: flex-start;
		gap: 2rem;
	}

	body.p30a-design.p30a-has-date-bar .product-hero__footer > .price {
		flex: 0 0 auto;
		padding-top: 0;
	}

	body.p30a-design.p30a-has-date-bar .product-hero__footer form.cart {
		flex: 1 1 auto;
	}
}


/* --- 25 The per-day suffix ------------------------------------------------
   The comp writes the hero price as

     <p class="product-hero__price-label">From</p>
     <p class="product-hero__price">$85<span>/day</span></p>

   - a large figure with the unit dropped to --fs-label-md beside it. Section
   13.2 carries the first two parts: the "From:" line is the label and .amount
   is the 3.0625rem figure in --p3. (It only actually carries them as of the
   !important noted up there - building this suffix is what exposed that the
   figure had been rendering at Divi's 26px all along, which is why the unit
   looked oversized beside it.) This adds the unit.

   It is generated content rather than markup because the figure is
   WooCommerce's and must stay WooCommerce's. A filter on the price HTML would
   reach the loop cards, the cart, the related rails and the Product/Offer
   structured data, where "/day" has no business being; a ::after on this one
   element in this one panel cannot.

   Applied to the direct child only. A product on sale renders its amounts
   inside <del> and <ins>, so neither is a direct child of .price and the
   suffix simply does not appear - which is the right way for this to fail,
   rather than printing "/day" twice.

   Bookable products only: the merch items are priced per item, and their
   approved briefs say "$25" with no unit at all.

   COLOUR. The comp lets the unit inherit the figure's colour, and it does here
   too. That was worth checking rather than assuming, because a unit at label
   size needs 4.5:1 where the figure beside it only needs 3:1 - inheriting is
   not automatically safe. Measured: the figure is --p3, the comp's own
   #01009a, and on the panel's --s1 (#efefef) that is 12.44:1. The unit
   inherits it and clears the minimum nearly three times over. No override, and
   the price reads as one piece of type exactly as drawn.

   SIZE. --fs-label-md against the figure's 3.0625rem is the comp's own ratio,
   0.51, and the tokens carry it down the breakpoints together (--fs-label-md
   steps 1.5625 / 1.0625 / 1rem). Measured after the 13.2 fix: 19.69px on
   38.59px, 0.51 - the comp exactly. Checked for wrapping down to a 342px
   column with a four-digit price ($1,250.00/day, 199px): one line box, so no
   nowrap guard is needed here.
   -------------------------------------------------------------------------- */

body.p30a-design .product-type-booking .product-hero__footer > .price > .amount::after {
	content: "/day";
	margin-left: 0.125rem;
	font-size: var(--fs-label-md, 1rem);
	letter-spacing: 0.03125rem;
}


/* --- 26 Colour swatches ---------------------------------------------------
   Two of the three merch items come in more than one colour, and their own
   approved spec bars say so - "COLORS: 5 Options". While they were in-store
   items that was a fact about the shelf. Purchasable, it is a choice the cart
   has to carry, so the import writes a required colour field through
   WooCommerce Product Add-Ons (already installed; see inc/vendor-import.php).

   The plugin's own markup is:

     div.wc-pao-addon.wc-pao-required-addon
       label.wc-pao-addon-name          "Color" + em.required
       p.wc-pao-addon-wrap
         a.wc-pao-addon-image-swatch > img      (one per colour)
         select.wc-pao-addon-image-swatch-select (hidden by the plugin; the
                                                  real form field)

   and its own stylesheet gives the swatches a 1px #ddd outline, a #666 hover
   and a #0f834d selected state - a green that belongs to no palette on this
   site. Everything below is that treatment restated in the design's own terms.
   Nothing here is !important: the plugin's rules are single-class, so one
   body.p30a-design in front of them is enough.

   LAYOUT. The panel footer is a row - price on the left, the cart form on the
   right - and the swatches go inside the form. So the form becomes a column:
   the colour row first, then quantity and Add to cart on a line of their own.
   Scoped to simple products because a booking's fieldset is laid out by
   section 21 and must not be touched.

   CONTRAST, measured on the panel's --s1 (#efefef):
     label --p1  #3959ba  5.52:1   (the same treatment as "Included", 19.7px)
     selected outline --p3 #01009a 12.44:1
     resting outline  #767676      3.95:1, above the 3:1 a non-text boundary
                                   needs, and the selected state is not carried
                                   by the outline alone - it also thickens, so
                                   the difference survives a colour-blind or
                                   greyscale view.
   -------------------------------------------------------------------------- */

/* The swatch row makes the cart form two to three times taller than the price
   beside it, and a centred row then leaves the price floating at the middle of
   nothing. Bottom-aligned, the price sits level with Add to cart, which is
   where the comp draws it - measured at 0px difference between the two
   baselines, against 94px centred. */
body.p30a-design .product-type-simple .product-hero__footer {
	align-items: flex-end;
}

body.p30a-design .product-type-simple .product-hero__footer form.cart {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 0.9375rem;
}

body.p30a-design .product-type-simple .product-hero__footer form.cart > .quantity {
	order: 1;
}

body.p30a-design .product-type-simple .product-hero__footer form.cart > .single_add_to_cart_button {
	order: 2;
}

body.p30a-design .product-hero__footer .wc-pao-addon {
	order: 0;
	width: 100%;
	margin: 0;
}

/* The field label, given the "Included" treatment so the panel reads as one
   piece rather than as a plugin bolted to the bottom of it. */
/* MEASURED, not assumed. The first version of this rule lost, and lost to
   section 21's own
     body.p30a-design .product-hero__panel form.cart label      (0,3,3)
   which sizes the booking form's labels and reaches this one too, because an
   add-on label is a label inside form.cart. A (0,3,1) rule does not outrank
   three type selectors. Qualified with the panel, the form and the element so
   this counts (0,4,3) and the label is the size the design asks for - verified
   at 19.69px rather than the 13px it was inheriting. */
body.p30a-design .product-hero__panel form.cart label.wc-pao-addon-name,
body.p30a-design .product-hero__footer .wc-pao-addon-name {
	display: block;
	margin: 0 0 0.5rem;
	font-family: var(--font-body);
	font-size: var(--fs-label-md, 1rem);
	line-height: 1.4;
	text-transform: uppercase;
	color: var(--p1);
}

body.p30a-design .product-hero__footer .wc-pao-addon-name em.required {
	font-style: normal;
	color: var(--p3);
}

/* The plugin hides its own backing select with
     .wc-pao-addon-image-swatch-select { display: none }     (0,1,0)
   and on this site that loses to WooCommerce's
     .woocommerce form .form-row select { display: block }   (0,2,2)
   so the select renders UNDER the swatches as a second, redundant colour
   control. Measured on staging, not guessed. Restated here at (0,3,2), which
   outranks it. The select is still the real form field - the swatches write
   their value into it - and a display:none field still submits. */
body.p30a-design .product-hero__footer select.wc-pao-addon-image-swatch-select {
	display: none;
}

body.p30a-design .product-hero__footer .wc-pao-addon-wrap {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	margin: 0;
}

body.p30a-design .product-hero__footer .wc-pao-addon-image-swatch {
	display: block;
	margin: 0;
	padding: 0.125rem;
	background: #fff;
	outline: 1px solid #767676;
	outline-offset: 0;
	border-radius: 0.125rem;
	transition: outline-color 0.15s ease, outline-width 0.15s ease;
}

body.p30a-design .product-hero__footer .wc-pao-addon-image-swatch img {
	display: block;
	width: 3.25rem;
	height: 3.25rem;
	max-width: none;
	max-height: none;
	object-fit: cover;
	border-radius: 0.0625rem;
}

body.p30a-design .product-hero__footer .wc-pao-addon-image-swatch:hover {
	outline-color: var(--p1);
	outline-width: 2px;
}

/* A swatch is an <a href="#">, so it is in the tab order and has to show it.
   :focus-visible rather than :focus so a mouse click does not leave a ring
   sitting on the swatch afterwards. */
body.p30a-design .product-hero__footer .wc-pao-addon-image-swatch:focus-visible {
	outline: 3px solid var(--p3);
	outline-offset: 2px;
}

body.p30a-design .product-hero__footer .wc-pao-addon-image-swatch.selected {
	outline: 3px solid var(--p3);
	outline-offset: 0;
}

/* The plugin prints its running total under the field. With a colour field
   that costs nothing it has nothing to add and shows a second price below the
   first - the same empty box this panel has been cleared of once already. It
   is switched off in PHP, through the plugin's own
   woocommerce_product_addons_show_grand_total filter and only while every
   add-on on the product is price-neutral, so a priced add-on added later still
   shows its total. This rule is the belt to that brace, and is scoped the same
   way. */
body.p30a-design .product-type-simple .product-hero__footer #product-addons-total:empty {
	display: none;
}

/* The colour's NAME, in words, under the swatches - written by the swatch
   module from the plugin's own option labels. Before a choice it carries the
   plugin's placeholder ("Select an option..."); after one, the colour. Two
   states, two weights of emphasis, both measured on the panel's #efefef:
     prompt  #6b6b6b    4.63:1
     chosen  --p3       12.44:1
   It is aria-live, so the choice is announced as well as shown - which the
   swatches alone never did. */
body.p30a-design .product-hero__footer .p30a-swatch-caption {
	margin: 0.5rem 0 0;
	font-family: var(--font-body);
	font-size: var(--fs-label-md, 1rem);
	line-height: 1.3;
	color: #6b6b6b;
}

body.p30a-design .product-hero__footer .p30a-swatch-caption.is-chosen {
	color: var(--p3);
}

/* With the swatches driving the main photograph, WooCommerce's own thumbnail
   strip is the same five pictures a second time, directly below them. The
   module adds this class once it has a strip to drive, so the strip only
   disappears when something has taken over its job - never before. It is
   still in the DOM and still clickable from script, which is exactly how the
   swatches change the photograph. */
body.p30a-design .p30a-gallery--swatched .flex-control-thumbs {
	display: none;
}

/* Showing the chosen colour's photograph is deliberately NOT done from here.
   FlexSlider writes its layout onto every slide as an INLINE style -
   "width: 701.25px; margin-right: 0px; float: left; display: block;" - and an
   inline display beats any stylesheet rule short of !important. Measured: a
   rule at (0,4,1) left every slide computing block. So the module sets the
   inline display itself and restores what FlexSlider wrote when it lets go.
   The marker class below is kept for the thumbnail strip, which is ordinary
   CSS, and so the state is visible in the DOM. */

body.p30a-design .product-hero__footer .wc-pao-addon-checkbox-required-error,
body.p30a-design .product-hero__footer .wc-pao-addon-error {
	color: #a3200f;
	font-size: var(--fs-label-md, 1rem);
}


/* ---------------------------------------------------------------------------
   27. Category archive: contrast and the FAQ answer's padding
   ---------------------------------------------------------------------------
   Two things the vendor CSS gets wrong once its sections sit on this site.

   1. Contrast. sections.css uses #767676 for the section eyebrow and the
      feature-card copy. That is 4.54:1 on white - it clears AA by a hair - but
      .local-intro and .why-card sit on --s1 (#efefef), where the same grey
      measures 3.95:1 and fails. The card copy is 22.05px regular, below the
      24px that would make it large text, so 4.5:1 is the bar it has to clear.
      #6b6b6b measures 4.63:1 on #efefef and 5.33:1 on white, so it passes on
      both and the greys stay a family rather than becoming two.

      Scoped to the sections that sit on grey. Everywhere the vendor grey is on
      white it already passes and is left alone.

   2. The FAQ answer has no padding. sections.css puts the panel's inset and
      its top rule on

        .faq .accordion__panel > div

      but neither the comp's markup nor this theme's emits that div - the
      answer is a <p> straight inside the panel. Measured: 0px padding, the
      answer flush against the panel's edges and against the question above it.
      The same values are restored for the <p>, which is what is actually
      there. The > div rule is left in place in case a future answer carries
      markup of its own.
   --------------------------------------------------------------------------- */

body.p30a-design .local-intro .eyebrow,
body.p30a-design .why-card__copy {
	color: #6b6b6b;
}

body.p30a-design .faq .accordion__panel > p {
	margin-top: 0;
	padding: 0.625rem 2rem 2rem;
	border-top: 1px solid #e0e0e0;
}


/* ---------------------------------------------------------------------------
   28. Quantity inputs, and the swatch hint's size
   ---------------------------------------------------------------------------
   1. Divi's style-static.min.css ships

        .woocommerce .quantity input.qty,
        .woocommerce-page .quantity input.qty { color:#999; background:#eee;
                                                border:0 }

      at (0,2,1). Measured on the cart: #999 on #eee is 2.46:1 - the number a
      customer is about to change is barely legible - and border:0 leaves the
      field with no boundary at all, so it does not read as a field.

      Restored at (0,3,1), which outranks it on specificity. --p1 on white is
      6.34:1 for the number and #767676 on white is 4.54:1 for the boundary,
      both measured. Scoped to designed pages, so an undesigned WooCommerce
      screen keeps whatever it had.

   2. The colour swatches' hint line ("Select an option...", then the chosen
      colour) was rendering at 19.6875px - to the pixel, the same size as the
      "COLOR *" label above it. A hint that is as loud as its own label reads
      like a second label. Stepped down to 1.25rem, which is the size the
      section eyebrows use for the same job elsewhere in the design.
   --------------------------------------------------------------------------- */

body.p30a-design .woocommerce .quantity input.qty,
body.p30a-design .woocommerce-page .quantity input.qty {
	color: var(--p1);
	background: var(--white, #fff);
	border: 1px solid #767676;
}

/* The appended number on a booking line that has no bike count of its own.
   Matches the client's own inline treatment on the lines that do. */
body.p30a-design .p30a-cart-qty {
	display: inline-block;
	text-align: center;
}

body.p30a-design .p30a-swatch-caption {
	font-size: 1.25rem;
}


/* ---------------------------------------------------------------------------
   29. Holding the product page still while it loads
   ---------------------------------------------------------------------------
   Measured on staging, not guessed at. Two things move the page after first
   paint, and both are below the fold of the hero, so the reader watches the
   bike jump.

   1. THE DATE BAR - whose hidden attribute does not work at all.

      inc/product-page.php renders it as <section ... hidden> and
      shop-bridge.js removes that attribute once WooCommerce Bookings has drawn
      a real calendar for it to drive. That guard is right: a date bar with no
      calendar behind it is worse than no date bar.

      The guard has never fired. Divi's style-static.min.css ships

        section { display: block }

      and an author display declaration beats the user-agent's
      [hidden] { display: none }, so a <section hidden> is not hidden. Measured:
      setting .p30a-date-bar.hidden = true leaves it at 123px, display:block,
      and the hero does not move. The bar has been on screen from first paint
      on every product page, looking live while its buttons were still inert,
      and it would have stayed on screen for good on any page where Bookings
      never produced a calendar.

      Only <section> is affected - div and p carry no such rule, and the three
      other [hidden] elements on the page were measured correctly hidden - but
      the fix is written for the attribute rather than for the one tag, because
      the next <section hidden> would fail the same way.

      Making it work would then introduce the 123px shift it was accused of, so
      the bar's own rule reserves its box and suppresses only its paint.
      Removing hidden reveals it in place and nothing moves - measured at 0px
      against 123px. visibility also takes its contents out of the tab order,
      so nothing in there is reachable while it waits.

      shop-bridge.js adds .p30a-date-bar--off on every path where it has given
      up on the bar, which puts display:none back rather than leaving a gap
      holding space for something that is never coming.

   2. THE GALLERY, about 2,700px on a multi-image product.

      WooCommerce ships the gallery as every image stacked, with the whole
      block at opacity:0, and FlexSlider collapses it into one frame on init.
      opacity hides it but does NOT take it out of the layout, so the page is
      that much taller until the script runs.

      Measured on the rope hat, five images, at 701px wide: 3,269px as the
      server sends it, 504px once FlexSlider has run.

      Below, the slides after the first take no space until FlexSlider has run.
      The rule keys off the wrapper still being a direct child of the gallery -
      FlexSlider moves it inside .flex-viewport, which is a structural fact
      rather than a class anyone has to remember to set - so it releases itself
      at exactly the right moment and needs no counterpart in script.

   Both are scoped to html.p30a-js, set inline in the head (p30a_js_flag), so
   with scripting off the page keeps WooCommerce's own rendering: no reserved
   gap, and every gallery image visible as a plain stack.
   --------------------------------------------------------------------------- */

body.p30a-design [hidden] {
	display: none !important;
}

html.p30a-js .p30a-date-bar[hidden]:not(.p30a-date-bar--off) {
	display: block !important;
	visibility: hidden;
}

html.p30a-js .woocommerce-product-gallery > .woocommerce-product-gallery__wrapper > .woocommerce-product-gallery__image:nth-child(n + 2) {
	display: none;
}


/* ---------------------------------------------------------------------------
   30. Pagination
   ---------------------------------------------------------------------------
   Neither comp has pagination - category.html draws twelve cards and stops -
   so there was nothing to implement against and WooCommerce's default came
   through untouched. Measured on a product search:

     prev arrow   24x25   12.6px   #767676 on transparent        4.54:1
     page 1       17x25   12.6px   #767676 on transparent        4.54:1
     current      20x25   12.6px   #816f98 on #e9e6ed            3.65:1

   Three problems. The targets are 17-24px wide and 25px tall, against the
   44x44 a touch target needs. The current page is drawn in a muted purple that
   belongs to Divi rather than to this palette, and at 3.65:1 it fails AA for
   text - the one item in the row that has to be legible is the least legible.
   And the arrows carry no accessible name beyond the glyph (fixed in
   p30a_pagination_args()).

   Drawn below in the language of the filter pills directly above the grid -
   transparent box, 1px --p1 border, --p1 label, filled for the current one -
   because they are the same kind of control and the page already teaches that
   vocabulary. Sized to 44px rather than to the pills' 336px, which is a
   navigation row, not a filter row.
   --------------------------------------------------------------------------- */

body.p30a-design .woocommerce-pagination {
	margin-top: 3rem;
	text-align: center;
}

/* inline-flex rather than flex, so the nav's own text-align still centres the
   row. woocommerce.css floats the items left inside an inline-block list,
   which collapses the list to 65x27 while the items overflow it - so the float
   is cleared on the item as well as the row being made a flex container.
   Either one alone would do it; both are here because this row has to survive
   whichever of the two vendor rules a future WooCommerce keeps. */
body.p30a-design .woocommerce-pagination ul.page-numbers {
	display: inline-flex;
	flex-wrap: wrap;
	justify-content: center;
	align-items: center;
	gap: 0.5rem;
	margin: 0;
	padding: 0;
	border: 0;
	list-style: none;
}

body.p30a-design .woocommerce-pagination ul.page-numbers li {
	float: none;
	display: inline-flex;
	margin: 0;
	padding: 0;
	border: 0;
	overflow: visible;
}

body.p30a-design .woocommerce-pagination ul.page-numbers li a.page-numbers,
body.p30a-design .woocommerce-pagination ul.page-numbers li span.page-numbers {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	/* max(), not rem alone: this design's root is fluid and resolves to 12.6px
	   on a desktop canvas, where 2.75rem is 35px. Measured at 35x35 before the
	   floor was added - still short of the 44x44 a touch target needs. */
	min-width: max(2.75rem, 44px);
	min-height: max(2.75rem, 44px);
	padding: 0 0.75rem;
	background: transparent;
	border: 1px solid var(--p1);
	border-radius: var(--radius, 0);
	color: var(--p1);
	font-family: var(--font-body);
	font-size: max(1rem, 15px);
	line-height: 1;
	text-decoration: none;
}

/* The page you are on. Filled, the same way the active filter pill is. */
body.p30a-design .woocommerce-pagination ul.page-numbers li span.page-numbers.current,
body.p30a-design .woocommerce-pagination ul.page-numbers li a.page-numbers.current {
	background: var(--p1);
	border-color: var(--p1);
	color: var(--s1, #efefef);
}

body.p30a-design .woocommerce-pagination ul.page-numbers li a.page-numbers:hover,
body.p30a-design .woocommerce-pagination ul.page-numbers li a.page-numbers:focus-visible {
	background: var(--p1);
	border-color: var(--p1);
	color: var(--s1, #efefef);
}

/* The gap marker is not a control: no box, no border, and out of the way. */
body.p30a-design .woocommerce-pagination ul.page-numbers li span.page-numbers.dots {
	min-width: 0;
	padding: 0 0.25rem;
	border-color: transparent;
	background: transparent;
	color: #6b6b6b;
}


/* ---------------------------------------------------------------------------
   31. Card CTA containment on a phone
   ---------------------------------------------------------------------------
   Measured at a 390px viewport on /product-category/merch/: the grid stays at
   two columns, giving a 198.6px card. The CTA keeps its 1.25rem (20px) type,
   its 1.25rem side padding and white-space: nowrap, which leaves 156.6px of
   content box. "SELECT OPTIONS" - WooCommerce's own label for a product with a
   required add-on, which is every merch item once colours are on - measures
   171.6px. It overflowed its button by 15px.

   Two changes, because one alone only fixes today's string:

   1. The type and padding come down, which buys the room. 1.125rem puts the
      same label at 154.4px against 164.6px of box.
   2. white-space returns to normal. A label is allowed to wrap onto a second
      line rather than run out of its button, so a longer one WooCommerce or a
      plugin introduces later - a translated string, "Read more", "Select
      options" in another locale - cannot reopen this. min-height keeps a
      one-line button exactly the height it is now, so nothing moves on the
      cards whose labels still fit.

   Scoped to the breakpoint. Above it the design's own type is untouched. */
@media (max-width: 30rem) {
	.woocommerce body.p30a-design .bike-card a.button.bike-card__cta,
	body.p30a-design .bike-card a.button.bike-card__cta,
	body.p30a-design .bike-card__cta {
		padding: 0.75rem 1rem;
		font-size: 1.125rem;
		white-space: normal;
		text-align: center;
		overflow-wrap: break-word;
	}
}


/* ---------------------------------------------------------------------------
   32. The header's actions on a phone
   ---------------------------------------------------------------------------
   Measured at a 375px viewport, on every page: .site-header__actions starts at
   x=272 and is 236px wide, so it ends at 508 - 133px past the right edge. The
   cart, the phone number and RESERVE NOW are all off-screen. On the shop and
   category pages an overflow-x further up hides the evidence by keeping
   document.scrollWidth at 375, which makes it look fine while the primary call
   to action sits where no thumb can reach it. On the cart and the 404, where
   nothing clips, the whole page scrolls sideways.

   Why ours and not the vendor's: the comp's header carries two actions, the
   phone button and RESERVE NOW. This one carries three - a cart was added,
   because this is a real shop and the comp was not. That is 57px plus a gap
   more than the vendor's mobile rules were written for, and it is what pushes
   the row past the edge. There is no comp for a mobile header with a cart in
   it, so the design cannot answer this one.

   The row wraps rather than anything being dropped or relabelled. Logo and
   menu button keep the first line; the three actions take the second and share
   it. Everything stays reachable, no copy changes, and the only cost is a
   taller header on a phone. Scoped to <=30rem so the vendor's own tablet
   treatment at 768 is untouched. */
@media (max-width: 30rem) {
	body.p30a-design .site-header__inner,
	.site-header .site-header__inner {
		flex-wrap: wrap;
		row-gap: 0.5rem;
		padding-bottom: 0.5rem;
	}

	body.p30a-design .site-header__actions,
	.site-header .site-header__actions {
		order: 3;
		flex: 1 0 100%;
		justify-content: flex-start;
		min-width: 0;
	}

	/* Let the sand button give ground first - it is the widest of the three
	   and the only one with a word in it. It still never wraps. */
	body.p30a-design .site-header__actions .btn--sand,
	.site-header .site-header__actions .btn--sand {
		flex: 0 1 auto;
		min-width: 0;
		white-space: nowrap;
	}

	body.p30a-design .site-header__actions .btn--primary,
	body.p30a-design .site-header__actions .site-header__cart,
	.site-header .site-header__actions .btn--primary,
	.site-header .site-header__actions .site-header__cart {
		flex: 0 0 auto;
	}
}


/* ---------------------------------------------------------------------------
   33. The 404's buttons on a phone
   ---------------------------------------------------------------------------
   Measured at 375px: .p30a-404__btn is 388px wide and sits at left -7, so both
   buttons bleed past both edges and the page scrolls sideways. The row already
   wraps, so each button is on its own line and the width is its own: 2.5rem of
   padding on each side (80px) plus a label that cannot wrap. "Back to Peddlers
   30A" needs more than the 295px that leaves.

   Narrower padding, and the button is allowed to fill the line rather than be
   sized by its text. Above the breakpoint nothing changes. */
@media (max-width: 30rem) {
	body.p30a-design .p30a-404__btn {
		width: 100%;
		max-width: 100%;
		padding: 1rem 1.25rem;
		white-space: normal;
	}

	body.p30a-design .p30a-404__actions {
		width: 100%;
		max-width: 100%;
	}
}


/* ---------------------------------------------------------------------------
   34. The compact hero
   ---------------------------------------------------------------------------
   The storefront's hero, sized to the one the vendor's own inner pages use
   rather than the full-height one they drew for rentals.html - which turned out
   to be their home page, and now exists as their home page. Two pages opening
   with the same photograph at the same scale reads as one page that failed to
   navigate.

   Measured off their live /blog/ at 1440px, which carries the same
   .hero.hero--rentals classes this theme does:

     height    336px   (this theme's full hero: 1046px)
     h1        60px / 700 / line-height 1.1 / letter-spacing -0.02em
     eyebrow   19.2px / letter-spacing 1.8px / the sand, --s3
     lead      19.8px / line-height 1.6
     actions   none - the catalogue below is the call to action

   Height scales down rather than being pinned, so the 336px is the desktop
   figure and a phone gets something proportionate instead of a letterbox. */
body.p30a-design .hero.hero--compact {
	height: auto;
	min-height: 0;
	padding: clamp(3.5rem, 2rem + 7vw, 6.5rem) 0;
}

body.p30a-design .hero.hero--compact .hero__title {
	font-size: clamp(2.25rem, 1.4rem + 3.4vw, 3.75rem);
}

body.p30a-design .hero.hero--compact .hero__lead {
	margin-top: 1rem;
	max-width: 44rem;
}

/* No buttons in this one; the markup omits them, and this stops a stray
   .hero__actions from an edited page opening a gap under the lead. */
body.p30a-design .hero.hero--compact .hero__actions:empty {
	display: none;
}


/* ---------------------------------------------------------------------------
   35. The closing call to action, matched to the vendor's
   ---------------------------------------------------------------------------
   Section 10 already centres this block - .closing-cta carries text-align:
   center, the copy has margin auto, the actions row is justify-content:
   center. It still rendered with the heading hard left and the paragraph
   ragged-left, because .container inside it sets text-align: left and wins on
   the cascade. The centring was being inherited down and then switched off one
   level above the content.

   Measured against their live CTA at 1440 and matched to it:

                        theirs              ours before
     section align      center              center, undone by .container
     heading            centred, w700       LEFT, full width
     paragraph          centred, 480px      left-aligned text in a centred box
     copy colour        solid white         white at 0.9 opacity
     ghost border       rgba(255,255,255,.4) rgba(255,255,255,.6)
     primary button     19.2px              19.2px
     secondary button   10.2px              19.2px

   The two buttons differing in size by about half is theirs, not a slip here -
   see the note in the handover about whether they meant it. */
body.p30a-design .closing-cta .container {
	text-align: center;
}

body.p30a-design .closing-cta__title {
	text-align: center;
}

body.p30a-design .closing-cta__copy {
	text-align: center;
	opacity: 1;
}

body.p30a-design .closing-cta__actions {
	display: flex;
	justify-content: center;
	align-items: center;
}

body.p30a-design .closing-cta__call {
	border-color: rgba(255, 255, 255, 0.4);
	/*
	 * em on font-size resolves against the PARENT's computed size, not the
	 * element's own. The primary button is 19.2px, so 0.55em looked like it
	 * would land near their 10.2px - but the parent row inherits 12px from the
	 * section, and 12 x 0.55 is 6.6px. That is what shipped, and it rendered
	 * unreadable.
	 *
	 * 0.85em against the same 12px parent gives 10.2px, which is theirs.
	 */
	font-size: 0.85em;
}


/* ---------------------------------------------------------------------------
   36. The primary navigation, matched to peddlers30a.com
   ---------------------------------------------------------------------------
   The marketing site collapses its nav into a right-hand drawer at 1440px and
   below. Measured on the live site: inline links at 1442px, hamburger at 1440px,
   the open panel fixed at 264px wide and full height, over a dimming overlay.

   The design package we were given collapses at 768px into a full-width panel
   that drops down under the header - their prototype, built before the live
   site moved the breakpoint out. Between 769px and 1440px the shop therefore
   showed six inline links, a phone button and RESERVE NOW crammed onto one row
   while the marketing site beside it showed a clean hamburger.

   This section closes that gap without editing design/assets/css/*, which stays
   the vendor's file. The rules are deliberately scoped to body.p30a-design so
   they outrank the prototype's bare .site-nav selectors at every width - which
   means one consistent drawer from 1440px down to the smallest phone, rather
   than a dropdown on phones and a drawer on tablets.

   Hidden with visibility rather than display:none so the panel can transition,
   and so its links leave the tab order while it is closed. The JS half - focus
   into the panel, focus trap, focus back to the toggle, scroll lock, close on
   outside click - is in assets/js/shop-bridge.js.
   --------------------------------------------------------------------------- */

@media (max-width: 90rem) {

	body.p30a-design .site-header__toggle {
		display: flex;
	}

	body.p30a-design .site-nav {
		display: flex;
		position: fixed;
		top: 0;
		right: 0;
		bottom: 0;
		left: auto;
		/* 264px is the live site's panel width, measured. Not 16.5rem - the
		   design binds the root font-size to clamp(12px, 100vw/120, 16px), so a
		   rem here would shrink to 198px on the very viewports that need the
		   drawer. px keeps it theirs at every width. */
		width: min(264px, 85vw);
		flex-direction: column;
		align-items: stretch;
		/* The desktop rule is a centred flex row; in column mode that same
		   justify-content centres the six links in 900px of panel and leaves a
		   230px hole above them. */
		justify-content: flex-start;
		gap: 0;
		margin: 0;
		padding: 5.25rem 1.5rem 2rem;
		background: var(--white, #fff);
		box-shadow: -0.75rem 0 2rem rgba(0, 0, 0, 0.16);
		overflow-y: auto;
		overscroll-behavior: contain;
		z-index: 1000;

		/* Closed: off to the right, out of the tab order, not announced. */
		visibility: hidden;
		transform: translateX(100%);
		transition: transform 0.28s ease, visibility 0s linear 0.28s;
	}

	body.p30a-design .site-header.is-open .site-nav {
		visibility: visible;
		transform: translateX(0);
		transition: transform 0.28s ease, visibility 0s linear 0s;
	}

	/* The dimming overlay. A pseudo-element rather than injected markup - the
	   click-to-close is handled by an outside-click listener, so the overlay
	   needs no node of its own. */
	body.p30a-design .site-header.is-open::before {
		content: "";
		position: fixed;
		inset: 0;
		background: rgba(0, 0, 0, 0.45);
		z-index: 999;
	}

	/* The toggle has to sit above both, so it can close what it opened. */
	body.p30a-design .site-header__toggle {
		position: relative;
		z-index: 1001;
	}

	body.p30a-design .site-nav__link,
	body.p30a-design .site-nav a {
		padding: 0.95rem 0;
		border-bottom: 1px solid rgba(0, 0, 0, 0.07);
		font-size: 0.95rem;
		line-height: 1.3;

		/* 44px minimum touch target. */
		min-height: 2.75rem;
		display: flex;
		align-items: center;
	}

	body.p30a-design .site-nav__link.is-active,
	body.p30a-design .site-nav .current-menu-item > a {
		border-left: 3px solid var(--p1, #3959ba);
		padding-left: 0.75rem;
	}
}

/* Anyone who has asked for less motion gets the panel without the slide. */
@media (max-width: 90rem) and (prefers-reduced-motion: reduce) {

	body.p30a-design .site-nav,
	body.p30a-design .site-header.is-open .site-nav {
		transition: none;
	}
}
