/* .footer-nav {
    background-color: #1177BA;
} */

/* Reduce spacing between top navigation and first header section on all divisions */
#content > section:first-of-type,
.content-area .page-header,
.content-area .entry-header {
    padding-top: 10px !important;
    padding-bottom: 10px !important;
}

.breadcrumb,
.breadcrumbs,
.page-title,
h1.entry-title {
    margin-top: 0 !important;
    margin-bottom: 8px !important;
}

/* Trim default padding on generic page header/hero blocks */
.page-header,
.entry-header,
.content-area .section-header {
    padding-top: 8px !important;
    padding-bottom: 12px !important;
}

/* Specific reduction for pageheader blocks to close the gap under the nav */
.element.pageheader {
    padding-top: 20px !important; /* was 50px top in base styles */
}

.element.pageheader .breadcrumb {
    padding-top: 0 !important; /* override pt-md-5 */
    margin-top: 0 !important;
}

.element.pageheader h1 {
    margin-top: 0 !important;
}

.element.listing {
    padding-top: 20px !important;
}

/* ===========================================================================
   Wide listing tiles — 2026-08-21
   ===========================================================================

   A listing tile's width now comes from the shape of its picture: about 2:1
   makes it half the row, about 4:1 the whole row. phTileSpan() in
   includes/thumbnails.php decides; these rules give the tile the right height.

   THE HEIGHT IS THE WHOLE POINT. Every tile in a row must be exactly as tall
   as a one-column tile, or the caption bars stop lining up and it reads as a
   bug rather than a layout. Since padding-bottom is a percentage of the
   element's OWN width, a double-width tile is NOT 50%.

   The reason it is not 50% is the gutter. At xxl the container holds 1296px of
   content and the gutter is 24px, so a one-column card is 1296/4 - 24 = 300px,
   while a two-column card is 1296/2 - 24 = 624px — it swallows a gutter, so it
   is 624 rather than 600. To be 300px tall it needs 300/624 = 48.1%, and 50%
   would stand 12px proud of its neighbours.

   Worked out at every breakpoint, "same height as a one-column tile" is:

     span 2   xs 46.3%   sm 47.6%   md 47.3%   lg 47.3%   xl 47.8%   xxl 48.1%
     span 4   xs 46.3%   sm 47.6%   md 30.9%   lg 23.0%   xl 23.4%   xxl 23.6%

   Span 2 barely moves, so one value covers it — 47.5%, never more than about
   4px out. Span 4 does not, because the grid is not four wide below lg: it is
   three across at md and two across at xs/sm, so "the whole row" is 3x and 2x
   there rather than 4x. Hence the two media queries.

   Redo this arithmetic if the container widths or the 24px gutter ever change.
   =========================================================================== */

.element.listing .each a .has-image.has-square.has-span2:after,
.element.listing .each a .has-image.has-square.has-span4:after {
    padding-bottom: 47.5%;
}

@media (min-width: 768px) {
    /* md: three across, so a full-row tile is 3x a normal one, not 4x. */
    .element.listing .each a .has-image.has-square.has-span4:after {
        padding-bottom: 30.9%;
    }
}

@media (min-width: 992px) {
    /* lg and up: four across at last, so a full-row tile really is 4x. */
    .element.listing .each a .has-image.has-square.has-span4:after {
        padding-bottom: 23.4%;
    }
}

/* ===========================================================================
   Wide tiles: no caption strip, a shadow on hover instead
   ---------------------------------------------------------------------------
   A 2:1 or 4:1 image is composed artwork - its own wording, often its own
   arrow. The theme's .has-content strip repeated the category name underneath
   and added a second arrow (Font Awesome 061), which is the clash. Both go,
   along with the blue hover fill that came with the strip.

   Only the two wide spans are affected. Normal quarter-width tiles keep the
   label, the arrow and the hover fill exactly as before.

   .has-content is the next sibling of .has-image, so the span class on the
   image can reach it without touching the markup or the renderer.
   =========================================================================== */

.element.listing .each a .has-image.has-span2 + .has-content,
.element.listing .each a .has-image.has-span4 + .has-content {
    display: none;
}

