@font-face{font-family:'Montserrat';font-style:normal;font-weight:600;font-display:swap;src:url(/assets/montserrat-600.woff2?v=uj8hdp) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face{font-family:'Montserrat';font-style:normal;font-weight:700;font-display:swap;src:url(/assets/montserrat-600.woff2?v=uj8hdp) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face{font-family:'Source Sans 3';font-style:normal;font-weight:400;font-display:swap;src:url(/assets/source-sans-3-400.woff2?v=g1p126) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face{font-family:'Source Sans 3';font-style:normal;font-weight:600;font-display:swap;src:url(/assets/source-sans-3-400.woff2?v=g1p126) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}

:root {
  /* --blue is the ACCENT: links, active nav, headings, icon strokes. It moves
     with the theme and goes lighter in dark mode.
     --brand-fill is the SOLID: anything with white text sitting on it. It must
     stay dark enough for that text in both themes, so the two cannot be one
     token - lightening the accent for dark mode would put white on pale blue. */
  --blue: #006898;
  --brand-fill: #006898;
  --blue-deep: #00537A;
  --blue-tint: #E8F4F9;
  --tint-line: #CFE4EF;
  --cyan: #00B0D8;
  /* Same split as --blue / --brand-fill. --green is the accent (savings figures,
     the live-stock tick); --green-fill is the solid behind white button text,
     and is darker because #469C15 under white is 3.9:1 and the dark theme's
     lighter green was 2.7:1 - both short of the 4.5:1 small text needs. */
  --green: #469C15;
  --green-fill: #357A0F;
  --red: #C4211F;
  --amber: #B26A00;
  --ground: #DCE5EC;
  --surface: #FFFFFF;
  --surface-2: #F7FBFD;
  --ink: #13242E;
  --muted: #5D7284;
  --line: #DBE7EE;
  --line-strong: #BFD2DE;
  --ok-bg: #E6F3DE; --ok-ink: #35750F;
  --low-bg: #FBEFD9; --low-ink: #8A5200;
  --out-bg: #EDF1F4; --out-ink: #77879A;
  --shadow: 0 1px 2px rgba(0,60,90,.07), 0 12px 28px -20px rgba(0,60,90,.45);

  /* Page container width. Both .wrap and .megawrap read this, so the page and
     the mega menu can never drift to different widths. */
  --page: 96rem;

  /* Corner rounding, in one place on purpose. Every boxed surface on every page
     reads from --radius, so the whole site retunes by changing this one number.
     --radius-sm is for controls sitting inside a rounded box, which need a
     tighter curve or they read as bulging out of it; --radius-lg is the hero,
     which the concept mockup gives a deliberately larger curve. */
  --radius: 8px;
  --radius-sm: 6px;
  --radius-lg: 16px;
  --display: "Montserrat", "Helvetica Neue", Arial, sans-serif;
  --body: "Source Sans 3", "Segoe UI", Helvetica, Arial, sans-serif;
  /* System monospace. IBM Plex Mono was dropped: it appeared only on SKUs and
     figures, where the platform face is near-indistinguishable, and it cost
     14.7KB and a request on every first visit. */
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
}

/* ---------- dark theme ----------
   Only the palette changes; not one layout rule is duplicated. The switch sets
   data-theme on <html>, and "no choice yet" follows the operating system.
   Solid brand fills stay dark (see --brand-fill) so the white text on them is
   unchanged, while the accent lightens to stay readable on a dark ground. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { color-scheme: dark;
    --blue: #5CBFEA; --brand-fill: #0E4A69; --blue-deep: #0A2E42;
    --blue-tint: #12303F; --tint-line: #1E4257; --cyan: #35C9EC;
    --green: #57B22B; --green-fill: #357A0F; --red: #E4635F; --amber: #D99425;
    --ground: #0B1620; --surface: #132330; --surface-2: #182C3A;
    --ink: #E7EFF5; --muted: #93A9B9; --line: #22394A; --line-strong: #34505F;
    --ok-bg: #14301A; --ok-ink: #8FD86A;
    --low-bg: #33280F; --low-ink: #E0B45C;
    --out-bg: #1E2A33; --out-ink: #8FA3B3;
    --shadow: 0 1px 2px rgba(0,0,0,.45), 0 12px 28px -20px rgba(0,0,0,.9); }
}
:root[data-theme="dark"] { color-scheme: dark;
  --blue: #5CBFEA; --brand-fill: #0E4A69; --blue-deep: #0A2E42;
  --blue-tint: #12303F; --tint-line: #1E4257; --cyan: #35C9EC;
  --green: #57B22B; --green-fill: #357A0F; --red: #E4635F; --amber: #D99425;
  --ground: #0B1620; --surface: #132330; --surface-2: #182C3A;
  --ink: #E7EFF5; --muted: #93A9B9; --line: #22394A; --line-strong: #34505F;
  --ok-bg: #14301A; --ok-ink: #8FD86A;
  --low-bg: #33280F; --low-ink: #E0B45C;
  --out-bg: #1E2A33; --out-ink: #8FA3B3;
  --shadow: 0 1px 2px rgba(0,0,0,.45), 0 12px 28px -20px rgba(0,0,0,.9); }


/* 18 Oct 2026: the light theme's thin lines (card edges, separators, boxes,
   tables) a step darker, the same values the POS took on 17 Oct
   (worker-pos/views.ts). Plain :root, so the dark theme's selectors in TOKENS
   still outrank it. Shared tokens.ts is left alone for the WMS and backend. */
:root { --line: #B3C6D2; --line-strong: #8AA3B4; }
/* ==========================================================================
   SECTION: Page basics
   body, links, page width
   ========================================================================== */
* { box-sizing: border-box; }
/* Always keep the scrollbar's space (Jacob, 18 Oct 2026). The product page
   streams: everything below the stock panel arrives with the stock, so the
   page starts short with no scrollbar, then grows one, and the centred page
   jumped sideways by half its width. Phones' overlay scrollbars are unaffected. */
html { scrollbar-gutter: stable; }
body { margin: 0; background: var(--ground); color: var(--ink); font-family: var(--body); font-size: 16px; line-height: 1.55; -webkit-font-smoothing: antialiased; }
a { color: var(--blue); }
.wrap { max-width: var(--page); margin: 0 auto; padding: 0 1.25rem; }
@media (min-width: 90rem) { .wrap, .megawrap { padding: 0 2rem; } }

/* ==========================================================================
   SECTION: Utility bar
   The blue strip at the very top: its links, the My Account menu and the
   light/dark switch.
   ========================================================================== */
.utility { background: var(--brand-fill); color: #fff; }
.utility .wrap { display: flex; align-items: center; justify-content: flex-end; gap: 1.4rem; min-height: 2.6rem;
  font-family: var(--display); font-size: .68rem; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; }
.utility a { white-space: nowrap; }
/* The bar is justified to the right, so anything that does not fit overflows
   off the LEFT edge, silently unreachable rather than visibly clipped.
   Wrapping to a second line is the honest failure mode on a narrow screen. */
@media (max-width: 60rem) {
  .utility .wrap { flex-wrap: wrap; justify-content: center; gap: .1rem 1.1rem;
    padding-top: .45rem; padding-bottom: .45rem; }
  .utility { font-size: .78rem; }
  .utility .sep { display: none; }
}
.utility a { color: #fff; text-decoration: none; opacity: .9; }
.utility a:hover { opacity: 1; }
/* Groups the bar into browse / order / quote / account. Decoration, so it is
   aria-hidden in the markup and sized from the text rather than a fixed pixel
   height, and it takes half the row gap on each side rather than adding width. */
.utility .sep { flex: none; width: 1px; height: 1.05em; background: currentColor; opacity: .32;
  margin: 0 -.55rem; }
/* My Account is a menu, not a link. A details element so it opens without
   script; the script above only closes it. The panel drops from the right
   edge on a desktop and spans the bar on a phone, where the bar wraps and
   there is no right edge to hang from. */
.acctmenu { position: relative; }
.acctmenu > summary { list-style: none; cursor: pointer; user-select: none; white-space: nowrap; opacity: .9; }
.acctmenu > summary:hover, .acctmenu[open] > summary { opacity: 1; }
.acctmenu > summary::-webkit-details-marker { display: none; }
/* A proper chevron rather than a small triangle glyph: drawn with borders so
   it is the same size in every font, and it turns over when the menu is open. */
.acctmenu > summary::after { content: ""; display: inline-block; width: .45em; height: .45em; margin-left: .45em;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor; transform: translateY(-.2em) rotate(45deg);
  transition: transform .15s; }
.acctmenu[open] > summary::after { transform: translateY(.1em) rotate(-135deg); }
.acctmenu .menu { position: absolute; right: 0; top: calc(100% + .45rem); z-index: 60; min-width: 13.5rem;
  background: var(--surface); color: var(--ink); border: 1px solid var(--line-strong); border-radius: var(--radius);
  box-shadow: 0 14px 34px -14px rgba(0,0,0,.5); padding: .4rem; display: flex; flex-direction: column;
  text-transform: none; letter-spacing: 0; font-family: var(--body); font-weight: 500; font-size: .92rem; }
.acctmenu .menu a { color: var(--ink); opacity: 1; padding: .5rem .75rem; border-radius: var(--radius-sm); }
.acctmenu .menu a:hover { background: var(--blue-tint); }
.acctmenu .menu a.out { border-top: 1px solid var(--line); margin-top: .3rem; padding-top: .7rem; color: var(--muted); border-radius: 0; }
@media (max-width: 60rem) {
  .utility .wrap { position: relative; }
  .acctmenu { position: static; }
  .acctmenu .menu { left: .6rem; right: .6rem; top: 100%; }
}
/* The cart moved out of this bar and next to the search field, where it is a
   primary control rather than a utility link. */
.themeswitch { background: none; border: 0; padding: .3rem; margin: 0 -.3rem 0 .4rem; cursor: pointer;
  color: #fff; opacity: .85; display: inline-flex; align-items: center; border-radius: var(--radius-sm); }
.themeswitch:hover { opacity: 1; }
.themeswitch:focus-visible { outline: 2px solid #fff; outline-offset: 1px; }
.themeswitch svg { display: block; }
/* Show the icon for the theme you would switch TO, which is the convention
   people already read: a moon means "go dark". */
.themeswitch .ico-moon { display: block; }
.themeswitch .ico-sun { display: none; }
:root[data-theme="dark"] .themeswitch .ico-moon { display: none; }
:root[data-theme="dark"] .themeswitch .ico-sun { display: block; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .themeswitch .ico-moon { display: none; }
  :root:not([data-theme="light"]) .themeswitch .ico-sun { display: block; }
  :root[data-theme="dark"] .themeswitch .ico-moon { display: none; }
  :root[data-theme="dark"] .themeswitch .ico-sun { display: block; }
}

/* ==========================================================================
   SECTION: Masthead
   Logo, search box, the Cart and Quote buttons, and the main menu links.
   The drop-down mega menu itself is in nav.ts.
   ========================================================================== */
.masthead { background: var(--surface); border-bottom: 1px solid var(--line); }
.masthead .wrap { display: flex; flex-direction: column; align-items: center; gap: 1.1rem; padding-top: 20px; padding-bottom: 1rem; }
/* Logo, search and cart on one line. The search field is the flexible element,
   so the logo and the cart keep their intrinsic size and the field absorbs the
   rest of the width. */
.masthead-top { display: flex; align-items: center; gap: 1.5rem; width: 100%; }
.masthead-top .brand { flex: none; line-height: 0; }
.masthead-top .sitesearch { flex: 1; max-width: none; margin: 0; }
.cartbtn { flex: none; display: inline-flex; align-items: center; gap: .55rem;
  padding: .78rem 1.25rem; border-radius: var(--radius-sm); background: var(--green-fill);
  color: #fff; text-decoration: none; font-family: var(--display); font-weight: 600;
  font-size: .8rem; letter-spacing: .05em; text-transform: uppercase;
  border: 1px solid transparent; box-shadow: 0 1px 2px rgba(0,60,90,.14); }
.cartbtn:hover { filter: brightness(1.07); }
/* Same shape as Cart, quieter fill. Both are baskets, but only one of them is
   the one you are buying out of today. */
.quotebtn { background: transparent; border-color: rgba(255,255,255,.55); color: var(--blue); border-color: var(--line-strong); }
.quotebtn:hover { background: var(--blue-tint); filter: none; }
.quotebtn .cartcount { background: var(--blue); color: #fff; }
.cartcount { font-family: var(--mono); font-weight: 600; font-size: .78rem;
  background: rgba(255,255,255,.22); border-radius: 999px; padding: .05rem .5rem; letter-spacing: 0; }
@media (max-width: 60rem) {
  /* Search drops to its own line: three controls on one row leaves the field
     too narrow to read a SKU in. */
  .masthead-top { flex-wrap: wrap; gap: .8rem 1rem; }
  .masthead-top .brand { margin-right: auto; }
  .masthead-top .sitesearch { order: 3; flex-basis: 100%; }
  .cartbtn .cartlabel { display: none; }
  .cartbtn { padding: .6rem .8rem; }
}
.logo { height: 3.9rem; width: auto; max-width: 100%; display: block; }
nav.primary { display: flex; justify-content: center; gap: 1.6rem; flex-wrap: wrap;
  font-family: var(--display); font-weight: 600; font-size: .78rem; letter-spacing: .05em; text-transform: uppercase; }
/* Scoped to the direct children of a nav group, never to every anchor inside
   the nav. These three rules are meant for the seven top-level links, but as
   "nav.primary a" they also hit everything in the open mega panel - at (0,1,1)
   they outrank ".btn" at (0,1,0), so buttons in the menu inherited the flat
   link padding AND the transparent 2px bottom border, which read as a button
   with three sides. Scoping is the fix; patching each property was not. */
nav.primary .navgroup > a { color: var(--ink); text-decoration: none; padding: .2rem 0; border-bottom: 2px solid transparent; }
nav.primary .navgroup > a:hover { color: var(--blue); }
nav.primary .navgroup > a.current { color: var(--blue); border-bottom-color: var(--blue); }

/* ==========================================================================
   SECTION: Account bar
   The strip under the header for a signed-in customer (account, balance).
   ========================================================================== */
/* 18 Oct 2026 (Jacob): a fade, the bottom one shade darker than the page
   (--ground #DCE5EC light, #0B1620 dark) rising to the bar's earlier lighter
   shade at the top; and larger text. */
:root { --acctbar-top: #E8F0F5; --acctbar: #CDD8E1; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { --acctbar-top: var(--surface-2); --acctbar: #07111A; } }
:root[data-theme="dark"] { --acctbar-top: var(--surface-2); --acctbar: #07111A; }
.accountbar { background: var(--acctbar); background-image: linear-gradient(to bottom, var(--acctbar-top), var(--acctbar));
  border-bottom: 1px solid var(--line); }
.accountbar .wrap { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem 2rem; padding-top: .7rem; padding-bottom: .7rem; }
.acct { display: flex; flex-direction: column; gap: .05rem; }
.acct .k { font-family: var(--mono); font-size: .8rem; letter-spacing: .09em; text-transform: uppercase; color: var(--muted); }
.acct .v { font-weight: 600; font-size: 1.04rem; }
.acct .v.money { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.acct.push { margin-left: auto; }
/* PS Rewards: a gold star, "Shop & Earn" and a Trips pill (no points for now, 28 Oct 2026). */
.acct.rewards { text-decoration: none; color: inherit; border-radius: var(--radius-sm); margin: -.3rem -.5rem; padding: .3rem .5rem; }
.acct.rewards:hover { background: rgba(255,255,255,.45); }
.acct.rewards:hover .v { text-decoration: underline; text-underline-offset: 3px; }
/* On the right, after Account (Jacob, 18 Oct 2026). */
.acct.rewards .v { display: inline-flex; align-items: center; gap: .35rem; font-family: var(--display); font-weight: 700; color: var(--blue); }
.acct.rewards svg { width: 1rem; height: 1rem; fill: #E2A400; }
.acct.rewards .trips { font-family: var(--body); font-weight: 600; font-size: .78rem; color: var(--ok-ink); background: var(--ok-bg);
  border-radius: 999px; padding: .1rem .55rem; margin-left: .25rem; white-space: nowrap; }
.acct .sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* ==========================================================================
   SECTION: Gallery
   gallery() in worker/views/gallery.ts: tiles, and the full-screen viewer
   with Previous / Next and swipe. For any page (Rewards trips first).
   ========================================================================== */
.gal { display: grid; grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr)); gap: 1rem; }
.gal-item { position: relative; display: block; aspect-ratio: 4 / 3; border-radius: var(--radius); overflow: hidden;
  border: 1px solid var(--line); background: var(--surface-2) center / cover no-repeat; cursor: zoom-in; text-decoration: none; }
.gal-item::after { content: ""; position: absolute; inset: 0; background: linear-gradient(0deg, rgba(4,24,38,.7), rgba(4,24,38,0) 45%); transition: opacity .2s; }
.gal-item:hover::after { opacity: .75; }
.gal-label { position: absolute; left: .9rem; right: .9rem; bottom: .75rem; z-index: 1; color: #fff; }
.gal-label b { display: block; font-family: var(--display); font-size: 1.05rem; }
.gal-label span { font-size: .85rem; opacity: .9; }
.gal-view { width: 100vw; height: 100vh; height: 100dvh; max-width: none; max-height: none; margin: 0; padding: 0; border: 0;
  background: rgba(4,14,22,.94); color: #fff; overscroll-behavior: contain; }
.gal-view::backdrop { background: rgba(4,14,22,.6); }
.gal-view figure { margin: 0; height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: .8rem; padding: 3.2rem 5rem 2rem; touch-action: pan-y; }
.gal-view img { max-width: 100%; max-height: calc(100% - 3rem); object-fit: contain; border-radius: var(--radius); user-select: none; -webkit-user-drag: none; }
.gal-view img { transition: opacity .15s; }
.gal-view img.loading { opacity: .25; }
.gal-view figcaption { display: flex; gap: 1.2rem; align-items: baseline; font-size: .98rem; }
.gal-n { font-family: var(--mono); font-size: .8rem; opacity: .75; }
.gal-btn, .gal-close { position: absolute; border: 0; cursor: pointer; color: #fff; background: rgba(255,255,255,.14);
  display: flex; align-items: center; justify-content: center; line-height: 1; }
.gal-btn { top: 50%; transform: translateY(-50%); width: 3.2rem; height: 3.2rem; border-radius: 50%; font-size: 2.2rem; padding-bottom: .2rem; }
.gal-btn:hover, .gal-close:hover { background: rgba(255,255,255,.28); }
.gal-prev { left: 1rem; } .gal-next { right: 1rem; }
.gal-close { top: 1rem; right: 1rem; width: 2.6rem; height: 2.6rem; border-radius: 50%; font-size: 1.7rem; }
.gal-view.single .gal-btn { display: none; }
@media (max-width: 40rem) {
  .gal { grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr)); }
  .gal-view figure { padding: 3.4rem .6rem 1.4rem; }
  /* On a phone the photo takes the width; the arrows sit low and small, swiping does the work. */
  .gal-btn { top: auto; bottom: 1rem; transform: none; width: 2.6rem; height: 2.6rem; font-size: 1.8rem; }
}

/* ==========================================================================
   SECTION: Buttons
   .btn plus a colour: .btn-green (buy), .btn-blue (main action),
   .btn-ghost (secondary), .btn-outline. Size: .btn-sm (in Quantity stepper).
   ========================================================================== */
.btn { font-family: var(--display); font-weight: 600; font-size: .78rem; letter-spacing: .05em; text-transform: uppercase;
  padding: .85rem 1.75rem; border-radius: var(--radius-sm); border: 1px solid transparent; text-decoration: none;
  display: inline-flex; align-items: center; gap: .5rem; cursor: pointer; }
.btn-green { background: var(--green-fill); color: #fff; }
.btn-blue { background: var(--brand-fill); color: #fff; transition: box-shadow .15s, filter .15s; }
/* A glow on hover for the filled buttons, so Sign in and Place order answer the pointer. */
.btn-blue:hover { filter: brightness(1.08);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand-fill) 28%, transparent), 0 8px 20px -6px var(--brand-fill); }
.btn-green { transition: box-shadow .15s, filter .15s; }
.btn-green:hover { filter: brightness(1.06);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--green) 28%, transparent), 0 8px 20px -6px var(--green); }
/* A white button on a white strip needs its own edge to read as a control,
   so the ghost variant carries a slightly stronger border plus a hairline
   shadow. Both, not one: the border defines the shape, the shadow lifts it. */
.btn-ghost { background: var(--surface); color: var(--blue); border-color: var(--line-strong);
  box-shadow: 0 1px 2px rgba(0,60,90,.10), 0 1px 0 rgba(0,60,90,.04); }
.btn-ghost:hover { border-color: var(--blue); box-shadow: 0 2px 5px rgba(0,60,90,.14); }
.btn-outline { background: transparent; color: var(--blue); border-color: var(--blue); }

/* ==========================================================================
   SECTION: Page sections and hero
   Bands (the full-width page sections), section headings, the home hero.
   ========================================================================== */
.band { padding: 2.4rem 0; }
/* A page that opens with breadcrumbs starts close under the header bar. */
.band:has(> .wrap > .crumbs:first-child) { padding-top: 1.1rem; }
.band.alt { background: var(--surface); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.section-head { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; flex-wrap: wrap; margin-bottom: 1.2rem; }
.section-head h2 { font-family: var(--display); font-weight: 700; font-size: 1.18rem; margin: 0; }
.section-head .note { color: var(--muted); font-size: .9rem; }

/* The hero photo carries the ProSource wordmark and strapline baked in, so it
   is never cropped: the box matches the image's own 1437x670 proportions at
   every width. On desktop the mockup scales it to 80% and centres it, which is
   what stops a full-bleed banner from swallowing the fold. */
.hero { width: 100%; aspect-ratio: 1437 / 670; background-size: cover; background-position: center;
  background-color: #0B1B2B; border-bottom: 1px solid var(--line); }
/* Sized by the window's height as well as its width (Jacob, 28 Oct 2026): the
   two callouts under it must clear the fold on a laptop screen. */
@media (min-width: 60rem) {
  .hero { width: min(80%, max(26rem, calc((100svh - 32rem) * 1437 / 670))); margin: 24px auto 0;
    border: 1px solid var(--line); border-radius: var(--radius-lg); }
}
.hero-copy { background: var(--surface); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
  padding: 1.6rem 0 1.7rem; margin-top: 1.4rem; }
.callouts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.25rem 2.5rem; }
@media (max-width: 50rem) { .callouts { grid-template-columns: 1fr; } }
/* Centred per column, with the buttons on one line across both (Jacob, 28 Oct 2026). */
.callout { display: flex; flex-direction: column; align-items: center; text-align: center; }
.callout p { margin-left: auto; margin-right: auto; }
@media (min-width: 75rem) { .callout p { flex: 1; } }
.callout .hero-actions { justify-content: center; }
.callout.design { border-left: 1px solid var(--line); padding-left: 2.5rem; }
@media (max-width: 50rem) { .callout.design { border-left: 0; padding-left: 0; border-top: 1px solid var(--line); padding-top: 1.25rem; } }
.hero-copy h1, .hero-copy h2 { font-family: var(--display); font-weight: 700; color: var(--ink);
  font-size: clamp(1.45rem, 2.6vw, 2rem); line-height: 1.14; margin: 0 0 .55rem; text-wrap: balance; }
.hero-copy h1 em { font-style: normal; color: var(--blue); }
.hero-copy p { color: var(--muted); margin: 0 0 1.1rem; font-size: 1.02rem; max-width: 34rem; }
.hero-actions { display: flex; flex-wrap: wrap; gap: .7rem; }

/* ==========================================================================
   SECTION: Category tiles
   The photo tiles on the home and category pages.
   ========================================================================== */
.tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: 1rem; }
.tile { position: relative; min-height: 11rem; border-radius: var(--radius); overflow: hidden;
  background-size: cover; background-position: center; display: flex; align-items: flex-end;
  border: 1px solid var(--line); text-decoration: none; }
.tile::after { content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(12,26,45,0) 30%, rgba(12,26,45,.84) 100%); }
.tile span { position: relative; z-index: 1; font-family: var(--display); font-weight: 700; font-size: .84rem;
  letter-spacing: .07em; text-transform: uppercase; color: #fff; padding: 1rem 1.1rem; }
.tile:hover { border-color: var(--line-strong); box-shadow: var(--shadow); }
/* Home tiles: a short "what's inside" line under the name, shown on hover or
   keyboard focus, and always on touch screens where there is no hover. */
.hometiles { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 60rem) { .hometiles { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 40rem) { .hometiles { grid-template-columns: 1fr; } }
.hometiles .tile { flex-direction: column; align-items: stretch; justify-content: flex-end; }
.hometiles .tile::after { transition: background .2s ease; }
.hometiles .tile .tile-name { padding-bottom: .35rem; }
.hometiles .tile .tile-list { font-family: var(--body); font-weight: 500; font-size: .86rem; line-height: 1.4;
  letter-spacing: 0; text-transform: none; color: rgba(255,255,255,.92); padding: 0 1.1rem 1rem;
  max-height: 0; opacity: 0; overflow: hidden; transition: max-height .25s ease, opacity .2s ease; }
.hometiles .tile:hover .tile-list, .hometiles .tile:focus-visible .tile-list { max-height: 6rem; opacity: 1; }
.hometiles .tile:hover::after, .hometiles .tile:focus-visible::after {
  background: linear-gradient(180deg, rgba(12,26,45,.15) 0%, rgba(12,26,45,.9) 100%); }
@media (hover: none) { .hometiles .tile .tile-list { max-height: none; opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .hometiles .tile .tile-list, .hometiles .tile::after { transition: none; } }

/* ==========================================================================
   SECTION: Product cards
   The product grid on category and search pages: each card, its photo,
   brand, SKU, price, the favourite heart and the Add button.
   ========================================================================== */
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); gap: 1rem; }
.card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); display: flex; flex-direction: column;
  overflow: hidden; text-decoration: none; color: inherit; }
.card:hover { border-color: var(--line-strong); box-shadow: var(--shadow); }
.card .shot { aspect-ratio: 1/1; background: var(--surface-2); border-bottom: 1px solid var(--line); overflow: hidden; }
.card .shot img { width: 100%; height: 100%; object-fit: contain; display: block; }
.card .body { padding: .85rem .95rem; display: flex; flex-direction: column; gap: .35rem; flex: 1; }
.card .vendor { font-family: var(--display); font-weight: 600; font-size: .66rem; letter-spacing: .09em;
  text-transform: uppercase; color: var(--blue); }
.card .sku { font-family: var(--mono); font-size: .72rem; color: var(--muted); letter-spacing: .03em; }
.card .name { font-size: .92rem; line-height: 1.35; }
.card .price { margin-top: auto; font-family: var(--display); font-weight: 700; font-size: 1.05rem; font-variant-numeric: tabular-nums; }
.card .price small { font-family: var(--body); font-weight: 400; font-size: .72rem; color: var(--muted); display: block; }
.card .clink { display: flex; flex-direction: column; flex: 1; text-decoration: none; color: inherit; }
.cfoot { display: flex; gap: .45rem; align-items: stretch; padding: 0 .95rem .85rem; }
.cfoot .cadd { padding: 0; flex: 1; }
.cadd { margin: 0; padding: 0 .95rem .85rem; }
/* The heart. Outline until saved, filled after; a form, so it works without a script. */
.fav { margin: 0; display: inline-flex; }
.fav button { font: inherit; display: inline-flex; align-items: center; justify-content: center; padding: .35rem .5rem;
  border-radius: var(--radius-sm); border: 1px solid var(--line-strong); background: var(--surface); color: var(--muted); cursor: pointer; }
.fav button:hover { color: var(--stop); border-color: var(--stop); }
.fav.on button { color: var(--stop); border-color: var(--stop); }
.fav svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linejoin: round; }
.fav.on svg { fill: currentColor; }
.cadd button { width: 100%; font: inherit; font-family: var(--display); font-weight: 600; font-size: .74rem; letter-spacing: .06em;
  text-transform: uppercase; padding: .5rem .7rem; border-radius: var(--radius-sm); cursor: pointer;
  border: 1px solid var(--green); background: var(--green); color: #fff; }
.cadd button:hover { filter: brightness(1.08); }

/* ==========================================================================
   SECTION: Product page
   Breadcrumbs, the two-column layout, brand and title, the price box,
   price breaks (the ladder), eco fee and tariff rows, the sign-in nudge.
   ========================================================================== */
.crumbs { font-size: .82rem; color: var(--muted); margin-bottom: 1.2rem; }
.crumbs a { color: var(--muted); text-decoration: none; }
.pdpcrumbs { display: flex; flex-wrap: wrap; gap: .4rem 1rem; justify-content: space-between; align-items: baseline; }
/* Small buttons, the btn-ghost look at a crumb's size (Jacob, 18 Oct 2026). */
.pnav { display: flex; flex-wrap: wrap; gap: .4rem; align-items: center; }
.pnav a, .pnav .off { font-family: var(--display); font-weight: 600; font-size: .66rem; letter-spacing: .05em; text-transform: uppercase;
  padding: .35rem .7rem; border-radius: var(--radius-sm); border: 1px solid var(--line-strong); background: var(--surface);
  color: var(--blue); text-decoration: none; box-shadow: 0 1px 2px rgba(0,60,90,.10); white-space: nowrap; }
.pnav a:hover { border-color: var(--blue); box-shadow: 0 2px 5px rgba(0,60,90,.14); }
.pnav .off { color: var(--line-strong); box-shadow: none; cursor: default; }
.pnav .pos { font-family: var(--mono); font-size: .74rem; color: var(--muted); padding: 0 .2rem; }
/* The photo column is capped so the tabs below come into view on a laptop screen (Jacob, 23 Oct 2026). */
.pdp { display: grid; grid-template-columns: minmax(0, 31rem) minmax(0, 1fr); gap: 2.4rem; align-items: start; }
.detail { display: flex; flex-direction: column; gap: .9rem; }
/* The brand is often the first thing a trade buyer scans for, so it reads as
   a heading in its own right rather than as a label. */
.detail .vendor { font-family: var(--display); font-weight: 700; font-size: 1.02rem; letter-spacing: .06em;
  text-transform: uppercase; color: var(--blue); display: block; margin-bottom: .25rem; }
.detail h1 { font-family: var(--display); font-weight: 700; font-size: 1.5rem; line-height: 1.25; margin: 0; text-wrap: balance; }
.meta { font-family: var(--mono); font-size: .92rem; color: var(--muted); display: flex; gap: 1.2rem; flex-wrap: wrap; }
/* Per-unit charges on top of the price: eco fee, tariff. Their own rows, so
   they read in the same glance as the price rather than as small print. */
.charges { margin-top: .75rem; padding-top: .65rem; border-top: 1px dashed var(--line-strong); display: flex; flex-direction: column; gap: .25rem; }
.chargerow { display: flex; justify-content: space-between; align-items: baseline; gap: 1rem; font-size: .92rem; }
.chargerow .amt { font-family: var(--mono); font-variant-numeric: tabular-nums; color: var(--ink); font-weight: 600; }
.charges .hint { font-size: .78rem; margin-top: .1rem; }
.pricebox { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: .95rem 1.2rem;
  display: flex; flex-direction: column; gap: .45rem; box-shadow: var(--shadow); }
/* Signed in: "Prices exclude tax" sits on the badge's line, not a line of its
   own (Jacob, 18 Oct 2026: price, buy and stock above the fold). */
.pricebox:has(> .badge) { display: grid; grid-template-columns: auto 1fr; column-gap: 1rem; }
.pricebox:has(> .badge) > * { grid-column: 1 / -1; }
.pricebox:has(> .badge) > .badge { grid-column: 1; grid-row: 1; }
.pricebox:has(> .badge) > .unit { grid-column: 2; grid-row: 1; justify-self: end; align-self: center; text-align: right; }
.pricerow { display: flex; align-items: baseline; gap: .8rem; flex-wrap: wrap; }
.price-lg { font-family: var(--display); font-weight: 700; font-size: 2.1rem; font-variant-numeric: tabular-nums; }
/* The dash is a placeholder while the account price is still being fetched. It
   is streamed past rather than replaced, so it has to hide itself the moment a
   real figure lands beside it - the same swap the stock panel makes. */
.pricerow:has(.price-lg:not(.pending)) .pending { display: none; }
/* The ladder takes its own line inside the flex price row. */
.ladder { flex-basis: 100%; margin-top: .7rem; }
.lhead { font-family: var(--mono); font-size: .66rem; letter-spacing: .08em;
  text-transform: uppercase; color: var(--muted); display: block; margin-bottom: .35rem; }
.tiers { display: flex; gap: .4rem; flex-wrap: wrap; }
.tier { display: flex; gap: .5rem; align-items: baseline; padding: .35rem .6rem;
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm); background: var(--surface-2); }
/* The tier the quantity in the box is actually getting. */
.tier.on { border-color: var(--green); background: var(--ok-bg); }
.tq { font-family: var(--mono); font-size: .78rem; color: var(--muted); }
.tp { font-weight: 600; font-variant-numeric: tabular-nums; }
.tier.on .tp { color: var(--ok-ink); }
.ts { font-family: var(--mono); font-size: .72rem; color: var(--green); }
.list { color: var(--muted); text-decoration: line-through; font-family: var(--mono); font-size: .95rem; }
.save { color: var(--green); font-weight: 600; font-size: .9rem; }
.badge { align-self: flex-start; font-family: var(--display); font-weight: 600; font-size: .66rem; letter-spacing: .08em;
  text-transform: uppercase; padding: .25rem .55rem; border-radius: var(--radius-sm); background: var(--brand-fill); color: #fff; }
.unit { color: var(--muted); font-size: .88rem; }
.signin-nudge { border-left: 3px solid var(--cyan); background: var(--blue-tint); padding: .8rem 1rem; border-radius: 0 var(--radius) var(--radius) 0; font-size: .92rem; }
/* ==========================================================================
   SECTION: Quantity stepper
   The minus / number / plus control, and the small button size .btn-sm.
   ========================================================================== */
/*
 * The browser's own arrows are removed rather than accommodated.
 *
 * Chrome draws the spinner inside the CONTENT box, so padding-right meant to
 * clear it moves the arrows inward instead - a gap opens at the border and the
 * digits stay jammed against the arrows. That is what the last attempt did, and
 * it looked worse than leaving it alone. They are also tiny, and different in
 * every browser.
 */
input[type="number"].qtybox::-webkit-inner-spin-button,
input[type="number"].qtybox::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
input[type="number"].qtybox { -moz-appearance: textfield; appearance: textfield; }

.stepper { display: inline-flex; align-items: stretch; background: var(--surface);
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm); overflow: hidden; }
.stepper:focus-within { border-color: var(--cyan); box-shadow: 0 0 0 2px var(--blue-tint); }
.stepper input.qtybox { width: 3.2rem; min-width: 0; text-align: center; border: none;
  background: none; color: var(--ink); font-family: var(--mono); font-size: 1rem;
  padding: .55rem .2rem; }
.stepper input.qtybox:focus { outline: none; }
/* Wide enough for a gloved thumb at a job site, which is the point of replacing
   a 12px browser arrow. */
.stepbtn { width: 2.3rem; border: none; cursor: pointer; background: var(--surface-2);
  color: var(--ink); font-family: var(--display); font-weight: 700; font-size: 1.05rem;
  line-height: 1; padding: 0; display: flex; align-items: center; justify-content: center;
  user-select: none; }
.stepbtn:first-child { border-right: 1px solid var(--line); }
.stepbtn:last-child { border-left: 1px solid var(--line); }
.stepbtn:hover { background: var(--blue-tint); color: var(--blue); }
.stepbtn:active { background: var(--line); }
.btn-sm { padding: .35rem .7rem; font-size: .78rem; }
/* A hairline, not the full row rule the lines use - enough to close the column
   off from the last item without reading as another line of the order. */
table.lines tfoot tr.updaterow td { border-top: 1px solid var(--line-strong); padding-top: .7rem; }

.buyrow { display: flex; gap: .7rem; align-items: stretch; flex-wrap: wrap; }

/* ==========================================================================
   SECTION: Search extras
   "Showing results for" after a spelling fix, recent searches, the
   suggestion list headings, and the Add to order button row.
   ========================================================================== */
/* "Showing results for elbow" - a correction has to announce itself, or the
   customer cannot tell a fixed typo from a different product. */
.corrected { background: var(--blue-tint); border: 1px solid var(--tint-line);
  border-radius: var(--radius-sm); padding: .7rem .9rem; margin: 0 0 1.2rem;
  font-size: .95rem; }
.corrected strong { font-weight: 700; }
.recents { display: flex; flex-wrap: wrap; gap: .5rem; }
.recent { display: inline-flex; gap: .55rem; align-items: baseline; text-decoration: none;
  background: var(--surface); border: 1px solid var(--line-strong); border-radius: 999px;
  padding: .4rem .85rem; color: var(--ink); font-size: .92rem; }
.recent:hover { border-color: var(--blue); background: var(--blue-tint); }
.recent .rn { font-family: var(--mono); font-size: .74rem; color: var(--muted); }
.sghead { font-family: var(--mono); font-size: .64rem; letter-spacing: .09em;
  text-transform: uppercase; color: var(--muted); padding: .5rem .8rem .3rem; }
.sgrecent .sgname { font-weight: 500; }
/* Add to order, Reprice and Add to quote are one decision, so they sit on one
   line. The quote picker drops out underneath when opened. */
.buyline { display: flex; gap: .7rem; align-items: flex-start; flex-wrap: wrap; }
.buyline .buyrow { margin: 0; }
.buyline .addquote { margin-top: 0; }
/* Every control on the line the same height, the heart square, so the row
   reads as one strip (Jacob, 18 Oct 2026). */
.buyline .btn, .buyline .stepper { height: 2.9rem; padding-top: 0; padding-bottom: 0; }
.buyline .fav button { width: 2.9rem; height: 2.9rem; padding: 0; }
.buyline .fav svg { width: 18px; height: 18px; }

/* ==========================================================================
   SECTION: Variants
   Size and option pickers on matrix items (a list, or one drop-down per option).
   ========================================================================== */
.variants { display: flex; flex-wrap: wrap; align-items: center; gap: .45rem 1rem; margin: 0; }
.variants .vhead, .variants .vlist { flex-basis: 100%; }
.variants .vchooser { flex: 1 1 22rem; }
.vhead { font-family: var(--display); font-size: .95rem; letter-spacing: .03em;
  color: var(--ink); font-weight: 700; display: block; margin-bottom: .1rem; }
/* "30 options in this range" was small enough to miss. */
.variants .hint { font-size: .88rem; margin: 0; }
.vlist { display: grid; gap: .35rem; }
.vopt { display: grid; grid-template-columns: 1fr auto auto; gap: .8rem; align-items: baseline;
  padding: .55rem .75rem; border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  background: var(--surface); text-decoration: none; color: var(--ink); }
.vopt:hover { border-color: var(--blue); background: var(--blue-tint); }
/* The one you are on: marked, and not a link to where you already are. */
.vopt.on { border-color: var(--blue); background: var(--blue-tint); font-weight: 600; }
.vlabel { font-size: .95rem; }
.vsku { font-family: var(--mono); font-size: .74rem; color: var(--muted); }
.vprice { font-family: var(--mono); font-size: .85rem; white-space: nowrap; }
/* One dropdown per dimension, side by side while they fit. */
.vchooser { display: flex; gap: .5rem 1rem; align-items: center; flex-wrap: wrap; }
/* The option's name beside its dropdown, not above it. */
.vfield { display: flex; flex-direction: row; align-items: center; gap: .6rem; min-width: 12rem; flex: 1 1 12rem; }
.vfield .vname { white-space: nowrap; }
.vfield select { flex: 1; min-width: 0; }
.vname { font-family: var(--mono); font-size: .78rem; letter-spacing: .07em;
  text-transform: uppercase; color: var(--ink); font-weight: 500; }
.vchooser select { padding: .55rem .7rem; border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm); background: var(--surface); color: var(--ink);
  font-family: var(--body); font-size: .95rem; width: 100%; }
.vchooser select:focus { outline: 2px solid var(--cyan); outline-offset: -1px; }
/* The submit is the no-script path; with script the change event beats it to it. */
.vchooser button { flex: none; }
@media (max-width: 34rem) {
  .vopt { grid-template-columns: 1fr auto; }
  .vsku { grid-column: 1 / -1; }
}

/* ==========================================================================
   SECTION: Add to quote
   The quote picker that opens under Add to order.
   ========================================================================== */
/* Add to Quote. Closed, the summary IS the button sitting beside Add to order;
   open, it drops a picker underneath. list-style:none on both selectors because
   Safari uses the -webkit- pseudo-element and ignores display. */
.addquote { position: relative; display: inline-block; margin-top: .7rem; }
.addquote > summary { list-style: none; cursor: pointer; user-select: none; }
.addquote > summary::-webkit-details-marker { display: none; }
.addquote > summary::after { content: " ▾"; opacity: .6; }
.addquote[open] > summary::after { content: " ▴"; }
.addquote-body { margin-top: .6rem; background: var(--surface); border: 1px solid var(--line-strong);
  border-radius: var(--radius); padding: 1rem; display: grid; gap: .8rem; min-width: 17rem; }
.addquote-actions { display: flex; gap: .6rem; align-items: center; flex-wrap: wrap; }
.gridactions { display: flex; gap: .7rem; align-items: center; }
.gridactions .addquote { margin-top: 0; }
.gridactions .addquote-body { position: absolute; right: 0; bottom: 100%; margin-bottom: .6rem; z-index: 20;
  box-shadow: 0 12px 28px rgba(19,36,46,.18); }
/* In a grid row the panel would push every row below it down, so there it
   floats over the rows instead. */
table .addquote-body { position: absolute; right: 0; z-index: 20; box-shadow: 0 12px 28px rgba(19,36,46,.18); }

/* ==========================================================================
   SECTION: Stock panel
   Stock by branch on the product page, and the in stock / low / out pills.
   ========================================================================== */
.stock { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.stock h3 { font-family: var(--display); font-weight: 700; font-size: .78rem; letter-spacing: .07em; text-transform: uppercase;
  margin: 0; padding: .65rem 1.1rem; border-bottom: 1px solid var(--line); color: var(--muted); display: flex; justify-content: space-between; gap: 1rem; }
.stock h3 .live { color: var(--green); }
.branch { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: .45rem 1.1rem;
  border-bottom: 1px solid var(--line); font-size: .92rem; }
.branch:last-child { border-bottom: none; }
.pill { font-family: var(--mono); font-size: .76rem; padding: .16rem .55rem; border-radius: 999px; font-variant-numeric: tabular-nums; white-space: nowrap; }
.pill.ok { background: var(--ok-bg); color: var(--ok-ink); }
.pill.low { background: var(--low-bg); color: var(--low-ink); }
.pill.out { background: var(--out-bg); color: var(--out-ink); }

/* ==========================================================================
   SECTION: Descriptions and panels
   The product description, info panels, and the account tables
   (orders, invoices, statement, payments).
   ========================================================================== */
.desc { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 1.2rem 1.3rem; }
.desc h2 { font-family: var(--display); font-size: 1rem; margin: 0 0 .6rem; }
.desc :is(h2,h3) { font-family: var(--display); }
.desc table { width: 100%; border-collapse: collapse; font-size: .9rem; }
.desc td, .desc th { border-bottom: 1px solid var(--line); padding: .35rem .5rem; text-align: left; }

.panels { display: grid; grid-template-columns: repeat(auto-fit, minmax(16rem,1fr)); gap: 1rem; }
.panel { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 1.1rem 1.2rem;
  display: flex; flex-direction: column; gap: .7rem; }
.panel h3 { font-family: var(--display); font-weight: 700; font-size: .78rem; letter-spacing: .07em; text-transform: uppercase; color: var(--muted); margin: 0; }
.panel .big { font-family: var(--display); font-weight: 700; font-size: 1.7rem; font-variant-numeric: tabular-nums; }
.panel .sub { color: var(--muted); font-size: .88rem; }
/* The account tables (orders, invoices, AR, payments): the body font, text
   to the left and amounts to the right. Tabular figures keep digits in
   columns without a monospaced font. */
table.invoices { width: 100%; border-collapse: collapse; font-family: var(--body); font-size: .9rem; font-variant-numeric: tabular-nums; background: var(--surface); border: 1px solid var(--line); }
table.invoices th, table.invoices td { padding: .55rem .8rem; border-bottom: 1px solid var(--line); text-align: left; white-space: nowrap; }
table.invoices th.num, table.invoices td.num { text-align: right; }
table.invoices thead th { font-size: .68rem; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); font-weight: 500; }
table.invoices tr.overdue td { color: var(--red); }

/* ==========================================================================
   SECTION: Forms and sign-in
   The sign-in form and similar small forms, the red error box, the search box, the pager.
   ========================================================================== */
form.login { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 1.6rem; max-width: 24rem;
  display: flex; flex-direction: column; gap: .9rem; box-shadow: var(--shadow); }
form.login label { font-family: var(--mono); font-size: .68rem; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); display: block; margin-bottom: .3rem; }
form.login input, form.login select { width: 100%; padding: .6rem .7rem; border: 1px solid var(--line-strong); border-radius: var(--radius-sm); font-family: var(--body); font-size: .95rem; }
/* A select drawn like the text boxes beside it: same height, colours and border. */
form.login select { background: var(--surface); color: var(--ink); height: 2.7rem; padding-top: 0; padding-bottom: 0; }
form.login input:not([type=checkbox]):not([type=radio]) { height: 2.7rem; }
.error { background: #FDEBEA; border-left: 3px solid var(--red); color: var(--red); padding: .7rem .9rem; font-size: .9rem; border-radius: 0 var(--radius) var(--radius) 0; }

.search { display: flex; gap: .5rem; }
.search input { flex: 1; padding: .6rem .75rem; border: 1px solid var(--line-strong); border-radius: var(--radius-sm); font-family: var(--body); font-size: .95rem; }

.pager { display: flex; gap: .6rem; justify-content: center; margin-top: 1.6rem; }

/* ==========================================================================
   SECTION: Product images
   The big photo and the thumbnails on the product page, and the small
   photo on a cart line.
   ========================================================================== */
.pdpshots { display: flex; flex-direction: column; gap: .6rem; }
.pdpshots .shot { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); aspect-ratio: 1/1; overflow: hidden; }
.pdpshots .shot img { width: 100%; height: 100%; object-fit: contain; display: block; }
.thumbs { display: flex; gap: .5rem; flex-wrap: wrap; }
.thumb { width: 4.2rem; height: 4.2rem; padding: 0; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); cursor: pointer; overflow: hidden; }
.thumb:hover { border-color: var(--blue); }
.thumb img { width: 100%; height: 100%; object-fit: contain; display: block; }
table.lines .lineshot { width: 2.6rem; height: 2.6rem; object-fit: contain; background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--radius-sm); vertical-align: middle; margin-right: .6rem; }

/* ==========================================================================
   SECTION: Order line tables
   The cart, checkout and order tables (table.lines), and the rounded
   corners shared with the account tables (table.invoices).
   ========================================================================== */
table.lines { width: 100%; border-collapse: collapse; background: var(--surface); border: 1px solid var(--line); font-size: .92rem; }
table.lines th, table.lines td { padding: .7rem .8rem; border-bottom: 1px solid var(--line); text-align: right; vertical-align: middle; }
table.lines th:first-child, table.lines td:first-child { text-align: left; }
table.lines thead th { font-family: var(--mono); font-size: .66rem; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); font-weight: 500; white-space: nowrap; }
table.lines td.num { font-family: var(--mono); font-variant-numeric: tabular-nums; white-space: nowrap; }
table.lines .sku { font-family: var(--mono); font-size: .74rem; color: var(--muted); display: block; }
/* Rounded like the cards. Corner cells carry the radius, not overflow:hidden,
   so sticky headers keep sticking. */
table.invoices, table.lines { border-collapse: separate; border-spacing: 0; border-radius: var(--radius); }
table.invoices > :first-child > tr:first-child > :first-child, table.lines > :first-child > tr:first-child > :first-child { border-top-left-radius: var(--radius); }
table.invoices > :first-child > tr:first-child > :last-child, table.lines > :first-child > tr:first-child > :last-child { border-top-right-radius: var(--radius); }
table.invoices > :last-child > tr:last-child > :first-child, table.lines > :last-child > tr:last-child > :first-child { border-bottom-left-radius: var(--radius); }
table.invoices > :last-child > tr:last-child > :last-child, table.lines > :last-child > tr:last-child > :last-child { border-bottom-right-radius: var(--radius); }
table.invoices > :last-child > tr:last-child > td, table.lines > :last-child > tr:last-child > td { border-bottom: none; }
/* Its own line. Inline, it ran straight into the figure: "$2.88Your account
   price", which reads as a mangled number before it reads as an explanation. */
table.lines .why { display: block; font-size: .72rem; color: var(--muted); line-height: 1.35; margin-top: .1rem; }
/* A theme token, not a literal: #FDF4F3 is invisible against a dark ground. */
table.lines tr.no-price td { background: var(--low-bg); }
table.lines tbody tr:last-child td { border-bottom: none; }
table.lines tfoot td { border-bottom: none; }
.linkbtn { background: none; border: none; color: var(--muted); text-decoration: underline; cursor: pointer; font-family: var(--body); font-size: .82rem; padding: 0; }
.linkbtn:hover { color: var(--red); }

/* ==========================================================================
   SECTION: Totals
   Subtotal, fees, freight, tax and the grand total under an order.
   ========================================================================== */
.totals { display: flex; flex-direction: column; align-items: flex-end; gap: .3rem; margin-top: 1.1rem; }
.totals .row { display: flex; gap: 2.5rem; align-items: baseline; font-variant-numeric: tabular-nums; }
.totals .row .k { color: var(--muted); font-size: .9rem; }
.totals .row .v { font-family: var(--mono); min-width: 7rem; text-align: right; }
.totals .row.grand .k { color: var(--ink); font-weight: 600; font-size: 1rem; }
.totals .row.grand .v { font-family: var(--display); font-weight: 700; font-size: 1.25rem; color: var(--ink); }
.totals .row.note .k { font-size: .82rem; }
.totals .row.grand .k { color: var(--ink); font-family: var(--display); font-weight: 700; }
.totals .row.grand .v { font-family: var(--display); font-weight: 700; font-size: 1.3rem; }

/* ==========================================================================
   SECTION: Actions and help
   Rows of buttons, the empty-list box, and the numbered how-to box.
   ========================================================================== */
.actionrow { display: flex; gap: .7rem; flex-wrap: wrap; align-items: center; margin-top: 1.2rem; }
.actionrow .spacer { flex: 1; }
/* The quote's print choices on one line, sharing the width (Jacob, 20 Oct 2026). */
.printrow { flex-wrap: nowrap; }
.printrow .btn { flex: 1 1 0; justify-content: center; white-space: nowrap; padding-left: .5rem; padding-right: .5rem; letter-spacing: .03em; }
@media (max-width: 560px) { .printrow { flex-wrap: wrap; } .printrow .btn { flex-basis: 100%; } }
/* Buttons that share the whole row equally (the quote's send and convert). */
.fillrow .btn { flex: 1 1 0; justify-content: center; }
.empty { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 2.2rem; text-align: center; color: var(--muted); }

/* Instructions, not a card of data - so a tinted ground rather than the white
   surface the order tables use, and the counters are the structure. */
.howto { background: var(--blue-tint); border: 1px solid var(--tint-line); border-radius: var(--radius);
  padding: 1.4rem 1.6rem; margin-bottom: 1.4rem; }
.howto h3 { font-family: var(--display); font-weight: 700; font-size: .78rem; letter-spacing: .07em;
  text-transform: uppercase; color: var(--blue); margin: 0 0 .8rem; }
.howto ol { margin: 0; padding: 0; list-style: none; counter-reset: howto;
  display: grid; gap: .7rem; }
.howto li { counter-increment: howto; position: relative; padding-left: 2.1rem; color: var(--ink);
  font-size: .95rem; line-height: 1.5; }
.howto li::before { content: counter(howto); position: absolute; left: 0; top: .05rem;
  width: 1.45rem; height: 1.45rem; border-radius: 50%; background: var(--blue); color: #fff;
  font-family: var(--display); font-weight: 700; font-size: .78rem;
  display: flex; align-items: center; justify-content: center; }
.howto p.note { margin: .9rem 0 0; font-size: .87rem; }
@media (max-width: 640px) { .howto { padding: 1.1rem 1.1rem; } }

/* ==========================================================================
   SECTION: Checkout and settings
   The two-column checkout, the Settings page layout, form cards and
   fields, the branch picker, Pick up / Ship to me, the ship-to row.
   ========================================================================== */
.checkout { display: grid; grid-template-columns: minmax(0,1fr) minmax(0,1.1fr); gap: 1.6rem; align-items: start; }
/* Settings (tidied 18 Oct 2026): two stacks of cards, Your branch, How we
   contact you and Appearance on the left, Password and Your searches on the
   right, each stack as tall as its own cards. A narrower page, so fields are
   a readable width. One column on a phone, left stack first. */
.settingswrap { max-width: 68rem; }
.settings { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.2rem; align-items: start; }
.settings .scol { display: flex; flex-direction: column; gap: 1.2rem; min-width: 0; }
.settings .recents { margin-top: 0; }
.settings .formcard { gap: .85rem; }
.settings .lead { margin: 0; font-size: .95rem; line-height: 1.5; }
.settings .radios { display: flex; gap: .4rem 1.4rem; flex-wrap: wrap; }
.settings .check { display: inline-flex; align-items: center; gap: .45rem; cursor: pointer; font-size: .95rem; }
.settings .check input { width: auto; margin: 0; accent-color: var(--blue); }
@media (max-width: 48rem) {
  .settings { grid-template-columns: 1fr; }
}
.formcard { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 1.2rem 1.3rem; display: flex; flex-direction: column; gap: 1rem; }
.formcard h3 { font-family: var(--display); font-weight: 700; font-size: .78rem; letter-spacing: .07em; text-transform: uppercase; color: var(--muted); margin: 0; }
.field > label { font-family: var(--mono); font-size: .66rem; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); display: block; margin-bottom: .3rem; }
.field input, .field textarea, .field select { width: 100%; padding: .55rem .7rem; border: 1px solid var(--line-strong); border-radius: var(--radius-sm); font-family: var(--body); font-size: .95rem; }
.hint { color: var(--muted); font-size: .8rem; margin-top: .3rem; display: block; }
.branches { display: grid; grid-template-columns: repeat(auto-fit, minmax(6.6rem, 1fr)); gap: .5rem; }
.branchpick { border: 1px solid var(--line-strong); border-radius: var(--radius-sm); padding: .6rem .55rem; display: flex; gap: .45rem; align-items: center; cursor: pointer; background: var(--surface); min-width: 0; }
.branchpick:has(input:checked) { border-color: var(--blue); background: var(--blue-tint); }
.branchpick .n { font-weight: 600; font-size: .88rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.branchpick .p { color: var(--muted); font-size: .76rem; }
/* Every branch on one line where the card is narrow (a quote's What next panel). */
.branches.oneline { grid-template-columns: repeat(auto-fit, minmax(5.2rem, 1fr)); gap: .4rem; }
.branches.oneline .branchpick { padding: .55rem .45rem; gap: .35rem; }
.branches.oneline .branchpick .n { font-size: .84rem; }
.branches.oneline .branchpick input { margin: 0; flex: none; }
/* The fulfilment choice is two wide options rather than six narrow ones, so it
   gets room for the sentence that explains each. */
/* Pick up / Ship to me as two boxes. The chosen one is live; the other dims
   on a desktop and folds to its title on a phone. No script: :has() reads the
   radio. */
.fulfil-grid { display: flex; flex-direction: column; gap: 1.2rem; }
.fulfil-box { gap: .8rem; transition: border-color .15s, opacity .15s; }
.fulfil-box:has(> .fulfil-head input:checked) { border-color: var(--green); box-shadow: 0 0 0 1px var(--green) inset; }
.fulfil-head { display: flex; gap: .6rem; align-items: flex-start; cursor: pointer; }
.fulfil-head input { margin-top: .3rem; }
.fulfil-head.plain { cursor: default; }
.fulfil-head .n { display: block; font-family: var(--display); font-weight: 700; font-size: 1rem; }
.fulfil-head .p { display: block; color: var(--muted); font-size: .8rem; margin-top: .15rem; line-height: 1.35; }
.fulfil-body { display: flex; flex-direction: column; }
.fulfil-box:not(:has(> .fulfil-head input:checked)) .fulfil-body { opacity: .45; pointer-events: none; }
/* City, postal, province on one row; Get rates on its own. The column is
   half the page wide, so four across would squeeze the inputs. */
.shipto { display: grid; grid-template-columns: 1fr 6.5rem 5.5rem; gap: .6rem; align-items: end; }
.shipto > button { grid-column: 1 / -1; justify-content: center; }
@media (max-width: 52rem) {
  .fulfil-box:not(:has(> .fulfil-head input:checked)) .fulfil-body { display: none; }
  .fulfil-box:not(:has(> .fulfil-head input:checked)) { opacity: .8; }
}
.branchpick.fulfil { align-items: flex-start; padding: .75rem .85rem; }
/* ==========================================================================
   SECTION: Team page and chips
   The account's Users page (one row per person), and the people chips on
   the account page.
   ========================================================================== */
/* The team page: one row per person, a form each. */
.teamlist { display: flex; flex-direction: column; gap: .6rem; }
.teamrow { display: grid; grid-template-columns: minmax(12rem,1.4fr) 10rem auto auto 9rem auto; gap: 1rem; align-items: end;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: .9rem 1.1rem; }
.teamrow.saved { border-color: var(--green); }
.teamrow .who { display: flex; flex-direction: column; gap: .15rem; align-self: center; }
.teamrow .lbl { display: block; font-family: var(--mono); font-size: .72rem; letter-spacing: .07em; text-transform: uppercase; color: var(--muted); margin-bottom: .3rem; }
.teamrow select, .teamrow input[name=orderLimit] { width: 100%; padding: .5rem .6rem; border: 1px solid var(--line-strong); border-radius: var(--radius-sm); background: var(--surface); color: var(--ink); font: inherit; }
.teamrow .check { display: flex; gap: .5rem; align-items: center; align-self: center; padding-top: 1.2rem; white-space: nowrap; }
.teamrow .fixed { display: block; padding: .5rem 0; font-weight: 600; }
@media (max-width: 52rem) { .teamrow { grid-template-columns: 1fr 1fr; } .teamrow .who { grid-column: 1 / -1; } }
/* People chips on the account page: a lens on the order list, one per person. */
.chips { display: flex; flex-wrap: wrap; gap: .5rem; }
.chip { display: inline-flex; align-items: center; gap: .45rem; padding: .35rem .8rem; border-radius: 999px;
  border: 1px solid var(--line-strong); background: var(--surface); color: var(--ink); text-decoration: none;
  font-size: .86rem; font-weight: 500; }
.chip:hover { border-color: var(--blue); }
.chip.on { border-color: var(--blue); background: var(--blue-tint); }
.chip .ct { font-family: var(--mono); font-size: .74rem; color: var(--muted); }
/* ==========================================================================
   SECTION: Checkout extras
   The truck option, stock notes on checkout lines, the "Your branch" marker,
   and the send-a-list preview.
   ========================================================================== */
/* The branch's own truck, first among the shipping options. */
.branchpick.truck { border-style: dashed; }
.branchpick.truck:has(input:checked) { border-style: solid; }
.branchpick.fulfil .n { display: block; font-size: .98rem; }
.branchpick.fulfil .p { display: block; margin-top: .15rem; line-height: 1.35; }
table.lines td.base, table.lines th.base { color: var(--muted); }
.stocknote { display: block; font-size: .78rem; color: var(--ok-ink); margin-top: .15rem; }
.stocknote.none { color: var(--low-ink); }
/* "Your branch": the person's own branch from Settings, on the product page's
   stock panel and among the checkout's pick-up branches. */
.yourbranch { display: inline-block; margin-left: .5rem; font-family: var(--mono); font-size: .64rem;
  letter-spacing: .06em; text-transform: uppercase; color: var(--blue); vertical-align: .1em; }
.branch.home { box-shadow: inset 3px 0 0 var(--blue); }
.branch.home > span:first-child { font-weight: 600; }
.listbody { white-space: pre-wrap; font-family: var(--mono); font-size: .8rem; margin: .5rem 0 0; color: var(--ink); }

/* ==========================================================================
   SECTION: Confirmation
   The "Order placed" / "Saved as a quote" boxes and their fact grid.
   ========================================================================== */
.confirm { background: var(--surface); border: 1px solid var(--line); border-left: 3px solid var(--green); border-radius: 0 var(--radius) var(--radius) 0; padding: 1.3rem 1.4rem; margin-bottom: 1.4rem; }
.confirm h2 { font-family: var(--display); margin: 0 0 .3rem; font-size: 1.25rem; }
.confirm .so { font-family: var(--mono); font-size: 1.5rem; font-weight: 500; color: var(--blue); }
/* What happens next, in large type: tracker 78 (meeting 29 Sep 2026), so a pick-up
   customer cannot miss where to collect and that the branch calls first. */
.confirm .nextstep { font-size: 1.4rem; line-height: 1.45; font-weight: 600; color: var(--ink); margin: .9rem 0 1.2rem; padding: 1rem 1.2rem; background: var(--blue-tint); border-radius: var(--radius); }
@media (max-width: 640px) { .confirm .nextstep { font-size: 1.2rem; } }
.confirm.warn { border-left-color: var(--amber); }
.factgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(10rem,1fr)); gap: .9rem; margin-top: 1rem; }
.fact .k { font-family: var(--mono); font-size: .62rem; letter-spacing: .09em; text-transform: uppercase; color: var(--muted); display: block; }
.fact .v { font-weight: 600; font-size: .95rem; }

