/* 810 Fireworks - one stylesheet, mobile first.
 *
 * Palette is the client's: navy #0d2149, red #d81e2c, white, with a bright
 * sky blue for the second half of the headline (a mid blue on a navy ground
 * is unreadable, so the "white/blue" word coloring from the mockup uses a
 * blue that actually holds contrast against navy).
 *
 * Every piece of decoration here is drawn in CSS or inline SVG. There is not
 * one generated or stock photograph anywhere in this file or in
 * public/assets/img - the only images the site ships are the client's own
 * logo and their 2025 banner artwork.
 *
 * The logo is used exactly as supplied. The .logo frame crops the white
 * canvas around the artwork (the file is 1100x746 with the mark occupying
 * 1065x458 at offset 11,153) by positioning the untouched image inside an
 * overflow-hidden box. The artwork itself is never scaled non-uniformly,
 * never recolored and never redrawn.
 */

:root {
  --navy: #0d2149;
  --navy-deep: #081634;
  --navy-mid: #16325f;
  --navy-line: #27406f;
  --red: #d81e2c;
  /* The same red, lifted until it is legible as TEXT on this site's dark
   * ground. Measured: --red on --navy is 3.12:1, which fails the 4.5:1 gate;
   * --red-lit on --navy is 4.76:1. Hue is preserved - both sit at 355.5deg,
   * so this is the brand red at a different lightness, not a fourth colour.
   * Use --red for fills, bars, borders and buttons; --red-lit only where red
   * has to be read as a word. */
  --red-lit: #f9505c;
  --red-dark: #ae1622;
  --blue: #52a8ff;
  --ink: #111a2c;
  --ink-soft: #46536b;
  --cream: #f4f7fc;
  --line: #dde4ef;
  --wrap: 1180px;
  --head-h: 64px;
  /* The header's bottom border lives OUTSIDE --head-h: the element is
   * box-sizing: border-box with min-height: var(--head-h) on .head-row, so the
   * rendered border box is --head-h + this. .first-screen must subtract both
   * or it overflows the viewport by exactly this much. */
  --head-border: 1px;
  --r: 14px;
  --sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --shadow: 0 14px 40px rgba(8, 22, 52, .14);
  --shadow-dark: 0 22px 60px rgba(0, 0, 0, .45);
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0; background: #fff; color: var(--ink);
  font: 16px/1.6 var(--sans);
  -webkit-font-smoothing: antialiased;
}
img, svg { max-width: 100%; }
img { height: auto; }
a { color: var(--red); text-decoration: none; }
a:hover { text-decoration: underline; }
h1, h2, h3 { margin: 0 0 .5em; line-height: 1.1; letter-spacing: -.015em; font-weight: 800; }
p { margin: 0 0 1em; }
.wrap { width: 100%; max-width: var(--wrap); margin: 0 auto; padding: 0 18px; }
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.dot { opacity: .55; padding: 0 .15em; }
.muted { color: var(--ink-soft); }
.skip { position: absolute; left: -9999px; }
.skip:focus { left: 8px; top: 8px; z-index: 60; background: #fff; color: var(--navy); padding: 10px 14px; border-radius: 8px; box-shadow: var(--shadow); }
:focus-visible { outline: 3px solid var(--blue); outline-offset: 2px; border-radius: 4px; }

/* ---------- header ---------- */
/* Dark nav with the red pill CTA top-right, from the client's mock. This is
 * shared chrome, so it is the one part of the home-page lane that shows up on
 * every page - deliberately, because the mock's nav is the mock's nav.
 *
 * The logo needs no special handling on a dark bar. The supplied PNG has an
 * opaque white background and no alpha, and .logo is an overflow-hidden crop
 * box that the image fills completely, so on navy it reads as a white badge.
 * That is the file as supplied, uncropped and unrecolored, which is the
 * standing rule - the only addition is a corner radius on the box. */
.site-head {
  position: sticky; top: 0; z-index: 40;
  background: var(--navy-deep); border-bottom: 1px solid var(--navy-line);
}
.head-row { display: flex; align-items: center; justify-content: space-between; gap: 14px; min-height: var(--head-h); }
.logo { display: block; position: relative; overflow: hidden; height: 38px; aspect-ratio: 1065 / 458; flex: none; }
.logo img { position: absolute; left: -1.033%; top: -33.406%; width: 103.286%; height: 162.882%; max-width: none; }
.logo { border-radius: 9px; }
.logo:hover { text-decoration: none; opacity: .88; }

/* The red pill, top-right. Not .btn: that one is sized for in-page calls to
 * action and would push .head-row past --head-h, which the first-screen
 * height math below subtracts as a known constant. */
.head-right { display: flex; align-items: center; gap: 10px; flex: none; }
.head-cta {
  display: inline-flex; align-items: center; background: var(--red); color: #fff;
  border-radius: 999px; padding: 9px 15px; white-space: nowrap;
  font-size: 12.5px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
  box-shadow: 0 8px 20px rgba(216,30,44,.3);
}
.head-cta:hover { background: var(--red-dark); text-decoration: none; }

.nav-toggle {
  appearance: none; border: 0; background: var(--navy-mid); color: #fff;
  width: 42px; height: 38px; border-radius: 10px; padding: 10px 9px;
  display: flex; flex-direction: column; justify-content: space-between; cursor: pointer;
}
.nav-toggle span { display: block; height: 2px; background: #fff; border-radius: 2px; }
.nav-toggle span:nth-child(2) { background: var(--red); }

.site-nav { display: none; }
body.nav-open .site-nav {
  display: flex; flex-direction: column;
  position: absolute; left: 0; right: 0; top: 100%;
  background: var(--navy-deep); border-bottom: 3px solid var(--red);
  box-shadow: var(--shadow-dark); padding: 6px 18px 14px;
}
.site-nav a {
  color: #dbe6f8; font-weight: 700; font-size: 15px;
  text-transform: uppercase; letter-spacing: .07em;
  padding: 13px 2px; border-bottom: 1px solid var(--navy-line);
}
.site-nav a:last-child { border-bottom: 0; }
/* A red underline rather than red text: #d81e2c on #081634 is about 3:1,
 * which is under the 4.5:1 floor for 15px type. White text with a red rule
 * marks the current page without dropping below contrast. */
.site-nav a.on { color: #fff; box-shadow: inset 0 -3px 0 var(--red); }

/* ---------- decorative starbursts ---------- */
.sparks { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
.sparks i {
  position: absolute; width: 3px; height: 3px; border-radius: 50%;
  background: #fff; opacity: .5;
  box-shadow:
    0 0 0 1px rgba(255,255,255,.18),
    14px 0 0 -1px rgba(216,30,44,.75), -14px 0 0 -1px rgba(216,30,44,.75),
    0 14px 0 -1px rgba(255,255,255,.6), 0 -14px 0 -1px rgba(255,255,255,.6),
    10px 10px 0 -1px rgba(82,168,255,.7), -10px -10px 0 -1px rgba(82,168,255,.7),
    10px -10px 0 -1px rgba(255,255,255,.45), -10px 10px 0 -1px rgba(255,255,255,.45),
    26px 0 0 -2px rgba(216,30,44,.5), -26px 0 0 -2px rgba(216,30,44,.5),
    0 26px 0 -2px rgba(255,255,255,.35), 0 -26px 0 -2px rgba(255,255,255,.35),
    19px 19px 0 -2px rgba(82,168,255,.45), -19px -19px 0 -2px rgba(82,168,255,.45),
    19px -19px 0 -2px rgba(255,255,255,.3), -19px 19px 0 -2px rgba(255,255,255,.3);
}
.sparks .s1 { left: 8%;  top: 18%; transform: scale(.9); }
.sparks .s2 { left: 82%; top: 12%; transform: scale(1.25); }
.sparks .s3 { left: 60%; top: 72%; transform: scale(.7); }
.sparks .s4 { left: 24%; top: 82%; transform: scale(1); }
.sparks .s5 { left: 94%; top: 56%; transform: scale(.8); }
.sparks .s6 { left: 44%; top: 8%;  transform: scale(.6); }

/* ---------- buttons ---------- */
.btn {
  display: inline-flex; align-items: center; gap: 8px;
  font: 700 14.5px/1 var(--sans); letter-spacing: .06em; text-transform: uppercase;
  padding: 16px 24px; border-radius: 11px; border: 2px solid transparent; cursor: pointer;
  transition: transform .12s ease, background-color .12s ease, box-shadow .12s ease;
}
.btn:hover { text-decoration: none; transform: translateY(-1px); }
.btn svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; }
.btn-red { background: var(--red); color: #fff; box-shadow: 0 10px 26px rgba(216,30,44,.34); }
.btn-red:hover { background: var(--red-dark); }
.btn-navy { background: var(--navy); color: #fff; box-shadow: 0 10px 26px rgba(13,33,73,.26); }
.btn-navy:hover { background: var(--navy-deep); }
.btn-ghost { border-color: rgba(255,255,255,.55); color: #fff; }
.btn-ghost:hover { background: rgba(255,255,255,.1); }
.p-gallery .btn-ghost, .p-product .btn-ghost, .prod .btn-ghost { border-color: var(--navy); color: var(--navy); }
.btn-link { color: #fff; padding: 16px 6px; text-decoration: underline; text-underline-offset: 4px; }
.prod .btn-link, .prose .btn-link { color: var(--red); }

/* ---------- hero ---------- */
.hero {
  position: relative; overflow: hidden; color: #fff;
  background:
    radial-gradient(900px 520px at 12% -20%, #22457f 0%, rgba(34,69,127,0) 62%),
    radial-gradient(700px 420px at 92% 8%, rgba(216,30,44,.34) 0%, rgba(216,30,44,0) 60%),
    linear-gradient(170deg, var(--navy) 0%, var(--navy-deep) 100%);
  padding: 34px 0 40px;
}
/* z-index 2 so the copy sits ABOVE .hero-scrim (z-index 1). Without it
 * .hero-row is position:relative/z-index:auto and the scrim - a later
 * sibling with a positive z-index - paints over the text: measured at 390,
 * white rendered as rgb(141,148,161), exactly 0.46-alpha scrim over white.
 * The text treatment below is also inside this layer, so it only works
 * once the layer is above the scrim. .first-screen > .wrap does not help:
 * this .wrap's parent is .hero-band, not .first-screen. */
.hero-row { position: relative; z-index: 2; }
/* The headline is the one piece of copy the brief fixes word for word, and
 * the mockup sets it as two lines: "BIG COLOR." over "HOMETOWN SPIRIT.".
 * Keeping that lockup is a sizing job, not a nowrap job - nowrap would push
 * the longer line off the side of a narrow phone. "HOMETOWN SPIRIT." is
 * about 9.3x the font size wide in a Helvetica-metric face, and a .wrap line
 * is viewport minus 36px of padding, so 9.3vw fits with a few percent in
 * hand at every phone width and still wraps safely rather than overflowing
 * if a visitor's font is wider than we assumed. */
.hero-h { margin: 0 0 14px; text-transform: uppercase; font-weight: 900; letter-spacing: -.03em; line-height: .94; font-size: clamp(28px, 9.3vw, 58px); }
.hero-h .hl { display: block; }
/* --red-lit, not --red, for the same reason .lun-r uses it, only harder:
 * --red #d81e2c has a relative luminance of 0.1571, so even over pure black
 * its best possible contrast is 3.84:1. It cannot reach 4.5:1 against ANY
 * ground, which means the old rule failed the gate everywhere - measured
 * 3.30:1 at 1440 and 1.61:1 at 390 on the live page. --red-lit #f9505c is
 * the same hue (355.7deg against 355.5deg) and clears it. See :root. */
.hero-h .red { color: var(--red-lit); }
.hero-h .blue { color: var(--blue); }

/* The hero copy is the only text on this page sitting on the photograph, and
 * with the bursts back in frame no scrim light enough to satisfy "this is too
 * dark" holds 4.5:1: the worst pixel under the headline at 1440 is a burst
 * core at source (624,206), rgb(255,232,235), and even a .62/.34/.12 scrim
 * leaves it at 2.44:1. So legibility is carried by the glyphs instead of by
 * darkening the whole picture - a ground attached to the text, not to the
 * band. Stacked 0-offset shadows, repeated because each pass multiplies the
 * remaining transmission; tighter radii on the lede because its strokes are
 * ~2px and a wide blur barely covers them. No offset, so it reads as weight
 * rather than as a drop shadow. */
.hero-h {
  /* The two 4px passes carry the narrow widths. The headline is clamped from
   * 58px down to 36px at 390, so its strokes thin to ~5px while the blur
   * radius does not, and a 9px blur stops being opaque over its own glyph:
   * measured at 390 with 9px as the tightest pass, "Color." came out at
   * 3.90:1 and "Spirit." at 2.88:1 against burst cores the halo was not
   * reaching. Tight radii hug a thin stroke; the wide ones do the visible
   * separation from the picture. */
  text-shadow:
    0 0 4px rgba(3,10,26,.96), 0 0 4px rgba(3,10,26,.96),
    0 0 9px rgba(3,10,26,.95), 0 0 9px rgba(3,10,26,.95),
    0 0 9px rgba(3,10,26,.92), 0 0 26px rgba(3,10,26,.85),
    0 0 54px rgba(3,10,26,.7);
}
.hero-lede {
  text-shadow:
    0 0 3px rgba(3,10,26,.96), 0 0 3px rgba(3,10,26,.96),
    0 0 3px rgba(3,10,26,.96), 0 0 10px rgba(3,10,26,.9),
    0 0 22px rgba(3,10,26,.75);
}
.hero-lede { color: #d9e4f6; font-size: 17px; max-width: 34em; margin-bottom: 22px; }
.hero-cta { margin: 0 0 26px; }

/* ---------- the first screen (home) ----------
 *
 * Neel: "I don't want the page to be where you are scrolling down for
 * everything." So the pitch and the category doors share ONE section that is
 * exactly the height of the first screen, with the two groups centred in it.
 * Fitting is then a layout invariant rather than a hope about font metrics:
 * the section cannot be taller than the viewport unless its content
 * overflows, and the content is sized so it does not. Verified by measuring
 * the doors' bottom edge against innerHeight at 1440, 820 and 390 - the three
 * numbers are in the dev log. The only chrome above it is the header: the
 * navy location strip that used to sit between them is gone.
 *
 * svh, not vh: on iOS Safari - which is what Neel tests on - vh is the TALL
 * viewport, the one that assumes the URL bar is hidden. Sizing to 100vh there
 * puts the bottom of the doors underneath the browser chrome on first load,
 * which is the exact bug this section exists to avoid. A vh line is kept
 * first as the fallback for anything too old to know svh. */
.first-screen {
  min-height: calc(100vh - var(--head-h) - var(--head-border));
  min-height: calc(100svh - var(--head-h) - var(--head-border));
  display: flex; flex-direction: column; justify-content: center;
  gap: clamp(14px, 2.6vh, 50px);
  padding: 20px 0 18px;
}
.first-screen > .wrap { position: relative; z-index: 2; }

/* The doors sit on the section ground, NOT on the photograph - the photo is
 * confined to .hero-band above them. That is what makes their contrast a
 * number we can guarantee rather than a property of whatever the picture
 * happens to be doing in that corner: the ground here runs between --navy and
 * --navy-deep and nothing lighter, so the worst case is --navy and every
 * colour on it can be checked once. The two radial tints that used to light
 * this gradient moved onto .hero-band, where they belong - they are the
 * photograph's fallback ground. */
.p-home .hero {
  padding-top: 0;
  background: linear-gradient(180deg, var(--navy) 0%, var(--navy-deep) 100%);
}

/* ---------- the hero band (home) ----------
 *
 * Edge to edge, roughly 300-420px, with the picture running the full width
 * including behind the headline.
 *
 * The photo is absolutely positioned rather than in flow, so the band's height
 * comes from its own min-height and its copy. The image cannot move anything
 * as it arrives - no CLS - even though its intrinsic 16:9 never matches the
 * band's shape at any width. */
.hero-band {
  position: relative; overflow: hidden;
  display: flex; flex-direction: column; justify-content: center;
  min-height: clamp(300px, 46vh, 420px); padding: 26px 0;
  background:
    radial-gradient(900px 520px at 12% -20%, #22457f 0%, rgba(34,69,127,0) 62%),
    radial-gradient(700px 420px at 92% 8%, rgba(216,30,44,.34) 0%, rgba(216,30,44,0) 60%),
    linear-gradient(170deg, var(--navy) 0%, var(--navy-deep) 100%);
}
.hero-photo-wrap { position: absolute; inset: 0; z-index: 0; display: block; }
/* The focal point. cover crops on one axis only, and which axis flips with
 * the viewport: a wide band is scaled to width and loses height, a narrow tall
 * one is scaled to height and loses width. So the vertical number governs at
 * desktop and the horizontal one at mobile, and they are set from measured
 * pixels, not taste. The photograph has two lit regions: a blue-and-red
 * cluster at source x0-400/y0-240 (12.3% of all lit pixels) and a much
 * larger one at x800-1280/y0-560 (67.7%), with a near-dead corridor at
 * x400-560 between them.
 *
 * 15% vertical: at 1440x900 the band is 1440x414, cover scales 1.125x and
 * crops 396px of height. 15% keeps source rows 52.8-420.8, which holds 88.1%
 * of the top-left cluster and 69.3% of the right one - the only anchor range
 * with both clusters in frame, and the brightest within it. The previous
 * 100% kept rows 352-720: 0% of the top-left cluster, 40% of the right, and
 * 39.2% of all lit pixels against 66.0% now. It was keeping the treeline,
 * which is a black silhouette, at the cost of half the fireworks.
 *
 * 100% horizontal: at 390x844 the band is 390x388, cover scales 0.5389x and
 * only 723.7 of 1280 source columns survive. Both clusters cannot fit - their
 * union needs the full width - so the larger one wins: 100% keeps columns
 * 556.3-1280, all of the right cluster and 87.3% of all lit pixels, against
 * 67.9% and 60.8% at the old 72%. There is no horizontal overflow at 1440,
 * 820 or 768 and no vertical overflow at 390, so each number is a no-op at
 * the widths the other one governs and one pair serves all four.
 *
 * Losing the treeline is intended. */
.hero-photo {
  display: block; width: 100%; height: 100%;
  object-fit: cover; object-position: 100% 15%;
}

/* NOTHING RENDERS THIS. A photograph the client supplied replaced the drawn
 * sky, so no page emits a canvas.skyfield any more. The rule is kept beside
 * src/views/skyfield.js, which is kept for the same reason: the decision that
 * replaced it is about one photograph and could be revisited, and a revert
 * that restores the markup should not also have to rediscover its CSS. Four
 * dead lines in a stylesheet cost a visitor nothing; a dead <script> would,
 * and there isn't one. */
.skyfield {
  position: absolute; inset: 0; z-index: 0; display: block;
  width: 100%; height: 100%; opacity: .9; pointer-events: none;
}
/* The readability budget, and the only thing standing between the headline and
 * a photograph whose content nobody controls. CSS rather than baked into the
 * image on purpose: it applies from first paint, before the photo has
 * arrived, so the headline is never briefly sitting on an unscrimmed ground.
 * Heavier at the bottom because that is where the lit horizon is. */
.hero-scrim {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(180deg, rgba(8,22,52,.34) 0%, rgba(8,22,52,.18) 46%, rgba(8,22,52,.30) 100%);
}

.p-home .hero-lede { margin-bottom: 18px; }
.p-home .hero-cta { margin: 0; }

/* "Light up the night" - the line Neel asked to make pop (#26352 "Make light
 * up the Night Pop. Keep the Red White Blue color theme").
 *
 * Mixed case, not the all-caps every other heading on the site uses, because
 * that is most of what makes it read as a different kind of line. Three words,
 * three colours, one each: "Light" red, "up the" white, "night" blue. A thin
 * rule runs out to each side and ends in a small burst.
 *
 * "Light" is --red-lit, not --red. --red on this ground measures 3.12:1 and
 * fails the 4.5:1 gate; --red-lit is the same hue and clears it. See :root. */
.lun {
  display: flex; align-items: center; gap: 10px;
  margin: 0 0 10px; font-weight: 900; letter-spacing: -.015em; line-height: 1.05;
  font-size: clamp(22px, 6.4vw, 34px);
}
.lun-t { white-space: nowrap; }
.lun-r { color: var(--red-lit); }
.lun-w { color: #fff; }
.lun-b { color: var(--blue); }
.lun-orn { flex: 1 1 0; display: flex; align-items: center; gap: 8px; min-width: 0; }
.lun-orn-end { justify-content: flex-end; }
.lun-rule {
  flex: 1 1 0; height: 2px; border-radius: 2px;
  background: linear-gradient(90deg, rgba(255,255,255,.12) 0%, rgba(255,255,255,.34) 100%);
}
.lun-orn-end .lun-rule { background: linear-gradient(90deg, rgba(255,255,255,.34) 0%, rgba(255,255,255,.12) 100%); }
.lun-burst { flex: 0 0 auto; width: clamp(16px, 4.6vw, 24px); height: clamp(16px, 4.6vw, 24px); }

/* ---------- the three large tiles ----------
 *
 * The three biggest categories by live count - the page asks the database
 * which three on every request and nothing here knows the answer. Each tile is
 * a different region of the same hero photograph.
 *
 * Three across at every width, never stacked: stacked they would cost more
 * than the one screen this page is allowed. */
.doors-big { display: grid; grid-template-columns: repeat(3, 1fr); gap: 7px; margin-bottom: 7px; }
.tile-big {
  position: relative; display: block; overflow: hidden; color: #fff;
  border: 1px solid var(--navy-line); border-radius: 11px;
  aspect-ratio: 16 / 9; background: var(--navy-deep);
  transition: border-color .14s ease, transform .14s ease;
}
.tile-big img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* The label sits on an opaque strip rather than straight on the picture, so
 * its contrast is a property of the strip and holds no matter what the
 * photograph is doing behind it. */
.tb-in {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 1;
  display: flex; flex-direction: column; gap: 1px;
  padding: 6px 9px 7px; background: rgba(5,14,34,.90);
}
.tb-name { font-size: 13px; font-weight: 800; letter-spacing: -.01em; line-height: 1.2; }
.tb-n { font-size: 10px; font-weight: 700; letter-spacing: .09em; text-transform: uppercase; color: #c3d3ec; }
.tile-big:hover { text-decoration: none; border-color: var(--red); transform: translateY(-2px); }
.tile-big:hover .tb-in { background: rgba(5,14,34,.96); }
.tile-big:hover .tb-n { color: #fff; }
.doors { display: grid; grid-template-columns: repeat(2, 1fr); gap: 7px; }
/* A door, not a chip and not a product tile. It is the primary navigation on
 * this page, so it gets a target big enough to be the obvious thing to press
 * and a count so it never promises products it cannot show. */
/* ONE red accent, and only one: the left bar. Not a bar and an underline and
 * a red count - the amendment is explicit that three reads as noise. The bar
 * is decorative, so it uses --red; the count is text, so it uses a tint that
 * passes the contrast gate. */
.door {
  display: flex; flex-direction: column; justify-content: center; color: #fff;
  background: rgba(255,255,255,.07); border: 1px solid var(--navy-line);
  border-left: 3px solid var(--red);
  border-radius: 11px; padding: 8px 11px;
  transition: background .14s ease, border-color .14s ease, transform .14s ease;
}
.door:hover { text-decoration: none; background: rgba(255,255,255,.14); border-color: var(--red); transform: translateY(-2px); }
.door-name { font-size: 14px; font-weight: 800; letter-spacing: -.01em; line-height: 1.2; }
.door-n { font-size: 10.5px; font-weight: 700; letter-spacing: .09em; text-transform: uppercase; color: #c3d3ec; margin-top: 2px; }
.door:hover .door-n { color: #fff; }
/* Focus has to be visible to somebody on a keyboard, not only to somebody on
 * a mouse. A white ring is the one treatment that cannot be lost against
 * either the navy ground or the photograph. */
.door:focus-visible, .tile-big:focus-visible {
  outline: 3px solid #fff; outline-offset: 3px; border-color: var(--red-lit);
}
/* The logo, large, on the right, sitting straight on the sky - no white card
 * and no panel.
 *
 * It is NOT logo.png. That file is black line art on a white field (measured:
 * 61.98% pure white, 7.60% pure black), so on a night sky it has two possible
 * fates and both are wrong: keyed transparent it is black-on-navy and
 * unreadable, left alone it IS the white card. hero-mark is built from
 * banner.png instead - the client's own dark-ground lockup of the same logo -
 * with its single light-grey column cropped off and its outer navy replicated
 * outward, then ramped to transparent across the replicated margin only.
 * Every original pixel is byte-identical at full alpha; the rectangle simply
 * dissolves into the sky. No artwork was recoloured, cropped into or
 * regenerated.
 *
 * Hidden below 960px: there is one column there, and the logo is already in
 * the header two inches above. Repeating it would cost about 150px of the one
 * screen this page is allowed. */
.hero-mark { display: none; }

/* ---------- bands ---------- */
.band { padding: 44px 0; }
.band-h { font-size: clamp(25px, 7vw, 34px); text-transform: uppercase; font-weight: 900; letter-spacing: -.02em; margin-bottom: 6px; }
.band-sub { color: #c3d3ec; margin-bottom: 26px; }
.band-h.dark { color: var(--navy); }
.band-sub.dark { color: var(--ink-soft); }
.band-cta { margin: 28px 0 0; text-align: center; }

.chips { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 4px; }
.chips a {
  display: inline-block; background: #fff; color: var(--navy);
  border: 1px solid var(--line); border-radius: 999px;
  padding: 9px 15px; font-size: 13.5px; font-weight: 700; letter-spacing: .02em;
}
.chips a:hover { text-decoration: none; border-color: var(--navy); }
.chips a.on { background: var(--navy); color: #fff; border-color: var(--navy); }

.latest { background: #fff; }

/* ---------- product tiles ---------- */
.tile-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(158px, 1fr)); gap: 14px; }
.tile {
  display: flex; flex-direction: column; color: var(--ink);
  background: #fff; border: 1px solid var(--line); border-radius: var(--r);
  overflow: hidden; transition: transform .14s ease, box-shadow .14s ease, border-color .14s ease;
}
.tile:hover { text-decoration: none; transform: translateY(-3px); box-shadow: var(--shadow); border-color: #c7d3e6; }
.tile-art {
  position: relative; display: grid; place-items: center; aspect-ratio: 1 / 1;
  background: linear-gradient(160deg, #13295a 0%, var(--navy-deep) 100%);
}
.tile-art.has-img { background: #fff; }
.tile-img { width: 100%; height: 100%; object-fit: contain; }
.tile-soon { display: grid; place-items: center; gap: 8px; text-align: center; padding: 14px; color: #8fa8ce; }
.tile-soon svg { width: 30px; height: 30px; fill: currentColor; opacity: .7; }
.tile-soon em { font-style: normal; font-size: 11.5px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; }
.chip-draft {
  position: absolute; left: 8px; top: 8px;
  background: #f5c243; color: #3a2a00; border-radius: 999px;
  padding: 3px 9px; font-size: 10.5px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
}
.chip-draft.big { position: static; display: inline-block; margin-bottom: 12px; padding: 6px 12px; font-size: 12px; }
.tile-body { display: flex; flex-direction: column; flex: 1; padding: 13px 14px 14px; }
.tile-cat { font-size: 10.5px; font-weight: 800; letter-spacing: .12em; text-transform: uppercase; color: var(--red); }
.tile-name { font-size: 16px; font-weight: 800; letter-spacing: -.01em; margin: 4px 0 2px; }
.tile-meta { font-size: 13px; color: var(--ink-soft); }
.tile-go { margin-top: auto; padding-top: 12px; display: inline-flex; align-items: center; gap: 5px; color: var(--navy); font-size: 12.5px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; }
.tile-go svg { width: 13px; height: 13px; fill: none; stroke: currentColor; stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round; }
.tile:hover .tile-go { color: var(--red); }

/* ---------- sub hero (gallery / about / contact / product) ---------- */
.sub-hero {
  position: relative; overflow: hidden; color: #fff; padding: 26px 0 32px;
  background:
    radial-gradient(700px 360px at 80% -30%, rgba(216,30,44,.3) 0%, rgba(216,30,44,0) 62%),
    linear-gradient(170deg, var(--navy) 0%, var(--navy-deep) 100%);
}
.sub-hero .wrap { position: relative; }
.sub-hero h1 { font-size: clamp(30px, 9vw, 46px); text-transform: uppercase; font-weight: 900; margin: 0 0 10px; }
.sub-lede { color: #d2deef; max-width: 46em; margin-bottom: 0; }
.crumbs { font-size: 12px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: #9fb8de; margin-bottom: 14px; }
.crumbs a { color: #cfdcf2; }
.crumbs span { padding: 0 6px; opacity: .5; }

/* The field takes a whole row on a phone so the placeholder is readable;
 * the button drops underneath it. Side by side below ~520px the input is
 * narrow enough that "Search name, brand or code" is cut off mid-word, which
 * reads like a broken control rather than a hint. */
.search { display: flex; flex-wrap: wrap; gap: 8px; margin: 22px 0 0; position: relative; }
.search-ic { position: absolute; left: 13px; top: 17px; width: 18px; height: 18px; fill: #7f93b5; }
.search input[type=search] {
  flex: 1 1 100%; min-width: 0; font: 16px/1 var(--sans); color: var(--ink);
  padding: 15px 14px 15px 40px; border: 2px solid transparent; border-radius: 11px; background: #fff;
}
@media (min-width: 520px) { .search input[type=search] { flex: 1 1 220px; } }
.search input[type=search]:focus { border-color: var(--blue); outline: none; }
.search .clear { align-self: center; color: #cfdcf2; font-size: 13px; text-decoration: underline; }
.count { color: var(--ink-soft); font-size: 13.5px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; margin: 22px 0 14px; }
.gallery { background: #fff; padding-top: 28px; }
.empty { text-align: center; padding: 40px 0 20px; }
.empty h2 { color: var(--navy); }

/* ---------- product detail ---------- */
.prod { position: relative; overflow: hidden; background: var(--cream); padding: 22px 0 40px; }
.prod > .wrap { position: relative; }
.prod .crumbs { color: #5d6e8c; }
.prod .crumbs a { color: var(--navy); }
.prod-row { display: grid; gap: 22px; }
.shot { margin: 0; background: #fff; border: 1px solid var(--line); border-radius: var(--r); aspect-ratio: 1 / 1; display: grid; place-items: center; overflow: hidden; }
.shot img { width: 100%; height: 100%; object-fit: contain; }
.shot-soon { background: linear-gradient(160deg, #13295a 0%, var(--navy-deep) 100%); border-color: var(--navy-deep); }
.shot-more { display: grid; grid-template-columns: repeat(auto-fill, minmax(72px, 1fr)); gap: 8px; margin-top: 8px; }
.shot-more img { background: #fff; border: 1px solid var(--line); border-radius: 9px; aspect-ratio: 1/1; object-fit: contain; }
.prod-info h1 { font-size: clamp(27px, 7.5vw, 40px); color: var(--navy); text-transform: uppercase; font-weight: 900; }
.prod-cat { font-size: 11.5px; font-weight: 800; letter-spacing: .14em; text-transform: uppercase; color: var(--red); margin-bottom: 6px; }
.prod-facts { display: flex; flex-wrap: wrap; gap: 10px; margin: 0 0 18px; padding: 0; }
.prod-facts div { background: #fff; border: 1px solid var(--line); border-radius: 11px; padding: 10px 14px; min-width: 104px; }
.prod-facts dt { font-size: 10.5px; font-weight: 800; letter-spacing: .12em; text-transform: uppercase; color: var(--ink-soft); }
.prod-facts dd { margin: 3px 0 0; font-size: 16px; font-weight: 700; color: var(--navy); }
.note { background: #fff7e3; border-left: 4px solid #f5c243; border-radius: 8px; padding: 12px 14px; font-size: 14.5px; color: #4a3a12; }
.prod-desc { font-size: 17px; }
.spec { width: 100%; border-collapse: collapse; margin: 18px 0; background: #fff; border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
.spec th, .spec td { text-align: left; padding: 12px 14px; border-bottom: 1px solid var(--line); font-size: 15px; }
.spec tr:last-child th, .spec tr:last-child td { border-bottom: 0; }
.spec th { width: 42%; color: var(--ink-soft); font-size: 12px; font-weight: 800; letter-spacing: .09em; text-transform: uppercase; }
.vid { position: relative; padding-top: 56.25%; margin: 18px 0; border-radius: var(--r); overflow: hidden; background: #000; }
.vid iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.prod-back { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-top: 22px; }

/* ---------- about / prose ---------- */
.prose-band { background: #fff; }
.prose { max-width: 44em; }
.prose p { font-size: 17.5px; color: #26324a; }
.prose p strong { color: var(--navy); }
.prose-cta { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-top: 26px; }

/* ---------- contact ---------- */
.contact-band { background: var(--cream); }
.contact-row { display: grid; gap: 26px; }
.contact-side h2, .contact-main h2 { color: var(--navy); font-size: 21px; text-transform: uppercase; }
.contact-side { color: #3c4a63; }
.contact-line { font-weight: 700; color: var(--navy); }
.form { display: grid; gap: 4px; background: #fff; border: 1px solid var(--line); border-radius: var(--r); padding: 20px; }
.form label { font-size: 12px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-soft); margin-top: 12px; }
.form label .opt { font-weight: 600; letter-spacing: .02em; text-transform: none; opacity: .7; }
.form input, .form textarea, .form select {
  font: 16px/1.5 var(--sans); color: var(--ink);
  padding: 12px 13px; border: 1px solid #c8d3e4; border-radius: 10px; background: #fff; width: 100%;
}
.form input:focus, .form textarea:focus, .form select:focus { border-color: var(--blue); outline: none; box-shadow: 0 0 0 3px rgba(82,168,255,.2); }
.form textarea { resize: vertical; }
.form .btn { margin-top: 20px; justify-self: start; }
.hp { position: absolute; left: -9999px; }
.err { background: #fdeaec; border-left: 4px solid var(--red); border-radius: 8px; padding: 12px 14px; color: #7d1420; font-weight: 600; }
.ok { background: #fff; border: 1px solid var(--line); border-left: 4px solid #2e9e5b; border-radius: var(--r); padding: 22px; }
.ok h2 { color: var(--navy); }

/* ---------- closing band ---------- */
.closing {
  position: relative; overflow: hidden; color: #fff; padding: 48px 0;
  background:
    radial-gradient(640px 320px at 18% 120%, rgba(82,168,255,.22) 0%, rgba(82,168,255,0) 60%),
    radial-gradient(640px 320px at 86% -20%, rgba(216,30,44,.3) 0%, rgba(216,30,44,0) 60%),
    linear-gradient(160deg, var(--navy-deep) 0%, var(--navy) 100%);
}
.closing-in { position: relative; max-width: 40em; }
.closing h2 { font-size: clamp(27px, 8vw, 40px); text-transform: uppercase; font-weight: 900; }
.closing p { color: #d5e1f3; }
.closing .btn-link { color: #cfdcf2; }
.closing-cta { margin-top: 22px; }

/* ---------- footer ---------- */
.site-foot { background: var(--navy-deep); color: #b9c9e4; padding: 40px 0 30px; border-top: 4px solid var(--red); }
.foot-in { text-align: center; }
.foot-mark { width: min(300px, 74vw); height: auto; border-radius: 12px; clip-path: inset(0 2px 0 0); }
.foot-tag { margin: 18px 0 14px; color: #fff; font-size: 13px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; }
.foot-nav { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px 18px; margin-bottom: 18px; }
.foot-nav a { color: #cfdcf2; font-size: 13.5px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; }
.foot-note { font-size: 13px; color: #8fa8ce; max-width: 34em; margin: 0 auto 10px; }
.foot-fine { font-size: 12px; color: #6f86ab; margin: 0; }

/* ---------- 480px up ---------- */
@media (min-width: 480px) {
  .tile-grid { grid-template-columns: repeat(auto-fill, minmax(176px, 1fr)); gap: 16px; }
  .doors { grid-template-columns: repeat(3, 1fr); gap: 8px; }
  .doors-big { gap: 8px; margin-bottom: 8px; }
}

/* ---------- 700px up ---------- */
@media (min-width: 700px) {
  :root { --head-h: 76px; }
  .logo { height: 46px; }
  .nav-toggle { display: none; }
  .site-nav { display: flex; align-items: center; gap: 4px; }
  .site-nav a { border: 0; padding: 10px 12px; border-radius: 8px; font-size: 13.5px; }
  .site-nav a:hover { background: var(--cream); text-decoration: none; }
  .site-nav a.on { background: var(--navy); color: #fff; }
  .hero { padding: 56px 0 60px; }
  .first-screen { padding: 28px 0 26px; }
  .doors { grid-template-columns: repeat(4, 1fr); gap: 10px; }
  .doors-big { gap: 10px; margin-bottom: 10px; }
  .door { padding: 12px 14px; border-radius: 12px; }
  .door-name { font-size: 16px; }
  .door-n { font-size: 11px; }
  .tile-big { border-radius: 12px; }
  .tb-in { padding: 8px 12px 9px; }
  .tb-name { font-size: 15px; }
  .tb-n { font-size: 11px; }
  .lun { margin-bottom: 13px; gap: 14px; }
  /* Single-column hero up to 959px: the full .wrap line is available. */
  .hero-h { font-size: clamp(52px, 7.6vw, 76px); }
  .hero-lede { font-size: 18px; }
  .band { padding: 60px 0; }
  .contact-row { grid-template-columns: 1fr 1.35fr; gap: 40px; }
  .prod-row { grid-template-columns: 1fr 1.2fr; gap: 36px; align-items: start; }
  .prod { padding: 28px 0 56px; }
  .sub-hero { padding: 34px 0 44px; }
  .closing { padding: 72px 0; }
  .form { padding: 26px; }
}

/* ---------- 960px up ---------- */
@media (min-width: 960px) {
  .hero-row { display: grid; grid-template-columns: 1.02fr .98fr; gap: 40px; align-items: center; }
  /* Three big tiles in a row, then the remaining seven in a single row under
   * them. Seven, not ten: three of the ten are the tiles above. Nothing here
   * is written as a number of categories - if a category is added or emptied
   * the grid just divides differently. */
  .doors { grid-template-columns: repeat(7, 1fr); gap: 12px; }
  .doors-big { gap: 12px; margin-bottom: 12px; }
  .door-name { font-size: 15px; }
  .p-home .hero-mark {
    display: block; width: 100%; max-width: 430px; margin-left: auto;
    aspect-ratio: 886 / 597;
    background-position: center; background-repeat: no-repeat; background-size: contain;
    /* Two declarations, not one: a browser that does not understand
     * image-set() keeps the PNG, and one that does takes the WebP, which is
     * 36KB against 398KB. Nothing below 960px fetches either - a background
     * behind an unmatched media query is never requested, which an <img>
     * inside display:none would be. */
    background-image: url("/assets/img/hero-mark.png?v=5");
    background-image: image-set(url("/assets/img/hero-mark.webp?v=5") type("image/webp"), url("/assets/img/hero-mark.png?v=5") type("image/png"));
  }
  /* Left-weighted scrim at this width: the copy is in the left column and the
   * busy half of the photograph is the right one, so the darkening is heaviest
   * where the headline is and lightest where the bursts are. */
  .hero-scrim { background: linear-gradient(100deg, rgba(8,22,52,.30) 0%, rgba(8,22,52,.18) 46%, rgba(8,22,52,.08) 100%); }
  /* Two columns now, so the headline is sized against its own column (~51%
   * of a 1180px wrap = 563px at the cap), not against the viewport. */
  .hero-h { font-size: clamp(44px, 3.9vw, 56px); }
  .hero { padding: 72px 0 80px; }
  .first-screen { padding: 30px 0 28px; }
  .hero-cta { margin-bottom: 0; }
  .prod-row { grid-template-columns: 1fr 1.25fr; gap: 48px; }
  .tile-grid { grid-template-columns: repeat(auto-fill, minmax(214px, 1fr)); gap: 20px; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .btn, .tile, .door, .tile-big { transition: none; }
}