/* Nothing else signals that the tile is clickable once the strip is gone, so
   the picture lifts on hover. No offset: the shadow is meant to read as an
   even glow all the way round rather than a light source. */
.element.listing .each a .has-image.has-span2,
.element.listing .each a .has-image.has-span4 {
    transition: box-shadow 0.25s ease;
}

.element.listing .each a:hover .has-image.has-span2,
.element.listing .each a:focus .has-image.has-span2,
.element.listing .each a:hover .has-image.has-span4,
.element.listing .each a:focus .has-image.has-span4 {
    box-shadow: 0 0 14px rgba(17, 17, 17, 0.22);
}

/* Keyboard users get the same cue, and a visible ring so focus is not left
   relying on a shadow alone. */
.element.listing .each a:focus-visible .has-image.has-span2,
.element.listing .each a:focus-visible .has-image.has-span4 {
    outline: 2px solid #1177BA;
    outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
    .element.listing .each a .has-image.has-span2,
    .element.listing .each a .has-image.has-span4 {
        transition: none;
    }
}

/* ---------------------------------------------------------------------------
   Wide tiles fill the whole tile
   ---------------------------------------------------------------------------
   Columns in a row all stretch to the tallest. A normal tile is picture plus a
   100px caption strip; a wide tile has no strip any more, so its column gets
   stretched to match and the difference showed as white under the picture.

   :has() is used to reach the column from the image class inside it. Supported
   everywhere this CMS is used; where it is not, the tile simply keeps the old
   behaviour rather than breaking.
   --------------------------------------------------------------------------- */

/* Match the height of a normal tile.
   A normal tile is a square picture plus a caption strip; a wide tile has no
   strip and would otherwise be shorter, leaving the row ragged. Columns stretch
   to the tallest by default, so the matching height comes for free - the
   picture just has to fill it.

   The stretched box is TALLER in proportion than the saved thumbnail, so cover
   scales to the height, so the overflow is HORIZONTAL - it trims the LEFT and RIGHT
   edges, not the top and bottom. This comment said top and bottom and was wrong,
   which sent wide artwork being composed with margins on the one axis that is
   never cut. Measured 2026-09-11 in headless Edge: the box is 634x400, and a
   1.75:1 tile lost 9.4% of its width - 4.7% off each side.
   phTileSpanDrawnRatios() in includes/thumbnails.php now frames the cropper at
   the real 1.586:1, so a freshly cropped tile is not trimmed at desktop width.
   Below 1200px the box narrows again (1.53 at 1200, 1.37 at 992), so a margin
   at the SIDES is still the safe way to compose wide artwork. */
.element.listing .each:has(.has-image.has-span2) > a,
.element.listing .each:has(.has-image.has-span4) > a {
    display: flex;
    flex-direction: column;
    height: 100%;
}

/* The :after padding sets the shape but must not cap the height, or the picture
   cannot take up the slack the row has given it. */
.element.listing .each:has(.has-image.has-span2) > a .has-image,
.element.listing .each:has(.has-image.has-span4) > a .has-image {
    flex: 1 1 auto;
}

/* Edge to edge. The box is a hair wider than 2:1 to allow for the gutters, so
   cover trims a couple of percent rather than letterboxing - which is what put
   the empty strip back. */
.element.listing .each:has(.has-image.has-span2) > a .has-image,
.element.listing .each:has(.has-image.has-span4) > a .has-image {
    background-size: cover;
    background-position: center;
}

/* ===========================================================================
   Header type-ahead search dropdown  (scripts/quicksearch.js)
   20260916

   DESKTOP ONLY. The panel is a 3x4 grid of product tiles, which does not fit a
   phone; below 1024px the script does not bind and this rule hides the panel
   even if one were somehow rendered.

   The panel is position:fixed and placed by script. Inside the header it would
   be clipped by an ancestor's overflow - the same trap the stockcode
   type-ahead and the campaign-banner URL picker both hit - and the header is
   itself position:fixed with z-index 9999, so the panel has to clear it.
   =========================================================================== */