/* ==========================================================================
   SECTION: Footer
   The dark footer, its four link columns and the contact line.
   ========================================================================== */
footer.foot { background: var(--blue-deep); color: rgba(255,255,255,.82); padding: 1.6rem 0; font-size: .85rem; margin-top: 2rem; }
footer.foot a { color: #fff; text-underline-offset: .2em; }
/* Four link columns (shop, account, company, policies), then a base line with
   the company's contact details. Two columns on a tablet, then one. */
footer.foot .footcols { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1.4rem 2rem; padding-bottom: 1.4rem; }
footer.foot .footcols nav { display: flex; flex-direction: column; gap: .45rem; }
footer.foot .footcols h2 { font-family: var(--display); font-weight: 700; font-size: .72rem; letter-spacing: .09em; text-transform: uppercase;
  color: rgba(255,255,255,.62); margin: 0 0 .2rem; }
footer.foot .footcols a { text-decoration: none; }
footer.foot .footcols a:hover { text-decoration: underline; }
footer.foot .footbase { display: flex; justify-content: space-between; gap: .6rem 1rem; flex-wrap: wrap;
  border-top: 1px solid rgba(255,255,255,.18); padding-top: 1rem; font-size: .8rem; color: rgba(255,255,255,.7); }
@media (max-width: 54rem) { footer.foot .footcols { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 30rem) { footer.foot .footcols { grid-template-columns: 1fr; } }

/* ==========================================================================
   SECTION: Small screens
   Last-word adjustments for tablets and phones. Most sections also carry
   their own small-screen rules next to them.
   ========================================================================== */
@media (max-width: 54rem) {
  .pdp { grid-template-columns: 1fr; gap: 1.6rem; }
  .checkout { grid-template-columns: 1fr; }
  nav.primary { font-size: .7rem; gap: 1rem; }
  .logo { height: 3rem; }
}

/* The panel hangs off the masthead, not off nav.primary. The nav is a centred
   flex row only as wide as its items, so anchoring to it gave a ~700px panel
   whose columns had nowhere to go. */
.masthead { position: relative; }
/* Padding extends the hover target down to meet the panel; without it the
   ~10px gap below the link is a dead zone that closes the menu as the pointer
   crosses it. The negative margin keeps the nav's own layout unchanged. */
/* The panel is measured from the nav row, not the page, so it comes out only a
   little wider than the links themselves. That is why nav.primary is the
   positioning context and .navgroup stays static: .navgroup is one link wide,
   and anchoring to it would give a panel the width of a single word. */
nav.primary { position: relative; }
.navgroup { position: static; padding-bottom: 1rem; margin-bottom: -1rem; }
/* The wrapper spans the full width so the panel can be full-bleed, but only
   the visible card should hold the menu open. Without this, moving sideways
   off the panel stays inside the full-width wrapper and the menu will not
   close until the pointer drops below it. */
.mega { pointer-events: none; }
.navpanel, .megainner { pointer-events: auto; }
/* The -2rem bleed is the "little wider than the menu" - the panel overhangs
   the first and last link rather than starting flush with them. */
.mega { position: absolute; left: -2rem; right: -2rem; top: 100%; z-index: 40;
  opacity: 0; visibility: hidden; transform: translateY(-6px);
  transition: opacity .16s ease, transform .16s ease, visibility .16s; }
.navgroup:hover .mega, .navgroup:focus-within .mega { opacity: 1; visibility: visible; transform: translateY(0); }
/* Its own container, not the shared .wrap: .wrap inside .masthead is flex,
   column and centred, which would shrink the panel to its content width and
   stack every column. It no longer needs a max-width of its own - .mega is now
   sized by the nav row - but it must keep its own name for that reason. */
.megawrap { margin: 0 auto; padding: 0; }
@media (max-width: 60rem) { .mega { display: none; } }

/* ---------- design 1: panel ---------- */
.mega:has(.megainner) { background: var(--surface); border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line); box-shadow: 0 18px 40px -24px rgba(0,60,90,.55);
  border-radius: 0 0 var(--radius) var(--radius); }
.megainner { display: flex; flex-wrap: wrap; gap: 1.2rem 3rem; padding: 1.8rem 0 1.4rem; align-items: flex-start; }
.megacol { display: flex; flex-direction: column; gap: .4rem; min-width: 9rem; }
.megahead { font-family: var(--mono); font-size: .62rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--muted); margin-bottom: .35rem; }
.megacol a { color: var(--ink); text-decoration: none; font-size: .93rem; font-family: var(--body);
  font-weight: 400; letter-spacing: 0; text-transform: none; padding: .12rem 0; border: none; }
