/* ==========================================================================
   COMPONENTS — buttons, media, cards, shell (header / mobile bar / footer)
   ========================================================================== */

/* --- BUTTONS ------------------------------------------------------------ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-height: var(--tap-min);
  padding: var(--sp-3) var(--sp-5);
  border-radius: var(--radius);
  font-family: var(--font-label);
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  text-align: center;
  text-wrap: balance;
  transition:
    background-color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out),
    transform var(--dur-fast) var(--ease-out);
}

.btn__arrow {
  transition: transform var(--dur-fast) var(--ease-out);
}

.btn:hover .btn__arrow { transform: translateX(4px); }

.btn--primary {
  background: var(--accent);
  color: #FFFFFF;
}

.btn--primary:hover {
  background: var(--accent-deep);
  transform: translateY(-2px);
}

/* default: light-on-dark — the vast majority of the site is dark now */
.btn--secondary {
  border: var(--hairline) solid rgba(255, 255, 255, 0.3);
  color: var(--paper);
}

.btn--secondary:hover {
  border-color: var(--paper);
  background: rgba(255, 255, 255, 0.06);
}

/* .on-light lives in base.css/pages.css, but this override belongs here
   next to .btn--secondary itself — and, crucially, in components.css so it
   loads on every page (index.html does not load pages.css). */
.on-light .btn--secondary {
  border-color: rgba(11, 11, 13, 0.25);
  color: var(--ink);
}

.on-light .btn--secondary:hover {
  border-color: var(--ink);
  background: rgba(11, 11, 13, 0.05);
}

/* outlined-red variant — used for the header "BOKA VISNING" CTA per the
   approved layout: a quiet, precise outline, not another solid red block */
.btn--outline-accent {
  border: var(--hairline) solid var(--accent);
  color: var(--paper);
}

.btn--outline-accent:hover {
  background: var(--accent);
  color: #FFFFFF;
}

.btn--lg {
  min-height: 60px;
  padding: var(--sp-4) var(--sp-6);
  font-size: var(--fs-spec);
}

/* Text link with drawn underline */
.tlink {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  position: relative;
  min-height: 44px;
  padding-block: var(--sp-2);
  font-family: var(--font-label);
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
}

.tlink::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: var(--hairline);
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur-fast) var(--ease-out);
}

.tlink:hover::after { transform: scaleX(1); }
.tlink:hover .btn__arrow { transform: translateX(4px); }

/* --- MEDIA + PLACEHOLDERS ---------------------------------------------- *
   Every image slot degrades to an unmistakable, clearly-labelled placeholder.
   No stock photography anywhere in this build.
   ------------------------------------------------------------------------ */

.media {
  position: relative;
  overflow: hidden;
  background: var(--ink-raised);
}

.media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--dur-mid) var(--ease-out);
}

.media--hoverable:hover img { transform: scale(1.04); }

/* Placeholders are art-directed frame specs, not wireframe boxes.
   Each one carries a modelled light source so the intended photographic
   composition and tonal range read before any real image exists.        */

/* --- IMAGE SLOT ------------------------------------------------------------
   What a visitor sees when a slot has no photograph yet. It must read as a
   deliberate brand plate, not as scaffolding.

   Previously this drew four red "registration tick" corners and printed the
   aspect ratio, a [CLIENT CONTENT REQUIRED] tag and the photographer's shot
   brief. The two text rules even contradicted each other — .ph__note was set
   to display:none and then re-declared display:block further down, so the
   briefing text won and rendered live on category pages. All of that markup
   is gone now (see build.py ph()); what remains is a quiet dark panel
   carrying the logo mark, which looks intentional wherever it appears.
   -------------------------------------------------------------------------- */

