/* ===========================================================================
   LATCHFORD — SITE CHROME AND PAGE COMPONENTS
   Added 14-Sep-2026. brand.css owns type, tokens-in-use, hero, cards, steps,
   FAQ rows, buttons and the interior prose rules. This file adds what the
   competitor set (SECLOCK, Trudoor, Banner, Quality Door, National Lock,
   Access Hardware, CDF) has and this site did not:
     - a three-row trade header: utility bar, masthead with a real search
       field, category navigation with dropdowns
     - a mobile drawer
     - a five-column footer with contact, product tree, guides and policies
     - category tiles, a sibling rail for category pages, segment tiles,
       service cards, accordion FAQ, search results, 404, track-order
   Colour VALUES come from style.css tokens only. Bronze is graphic only.
   =========================================================================== */

/* -------------------------------------------------------------- HEADER */
.lx-header { background: #fff; position: relative; z-index: 60; }
.lx-header a { text-decoration: none; }

/* Utility bar: one of the four permitted dark panels. */
.lx-utility { background: var(--latch-panel); color: var(--latch-panel-muted); font-size: 0.8125rem; }
.lx-utility__row { display: flex; align-items: center; justify-content: space-between; gap: 1rem; min-height: 36px; }
.lx-utility__claim { color: var(--latch-panel-muted); }
.lx-utility__links { display: flex; align-items: center; gap: 1.35rem; margin: 0; padding: 0; list-style: none; }
.lx-utility__links a { color: var(--latch-panel-text); }
.lx-utility__links a:hover { color: #fff; text-decoration: underline; text-underline-offset: .18em; text-decoration-color: var(--latch-bronze); }

/* Masthead: logo, search, primary action. White, hairline below. */
.lx-masthead { border-bottom: 1px solid var(--latch-line); }
.lx-masthead__row {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center;
  gap: clamp(1.25rem, 3vw, 3rem); padding-block: 1.05rem;
}
.lx-logo { display: inline-flex; align-items: center; }
.lx-logo img { display: block; width: 208px; height: auto; }

.lx-search {
  display: flex; width: 100%; max-width: 640px; margin-inline: auto; box-sizing: border-box;
  border: 1px solid var(--latch-control); border-radius: 2px; background: #fff;
}
.lx-search:focus-within { border-color: var(--latch-ink); box-shadow: 0 0 0 2px var(--latch-line); }
.lx-search input[type="search"] {
  flex: 1; min-width: 0; max-width: none; border: 0; border-radius: 0; background: transparent; box-sizing: border-box;
  padding: .72rem .95rem; font: inherit; font-size: .95rem; color: var(--latch-ink);
}
.lx-search input[type="search"]:focus-visible { outline: none; }
.lx-search input::placeholder { color: var(--latch-steel); }
.lx-search button {
  flex: none; width: 50px; border: 0; background: var(--latch-ink); color: #fff; box-sizing: border-box;
  display: grid; place-items: center; cursor: pointer; border-radius: 0;
}
.lx-search button:hover { background: #2a3038; }
.lx-search button svg { width: 18px; height: 18px; }

/* Masthead only: the search field and the quote button sit side by side and
   should read as the same height. Both default to their own font-driven
   padding, which don't quite agree (found 18-Sep-2026, the search field ran
   visibly shorter than the button), so pin both to one explicit height here
   and let their children fill it with height: 100%. */
.lx-masthead .lx-search, .lx-masthead__actions .lx-btn--quote { height: 3rem; box-sizing: border-box; }
.lx-masthead .lx-search input[type="search"], .lx-masthead .lx-search button { height: 100%; }
.lx-masthead__actions .lx-btn--quote { align-items: center; padding-block: 0; }

.lx-masthead__actions { display: flex; align-items: center; gap: .75rem; justify-self: end; }
.lx-masthead__actions .lx-btn { white-space: nowrap; }
/* The hero's own "Send a photo, get a quote" only duplicates the masthead's
   copy of that exact button on screens wide enough to show both at once
   (found 21-Sep-2026: both visible in the same frame at 1920x1080). Below
   1081px the masthead hides its quote button (max-width: 1080px, above),
   so there the hero's is the only one on screen without opening the menu --
   keep it there; hide it only where it is genuinely a repeat. */
@media (min-width: 1081px) { .lx-hero__quote-cta { display: none; } }
.lx-iconbtn {
  display: inline-grid; place-items: center; width: 44px; height: 44px; border: 1px solid var(--latch-line);
  border-radius: 2px; background: #fff; color: var(--latch-ink); cursor: pointer; font: inherit; position: relative;
}
.lx-iconbtn:hover { border-color: var(--latch-control); background: var(--latch-surface); }
.lx-iconbtn svg { width: 20px; height: 20px; }
.lx-iconbtn__count {
  position: absolute; top: -6px; right: -6px; min-width: 18px; height: 18px; padding: 0 5px;
  border-radius: 9px; background: var(--latch-ink); color: #fff; font-size: .6875rem; font-weight: 700;
  display: grid; place-items: center; font-variant-numeric: tabular-nums;
}
.lx-burger { display: none; }
.lx-burger span { display: block; width: 18px; height: 2px; background: currentColor; margin: 2px auto; }

/* Navigation row. Hover and focus-within open a dropdown without JS; the
   script only adds click-to-toggle for touch and closes on Escape. */
.lx-nav { border-bottom: 1px solid var(--latch-line); }
.lx-nav__list { display: flex; align-items: stretch; gap: .15rem; margin: 0; padding: 0; list-style: none; }
.lx-nav__item { position: relative; }
.lx-nav__link {
  display: inline-flex; align-items: center; gap: .4rem; padding: .95rem .95rem; margin-bottom: -1px;
  font: inherit; font-size: .9rem; font-weight: 600; color: var(--latch-ink); background: none; border: 0;
  border-bottom: 2px solid transparent; cursor: pointer; white-space: nowrap;
}
.lx-nav__link:hover, .lx-nav__link[aria-expanded="true"], .lx-nav__item.is-current > .lx-nav__link {
  border-bottom-color: var(--latch-bronze);
}
/* Was 10x10 with a chevron path tucked in a corner of its own viewBox, so the
   mark itself was only a few px -- effectively invisible (found 18-Sep-2026).
   The path is now centred and the box is bigger; stroke-width bumped to match. */
.lx-nav__link svg { width: 15px; height: 15px; stroke-width: 2.1; transition: transform .15s ease; }
.lx-nav__link[aria-expanded="true"] svg { transform: rotate(180deg); }
.lx-nav__item--cta { margin-left: auto; }
.lx-nav__item--cta .lx-nav__link { font-weight: 700; }

/* ------------------------------------------------------ NAV DROPDOWNS, REBUILT 21-Sep-2026
   One panel shape and one row style for all four menus (Products, Brands,
   Who we serve, Resources). Before this, each menu was visually its own
   thing: Products was an icon+title+2-line-description card grid, Who we
   serve and Resources were description rows at ad-hoc inline widths
   (min-width:360px, 380px, typed by hand per menu), and Brands was a
   wholly separate two-pane composite. Flagged directly: "there is separate
   type size and shape of box... I don't like that." Checked against
   Banner Solutions and Hinge Outlet's own mega menus: neither ever mixes
   card-with-description rows and plain-text rows in the same nav --
   every column is a bold caption over a flat list of single-line links,
   same row height and type size throughout, hover is a left accent bar,
   nothing else. That's the one shape everything below uses now. */
.lx-dd {
  position: absolute; top: 100%; left: 0; z-index: 70; display: none;
  background: #fff; border: 1px solid var(--latch-line); border-top: 2px solid var(--latch-ink);
  box-shadow: 0 18px 40px rgba(16,20,24,.12); padding: 1.5rem; min-width: 320px;
}
.lx-nav__item:hover > .lx-dd, .lx-nav__item:focus-within > .lx-dd, .lx-nav__item.is-open > .lx-dd { display: block; }
.lx-dd--wide { width: min(760px, calc(100vw - 2 * var(--gutter))); }
/* Replaces the old per-menu inline min-width:360px/380px -- one sized class
   instead of two hand-typed numbers that happened to end up close. */
.lx-dd--md { width: min(340px, calc(100vw - 2 * var(--gutter))); }

/* The bold caption every column gets, matching Banner's "Categories /
   Sub Categories / Featured Products" and Hinge Outlet's all-caps column
   heads -- a labelled list reads as structured; an unlabelled one reads
   as a stray menu. */
.lx-dd__cap {
  display: block; font-size: .6875rem; font-weight: 700; letter-spacing: .09em; text-transform: uppercase;
  color: var(--latch-steel); margin: 0 0 .75rem;
}

.lx-dd__grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 1.75rem; margin: 0; padding: 0; list-style: none; }
.lx-dd__list { margin: 0; padding: 0; list-style: none; display: grid; gap: .05rem; }

/* THE one row every dropdown link uses -- one line, no description crammed
   in (a category's or resource's blurb lives on its own page; that's what
   made every row a different height when it was here). Icon is optional:
   the eight category rows (Products, Brands' "what we supply" list) and
   Who we serve pass one; Brands' own names, Resources and the nested
   .lx-dd__row--sub types under a category stay icon-less text, so the list
   still reads as one system either way. */
.lx-dd__row {
  display: flex; align-items: center; gap: .65rem; padding: .6rem .7rem; margin-inline: -.7rem; border-radius: 2px;
  color: var(--latch-ink); font-size: .875rem; font-weight: 600; line-height: 1.3;
  border-left: 2px solid transparent; transition: background-color .15s ease, border-color .15s ease;
}
/* Who we serve's icon: a plain latch_glyph(), same 24x24/stroke-1.6 language
   as the masthead's own search/cart icons (there's no "product" to draw for
   an audience, so the technical-drawing treatment below doesn't apply). The
   more specific .lx-dd__ico selector below wins where a row has one. */
.lx-dd__row svg { flex: none; width: 22px; height: 22px; color: var(--latch-steel); transition: color .15s ease; }
.lx-dd__row:hover svg, .lx-dd__row:focus-visible svg, .lx-dd__row.is-active svg { color: var(--latch-bronze); }
/* The real technical drawing, an -icon rendering of it (illustrations/
   build-illustrations.py: same geometry, the THIN tier -- centre lines,
   screws, dimension ticks -- dropped, OUTLINE/DETAIL boldened) rather than
   the card/hero file directly. That file's own strokes (2.0/1.2/0.7 on a
   240x180 viewBox) were sized for 150px+ contexts; even at this row's width
   they fell under a pixel and read as no line at all, confirmed on the
   deployed page, not guessed from the numbers. viewBox is still 240x180 so
   width alone with height auto keeps proportions. */
.lx-dd__row .lx-dd__ico { flex: none; width: 44px; height: auto; color: var(--latch-steel); transition: color .15s ease; }
.lx-dd__row:hover .lx-dd__ico, .lx-dd__row:focus-visible .lx-dd__ico, .lx-dd__row.is-active .lx-dd__ico { color: var(--latch-bronze); }
.lx-dd__row:hover, .lx-dd__row:focus-visible, .lx-dd__row.is-active {
  background: var(--latch-surface); border-left-color: var(--latch-bronze); color: var(--latch-ink);
}
/* A second-level row (Brands' types, nested under a category) -- same
   shape, indented and a size down, never a different row style. */
.lx-dd__row--sub { padding-left: 1.55rem; font-size: .8125rem; font-weight: 500; color: var(--latch-steel); }
.lx-dd__row--sub:hover, .lx-dd__row--sub:focus-visible { color: var(--latch-ink); }

.lx-dd__foot {
  display: flex; flex-wrap: wrap; gap: .75rem 1.5rem; align-items: center; justify-content: space-between;
  margin-top: 1.25rem; padding-top: 1rem; border-top: 1px solid var(--latch-line); font-size: .875rem;
}
.lx-dd__foot a { font-weight: 600; color: var(--latch-ink); text-decoration: underline; text-underline-offset: .18em; text-decoration-color: var(--latch-bronze); }
.lx-dd__foot a:hover { color: var(--latch-bronze); }

/* Brands dropdown: a brand list on the left, that brand's categories on the
   right -- the same two-pane shape Banner Solutions' own Brands menu uses.
   Server-rendered for every brand (each .lx-dd__cats panel exists in the
   markup, only one un-hidden), so it works with no JS at all -- the footer
   script just swaps which panel is visible on hover/focus. Every link in
   here is .lx-dd__row, same as Products/Who we serve/Resources; only the
   two-pane frame around it is Brands-specific. */
.lx-dd--brands { padding: 0; width: min(680px, calc(100vw - 2 * var(--gutter))); }
/* .lx-dd__foot only ever carried its own top padding (for the divider line)
   -- everywhere else it sits inside .lx-dd's 1.5rem padding, which supplies
   the sides and the bottom. The brands panel zeroes that padding out (its
   two columns need to run edge to edge with their own backgrounds), so the
   footer row inherited none of it and sat flush against the box on three
   sides (found 21-Sep-2026, compared directly against the Products menu).
   Restore just those three sides, here only. */
.lx-dd--brands .lx-dd__foot { padding-inline: 1.5rem; padding-bottom: 1.5rem; }
/* min-height: 360px REMOVED 21-Sep-2026: it forced the row (and the
   category pane, stretched to match by grid's own default) to at least
   360px even for a brand with only one or two categories -- measured a
   95px gap of plain white space below Sargent's five-row list before this.
   The sidebar's own scroll cap (max-height, below) was the real driver of
   that height, at 420px far taller than a typical category list needs; cut
   to 300px, close to what a 4-6 category pane actually runs, so the two
   columns land within a row's height of each other instead of one hugely
   overshooting the other. */
.lx-dd__brandpanel { display: grid; grid-template-columns: 200px 1fr; }
/* The sidebar column: caption + scrolling list share one tinted, bordered
   box, so the caption doesn't visually detach from the list it labels when
   the list itself scrolls. */
.lx-dd__brandpanel > div:first-child {
  display: flex; flex-direction: column; padding: 1.5rem 0 1.5rem 1.5rem;
  border-right: 1px solid var(--latch-line); background: var(--latch-surface); min-height: 0;
}
.lx-dd__brandpanel > div:first-child > .lx-dd__cap { padding-right: 1rem; }
.lx-dd__brandlist { margin: 0; padding: 0 1rem 0 0; list-style: none; overflow-y: auto; max-height: 300px; }
.lx-dd__catpanel { padding: 1.5rem 1.75rem; }
.lx-dd__cats[hidden] { display: none; }
.lx-dd__cattype { margin-bottom: .1rem; }
.lx-dd__catrow { display: flex; align-items: stretch; }
.lx-dd__catrow .lx-dd__row { flex: 1; }
.lx-dd__typetoggle {
  flex: none; width: 34px; border: 0; background: none; color: var(--latch-steel);
  display: grid; place-items: center; cursor: pointer; border-radius: 2px;
}
.lx-dd__typetoggle:hover { color: var(--latch-ink); background: var(--latch-surface); }
.lx-dd__typetoggle svg { width: 11px; height: 11px; transition: transform .15s ease; }
.lx-dd__typetoggle[aria-expanded="true"] svg { transform: rotate(180deg); }
.lx-dd__types { margin: 0 0 .35rem; padding: 0; list-style: none; display: grid; gap: .05rem; }
.lx-dd__types[hidden] { display: none; }
.lx-dd__brandlink { display: inline-flex; align-items: center; gap: .3rem; font-size: .8125rem; font-weight: 600; color: var(--latch-steel); margin-top: .5rem; }
.lx-dd__brandlink:hover { color: var(--latch-ink); }
.lx-dd__brandlink svg { width: 10px; height: 10px; transform: rotate(-90deg); }

/* Mobile drawer: native <details> groups, no JS required to read it. */
.lx-drawer {
  display: none; background: #fff; border-bottom: 1px solid var(--latch-line);
}
.lx-drawer.is-open { display: block; }
.lx-drawer__inner { padding-block: 1rem 1.5rem; }
.lx-drawer .lx-search { max-width: none; margin-bottom: 1rem; }
.lx-drawer__group { border-top: 1px solid var(--latch-line); }
.lx-drawer__group summary, .lx-drawer__link {
  display: flex; align-items: center; justify-content: space-between; padding: .9rem 0;
  font-weight: 700; font-size: 1rem; color: var(--latch-ink); cursor: pointer; list-style: none;
}
.lx-drawer__group summary::-webkit-details-marker { display: none; }
.lx-drawer__group summary::after { content: "+"; font-weight: 400; font-size: 1.35rem; color: var(--latch-steel); line-height: 1; }
.lx-drawer__group[open] summary::after { content: "\2212"; }
.lx-drawer__sub { margin: 0 0 .9rem; padding: 0; list-style: none; display: grid; gap: .1rem; }
.lx-drawer__sub a { display: block; padding: .55rem 0 .55rem 1rem; color: var(--latch-ink); font-size: .95rem; border-left: 2px solid var(--latch-line); }
.lx-drawer__sub a:hover { border-left-color: var(--latch-bronze); }
.lx-drawer__foot { margin-top: 1.25rem; display: grid; gap: .75rem; }
.lx-drawer__foot .lx-btn { width: 100%; justify-content: center; }
.lx-drawer__meta { font-size: .875rem; color: var(--latch-steel); }
.lx-drawer__meta a { color: var(--latch-ink); text-decoration: underline; text-underline-offset: .18em; text-decoration-color: var(--latch-bronze); }

@media (max-width: 1080px) {
  .lx-nav { display: none; }
  .lx-burger { display: inline-grid; }
  .lx-masthead__row {
    grid-template-columns: 1fr auto; grid-template-areas: "logo actions" "search search"; gap: .9rem 1rem; padding-block: .85rem;
  }
  .lx-logo { grid-area: logo; }
  .lx-masthead__actions { grid-area: actions; }
  .lx-masthead .lx-search { grid-area: search; max-width: none; }
  .lx-masthead__actions .lx-btn--quote { display: none; }
  .lx-logo img { width: 172px; }
}
@media (max-width: 600px) {
  .lx-utility__claim { display: none; }
  .lx-utility__row { justify-content: center; }
  .lx-utility__links { gap: 1rem; }
  .lx-logo img { width: 160px; }
}

/* Blocksy's own header, offcanvas and search modal are replaced by the
   markup above, so anything the parent still tries to print is silenced. */
#header.ct-header, .ct-header-search-modal, .ct-panel.ct-header, #search-modal, #offcanvas { display: none !important; }

/* -------------------------------------------------------------- FOOTER */
.lx-footer { background: var(--latch-panel); color: var(--latch-panel-muted); font-size: .9rem; }
.lx-footer a { color: var(--latch-panel-muted); text-decoration: none; transition: color .15s ease; }
.lx-footer a:hover { color: #fff; text-decoration: underline; text-underline-offset: .18em; text-decoration-color: var(--latch-bronze); }
.lx-footer__grid {
  display: grid; grid-template-columns: 1.5fr 1fr 1fr 1fr 1fr;
  gap: clamp(1.5rem, 3vw, 3rem); padding-block: clamp(2.5rem, 2rem + 2vw, 4rem) clamp(2rem, 1.5rem + 1.5vw, 3rem);
}
.lx-footer__brand img { display: block; width: 190px; height: auto; margin-bottom: 1.1rem; }
.lx-footer__brand p { margin: 0 0 .9rem; max-width: 34ch; line-height: 1.6; }
.lx-footer__brand strong { color: var(--latch-panel-text); font-weight: 600; }
.lx-footer__mail { display: inline-block; color: #fff !important; font-weight: 600; font-size: 1rem; text-decoration: underline !important; text-underline-offset: .18em; text-decoration-color: var(--latch-bronze) !important; }
.lx-footer__t {
  font-size: var(--fs-eyebrow); font-weight: 700; letter-spacing: .14em; text-transform: uppercase;
  color: #fff; margin: 0 0 1rem;
}
.lx-footer__col ul { list-style: none; margin: 0; padding: 0; display: grid; gap: .55rem; }
.lx-footer__legal {
  border-top: 1px solid rgba(255,255,255,.12); padding-block: 1.25rem 1.5rem;
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: .75rem 2rem; font-size: .8125rem; line-height: 1.6;
}
.lx-footer__legal p { margin: 0; max-width: 80ch; }
.lx-footer__legal ul { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: .25rem 1.25rem; }
@media (max-width: 1000px) { .lx-footer__grid { grid-template-columns: 1fr 1fr 1fr; } .lx-footer__brand { grid-column: 1 / -1; } }
@media (max-width: 600px) { .lx-footer__grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 340px) { .lx-footer__grid { grid-template-columns: 1fr; } }
/* Blocksy's footer is replaced outright. */
footer.ct-footer { display: none !important; }

/* ------------------------------------------------------- PAGE HEADER + */
.lx-crumbs { display: flex; flex-wrap: wrap; gap: .45rem; margin: 0 0 1rem; padding: 0; list-style: none; font-size: .8125rem; color: var(--latch-panel-muted); }
.lx-crumbs a { color: var(--latch-panel-muted); text-decoration: none; }
.lx-crumbs a:hover { color: #fff; text-decoration: underline; text-underline-offset: .18em; }
.lx-crumbs li + li::before { content: "/"; margin-right: .45rem; color: rgba(255,255,255,.35); }
.lx-pagehead__grid { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: clamp(1.5rem, 4vw, 4rem); align-items: center; }
.lx-pagehead__art { color: #fff; opacity: .95; }
.lx-pagehead__art .latch-art { width: 100%; max-width: 300px; }
.lx-pagehead__actions { margin-top: 1.5rem; }
@media (max-width: 800px) { .lx-pagehead__grid { grid-template-columns: 1fr; } .lx-pagehead__art { display: none; } }

/* ---------------------------------------------------- GRID MODIFIERS */
.lx-grid--3 { grid-template-columns: repeat(3, 1fr); }
.lx-grid--2 { grid-template-columns: repeat(2, 1fr); }
.lx-card__cta {
  margin-top: auto; padding-top: 1rem; font-size: .85rem; font-weight: 600; color: var(--latch-ink);
  display: inline-flex; align-items: center; gap: .4rem;
}
.lx-card__cta::after { content: "\2192"; color: var(--latch-bronze); }
.lx-card__ico { display: block; width: 40px; height: 40px; color: var(--latch-ink); margin-bottom: 1rem; }
.lx-card__ico svg { width: 100%; height: 100%; display: block; }
.lx-card--static { cursor: default; }
.lx-card--static:hover { background: #fff; }
.lx-card--static:hover::after { transform: scaleX(0); }
@media (max-width: 1080px) { .lx-grid--3 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 600px) { .lx-grid--3, .lx-grid--2 { grid-template-columns: 1fr; } }
/* .lx-brandwall's responsive grid rules removed 23-Sep-2026: replaced by
   .lx-marquee (brand.css), which needs no breakpoints -- a flex row inside
   overflow:hidden is fluid at any width by construction. */

/* Section header row with a link on the right, the way Banner and Quality
   Door put "View all" beside a section title. */
.lx-sechead { display: flex; align-items: flex-end; justify-content: space-between; gap: 1rem 2rem; flex-wrap: wrap; margin-bottom: 1.6rem; }
.lx-sechead .lx-h2, .lx-sechead .lx-lead { margin-bottom: 0; }
.lx-sechead__link { font-weight: 600; font-size: .9rem; color: var(--latch-ink); text-decoration: underline; text-underline-offset: .18em; text-decoration-color: var(--latch-bronze); white-space: nowrap; }
.lx-sechead__link:hover { color: var(--latch-bronze); }

/* --------------------------------------------------------- SIBLING RAIL
   IKEA's category pattern: every sibling category is one click away from
   any category page, and the first item is the parent. */
.lx-rail { display: flex; gap: .5rem; overflow-x: auto; padding: 0 0 .6rem; margin: 0; list-style: none; scrollbar-width: thin; scroll-snap-type: x proximity; }
.lx-rail::-webkit-scrollbar { height: 4px; }
.lx-rail::-webkit-scrollbar-thumb { background: var(--latch-line); }
.lx-rail li { flex: 0 0 auto; scroll-snap-align: start; }
.lx-rail__item {
  display: inline-flex; align-items: center; gap: .6rem; padding: .5rem .95rem .5rem .55rem;
  border: 1px solid var(--latch-line); background: #fff; color: var(--latch-ink) !important;
  font-size: .875rem; font-weight: 600; text-decoration: none !important; white-space: nowrap; border-radius: 2px;
  transition: border-color .15s ease, background-color .15s ease;
}
.lx-rail__item:hover { border-color: var(--latch-control); background: var(--latch-surface); }
.lx-rail__item.is-current { border-color: var(--latch-ink); background: var(--latch-surface); }
.lx-rail__item .latch-art { width: 40px; color: var(--latch-ink); }
.lx-rail__item--up { padding-left: .95rem; }

/* ------------------------------------------------------- SEGMENT TILES
   Trudoor's category tiles and Banner's "Who we serve": a photograph under
   a scrim with the label over it. Our four duotone photographs carry it. */
.lx-segs { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; }
.lx-seg {
  position: relative; isolation: isolate; overflow: hidden; display: flex; align-items: flex-end;
  aspect-ratio: 4 / 5; background: var(--latch-panel); color: #fff; text-decoration: none !important;
}
.lx-seg img { position: absolute; inset: 0; z-index: -2; width: 100%; height: 100%; object-fit: cover; transition: transform .45s ease; }
.lx-seg::after { content: ""; position: absolute; inset: 0; z-index: -1; background: linear-gradient(180deg, rgba(16,20,24,.05) 30%, rgba(16,20,24,.92) 100%); }
.lx-seg:hover img { transform: scale(1.04); }
.lx-seg__body { position: relative; padding: clamp(1.1rem, 1rem + .5vw, 1.5rem); width: 100%; }
.lx-seg__body::before { content: ""; display: block; width: 26px; height: 2px; background: var(--latch-bronze); margin-bottom: .8rem; }
/* Reserve fixed space for the title (up to 2 lines) so the bottom-anchored
   block starts at the same height on every card regardless of how many
   lines each one's text wraps to (found 18-Sep-2026: "Property managers" is
   one line, "Contractors and multi-door jobs" is two). Description and cta
   link removed 22-Sep-2026 -- title only, real photos underneath now carry
   the rest. */
.lx-seg__t { display: block; font-size: clamp(1.1rem, 1rem + .5vw, 1.35rem); line-height: 1.25; min-height: 2.5em; font-weight: 800; letter-spacing: -.015em; color: #fff; }
@media (max-width: 1000px) { .lx-segs { grid-template-columns: repeat(2, 1fr); } .lx-seg { aspect-ratio: 5 / 4; } }
@media (max-width: 520px) { .lx-segs { grid-template-columns: 1fr; } .lx-seg { aspect-ratio: 16 / 10; } }

/* ------------------------------------------------------------ ACCORDION
   Native details/summary. Quality Door's FAQ is an accordion; ours also
   keeps the answers in the DOM for crawlers and print. */
.lx-acc { border-top: 1px solid var(--latch-line); margin-top: 1.4rem; }
.lx-acc details { border-bottom: 1px solid var(--latch-line); }
.lx-acc summary {
  list-style: none; cursor: pointer; display: grid; grid-template-columns: 1fr 24px; gap: 1.5rem; align-items: center;
  padding: 1.1rem 0; font-size: var(--fs-h3); font-weight: 700; color: var(--latch-ink);
}
.lx-acc summary::-webkit-details-marker { display: none; }
.lx-acc summary::after {
  content: ""; width: 12px; height: 12px; justify-self: center;
  background: linear-gradient(var(--latch-ink), var(--latch-ink)) center / 100% 2px no-repeat,
              linear-gradient(var(--latch-ink), var(--latch-ink)) center / 2px 100% no-repeat;
  transition: transform .2s ease;
}
.lx-acc details[open] summary::after { transform: rotate(45deg); }
.lx-acc summary:hover { color: var(--latch-bronze); }
.lx-acc__a { padding: 0 3rem 1.25rem 0; color: var(--latch-steel); font-size: var(--fs-small); line-height: 1.65; max-width: 72ch; }
.lx-acc__a p { margin: 0 0 .7rem; }
.lx-acc__a p:last-child { margin-bottom: 0; }
.lx-acc__a ul { margin: .4rem 0 .6rem; padding-left: 0; list-style: none; }
.lx-acc__a li { position: relative; padding-left: 1.2rem; margin-bottom: .3rem; }
.lx-acc__a li::before { content: ""; position: absolute; left: 0; top: .62em; width: .5rem; height: 2px; background: var(--latch-bronze); }
.lx-acc__group { margin-top: 2.25rem; }
.lx-acc__group:first-of-type { margin-top: 0; }
.lx-acc__gt { font-size: var(--fs-eyebrow); font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--latch-steel); margin: 0; }

/* ----------------------------------------------------------- TABLE */
.lx-table { width: 100%; border-collapse: collapse; font-size: var(--fs-small); margin: 1.5rem 0; }
.lx-table th, .lx-table td { text-align: left; padding: .8rem .9rem; border-bottom: 1px solid var(--latch-line); vertical-align: top; }
.lx-table th { font-size: var(--fs-eyebrow); font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: var(--latch-steel); border-bottom: 2px solid var(--latch-ink); }
.lx-table td:first-child { font-weight: 700; font-variant-numeric: tabular-nums slashed-zero; }
.lx-table tbody tr:nth-child(even) td { background: var(--latch-surface); }
.lx-tablewrap { overflow-x: auto; }

/* ------------------------------------------------------ SEARCH RESULTS */
.lx-results { list-style: none; margin: 1.5rem 0 0; padding: 0; display: grid; gap: 1px; background: var(--latch-line); border: 1px solid var(--latch-line); }
.lx-result { background: #fff; padding: 1.25rem 1.4rem; display: grid; gap: .3rem; }
.lx-result__k { font-size: var(--fs-eyebrow); font-weight: 700; letter-spacing: .13em; text-transform: uppercase; color: var(--latch-steel); }
.lx-result__t { font-size: var(--fs-h3); font-weight: 700; margin: 0; }
.lx-result__t a { color: var(--latch-ink); text-decoration: none; }
.lx-result__t a:hover { color: var(--latch-bronze); text-decoration: underline; text-underline-offset: .18em; }
.lx-result__d { margin: 0; font-size: var(--fs-small); color: var(--latch-steel); max-width: 80ch; }
.lx-result__price { font-weight: 700; font-variant-numeric: tabular-nums slashed-zero; }
.lx-empty { border: 1px solid var(--latch-line); border-left: 3px solid var(--latch-bronze); background: var(--latch-surface); padding: 1.5rem 1.6rem; max-width: 72ch; }
.lx-empty h2 { font-size: var(--fs-h3); margin: 0 0 .5rem; }
.lx-empty p { margin: 0 0 1rem; color: var(--latch-steel); font-size: var(--fs-small); }
.lx-empty .lx-actions { margin-top: .25rem; }
.lx-pagination { display: flex; gap: .5rem; flex-wrap: wrap; margin-top: 1.5rem; }
.lx-pagination a, .lx-pagination span { display: inline-grid; place-items: center; min-width: 40px; height: 40px; padding: 0 .75rem; border: 1px solid var(--latch-line); font-size: .875rem; font-weight: 600; color: var(--latch-ink); text-decoration: none; }
.lx-pagination .current { background: var(--latch-ink); color: #fff; border-color: var(--latch-ink); }
.lx-search--page { max-width: 720px; margin: 0; }

/* ----------------------------------------------------------- LINE PAGE */
.lx-linegrid { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, .8fr); gap: clamp(1.5rem, 4vw, 4rem); align-items: start; }
.lx-linegrid .lx-h2 { max-width: none; }
/* The line body is printed by inc/lines.php through a WooCommerce hook, so it
   sits OUTSIDE .entry-content and never picks up brand.css's prose h3 size.
   Its h3s fell back to Blocksy's own h3, a fixed 30px, while .lx-h2 clamps with
   the viewport: measured 15-Sep-2026 at 913px wide, h2 30.6px against h3 30px,
   and below that the h3 overtakes the h2 it sits under. Same token as the prose
   h3 so the two contexts match. */
.lx-linegrid h3 { font-size: var(--fs-h3); font-weight: 700; margin-top: 1.8rem; margin-bottom: .4rem; }
.lx-facts { border: 1px solid var(--latch-line); background: #fff; }
.lx-facts__row { padding: 1.1rem 1.3rem; border-bottom: 1px solid var(--latch-line); }
.lx-facts__row:last-child { border-bottom: 0; }
.lx-facts__k { display: block; font-size: var(--fs-eyebrow); font-weight: 700; letter-spacing: .13em; text-transform: uppercase; color: var(--latch-steel); margin-bottom: .45rem; }
.lx-facts__v { display: block; font-size: var(--fs-small); line-height: 1.55; }
.lx-facts__v ul { list-style: none; margin: 0; padding: 0; }
.lx-facts__v li { position: relative; padding-left: 1.1rem; margin-bottom: .3rem; }
.lx-facts__v li::before { content: ""; position: absolute; left: 0; top: .62em; width: .5rem; height: 2px; background: var(--latch-bronze); }
/* "Covers" (category pages) and "Other types in..." (type pages) are lists of
   real links now, not plain text -- style them like the rest of lx-facts__v
   but as proper link rows. */
.lx-facts__covers a { color: var(--latch-ink); }
.lx-facts__covers a:hover { color: var(--latch-bronze); }
.lx-facts__row--cta { background: var(--latch-surface); }
.lx-facts__row--cta .lx-btn { width: 100%; justify-content: center; }
.lx-facts__row--cta .lx-btn + .lx-btn { margin-top: .5rem; }
@media (max-width: 900px) { .lx-linegrid { grid-template-columns: 1fr; } }

/* WooCommerce archive chrome that Blocksy prints for category pages: the
   result count and ordering select mean nothing on an empty shelf. */
.lx-line-empty .woocommerce-result-count, .lx-line-empty .woocommerce-ordering, .lx-line-empty .ct-shop-toolbar, .lx-line-empty .woocommerce-notices-wrapper { display: none !important; }
.lx-line-empty .woocommerce-info { display: none !important; }
body.post-type-archive-product .hero-section, body.tax-product_cat .hero-section, body.search .hero-section, body.error404 .hero-section { display: none !important; }
body.tax-product_cat .entry-content > .lx, body.post-type-archive-product .entry-content > .lx,
body.tax-product_cat #main > .lx, body.post-type-archive-product #main > .lx, body.search #main > .lx, body.error404 #main > .lx {
  max-width: none !important; width: auto !important; margin-left: calc(50% - 50vw) !important; margin-right: calc(50% - 50vw) !important;
}
body.tax-product_cat #main, body.post-type-archive-product #main, body.search #main, body.error404 #main { padding-top: 0 !important; margin-top: 0 !important; }
body.tax-product_cat .ct-container, body.post-type-archive-product .ct-container, body.search .ct-container, body.error404 .ct-container { padding-top: 0; }

/* ---------------------------------------------------------- TRACK ORDER */
.lx-trackpanel { border: 1px solid var(--latch-line); background: #fff; padding: clamp(1.4rem, 1rem + 1.6vw, 2.25rem); max-width: 40rem; }
.lx-trackpanel form.track_order p { margin: 0 0 1rem; }
.lx-trackpanel form.track_order .form-row { margin-bottom: 1rem; }
.lx-trackpanel form.track_order label { display: block; font-weight: 500; margin-bottom: .35rem; }
.lx-trackpanel form.track_order input[type="text"], .lx-trackpanel form.track_order input[type="email"] { max-width: none; }
.lx-trackpanel form.track_order button, .lx-trackpanel form.track_order .button {
  background: var(--latch-ink); color: #fff; border: 1px solid var(--latch-ink); border-radius: 2px; padding: .82rem 1.4rem; font: inherit; font-weight: 600; cursor: pointer;
}

/* ------------------------------------------------------- 404 QUICK LINKS */
.lx-quicklinks { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1px; background: var(--latch-line); border: 1px solid var(--latch-line); margin-top: 1.5rem; }
.lx-quicklinks a { background: #fff; padding: 1.1rem 1.25rem; color: var(--latch-ink); text-decoration: none !important; font-weight: 600; font-size: .95rem; }
.lx-quicklinks a:hover { background: var(--latch-surface); color: var(--latch-bronze); }
@media (max-width: 700px) { .lx-quicklinks { grid-template-columns: 1fr; } }

/* ----------------------------------------------------------- MISC */
.lx-hero__copy .lx-actions { align-items: center; }
.lx-hero__search { margin-top: 1.5rem; max-width: 520px; }
.lx-hero__search .lx-search { margin: 0; border-color: rgba(255,255,255,.55); background: #fff; }
.lx-hero__hint { font-size: .8125rem; color: var(--latch-panel-muted); margin: .6rem 0 0; }
.lx-hero__hint a { color: #fff; text-decoration: underline; text-underline-offset: .18em; text-decoration-color: var(--latch-bronze); }
.lx-hero--photo .lx-hero__bg, .lx-hero--photo .lx-hero__bg img { width: 100%; }
.lx-mt0 { margin-top: 0 !important; }
.lx-mb0 { margin-bottom: 0 !important; }
.lx-lead--wide { max-width: 68ch; }
.lx-note--onDark { border-left-color: var(--latch-panel-muted); color: var(--latch-panel-muted); }
.lx-chips--onDark li { background: transparent; border-color: rgba(255,255,255,.2); border-bottom-color: var(--latch-panel-muted); color: #fff; }
.screen-reader-text { position: absolute !important; width: 1px; height: 1px; overflow: hidden; clip: rect(1px,1px,1px,1px); white-space: nowrap; }
.lx-skip { position: absolute; left: -999px; top: 0; background: var(--latch-ink); color: #fff; padding: .6rem 1rem; z-index: 100; }
.lx-skip:focus { left: 8px; top: 8px; }

/* --------------------------------------------------------- LATE FIXES
   Measured 14-Sep-2026 on the deployed chrome. */
/* style.css paints every .entry-content link ink with a bronze underline; the
   page header is prepended INSIDE the content, so breadcrumb links went ink
   on ink and vanished. Outscore that rule for anything inside a dark header. */
.entry-content .lx-pagehead .lx-crumbs a, .lx-crumbs a { color: var(--latch-panel-muted) !important; text-decoration: none !important; }
.entry-content .lx-pagehead .lx-crumbs a:hover, .lx-crumbs a:hover { color: #fff !important; text-decoration: underline !important; text-underline-offset: .18em; }
.entry-content .lx--dark a:not(.lx-btn), .entry-content .lx-pagehead a:not(.lx-btn):not(.lx-crumbs a) { color: #fff; text-decoration-color: var(--latch-panel-muted); }
/* The homepage hero scrim thinned to .62 at the right edge, and the photo's
   bright wall there read as an unfinished white strip. Hold it darker. */
.lx-hero--photo::after { background: linear-gradient(90deg, rgba(16,20,24,.97) 0%, rgba(16,20,24,.93) 45%, rgba(16,20,24,.80) 100%); }
.lx-pagehead--photo::after { background: linear-gradient(90deg, rgba(16,20,24,.97) 0%, rgba(16,20,24,.92) 50%, rgba(16,20,24,.78) 100%); }

/* ------------------------------------------------ HOMEPAGE HERO, 17-Sep-2026
   The hero drawing is now the opening-set specification plate: it carries type,
   so it runs larger than the old 460px closer, and it is HIDDEN below 1200px,
   where its labels fall under legible size and where, stacked above the copy,
   it pushed the h1 below the fold on a phone.
   The capability strip moved INTO the hero as its bottom row. As a loose white
   band under the hero it read as four orphan bronze bars; attached, it is the
   hero's proof. Its four facts were also replaced: "Grade 1 and Grade 2"
   repeated the hero, and "30 day returns" is false for special-order and
   factory-order hardware, which is the half of the catalogue the business is
   built around (product-catalogue.md Section 0). */
/* A little more top padding than the base .lx-hero clamp (brand.css), 18-Sep-2026,
   at the owner's request: the background photo reads taller with a bit more room
   above the eyebrow line. Bottom stays at 0 (lx-hero--caps), so only the top grows.
   Bumped a third time the same week, owner asked for more still each time. */
/* Height, rule as of 21-Sep-2026 (two bugs, same root cause, fixed together):
   min-height: 100vh ignored the header sitting above the hero, so the
   section was a full screen tall ON TOP OF the header, making the page
   header-height-worth taller than one screen. Content stayed pinned near
   the top (padding-top), so that extra height showed up as dead background
   below the buttons, only visible once you scrolled -- reported as the text
   "not centred" in the photo. Removing min-height fixed that, but then
   left the opposite problem on any screen where the header plus the actual
   content came out SHORTER than the screen: the next section's light
   background showed through at the bottom before you had scrolled at all.
   Fix is the header's REAL height, not a guess: --lx-header-h is measured
   in JS (inc/nav.php, wp_footer script) and kept current on resize. The
   hero's min-height is exactly "the rest of the screen" -- never taller
   (nothing left to scroll into), never shorter (nothing shows through).
   100svh over 100vh where supported, so mobile browser chrome showing or
   hiding doesn't reintroduce the same gap; 100vh is the fallback for
   browsers without svh, and 176px is the fallback for the instant before
   the JS measurement runs, or with JS disabled. */
.lx-hero--photo {
  padding-top: clamp(9rem, 5.5rem + 9vw, 14.5rem); padding-bottom: clamp(5.5rem, 4rem + 5.5vw, 9rem);
  min-height: calc(100vh - var(--lx-header-h, 176px));
  min-height: calc(100svh - var(--lx-header-h, 176px));
}
.lx-hero--photo .lx-hero__art { display: block; }
.lx-hero--photo .lx-hero__art svg { margin-left: auto; }
/* Bumped 560 -> 600px, 17-Sep-2026: the plate was restored to its fuller detail
   (header, corner marks, footer block) and enlarged at the owner's request, after
   an earlier same-day thinning the owner had not asked for. */
.lx-hero--photo .latch-art--hero { max-width: 600px; margin-left: auto; opacity: 1; }
/* Hidden below 1200px, not 900px: measured 17-Sep-2026 at a 1024px window the plate
   rendered about 420px wide and its labels fell to 8 to 10px. With the plate gone the
   hero goes single column so the right half is not left empty. */
@media (max-width: 1199px) {
  .lx-hero--caps .lx-hero__grid { grid-template-columns: 1fr; }
  .lx-hero--caps .lx-hero__art { display: none; }
}
/* The photo hero (the homepage) shares this same plate and never got the fix
   above -- it was still switching to one column at the generic 900px used by
   every other hero/split layout, so between 901 and 1199px it stayed two
   columns while the column narrowed. Measured 21-Sep-2026: by 988px the plate
   was already down to 409px wide, past the same illegibility point, while the
   headline's font had only shrunk about 10% in that same range -- the plate
   visibly outpacing the text, then an abrupt reflow at 900px on top of that
   (found via devtools at a resized window, text and art swapping position).
   Unlike lx-hero--caps this plate stays wanted at any size (the owner has
   asked more than once for it to be prominent), so it doesn't hide -- it
   moves above the headline at the same 1199px line instead, where it gets a
   full column's width (up to its own 600px cap) rather than a shrinking
   fraction of one. */
@media (max-width: 1199px) {
  .lx-hero--photo .lx-hero__grid { grid-template-columns: 1fr; }
  .lx-hero--photo .lx-hero__art { order: -1; }
}


/* The photo's bright wall and door signage sat directly behind the plate's 13px
   type and read as clutter at wide viewports. The photo still covers edge to edge
   (measured 1825 of 1825px at a 1840px window); this holds the right side dark. */
@media (min-width: 901px) {
  .lx-hero--caps::after { background: linear-gradient(90deg, rgba(16,20,24,.97) 0%, rgba(16,20,24,.94) 50%, rgba(16,20,24,.92) 100%); }
}
.lx-caps--hero {
  margin-top: clamp(2.5rem, 1.5rem + 3vw, 4rem);
  border-top: 1px solid rgba(255,255,255,.14); border-bottom: 0;
  grid-template-columns: repeat(4, 1fr);
}
.lx-caps--hero .lx-cap {
  border-top: 0; margin: 0; padding: 1.6rem 1.5rem 1.9rem;
  display: grid; grid-template-columns: 1.375rem minmax(0, 1fr); column-gap: .85rem; align-content: start;
}
.lx-caps--hero .lx-cap:first-child { padding-left: 0; }
.lx-caps--hero .lx-cap + .lx-cap { border-left: 1px solid rgba(255,255,255,.14); }
.lx-cap__ico { grid-row: 1 / span 2; width: 1.375rem; height: 1.375rem; color: #fff; margin-top: .1rem; }
.lx-cap__ico svg { width: 100%; height: 100%; display: block; }
.lx-caps--hero .lx-cap__k { grid-column: 2; color: #fff; font-size: .9375rem; margin-bottom: .2rem; }
.lx-caps--hero .lx-cap__v { grid-column: 2; color: var(--latch-panel-muted); }
/* Four across only where each fact fits on one line: measured 17-Sep-2026, every key
   and value is single-line once the strip's box is 1240px or wider, a 1260px window. */
@media (max-width: 1259px) {
  .lx-caps--hero { grid-template-columns: repeat(2, 1fr); }
  .lx-caps--hero .lx-cap:nth-child(odd) { padding-left: 0; border-left: 0; }
  .lx-caps--hero .lx-cap:nth-child(n+3) { border-top: 1px solid rgba(255,255,255,.14); }
}
@media (max-width: 600px) {
  .lx-caps--hero { grid-template-columns: 1fr; }
  .lx-caps--hero .lx-cap { padding: 1.15rem 0; }
  .lx-caps--hero .lx-cap + .lx-cap { border-left: 0; border-top: 1px solid rgba(255,255,255,.14); }
}

/* ------------------------------------------ SEAMS BETWEEN BANDS, 17-Sep-2026
   A page body is a stack of full-bleed bands, but Blocksy's flow layout gives
   every block a bottom margin of --theme-content-spacing (25.5px) and its content
   container a 60px bottom padding. Wherever two non-white bands met, that showed
   as a white seam: hero to grey, dark to grey, grey to dark, and a white band
   between every closing call to action and the footer. Measured by scanning the
   rendered homepage edge: seams at 26px, 26px, 25px, and 157px above the footer.
   The :has() rule touches only pages whose body ENDS in a band, so cart, account,
   privacy and terms keep their spacing. */
.entry-content > section.lx { margin-block: 0; }
[data-vertical-spacing]:has(> article > .entry-content > section.lx:last-child) { padding-bottom: 0; }
/* The closing band and the footer are the same panel colour; with no gap they
   would read as one block, so the footer carries a hairline edge. */
.lx-footer { border-top: 1px solid rgba(255,255,255,.1); }

/* ------------------------------------------------ CATALOGUE REALIGN, 17-Sep-2026
   The brands grid now holds 23 cards, so the last row left a painted empty cell
   (the hairlines are the container background). The last card spans whatever its
   row has left, per column count: 3 above 1080px, 2 from 621px (brand.css).
   CORRECTED the same day: "grid-column-end: -1" was tried first and moved the last
   card into the third column, leaving the hole in the middle instead. The two-card
   case is excluded because brand.css already turns that grid into two columns. */
@media (min-width: 1081px) {
  .lx-brands > .lx-brand:last-child:nth-child(3n+2):not(:nth-child(2)) { grid-column: span 2; }
  .lx-brands > .lx-brand:last-child:nth-child(3n+1):not(:first-child) { grid-column: span 3; }
}
@media (min-width: 621px) and (max-width: 1080px) {
  .lx-brands > .lx-brand:last-child:nth-child(2n+1):not(:first-child) { grid-column: span 2; }
}
/* Brand chips inside a category page's facts panel inherited the panel's own
   bronze list dash (.lx-facts__v li::before). A chip is not a bullet. */
.lx-facts__v .lx-chips li { padding-left: 1.05rem; }
.lx-facts__v .lx-chips li::before { content: none; }

/* -------------------------------------------------- PROOF BAND (home, dark)
   23-Sep-2026. Replaces the icon-and-caption row: the number is the point, so
   it is set large and the sentence sits under it. Dark ground, so white and
   muted only, no bronze. A hairline draws in over each cell on reveal. */
.lx-proof { display: grid; grid-template-columns: repeat(3, 1fr); margin-top: 2.2rem; }
.lx-proof__i { position: relative; display: grid; grid-template-columns: 1fr auto; align-content: start; padding: 1.6rem 1.5rem 1.7rem; transition: background-color .2s ease; }
.lx-proof__i + .lx-proof__i { border-left: 1px solid rgba(255,255,255,.10); }
.lx-proof__i::before { content: ""; position: absolute; inset: 0 0 auto 0; height: 2px; background: #fff; transform-origin: left; opacity: .9; }
.lx-proof__i:first-child { padding-left: 0; }
.js-reveal .lx-proof__i::before { transform: scaleX(0); transition: transform .7s cubic-bezier(.2,.7,.2,1); }
.js-reveal .lx-proof.is-in .lx-proof__i::before { transform: scaleX(1); }
.js-reveal .lx-proof.is-in .lx-proof__i:nth-child(2)::before { transition-delay: .12s; }
.js-reveal .lx-proof.is-in .lx-proof__i:nth-child(3)::before { transition-delay: .24s; }
.lx-proof__i:hover { background: rgba(255,255,255,.04); }
.lx-proof__ico { grid-column: 2; grid-row: 1; width: 1.4rem; height: 1.4rem; color: var(--latch-panel-muted); transition: color .2s ease; }
.lx-proof__ico svg { width: 100%; height: 100%; display: block; }
.lx-proof__i:hover .lx-proof__ico { color: #fff; }
.lx-proof__n { grid-column: 1 / -1; grid-row: 1; font-size: clamp(2.4rem, 4.2vw, 3.5rem); font-weight: 800; line-height: 1; letter-spacing: -.03em; color: #fff; font-variant-numeric: tabular-nums; }
.lx-proof__u { grid-column: 1 / -1; font-size: .8125rem; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--latch-panel-muted); margin: .55rem 0 1.1rem; }
.lx-proof__k { grid-column: 1 / -1; font-size: 1rem; font-weight: 700; color: #fff; margin-bottom: .3rem; }
.lx-proof__v { grid-column: 1 / -1; font-size: var(--fs-small); color: var(--latch-panel-muted); line-height: 1.5; }
@media (max-width: 600px) {
  .lx-proof { grid-template-columns: 1fr; }
  .lx-proof__i, .lx-proof__i + .lx-proof__i { padding: 1.3rem 0; border-left: 0; }
  .lx-proof__i + .lx-proof__i { border-top: 1px solid rgba(255,255,255,.10); }
}
@media (prefers-reduced-motion: reduce) { .lx-proof__i, .lx-proof__ico, .lx-proof__i::before { transition: none !important; } }

/* ------------------------------------------- CLOSING BAND, PHOTO READ (home, dark)
   23-Sep-2026. Right column of "A dealer that does not pretend to hold
   stock". An earlier draft drew warehouse -> Latchford -> door, which made
   Latchford look like a middleman; dropped the same day. This shows the
   signature offer instead: what we read off a photo of the part. No stock
   photo (hard rule 1). White and muted only on dark. */
.lx-close { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr); gap: clamp(2rem, 6vw, 5rem); align-items: center; }
.lx-scan { margin: 0; padding: 1.4rem 1.2rem 1rem; background: rgba(255,255,255,.04); border: 1px solid rgba(255,255,255,.12); }
.lx-scan__svg { display: block; width: 100%; height: auto; }
.lx-scan__cap { margin-top: .6rem; font-size: var(--fs-small); color: var(--latch-panel-muted); }
.js-reveal .lx-scan__ln { stroke-dasharray: 1; stroke-dashoffset: 1; transition: stroke-dashoffset .8s cubic-bezier(.2,.7,.2,1) var(--d, 0s); }
.js-reveal .lx-scan__t { opacity: 0; transition: opacity .5s ease calc(var(--d, 0s) + .3s); }
.js-reveal .lx-scan.is-in .lx-scan__ln { stroke-dashoffset: 0; }
.js-reveal .lx-scan.is-in .lx-scan__t { opacity: 1; }
@media (max-width: 900px) { .lx-close { grid-template-columns: 1fr; } }
@media (prefers-reduced-motion: reduce) { .js-reveal .lx-scan__ln, .js-reveal .lx-scan__t { transition: none; } }

/* Mobile pass, 23-Sep-2026 (checked at 390px in headless Chrome). */
@media (max-width: 600px) {
  .lx-scan { padding: 1rem .5rem .8rem; }
  .lx-scan__svg { overflow: visible; }
  .lx-scan__t { font-size: 19px; }
  .lx-scan__t + .lx-scan__t { font-size: 15.5px; }
}

/* ------------------------------------------------- SERIES PRODUCT PAGES
   26-Sep-2026, inc/product.php. WooCommerce's own single-product template
   with Blocksy's gallery on the left and our buy box on the right, then the
   part-number table and the reference sections, all scoped to body.lx-series.
   The table turns into one card per part number under 760px. */
.lx-series .product-entry-wrapper { align-items: start; }
.lx-pd__crumbs { margin: 0 auto 1.25rem; }
.lx-pd__crumbs .lx-crumbs { margin: 0; color: var(--latch-steel); }
.lx-pd__crumbs .lx-crumbs a { color: var(--latch-steel) !important; }
.lx-pd__crumbs .lx-crumbs a:hover { color: var(--latch-ink) !important; }
.lx-pd__crumbs .lx-crumbs li + li::before { color: var(--latch-control); }
.lx-series .woocommerce-product-gallery .ct-media-container { border: 1px solid var(--latch-line); }
/* Blocksy crops gallery images to 3:4 with object-fit cover; product photos are square on white and must show whole. */
.lx-series .woocommerce-product-gallery .ct-media-container img { aspect-ratio: 1 / 1 !important; object-fit: contain !important; height: auto; }
.lx-pd__body { padding-bottom: clamp(2.5rem, 2rem + 2.5vw, 4rem); }

.lx-pd__eyebrow { display: flex; align-items: center; gap: .55rem; font-size: var(--fs-eyebrow); font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: var(--latch-steel); margin: 0 0 .6rem; }
.lx-pd__eyebrow::before { content: ""; width: 1.25rem; height: 2px; background: var(--latch-bronze); } /* bronze is 4.22:1, too low for 11px text (Lighthouse, 26-Sep) */
.lx-series .lx-pd__title { font-size: clamp(1.75rem, 1.3rem + 1.6vw, 2.5rem); font-weight: 800; line-height: 1.08; margin: 0 0 1rem; max-width: 20ch; }
.lx-pd__capsule { font-size: var(--fs-lead); line-height: 1.55; margin: 0 0 1.4rem; max-width: 56ch; }
.lx-pd__facts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); margin: 0 0 1.5rem; border-top: 1px solid var(--latch-line); }
.lx-pd__fact { padding: .8rem 1rem .8rem 0; border-bottom: 1px solid var(--latch-line); }
.lx-pd__fact:nth-child(even) { padding-left: 1rem; border-left: 1px solid var(--latch-line); }
.lx-pd__fact dt { font-weight: 800; font-size: var(--fs-body); letter-spacing: -.01em; }
.lx-pd__fact dd { margin: .1rem 0 0; font-size: var(--fs-small); color: var(--latch-steel); line-height: 1.45; }
.lx-pd__buy { background: var(--latch-surface); border: 1px solid var(--latch-line); border-top: 3px solid var(--latch-bronze); padding: 1.2rem 1.3rem 1.35rem; margin: 0 0 1.25rem; }
.lx-pd__price { margin: 0; display: flex; align-items: baseline; flex-wrap: wrap; gap: .45rem; }
.lx-pd__from, .lx-pd__cur { font-size: var(--fs-small); color: var(--latch-steel); font-weight: 600; }
.lx-pd__amount { font-size: clamp(1.75rem, 1.4rem + 1.2vw, 2.25rem); font-weight: 800; letter-spacing: -.02em; font-variant-numeric: tabular-nums; line-height: 1.1; }
.lx-pd__pricenote { margin: .3rem 0 1.1rem; font-size: var(--fs-small); color: var(--latch-steel); }
.lx-pd__buy .lx-actions .lx-btn { flex: 1 1 13rem; }
.lx-pd__assure { list-style: none; margin: 0; padding: 0; display: grid; gap: .55rem; }
.lx-pd__assure li { display: flex; gap: .6rem; align-items: flex-start; font-size: var(--fs-small); color: var(--latch-steel); margin: 0; line-height: 1.45; }
.lx-pd__assure svg { flex: none; width: 1.15rem; height: 1.15rem; color: var(--latch-bronze); margin-top: .05rem; }

.lx-pd__sec { margin-top: clamp(2.5rem, 2rem + 2.5vw, 4rem); padding-top: clamp(2.5rem, 2rem + 2.5vw, 4rem); border-top: 1px solid var(--latch-line); scroll-margin-top: 5rem; }
.lx-pd__sec .lx-lead { margin-bottom: 1.5rem; }
.lx-pd__small { font-size: var(--fs-small); color: var(--latch-steel); margin: .9rem 0 0; max-width: 72ch; }

.lx-pd__tablewrap { border: 1px solid var(--latch-line); overflow-x: auto; }
.lx-series table.lx-pd__table { width: 100%; border-collapse: collapse; border: 0; margin: 0; font-size: var(--fs-small); }
.lx-series .lx-pd__table th, .lx-series .lx-pd__table td { padding: .8rem .9rem; border: 0; border-bottom: 1px solid var(--latch-line); text-align: left; vertical-align: middle; }
.lx-series .lx-pd__table thead th { font-size: var(--fs-eyebrow); letter-spacing: .1em; text-transform: uppercase; color: var(--latch-steel); font-weight: 700; background: var(--latch-surface); white-space: nowrap; }
.lx-series .lx-pd__table tbody tr:last-child > * { border-bottom: 0; }
.lx-pd__table tbody tr:hover { background: #FAFAFB; }
.lx-pd__sku { font-weight: 800; font-size: .9375rem; white-space: nowrap; }
/* Each part number links to its own preselected URL (?part=), which Google's
   variant markup requires. It reads as the part number, not as a link. */
a.lx-pd__sku { color: inherit; text-decoration: none; }
a.lx-pd__sku:hover, a.lx-pd__sku:focus-visible { text-decoration: underline; text-underline-offset: 3px; }
.lx-pd__table tr.is-selected { background: var(--latch-surface); box-shadow: inset 3px 0 0 var(--latch-bronze); }
.lx-pd__selected { margin: 0 0 .25rem; font-size: var(--fs-small); color: var(--latch-steel); }
.lx-pd__selected strong { color: var(--latch-ink); }
.lx-series .lx-pd__table .lx-pd__num { text-align: right; font-variant-numeric: tabular-nums; font-weight: 700; white-space: nowrap; }
.lx-pd__onreq { font-weight: 600; color: var(--latch-steel); }
.lx-series .lx-pd__table .lx-pd__act { text-align: right; white-space: nowrap; width: 1%; }
.lx-pd__btn { padding: .6rem 1rem; font-size: .8125rem; }

.lx-pd__builder { margin-top: 2rem; padding: 1.4rem 1.5rem .4rem; border: 1px solid var(--latch-line); }
.lx-pd__builder h3 { font-size: var(--fs-h3); margin: 0 0 .5rem; }
.lx-pd__builder > p:not(.lx-note) { font-size: var(--fs-small); color: var(--latch-steel); max-width: 72ch; margin: 0 0 1.2rem; }
.lx-pd__codegrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); gap: 1.5rem; margin-bottom: 1.4rem; }
.lx-pd__codes h4 { font-size: var(--fs-eyebrow); letter-spacing: .1em; text-transform: uppercase; color: var(--latch-steel); margin: 0 0 .5rem; }
.lx-series .lx-pd__codes ul { list-style: none; margin: 0; padding: 0; }
.lx-series .lx-pd__codes li { display: grid; grid-template-columns: 4.25rem 1fr; gap: .6rem; padding: .45rem 0; margin: 0; border-top: 1px solid var(--latch-line); font-size: var(--fs-small); line-height: 1.4; }
.lx-pd__codes code { font-family: inherit; font-size: inherit; font-weight: 800; background: none; padding: 0; color: var(--latch-ink); }
.lx-pd__codes span { color: var(--latch-steel); }

.lx-pd__specgrid { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); gap: clamp(1.5rem, 4vw, 3.5rem); align-items: start; margin-top: 1.5rem; }
.lx-series table.lx-pd__spec { width: 100%; border-collapse: collapse; border: 0; border-top: 1px solid var(--latch-line); margin: 0; font-size: var(--fs-small); }
.lx-series .lx-pd__spec th, .lx-series .lx-pd__spec td { padding: .75rem 0; border: 0; border-bottom: 1px solid var(--latch-line); text-align: left; vertical-align: top; line-height: 1.5; }
.lx-series .lx-pd__spec th { width: 38%; padding-right: 1.25rem; font-weight: 700; }
.lx-series .lx-pd__spec td { color: var(--latch-steel); }
.lx-pd__specgrid--solo { grid-template-columns: minmax(0, 60rem); } /* no drawing: the table takes the width */
.lx-pd__figure { margin: 0; padding: 1.25rem 1.25rem 1rem; border: 1px solid var(--latch-line); color: var(--latch-ink); position: sticky; top: 6rem; }
.lx-pd__drawing { display: block; width: 100%; height: auto; }
.lx-pd__figure figcaption { font-size: var(--fs-small); color: var(--latch-steel); margin-top: .75rem; }

.lx-pd__fit { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 clamp(1.5rem, 4vw, 3rem); border-top: 1px solid var(--latch-line); margin: 1.5rem 0 2rem; }
.lx-pd__fitrow { padding: 1rem 0; border-bottom: 1px solid var(--latch-line); }
.lx-pd__fitrow h3 { font-size: var(--fs-body); font-weight: 700; margin: 0 0 .25rem; letter-spacing: -.01em; }
.lx-pd__fitrow p { margin: 0; font-size: var(--fs-small); color: var(--latch-steel); line-height: 1.55; }
.lx-pd__ahj { margin-bottom: 0; }
.lx-series .lx-steps { margin-top: 1.5rem; clip-path: inset(-12px 0 -12px 0); } /* the travelling bar starts at left:-16% and spilled into the gutter */

.lx-pd__foot { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 2rem; border-top: 0; padding-top: 0; } /* the FAQ's last rule already separates it */
.lx-pd__h3 { font-size: var(--fs-h3); font-weight: 800; margin: 0 0 .75rem; }
.lx-series .lx-pd__links { list-style: none; margin: 0; padding: 0; display: grid; gap: .55rem; font-size: var(--fs-small); }
.lx-series .lx-pd__links li { margin: 0; }
.lx-pd__links a { color: var(--latch-ink); text-decoration: underline; text-decoration-color: var(--latch-control); text-underline-offset: .2em; }
.lx-pd__links a:hover { text-decoration-color: var(--latch-bronze); }

.lx-pd__band { margin-top: clamp(2.5rem, 2rem + 2.5vw, 4rem); background: var(--latch-panel); color: var(--latch-panel-text); padding: clamp(1.75rem, 1.2rem + 2vw, 3rem); display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 1.5rem 3rem; align-items: center; }
.lx-pd__band .lx-h2 { margin-bottom: .5rem; }
.lx-pd__band p { margin: 0; color: var(--latch-panel-muted); font-size: var(--fs-small); max-width: 60ch; }

@media (max-width: 900px) {
  .lx-pd__codegrid, .lx-pd__specgrid { grid-template-columns: 1fr; }
  .lx-pd__figure { position: static; }
}
@media (max-width: 760px) {
  .lx-pd__fit, .lx-pd__foot, .lx-pd__band { grid-template-columns: 1fr; }
  .lx-pd__tablewrap { border: 0; overflow: visible; }
  .lx-pd__table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .lx-pd__table, .lx-pd__table tbody { display: block; }
  .lx-pd__table tbody tr { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: .15rem 1rem; align-items: center; padding: .9rem 1rem; border: 1px solid var(--latch-line); margin-bottom: .5rem; }
  .lx-series .lx-pd__table th, .lx-series .lx-pd__table td { display: block; padding: 0; border: 0; }
  .lx-series .lx-pd__table .lx-pd__num { grid-column: 2; grid-row: 1; font-size: 1rem; }
  .lx-pd__table td[data-label]:not(.lx-pd__num) { grid-column: 1 / -1; color: var(--latch-steel); }
  .lx-pd__table td[data-label]:not(.lx-pd__num):not([data-label="Availability"])::before { content: attr(data-label) ": "; color: var(--latch-ink); font-weight: 600; }
  .lx-series .lx-pd__table td[data-label="Availability"] { grid-column: 1; margin-top: .55rem; }
  .lx-series .lx-pd__table .lx-pd__act { grid-column: 2; width: auto; margin-top: .55rem; }
}

/* Quote form: the part number a product row sent, shown so the buyer can see it arrived. */
.lx-quote-item { margin: 0 0 1.25rem; }
.lx-quote-item strong { color: var(--latch-ink); }