.megacol a:hover { color: var(--blue); }
.megafeature { background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 1.2rem 1.25rem; display: flex; flex-direction: column; gap: .6rem; align-items: flex-start;
  margin-left: auto; width: 20rem; flex: none; }
.megafeature strong { font-family: var(--display); font-size: .98rem; text-transform: none; letter-spacing: 0; }
.megafeature p { margin: 0; color: var(--muted); font-size: .85rem; font-family: var(--body);
  text-transform: none; letter-spacing: 0; font-weight: 400; line-height: 1.45; }
.megaall { width: 100%; border-top: 1px solid var(--line); padding-top: .9rem; margin-top: .2rem; }
.megaall a { color: var(--blue); text-decoration: none; font-size: .8rem; }

/* ---------- design 2: cards ---------- */
/* A floating tinted panel inset from the page edge rather than a full-bleed
   white band, so the menu reads as an object sitting above the page. */
.navpanel { background: var(--ground); border: 1px solid var(--line); border-radius: var(--radius-lg);
  box-shadow: 0 26px 60px -30px rgba(0,60,90,.6); margin-top: .55rem; overflow: hidden; }
.navcols { display: flex; align-items: stretch; }
.navcol { flex: 1; min-width: 0; padding: 1.5rem 1.6rem 1.7rem; }
/* Rules between columns rather than around them: one border on each column
   after the first, so a single-column group has no stray divider. */