.ph {
  --ph-light-x: 32%;
  --ph-light-y: 26%;

  position: relative;
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
  min-height: 180px;
  padding: var(--sp-5);
  overflow: hidden;
  background-color: var(--ink-raised);
  background-image:
    radial-gradient(
      ellipse 78% 66% at var(--ph-light-x) var(--ph-light-y),
      rgba(255, 255, 255, 0.075) 0%,
      rgba(255, 255, 255, 0.022) 44%,
      transparent 70%
    ),
    linear-gradient(158deg, #1B1B1F 0%, #121215 54%, #0A0A0C 100%);
}

/* a single hairline across the foot of the plate — the same quiet red
   detail as the sill line in the logo and the rule above section eyebrows,
   so the plate belongs to the same system as everything else */
.ph::after {
  content: '';
  position: absolute;
  left: var(--sp-5);
  right: var(--sp-5);
  bottom: var(--sp-5);
  height: 1px;
  background: var(--accent);
  opacity: 0.3;
}

.ph__mark {
  display: block;
  line-height: 0;
  width: min(38%, 150px);
  opacity: 0.45;
}

/* full-bleed frames (page heroes, wide breaks) are far larger than a card,
   so the mark must not scale with them — it stays a quiet detail */
.phero .ph__mark,
.ph--hero .ph__mark,
.mbreak .ph__mark { width: min(18%, 132px); opacity: 0.3; }

.phero .ph::after,
.ph--hero .ph::after,
.mbreak .ph::after { opacity: 0.18; }

.ph__mark svg { width: 100%; height: auto; }

/* legacy briefing nodes — removed from markup, kept neutralised so any
   stale cached HTML cannot render them */
.ph__meta,
.ph__note,
.ph__ratio,
.ph__tag { display: none !important; }

/* light-source variants — give each frame its own tonal character */
.ph--light-tl { --ph-light-x: 24%; --ph-light-y: 22%; }
.ph--light-tr { --ph-light-x: 74%; --ph-light-y: 24%; }
.ph--light-c  { --ph-light-x: 50%; --ph-light-y: 42%; }
.ph--light-bl { --ph-light-x: 26%; --ph-light-y: 72%; }
.ph--light-br { --ph-light-x: 72%; --ph-light-y: 68%; }

/* paper frame — reserved for slots living inside a light section */
.ph--paper {
  background-color: #EAEAEC;
  background-image:
    radial-gradient(
      ellipse 76% 64% at var(--ph-light-x) var(--ph-light-y),
      rgba(255, 255, 255, 0.85) 0%,
      transparent 66%
    ),
    linear-gradient(158deg, #F2F2F4 0%, #E4E4E8 100%);
}

.ph--paper .ph__mark { opacity: 0.62; }

/* hero frame — deeper, more cinematic falloff (full-bleed, always under a scrim) */
.ph--hero {
  --ph-light-x: 62%;
  --ph-light-y: 34%;
  background-image:
    radial-gradient(
      ellipse 82% 78% at var(--ph-light-x) var(--ph-light-y),
      rgba(255, 255, 255, 0.14) 0%,
      rgba(255, 255, 255, 0.04) 40%,
      transparent 72%
    ),
    repeating-linear-gradient(
      -45deg,
      transparent 0 17px,
      rgba(255, 255, 255, 0.016) 17px 18px
    ),
    linear-gradient(155deg, #1A1A1D 0%, #101012 48%, #000000 100%);
}

/* --- VEHICLE CARD ------------------------------------------------------- */

.vcard { display: flex; flex-direction: column; }

.vcard__media { aspect-ratio: 4 / 3; margin-bottom: var(--sp-4); }

.vcard__name {
  font-family: var(--font-body);
  font-size: 1.25rem;
  font-weight: 600;
  letter-spacing: -0.005em;
  line-height: 1.2;
  margin-bottom: var(--sp-3);
}

.vcard__spec {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-3);
  padding-top: var(--sp-3);
  border-top: var(--hairline) solid var(--paper-hairline);
}

.vcard__price {
  font-family: var(--font-label);
  font-size: var(--fs-spec);
  letter-spacing: var(--tr-spec);
  color: var(--accent);
  margin-top: var(--sp-2);
}

.vcard__cta { margin-top: var(--sp-4); align-self: flex-start; }

/* --- HEADER -------------------------------------------------------------- *
   Dark glass, fixed. The site is dark-first now, so a dark translucent bar
   reads correctly over almost everything (hero photo, dark sections, and
   even the two light .on-light pages, the same way the dark footer already
   grounds light content above it).
   Layout: logo left · nav center · phone + outlined CTA right.
   ------------------------------------------------------------------------ */

.header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: var(--z-header);
  background: rgba(11, 11, 13, 0.86);
  backdrop-filter: blur(10px);
  border-bottom: var(--hairline) solid var(--ink-hairline);
  transition: box-shadow var(--dur-mid) var(--ease-out);
}

.header.is-stuck { box-shadow: 0 4px 28px rgba(0, 0, 0, 0.35); }

.header__inner {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: var(--sp-4);
  min-height: 72px;
}

.wordmark {
  display: inline-flex;
  align-items: center;
  padding-block: 10px;
  color: var(--paper);
}

.nav { display: none; justify-content: center; }

.nav__list {
  display: flex;
  align-items: center;
  gap: var(--sp-5);
}

.nav__item { position: relative; }

.nav__link {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding-block: 15px;
  font-family: var(--font-label);
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  color: var(--paper-dim);
  transition: color var(--dur-fast) var(--ease-out);
}

.nav__link:hover,
.nav__link[aria-current='page'] { color: var(--paper); }

.nav__trigger { background: none; border: 0; cursor: pointer; }

.nav__chevron { width: 10px; height: 10px; transition: transform var(--dur-fast) var(--ease-out); }
.nav__trigger[aria-expanded='true'] .nav__chevron { transform: rotate(180deg); }

.nav__dropdown {
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translate(-50%, 6px);
  z-index: var(--z-dropdown);
  display: flex;
  flex-direction: column;
  min-width: 208px;
  padding: var(--sp-2);
  background: var(--ink-raised);
  border: var(--hairline) solid var(--ink-hairline);
  border-radius: var(--radius);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.4);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out), visibility var(--dur-fast);
}

.nav__item--dropdown:hover .nav__dropdown,
.nav__dropdown.is-open {
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, 0);
}

.nav__dropdown-link {
  display: block;
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--radius-sm);
  font-family: var(--font-body);
  font-size: var(--fs-body-s);
  color: var(--paper-dim);
  transition: background-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}

.nav__dropdown-link:hover { background: var(--ink-elevated); color: var(--paper); }

.header__right { display: flex; align-items: center; gap: var(--sp-4); justify-content: flex-end; }

.header__phone {
  display: none;
  align-items: center;
  gap: var(--sp-2);
  min-height: 44px;
  font-family: var(--font-body);
  font-size: var(--fs-body-s);
  font-weight: 500;
  color: var(--paper);
}