.phqs {
    position: fixed;
    z-index: 10000;                 /* .main-header is 9999 */
    max-height: 72vh;
    overflow-y: auto;
    background: #fff;
    border: 1px solid #d7dde3;
    border-radius: 6px;
    box-shadow: 0 18px 44px rgba(15, 33, 56, .20);
    font-size: 14px;
    color: #1f2933;
}
.phqs[hidden] { display: none !important; }

@media screen and (max-width: 1023px) {
    .phqs { display: none !important; }
}

/* #0f6cb9 is the site's primary blue - the logo, the tile hover ring below, and
   --swiper-theme-color all use it - so the bar reads as part of the site rather
   than as a new colour introduced by the dropdown. White on it clears 4.5:1. */
.phqs__head {
    padding: 9px 16px;
    background: #0f6cb9;
    border-bottom: 1px solid #0f6cb9;
    font-size: 12.5px;
    font-weight: 700;
    color: #fff;
}

/* 3 across. auto-fit rather than a fixed 3 so the grid still behaves if the
   panel is narrowed on a small laptop. */
/* The dividers are borders on the tiles, NOT a 1px gap over a tinted
   background. The gap trick is neater to write, but the tint shows through any
   cell the results do not fill - 5 results in a 6-cell grid left a blue square
   in the corner. Borders belong to the tiles, so an absent tile draws nothing. */
.phqs__grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
    gap: 0;
    background: #fff;
}

.phqs__tile {
    display: flex;
    align-items: flex-start;
    gap: 11px;
    padding: 11px 13px;
    background: #fff;
    text-decoration: none;
    color: inherit;
    min-height: 74px;
    border-right: 1px solid #e8edf3;
    border-bottom: 1px solid #e8edf3;
}
/* The box goes blue, the background stays white - matching the product tiles,
   which do border-color:#0f6cb9 on hover (styles.css ~3095). A tinted fill was
   a second visual language for the same gesture.

   box-shadow rather than a border change: an inset ring on all four sides
   overrides the 1px divider borders without altering the tile's box, so
   neighbouring tiles do not shift by a pixel as the pointer moves across. */
.phqs__tile:hover,
.phqs__tile:focus {
    background: #fff;
    text-decoration: none;
    box-shadow: inset 0 0 0 2px #0f6cb9;
    position: relative;             /* lift the ring above adjacent borders */
    z-index: 1;
}

.phqs__shot {
    flex: 0 0 56px;
    width: 56px; height: 56px;
    display: flex; align-items: center; justify-content: center;
    background: #fff;
    /* No border. The product shots are cut-outs on white, so a box around them
       framed empty space rather than the product and made the grid look like a
       spreadsheet. */
    overflow: hidden;
}
/* Fill the box and letterbox, rather than max-width/max-height. This is a flex
   container, and as a flex item an <img> constrained only by max-* has its width
   and height resolved separately - so a tall, narrow shot such as 06610 (83x245)
   was stretched out to the full square. object-fit keeps the proportions. */