.navcol + .navcol { border-left: 1px solid var(--line); }
.navcol.promoted { background: var(--blue-tint); }
.navcolhead { display: block; font-family: var(--display); font-weight: 700; font-size: .7rem;
  letter-spacing: .12em; text-transform: uppercase; color: var(--blue);
  padding-bottom: .7rem; border-bottom: 1px solid var(--line-strong); margin-bottom: .9rem; }
.navcards { display: flex; flex-direction: column; gap: .15rem; }
.navcard { display: flex; gap: .8rem; align-items: flex-start; padding: .65rem .7rem;
  border-radius: var(--radius); text-decoration: none; color: inherit;
  font-family: var(--body); font-weight: 400; letter-spacing: 0; text-transform: none; border: none; }
.navcard:hover { background: var(--surface); box-shadow: 0 1px 2px rgba(0,60,90,.08); }
.navcol.promoted .navcard { background: var(--surface); border: 1px solid #D3E6F0; margin-bottom: .35rem; }
.navcol.promoted .navcard:hover { border-color: var(--cyan); }
.navicon { flex: none; width: 2.1rem; height: 2.1rem; border-radius: var(--radius-sm);
  background: var(--surface); border: 1px solid var(--line); color: var(--blue);
  display: flex; align-items: center; justify-content: center; }
.navcol.promoted .navicon { background: var(--blue-tint); border-color: var(--tint-line); }
.navicon svg { width: 1.15rem; height: 1.15rem; display: block; }
.navtext { display: flex; flex-direction: column; gap: .1rem; min-width: 0; }
.navtitle { font-family: var(--display); font-weight: 700; font-size: .88rem; color: var(--ink);
  display: flex; align-items: center; gap: .45rem; flex-wrap: wrap; letter-spacing: 0; text-transform: none; }
.navcard:hover .navtitle { color: var(--blue); }
.navbadge { font-family: var(--display); font-style: normal; font-weight: 700; font-size: .55rem;
  letter-spacing: .1em; text-transform: uppercase; color: var(--blue); background: var(--blue-tint);
  border: 1px solid var(--tint-line); border-radius: 999px; padding: .12rem .42rem; }
.navblurb { color: var(--muted); font-size: .8rem; line-height: 1.4; }
/* No button overrides needed here any more. The nav link rules in layout.ts are
   scoped to "nav.primary .navgroup > a", so they no longer reach into the open
   panel and ".btn" applies to menu buttons exactly as it does everywhere else. */

/* The closing strip, which is where the eye lands last and the only place in
   the panel with a button. */
.navstrip { display: flex; align-items: center; gap: 2rem; flex-wrap: wrap;
  background: var(--surface); border-top: 1px solid var(--line); padding: 1.35rem 1.6rem; }
.navstriptext { flex: 1; min-width: 14rem; }
.navstriptext strong { display: block; font-family: var(--display); font-weight: 700; font-size: .95rem;
  color: var(--ink); letter-spacing: 0; text-transform: none; }
.navstriptext p { margin: .15rem 0 0; color: var(--muted); font-size: .84rem; font-family: var(--body);
  font-weight: 400; letter-spacing: 0; text-transform: none; line-height: 1.45; }
@media (max-width: 74rem) { .navcols { flex-wrap: wrap; } .navcol { flex: 1 1 16rem; }
  .navcol + .navcol { border-left: none; border-top: 1px solid var(--line); } }

/* ---------- category browsing ---------- */
.cathead { margin-bottom: 1.4rem; }
/* The category banner: a photo with the name in a translucent brand box, the
   way a collection header reads on a retail site. */
.cathero { position: relative; min-height: 14rem; background-size: cover; background-position: center; border-radius: var(--radius-lg); display: grid; place-items: center; margin-bottom: 1rem; overflow: hidden; }
.cathero::before { content: ""; position: absolute; inset: 0; background: linear-gradient(rgba(0,30,46,.12), rgba(0,30,46,.38)); }
.cathero .box { position: relative; background: rgba(0,104,152,.84); color: #fff; padding: 1rem 2.4rem; border-radius: var(--radius); text-align: center; max-width: min(90%, 40rem); }
.cathero h1 { font-family: var(--display); font-weight: 600; font-size: clamp(1.5rem, 3.4vw, 2.2rem); margin: 0; color: #fff; }
.cathero .cnt { font-size: .6em; opacity: .85; vertical-align: super; margin-left: .2rem; font-weight: 500; }
.cathero .sub { margin: .35rem 0 0; color: #EAF4FA; font-size: 1rem; }
.cathero .sub p { margin: 0; } .cathero .sub p + p { margin-top: .4rem; } .cathero .sub a { color: #fff; }
.cathero .sub ul, .cathero .sub ol { margin: .3rem 0 0; padding-left: 1.2rem; text-align: left; }
@media (max-width: 40rem) { .cathero { min-height: 10rem; } .cathero .box { padding: .7rem 1.2rem; } }
.cathead h1 { font-family: var(--display); font-weight: 700; font-size: 1.7rem; margin: 0 0 .3rem; }
.catblurb { color: var(--muted); margin: 0; max-width: 46rem; font-size: .98rem; }
.catblurb p { margin: 0; } .catblurb p + p { margin-top: .4rem; }

/* Subcategory tiles. Taller and squarer than the home page tiles, because
   these are the primary navigation of a category page rather than a flourish. */
/* Tiles stretch to share the row (.tiles, auto-fit): Jacob prefers two wide
   tiles on the Pipe page to two small ones (27 Oct 2026). */
.cattiles { margin-bottom: 2rem; }
.cattile { position: relative; min-height: 9.5rem; border-radius: var(--radius); overflow: hidden;
  background-size: cover; background-position: center; background-color: var(--blue-deep);
  display: flex; align-items: flex-end; border: 1px solid var(--line); text-decoration: none; }
.cattile::after { content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(12,26,45,0) 35%, rgba(12,26,45,.85) 100%); }
/* No thumbnail yet: a flat brand panel reads as deliberate, a broken image does not. */
.cattile.noimage { background-image: linear-gradient(150deg, #0E3C55, #12658C); }
.cattile:hover { border-color: var(--line-strong); box-shadow: var(--shadow); }
.cattext { position: relative; z-index: 1; padding: 1rem 1.1rem; display: flex; flex-direction: column; gap: .1rem; }
.catname { font-family: var(--display); font-weight: 700; font-size: .9rem; color: #fff; }
.catcount { font-family: var(--mono); font-size: .7rem; color: rgba(255,255,255,.8); }

/* Sidebar plus results. The sidebar is deliberately narrow: the ask was six
   products across, and every rem given to filters comes out of the grid. */
.browse { display: grid; grid-template-columns: 13rem minmax(0, 1fr); gap: 1.8rem; align-items: start; }
.results { min-width: 0; }

.filters { position: sticky; top: 1rem; font-size: .88rem; }
.fbar { display: flex; align-items: baseline; justify-content: space-between; gap: .5rem;
  padding-bottom: .6rem; border-bottom: 1px solid var(--line-strong); margin-bottom: 1rem; }
/* Headings sized up for reading (Jacob, 27 Sep): .78rem and .68rem were hard to read. */
.ftitle { font-family: var(--display); font-weight: 700; font-size: .95rem; letter-spacing: .08em; text-transform: uppercase; }
.fclear { font-size: .78rem; }
/* Selected: one chip per filter in force, the x takes that one off. */
.fselected { margin-bottom: 1.2rem; }
.fchips { display: flex; flex-wrap: wrap; gap: .35rem; }
.fchip { display: inline-flex; align-items: baseline; gap: .35rem; max-width: 100%; padding: .22rem .5rem .22rem .6rem;
  border: 1px solid var(--tint-line); background: var(--blue-tint); color: var(--ink); border-radius: 999px;
  text-decoration: none; font-size: .8rem; line-height: 1.3; }
.fchip .fk { color: var(--muted); font-size: .68rem; }
.fchip .fv { font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fchip .fx { color: var(--blue); font-weight: 700; font-size: .95rem; line-height: 1; }
.fchip:hover { border-color: var(--red); }
.fchip:hover .fx { color: var(--red); }
.fgroup { margin-bottom: 1.3rem; }
.fhead { display: block; font-family: var(--display); font-weight: 700; font-size: .84rem; letter-spacing: .07em;
  text-transform: uppercase; color: var(--blue); margin-bottom: .5rem; }
.fvalues { display: flex; flex-direction: column; gap: .1rem; }
/* Links, not checkboxes: filter state lives in the URL so a filtered view is
   shareable, bookmarkable and crawlable, and the page needs no JavaScript. */
.fval { display: flex; align-items: center; gap: .5rem; padding: .25rem .35rem; border-radius: var(--radius-sm);
  text-decoration: none; color: var(--ink); }
.fval:hover { background: var(--surface); }
.fbox { flex: none; width: .85rem; height: .85rem; border: 1px solid var(--line-strong); border-radius: 3px;
  background: var(--surface); position: relative; }
.fval.on .fbox { background: var(--brand-fill); border-color: var(--brand-fill); }
.fval.on .fbox::after { content: ""; position: absolute; left: .24rem; top: .06rem; width: .2rem; height: .42rem;
  border: solid #fff; border-width: 0 2px 2px 0; transform: rotate(45deg); }
.flabel { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fval.on .flabel { font-weight: 600; }
/* A category with nothing matching the current filters: still a link, but quiet. */
.fval.zero { opacity: .5; }
.fcount { font-family: var(--mono); font-size: .72rem; color: var(--muted); }
.fmore summary { cursor: pointer; color: var(--blue); font-size: .8rem; padding: .3rem .35rem; list-style: none; }
.fmore summary::-webkit-details-marker { display: none; }

.sortbar { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap;
  padding-bottom: .8rem; border-bottom: 1px solid var(--line); margin-bottom: 1.1rem; }
.sortbar .count { font-family: var(--mono); font-size: .82rem; color: var(--muted); }
.sortpick { display: flex; align-items: center; gap: .5rem; font-size: .85rem; color: var(--muted); }
.sortpick select { font-family: var(--body); font-size: .88rem; padding: .4rem .6rem; border-radius: var(--radius-sm);
  border: 1px solid var(--line-strong); background: var(--surface); color: var(--ink); }

/* Six across on a wide screen, degrading by whole columns rather than reflowing
   to an awkward count. */
.pgrid { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: .85rem; }
@media (max-width: 82rem) { .pgrid { grid-template-columns: repeat(5, minmax(0, 1fr)); } }
@media (max-width: 70rem) { .pgrid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .browse { grid-template-columns: 11.5rem minmax(0, 1fr); gap: 1.2rem; } }
@media (max-width: 60rem) { .pgrid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .browse { grid-template-columns: 1fr; } .filters { position: static; } }
@media (max-width: 40rem) { .pgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.pcard { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  padding: .6rem .65rem .75rem; display: flex; flex-direction: column; gap: .18rem;
  text-decoration: none; color: inherit; }
.pcard:hover { border-color: var(--line-strong); box-shadow: var(--shadow); }
.pcard .plink { display: flex; flex-direction: column; gap: .18rem; text-decoration: none; color: inherit; flex: 1; }
.pfoot { display: flex; align-items: center; justify-content: space-between; gap: .4rem; margin-top: auto; padding-top: .3rem; }
.pfoot .pprice { margin-top: 0; padding-top: 0; }
.padd { margin: 0; }
.padd button { font: inherit; font-family: var(--display); font-weight: 600; font-size: .7rem; letter-spacing: .06em;
  text-transform: uppercase; padding: .3rem .6rem; border-radius: var(--radius-sm); cursor: pointer;
  border: 1px solid var(--green); background: var(--green); color: #fff; }
.padd button:hover { filter: brightness(1.08); }
.added { margin: 0 0 .9rem; padding: .55rem .8rem; border-radius: var(--radius-sm); background: var(--ok-bg);
  border: 1px solid var(--green); font-size: .9rem; }
.added code { font-family: var(--mono); font-size: .85em; }
.pshot { aspect-ratio: 1/1; background: var(--surface-2); border-radius: var(--radius-sm); overflow: hidden; margin-bottom: .4rem; }
.pshot img { width: 100%; height: 100%; object-fit: contain; display: block; }
.pvendor { font-family: var(--display); font-weight: 600; font-size: .58rem; letter-spacing: .09em;
  text-transform: uppercase; color: var(--blue); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pname { font-size: .95rem; font-weight: 500; line-height: 1.3; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.psku { font-family: var(--mono); font-size: .66rem; color: var(--muted); }
.pprice { margin-top: auto; padding-top: .3rem; font-family: var(--display); font-weight: 700; font-size: .95rem;
  font-variant-numeric: tabular-nums; }
.pagenote { font-family: var(--mono); font-size: .8rem; color: var(--muted); align-self: center; }

/* ---------- mobile ---------- */
/*
  Two problems on a phone, both from desktop patterns that do not survive the
  narrower screen:

  The mega menu cannot hover, and dumping every subcategory into a stacked list
  gave a wall of links several screens tall. Instead the nav becomes a drawer
  that shows ONE level at a time: the seven roots, and tapping one slides to its
  children with a back link. Only one list is ever on screen.

  The filter sidebar sat above the products, so on a phone you scrolled past
  every facet before reaching the first item. It becomes a button that opens a
  full-height sheet, which is the pattern people already know from retail apps.

  Both use the checkbox-and-label trick rather than JavaScript, so they work on
  the cached anonymous pages with no script.
*/
.navtoggle, .filtertoggle, .drawerclose, .sheetdone { display: none; }

@media (max-width: 60rem) {
  /* --- nav drawer --- */
  nav.primary { display: none; }
  .navtoggle { display: inline-flex; align-items: center; gap: .5rem; cursor: pointer;
    font-family: var(--display); font-weight: 700; font-size: .78rem; letter-spacing: .06em;
    text-transform: uppercase; color: var(--ink); background: var(--surface);
    border: 1px solid var(--line-strong); border-radius: var(--radius-sm); padding: .6rem 1rem; }
  #navdrawer:checked ~ .masthead nav.primary { display: block; position: fixed; inset: 0; z-index: 60;
    background: var(--surface); overflow-y: auto; padding: 1rem 0 3rem; }
  #navdrawer:checked ~ .masthead nav.primary .navgroup { display: block; padding: 0; margin: 0; }
  #navdrawer:checked ~ .masthead nav.primary .navgroup > a { display: block; padding: .95rem 1.25rem;
    border-bottom: 1px solid var(--line); font-size: .85rem; }
  #navdrawer:checked ~ .masthead .drawerclose { display: flex; justify-content: flex-end;
    padding: .6rem 1.25rem; }

  /* One level at a time: the panel is hidden until its own group is opened. */
  .mega { position: static; opacity: 1; visibility: visible; transform: none; pointer-events: auto;
    display: none; }
  .navgroup:focus-within .mega { display: block; }
  .megawrap { padding: 0; }
  .navpanel { border: none; border-radius: 0; box-shadow: none; margin: 0; background: var(--surface-2); }
  .navcols { display: block; }
  .navcol { padding: .8rem 1.25rem; }
  .navcol + .navcol { border-left: none; border-top: 1px solid var(--line); }
  .navstrip { padding: 1rem 1.25rem; }

  /* --- filter sheet --- */
  .filtertoggle { display: inline-flex; align-items: center; gap: .5rem; cursor: pointer;
    font-family: var(--display); font-weight: 600; font-size: .76rem; letter-spacing: .05em;
    text-transform: uppercase; color: var(--blue); background: var(--surface);
    border: 1px solid var(--line-strong); border-radius: var(--radius-sm); padding: .65rem 1.1rem;
    box-shadow: 0 1px 2px rgba(0,60,90,.10); }
  .filters { display: none; }
  #filtersheet:checked ~ .browse .filters { display: block; position: fixed; inset: 0; z-index: 60;
    background: var(--surface); overflow-y: auto; padding: 1.1rem 1.25rem 5rem; }
  #filtersheet:checked ~ .browse .filters .fbar { position: sticky; top: 0; background: var(--surface);
    padding-top: .4rem; z-index: 1; }
  /* The Apply control is fixed to the bottom of the sheet, where a thumb is. */
  #filtersheet:checked ~ .browse .filters::after { content: ""; display: block; height: 1rem; }
  .sheetdone { display: none; }
  #filtersheet:checked ~ .browse .sheetdone { display: flex; position: fixed; left: 0; right: 0; bottom: 0;
    z-index: 61; padding: .8rem 1.25rem; background: var(--surface); border-top: 1px solid var(--line);
    justify-content: center; }
  .browse { grid-template-columns: 1fr; }
}

/* ---------- universal search ---------- */
/* Sits under the logo and above the nav, so it is the first thing reachable on
   every page. Trade buyers arrive knowing a SKU far more often than they arrive
   wanting to browse, so search outranks the category menu in the hierarchy. */
.sitesearch { display: flex; width: 100%; max-width: 34rem; gap: .5rem; }
.sitesearch input { flex: 1; min-width: 0; padding: .7rem .9rem; font-family: var(--body); font-size: .95rem;
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm); background: var(--surface); color: var(--ink); }
.sitesearch input:focus { outline: 2px solid var(--cyan); outline-offset: -1px; border-color: var(--cyan); }
/* Direct child only. The suggestion dropdown renders its rows as buttons inside
   this same form, and a bare "button" selector painted every one of them as a
   blue Search button - the same shape of mistake as "nav.primary a" reaching
   into the mega menu. */
.sitesearch > button { display: inline-flex; align-items: center; gap: .45rem; padding: .7rem 1.1rem; cursor: pointer;
  background: var(--brand-fill); color: #fff; border: 1px solid transparent; border-radius: var(--radius-sm);
  font-family: var(--display); font-weight: 600; font-size: .74rem; letter-spacing: .05em; text-transform: uppercase; }
.sitesearch > button svg { width: 1rem; height: 1rem; }

/* ---------- sign in / account request ---------- */
.authwrap { max-width: 26rem; }
.authhead { font-family: var(--display); font-weight: 700; font-size: 1.4rem; margin: 0 0 1.1rem; text-align: center; }
.authwrap form.login { max-width: none; margin: 0; }
/* The account request form: wider, and two fields across on anything wider
   than a phone. The button and the back link run the full width. */
.authwrap.wide { max-width: 44rem; }
form.login.twocol { display: grid; grid-template-columns: 1fr; gap: .9rem; }
@media (min-width: 48rem) {
  form.login.twocol { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .9rem 1.1rem; }
  form.login.twocol > .span { grid-column: 1 / -1; }
}
.authlink { font-size: .85rem; text-align: center; }
.authfoot { border-top: 1px solid var(--line); padding-top: 1rem; margin-top: .3rem;
  display: flex; flex-direction: column; gap: .6rem; align-items: center; text-align: center;
  color: var(--muted); font-size: .85rem; }
/* The line under the sign-in form. Trade-only is the message; the request
   button is the way in for someone who has not got an account yet. */
.authfoot .trade { font-family: var(--display); font-weight: 500; font-size: 1.05rem; letter-spacing: .02em; color: var(--ink); }
.btn-request { border-radius: 999px; padding: .5rem 1.1rem; font-size: .74rem;
  background: var(--surface); color: var(--blue); border: 2px solid var(--blue); }
.btn-request:hover { background: var(--blue); color: #fff; }
/* "Check your email", after a sign-in link is asked for. */
.sentcard { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow);
  padding: 1.8rem 1.6rem 1.3rem; display: flex; flex-direction: column; align-items: center; gap: 1rem; text-align: center; }
.sentico { width: 3.6rem; height: 3.6rem; border-radius: 50%; display: grid; place-items: center;
  background: var(--blue-tint); color: var(--blue); border: 1px solid var(--tint-line); }
.sentico svg { width: 1.7rem; height: 1.7rem; }
.sentto { margin: 0; color: var(--muted); font-size: .95rem; }
.sentto strong { display: block; margin-top: .2rem; color: var(--ink); font-size: 1.08rem; overflow-wrap: anywhere; }
.sentnote { margin: 0; font-size: .92rem; max-width: 21rem; }
.senthelp { width: 100%; text-align: left; background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: .8rem 1rem; font-size: .88rem; }
.senthelp .btn-request { display: table; margin: .85rem auto .15rem; }
.senthelp ul { margin: .4rem 0 0; padding-left: 1.1rem; display: flex; flex-direction: column; gap: .3rem; color: var(--muted); }
.sentfoot { display: flex; gap: .6rem; flex-wrap: wrap; justify-content: center; font-size: .85rem; color: var(--muted); }

/* ---------- static pages ---------- */
/* Content pages (about, contact, catalogue, privacy, terms, returns): one
   centred column the width of comfortable reading, the heading centred over
   it, the text in a single card. */
.docpage { max-width: 52rem; }
.docpage .crumbs { text-align: center; }
.docpage .cathead { text-align: center; margin-bottom: 1.6rem; }
.docpage .catblurb { margin: 0 auto; }
.docpage .prose { max-width: none; padding: 2rem 2.4rem; }
.docpage .prose h2 { font-size: 1.1rem; margin-top: 1.8rem; padding-top: 1.2rem; border-top: 1px solid var(--line); }
.docpage .prose h2:first-child { margin-top: 0; padding-top: 0; border-top: none; }
.docpage .prose p, .docpage .prose li { font-size: .98rem; }
.docpage .todo { margin-left: auto; margin-right: auto; }
@media (max-width: 40rem) { .docpage .prose { padding: 1.3rem 1.2rem; } }
.prose { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 1.6rem 1.8rem; max-width: 46rem; }
.prose h2 { font-family: var(--display); font-size: 1.05rem; margin: 1.4rem 0 .5rem; }
.prose h2:first-child { margin-top: 0; }
.prose p { margin: 0 0 .9rem; line-height: 1.6; }
.prose ul { margin: 0 0 .9rem; padding-left: 1.2rem; }
.prose li { margin-bottom: .3rem; }
.todo { border-left: 3px solid var(--amber); background: var(--low-bg); color: var(--low-ink);
  padding: .7rem .9rem; border-radius: 0 var(--radius) var(--radius) 0; font-size: .88rem; margin-bottom: 1.2rem; }

/* Six in one row on desktop, which is the whole branch network at a glance.
   It only fits because the opening hours moved out of the card to a single
   line above the grid - the same string six times was what forced 17rem
   columns. Fixed six-up rather than auto-fit: auto-fit would drop to five and
   leave one branch orphaned on a second row. */
.branchgrid { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: .9rem; }
@media (max-width: 90rem) { .branchgrid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 52rem) { .branchgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 34rem) { .branchgrid { grid-template-columns: 1fr; } }

.idesc { display: block; font-size: .88rem; }
table.lines tfoot tr.grand td { font-weight: 700; border-top: 2px solid var(--line-strong); }

/* ---------- search suggestions ---------- */
/* Anchored to the input's own wrapper, which the script makes positioned if it
   is not already, so the same markup works in the masthead and in the grid. */
.sgbox { position: absolute; top: calc(100% + .3rem); left: 0; right: 0; z-index: 70;
  background: var(--surface); border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm); box-shadow: var(--shadow);
  max-height: 21rem; overflow-y: auto; padding: .25rem; }
.sgrow { display: block; width: 100%; text-align: left; cursor: pointer;
  background: none; border: 0; border-radius: var(--radius-sm);
  padding: .5rem .6rem; font: inherit; color: var(--ink); }
.sgrow:hover, .sgrow.on { background: var(--blue-tint); }
.sgitem { display: flex; align-items: stretch; }
.sgitem .sgrow { flex: 1; min-width: 0; }
.sgadd { font: inherit; font-family: var(--display); font-weight: 600; font-size: .68rem; letter-spacing: .06em; text-transform: uppercase;
  margin: .3rem .5rem .3rem 0; padding: 0 .7rem; border-radius: var(--radius-sm); cursor: pointer; white-space: nowrap;
  border: 1px solid var(--green); background: var(--green); color: #fff; }
.sgadd:hover { filter: brightness(1.08); }
.sgadd.done { background: var(--surface); color: var(--green); }
.sgadd:disabled { opacity: .7; cursor: default; }
.pacts { display: flex; gap: .3rem; align-items: center; }
.sgname { display: block; font-size: .92rem; font-weight: 600; line-height: 1.3; }
.sgmeta { display: block; font-family: var(--mono); font-size: .72rem; color: var(--muted); }
.sgvar { display: inline-block; margin-top: .15rem; font-family: var(--display);
  font-weight: 700; font-size: .58rem; letter-spacing: .09em; text-transform: uppercase;
  color: var(--blue); background: var(--blue-tint); border: 1px solid var(--tint-line);
  border-radius: 999px; padding: .1rem .4rem; }

/* The last row, separated so it reads as an action rather than a sixth result. */
.sgall { border-top: 1px solid var(--line); margin-top: .25rem; padding-top: .6rem;
  font-family: var(--display); font-weight: 600; font-size: .8rem;
  letter-spacing: .03em; color: var(--blue); border-radius: 0 0 var(--radius-sm) var(--radius-sm); }
.sgall:hover, .sgall.on { background: var(--blue-tint); }

/* The masthead search is a flex row; the dropdown must span the field only,
   not the field plus the Search button. */
.sitesearch { position: relative; }
.sitesearch .sgbox { right: auto; width: 100%; max-width: 34rem; }

/* ---------- order grid ---------- */
.gridsearch { display: flex; gap: .6rem; flex-wrap: wrap; align-items: center; margin-bottom: 1.3rem; }
.gridsearch input[type="search"] { flex: 1; min-width: 15rem; padding: .7rem .9rem;
  font-family: var(--body); font-size: .95rem; border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm); background: var(--surface); color: var(--ink); }
.gridsearch input[type="search"]:focus { outline: 2px solid var(--cyan); outline-offset: -1px; }
.branchsel { display: flex; align-items: center; gap: .5rem; font-size: .85rem; color: var(--muted); }
.branchsel select { padding: .65rem .7rem; font-family: var(--body); font-size: .9rem;
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--ink); }

/* The table scrolls inside its own box; the page never scrolls sideways. */
.gridwrap { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface); }
.ogrid { width: 100%; border-collapse: collapse; font-size: .9rem; min-width: 46rem; }
.ogrid th, .ogrid td { padding: .35rem .55rem; border-bottom: 1px solid var(--line); vertical-align: middle; }
.ogrid thead th { font-family: var(--display); font-weight: 600; font-size: .68rem;
  letter-spacing: .07em; text-transform: uppercase; color: var(--muted); text-align: left;
  background: var(--surface-2); position: sticky; top: 0; z-index: 1; }
.ogrid .num, .ogrid th.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.ogrid tbody tr:last-child td { border-bottom: none; }
.ogrid tbody tr.has-qty { background: var(--blue-tint); }
/* Section heads when earlier picks are kept above the new results. */
.ogrid tr.gsection th { text-align: left; padding: .35rem .55rem; font-family: var(--display); font-weight: 700;
  font-size: .72rem; letter-spacing: .06em; text-transform: uppercase; color: var(--blue);
  background: var(--surface-2); border-bottom: 1px solid var(--line); }
.ogrid tr.gsection th span { margin-left: .6rem; font-family: var(--body); font-weight: 400; font-size: .78rem;
  letter-spacing: 0; text-transform: none; color: var(--muted); }
.ogrid tbody.gkept { border-bottom: 2px solid var(--tint-line); }

.ogrid td.gimg, .ogrid th.gimg { width: 2.8rem; }
.ogrid td.gimg img { width: 36px; height: 36px; object-fit: contain; display: block;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-sm); }
.gname { min-width: 13rem; line-height: 1.3; }
.gname a { color: var(--ink); text-decoration: none; font-weight: 600; }
.gname a:hover { color: var(--blue); }
.gvendor { display: block; font-family: var(--display); font-weight: 700; font-size: .6rem;
  letter-spacing: .09em; text-transform: uppercase; color: var(--blue); }
.gsku { display: block; font-family: var(--mono); font-size: .72rem; color: var(--muted); }
.gvariant select { max-width: 13rem; padding: .4rem .5rem; font-family: var(--body);
  font-size: .84rem; border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--ink); }
.novariant { color: var(--line-strong); }
.gprice .price { font-weight: 600; }
.gprice .price.pending { opacity: .45; }
.pricenote { display: block; font-family: var(--mono); font-size: .65rem; color: var(--muted); }
.gstock .pill.pending { background: var(--out-bg); color: var(--muted); letter-spacing: .1em; }
.gqty input { width: 5.6rem; padding: .5rem .6rem; font-family: var(--body); font-size: .95rem;
  text-align: right; border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--ink); }
.gqty input:focus { outline: 2px solid var(--cyan); outline-offset: -1px; }
.gline { font-weight: 600; min-width: 5rem; }

/* Only ever shown when the next tier costs less, so it can afford to look like
   an offer rather than a warning. Clicking it fills the quantity. */
.breakhint { display: block; margin-top: .3rem; padding: .25rem .45rem; cursor: pointer;
  font-family: var(--display); font-weight: 600; font-size: .62rem; letter-spacing: .02em;
  color: var(--ok-ink); background: var(--ok-bg); border: 1px solid var(--ok-ink);
  border-radius: var(--radius-sm); white-space: nowrap; }
.breakhint:hover { filter: brightness(1.04); }

/* The grid on the left; Your order on the right, kept in view while the grid
   scrolls. Narrower screens stack it under the grid as a summary. */
.gridlayout { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); gap: .9rem; align-items: start; }
.gridmain { min-width: 0; }
.gridpanel { position: sticky; top: .75rem; display: grid; gap: .6rem; padding: .8rem .9rem;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow); }
.gridpanel h3 { margin: 0; font-family: var(--display); font-weight: 700; font-size: .78rem; letter-spacing: .07em;
  text-transform: uppercase; color: var(--muted); }