.header__phone svg { width: 16px; height: 16px; stroke: var(--accent); fill: none; }

.header__cta { display: none; }

@media (min-width: 1024px) {
  .nav,
  .header__phone { display: flex; }
  .header__cta { display: inline-flex; }
}

/* The desktop header is a single 72px row and must stay one. Measured at
   1024px after the service was renamed from "Tuningchip" to
   "Motoroptimering" (2026-09-16): the longer nav label pushed the row to
   90px and broke the phone number onto two lines.
   Two parts to the fix, both narrow:
     1. the nav labels and the phone number never wrap — they are single
        tokens and wrapping them is always wrong, at any width;
     2. between 1024 and 1199, where it is genuinely tight, the nav gap, the
        right-hand gap and the logo tighten slightly.
   The CTA button deliberately still wraps to two lines: forcing it onto one
   makes it 200px wide and it runs past the container edge at 1024. */
.nav__link,
.header__phone { white-space: nowrap; }

@media (min-width: 1024px) and (max-width: 1199px) {
  .nav__list { gap: var(--sp-4); }
  .header__right { gap: var(--sp-3); }
  /* the matching logo step-down lives with the other .header .logo widths */
}

/* --- MOBILE MENU -------------------------------------------------------- */

.menu-toggle {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: var(--tap-min);
  height: var(--tap-min);
  align-items: flex-end;
}

.menu-toggle span {
  display: block;
  width: 22px;
  height: 1px;
  background: var(--paper);
  transition: transform var(--dur-fast) var(--ease-out),
              opacity var(--dur-fast) var(--ease-out);
}

.menu-toggle[aria-expanded='true'] span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.menu-toggle[aria-expanded='true'] span:nth-child(2) { opacity: 0; }
.menu-toggle[aria-expanded='true'] span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

@media (min-width: 1024px) {
  .menu-toggle { display: none; }
}

.menu {
  position: fixed;
  inset: 0;
  z-index: var(--z-menu);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  overflow-y: auto;
  padding: 96px var(--gutter) calc(var(--mobilebar-h) + var(--sp-6));
  background: var(--ink);
  color: var(--paper);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--dur-mid) var(--ease-out), visibility var(--dur-mid);
}

.menu.is-open { opacity: 1; visibility: visible; }

.menu__list { display: flex; flex-direction: column; gap: var(--sp-1); }

.menu__link {
  display: block;
  padding-block: var(--sp-3);
  font-family: var(--font-display);
  font-size: 2rem;
  font-weight: 700;
  letter-spacing: 0;
  border-bottom: var(--hairline) solid var(--ink-hairline);
}

.menu__sublist {
  display: flex;
  flex-direction: column;
  padding-left: var(--sp-4);
  border-bottom: var(--hairline) solid var(--ink-hairline);
}

.menu__sublink {
  display: block;
  padding-block: var(--sp-2);
  font-family: var(--font-body);
  font-size: 1.125rem;
  color: var(--paper-dim);
}

.menu__sublink[aria-current='page'] { color: var(--paper); }

.menu__foot { display: flex; flex-direction: column; gap: var(--sp-3); margin-top: var(--sp-5); }

.menu__phone {
  display: inline-block;
  padding-block: var(--sp-1);
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-weight: 700;
}

/* --- FIXED MOBILE ACTION BAR ------------------------------------------- *
   Three equal zones. Hairline-divided, not a chrome nav bar.
   ------------------------------------------------------------------------ */

.actionbar {
  position: fixed;
  inset: auto 0 0 0;
  z-index: var(--z-mobilebar);
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  /* min-height rather than height, plus the safe-area inset: on an iPhone the
     bar sits under the home indicator, and a fixed 60px put its labels
     behind it. The bar now grows into that strip instead. */
  min-height: var(--mobilebar-h);
  padding-bottom: env(safe-area-inset-bottom, 0px);
  background: rgba(11, 11, 13, 0.94);
  backdrop-filter: blur(10px);
  border-top: var(--hairline) solid var(--ink-hairline);
  transform: translateY(100%);
  transition: transform var(--dur-mid) var(--ease-out);
}

.actionbar.is-visible { transform: none; }

.actionbar__item {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  font-family: var(--font-label);
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  color: var(--paper);
}

.actionbar__item + .actionbar__item {
  border-left: var(--hairline) solid var(--ink-hairline);
}

.actionbar__item svg { width: 15px; height: 15px; stroke: currentColor; fill: none; }

.actionbar__item--accent { color: var(--accent); }

@media (min-width: 768px) {
  .actionbar { display: none; }
}

/* --- FOOTER ------------------------------------------------------------- */

.footer {
  background: var(--ink);
  color: var(--paper);
  padding-top: var(--section-y);
  padding-bottom: var(--sp-6);
}

/* --- SOCIAL LINKS --------------------------------------------------------
   Real icons (not emoji), square touch targets. Default styled for the
   dark surfaces that host them everywhere except the two light pages.
   -------------------------------------------------------------------------- */

.social-links {
  display: flex;
  gap: var(--sp-3);
  margin-top: var(--sp-2);
}

