/* ==========================================================================
   Digital Home Cinema — Kollam
   assets/css/site.css

   Direction: warm paper base, red accent, one typeface (Archivo) worked at
   two very different widths. Dark bands used deliberately where cinema
   atmosphere earns it, not as an overall theme.

   Deliberately unlike homeconnectcinemas.com, who are cyan-on-charcoal,
   centre-aligned, with casual script headings and a static grey logo row.

   Contrast, measured rather than assumed:
     red   #D8232A on paper #FBF9F5  = 4.76:1   ok for text
     red   #D8232A on white          = 5.01:1   ok
     white on red                    = 5.01:1   ok for buttons
     ink   #17161A on paper          = 17.1:1
     ink-2 #3E3B38 on paper          = 10.6:1
     green #1D7A46 on paper          = 5.09:1
   ========================================================================== */

/* --- 0. fonts ------------------------------------------------------------

   Self-hosted in assets/fonts/. The third-party Google Fonts stylesheet was
   render-blocking, and visitors' browsers should not have to phone Google to
   paint text. unicode-range mirrors Google's own subsets, so the Malayalam
   files download only when Malayalam text is present on the page.

   The three fallback faces are metric-matched to the webfonts (computed from
   the font tables with fontTools): size-adjust scales the fallback to the
   webfont's cap height, the overrides hand it the webfont's ascent/descent.
   The swap is metric-invisible — no layout shift while fonts arrive. */

@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/plex-sans.woff2") format("woff2-variations");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Spectral";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/spectral-400.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Spectral";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("../fonts/spectral-500.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Spectral";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("../fonts/spectral-600.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Spectral";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/spectral-400i.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Manjari";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/manjari-400-mal.woff2") format("woff2");
  unicode-range: U+0307, U+0323, U+0951-0952, U+0964-0965, U+0D00-0D7F, U+1CDA, U+1CF2, U+200C-200D, U+20B9, U+25CC, U+A830-A832;
}
@font-face {
  font-family: "Manjari";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/manjari-400.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Manjari";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("../fonts/manjari-700-mal.woff2") format("woff2");
  unicode-range: U+0307, U+0323, U+0951-0952, U+0964-0965, U+0D00-0D7F, U+1CDA, U+1CF2, U+200C-200D, U+20B9, U+25CC, U+A830-A832;
}
@font-face {
  font-family: "Manjari";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("../fonts/manjari-700.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Plex Fallback";
  src: local("Segoe UI");
  size-adjust: 99.7%;
  ascent-override: 102.8%;
  descent-override: 27.6%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Spectral Fallback";
  src: local("Georgia");
  size-adjust: 95.3%;
  ascent-override: 111.2%;
  descent-override: 48.6%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Manjari Fallback";
  src: local("Nirmala UI");
  size-adjust: 96.6%;
  ascent-override: 75.8%;
  descent-override: 37.9%;
  line-gap-override: 0%;
}

/* --- 1. tokens ----------------------------------------------------------- */

:root {
  --paper:   #FBF9F5;
  --white:   #FFFFFF;
  --shade:   #F1EDE6;
  --line:    #E4DED4;
  --line-2:  #CEC6B9;

  --ink:     #17161A;
  --ink-2:   #3E3B38;
  --ink-3:   #6E6862;

  --black:   #111114;
  --black-2: #1C1C20;
  --black-3: #2A2A2F;

  --red:      #D8232A;
  --red-dk:   #A8151B;
  --red-wash: #FDF1F0;

  --green:   #1D7A46;
  --gold:    #C9971F;

  /* Type.

     A committed serif-over-sans pairing, chosen directly against the
     documented 2026 AI defaults. The tells, per sailop.com's forensic list
     ("AI Typography Tells", June 2026) and aiskill.market ("Banning Inter"):
     Inter, Geist, Roboto, Space Grotesk, Open Sans / Lato / Nunito, the
     Manrope–DM Sans–Plus Jakarta–Sora grotesque pool, and Poppins with
     Montserrat — named there as "the geometric template defaults". Ultra-thin
     display weights are a second tell (and an accessibility problem), so the
     headings here sit at real text weights.

     The human move the same sources name: a serif display over a sans body.
     Spectral (Production Type, drawn for screens, with true italics) carries
     the headings. IBM Plex Sans — called out as a workhorse "with no AI
     cohort", and fitting for a shop that sells precision equipment — carries
     body and UI. Manjari stays for Malayalam. */
  --font:    "IBM Plex Sans", "Plex Fallback", "Segoe UI", sans-serif;
  --font-d:  "Spectral", "Spectral Fallback", Georgia, serif;
  --font-ml: "Manjari", "Manjari Fallback", "Nirmala UI", sans-serif;

  --gut:   clamp(1.15rem, 4vw, 2.5rem);
  --shell: 75rem;
  /* Was clamp(3.25rem, 6.5vw, 6rem): 96px top and bottom on twelve sections
     put roughly 190px between every block, which is the "premium spacing" look
     that generated sites default to. */
  --sec:   clamp(2.25rem, 4.2vw, 3.75rem);

  /* Radius scale rather than one global value. Applying a single radius to
     every surface flattens hierarchy and is itself a giveaway, so small
     controls, cards and large media each get their own. */
  --r-sm:   6px;    /* tags, badges, chips */
  --r:     11px;    /* cards, panels, inputs */
  --r-lg:  16px;    /* video frame, map, large media */
  --r-pill: 999px;  /* phone and WhatsApp actions */

  --fast: 150ms;
  --mid:  240ms;
  --ease: cubic-bezier(0.2, 0.7, 0.2, 1);
}

/* --- 2. reset ------------------------------------------------------------ */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 6rem;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink-2);
  font-family: var(--font);
  font-size: 1rem;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img, svg, video { display: block; max-width: 100%; height: auto; }

/* The rule above is author-level, so it beats the browser's own
   [hidden] { display: none } and leaves hidden SVGs visible. Put that back. */
[hidden] { display: none !important; }
button, input, select, textarea { font: inherit; color: inherit; }
h1, h2, h3, h4, h5, p, ul, ol, figure, blockquote, dl, dd { margin: 0; }
ul, ol { padding: 0; list-style: none; }
a { color: inherit; }