.gpempty { margin: 0; font-size: .86rem; }
.gplist { list-style: none; margin: 0; padding: 0; max-height: min(52vh, 30rem); overflow-y: auto; }
.gplist:empty { display: none; }
/* Name on its own line (wrapping), then quantity, line total and remove beneath it. */
.gplist li { display: grid; grid-template-columns: 4rem minmax(0, 1fr) 1.4rem; gap: .2rem .5rem; align-items: center;
  padding: .4rem 0; border-bottom: 1px solid var(--line); }
.gplist li:last-child { border-bottom: none; }
.gpname { grid-column: 1 / -1; min-width: 0; }
.gpname a { display: block; color: var(--ink); text-decoration: none; font-weight: 600; font-size: .84rem; line-height: 1.25; }
.gpname .gsku { font-size: .68rem; }
.gpname a:hover { color: var(--blue); }
.gpqty { width: 100%; padding: .2rem .4rem; text-align: right; font-family: var(--body); font-size: .88rem;
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm); background: var(--surface); color: var(--ink); }
.gpqty:focus { outline: 2px solid var(--cyan); outline-offset: -1px; }
.gpline { text-align: right; font-weight: 600; font-size: .86rem; font-variant-numeric: tabular-nums; }
.gprm { border: none; background: none; color: var(--muted); font-size: 1.15rem; line-height: 1; cursor: pointer; padding: .2rem; }
.gprm:hover { color: var(--red); }
.gridpanel .gridtotals { padding-top: .6rem; border-top: 1px solid var(--line); }
.gridpanel .gridactions { flex-direction: column; align-items: stretch; }
.gridpanel .gridactions .btn, .gridpanel .addquote, .gridpanel .addquote > summary { width: 100%; justify-content: center; }
.gridpanel .addquote-body { left: 0; right: 0; }
/* With the panel running, earlier picks live there rather than at the top of the grid. */
.has-panel tbody.gkept { display: none; }
@media (max-width: 1100px) {
  .gridlayout { grid-template-columns: 1fr; }
  .gridpanel { position: static; }
}
.gridtotals { display: flex; gap: 1.4rem; flex-wrap: wrap; align-items: baseline;
  font-size: .9rem; color: var(--muted); }