.social-links__item {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--tap-min);
  height: var(--tap-min);
  border-radius: var(--radius-sm);
  border: var(--hairline) solid var(--ink-hairline);
  color: var(--paper-dim);
  transition: border-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out), background-color var(--dur-fast) var(--ease-out);
}

.social-links__item svg { width: 19px; height: 19px; stroke: currentColor; fill: none; }

.social-links__item:hover {
  border-color: var(--accent);
  color: var(--accent);
  background: var(--accent-tint);
}

.on-light .social-links__item {
  border-color: var(--paper-hairline);
  color: var(--graphite);
}

.footer__top {
  display: grid;
  gap: var(--sp-7);
  margin-bottom: var(--sp-8);
}

.footer__top > * { min-width: 0; }

.footer__logo {
  display: inline-flex;
  width: 100%;
  font-size: clamp(0.8rem, 2.4vw, 1.35rem);
  margin-bottom: var(--sp-5);
}

.footer__call {
  font-family: var(--font-display);
  font-size: var(--fs-display-m);
  font-weight: 700;
  letter-spacing: 0;
  display: inline-block;
  transition: color var(--dur-fast) var(--ease-out);
}

.footer__call:hover { color: var(--accent); }

.footer__email {
  display: inline-block;
  margin-top: var(--sp-2);
  font-size: var(--fs-body);
  color: var(--paper-dim);
  transition: color var(--dur-fast) var(--ease-out);
}

.footer__email:hover { color: var(--paper); }

/* minmax(0, 1fr), not 1fr: a plain 1fr track refuses to shrink below its
   content's min-content width, so one long unbreakable service name
   ("Fordonsanskaffning") pushed the whole footer grid ~1px past the viewport
   at exactly 768px. Measured 2026-09-16. */
.footer__cols {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-6) var(--sp-4);
}

.footer__list { display: flex; flex-direction: column; gap: var(--sp-2); margin-top: var(--sp-3); }

.footer__list a {
  display: inline-block;
  overflow-wrap: break-word;
  padding-block: 5px;
  font-size: var(--fs-body-s);
  color: var(--paper-dim);
  transition: color var(--dur-fast) var(--ease-out);
}

.footer__list a:hover { color: var(--paper); }

.footer__addr {
  font-size: var(--fs-body-s);
  color: var(--paper-dim);
  font-style: normal;
  margin-top: var(--sp-3);
  line-height: 1.7;
}

/* The footer splits into brand | links only from 1024px. It used to split at
   768px, which left the three link columns sharing ~296px — about 82px per
   column. That was survivable while "Tjänster" held one short link; with the
   full service list (2026-09-16) "Motoroptimering" no longer fits its track
   and the columns overlapped. Below 1024 the brand block now takes its own
   full-width row and the three columns get the whole container. */
@media (min-width: 768px) {
  .footer__cols { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (min-width: 1024px) {
  .footer__top { grid-template-columns: 1fr 1fr; gap: var(--sp-8); }
}

/* --- CONCEPT IMAGERY ---------------------------------------------------- *
   Temporary presentation layer. A filled frame drops its placeholder
   scaffolding entirely so the client sees the finished visual, and carries
   only a discreet corner chip identifying it as concept work.
   ------------------------------------------------------------------------ */

.ph--filled {
  padding: 0;
  background: var(--ink-raised);
}

.ph--filled::before { display: none; }

.concept-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  /* unifies mixed-source imagery into the Nordic Garage tonality */
  filter: saturate(0.92) contrast(1.04) brightness(0.98);
  transition: transform var(--dur-mid) var(--ease-out);
}

.media--hoverable:hover .concept-img,
.world:hover .concept-img { transform: scale(1.04); }

/* ==========================================================================
   SHARED SECTION COMPONENTS
   These appear on the homepage AND on interior pages (Fordon hub, the four
   category pages, Kontakt), so they must live here rather than in home.css —
   interior pages do not load home.css.
   ========================================================================== */

/* --- 03 FEATURED VEHICLES ---------------------------------------------- *
   Hidden entirely unless real client vehicle data exists in config.js
   ------------------------------------------------------------------------ */

.featured__grid {
  display: grid;
  gap: var(--sp-6);
}

@media (min-width: 768px) {
  .featured__grid { grid-template-columns: repeat(2, 1fr); }
}

@media (min-width: 1024px) {
  .featured__grid { grid-template-columns: repeat(3, 1fr); gap: var(--sp-6) var(--sp-4); }
}

/* --- 04 BLOCKET BAND ---------------------------------------------------- *
   Tonal inversion. The strongest transition on the page. No imagery.
   ------------------------------------------------------------------------ */

.blocket {
  background: var(--ink);
  color: var(--paper);
}

.blocket__inner {
  display: flex;
  flex-direction: column;
  gap: var(--sp-6);
}

.blocket .spec { color: var(--paper-dim); }

.blocket__head { display: flex; flex-direction: column; gap: var(--sp-4); }

.blocket__title {
  font-family: var(--font-display);
  font-size: var(--fs-display-l);
  font-weight: 700;
  letter-spacing: var(--tr-display-l);
  line-height: 1.05;
  text-transform: uppercase;
  max-width: 16ch;
}

.blocket__lead {
  font-size: var(--fs-body-l);
  color: var(--paper-dim);
  max-width: 42ch;
}

@media (min-width: 900px) {
  .blocket__inner {
    flex-direction: row;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--sp-8);
  }
  .blocket__actions { padding-bottom: var(--sp-1); }
}