.phqs__shot img { width: 100%; height: 100%; object-fit: contain; display: block; }
.phqs__shot--none { background: #f5f7fa; border-radius: 3px; }

.phqs__text { min-width: 0; display: flex; flex-direction: column; gap: 2px; }

.phqs__code {
    font-weight: 700;
    font-size: 13.5px;
    color: #0f4c81;
    word-break: break-all;          /* stock codes are long and unbreakable */
}
.phqs__desc {
    font-size: 12.5px;
    line-height: 1.34;
    color: #52627a;
    /* Two lines, then ellipsis: tiles have to stay the same height or the grid
       rows go ragged. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.phqs__pages { display: flex; flex-wrap: wrap; gap: 0; background: #fff; }
.phqs__page {
    flex: 1 1 250px;
    padding: 10px 13px;
    background: #fff;
    border-right: 1px solid #e8edf3;
    border-bottom: 1px solid #e8edf3;
    text-decoration: none;
    color: #0f4c81;
    font-size: 13.5px;
    font-weight: 600;
}
.phqs__page:hover {
    background: #fff;
    text-decoration: none;
    box-shadow: inset 0 0 0 2px #0f6cb9;
    position: relative;
    z-index: 1;
}

.phqs__more {
    padding: 11px 16px;
    border-top: 1px solid #e3e8ef;
    background: #fafbfd;
    font-size: 13px;
    color: #52627a;
    text-align: center;
}
.phqs__more kbd {
    display: inline-block;
    padding: 1px 6px;
    border: 1px solid #c8d2df;
    border-bottom-width: 2px;
    border-radius: 4px;
    background: #fff;
    font-family: inherit;
    font-size: 12px;
    font-weight: 700;
    color: #1f2933;
}

.phqs__none { padding: 18px 16px; color: #52627a; text-align: center; }

/* ---------------------------------------------------------------------------
   Search results: close the gap under the grey page header.

   The results grid is a <section class="element listing"> that dcg/search.php
   emits INTO a page, and templates/pages.html wraps every page body in a
   generic <section class="element">. Both carry .element's `padding: 80px 0`,
   so 160px of empty white opened between the grey "Search Results" band and
   the first line of results.

   Zeroing the inner section's own padding removes only half of it. The other
   half belongs to the wrapper in pages.html, which renders EVERY page on the
   site - it cannot be zeroed there for the sake of one page - so the inner
   section is pulled back up over it instead.

   The pull therefore mirrors .element's own padding, which is responsive:
   80px by default and 50px under 991px (styles.css ~1559 and ~3700). Both
   values leave ~24px of deliberate breathing room. IF .element's PADDING IS
   EVER RETUNED, THESE TWO NUMBERS MUST FOLLOW IT.

   Safe against the wrapper's `overflow: hidden`: clipping happens at the
   padding box, and a pull smaller than the padding stays inside it.

   Deliberately NOT done with a `.element .element.listing` descendant rule:
   productTitlesByStockcodes and productTitlesByFamilyName emit the same
   markup, and those are the supplier pages whose spacing is already approved.
   Hence the extra class, applied only by search.php.

   Bottom padding is left alone - the wrapper's own is still doubled there, but
   that space reads as the end of the page rather than as a gap.
   --------------------------------------------------------------------------- */
.element.listing.phsearchresults {
    padding-top: 0;
    margin-top: -56px;      /* 80px wrapper padding, less 24px kept */
}
@media (max-width: 991px) {
    .element.listing.phsearchresults {
        margin-top: -26px;  /* 50px wrapper padding, less 24px kept */
    }
}

/* ---------------------------------------------------------------------------
   Search results: the "Pages matching" tiles.

   These reuse the site's .each / .has-content tile, which already fills
   #0f6cb9 and sets color:#fff on hover (styles.css ~1694). The title and blurb
   were originally coloured with style attributes, and an inline style outranks
   any stylesheet rule - so the fill went blue while the words stayed near
   black, which was unreadable. Colours therefore live here, where the hover
   rule can win.

   The pale frame on hover was the same cause seen from the other side: the
   anchor's own `1px solid #e9ecef` border and .has-content's border-top stayed
   grey against the blue fill and read as a white outline. Both are taken to
   the fill colour on hover.

   Scoped to .phsearchresults .phpagetile so the product tiles - whose look is
   already settled - are untouched.
   --------------------------------------------------------------------------- */
.phsearchresults .each.phpagetile a .has-content h6 {
    color: #222;
}
.phsearchresults .each.phpagetile .phpagetile__blurb {
    font-weight: 400;
    font-size: 12px;
    color: #555;
}
.phsearchresults .each.phpagetile a:hover .has-content h6,
.phsearchresults .each.phpagetile a:focus .has-content h6,
.phsearchresults .each.phpagetile a:hover .phpagetile__blurb,
.phsearchresults .each.phpagetile a:focus .phpagetile__blurb {
    color: #fff;
}
.phsearchresults .each.phpagetile a:hover,
.phsearchresults .each.phpagetile a:focus {
    border-color: #0f6cb9;
}
.phsearchresults .each.phpagetile a:hover .has-content,
.phsearchresults .each.phpagetile a:focus .has-content {
    border-top-color: #0f6cb9;
}