.gridtotals strong { color: var(--ink); font-variant-numeric: tabular-nums; }
.grandtotal { font-size: 1rem; }
.grandtotal strong { font-family: var(--display); font-size: 1.15rem; }
.gridfoot { margin-top: 1.2rem; font-size: .86rem; }
/* Downloads tab rows. */
.dlrow { display: flex; gap: .75rem; align-items: center; padding: .55rem 1.1rem; border-bottom: 1px solid var(--line);
  text-decoration: none; color: var(--ink); }
.dlrow:last-child { border-bottom: none; }
.dlrow:hover { background: var(--blue-tint); }
/* Related and Recently viewed: six cards across, scrolling sideways. */
.carousel { margin-top: 2.2rem; }
.carousel[hidden] { display: none; }
.chead { display: flex; justify-content: space-between; align-items: center; gap: 1rem; margin-bottom: .7rem; }
.chead h2 { font-family: var(--display); font-size: 1.25rem; margin: 0; }
.carrows { display: flex; gap: .4rem; }
.carrow { width: 2.2rem; height: 2.2rem; border: 1px solid var(--line-strong); border-radius: 50%; background: var(--surface); color: var(--ink);
  font-size: 1.3rem; line-height: 1; cursor: pointer; }
.carrow:hover { border-color: var(--blue); color: var(--blue); }
.ctrack { display: grid; grid-auto-flow: column; grid-auto-columns: calc((100% - 5 * .9rem) / 6); gap: .9rem; overflow-x: auto;
  scroll-snap-type: x mandatory; scrollbar-width: thin; padding-bottom: .4rem; }