.location__addr {
  font-style: normal;
  font-size: var(--fs-body-l);
  line-height: 1.5;
}

.location__map {
  aspect-ratio: 4 / 3;
  min-height: 260px;
  border: var(--hairline) solid var(--paper-hairline);
}

@media (min-width: 900px) {
  .location__map { aspect-ratio: 16 / 10; }
}

/* ==========================================================================
   V2 ADDITIONS — light system components
   ========================================================================== */

/* --- HEADER NAV CTA ------------------------------------------------------ */

.btn--nav-cta { min-height: 44px; padding: var(--sp-2) var(--sp-4); }

/* --- CARD SHELL ----------------------------------------------------------
   Shared light-card treatment: vehicle cards, review cards, trust points.
   -------------------------------------------------------------------------- */

.card {
  background: var(--paper);
  border: var(--hairline) solid var(--paper-hairline);
  border-radius: var(--radius);
  transition: border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}

/* No lift, no drop shadow — the rest of the system is flat and precise, and
   a floating card reads like a SaaS dashboard. Hover moves the border to the
   accent instead, which is the same signal the buttons and links use. */
.card:hover { border-color: var(--accent); }

.vcard.card { padding: var(--sp-4); }
.vcard .vcard__media { border-radius: var(--radius-sm); margin-bottom: var(--sp-4); }

/* --- REVIEWS --------------------------------------------------------------
   Structured to accept real Google Places data later — see js/config.js
   "reviews". Until then it renders clearly-labelled sample content, never
   presented as published customer data.
   -------------------------------------------------------------------------- */

.reviews__head {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  margin-bottom: var(--sp-6);
}

.reviews__rating {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  flex-wrap: wrap;
}

.reviews__stars { display: inline-flex; gap: 2px; }
.reviews__stars svg { width: 16px; height: 16px; fill: var(--accent); }
.reviews__stars svg.is-empty { fill: var(--paper-hairline); }

.reviews__sample-note {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  background: var(--accent-tint);
  border: var(--hairline) dashed var(--accent);
  border-radius: var(--radius-sm);
  font-family: var(--font-label);
  font-size: var(--fs-label);
  letter-spacing: 0.03em;
  color: var(--accent-deep);
  max-width: 62ch;
}

.reviews__grid {
  display: grid;
  gap: var(--sp-4);
}

@media (min-width: 768px) {
  .reviews__grid { grid-template-columns: repeat(3, 1fr); }
}

.review {
  padding: var(--sp-5);
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  position: relative;
}

.review__stars { display: inline-flex; gap: 2px; }
.review__stars svg { width: 14px; height: 14px; fill: var(--accent); }

.review__text { font-size: var(--fs-body-s); line-height: 1.6; color: var(--ink); }

.review__foot {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-3);
  padding-top: var(--sp-3);
  border-top: var(--hairline) solid var(--paper-hairline);
}

.review__name { font-family: var(--font-body); font-weight: 600; font-size: var(--fs-body-s); }
.review__date { font-family: var(--font-label); font-size: var(--fs-label); color: var(--graphite); }

.review__source {
  display: block;
  margin-top: var(--sp-2);
  font-family: var(--font-label);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--graphite);
  opacity: 0.75;
}

.review__sample-chip {
  position: absolute;
  top: var(--sp-3);
  right: var(--sp-3);
  padding: 3px 7px;
  font-family: var(--font-label);
  font-size: 9px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent-deep);
  background: var(--accent-tint);
  border-radius: var(--radius-sm);
}

/* --- SOLD VEHICLES ("Sålda fordon") ---------------------------------------
   Social proof, not clearance stock — large image, one quiet badge, no
   red "SOLD" sticker. Same shell on the homepage teaser and the full
   /fordon/salda/ archive (js/main.js initSoldVehicles).
   -------------------------------------------------------------------------- */

.sold__grid {
  display: grid;
  gap: var(--sp-5);
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
}

.soldcard { display: flex; flex-direction: column; gap: var(--sp-3); }

.soldcard__media {
  position: relative;
  aspect-ratio: 4 / 5;
  border-radius: var(--radius);
}

.soldcard__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--dur-mid) var(--ease-out);
}

.soldcard:hover .soldcard__media img { transform: scale(1.03); }

.soldcard__badge {
  position: absolute;
  top: var(--sp-3);
  left: var(--sp-3);
  padding: 4px 10px;
  font-family: var(--font-label);
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  color: var(--paper);
  background: rgba(28, 26, 23, 0.72);
  backdrop-filter: blur(4px);
  border-radius: var(--radius-sm);
}

.soldcard__body { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-2); }

.soldcard__title { font-family: var(--font-body); font-weight: 600; font-size: var(--fs-body-l); }
.soldcard__cat { font-family: var(--font-label); font-size: var(--fs-label); color: var(--graphite); text-transform: uppercase; letter-spacing: var(--tr-label); }