:focus-visible { outline: 3px solid var(--red); outline-offset: 2px; }
.dark :focus-visible { outline-color: #FF8E82; }
::selection { background: var(--red); color: #fff; }

/* --- 3. layout ----------------------------------------------------------- */

.shell { width: 100%; max-width: var(--shell); margin-inline: auto; padding-inline: var(--gut); }
.shell--wide { max-width: 84rem; }

/* Escapes the shell. Every block on the site sat inside the same 75rem column,
   which is a large part of why the page rhythm became predictable. This lets one
   or two things run edge to edge. Used sparingly and on purpose. */
.bleed { width: 100%; }
.bleed > img { display: block; width: 100%; height: clamp(15rem, 34vw, 26rem); object-fit: cover; }
.bleed figcaption {
  max-width: var(--shell); margin-inline: auto; padding: 0.7rem var(--gut) 0;
  font-size: 0.8125rem; color: var(--ink-3);
}
/* Dark band so the photograph is the only thing in view, and the section either
   side of it does not have to change colour to make the break register. */
.bleed--dark { background: var(--black); }
.bleed--dark figcaption { color: #8B857F; }

.section { padding-block: var(--sec); }
/* Holds one row of category links. Was up to 48px top and bottom, which left a
   near-empty band across the page for a single line of small controls. */
.section--tight { padding-block: clamp(0.9rem, 1.4vw, 1.15rem); }

/* Hairline between sections instead of a background colour change. The page
   used to alternate dark / beige / white down its whole length, which is the
   most recognisable generated-landing-page structure there is. A rule does the
   same separating job without restating the brand palette every 400px. */
.section--sep { border-top: 1px solid var(--line); }
.section--sep + .section--sep { border-top: 1px solid var(--line); }

.bg-white { background: var(--white); }
.bg-shade { background: var(--shade); }

/* Dark band. Used three or four times on the site, never as the default. */
.dark { background: var(--black); color: #CFCAC3; }
.dark h1, .dark h2, .dark h3, .dark h4, .dark b, .dark strong { color: #fff; }
.dark .lead { color: #ADA8A1; }
.dark .small { color: #8B857F; }

.rule { height: 1px; background: var(--line); border: 0; }

/* --- 4. type ------------------------------------------------------------- */

/* Headlines. Sentence case at a normal shop size. These were uppercase, 86%
   width, weight 800 and up to 4.75rem, which is the stock AI-landing-page hero
   and the first thing people read as generated. A dealer's own site sets a
   heading a bit above body size and moves on. */
.hd {
  font-family: var(--font-d);
  font-weight: 400;
  color: var(--ink);
  line-height: 1.12;
  letter-spacing: -0.005em;
  text-wrap: balance;
}
.dark .hd { color: #fff; }
.hd .red { color: var(--red); }
.dark .hd .red { color: #FF6B5E; }

h1.hd { font-size: clamp(1.85rem, 3.4vw, 2.6rem); line-height: 1.08; letter-spacing: -0.01em; }
h2.hd { font-size: clamp(1.3rem, 2.1vw, 1.75rem); letter-spacing: -0.005em; }
h3.hd { font-size: clamp(1.05rem, 1.5vw, 1.2rem); line-height: 1.25; letter-spacing: 0; font-weight: 600; }

/* Card and product titles read better at normal width, sentence case. */
.tt {
  font-weight: 600;
  font-stretch: 100%;
  text-transform: none;
  letter-spacing: -0.005em;
  line-height: 1.3;
  color: var(--ink);
  font-size: 1.0625rem;
}
.dark .tt { color: #fff; }

/* Small label above a heading, set as a quiet uppercase eyebrow with wide
   tracking — the convention on the premium dealer sites this now matches. */
.label {
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--red);
  margin-bottom: 0.6rem;
}
.dark .label { color: #FF6B5E; }

.lead { font-size: clamp(1.0625rem, 0.99rem + 0.35vw, 1.1875rem); line-height: 1.6; color: var(--ink-2); max-width: 56ch; text-wrap: balance; }
.prose { max-width: 66ch; }
.prose p + p { margin-top: 1.05em; }
.prose strong { color: var(--ink); font-weight: 700; }
.dark .prose strong { color: #fff; }
.small { font-size: 0.875rem; line-height: 1.6; color: var(--ink-3); }

/* Malayalam gets a real Malayalam face, and runs a touch larger and looser
   because the script needs the extra leading to stay readable. */
/* Malayalam appears twice on the whole site, so when it does appear it is
   sized to be read rather than tucked away as decoration. Manjari needs more
   leading than a Latin face at the same size. */
.ml {
  font-family: var(--font-ml);
  font-size: clamp(1.125rem, 1.05rem + 0.35vw, 1.375rem);
  line-height: 1.75;
  font-weight: 400;
  margin-top: 1.5rem;
  color: var(--brass, #E9B949);
}
.hero .ml { color: #E4B34A; }
.dark .ml { color: #E4B34A; }

.link { color: var(--red); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px; }
.link:hover { color: var(--red-dk); }
.dark .link { color: #FF8E82; }

/* Figures that stack or get compared (spec rows, prices, phone numbers, the
   room diagram) use tabular numerals so columns stop wobbling. */
.prod dl, .prod__price, .tier__p, .tier__ask, .facts dd, .row dd, .d-t, .d-t2 {
  font-variant-numeric: tabular-nums;
}

/* Widow/orphan control for running text; quote marks hang outside the text
   edge where the engine supports it. Both are no-ops where unsupported. */
p, li, dd { text-wrap: pretty; }
.quote p, .prose { hanging-punctuation: first last; }

/* Journal dates in true small caps (Spectral and Plex both ship smcp). */
.post time { font-variant-caps: small-caps; letter-spacing: 0.04em; }

/* --- 5. section heading -------------------------------------------------- */

.head { display: grid; gap: 0.9rem 3rem; margin-bottom: clamp(1.6rem, 3.2vw, 2.5rem); }
@media (min-width: 58rem) {
  /* Bottom-aligned so the small label sits level with the top of the lead
     paragraph and the two columns finish on the same line. */
  .head--2 { grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr); align-items: end; }

  /* Guard. Bottom alignment only reads correctly when the left column carries a
     label above the heading, which makes it roughly as tall as the paragraph
     beside it. Without one, a single-line heading drops to the bottom of the row
     and appears to hang below its own paragraph. Top-align that case instead. */
  .head--2:not(:has(.label)) { align-items: start; }
}

/* --- 6. buttons ---------------------------------------------------------- */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem;
  padding: 0.9rem 1.6rem;
  background: var(--red); color: #fff;
  border: 2px solid var(--red);
  /* Slightly rounded, not a pill. This was 999px, which made every action on
     the page a capsule and is a large part of why the layout read as a
     template. --r-pill is now kept for the floating WhatsApp action and the
     video unmute chip, where a capsule is the normal convention. */
  border-radius: var(--r-sm);
  font-size: 0.9375rem; font-weight: 600; line-height: 1.2;
  text-decoration: none; cursor: pointer;
  transition: background-color var(--mid) var(--ease), border-color var(--mid) var(--ease), color var(--mid) var(--ease);
}
.btn:hover { background: var(--red-dk); border-color: var(--red-dk); }
.btn svg { width: 1.125rem; height: 1.125rem; flex: none; }

.btn--line { background: transparent; color: var(--ink); border-color: var(--line-2); }
.btn--line:hover { background: var(--ink); border-color: var(--ink); color: #fff; }
.dark .btn--line { color: #fff; border-color: #45454B; }
.dark .btn--line:hover { background: #fff; border-color: #fff; color: var(--ink); }

.btn--wa { background: var(--green); border-color: var(--green); }
.btn--wa:hover { background: #145C34; border-color: #145C34; }

.btn--sm { padding: 0.55rem 0.95rem; font-size: 0.875rem; }
.btns { display: flex; flex-wrap: wrap; gap: 0.6rem; }

.more { display: inline-flex; align-items: center; gap: 0.35rem; font-size: 0.9375rem; font-weight: 600; color: var(--red); text-decoration: none; cursor: pointer; }
.more svg { width: 1rem; height: 1rem; transition: transform var(--mid) var(--ease); }
.more:hover svg { transform: translateX(3px); }
.dark .more { color: #FF8E82; }

/* --- 7. utility bar ------------------------------------------------------ */

.topbar { background: var(--black); color: #9D9891; font-size: 0.8125rem; }
.topbar__in { display: flex; align-items: center; justify-content: space-between; gap: 1rem; min-height: 2.4rem; padding-block: 0.35rem; }
.topbar__l { display: flex; align-items: center; gap: 0.5rem; }
.dot { width: 6px; height: 6px; border-radius: 50%; background: #35C46B; flex: none; }
.topbar__r { display: flex; align-items: center; gap: 1.1rem; }
.topbar a { color: #fff; font-weight: 700; text-decoration: none; }
.topbar a:hover { color: #FF8E82; }
@media (max-width: 44rem) {
  .topbar__in { justify-content: center; }
  .topbar__l { display: none; }
}

/* --- 8. header ----------------------------------------------------------- */

.skip { position: absolute; left: -9999px; top: 0; z-index: 200; padding: 0.75rem 1.25rem; background: var(--red); color: #fff; font-weight: 700; }
.skip:focus { left: 0.5rem; top: 0.5rem; }

.header { position: sticky; top: 0; z-index: 100; background: var(--white); border-bottom: 1px solid var(--line); transition: box-shadow var(--mid) var(--ease); }
/* The JS sets data-scrolled after 24px of travel; this is the stylesheet half
   of that contract. A soft lift, not a colour change. */
.header[data-scrolled="true"] { box-shadow: 0 14px 34px -22px rgba(23,22,26,0.4); }
.header__in { display: flex; align-items: center; justify-content: space-between; gap: 1.25rem; min-height: 4.25rem; padding-block: 0.55rem; }
@media (min-width: 62rem) { .header__in { min-height: 4.75rem; } }

.logo { display: flex; align-items: center; gap: 0.6rem; text-decoration: none; flex: none; }
/* Logo is an external file so the real artwork can replace it without
   touching markup. Works on light and dark because the SVG is transparent. */
.logo svg, .logo img { width: 2.25rem; height: 2.25rem; flex: none; }

/* Sound format capability line.

   These are set as text, not logos, and that is deliberate. Dolby state that
   most third-party use of their trademarks and logos requires a licence
   agreement; DTS:X and the DTS:X logo are registered marks of DTS, Inc. Naming
   a format in words is the accepted way to state compatibility without a
   licence, and an approximated double-D drawn from memory would look wrong
   anyway.

   If the official asset pack arrives from the distributor, drop the SVGs into
   assets/img/formats/ and swap each <b> for an <img>; .formats img is ready. */
.formats {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 0.5rem 1.15rem;
  padding-top: 0.85rem;
  border-top: 1px solid var(--line-2);
}
.dark .formats { border-top-color: #3A3A40; }

.formats__lead {
  font-size: 0.75rem; font-weight: 700; color: var(--ink-3);
  margin-right: 0.15rem;
}
.dark .formats__lead { color: #8B857F; }

.formats b {
  font-weight: 800; font-stretch: 88%;
  font-size: 0.8125rem; letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--ink);
}
.dark .formats b { color: #fff; }
.formats b sup { font-size: 0.62em; font-weight: 500; letter-spacing: 0; top: -0.5em; }

/* Hairline between each mark instead of a box around each one. */
.formats b + b { position: relative; padding-left: 1.15rem; }
.formats b + b::before {
  content: ""; position: absolute; left: 0; top: 0.1em; bottom: 0.1em;
  width: 1px; background: var(--line-2);
}
.dark .formats b + b::before { background: #3A3A40; }

.formats img { max-height: 1.5rem; width: auto; }

/* Trademark attribution. Professional AV sites carry this, and it reads as
   more credible than omitting it. */
.tm { font-size: 0.6875rem; line-height: 1.6; color: #77726C; max-width: 78ch; }
.logo__t { font-weight: 800; font-stretch: 84%; text-transform: uppercase; font-size: 0.9375rem; line-height: 1.05; color: var(--ink); }
.logo__t span { display: block; font-weight: 500; font-stretch: 100%; font-size: 0.625rem; letter-spacing: 0.12em; color: var(--ink-3); }
.dark .logo__t, .footer .logo__t { color: #fff; }
.footer .logo__t span { color: #8B857F; }
@media (max-width: 30rem) { .logo__t { font-size: 0.8125rem; } }

.nav { display: none; }
@media (min-width: 64rem) { .nav { display: flex; align-items: center; gap: clamp(0.95rem, 1.6vw, 1.6rem); } }
.nav a {
  position: relative;
  font-size: 0.9375rem; font-weight: 500; color: var(--ink-2); text-decoration: none;
  padding-block: 0.35rem; border-bottom: 2px solid transparent; cursor: pointer;
  transition: color var(--fast) var(--ease), border-color var(--fast) var(--ease);
}
/* Underline draws in from the left on hover; the current page keeps its
   static red rule and never animates. */
.nav a::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -2px; height: 2px;
  background: currentColor;
  transform: scaleX(0); transform-origin: left center;
  transition: transform 220ms var(--ease);
}
.nav a:hover { color: var(--ink); }
.nav a:hover::after { transform: scaleX(1); }
.nav a[aria-current="page"] { color: var(--red); font-weight: 700; border-bottom-color: var(--red); }
.nav a[aria-current="page"]::after { display: none; }

.header__cta { display: none; }
@media (min-width: 64rem) { .header__cta { display: inline-flex; } }

.burger { display: inline-flex; flex-direction: column; justify-content: center; gap: 5px; width: 2.75rem; height: 2.75rem; padding: 0 0.65rem; background: var(--white); border: 1px solid var(--line-2); border-radius: var(--r); cursor: pointer; }
.burger span { display: block; height: 2px; background: var(--ink); transition: transform var(--mid) var(--ease); }
.burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(3.5px) rotate(45deg); }
.burger[aria-expanded="true"] span:nth-child(2) { transform: translateY(-3.5px) rotate(-45deg); }
@media (min-width: 64rem) { .burger { display: none; } }

.drawer { display: grid; grid-template-rows: 0fr; overflow: hidden; background: var(--white); transition: grid-template-rows var(--mid) var(--ease); }
.drawer[data-open="true"] { grid-template-rows: 1fr; border-top: 1px solid var(--line); }
.drawer__in { min-height: 0; overflow: hidden; }
.drawer ul { padding-block: 0.4rem 1.15rem; }
.drawer li a { display: block; padding: 0.8rem 0; border-bottom: 1px solid var(--line); font-size: 1.0625rem; font-weight: 500; color: var(--ink); text-decoration: none; }
.drawer li a[aria-current="page"] { color: var(--red); font-weight: 700; }
.drawer .btns { margin-top: 1.1rem; padding-bottom: 0.25rem; }
.drawer .btn { flex: 1 1 9rem; }
@media (min-width: 64rem) { .drawer { display: none; } }

/* No-JS: the burger cannot open anything, so the drawer ships open and the
   button hides. Full navigation stays reachable. */
html:not(.js) .burger { display: none; }
html:not(.js) .drawer { grid-template-rows: 1fr; border-top: 1px solid var(--line); }
@media (min-width: 64rem) { html:not(.js) .drawer { display: none; } }
html:not(.js) .unmute { display: none; }

/* --- 9. hero ------------------------------------------------------------- */

/* No divider rule. Sections separate by background step and spacing instead,
   which avoids the ruled-lattice look. */
.hero {
  position: relative;
  background: var(--black);
  color: #CFCAC3;
  isolation: isolate;
}
/* Soft off-centre glow, like light coming off a screen in a dark room. Sits
   above the photograph and below the text. */
.hero::before {
  content: "";
  position: absolute; inset: 0; z-index: -1;
  background:
    radial-gradient(70% 90% at 88% 18%, rgba(216,35,42,0.18) 0%, rgba(216,35,42,0) 62%),
    radial-gradient(55% 70% at 72% 62%, rgba(120,130,170,0.12) 0%, rgba(17,17,20,0) 70%);
  pointer-events: none;
}

/* Background photograph.

   Every available image is a social creative with promo text burnt into it,
   and cropping to a clean region was not possible — two attempts hit text in
   different places. The fix is opacity: at this level the photograph reads as
   depth and texture, and none of the overlaid text is legible. Verified on a
   render rather than assumed.

   When a clean photograph exists, drop it in at assets/img/hero.jpg and raise
   --hero-photo-opacity toward 0.55. */
/* Background photograph. A clean, licensed image, so no blur or opacity trick
   is needed — just a scrim heavy enough on the left to hold text contrast. */
.hero__bg { position: absolute; inset: 0; z-index: -2; overflow: hidden; background: var(--black); }
.hero__bg img {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: 50% 52%;
}
.hero__bg::after {
  content: "";
  position: absolute; inset: 0;
  background:
    linear-gradient(100deg, rgba(14,14,17,0.93) 0%, rgba(14,14,17,0.84) 40%, rgba(14,14,17,0.52) 74%, rgba(14,14,17,0.42) 100%),
    linear-gradient(0deg, rgba(14,14,17,0.62) 0%, rgba(14,14,17,0.06) 58%);
}

/* Section photograph, used part-way down a page beside body copy. */
.figimg { margin: 0; }
.figimg .shot { border-radius: var(--r); }
.figimg figcaption { margin-top: 0.6rem; font-size: 0.8125rem; color: var(--ink-3); }
.dark .figimg figcaption { color: #8B857F; }

/* Image credit line. Required by the CC BY licences these photographs carry. */
.credits { font-size: 0.6875rem; line-height: 1.7; color: #77726C; max-width: 90ch; }
.credits a { color: #9D9891; text-decoration: underline; text-underline-offset: 2px; }
.credits a:hover { color: #fff; }
.hero .hd { color: #fff; }
.hero .hd .red { color: #FF6B5E; }
.hero .lead { color: #C4BFB8; }
.hero .small { color: #9D9891; }
.hero__where { color: #C4BFB8; }
.hero .btn--line { color: #fff; border-color: rgba(255,255,255,0.32); }
.hero .btn--line:hover { background: #fff; border-color: #fff; color: var(--ink); }
/* The hero was double-spacing itself: this grid has a gap AND every child
   carried its own margin-bottom, so the real distance between the lead and the
   buttons was gap + margin = about 72px. That, times four children, made an
   810px hero for five short elements. Gap only now, margins removed below. */
.hero__in { padding-block: clamp(1.6rem, 2.6vw, 2.5rem); display: grid; gap: clamp(1rem, 1.6vw, 1.4rem); }
/* Single column. The headline runs full width and the facts strip sits under
   it, which needs no filler panel to balance against. */
.hero__in { max-width: 62rem; }
.hero h1 { max-width: 24ch; }

.hero__where { display: flex; align-items: center; gap: 0.45rem; font-size: 0.875rem; font-weight: 700; color: var(--ink-3); }
.hero__where svg { width: 1rem; height: 1rem; color: var(--red); }

/* Replaced the price strip. Same slot in the hero, real information, no
   figures, because prices are quoted against the room and not published. */
.facts { display: grid; gap: 0.9rem 2.5rem; margin-top: 0.4rem; }
@media (min-width: 44rem) { .facts { grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); max-width: 40rem; } }
.facts dt { font-size: 0.75rem; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; color: #FF6B5E; margin-bottom: 0.3rem; }
.facts dd { font-size: 0.9375rem; line-height: 1.5; color: #D8D4CE; }

/* The shop's existing gold lockup, treated as the artwork it already is. */
.poster { position: relative; background: var(--black); border-radius: var(--r); overflow: hidden; padding: clamp(1.6rem, 3.5vw, 2.5rem); display: flex; flex-direction: column; justify-content: space-between; gap: 1.75rem; min-height: 20rem; }
.poster::after { content: ""; position: absolute; inset: 0; background: radial-gradient(70% 50% at 50% 0%, rgba(201,151,31,0.18), transparent 72%); pointer-events: none; }
.poster > * { position: relative; }
.poster__m span { display: block; font-weight: 800; font-stretch: 80%; text-transform: uppercase; color: var(--gold); line-height: 0.92; letter-spacing: -0.012em; }
.poster__m .a { font-size: clamp(1.05rem, 2.1vw, 1.4rem); }
.poster__m .b { font-size: clamp(1.9rem, 4.4vw, 2.85rem); }
/* Middle band of the poster. Also the right home for a hero photo later —
   drop an <img> in above this and it will sit behind the gold lockup. */
.poster__stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1px; background: #33333A; border: 1px solid #33333A; border-radius: var(--r); overflow: hidden; }
.poster__stats > div { background: #191920; padding: 0.8rem 0.85rem; }
.poster__stats b { display: block; font-weight: 800; font-stretch: 86%; font-size: 1.3rem; color: #fff; line-height: 1; }
.poster__stats span { display: block; font-size: 0.75rem; color: #8B857F; margin-top: 0.28rem; line-height: 1.35; }

.poster__f { display: grid; gap: 0.75rem; }
.poster__f p { color: #ADA8A1; font-size: 0.9375rem; }
.poster__f .ml { color: #D3CEC7; }

/* --- 9b. intro video ----------------------------------------------------- */

/* The source file is a portrait video pillarboxed inside a 16:9 container,
   so roughly a third of its width is dead grey padding on each side.
   A 9:16 box plus object-fit:cover crops to the centre 31.6%, which is
   almost exactly the real content. No re-encoding required. */
/* A 9:16 phone video 20rem wide is 570px tall, which set the row height and
   left the short text column beside it sitting in a void. Narrower column and a
   capped frame height keep the two sides closer to the same size, and the text
   starts at the top instead of floating in the middle of the gap. */
.vid { display: grid; gap: clamp(1.25rem, 2.5vw, 2rem); align-items: start; }
@media (min-width: 56rem) { .vid { grid-template-columns: minmax(0, 15rem) minmax(0, 1fr); } }

.vid__frame {
  position: relative;
  aspect-ratio: 9 / 16;
  width: 100%;
  max-width: 15rem;
  margin-inline: 0;
  background: #000;
  border-radius: var(--r);
  overflow: hidden;
}
.vid__frame video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }

/* Autoplay only works muted, so this is the control that gives the video its
   sound back. Sits over the footage rather than beside it. */
.unmute {
  position: absolute;
  left: 50%; bottom: 0.85rem;
  transform: translateX(-50%);
  display: inline-flex; align-items: center; gap: 0.45rem;
  padding: 0.5rem 0.9rem;
  background: rgba(17,17,20,0.72);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  color: #fff; border: 1px solid rgba(255,255,255,0.22);
  border-radius: var(--r-pill);
  font-size: 0.8125rem; font-weight: 700;
  cursor: pointer; white-space: nowrap;
  transition: background-color var(--fast) var(--ease);
}
.unmute:hover { background: rgba(17,17,20,0.9); }
.unmute svg { width: 1rem; height: 1rem; flex: none; }

/* --- 10. brand marquee --------------------------------------------------- */

.strip { background: var(--shade); padding-block: 1.6rem; }
.strip__cap { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 0.4rem 1.5rem; margin-bottom: 1rem; }
.strip__cap p { font-size: 0.875rem; font-weight: 700; color: var(--ink); }

.marquee {
  position: relative; overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 5%, #000 95%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 5%, #000 95%, transparent);
}
.marquee + .marquee { margin-top: 0.5rem; }

/* No-JS default: a static wrapped grid of every brand (JS builds the
   seamless loop, so the animation is meaningless — and visibly broken —
   without it). */
.marquee__track { display: flex; flex-wrap: wrap; width: 100%; }
.js .marquee__track { flex-wrap: nowrap; width: max-content; will-change: transform; animation: mq-l var(--marquee-duration, 60s) linear infinite; }
.marquee--rev .marquee__track { animation-name: mq-r; }
.marquee__row { display: flex; align-items: stretch; gap: 0.5rem; padding-right: 0.5rem; flex: none; }

@keyframes mq-l { to   { transform: translate3d(-50%, 0, 0); } }
@keyframes mq-r { from { transform: translate3d(-50%, 0, 0); } }

/* Continuous motion stops the moment anyone engages with it. */
.marquee:hover .marquee__track,
.marquee:focus-within .marquee__track { animation-play-state: paused; }

/* Brand names, set as a typographic row. These used to be 30 individual white
   bordered rounded boxes, which is the "logo cloud" module every SaaS template
   ships. A dealer listing the brands it stocks writes them out; the boxes added
   nothing except the pattern. A hairline between names keeps them countable. */
.chip { display: flex; align-items: center; flex: none; height: 2.6rem; padding-inline: clamp(1rem, 2vw, 1.75rem); border-right: 1px solid var(--line); }
/* Brand wordmark colours.

   Verified Sept 2026 against official site assets and brand references
   (logos measured from company websites / official files). JBL publishes no
   official hex — #FF6600 is the widely-cited approximation of its blaze
   orange. Marks left at black genuinely are black wordmarks (Magnat,
   Polk, Optoma, Onkyo, Klipsch) — that is accurate, not a fallback.
   Marantz's current wordmark is a copper-bronze gradient, set here in its
   anchor tone.

   Replace any of these with real logo files by dropping an <img> into the
   chip; .chip img is already styled for it. */
.chip__n { font-size: 0.9375rem; font-weight: 700; color: var(--ink); text-align: center; line-height: 1.1; white-space: nowrap; }

.chip__n[data-b="jvc"]     { color: #FF0000; }
.chip__n[data-b="benq"]    { color: #541785; }
.chip__n[data-b="epson"]   { color: #0C4DA2; }
.chip__n[data-b="svs"]     { color: #376CB1; }
.chip__n[data-b="taga"]    { color: #4E2583; }
.chip__n[data-b="anthem"]  { color: #D22630; }
.chip__n[data-b="cerwin"]  { color: #EC1C2E; }
.chip__n[data-b="magnat"]  { color: #000000; }
.chip__n[data-b="yaber"]   { color: #F99A2B; }
.chip__n[data-b="polk"]    { color: #000000; }
.chip__n[data-b="pioneer"] { color: #A90533; }
.chip__n[data-b="optoma"]  { color: #151515; }
.chip__n[data-b="marantz"] { color: #AA7460; }
.chip__n[data-b="onkyo"]   { color: #000000; }
.chip__n[data-b="klipsch"] { color: #000000; }
.chip__n[data-b="jbl"]     { color: #FF3300; }
.chip__n[data-c="caps"]  { text-transform: uppercase; letter-spacing: 0.085em; font-weight: 800; font-stretch: 90%; }
.chip__n[data-c="tight"] { text-transform: uppercase; letter-spacing: -0.015em; font-weight: 800; font-stretch: 76%; font-size: 1.15rem; }
.chip__n[data-c="low"]   { text-transform: lowercase; font-weight: 500; font-size: 1.0625rem; }
.chip__n small { display: block; font-size: 0.5625rem; font-weight: 600; letter-spacing: 0.13em; text-transform: uppercase; color: var(--ink-3); margin-top: 0.05rem; }
/* Definite height so viewBox-only SVGs (no intrinsic width/height) resolve
   their width from the intrinsic ratio. max-height alone leaves them 0px. */
.chip img { height: 1.3rem; width: auto; object-fit: contain; }

/* --- 11. cards ----------------------------------------------------------- */

.cards { display: grid; gap: 1rem; }
@media (min-width: 44rem) { .cards--2, .cards--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 66rem) { .cards--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 50rem) { .cards--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 70rem) { .cards--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.card { background: var(--white); border: 1px solid var(--line); border-radius: var(--r); padding: clamp(1.2rem, 2.2vw, 1.65rem); display: flex; flex-direction: column; gap: 0.65rem; }
.card p { font-size: 0.9375rem; }
.card__ft { margin-top: auto; padding-top: 0.35rem; }
.dark .card { background: var(--black-2); border-color: var(--black-3); }

a.card { text-decoration: none; color: inherit; cursor: pointer; transition: border-color var(--mid) var(--ease), transform var(--mid) var(--ease), box-shadow var(--mid) var(--ease); }
a.card:hover { border-color: var(--red); transform: translateY(-2px); box-shadow: 0 12px 30px -20px rgba(23,22,26,0.35); }

/* Service list.

   Replaces a row of six identical icon-topped cards, which is the single most
   recognisable generated-layout pattern there is. No cards, no icons, no equal
   heights: the first entry is deliberately larger than the rest so the group
   has a hierarchy instead of a grid. */
.svc { display: grid; gap: 2.25rem 3rem; }
@media (min-width: 46rem) { .svc { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 70rem) { .svc { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

.svc > li { display: flex; flex-direction: column; gap: 0.55rem; }
.svc a { text-decoration: none; color: inherit; }
.svc h3 { transition: color var(--fast) var(--ease); }
.svc a:hover h3 { color: var(--red); }
.svc p { font-size: 0.9375rem; }

/* The lead entry runs across the grid and sets its own type size. */
.svc > li[data-lead] { gap: 0.7rem; }
@media (min-width: 46rem) { .svc > li[data-lead] { grid-column: 1 / -1; max-width: 56rem; } }
.svc > li[data-lead] p { text-wrap: balance; }
.svc > li[data-lead] h3 { font-size: clamp(1.3rem, 2.2vw, 1.75rem); }
.svc > li[data-lead] p { font-size: 1.0625rem; }

/* Green price tag, the way the shop's own artwork does it. */
.tag { display: inline-block; align-self: flex-start; background: var(--green); color: #fff; font-size: 0.8125rem; font-weight: 700; padding: 0.2rem 0.6rem; border-radius: var(--r-sm); }

/* --- 12. process list ---------------------------------------------------- */

/* Unruled. The numerals and the indent give the list its structure, so the
   row-by-row hairlines are not needed. */
.steps { display: grid; gap: 0.35rem; }
.step { display: grid; gap: 0.3rem 1.6rem; padding: 1rem 1.15rem; border-radius: var(--r); }
.step:nth-child(odd) { background: var(--white); }
.dark .step:nth-child(odd) { background: var(--black-2); }
@media (min-width: 54rem) { .step { grid-template-columns: 2.75rem minmax(0, 13rem) minmax(0, 1fr); align-items: baseline; } }
.step__n { font-weight: 800; font-stretch: 86%; font-size: 1.1rem; color: var(--red); }
.dark .step__n { color: #FF6B5E; }
.step p { font-size: 0.9375rem; }

/* --- 13. packages -------------------------------------------------------- */

/* Packages as rows, not three columns.

   Three side-by-side cards with the middle one ringed and badged "Most
   Popular" is the canonical SaaS pricing template, and it gets shipped
   whether or not it suits the actual offer. These are three genuinely
   different jobs at three different scales, so they read as a rate card:
   price on the left, what it covers on the right. No highlight ring, no
   badge, no column of tick icons. */
.tiers { display: grid; gap: 0.6rem; }

.tier {
  display: grid; gap: 0.6rem 3rem;
  padding: clamp(1.35rem, 2.6vw, 2rem);
  background: var(--white);
  border-radius: var(--r);
}
@media (min-width: 52rem) {
  .tier { grid-template-columns: 15rem minmax(0, 1fr); align-items: start; }
}

.tier__p { font-weight: 800; font-stretch: 86%; font-size: clamp(1.8rem, 1.4rem + 1.4vw, 2.5rem); color: var(--ink); line-height: 0.95; }
.tier__p span { display: block; font-size: 0.8125rem; font-weight: 500; font-stretch: 100%; color: var(--ink-3); margin-top: 0.4rem; }
.tier__n { font-size: 0.9375rem; font-weight: 700; color: var(--red); margin-bottom: 0.4rem; }
/* Stands where the figure used to. Same weight in the layout, no number. */
.tier__ask { font-weight: 800; font-stretch: 86%; font-size: clamp(1.2rem, 1rem + 0.7vw, 1.5rem); color: var(--ink); line-height: 1.05; }

.tier__d { display: grid; gap: 0.7rem; }
.tier__d p { font-size: 0.9375rem; }

/* Inclusions as a plain wrapped list separated by rules, rather than a
   stack of green tick icons. */
.tier__inc { display: flex; flex-wrap: wrap; gap: 0.35rem 0.9rem; font-size: 0.875rem; color: var(--ink-2); }
.tier__inc li { position: relative; }
.tier__inc li + li { padding-left: 1.05rem; }
.tier__inc li + li::before { content: ""; position: absolute; left: 0; top: 0.55em; width: 5px; height: 5px; border-radius: 50%; background: var(--line-2); }

/* --- 14. products -------------------------------------------------------- */

.prod { background: var(--white); border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; display: flex; flex-direction: column; }
.prod__b { padding: 1.1rem 1.2rem 1.2rem; display: flex; flex-direction: column; gap: 0.5rem; flex: 1; }
.prod__brand { font-size: 0.75rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.07em; color: var(--red); }
.prod p { font-size: 0.875rem; }
.prod dl { display: grid; gap: 0.22rem; padding-top: 0.55rem; margin-top: 0.15rem; border-top: 1px solid var(--line); }
.prod dl > div { display: flex; justify-content: space-between; gap: 1rem; font-size: 0.8125rem; }
.prod dt { color: var(--ink-3); }
.prod dd { color: var(--ink); font-weight: 500; text-align: right; }
.prod__ft { margin-top: auto; padding-top: 0.85rem; display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; }
.prod__price { font-weight: 800; font-stretch: 86%; font-size: 1.15rem; color: var(--ink); }
.prod__price small { display: block; font-size: 0.6875rem; font-weight: 500; font-stretch: 100%; color: var(--ink-3); }

.filters { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-bottom: 0; }
/* Radius matched to the buttons. These were 999px capsules, which with pill
   buttons everywhere else was the "everything is rounded" template read. */
.filters a { font-size: 0.875rem; font-weight: 500; color: var(--ink-2); text-decoration: none; padding: 0.45rem 0.8rem; background: var(--white); border: 1px solid var(--line); border-radius: var(--r-sm); cursor: pointer; transition: background-color var(--fast) var(--ease), border-color var(--fast) var(--ease), color var(--fast) var(--ease); }
.filters a:hover { border-color: var(--ink); color: var(--ink); }
.filters a[aria-current="true"] { background: var(--ink); border-color: var(--ink); color: #fff; font-weight: 700; }

/* --- 15. room diagram --------------------------------------------------- */

.dg { background: var(--white); border: 1px solid var(--line); border-radius: var(--r); padding: clamp(1rem, 2.2vw, 1.6rem); }
.dg svg { width: 100%; height: auto; }
.dg figcaption { margin-top: 0.9rem; padding-top: 0.8rem; border-top: 1px solid var(--line); font-size: 0.8125rem; color: var(--ink-3); }
.d-room { fill: var(--shade); stroke: var(--line-2); stroke-width: 1.5; }
.d-scr  { stroke: var(--ink); stroke-width: 5; stroke-linecap: round; }
.d-seat { fill: #DFD8CA; stroke: var(--line-2); stroke-width: 1; }
.d-sp   { fill: var(--red); }
.d-sp2  { fill: var(--white); stroke: var(--red); stroke-width: 1.5; }
.d-ln   { stroke: var(--line-2); stroke-width: 1; fill: none; }
.d-t    { font-family: var(--font); font-size: 9px; font-weight: 700; fill: var(--ink-3); }
.d-t2   { font-family: var(--font); font-size: 9px; font-weight: 700; fill: var(--red); }

/* --- 16. photo slots ---------------------------------------------------- */

.shot { position: relative; aspect-ratio: 4/3; overflow: hidden; background: var(--shade); border-radius: var(--r); }
.shot--wide { aspect-ratio: 16/9; }
.shot--tall { aspect-ratio: 3/4; }
.shot--sq { aspect-ratio: 1; }
.shot img { width: 100%; height: 100%; object-fit: cover; transition: transform 700ms var(--ease); }
/* Slow drift into the frame on hover, the way a print settles under the
   enlarger. transform only; the frame's overflow keeps it contained. */
.shot:hover img { transform: scale(1.045); }

/* Any frame containing a person crops from the top, otherwise cover() takes
   the head off — which is exactly what happened to the owner's photo. */
.shot--face img { object-position: 50% 12%; }

/* Photo grid for the work section. Deliberately uneven — the first frame is
   wider than the rest so it is not a row of identical tiles. */
.gal { display: grid; gap: 0.6rem; }
@media (min-width: 44rem) { .gal { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 68rem) { .gal { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (min-width: 44rem) { .gal > li[data-wide] { grid-column: span 2; } }

.gal figure { margin: 0; position: relative; }
.gal figcaption {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 1.35rem 0.9rem 0.7rem;
  font-size: 0.8125rem; font-weight: 700; color: #fff;
  background: linear-gradient(0deg, rgba(12,12,14,0.85), transparent);
  border-radius: 0 0 var(--r) var(--r);
}
.shot__ph {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.45rem;
  text-align: center; padding: 1.2rem;
  background-image: repeating-linear-gradient(135deg, rgba(0,0,0,0.03) 0 1px, transparent 1px 8px);
}
.shot__ph svg { width: 1.4rem; height: 1.4rem; color: var(--line-2); }
.shot__ph span { font-size: 0.75rem; font-weight: 600; color: var(--ink-3); max-width: 24ch; line-height: 1.45; }

/* --- 17. reviews -------------------------------------------------------- */

.stars { display: flex; gap: 0.08rem; }
.stars svg { width: 1rem; height: 1rem; color: #E8A317; }

.quote { background: var(--white); border: 1px solid var(--line); border-radius: var(--r); padding: clamp(1.2rem, 2.2vw, 1.65rem); display: flex; flex-direction: column; gap: 0.9rem; }
/* Testimonial voices set in the display serif's true italic — an editorial
   move that costs one extra font file and reads unmistakably chosen. */
.quote p { font-family: var(--font-d); font-style: italic; font-weight: 400; font-size: 1.125rem; line-height: 1.6; color: var(--ink); }
.quote footer { margin-top: auto; display: flex; align-items: center; gap: 0.65rem; }
.quote footer b { font-size: 0.9375rem; color: var(--ink); }
.quote footer span { display: block; font-size: 0.8125rem; color: var(--ink-3); }
.ava { width: 2.35rem; height: 2.35rem; flex: none; border-radius: 50%; background: var(--shade); border: 1px solid var(--line); display: grid; place-items: center; font-weight: 800; font-size: 0.9375rem; color: var(--red); }

/* --- 18. faq ------------------------------------------------------------ */

.faq { border-top: 2px solid var(--ink); }
.faq details { border-bottom: 1px solid var(--line); }
.faq summary { display: flex; align-items: flex-start; justify-content: space-between; gap: 1.25rem; padding-block: 1.1rem; font-size: 1.0625rem; font-weight: 700; color: var(--ink); cursor: pointer; list-style: none; }
.faq summary::-webkit-details-marker { display: none; }
.faq summary:hover { color: var(--red); }
.faq summary::after {
  content: ""; flex: none; width: 1rem; height: 1rem; margin-top: 0.35rem; background: currentColor;
  -webkit-mask: linear-gradient(#000 0 0) center/100% 2px no-repeat, linear-gradient(#000 0 0) center/2px 100% no-repeat;
          mask: linear-gradient(#000 0 0) center/100% 2px no-repeat, linear-gradient(#000 0 0) center/2px 100% no-repeat;
  transition: transform var(--mid) var(--ease);
}
.faq details[open] summary { color: var(--red); }
.faq details[open] summary::after { transform: rotate(45deg); }
.faq__a { padding-bottom: 1.3rem; max-width: 70ch; }
.faq__a p + p { margin-top: 0.8em; }

/* --- 19. forms ---------------------------------------------------------- */

.f { display: grid; gap: 0.35rem; }
.f label { font-size: 0.875rem; font-weight: 700; color: var(--ink); }
.f label i { font-style: normal; color: var(--red); }
.f input, .f select, .f textarea {
  width: 100%; padding: 0.78rem 0.9rem;
  background: var(--white); color: var(--ink);
  border: 1px solid var(--line-2); border-radius: var(--r);
  transition: border-color var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}
.f textarea { min-height: 7rem; resize: vertical; }
.f input::placeholder, .f textarea::placeholder { color: #9C958D; }
.f input:focus, .f select:focus, .f textarea:focus { border-color: var(--red); box-shadow: 0 0 0 3px var(--red-wash); outline: none; }
.f select {
  appearance: none; cursor: pointer; padding-right: 2.4rem;
  background-image: linear-gradient(45deg, transparent 50%, var(--ink-2) 50%), linear-gradient(135deg, var(--ink-2) 50%, transparent 50%);
  background-position: calc(100% - 1.05rem) 1.15rem, calc(100% - 0.78rem) 1.15rem;
  background-size: 6px 6px; background-repeat: no-repeat;
}
.fg { display: grid; gap: 0.9rem; }
@media (min-width: 42rem) { .fg--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.fstat { font-size: 0.9375rem; font-weight: 500; }
.fstat:empty { display: none; }
.fstat[data-state="ok"] { color: var(--green); }
.fstat[data-state="error"] { color: var(--red-dk); }

.dark .f label { color: #fff; }
.dark .f input, .dark .f select, .dark .f textarea { background: var(--black-2); border-color: #3A3A40; color: #fff; }
.dark .f input::placeholder, .dark .f textarea::placeholder { color: #77726C; }
.dark .f input:focus, .dark .f select:focus, .dark .f textarea:focus { border-color: #FF6B5E; box-shadow: 0 0 0 3px rgba(216,35,42,0.22); }
.dark .fstat[data-state="ok"] { color: #4FD188; }
.dark .fstat[data-state="error"] { color: #FF8E82; }

/* --- 20. contact rows --------------------------------------------------- */

/* Banded instead of ruled, for the same reason as the step list. */
.rows { display: grid; gap: 0.2rem; }
.row { display: grid; gap: 0.15rem 1.5rem; padding: 0.8rem 1.05rem; border-radius: var(--r); }
.row:nth-child(odd) { background: var(--white); }
.dark .row:nth-child(odd) { background: var(--black-2); }
@media (min-width: 38rem) { .row { grid-template-columns: 7rem minmax(0, 1fr); align-items: baseline; } }
.row dt { font-size: 0.875rem; font-weight: 700; color: var(--ink-3); }
.dark .row dt { color: #8B857F; }
.row dd { font-size: 1.0625rem; color: var(--ink); }
.dark .row dd { color: #fff; }
.row dd a { text-decoration: none; border-bottom: 2px solid rgba(216,35,42,0.4); }
.row dd a:hover { border-bottom-color: var(--red); }

/* --- 21. footer --------------------------------------------------------- */

.footer { background: var(--black); color: #9D9891; padding-block: clamp(2.25rem, 4.5vw, 3.5rem) 1.4rem; }
/* Two columns, not four. The four-equal-columns-plus-newsletter footer gets
   generated whether or not the links exist; this one is built from what the
   site actually has, and the newsletter box is gone because there is no
   backend to receive a subscription. */
.footer__g { display: grid; gap: 2.25rem; }
@media (min-width: 52rem) { .footer__g { grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); gap: 3rem; } }
.footer__nav { display: grid; gap: 1.75rem 2.5rem; }
@media (min-width: 34rem) { .footer__nav { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.footer h4 { font-size: 0.8125rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: #fff; margin-bottom: 0.85rem; }
.footer ul { display: grid; gap: 0.5rem; }
.footer ul a { font-size: 0.9375rem; text-decoration: none; }
.footer ul a:hover { color: #fff; }
.footer__bot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 0.7rem; margin-top: clamp(1.75rem, 3.5vw, 2.75rem); padding-top: 1.25rem; border-top: 1px solid var(--black-3); font-size: 0.8125rem; }

.social { display: flex; gap: 0.45rem; }
.social a { display: grid; place-items: center; width: 2.35rem; height: 2.35rem; background: var(--black-2); border: 1px solid var(--black-3); border-radius: var(--r); color: #C0BBB4; cursor: pointer; transition: background-color var(--fast) var(--ease), border-color var(--fast) var(--ease), color var(--fast) var(--ease); }
.social a:hover { background: var(--red); border-color: var(--red); color: #fff; }
.social svg { width: 1.05rem; height: 1.05rem; }

.sub { display: flex; gap: 0.4rem; flex-wrap: wrap; }
.sub input { flex: 1 1 9rem; min-width: 0; }

/* --- 22. floating + sticky actions -------------------------------------- */

/* Desktop: one floating WhatsApp button. Mobile: a two-up action bar. */
.float {
  position: fixed; right: 1.25rem; bottom: 1.25rem; z-index: 95;
  display: none; align-items: center; gap: 0.5rem;
  padding: 0.8rem 1.1rem;
  background: var(--green); color: #fff;
  border-radius: 999px; text-decoration: none; font-weight: 700; font-size: 0.9375rem;
  box-shadow: 0 6px 22px rgba(0,0,0,0.22);
  cursor: pointer;
  transition: background-color var(--mid) var(--ease);
}
.float:hover { background: #145C34; }
.float svg { width: 1.25rem; height: 1.25rem; }
@media (min-width: 64rem) { .float { display: inline-flex; } }

.bar { position: fixed; inset: auto 0 0 0; z-index: 95; display: grid; grid-template-columns: 1fr 1fr; padding-bottom: env(safe-area-inset-bottom); }
.bar a { display: flex; align-items: center; justify-content: center; gap: 0.45rem; padding: 0.85rem 0.75rem; font-size: 0.9375rem; font-weight: 700; text-decoration: none; cursor: pointer; }
.bar a:first-child { background: var(--ink); color: #fff; }
.bar a:last-child { background: var(--green); color: #fff; }
.bar svg { width: 1.1rem; height: 1.1rem; }
@media (min-width: 64rem) { .bar { display: none; } }
@media (max-width: 63.99rem) { body { padding-bottom: 3.3rem; } }

/* --- 23. page header ---------------------------------------------------- */

.ph { background: var(--white); padding-block: clamp(1.25rem, 2vw, 1.75rem) clamp(1.5rem, 2.4vw, 2rem); }

/* Page header, single column: breadcrumb, title, one line of context, actions.

   This was a two-column grid with align-items:end, which had two faults. The
   right column holds a paragraph plus buttons so it is always taller, which
   pushed the short h1 to the bottom of the row and made the page title appear
   to sit BELOW its own description. Top-aligning fixed the order but left a
   dead half-column under one-word titles like "Products". A single column has
   no hole to fill and reads in the order the words are meant to be read. */
.ph__g { display: grid; gap: 0.75rem; }
.ph__g .lead { max-width: 58ch; }
.ph__g .btns { margin-top: 0.25rem; }
.ph__g .lead { margin-bottom: 0; }
/* Both of these were used in contact.html markup but never defined, so the
   contact card icons rendered unsized and the Directions button did not fill its
   card. Pre-existing, found by .dev/classcheck.py. */
.ico {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2.5rem; height: 2.5rem; margin-bottom: 0.9rem;
  background: var(--shade); border: 1px solid var(--line); border-radius: var(--r-sm);
  color: var(--red); flex: none;
}
.ico svg { width: 1.25rem; height: 1.25rem; }
.btn--block { display: flex; width: 100%; }

.crumb { font-size: 0.8125rem; color: var(--ink-3); margin-bottom: 0.75rem; }
.crumb a { text-decoration: none; }
.crumb a:hover { color: var(--red); }

/* --- 24. journal -------------------------------------------------------- */

.post { display: grid; gap: 0.3rem 1.6rem; padding-block: 1.25rem; border-bottom: 1px solid var(--line); text-decoration: none; color: inherit; cursor: pointer; }
@media (min-width: 54rem) { .post { grid-template-columns: 6.5rem minmax(0, 1fr); } }
.post:hover .tt { color: var(--red); }
.post .tt { margin-bottom: 0.25rem; transition: color var(--fast) var(--ease); }
.post p { font-size: 0.9375rem; }
.post time { font-size: 0.8125rem; color: var(--ink-3); }

/* --- 25. misc ----------------------------------------------------------- */

.split { display: grid; gap: clamp(1.6rem, 3.5vw, 2.75rem); align-items: start; }
@media (min-width: 58rem) {
  .split { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .split--a { grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); }
  .split--b { grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr); }
  /* A deliberately lopsided one. 1.15fr/1fr reads as "almost equal", which is
     the safe default the whole page was using. This is far enough off centre to
     register as a decision. Used once, for the acoustics text beside the room
     diagram. */
  .split--wide-l { grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr); }
}

/* No coloured left stripe: that border-accent card is one of the most
   reliable generated-design signatures going. Emphasis comes from the tinted
   ground and the bold lead-in instead. */
.note { background: var(--red-wash); border-radius: var(--r); padding: 1.1rem 1.25rem; font-size: 0.9375rem; color: var(--ink-2); }
.note b { color: var(--ink); }
.dark .note { background: rgba(216,35,42,0.12); color: #CFCAC3; }

.stack   { display: grid; gap: 1.15rem; }
.stack-s { display: grid; gap: 0.55rem; }
.mt      { margin-top: clamp(1.4rem, 2.8vw, 2rem); }
.mt-l    { margin-top: clamp(2rem, 4vw, 3rem); }
.sr { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* --- 25b. details animation + page transitions -------------------------- */

/* FAQ answers animate open AND closed. ::details-content keeps the content
   in the box tree during close; interpolate-size lets the keyword block-size
   transition run. Where either is unsupported the details just snaps, as it
   always has — no JS, no regression. */
:root { interpolate-size: allow-keywords; }
.faq details::details-content {
  block-size: 0;
  overflow: clip;
  transition: block-size var(--mid) var(--ease), content-visibility var(--mid) var(--ease) allow-discrete;
}
.faq details[open]::details-content { block-size: auto; }

/* Cross-page fade on real navigations. Opt-in only, motion-safe only. */
@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }
  ::view-transition-old(root), ::view-transition-new(root) {
    animation-duration: 200ms;
    animation-timing-function: cubic-bezier(0.2, 0.7, 0.2, 1);
  }
}

/* --- 26. motion --------------------------------------------------------- */

/* Hidden reveal states apply only when JS is running to reveal them (the
   .js class is set by one inline line in the head). No JS = everything
   visible, always. */
.js [data-reveal] { opacity: 0; transform: translateY(10px); transition: opacity 460ms var(--ease), transform 460ms var(--ease); }
[data-reveal][data-shown="true"] { opacity: 1; transform: none; }

/* Pointer-reactive glow: the JS writes --gx/--gy on the hero, the ::before
   glow layer follows with a soft lag. transform only, transition does the
   smoothing, and the whole thing is inert on touch and reduced-motion. */
.hero::before {
  transform: translate3d(var(--gx, 0px), var(--gy, 0px), 0);
  transition: transform 280ms ease-out;
}

@media (prefers-reduced-motion: no-preference) {

  /* Hero entrance: children rise in with a short stagger on load. First
     child starts immediately so LCP is unaffected. */
  .hero__in > * { animation: hero-in 560ms var(--ease) both; }
  .hero__in > *:nth-child(2) { animation-delay: 90ms; }
  .hero__in > *:nth-child(3) { animation-delay: 180ms; }
  .hero__in > *:nth-child(4) { animation-delay: 270ms; }
  .hero__in > *:nth-child(5) { animation-delay: 360ms; }
  @keyframes hero-in {
    from { opacity: 0; transform: translateY(14px); }
  }

  /* One slow zoom-out settle on the hero photograph — the projector warming
     up — then it holds still. Runs once, no perpetual motion. */
  .hero__bg img { animation: hero-zoom 16s ease-out both; transform-origin: 50% 52%; }
  @keyframes hero-zoom {
    from { transform: scale(1.08); }
    to   { transform: scale(1); }
  }

  /* Photographs develop top to bottom as they scroll into view. The JS adds
     .shot and .bleed to the same observer that drives data-shown. */
  .js .shot, .js .bleed { clip-path: inset(0 0 100% 0); transition: clip-path 640ms var(--ease); }
  .shot[data-shown="true"], .bleed[data-shown="true"] { clip-path: inset(0 0 0 0); }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; }
  [data-reveal] { opacity: 1; transform: none; }
  .marquee { -webkit-mask-image: none; mask-image: none; overflow: visible; }
  .marquee__track { animation: none !important; width: 100% !important; flex-wrap: wrap !important; }
  .marquee__row { flex-wrap: wrap !important; }
  .marquee [data-marquee-clone] { display: none; }
}

/* Forced colours (Windows High Contrast and friends). The system palette
   replaces ours by design — brand wordmarks falling back to CanvasText is
   the point of the mode, not a bug. What needs help is anything whose shape
   came from a fill alone: it gets a border so its bounds survive. */
@media (forced-colors: active) {
  .btn, .tag, .float, .bar a, .chip, .card, .tier, .prod, .quote, .f input, .f select, .f textarea {
    border: 1px solid;
  }
}

@media print {
  .topbar, .header, .bar, .float, .marquee, .drawer, .social { display: none !important; }
  body { background: #fff; color: #000; padding-bottom: 0; }
  .section { padding-block: 1.25rem; }
}