.cslide { scroll-snap-align: start; min-width: 0; display: flex; }
.cslide > .card { flex: 1; }
@media (max-width: 64rem) { .ctrack { grid-auto-columns: calc((100% - 2 * .9rem) / 3); } }
@media (max-width: 40rem) { .ctrack { grid-auto-columns: calc((100% - .9rem) / 2); } }
/* Branch stock in two columns on the product page: half the height, so the tabs sit higher. */
@media (min-width: 40rem) {
  .pdp .stock { display: grid; grid-template-columns: 1fr 1fr; gap: 1px; background: var(--line); }
  .pdp .stock h3 { grid-column: 1 / -1; background: var(--surface); border-bottom: none; }
  .pdp .stock .branch { background: var(--surface); border-bottom: none; }
}
/* Click-to-enlarge product photo. */
.pdpshots .shot[role="button"] { cursor: zoom-in; }
.pdpshots .shot[role="button"]:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }
.pzoom { width: 100vw; height: 100vh; max-width: none; max-height: none; margin: 0; padding: 0; border: none; background: rgba(8, 18, 26, .92); }
.pzoom::backdrop { background: rgba(8, 18, 26, .6); }
.pzoom[open] { display: flex; align-items: center; justify-content: center; }
.pzoom img { max-width: 92vw; max-height: 88vh; object-fit: contain; background: #fff; border-radius: var(--radius-sm); }
.pz-close, .pz-nav { position: absolute; border: none; background: rgba(255, 255, 255, .14); color: #fff; cursor: pointer; border-radius: 50%; }
.pz-close { top: 1rem; right: 1rem; width: 2.6rem; height: 2.6rem; font-size: 1.7rem; line-height: 1; }
.pz-nav { top: 50%; transform: translateY(-50%); width: 3rem; height: 3rem; font-size: 2rem; line-height: 1; display: none; }
.pz-prev { left: 1.2rem; } .pz-next { right: 1.2rem; }
.pzoom.many .pz-nav { display: block; }
.pz-close:hover, .pz-nav:hover { background: rgba(255, 255, 255, .28); }
.pz-count { position: absolute; bottom: 1.1rem; left: 50%; transform: translateX(-50%); color: #fff; font-family: var(--mono); font-size: .85rem; display: none; }
.pzoom.many .pz-count { display: block; }
/* Description and Specifications tabs under the product. */
.ptabs { margin-top: 1rem; display: flex; flex-wrap: wrap; }
.ptab-in { position: absolute; opacity: 0; pointer-events: none; }
.ptab { position: relative; z-index: 1; padding: .7rem 1.2rem; margin-bottom: -1px; cursor: pointer; font-family: var(--display); font-weight: 700; font-size: .82rem;
  letter-spacing: .06em; text-transform: uppercase; color: var(--muted); border: 1px solid transparent; border-bottom: none;
  border-radius: var(--radius-sm) var(--radius-sm) 0 0; }
.ptab:hover { color: var(--blue); }
.ptab-in:checked + .ptab { color: var(--ink); background: var(--surface); border-color: var(--line); border-bottom: 1px solid var(--surface); }
.ptab-in:disabled + .ptab { opacity: .45; cursor: default; }
.ptab-in:focus-visible + .ptab { outline: 2px solid var(--cyan); outline-offset: 2px; }
.ptab-panel { display: none; order: 9; flex-basis: 100%; background: var(--surface); border: 1px solid var(--line);
  border-radius: 0 var(--radius) var(--radius) var(--radius); padding: 2rem 1.4rem 1.8rem; }
#ptab-desc:checked ~ .ptab-panel[data-tab="desc"], #ptab-spec:checked ~ .ptab-panel[data-tab="spec"],
#ptab-docs:checked ~ .ptab-panel[data-tab="docs"] { display: block; }
.ptab-n { display: inline-flex; align-items: center; justify-content: center; min-width: 1.3rem; height: 1.3rem; margin-left: .4rem; padding: 0 .35rem; line-height: 1; vertical-align: .15em; border-radius: 999px; font-family: var(--mono);
  font-size: .7rem; font-weight: 700; letter-spacing: 0; text-align: center; background: var(--brand-fill); color: #fff; }
/* Downloads tab: a card per document with its first page (Jacob, 23 Oct 2026). */
.dcards { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1.2rem; }
@media (max-width: 75rem) { .dcards { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 52rem) { .dcards { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 34rem) { .dcards { grid-template-columns: 1fr; } }
.dcard { display: flex; flex-direction: column; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.dcard:hover { border-color: var(--blue); box-shadow: 0 4px 14px rgba(0, 60, 90, .10); }
.dthumb { display: flex; align-items: center; justify-content: center; aspect-ratio: 4 / 3; overflow: hidden; background: var(--surface-2);
  border-bottom: 1px solid var(--line); }
.dthumb img { width: 100%; height: 100%; object-fit: cover; object-position: top; background: #fff; display: block; }
.dlext.big { min-width: 6rem; padding: 1.4rem .9rem; font-size: 1.4rem; border-radius: var(--radius); }
.dbody { display: flex; flex-direction: column; gap: .3rem; padding: .8rem .9rem .9rem; flex: 1; }
.dkind { font-family: var(--display); font-weight: 700; font-size: .64rem; letter-spacing: .07em; text-transform: uppercase; color: var(--blue); }
.dtitle { font-weight: 600; font-size: .95rem; line-height: 1.3; color: var(--ink); text-decoration: none; }
.dtitle:hover { color: var(--blue); text-decoration: underline; }
.dmeta { font-family: var(--mono); font-size: .74rem; color: var(--muted); }
.dacts { display: flex; gap: .5rem; margin-top: auto; padding-top: .5rem; }
.dacts .dlbtn { flex: 1; text-align: center; }
.dlbtn { padding: .4rem .7rem; border: 1px solid var(--blue); border-radius: var(--radius-sm); color: var(--blue); text-decoration: none;
  font-family: var(--display); font-weight: 600; font-size: .7rem; letter-spacing: .05em; text-transform: uppercase; white-space: nowrap; }
.dlbtn:hover { background: var(--blue-tint); }
.dlbtn.solid { background: var(--brand-fill); border-color: var(--brand-fill); color: #fff; }
.dlbtn.solid:hover { filter: brightness(1.08); }
.ptab-panel p { margin: 0 0 .8rem; max-width: 72ch; }
/* Written descriptions: h2 and h3 under the page's h1, lists and tables. */
.ptab-panel.desc h2 { font-family: var(--display); font-size: 1.2rem; margin: 1.6rem 0 .6rem; }
.ptab-panel.desc h2:first-child { margin-top: 0; }
.ptab-panel.desc h3 { font-family: var(--display); font-size: 1rem; margin: 1.2rem 0 .4rem; }
.ptab-panel.desc ul { margin: 0 0 .9rem; padding-left: 1.2rem; max-width: 72ch; }
.ptab-panel.desc li { margin: .25rem 0; }
.ptab-panel.desc table { border-collapse: collapse; width: 100%; max-width: 46rem; font-size: .92rem; margin: 0 0 1rem; }
.ptab-panel.desc th, .ptab-panel.desc td { text-align: left; padding: .45rem .8rem; border-bottom: 1px solid var(--line); vertical-align: top; }
.ptab-panel.desc th { width: 38%; color: var(--muted); font-weight: 600; }
.features { margin: 0 0 1.2rem; padding-left: 1.2rem; max-width: 72ch; }
/* Description beside At a glance; features beside the spec table. One column on narrower screens. */
.pdgrid { display: grid; grid-template-columns: minmax(0, 88ch) minmax(18rem, 32rem); gap: 1.5rem 3.5rem; justify-content: space-between; align-items: start; }
.pmain p, .pmain ul { max-width: none; }
.pdgrid.pspec { grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr); justify-content: stretch; }
/* 60px side margins on desktop (Jacob, 23 Oct 2026); the content keeps its width and the gap takes the rest. */
.ptab-panel { padding-left: clamp(1.4rem, 4vw, 60px); padding-right: clamp(1.4rem, 4vw, 60px); }
.pdgrid.pspec .specs { max-width: none; }
.glance { position: sticky; top: 1rem; padding: 1rem 1.15rem; background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--radius); }
.ptab-panel .glance h3 { margin: 0 0 .7rem; font-family: var(--display); font-weight: 700; font-size: .74rem; letter-spacing: .07em; text-transform: uppercase; color: var(--muted); }
.ptab-panel .glance dl { margin: 0; display: grid; gap: .5rem; }
.glance dt { font-size: .76rem; color: var(--muted); }
.glance dd { margin: .1rem 0 0; font-weight: 600; font-size: .92rem; line-height: 1.35; }
.glance-more { display: inline-block; margin-top: .9rem; font-weight: 600; font-size: .86rem; color: var(--blue); cursor: pointer; }
.glance-more:hover { text-decoration: underline; }
.gdocs { margin-top: 1.1rem; padding-top: 1rem; border-top: 1px solid var(--line); display: grid; gap: .55rem; }
.glance h3 + .gdocs, .gdocs:first-child { margin-top: 0; padding-top: 0; border-top: none; }
.ptab-panel .gdocs h3 { margin: 0 0 .2rem; font-family: var(--display); font-weight: 700; font-size: .74rem; letter-spacing: .07em; text-transform: uppercase; color: var(--muted); }
.gdoc { display: grid; grid-template-columns: 3rem minmax(0, 1fr); gap: .7rem; align-items: center; text-decoration: none; color: var(--ink);
  padding: .35rem; margin: 0 -.35rem; border-radius: var(--radius-sm); }
.gdoc:hover { background: var(--surface); }
.gdoc img { width: 3rem; aspect-ratio: 3 / 4; object-fit: cover; object-position: top; background: #fff; border: 1px solid var(--line); border-radius: 3px; display: block; }
.gdoc .dlext { width: 3rem; text-align: center; }
.gdoc-t { display: block; font-weight: 600; font-size: .88rem; line-height: 1.3; }
.gdoc:hover .gdoc-t { color: var(--blue); }
.gdoc-m { display: block; font-size: .74rem; color: var(--muted); }
@media (max-width: 60rem) { .pdgrid, .pdgrid.pspec { grid-template-columns: 1fr; } .glance { position: static; } }
.features li { margin: .25rem 0; }
.specs { border-collapse: collapse; width: 100%; max-width: 46rem; font-size: .92rem; }
.specs th, .specs td { text-align: left; padding: .5rem .8rem; border-bottom: 1px solid var(--line); vertical-align: top; }
.specs th { width: 38%; color: var(--muted); font-weight: 600; }
.specs tr:last-child th, .specs tr:last-child td { border-bottom: none; }
.dlext { flex: none; min-width: 2.6rem; padding: .35rem .3rem; text-align: center; font-family: var(--display); font-weight: 700;
  font-size: .66rem; letter-spacing: .05em; color: #fff; background: var(--brand-fill); border-radius: var(--radius-sm); }
.dlname { font-weight: 600; font-size: .92rem; line-height: 1.3; min-width: 0; }
.dlmeta { display: block; font-weight: 400; font-size: .78rem; color: var(--muted); }
.gridhint { margin: -.8rem 0 .8rem; font-size: .84rem; }
/* The order grid: a working page, so a tighter head and a compact stepper. */
.gridpage { padding-top: .8rem; }
.gridpage .crumbs { margin-bottom: .5rem; }
.gridpage .cathead { margin-bottom: .8rem; }
.gridpage .cathead h1 { font-size: 1.45rem; margin-bottom: .1rem; }
.gridpage .catblurb { font-size: .9rem; }
.gridpage .gridsearch { margin-bottom: 1rem; }
.ogrid .stepper .btn, .ogrid .stepper button { padding-top: .3rem; padding-bottom: .3rem; }
.ogrid .stepper input.qtybox { padding-top: .3rem; padding-bottom: .3rem; }
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }


/* ---------- quoting ---------- */
.qhead { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem;
  flex-wrap: wrap; margin-bottom: 1.1rem; }
.qhead h1 { font-family: var(--display); font-weight: 700; font-size: 1.7rem; margin: 0 0 .3rem; }
.qheadside { display: flex; align-items: center; gap: .7rem; }

.qchip { display: inline-flex; align-items: center; font-family: var(--display); font-weight: 700;
  font-size: .62rem; letter-spacing: .09em; text-transform: uppercase; padding: .25rem .6rem;
  border-radius: 999px; border: 1px solid transparent; }
.q-requested { background: var(--low-bg); color: var(--low-ink); border-color: var(--low-ink); }
.q-reviewed  { background: var(--blue-tint); color: var(--blue); border-color: var(--tint-line); }
.q-agreed    { background: var(--ok-bg); color: var(--ok-ink); border-color: var(--ok-ink); }
.q-ordered   { background: var(--ok-bg); color: var(--ok-ink); border-color: var(--ok-ink); }
.q-declined, .q-expired { background: var(--out-bg); color: var(--out-ink); border-color: var(--out-ink); }
.qrev { font-family: var(--mono); font-size: .7rem; color: var(--muted); }

/* The status rail. A line the eye can follow left to right, rather than four
   badges the reader has to rank themselves. */
.qrail { display: flex; list-style: none; margin: 0 0 1.6rem; padding: 0; gap: 0; flex-wrap: wrap; }
.qrail li { flex: 1; min-width: 8rem; position: relative; padding-top: 1.5rem;
  font-family: var(--display); font-weight: 600; font-size: .78rem; color: var(--muted); }
.qrail li::before { content: ""; position: absolute; top: .45rem; left: 0; right: 0; height: 2px;
  background: var(--line); }
.qrail li:first-child::before { left: 50%; }
.qrail li:last-child::before { right: 50%; }
.qdot { position: absolute; top: 0; left: calc(50% - .45rem); width: .9rem; height: .9rem;
  border-radius: 50%; background: var(--surface); border: 2px solid var(--line-strong); }
.qrail li.done { color: var(--ink); }
.qrail li.done::before { background: var(--green); }
.qrail li.done .qdot { background: var(--green); border-color: var(--green); }
.qrail li.now { color: var(--blue); }
.qrail li.now .qdot { background: var(--blue); border-color: var(--blue);
  box-shadow: 0 0 0 4px var(--blue-tint); }
.qrail li { text-align: center; }
.qdead { background: var(--out-bg); color: var(--out-ink); border: 1px solid var(--line);
  border-radius: var(--radius); padding: .8rem 1rem; margin-bottom: 1.4rem; font-size: .92rem; }

.qgrid { display: grid; grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr); gap: 2rem; align-items: start; }
@media (max-width: 62rem) { .qgrid { grid-template-columns: 1fr; } }
.qsub { font-family: var(--display); font-weight: 700; font-size: .82rem; letter-spacing: .07em;
  text-transform: uppercase; color: var(--muted); margin: 0 0 .7rem; }
.qmain .qsub:not(:first-child), .qside .qsub:not(:first-child) { margin-top: 1.8rem; }
.qsource { font-size: .84rem; margin: -.4rem 0 1.2rem; }

.qactions { display: flex; align-items: center; gap: .7rem; flex-wrap: wrap; margin-bottom: .8rem; }
.qactions.subtle { margin-top: -.2rem; }
.qactions select, .qactions input[type="text"] { padding: .6rem .8rem; font-family: var(--body);
  font-size: .92rem; border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--ink); }
.qactions input[type="text"] { flex: 1; min-width: 12rem; }

/* Timeline */
.qtimeline { list-style: none; margin: 0 0 .5rem; padding: 0 0 0 1rem; border-left: 2px solid var(--line); }
.qtimeline li { position: relative; padding: 0 0 1rem .9rem; }
.qtimeline li::before { content: ""; position: absolute; left: -1.42rem; top: .35rem; width: .55rem;
  height: .55rem; border-radius: 50%; background: var(--line-strong); }
.qtimeline li:first-child::before { background: var(--blue); }
.qwhen { display: block; font-family: var(--mono); font-size: .7rem; color: var(--muted); }
.qwhat { display: block; font-size: .9rem; }
.qnote { display: block; color: var(--muted); font-size: .86rem; }

/* Thread */
.qthread { display: flex; flex-direction: column; gap: .7rem; margin-bottom: 1rem;
  max-height: 26rem; overflow-y: auto; }
.qmsg { background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--radius);
  padding: .7rem .85rem; }
.qmsg.mine { background: var(--blue-tint); border-color: var(--tint-line); }
/* An internal note must never look like anything the customer could have sent.
   It is only ever rendered for staff - the filter is in the SQL - but a rep
   also has to be able to tell at a glance which of their own messages the
   customer can read. */
.qmsg.internal { background: var(--low-bg); border-color: var(--low-ink); border-style: dashed; }
.qmsghead { display: flex; align-items: baseline; gap: .55rem; flex-wrap: wrap; font-size: .82rem; }
.qmsghead .qwhen { display: inline; }
.qmsg p { margin: .3rem 0 0; font-size: .92rem; }
.qinternal { font-family: var(--display); font-weight: 700; font-size: .58rem; letter-spacing: .09em;
  text-transform: uppercase; color: var(--low-ink); }
.qreply { display: flex; flex-direction: column; gap: .5rem; align-items: flex-start; }
.qreply textarea { width: 100%; padding: .7rem .85rem; font-family: var(--body); font-size: .93rem;
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--ink); resize: vertical; }
.qinternaltoggle { font-size: .85rem; color: var(--muted); display: flex; align-items: center; gap: .4rem; }
.quotelist td, .quotelist th { white-space: nowrap; }


.cataloguebtns { display: flex; align-items: center; justify-content: center; gap: .8rem; flex-wrap: wrap; }
/* A content card with everything centred (the catalogue page). Bullets sit
   inside the lines so a centred list still reads as a list. */
.prose.centred { text-align: center; }
.prose.centred ul { list-style-position: inside; padding-left: 0; }

.qoupload input[type="file"] { font-family: var(--body); font-size: .9rem; color: var(--ink);
  border: 1px dashed var(--line-strong); border-radius: var(--radius-sm); padding: .8rem;
  background: var(--surface-2); width: 100%; }
.qoupload input[type="file"]::file-selector-button { font: inherit; font-family: var(--display);
  font-weight: 600; font-size: .74rem; letter-spacing: .05em; text-transform: uppercase;
  margin-right: .8rem; padding: .5rem .9rem; cursor: pointer; color: #fff;
  background: var(--brand-fill); border: 1px solid transparent; border-radius: var(--radius-sm); }
/* Three peer ways to build an order, so three equal columns - not the
   .checkout grid, which is 1.25fr/1fr for a summary beside a sidebar and left
   the third card orphaned in the left column with dead space next to it.
   Below three columns the upload spans the full width rather than orphaning
   again. */
.qogrid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1.6rem; align-items: start; }
@media (max-width: 74rem) {
  .qogrid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .qogrid .qopaste { grid-column: 1 / -1; }
}
@media (max-width: 48rem) { .qogrid { grid-template-columns: 1fr; } }

/* The sample sits above the file input, because someone who needs it needs it
   before they go looking for a file, not after. */
.qosample { display: flex; align-items: center; gap: .75rem; flex-wrap: wrap; margin: 0 0 .2rem; }
.qosample .hint { margin: 0; }

/* The account price before NetSuite answers. Muted, and the same size as the
   real figure, so the line does not move when the number lands. */
.price-lg.pending { color: var(--line-strong); }

/* --- locator controls --- */
.locatorbar { display: flex; flex-wrap: wrap; align-items: center; gap: .7rem 1rem; margin-bottom: 1rem; }
.postalform { display: flex; gap: .5rem; }
.postalform input { padding: .7rem .9rem; font-family: var(--body); font-size: .95rem; width: 14rem;
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--ink); }
.postalform input:focus { outline: 2px solid var(--cyan); outline-offset: -1px; border-color: var(--cyan); }
.postalform input:disabled { opacity: .6; cursor: not-allowed; }
.locstatus { color: var(--muted); font-size: .9rem; }

.branchmap { height: 22rem; border: 1px solid var(--line); border-radius: var(--radius);
  overflow: hidden; background: var(--surface-2); margin-bottom: 1.1rem; }
.mapstub { height: 100%; display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: .3rem; text-align: center; padding: 1.5rem; color: var(--muted); }
.mapstub strong { font-family: var(--display); color: var(--ink); font-size: .95rem; }
.mapstub span { font-size: .88rem; max-width: 30rem; }
/* Google injects its own absolutely positioned furniture; without this the
   InfoWindow close button inherits the page button styling. */
.branchmap img { max-width: none; }

.branchcard .hours { color: var(--ink); font-size: .84rem; line-height: 1.4;
  display: flex; flex-direction: column; }
.branchcard .hours.unknown { color: var(--muted); font-style: italic; }
.branchcard .dist { font-family: var(--mono); font-size: .74rem; color: var(--blue); font-weight: 600; }
.branchcard.nearest { border-color: var(--green); box-shadow: 0 0 0 1px var(--green); }
.branchgrid.ranked .branchcard { cursor: pointer; }
.branchcard { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 1.1rem 1.2rem; display: flex; flex-direction: column; gap: .35rem; }
.branchcard h3 { font-family: var(--display); font-size: 1rem; margin: 0; }
.branchcard .addr { color: var(--muted); font-size: .9rem; line-height: 1.45; }
.branchcard .links { display: flex; gap: .8rem; flex-wrap: wrap; margin-top: .3rem; font-size: .85rem; }

/* ---------- quick order ---------- */
.qorows { display: flex; flex-direction: column; gap: .5rem; margin-bottom: 1rem; }
.qorow { display: grid; grid-template-columns: minmax(0,1fr) 6rem; gap: .5rem; }
.qorow input { padding: .6rem .7rem; border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  font-family: var(--body); font-size: .95rem; min-width: 0; }
.qorow input.sku { font-family: var(--mono); }
.qopaste textarea { width: 100%; min-height: 9rem; padding: .7rem .8rem; border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm); font-family: var(--mono); font-size: .88rem; line-height: 1.5; }

/* Streamed stock.
   The skeleton rows and both status labels ship in the first chunk; the real
   rows are appended when NetSuite answers. ":has" then hides the skeleton and
   swaps the amber "Stock pending" for the green "Live from NetSuite" - no
   script, and no layout jump, because the skeleton already names all six
   branches so the panel starts at its final height. */
.branch.pending span:first-child { color: var(--muted); }
.pill.pending { background: var(--low-bg); color: var(--low-ink); }
.stock:has(.branch:not(.pending)) .branch.pending { display: none; }

.stock h3 .waiting { color: var(--amber); }
.stock h3 .live { display: none; }
.stock:has(.branch:not(.pending)) h3 .waiting { display: none; }
.stock:has(.branch:not(.pending)) h3 .live { display: inline; }

/* ---------- listing pages on a phone (Jacob, 18 Oct 2026) ----------
   54 products in a two-across grid was 13 screens of scrolling. On a phone:
   - one product per row, the photo small on the left and the name, SKU,
     price and Add on the right: full-width names, bigger tap targets, about
     6.5 products a screen (the grid was 5.7);
   - the subcategory tiles become one strip you swipe sideways, instead of a
     stack two screens tall above the first product;
   - a Back to top button once you are well down the page (LISTING_PLACE in
     category-pages.ts). */
@media (max-width: 40rem) {
  .pgrid { grid-template-columns: 1fr; gap: .4rem; }
  .pcard { position: relative; padding: .5rem .6rem .5rem 5.9rem; min-height: 5.6rem; gap: .08rem; }
  .pcard .plink { gap: .08rem; }
  .pcard .pshot { position: absolute; left: .5rem; top: .5rem; width: 4.7rem; margin: 0; }
  .pname { -webkit-line-clamp: 2; line-height: 1.25; }
  .pfoot { padding-top: .2rem; }
  .padd button { padding: .4rem .7rem; }

  .cattiles { display: flex; gap: .6rem; overflow-x: auto; scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch;
    margin: 0 -1.25rem 1.2rem; padding: 0 1.25rem .35rem; scroll-padding: 0 1.25rem; scrollbar-width: none; }
  .cattiles::-webkit-scrollbar { display: none; }
  .cattile { flex: 0 0 9.5rem; min-height: 6.5rem; scroll-snap-align: start; }
  .cattext { padding: .6rem .7rem; }
  .catname { font-size: .82rem; }
}
.backtop { position: fixed; right: 1rem; bottom: 1rem; z-index: 40; display: flex; align-items: center; gap: .35rem;
  font-family: var(--display); font-weight: 600; font-size: .7rem; letter-spacing: .06em; text-transform: uppercase;
  padding: .6rem .85rem; border-radius: 999px; background: var(--brand-fill); color: #fff; text-decoration: none;
  box-shadow: 0 4px 14px rgba(0,40,60,.3); opacity: 0; pointer-events: none; transform: translateY(.5rem);
  transition: opacity .2s, transform .2s; }
.backtop.on { opacity: 1; pointer-events: auto; transform: none; }
@media (min-width: 60.01rem) { .backtop { display: none; } }