/* --- LOGO COMPONENT --------------------------------------------------------
   The one approved lockup, matched directly against the client's reference
   screenshot (see dev/logo/index.html): mark STACKED above the wordmark,
   above a rule-flanked "SWEDEN" line — not the old side-by-side layout.
   The mark is a flat red (--accent, baked into LOGO_MARK in build.py) —
   deliberately not a gradient: the previous six-stop gradient turned to mud
   at navigation size.

/* --- LOGO ----------------------------------------------------------------
   The client's own supplied asset, used as-is. Only WIDTH is set anywhere —
   height follows from the intrinsic 4.176:1 ratio, so the artwork can never
   be stretched. Sizes are chosen per context, not scaled by font-size.
   -------------------------------------------------------------------------- */
.logo { display: block; line-height: 0; }

.logo__img {
  display: block;
  width: 100%;
  height: auto;
}

.logo picture { display: block; }

/* Header — 190px reads confidently against the 72px bar without crowding the
   phone number and CTA. */
.header .logo { width: 215px; }

/* Footer — a touch larger, it is the sign-off. */
.footer__logo { width: 265px; margin-bottom: var(--sp-5); }

/* 1024-1199: the desktop bar is on but there is the least room in it — the
   nav, the phone number and the CTA all have to fit beside the logo. 180px
   keeps the lockup confident and the row at 72px. See the header notes above. */
@media (min-width: 1024px) and (max-width: 1199px) {
  .header .logo { width: 180px; }
}

@media (max-width: 1023px) {
  /* Tablet and phone: the lockup steps down so it never competes with the
     menu button. Clamped rather than fixed so it cannot outgrow a narrow
     viewport at any width. */
  .header .logo { width: clamp(158px, 45vw, 195px); }
  .footer__logo { width: clamp(200px, 60vw, 265px); }
}

/* --- INQUIRY FORM ----------------------------------------------------------
   One reusable component, embedded wherever a förfrågan is needed
   (kontakt/, motoroptimering/). Progressive enhancement: valid, submittable
   plain HTML form even with JS disabled.
   -------------------------------------------------------------------------- */

.form {
  display: grid;
  gap: var(--sp-4);
  max-width: 640px;
}

.form__row { display: grid; gap: var(--sp-4); }

@media (min-width: 560px) {
  .form__row--2 { grid-template-columns: 1fr 1fr; }
}

.field { display: flex; flex-direction: column; gap: var(--sp-2); }

.field__label {
  font-family: var(--font-label);
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  color: var(--paper-dim);
}

.field__label .field__opt { text-transform: none; letter-spacing: 0; color: var(--paper-dim); opacity: 0.7; }

.field__input,
.field__select,
.field__textarea {
  width: 100%;
  min-height: var(--tap-min);
  padding: var(--sp-3);
  background: var(--ink-elevated);
  border: var(--hairline) solid var(--ink-hairline);
  border-radius: var(--radius-sm);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  color: var(--paper);
  transition: border-color var(--dur-fast) var(--ease-out);
}

.field__textarea { min-height: 128px; resize: vertical; }

.field__input:focus,
.field__select:focus,
.field__textarea:focus { border-color: var(--accent); outline: none; }

.field__select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 4.5 6 8l3.5-3.5' fill='none' stroke='%23B8B8BE' stroke-width='1.4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--sp-3) center;
  background-size: 12px 12px;
  padding-right: var(--sp-7);
}

.field__hint { font-size: var(--fs-body-s); color: var(--paper-dim); }

.on-light .field__label,
.on-light .field__label .field__opt,
.on-light .field__hint { color: var(--graphite); }

.on-light .field__input,
.on-light .field__select,
.on-light .field__textarea {
  background: var(--paper);
  border-color: var(--paper-hairline);
  color: var(--ink);
}

.on-light .field__select {
  /* the .on-light background SHORTHAND above resets repeat/position — the
     chevron tiled across the whole field until these were restated here */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 4.5 6 8l3.5-3.5' fill='none' stroke='%236B6B72' stroke-width='1.4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--sp-3) center;
  background-size: 12px 12px;
}

.field--conditional { display: none; }
.field--conditional.is-active { display: flex; }

.form__vehicle-note {
  padding: var(--sp-3) var(--sp-4);
  background: var(--accent-tint);
  border-radius: var(--radius-sm);
  font-size: var(--fs-body-s);
  color: var(--accent-deep);
}

.form__submit { margin-top: var(--sp-2); align-self: flex-start; }

.form__status {
  display: none;
  padding: var(--sp-4);
  border-radius: var(--radius-sm);
  font-size: var(--fs-body-s);
  line-height: 1.6;
}

.form__status.is-success {
  display: block;
  background: rgba(91, 168, 90, 0.12);
  border: var(--hairline) solid #5FAE5D;
  color: #8FD98D;
}

.form__status.is-error {
  display: block;
  background: rgba(214, 19, 44, 0.1);
  border: var(--hairline) solid var(--accent);
  color: var(--paper); /* readable error text; the one red stays on the border/wash */
}

