/* ==========================================================================
   Cmagz RPM Detailing — built by RedHorseWebDev

   Direction: technical. Everything labelled, everything on a hairline grid,
   nothing shouted. The voice of a tradesman who writes down what he did.

   Red is a data accent, not decoration: it marks the AFTER, the price and the
   action. The moment it decorates, it stops meaning anything.

   Dark is the default because car photography lives on black. Light mode is a
   real second palette, not an inversion.
   ========================================================================== */

/* ------------------------------------------------------------------- fonts */
/* Self-hosted. Previously these came from fonts.googleapis.com, which cost the
   first paint two third-party origins before a single pixel could be drawn:
   one connection to fetch the stylesheet, and a second to fonts.gstatic.com
   for the files it pointed at -- and only gstatic was ever preconnected, so
   the first hop paid full DNS, TCP and TLS on a phone. Lighthouse measured the
   whole render-blocking chain at 1,040ms on mobile.

   These are the variable versions: one file per family covers every weight the
   site uses (Chivo 400-900, Chivo Mono 400-500), so self-hosting costs two
   requests rather than the six that separate weight files would need. Both are
   same-origin now, and nginx serves woff2 with a year of immutable cache.

   The latin-ext files are declared but almost never fetched: unicode-range
   tells the browser to download a subset only when a character in that range
   actually appears on the page. They are here so an accented name in a review
   renders properly rather than falling back mid-sentence.

   Deliberately NOT preloaded. font-display: swap means text paints immediately
   in the fallback face, so the fonts are not on the critical path -- while the
   hero photograph IS, being the largest contentful paint. Preloading fonts
   would put them in direct competition with it for the same scarce bandwidth
   on the phone this is all meant to be fast on.

   Chivo and Chivo Mono are SIL Open Font License, which permits this.
   Regenerate with tools/ fetch if the fonts are ever updated upstream. */