.on-light .form__status.is-success { color: #2F5C2E; }
.on-light .form__status.is-error { color: var(--accent-deep); }

.form.is-submitted .form__fields { display: none; }

/* honeypot — hidden from sighted users and keyboard/AT alike */
.form__honeypot {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* ==========================================================================
   STATEMENT BAND · FACT PANEL · MAP CARD
   Three components that replace image frames the site cannot fill. Each is
   built from the system already in use — spec eyebrow, display face, the
   red hairline, the same spacing scale — so they read as designed sections
   rather than as gaps where a photograph should be.
   ========================================================================== */

/* --- STATEMENT BAND ------------------------------------------------------ */
/* This band is always dark, but it can sit on a page whose <body> or <main>
   carries .on-light — in which case the inherited text colour is dark and the
   headline would render dark-on-dark. It therefore sets its own colours
   explicitly rather than inheriting them. (Three separate invisible-text bugs
   on this site have come from exactly this; see README-HANDOFF.md.) */
.statement {
  border-block: 1px solid var(--ink-hairline);
  background:
    radial-gradient(ellipse 60% 120% at 50% 0%,
      rgba(214, 19, 44, 0.07) 0%, transparent 70%),
    var(--ink);
  color: var(--paper);
}

.statement .spec { color: var(--paper-dim); }
.statement .spec-rule::before,
.statement .spec-rule::after { background: var(--accent); }

.statement__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--sp-4);
}

.statement__line {
  font-family: var(--font-display);
  font-weight: 700;
  /* The longest single word ("FORDONSINTRESSE.") is wider than a 375px
     viewport's content box at the full display size — it rendered 372px wide
     inside a 335px column and ran past the gutter to both screen edges. The
     scale is capped by viewport width on small screens; from 480px up it is
     the normal display size again. */
  font-size: clamp(1.55rem, 8vw, var(--fs-display-l));
  line-height: 1.15;
  letter-spacing: var(--tr-display-l);
  text-transform: uppercase;
  text-wrap: balance;
  max-width: 24ch;
  color: var(--paper);
}

.statement__meta {
  color: var(--paper-dim);
  font-family: var(--font-label);
  font-size: var(--fs-spec);
  font-weight: 500;
  letter-spacing: var(--tr-spec);
  text-transform: uppercase;
  color: var(--paper-dim);
}

/* --- FACT PANEL ---------------------------------------------------------- */
/* Lives inside a light section, so it inverts. */
.factpanel {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  padding: var(--sp-5);
  background: var(--paper-raised);
  border: 1px solid var(--paper-hairline);
  border-top: 2px solid var(--accent);
  border-radius: var(--radius);
  aspect-ratio: auto;
}

.factpanel__list { display: flex; flex-direction: column; }

.factpanel__list li {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding-block: var(--sp-3);
  border-bottom: 1px solid var(--paper-hairline);
}

.factpanel__list li:last-child { border-bottom: 0; padding-bottom: 0; }

.factpanel__k {
  font-family: var(--font-label);
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  color: var(--accent-deep);
}

.factpanel__v {
  font-size: var(--fs-body);
  color: var(--ink);
  font-weight: 500;
}

@media (min-width: 768px) {
  .factpanel { padding: var(--sp-6); }
  .factpanel__list li { flex-direction: row; align-items: baseline; gap: var(--sp-4); }
  .factpanel__k { flex: 0 0 5.5rem; }
}

/* --- MAP CARD ------------------------------------------------------------ */
.mapcard {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  text-align: center;
  padding: var(--sp-6) var(--sp-4);
  background: var(--paper-raised);
  border: 1px solid var(--paper-hairline);
  border-radius: var(--radius);
}

.mapcard__pin { color: var(--accent); line-height: 0; }
.mapcard__pin svg { width: 28px; height: 28px; }

.mapcard__label {
  font-family: var(--font-label);
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  color: var(--graphite);
}

.mapcard__addr {
  font-size: var(--fs-body);
  font-weight: 500;
  color: var(--ink);
}

.mapcard .btn { margin-top: var(--sp-3); }

/* ==========================================================================
   RESPONSIVE + TOUCH CORRECTIONS
   Found by measuring the rendered page at 375px, not by eye.
   ========================================================================== */

/* The Blocket item in the mobile action bar used --accent as running text.
   #D6132C on the near-black bar is 3.74:1 — under the 4.5:1 required for
   text this small. The tokens file already says the red is for borders,
   icons and CTA fills, never small copy. The item keeps its red icon; the
   label goes to full-strength paper so it passes. */
.actionbar__item--accent { color: var(--paper); }
.actionbar__item--accent svg { color: var(--accent); }

@media (max-width: 1023px) {
  /* The full lockup at header size filled most of a 375px viewport and
     crowded the menu button. Clamped rather than fixed, so it cannot
     outgrow the viewport at any width — tracking and proportions are
     unchanged, only the overall size. */
  .header .logo { font-size: clamp(0.68rem, 2.9vw, 1rem); }

  /* Touch targets. Measured at 375px: footer and menu links were rendering
     26-38px tall against a 44px minimum. */
  .footer__list a,
  .menu__sublist a,
  .footer a[href^="mailto:"],
  .footer a[href^="tel:"] {
    display: flex;
    align-items: center;
    min-height: 44px;
  }

  /* breadcrumb links measured 31px */
  .crumbs a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }
}

/* --- EXTERNAL-LINK ARROW -------------------------------------------------
   Marks links that leave the site for Speedy's Blocket store. Sized in em so
   it tracks whatever it sits inside — nav link, button or footer link.
   -------------------------------------------------------------------------- */
.ext {
  display: inline-block;
  width: 0.7em;
  height: 0.7em;
  margin-left: 0.5em;
  flex: 0 0 auto;
  vertical-align: baseline;
  opacity: 0.75;
}

a:hover > .ext,
.btn:hover > .ext { opacity: 1; }

.nav__link--ext,
.menu__link--ext,
.footer__ext { display: inline-flex; align-items: center; }

/* Moved here from home.css: the vehicles list is used on BOTH the homepage
   and /om-oss/, and om-oss does not load home.css. Shared rules must live
   in components.css — this exact split has caused invisible-component bugs
   on this site before.
 */
/* --- VEHICLES → BLOCKET -------------------------------------------------- *
   Typographic on purpose. Speedy's live listing photography varies too much
   in light, season and camera to sit inside this art direction, and Blocket
   already does inventory properly — so this section states the four worlds
   and hands off, rather than pretending to be a gallery.
   ------------------------------------------------------------------------- */
.worlds__head { max-width: 46ch; }
.worlds__lead { margin-top: var(--sp-4); }

.worlds__list {
  display: grid;
  margin: var(--sp-7) 0;
  border-top: 1px solid var(--ink-hairline);
}

.worlds__item {
  display: flex;
  align-items: baseline;
  gap: var(--sp-4);
  padding: var(--sp-4) 0;
  border-bottom: 1px solid var(--ink-hairline);
}

.worlds__num {
  font-family: var(--font-label);
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: var(--tr-label);
  color: var(--paper-dim);
  flex: 0 0 auto;
}

.worlds__name {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-display-m);
  letter-spacing: var(--tr-display-m);
  text-transform: uppercase;
  line-height: 1.1;
  color: var(--paper);
}

.worlds__actions { display: flex; gap: var(--sp-3); flex-wrap: wrap; }

@media (min-width: 768px) {
  .worlds__list { grid-template-columns: repeat(2, 1fr); column-gap: var(--sp-7); }
  .worlds__item { padding: var(--sp-5) 0; }
}

@media (min-width: 1024px) {
  .worlds__list { grid-template-columns: repeat(4, 1fr); column-gap: var(--sp-5); }
  .worlds__item {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--sp-3);
    border-bottom: 0;
    border-top: 2px solid var(--accent);
    padding: var(--sp-4) 0 0;
  }
  .worlds__list { border-top: 0; }
}

/* --- LOGO VARIANT D ------------------------------------------------------
   Wordmark set in Saira at expanded width, NOT the heading face: a brand
   wordmark and website typography are separate problems, and Saira sits
   wider, lower and slightly more technical — closer to how automotive
   wordmarks are actually drawn. Saira is already wide, so it needs less
   letter-spacing than the Archivo lockup to read as broad.
   -------------------------------------------------------------------------- */
.logo--d .logo__word {
  font-family: 'Saira', 'Archivo', 'Helvetica Neue', Arial, sans-serif;
  font-stretch: expanded;
  font-weight: 600;
  font-size: 1.26em;
  letter-spacing: 0.085em;
  text-indent: 0.085em;
}

.logo--d .logo__sub {
  font-family: 'Saira', 'Archivo', Arial, sans-serif;
  font-stretch: expanded;
  font-weight: 500;
  font-size: 0.4em;
  letter-spacing: 0.34em;
  text-indent: 0.34em;
}

.logo--d .logo__mark svg { height: 1.5em; }

/* --- VIEWING LOCATIONS ----------------------------------------------------
   Two places customers can view vehicles. Built from the existing .label and
   address vocabulary — no new design language. Stacked on a phone, side by
   side from 768px where both fit without crowding.
   -------------------------------------------------------------------------- */
.visning {
  display: grid;
  gap: var(--sp-4);
  margin-block: var(--sp-4);
}

.visning__place {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding-top: var(--sp-3);
  border-top: 2px solid var(--accent);
}

.visning__addr {
  font-style: normal;
  font-size: var(--fs-body);
  line-height: 1.5;
  color: inherit;
}

.visning__place .tlink { align-self: flex-start; }

@media (min-width: 768px) {
  .visning { grid-template-columns: repeat(2, 1fr); gap: var(--sp-5); }
}

/* Two map cards share the grid cell the single card used to fill.
   -------------------------------------------------------------------------
   .mapstack is also .location__map, which is sized like a MAP FRAME:
   `aspect-ratio: 4 / 3` with a 260px floor. That is right for one embedded
   map; it is wrong for a stack of cards, and it was the cause of the
   overlapping sections reported on a phone on 2026-09-16.
   Measured at 390px before the fix: the container's own box was 263px tall
   while the two cards inside it ended 218px further down, so the next
   section ("Vad gäller det?") began on top of the Gävle card, and on the
   homepage the footer — logo and all — was painted over "Visa karta".
   A stack of cards must be as tall as its cards, so the frame sizing is
   switched off here. The single-map version keeps it. */
.mapstack {
  display: grid;
  gap: var(--sp-3);
  align-content: start;
  aspect-ratio: auto;
  min-height: 0;
}

.mapstack .mapcard { aspect-ratio: auto; padding: var(--sp-5) var(--sp-4); }

/* Phone: the card is a label, an address and a button — it does not need
   desktop's breathing room, and the extra height was read as a layout fault
   in its own right. Desktop is unchanged. */
@media (max-width: 599px) {
  .mapstack .mapcard {
    padding: var(--sp-4) var(--sp-4);
    gap: var(--sp-1);
  }

  .mapstack .mapcard .btn { margin-top: var(--sp-2); }
}