@font-face {
  font-family: 'Chivo';
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  src: url(/assets/fonts/chivo-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Chivo';
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  src: url(/assets/fonts/chivo-latin.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: 'Chivo Mono';
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
  src: url(/assets/fonts/chivomono-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Chivo Mono';
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
  src: url(/assets/fonts/chivomono-latin.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;
}


:root {
  color-scheme: dark;
  --bg:      #000000;
  --panel:   #0d0d0f;
  --raised:  #16161a;
  --line:    #2a2a31;
  --hair:    #191920;
  --text:    #ffffff;
  --dim:     #9a9aa4;
  --dimmer:  #838391;
  --red:     #ff1a2e;
  --red-hot: #ff4053;
  --red-ink: #ff5563;
  --red-deep:#b20a18;
  --shade:   rgba(10, 10, 12, .82);

  --sans: Chivo, system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono: "Chivo Mono", ui-monospace, "Cascadia Mono", Consolas, monospace;

  --gutter: clamp(18px, 3.5vw, 40px);
  --wrap: 1280px;
}

[data-theme="light"] {
  color-scheme: light;
  --bg:      #ffffff;
  --panel:   #f2f2f3;
  --raised:  #e9e9eb;
  --line:    #16161a;
  --hair:    #d8d8dc;
  --text:    #000000;
  --dim:     #45454d;
  --dimmer:  #67676f;
  --red:     #e00014;
  --red-hot: #ff1a2e;
  --red-ink: #a80c19;
  --red-deep:#8e0511;
  --shade:   rgba(255, 255, 255, .88);
}

* { box-sizing: border-box; }
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}
img { display: block; max-width: 100%; }
a { color: inherit; }

.wrap { max-width: var(--wrap); margin: 0 auto; padding-inline: var(--gutter); }

/* The labelling voice. Every block on this site announces what it is. */
.k {
  font-family: var(--mono); font-size: 11px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--dimmer);
}
.k--red { color: var(--red); }

/* Heavy, tight and upper-case. The aggression comes from weight and from the
   size jump between a headline and its label -- not from ornament, which is
   where this kind of site usually goes wrong. */
h1, h2, h3 { margin: 0; text-wrap: balance; text-transform: uppercase; font-weight: 900; }
h1 { font-size: clamp(2.6rem, 6vw, 4.6rem); line-height: .9; letter-spacing: -.035em; }
h2 { font-size: clamp(1.9rem, 3.6vw, 2.8rem); line-height: .94; letter-spacing: -.03em; }
h3 { font-size: 1.1rem; line-height: 1.05; letter-spacing: -.015em; }
p { margin: 0 0 1em; }
.lede { color: var(--dim); max-width: 52ch; font-size: 16.5px; }

/* ------------------------------------------------------------------ header */
.top { border-bottom: 1px solid var(--line); position: sticky; top: 0; z-index: 50;
       background: var(--bg); }
.top__in {
  display: flex; align-items: center; gap: 1.4rem; height: 60px;
  max-width: var(--wrap); margin: 0 auto; padding-inline: var(--gutter);
}
.logo { font-weight: 700; letter-spacing: -.01em; text-decoration: none; font-size: 1.05rem;
        white-space: nowrap; }
.logo span { color: var(--red); }
.top__loc { border-left: 1px solid var(--line); padding-left: 1rem; }

.nav { margin-left: auto; display: flex; gap: .15rem; }
.nav a { text-decoration: none; color: var(--dim); font-size: 13.5px; padding: .4rem .7rem;
         border-radius: 0; }
.nav a:hover { color: var(--text); background: var(--panel); }
.nav a[aria-current="page"] { color: var(--text); }
.nav a[aria-current="page"]::after {
  content: ""; display: block; height: 2px; background: var(--red); margin-top: 2px;
}
.top__act { display: flex; align-items: center; gap: .45rem; }
.themer, .burger {
  width: 34px; height: 34px; flex: none; display: grid; place-items: center;
  background: transparent; border: 1px solid var(--line); border-radius: 0;
  color: var(--dim); cursor: pointer; padding: 0;
}
.themer:hover, .burger:hover { color: var(--text); border-color: var(--dimmer); }
.themer svg, .burger svg { width: 16px; height: 16px; }
.themer .sun { display: none; }
[data-theme="light"] .themer .sun { display: block; }
[data-theme="light"] .themer .moon { display: none; }
.burger { display: none; }

/* ----------------------------------------------------------------- buttons */
.btn {
  display: inline-block; text-decoration: none; font-family: var(--mono);
  font-size: 12.5px; letter-spacing: .1em; text-transform: uppercase;
  padding: .75rem 1.2rem; border: 1px solid var(--line); cursor: pointer;
  background: transparent; color: var(--text);
}
.btn:hover { border-color: var(--dimmer); }
.btn--red { background: var(--red); border-color: var(--red); color: #fff; }
.btn--red:hover { background: var(--red-hot); border-color: var(--red-hot); }

/* -------------------------------------------------------------------- hero */
.hero { display: grid; grid-template-columns: 1.05fr .95fr; border-bottom: 1px solid var(--line); }
.hero__txt {
  padding: clamp(34px, 5vw, 64px) var(--gutter);
  border-right: 1px solid var(--line);
  display: flex; flex-direction: column; justify-content: center;
}
.hero__txt > .k { margin-bottom: 1rem; }
.hero h1 { max-width: 17ch; }
.hero .lede { margin-top: 1.1rem; }
.hero__act { display: flex; flex-wrap: wrap; gap: .6rem; margin-top: 1.8rem; }
/* The hero photographs are stacked and crossfaded, so they are all out of
   flow and none of them gives the box a height. At desktop the grid row does
   that (the text column is taller). Below that breakpoint the hero is its own
   row with nothing to measure, so it states its own shape. */
/* No min-height alongside the ratio: the two together imply a minimum WIDTH
   of 320 * 4/3 = 427px, which is wider than a phone, and the grid column
   dutifully grows to it and pushes the page sideways. The ratio alone gives
   the box its height here; min-height goes back to being the desktop safety
   net, where there is no ratio to conflict with it. */
.hero__img { position: relative; aspect-ratio: 4 / 3; }
@media (min-width: 901px) { .hero__img { aspect-ratio: auto; min-height: 320px; } }
.hero__img img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  opacity: 0; transition: opacity .8s ease;
}
.hero__img img.on { opacity: 1; }
/* This label sits directly on the photograph. A text-shadow alone is not
   enough across his brighter frames -- pale pavement, foam, a white car -- so
   the bottom of the image gets a scrim that guarantees a dark field for it. */
.hero__img::after {
  content: ""; position: absolute; inset: auto 0 0 0; height: 110px;
  background: linear-gradient(to top, rgba(0,0,0,.88), rgba(0,0,0,.5) 45%, transparent);
  pointer-events: none;
}
.hero__img .k { position: absolute; left: 14px; bottom: 12px; z-index: 1; color: #fff;
                text-shadow: 0 1px 4px rgba(0,0,0,.8); }

/* Page header for the inner pages: same grid language, no photograph. */
.phead { border-bottom: 1px solid var(--line); padding-block: clamp(34px, 5vw, 60px); }
.phead .k { display: block; margin-bottom: .9rem; }
.phead .lede { margin-top: 1rem; }

/* Instrument row: real facts, formatted like a panel readout. */
.readout { display: grid; grid-template-columns: repeat(4, 1fr); border-bottom: 1px solid var(--line); }
.readout div { padding: 1.1rem var(--gutter); border-right: 1px solid var(--hair); }
.readout div:last-child { border-right: 0; }
.readout b { display: block; font-size: 1.05rem; font-weight: 600; letter-spacing: -.01em; }

/* ----------------------------------------------------------------- section */
.sec { padding-block: clamp(44px, 6vw, 76px); }
.sec--tight { padding-top: 0; }
.sec__head { max-width: 62ch; }
.sec__head .k { display: block; }
.sec__head h2 { margin-top: .7rem; }
.sec__head .lede { margin-top: .9rem; }

/* ------------------------------------------------------------ before/after */
.ba {
  display: grid; grid-template-columns: 1fr 1fr; gap: 1px;
  background: var(--line); border: 1px solid var(--line); margin-top: 2rem;
}
.ba figure { margin: 0; background: var(--bg); position: relative; }
.ba img { width: 100%; height: auto; aspect-ratio: 3 / 4; object-fit: cover; }
.ba figcaption {
  position: absolute; top: 10px; left: 10px;
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .16em;
  text-transform: uppercase; background: var(--shade); color: var(--text);
  padding: .3rem .55rem; border: 1px solid var(--line);
}
.ba .after figcaption { color: var(--red); border-color: var(--red); }

/* ---------------------------------------------------------------- packages */
.pkgs { display: grid; grid-template-columns: 1fr 1fr; gap: 1px;
        background: var(--line); border: 1px solid var(--line); margin-top: 2rem; }
/* Three across for the booking steps and the motorcycle tiers. This lives here
   rather than in a style attribute on the tag: inline styles outrank media
   queries, so as an attribute it could never collapse on a phone. */
.pkgs--three { grid-template-columns: repeat(3, 1fr); }
.pkg { background: var(--panel); padding: clamp(20px, 2.6vw, 30px); }
.pkg__top { display: flex; align-items: baseline; justify-content: space-between;
            gap: 1rem; border-bottom: 1px solid var(--line); padding-bottom: .9rem; }
.pkg .price { font-family: var(--mono); font-size: 12px; color: var(--red-ink); white-space: nowrap; }
.pkg .grp { display: block; margin: 1.2rem 0 .6rem; }
.pkg ul { margin: 0; padding: 0; list-style: none; }
.pkg li { font-size: 14px; color: var(--dim); display: grid;
          grid-template-columns: 14px 1fr; gap: .5rem; margin-bottom: .3rem; }
.pkg li::before { content: "+"; color: var(--dimmer); font-family: var(--mono); font-size: 12px; }
.pkg .caveat { font-size: 13px; color: var(--dimmer); margin: 1.2rem 0 0; }

.addons { border: 1px solid var(--line); border-top: 0; background: var(--panel);
          padding: clamp(20px, 2.6vw, 30px); }
.addons table { width: 100%; border-collapse: collapse; margin-top: .8rem; }
.addons td { padding: .55rem 0; border-bottom: 1px solid var(--hair); font-size: 14.5px; }
.addons td:last-child { text-align: right; font-family: var(--mono); font-size: 13px; color: var(--red-ink); }
.addons tr:last-child td { border-bottom: 0; }

/* ------------------------------------------------------------------ quotes */
/* One real review, shown as one quote rather than as a third of an empty grid.
   Two columns only once there is a second review to put in one, so the next
   one he sends needs no CSS -- and a lone review never sits in a row that
   advertises the two he has not got. */
.quotes { display: grid; gap: 2.2rem; margin-top: 2rem; }
@media (min-width: 900px) {
  .quotes:has(figure + figure) { grid-template-columns: 1fr 1fr; }
}
.quote { margin: 0; max-width: 60ch;
         border-left: 2px solid var(--red);
         padding-left: clamp(16px, 2.4vw, 28px); }
.quote blockquote { margin: 0; }
/* Stars sit above the quote, not beside it: at a glance the rating is the
   first thing read, and putting it inline would fight the opening word of the
   review for the same spot. Off stars are dimmed rather than removed so the
   count is legible as a proportion without counting. */
.stars { display: block; margin-bottom: .7rem; font-size: 15px; letter-spacing: .12em;
         color: var(--red); }
.stars__off { color: var(--line); }
/* Set large, and left exactly as he was sent it -- lower case, no full stop.
   Tidying a customer message into sentence case is the small lie that makes a
   testimonial read as written by the business. */
.quote p { margin: 0; font-weight: 500; letter-spacing: -.01em;
           font-size: clamp(19px, 2.3vw, 26px); line-height: 1.4; }
.quote figcaption { display: block; margin-top: 1rem; }

/* ----------------------------------------------------------------- gallery */
.filters { display: flex; flex-wrap: wrap; gap: .4rem; margin: 1.6rem 0 0; }
.filters button[aria-pressed="true"] { border-color: var(--red); color: var(--red); }

.gal { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
       gap: 1px; background: var(--line); border: 1px solid var(--line); margin-top: 2rem; }
.gal figure { margin: 0; position: relative; background: var(--bg); }
/* height:auto matters. The width/height attributes on the tag become a
   presentational hint of `height: 960px`, and a used height means the browser
   has no reason to consult aspect-ratio at all -- every tile then renders at
   the photo's full height. Releasing height hands the ratio back to the CSS. */
.gal img { width: 100%; height: auto; aspect-ratio: 3 / 4; object-fit: cover; }
.gal figcaption {
  position: absolute; left: 0; right: 0; bottom: 0; padding: .55rem .7rem;
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .12em;
  text-transform: uppercase; color: #fff;
  /* Weighted so the band the type actually occupies is reliably dark, rather
     than fading to full strength only at the very bottom edge. */
  background: linear-gradient(to top, rgba(0,0,0,.92) 0%, rgba(0,0,0,.8) 58%,
                              rgba(0,0,0,.34) 85%, transparent 100%);
  text-shadow: 0 1px 2px rgba(0,0,0,.8);
}
.gal figure[hidden] { display: none; }

/* The home page teaser strip.

   The gallery's auto-fill tracks are wrong here. auto-fill lays down as many
   tracks as fit and keeps the empty ones, so four photographs in a five-track
   row left a visible hole on a wide screen. auto-fit would collapse it, but
   the count would still have to divide into the tracks or the hole just moves
   to the last row.

   So the strip states its columns, and carries six photographs -- the one
   count that divides evenly into all three of them. Change the count in
   STRIP and these numbers have to change with it. */
.gal--strip { grid-template-columns: repeat(6, 1fr); }
@media (max-width: 1150px) { .gal--strip { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 720px)  { .gal--strip { grid-template-columns: repeat(2, 1fr); } }

/* A landscape photo cropped to a portrait tile loses both ends of the car, so
   the few of them take two columns and keep their own shape. Below the point
   where the grid is two columns wide this would fill the row on its own, which
   is fine -- it is the widest photo on the page. */
.gal figure.wide { grid-column: span 2; }
.gal figure.wide img { aspect-ratio: 4 / 3; }
/* Once the grid is down to a single column, span 2 would conjure an implicit
   second column and push the page sideways. Narrow, it is just another tile. */
@media (max-width: 560px) {
  .gal figure.wide { grid-column: auto; }
}

/* ------------------------------------------------------------------- about */
.split { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(28px, 4vw, 56px); align-items: start; }
.split img { width: 100%; border: 1px solid var(--line); }

/* ----------------------------------------------------------------- contact */
.contact { display: grid; grid-template-columns: 1fr 1fr; gap: 1px;
           background: var(--line); border: 1px solid var(--line); margin-top: 2rem; }
.contact > div { background: var(--panel); padding: clamp(22px, 3vw, 34px); }
/* The review form. The same panel as the contact form, but standing on its
   own rather than beside a column of contact details -- so it needs a width
   of its own. A text field eleven hundred pixels wide invites an essay and
   reads as a layout bug. */
.rev-form { background: var(--panel); border: 1px solid var(--line);
            padding: clamp(22px, 3vw, 34px); margin-top: 2rem; max-width: 620px; }
.rev-form .btn { margin-top: .4rem; }
/* Hidden once the review is away: leaving the emptied fields on screen makes
   it look like nothing happened. */
.rev-form .fields[hidden] { display: none; }

.field { display: block; margin-bottom: 1rem; }
.field span { display: block; margin-bottom: .35rem; }
.field input, .field select, .field textarea {
  width: 100%; background: var(--bg); color: var(--text);
  border: 1px solid var(--line); border-radius: 0;
  padding: .65rem .7rem; font-family: var(--sans); font-size: 15px;
}
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-color: var(--red);
}
.rows { margin: 1rem 0 0; padding: 0; list-style: none; }
.rows li { display: flex; justify-content: space-between; gap: 1rem;
           padding: .7rem 0; border-bottom: 1px solid var(--hair); font-size: 15px; }
.rows li:last-child { border-bottom: 0; }
.rows a { text-decoration: none; }
.rows a:hover { color: var(--red); }

/* [hidden] is a browser default at the lowest possible specificity, so any
   author rule that sets display -- flex, grid, block -- beats it and the
   element stays on screen while the code believes it is gone. This is the
   whole reason a form elsewhere sat frozen on "Sending..." for an hour with
   its success message visible underneath. Global, so it cannot recur here. */
[hidden] { display: none !important; }

/* The honeypot. Off-screen rather than display:none, because a bot that fills
   it is exactly the bot that checks for display:none first. Out of the tab
   order and hidden from screen readers, so no real person ever meets it. */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px;
      overflow: hidden; }

.notice { border: 1px solid var(--red); background: var(--panel);
          padding: .9rem 1rem; margin-top: 1rem; font-size: 14.5px; }

/* Red is right for the failure and wrong for the confirmation: it is the
   colour of every alert the reader has ever been shown, and a booking landing
   safely is the opposite of an alert. */
.notice--ok { border-color: var(--line); }

/* ------------------------------------------------------------------ footer */
.foot { border-top: 1px solid var(--line); padding-block: 40px 32px; }
.foot__in { display: grid; grid-template-columns: 1.5fr 1fr 1fr; gap: 2.4rem; }
/* h2, not h4: the footer follows an h1 on most pages, and h1 -> h4 breaks
   the outline a screen reader navigates by. Styled small, ranked honestly. */
/* His own badge, beside the wordmark. Decorative here -- alt="" on purpose,
   because the wordmark next to it already says the name, and a screen reader
   announcing it twice is noise. It is the only place the real mark appears:
   at favicon size it turns to mush, so that stays the simple "C". */
.foot__mark {
  display: inline-flex; align-items: center; gap: .7rem;
  text-decoration: none; margin-bottom: .9rem;
}
.foot__mark img {
  width: 46px; height: 46px; flex: none;
  border-radius: 50%;
}
.foot h2 { font-family: var(--mono); font-size: 11px; letter-spacing: .14em;
           font-weight: 500; line-height: 1.6; text-transform: uppercase;
           text-transform: uppercase; color: var(--dimmer); margin: 0 0 .9rem; font-weight: 400; }
.foot ul { margin: 0; padding: 0; list-style: none; }
.foot li { margin-bottom: .4rem; }
.foot a { color: var(--dim); text-decoration: none; font-size: 14.5px; }
.foot a:hover { color: var(--text); }
.foot__bottom { margin-top: 2.2rem; padding-top: 1.2rem; border-top: 1px solid var(--hair);
                display: flex; flex-wrap: wrap; gap: .5rem 1.3rem; align-items: center;
                font-size: 13px; color: var(--dimmer); }

/* Anything still waiting on the client. Deliberately loud, so it can never be
   mistaken for copy and can never reach a live page unnoticed. */
/* Things still needed from the client.

   These were red, which is the brand accent -- so they read as part of the
   design rather than as gaps, which is the opposite of their job. Electric
   yellow belongs to nothing else on the site, so it can only mean "this is
   missing".

   Filled rather than outlined, and black on yellow rather than yellow on the
   page: yellow type would be unreadable on the light theme's white, whereas a
   solid yellow chip with black text is 16:1 and identical in both themes,
   because it stops depending on the background behind it. */
.todo {
  font-family: var(--mono); font-size: .9em; font-weight: 700;
  background: #f2e600; color: #000;
  border: 1px dashed #8a7d00; border-radius: 0;
  padding: .05em .4em;
  /* Not nowrap. A long marker like "HOW LONG DETAILING? ANY TRAINING/CERTS?"
     then sets a min-content width its grid column cannot shrink below, and the
     whole page scrolls sideways on a phone -- while he is showing it to the
     client on a phone. */
  overflow-wrap: break-word;
}

:where(a, button, input, select, textarea):focus-visible {
  outline: 2px solid var(--red-hot); outline-offset: 2px;
}

/* -------------------------------------------------------------- responsive */
@media (max-width: 900px) {
  .hero { grid-template-columns: 1fr; }
  .hero__txt { border-right: 0; border-bottom: 1px solid var(--line); }
  .readout { grid-template-columns: 1fr 1fr; }
  .readout div:nth-child(2) { border-right: 0; }
  .pkgs, .pkgs--three, .contact, .split { grid-template-columns: 1fr; }
  .foot__in { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 720px) {
  .nav {
    position: fixed; inset: 60px 0 auto; flex-direction: column; gap: 0;
    background: var(--bg); border-bottom: 1px solid var(--line);
    padding: .4rem var(--gutter) 1rem; margin: 0; display: none;
  }
  .nav[data-open="true"] { display: flex; }
  .nav a { padding: .7rem 0; font-size: 15px; }
  .nav a[aria-current="page"]::after { width: 20px; }
  .burger { display: grid; }
  .top__loc { display: none; }
  .ba { grid-template-columns: 1fr; }
  .foot__in { grid-template-columns: 1fr; gap: 1.7rem; }
}


/* ==========================================================================
   AGGRESSIVE PASS
   The client asked for "clean, modern and aggressive". Aggression here comes
   from weight, contrast, hard edges and red used structurally -- red blocks,
   red rules, red fills. Not from texture, bevels, gradients or glow, which is
   where detailing sites usually end up and what makes them look cheap.
   ========================================================================== */

/* A section label is now a red block with black text: it reads as a stamp
   rather than a whisper, and it is the loudest thing after the headline. */
.k--block {
  display: inline-block; background: var(--red); color: #000;
  padding: .3rem .6rem .25rem; font-weight: 500; letter-spacing: .16em;
  /* fit-content because these sit in both flex columns and block containers,
     and in either one the default is to stretch the full width -- which turns
     a stamp into a banner. */
  width: fit-content;
}
[data-theme="light"] .k--block { color: #fff; }
.sec__head .k--block, .phead .k--block { margin-bottom: .2rem; }

/* Structural rules, not hairlines, where a section begins. */
.hero, .readout { border-bottom-width: 2px; }
.readout { border-top: 2px solid var(--red); }
.readout b { font-weight: 900; text-transform: uppercase; letter-spacing: -.02em;
             font-size: 1.15rem; }

/* Buttons get weight and lose their softness. The primary is a solid red
   slab; the secondary inverts on hover rather than politely tinting. */
.btn { font-weight: 500; border-width: 2px; padding: .8rem 1.3rem; }
.btn:hover { border-color: var(--text); background: var(--text); color: var(--bg); }
.btn--red { border-color: var(--red); }
.btn--red:hover { background: var(--red-hot); border-color: var(--red-hot); color: #fff; }

/* The one angled element on the site. A single skew reads as speed; a page
   full of them reads as a car dealership. */
.hero__txt { position: relative; overflow: hidden; }
.hero__txt::after {
  content: ""; position: absolute; right: -40px; top: 0; bottom: 0; width: 26px;
  background: var(--red); transform: skewX(-12deg); opacity: .9;
}
@media (max-width: 900px) { .hero__txt::after { display: none; } }

/* Headings sit tighter to what they label. */
.sec__head h2 { margin-top: .55rem; }
.pkg__top h3, .ba figcaption, .gal figcaption { letter-spacing: .02em; }

/* Package headers carry their own weight. */
.pkg__top { border-bottom-width: 2px; }
.pkg .price { font-weight: 500; }

/* Before/after labels become stamps too, and the AFTER is a solid red block:
   it is the whole argument of the section. */
.ba figcaption { background: var(--bg); border-width: 2px; font-weight: 500; }
.ba .after figcaption { background: var(--red); color: #000; border-color: var(--red); }
[data-theme="light"] .ba .after figcaption { color: #fff; }


/* ==========================================================================
   PHYSICAL PASS
   The keepers from the chrome experiment, and only the keepers.

   In:  red bloom on the things you click and the things that stamp, a low
        carbon weave for texture, and a slight bevel so panels feel like
        objects rather than rectangles.
   Out: the metallic gradient headline. It dated the whole page, cost real
        contrast through the middle of every letter, turned to mud at phone
        sizes, and competed with the photography -- which on a detailing site
        has to win.
   ========================================================================== */

/* Texture, not a texture effect. He asked for the weave to "pop slightly
   more", so it went from 1.8% to 3.2% on dark and 2.2% to 3.6% on light --
   roughly doubled, still under 4%.
   Raised this far and no further on purpose: past about 5% the diagonals stop
   being a surface and become a pattern, they crawl against the eye as you
   scroll on a phone, and they start competing with the photographs, which on a
   detailing site have to win. If he wants it louder again, raise both numbers
   together rather than one, or the two themes drift apart. */
body {
  background-image:
    repeating-linear-gradient(45deg,  rgba(255,255,255,.032) 0 2px, transparent 2px 4px),
    repeating-linear-gradient(-45deg, rgba(255,255,255,.032) 0 2px, transparent 2px 4px),
    radial-gradient(120% 70% at 50% 0%, #131318 0%, var(--bg) 62%);
}
[data-theme="light"] body {
  background-image:
    repeating-linear-gradient(45deg,  rgba(0,0,0,.036) 0 2px, transparent 2px 4px),
    repeating-linear-gradient(-45deg, rgba(0,0,0,.036) 0 2px, transparent 2px 4px),
    radial-gradient(120% 70% at 50% 0%, #ffffff 0%, #f0f0f2 70%);
}

/* The primary action glows and sits slightly proud. It is the one thing on
   the page that should look like a physical button. */
.btn.btn--red {
  background-color: var(--red);
  background-image: linear-gradient(180deg, #ff4a5b 0%, var(--red) 18%, var(--red-deep, #b20a18) 100%);
  box-shadow: 0 0 20px rgba(255, 26, 46, .45),
              inset 0 1px 0 rgba(255,255,255,.45),
              inset 0 -2px 0 rgba(0,0,0,.4);
  text-shadow: 0 1px 2px rgba(0,0,0,.4);
  border-color: #ff5f6e;
}
.btn.btn--red:hover {
  box-shadow: 0 0 32px rgba(255, 26, 46, .75),
              inset 0 1px 0 rgba(255,255,255,.55),
              inset 0 -2px 0 rgba(0,0,0,.4);
}

/* Stamps get the same treatment: they are the loudest red on the page after
   the button, so they carry the same physicality. */
.k--block {
  background-color: var(--red);
  background-image: linear-gradient(180deg, #ff4a5b 0%, var(--red) 18%, #b20a18 100%);
  color: #fff;
  box-shadow: 0 0 16px rgba(255, 26, 46, .38),
              inset 0 1px 0 rgba(255,255,255,.4),
              inset 0 -1px 0 rgba(0,0,0,.35);
  text-shadow: 0 1px 2px rgba(0,0,0,.45);
}
[data-theme="light"] .k--block { color: #fff; }

/* The AFTER label is an argument, so it stamps like one. */
.ba .after figcaption {
  background-color: var(--red);
  background-image: linear-gradient(180deg, #ff4a5b 0%, var(--red) 18%, #b20a18 100%);
  color: #fff; border-color: #ff5f6e;
  box-shadow: 0 0 14px rgba(255, 26, 46, .45);
  text-shadow: 0 1px 2px rgba(0,0,0,.45);
}
[data-theme="light"] .ba .after figcaption { color: #fff; }

/* The rule under the hero glows rather than sitting flat. */
.readout { box-shadow: 0 -1px 16px rgba(255, 26, 46, .3); }
.hero__txt::after { box-shadow: 0 0 22px rgba(255, 26, 46, .5); }

/* A slight bevel so panels read as objects. Deliberately faint: enough to
   catch the light, not enough to notice as an effect. */
.pkg, .addons, .contact > div, .rev-form {
  box-shadow: inset 0 1px 0 rgba(255,255,255,.07), inset 0 -1px 0 rgba(0,0,0,.45);
  background-image: linear-gradient(180deg, rgba(255,255,255,.035), transparent 40%);
}
[data-theme="light"] .pkg, [data-theme="light"] .addons,
[data-theme="light"] .contact > div, [data-theme="light"] .rev-form {
  box-shadow: inset 0 1px 0 rgba(255,255,255,.85), inset 0 -1px 0 rgba(0,0,0,.1);
  background-image: linear-gradient(180deg, rgba(255,255,255,.7), transparent 45%);
}

/* Photographs get a hairline inner edge so they sit in the grid rather than
   floating on it. */
.hero__img, .ba figure, .gal figure { box-shadow: inset 0 0 0 1px rgba(255,255,255,.08); }
[data-theme="light"] .hero__img, [data-theme="light"] .ba figure,
[data-theme="light"] .gal figure { box-shadow: inset 0 0 0 1px rgba(0,0,0,.08); }

/* For headings that exist to keep the document outline intact without being
   shown. Clipped rather than display:none, so screen readers still read it. */
.visually-hidden {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
