/*
 * Front page only — enqueued conditionally (is_front_page()) in
 * inc/enqueue.php, loads after components.css. Layout only; colors,
 * spacing, radius all come from tokens.css, no new tokens introduced.
 */

/* ---------- Astra container reset (front page only) ---------- */

/* Astra wraps this template's content in exactly one .ast-container div —
   read directly from astra/header.php + astra/footer.php via SSH, not
   guessed: get_header() opens #page > #content.site-content > .ast-container
   right before front-page.php prints <main id="hitsiaijat-front-page">, and
   get_footer() closes those same divs around it. Our own header/footer
   replace Astra's via astra_header_before/astra_footer_before (inc/header.php,
   inc/footer.php), both of which fire outside that container, so it holds
   nothing but this <main>. :has(> #hitsiaijat-front-page) matches only that
   one wrapper on this one template — every other page's .ast-container is
   untouched. */
.ast-container:has(> #hitsiaijat-front-page) {
  max-width: none;
  width: 100%;
  padding: 0;
  display: block;
}

#hitsiaijat-front-page {
  width: 100%;
}

.hero {
  padding-block: var(--space-8);
}

@media (min-width: 1024px) {
  .hero { padding-block: var(--space-9); }
}

/* No-image fallback: light, accent-led treatment instead of the previous
   .section--dark borrow (that class stays reserved for service-cta.php).
   base.css's default h1 { color: var(--color-text-default) } already
   reads correctly on this light background, so no color override is
   needed here the way the old dark variant required one. */
.hero--light {
  background-color: var(--color-canvas-050);
}

/* Mobile only: .hero__content/.cluster otherwise inherit the shared
   .stack/.cluster utilities' default left-start alignment, which read as
   the whole banner being pinned to the left edge below the 768px tablet
   breakpoint. Desktop (>=768px) is untouched — falls through to the
   .stack/.cluster defaults exactly as before. */
@media (max-width: 767.98px) {
  .hero__content {
    text-align: center;
    align-items: center;
  }

  .hero__accent-bar {
    margin-inline: auto;
  }

  .hero__content .cluster {
    justify-content: center;
  }
}

.hero__grid {
  display: grid;
  gap: var(--space-6);
  align-items: center;
}

@media (min-width: 1024px) {
  /* fr/minmax, not 55%/45%: percentage columns plus gap add up to more
     than 100% of the container width and overflow it. minmax(0, Nfr)
     keeps columns from growing past their share and lets them shrink
     below their content's intrinsic width instead of forcing overflow. */
  .hero__grid {
    grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
  }
}

/* Hero has no image (hitsiaijat_get_front_page_thumbnail_html() returned
   empty) — single column, text capped at reading width instead of
   stretching full-bleed under a 2-column grid with nothing in column 2. */
.hero--single-column .hero__grid {
  grid-template-columns: minmax(0, 1fr);
}

.hero--single-column .hero__content {
  max-width: var(--container-reading-max);
}

.hero__media img {
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border-radius: var(--radius-card);
}

@media (min-width: 1024px) {
  .hero__media img {
    aspect-ratio: 16 / 7;
  }
}

/* ---------- Category cards ---------- */

.front-category-card {
  text-decoration: none;
  color: inherit;
  text-align: center;
  align-items: center;
}

.front-category-card__media {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border-radius: var(--radius-control);
  background-color: var(--color-bg-page);
}

.front-category-card__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.front-category-card__media--fallback {
  color: var(--color-text-muted);
}

.front-category-card__title {
  font-weight: 600;
}

/* ---------- Product cards ---------- */

.front-product-card__link {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  text-decoration: none;
  color: inherit;
}

.front-product-card__title {
  font-weight: 600;
}

.front-product-card__price {
  font-weight: 600;
}

/* ---------- Brand logo carousel ---------- */

/* Compact section, asymmetric on purpose: the bottom padding is the
   smaller of the two because it stacks directly with the next section's
   (benefits.php, out of scope, unchanged) own top padding to form the
   visible gap before "Miksi valita Hitsi-Äijät" — keeping this section's
   own bottom edge tight is what actually shrinks that combined gap,
   since benefits.php's padding can't be touched here. Equal specificity
   to the shared .section rule (components.css), so it wins purely on
   source order — front-page.css always loads after components.css (see
   inc/enqueue.php's dependency chain) — same technique already used by
   .section--dark. */
/* Heading is now screen-reader-text (brands.php) — the old h2-to-logos
   `gap` and its margin-neutralizing override are gone; with the heading
   taken out of normal flow (screen-reader-text is `position: absolute`),
   `.container.stack`'s single remaining in-flow child (the carousel div)
   has nothing left to render a gap against, so those rules would be dead
   CSS if kept.

   padding-block-start is 0 here and the actual "previous block -> logos"
   spacing is produced entirely by a negative margin-top, because padding
   alone cannot reach the approved target: categories.php (untouched,
   out of scope) uses the shared `.section` bottom padding — a real,
   measured 96px at >=1024px and 58.368px below it (64px x 0.912, Astra's
   own responsive root font-size scaling — see the brand-tile-gap fix
   above for how that was found) — and 96px alone already exceeds the
   40-48px desktop target, so only a negative margin pulling this section
   up over part of that padding can hit it without touching categories.php.
   Both sections share a transparent background (confirmed live), so the
   overlap creates no visible seam.

   Desktop: 96px (categories) + (-52px) = 44px (mid of the approved
   40-48px range).
   Tablet/mobile: 58.368px (categories, scaled) + (-26.368px) = 32px
   exactly.
   Plain px on the margin (not a rem token) for the same reason as the
   tile-gap fix: immune to Astra's own root font-size scaling, so the
   result is the literal target regardless of breakpoint.

   padding-block-end / the gap to the next section ("Miksi valita
   Hitsi-Äijät") is untouched — removing the heading only affected space
   ABOVE the logos, this section's own bottom padding and benefits.php's
   top padding (out of scope) already give it a full, unmodified
   section-to-section gap. */
.section--brand-carousel {
  padding-block-start: 0;
  padding-block-end: var(--space-7);
  margin-top: -26.368px;
}

@media (min-width: 1024px) {
  .section--brand-carousel {
    margin-top: -52px;
  }
}

/* Tile width per breakpoint controls how many logos are visible at once
   (not a hard slide count — this is a continuous marquee, so "visible
   count" is however many tiles fit the viewport at the current tile
   width): ~2-3 mobile, ~3-5 tablet, ~5-7 desktop, matching the brief.
   Narrower than the first pass on purpose: a smaller fixed tile slot
   means bare logos fill proportionally more of their own box, which is
   what actually shrinks the visible empty space around every tile,
   including — most visibly — the two dark-chip tiles (EWM/Kemppi),
   whose own content is inherently narrow at any reasonable chip height.
   --brand-tile-gap is the SAME value used for the real inter-tile gap
   (.front-brand-carousel__tile's own margin-inline-end below) AND for
   how much extra width a wide bare logo may borrow — a single source of
   truth, not two independently-tunable numbers that could drift apart
   and reintroduce an uneven seam.

   Heights are literal px, not rem: Astra scales the root font-size on
   mobile/tablet, so rem heights would under-shoot the agreed visual
   sizes (3rem mobile ≈ 43.8px instead of 48px). Widths and gaps stay in
   rem because responsive scaling is desired there. */
.front-brand-carousel {
  --brand-tile-w: 8rem;
  --brand-tile-h: 48px;
  --brand-tile-gap: 2rem;
}

@media (min-width: 768px) {
  .front-brand-carousel {
    --brand-tile-w: 10rem;
    --brand-tile-h: 52px;
  }
}

@media (min-width: 1024px) {
  .front-brand-carousel {
    --brand-tile-w: 12rem;
    --brand-tile-h: 56px;
    /* Wider gap at desktop only: gives the widest real logo (Hypertherm,
       ~5.1:1 aspect ratio) enough borrowed headroom (tile + gap) to
       reach the full tile height without shrinking vertically — see
       .front-brand-carousel__logo-box img below. */
    --brand-tile-gap: 3rem;
  }
}

.front-brand-carousel__viewport {
  overflow: hidden;
  /* Horizontal drag/swipe is never captured by this element (there is no
     custom drag-to-scroll interaction at all), so a touch that starts
     here always falls through to native vertical page scrolling. */
  touch-action: pan-y;
  /* Softens the clip edge for whatever happens to be crossing it at any
     given animation frame — a bare logo silhouette or (EWM/Kemppi) a
     rectangular dark chip — into a fade instead of a hard, jarring cut.
     Standard-prefixed for Safari, which still requires -webkit-. */
  -webkit-mask-image: linear-gradient(to right, transparent, black 28px, black calc(100% - 28px), transparent);
  mask-image: linear-gradient(to right, transparent, black 28px, black calc(100% - 28px), transparent);
}

/* The single element that actually gets animated: two identical
   .front-brand-carousel__list rows laid side by side by flex, so
   translateX(-50%) moves exactly one list-width — the instant the real
   (first) list has scrolled fully out of view, the clone (second) list is
   sitting in exactly its old position. No JS is needed to compute this;
   it holds for any item count as long as both lists are identical. */
.front-brand-carousel__track {
  display: flex;
  width: max-content;
  animation: front-brand-carousel-scroll var(--brand-carousel-duration, 32s) linear infinite;
}

.front-brand-carousel__list {
  display: flex;
  align-items: center;
  list-style: none;
  margin: 0;
  padding: 0;
}

/* Deliberately margin, not the .list's own `gap` — CSS gap only inserts
   space BETWEEN children, never after the last one, so a list's rendered
   width would be smaller than "N x (tile + spacing)" by exactly one gap.
   That shortfall is invisible on a normal static grid, but it breaks the
   -50% seamless-loop math above: the clone list would land half a gap
   short of the real list's original position on every cycle, a visible
   stutter at the seam. Margin on every tile (including each list's last
   one, no :last-child exclusion) makes both .list rows exactly N x
   (tile-width + brand-tile-gap) wide, so two of them really are exact
   halves of .track — no special-casing the seam between list 1 and list
   2 is needed, and this is the ONLY place inter-tile spacing is ever
   applied (no `gap` on .track or .list, no extra padding anywhere in
   this component) — verified in tests/theme/js/test-brand-carousel.js by
   reading this exact CSS file's source, and independently confirmed by
   live getBoundingClientRect() measurement: every adjacent tile pair,
   including the last-real-tile-to-first-clone-tile seam, measures
   exactly the same gap. */
.front-brand-carousel__tile {
  flex: 0 0 var(--brand-tile-w);
  display: flex;
  align-items: center;
  justify-content: center;
  height: var(--brand-tile-h);
  margin-inline-end: var(--brand-tile-gap);
}

/* Wraps every <img> (inc/front-page.php) — the uniform, same-size
   transparent area every brand gets. height:100% ties every bare logo's
   available box to the SAME tile height, so "optical weight" differences
   between brands come only from each logo's own real aspect ratio, never
   from unequal boxes. */
.front-brand-carousel__logo-box {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  max-width: 100%;
}

.front-brand-carousel__logo-box img {
  /* height:100% (a definite value, resolved against .logo-box's own
     definite height), not height:auto — deliberately. width:auto +
     height:auto together (both unconstrained) is a known ambiguous case
     for CSS replaced-element sizing that at least one real logo here hit
     in practice: esab.svg has no width/height on its own <svg> root
     (only a viewBox), and with this rule as width:auto;height:auto, that
     specific image's computed box collapsed to 0x0 in Chrome (confirmed
     via getBoundingClientRect() — every OTHER logo, all of which are
     less unusual SVGs/PNGs/WebP, rendered fine). Giving the box a
     definite height removes the ambiguity entirely: object-fit:contain
     now has an unambiguous box to fit the image's aspect ratio into.
     Deliberately more max-width than the tile's own nominal width (not
     100%): a handful of real logos (Hypertherm, ESAB, Cebora) are wide
     enough relative to the fixed tile height that a strict
     100%-of-tile-width cap forces them to shrink vertically well short
     of the other logos' full tile height — visibly "lighter" among
     brands that are supposed to read as one consistent set. Letting the
     image borrow up to one full inter-tile gap's worth of extra width
     means it can reach the tile's full height instead (and if a max-width
     clamp is ever hit anyway, object-fit:contain still shrinks the
     visible content proportionally rather than distorting it) — the
     borrowed space is guaranteed empty (it's the gap to the next tile),
     so this never overlaps a neighboring logo. */
  max-width: calc(var(--brand-tile-w) + var(--brand-tile-gap));
  width: auto;
  height: 100%;
  object-fit: contain;
}

/* EWM's and Kemppi's only official assets are white knockout logos (no
   color/dark variant exists on either official site — see
   hitsiaijat_get_marketing_brand_logos() in inc/front-page.php). Fixed
   height (deliberately shorter than the tile's own height, so the chip
   still reads as a badge around the mark, not a card filling the tile —
   but closer to the tile height than a first attempt at this, which left
   visibly more blank tile padding around these two brands specifically
   than around any bare logo, standing out most at the point in the loop
   where EWM (last brand) sits right next to the seam), same
   radius/padding for both — width is intentionally auto (hugs each
   logo's own natural width instead of stretching to the tile's fixed
   slot), which is exactly what keeps these two from looking like two
   oversized, unequal black cards among the bare logos.

   Heights are literal px so the agreed visual sizes (40/44/48px) hold
   even though Astra scales the root rem on smaller viewports. */
.front-brand-carousel__logo-box--dark-chip {
  height: 40px;
  background-color: var(--color-industrial-900);
  border-radius: var(--radius-control);
  padding-inline: var(--space-3);
}

@media (min-width: 768px) {
  .front-brand-carousel__logo-box--dark-chip {
    height: 44px;
  }
}

@media (min-width: 1024px) {
  .front-brand-carousel__logo-box--dark-chip {
    height: 48px;
  }
}

.front-brand-carousel__logo-box--dark-chip img {
  max-width: calc(var(--brand-tile-w) - var(--space-4));
}

@keyframes front-brand-carousel-scroll {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}

/* Pause states:
   - :focus-within and .front-brand-carousel--paused apply everywhere:
     keyboard focus and document.hidden (tab backgrounded) must pause
     regardless of pointer type.
   - :hover pause is limited to devices with genuine hover + fine pointer.
     Touch browsers sometimes keep a sticky :hover after a tap, which would
     otherwise freeze the carousel on mobile. */
@media (hover: hover) and (pointer: fine) {
  .front-brand-carousel:hover .front-brand-carousel__track {
    animation-play-state: paused;
  }
}

.front-brand-carousel:focus-within .front-brand-carousel__track,
.front-brand-carousel--paused .front-brand-carousel__track {
  animation-play-state: paused;
}

/* Fewer than 3 real logos: brand-carousel.js adds this class, which both
   stops the animation and hides the now-pointless clone list — a 1-2 item
   loop is a jerky, pointless autoplay, so this leaves a plain static row
   of just the real logos. */
.front-brand-carousel--static .front-brand-carousel__track {
  animation: none;
}

.front-brand-carousel--static .front-brand-carousel__list[aria-hidden='true'] {
  display: none;
}

/* The edge-fade mask exists to soften a moving loop's clip boundary —
   with the animation off and no clone (a plain static row), it would
   instead make the genuinely-first/last logo look faded/cut off for no
   reason, so it's turned off here. */
.front-brand-carousel--static .front-brand-carousel__viewport {
  -webkit-mask-image: none;
  mask-image: none;
}

/* Reduced motion: no autoplay, no clone list — this is CSS-only (not
   dependent on brand-carousel.js running at all) so it holds even if the
   script fails to load. What's left is a single, normal, manually
   horizontally-scrollable strip so every logo stays reachable. Same
   reasoning as .front-brand-carousel--static above: the edge-fade mask is
   for the moving loop only, so it's off here too. */
@media (prefers-reduced-motion: reduce) {
  .front-brand-carousel__track {
    animation: none;
  }

  .front-brand-carousel__list[aria-hidden='true'] {
    display: none;
  }

  .front-brand-carousel__viewport {
    overflow-x: auto;
    -webkit-mask-image: none;
    mask-image: none;
  }
}

/* ---------- Service CTA (Huoltopalvelu band) ---------- */

/* Compact section padding, same technique as .section--brand-carousel:
   equal specificity to the shared .section rule (components.css), wins
   on source order since front-page.css always loads after it. The old
   .section--dark default (space-8/space-9, 64-96px) plus a solid dark
   background made this read as "half the screen" — the card below now
   carries its own visual weight, so the outer section only needs enough
   padding to separate it from its neighbors, not to look "big" itself. */
.section--service-cta {
  padding-block: var(--space-7);
}

/* Desktop/tablet: body and button as flex siblings (deliberately NOT
   .stack children, so the button can never inherit stretch the way the
   old .section--dark markup did — see service-cta.php's own header
   comment for the exact root cause this fixes). flex-wrap lets the
   button drop to its own row on narrower widths without a separate rule.
   Light canvas-050 card + thin neutral border + brand-blue top-border
   accent is the exact technique Phase B5's product-page service CTA
   (inc/product.php) and the Contact page's own card (contact.css)
   already established — reused as-is, not a new visual language. */
.front-service-cta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-5);
  padding: var(--space-5);
  background-color: var(--color-canvas-050);
  border: var(--border-width-default) solid var(--color-border-default);
  border-top: var(--border-width-active) solid var(--color-brand-blue-600);
  border-radius: var(--radius-card);
}

.front-service-cta__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-width: 0;
  max-width: 65ch;
}

.front-service-cta__title {
  margin: 0;
  color: var(--color-text-default);
  font-size: var(--text-h3-size-mobile);
  font-weight: var(--text-h3-weight);
  line-height: var(--text-h3-line-height);
}

@media (min-width: 1024px) {
  .front-service-cta__title {
    font-size: var(--text-h3-size);
  }
}

.front-service-cta__text {
  margin: 0;
  max-width: var(--text-reading-max-chars);
  color: var(--color-text-muted);
}

.front-service-cta__button {
  /* .btn is already display:inline-flex (sizes to its own content) —
     flex-shrink:0 is the only addition needed so it never gets squeezed
     by __body's max-width in the same flex row. Width-by-content, never
     100%, on every viewport down to the point flex-wrap drops it to its
     own row (see mobile override below). */
  flex-shrink: 0;
}

/* Mobile: single column, button becomes full-width only here (explicit
   requirement — desktop/tablet keep width-by-content). */
@media (max-width: 767.98px) {
  .front-service-cta {
    flex-direction: column;
    align-items: stretch;
  }

  .front-service-cta__body {
    max-width: none;
  }

  .front-service-cta__button {
    width: 100%;
  }
}

/* ---------- Contact block "Ota yhteyttä" CTA ---------- */

/* .front-contact__cta is a direct child of the inner .stack in
   contact.php (display:flex; flex-direction:column; no align-items
   override), so it inherits the default align-items: stretch — this
   override is what keeps it sized to its own content instead of
   stretching to the section's full width. Scoped to this one link only;
   .stack and .btn themselves are untouched, so nothing else that uses
   either class anywhere in the theme is affected. */
.front-contact__cta {
  align-self: flex-start;
}

@media (max-width: 767.98px) {
  .front-contact__cta {
    align-self: stretch;
    width: 100%;
  }
}

/* ---------- Photo feature (Variant A, after hero) ---------- */

/* Deliberately full-bleed, not wrapped in .container — matches the
   approved mockup (reports/front-page-photo-feature-analysis/, not
   committed) and is why no width override is needed here: .section only
   sets padding-block, and #hitsiaijat-front-page / the .ast-container
   reset above already leave nothing else constraining this section's
   width, so the frame naturally spans the full viewport edge-to-edge. */
.front-photo-feature {
  padding-block: 0;
}

.front-photo-feature__frame {
  position: relative;
  width: 100%;
  overflow: hidden;
}

.front-photo-feature__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 62% 38%;
}

/* Mobile crop (welder-action-mobile-800x1000, 4:5) — matches the
   <picture> source's own (max-width: 767.98px) breakpoint exactly, so
   markup and layout switch together. */
.front-photo-feature__frame {
  aspect-ratio: 4 / 5;
}

.front-photo-feature__scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(21, 21, 21, 0.05) 0%, rgba(21, 21, 21, 0.82) 62%);
}

.front-photo-feature__copy {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: flex-end;
  gap: var(--space-3);
  height: 100%;
  padding: var(--space-6) var(--space-5);
}

.front-photo-feature__title {
  margin: 0;
  color: var(--color-text-on-dark);
  font-size: var(--text-h2-size-mobile);
}

.front-photo-feature__text {
  margin: 0;
  max-width: var(--container-reading-max);
  /* No "muted text on a photo" token exists (tokens.css's muted color
     assumes a solid light/dark background, not a scrim over a photo) —
     same ad-hoc rgba-on-dark approach already used by
     .section--dark .btn--outline:hover in components.css. */
  color: rgba(255, 255, 255, 0.88);
}

/* Tablet crop (welder-action-tablet-2000x1125, 16:9) — matches the
   <picture> source's own (max-width: 1279.98px) breakpoint. */
@media (min-width: 768px) {
  .front-photo-feature__frame {
    aspect-ratio: 16 / 9;
  }

  .front-photo-feature__scrim {
    background: linear-gradient(90deg, rgba(21, 21, 21, 0.8) 0%, rgba(21, 21, 21, 0.42) 42%, rgba(21, 21, 21, 0.04) 68%);
  }

  .front-photo-feature__copy {
    justify-content: center;
    max-width: 34rem;
    padding-inline: var(--space-7);
  }
}

/* Desktop crop (welder-action-desktop-2400x1029) — matches the
   <picture> source's implicit else-branch (no media attribute, >=1280px
   in practice since it loses to the 1279.98px source below that width).
   Height is capped explicitly (not left to aspect-ratio alone) because
   this section is full-bleed: at a fixed aspect-ratio, height would keep
   growing with viewport width with no ceiling (2560px wide would be
   ~1097px tall) — clamp() keeps it in the ~420–520px range the approved
   mockup used, scaling fluidly between those bounds from ~1312px to
   ~1625px wide and holding flat outside that. */
@media (min-width: 1280px) {
  .front-photo-feature__frame {
    aspect-ratio: auto;
    height: clamp(420px, 32vw, 520px);
  }

  .front-photo-feature__title {
    font-size: var(--text-h2-size);
  }
}

/* The CTA sits over a dark photo scrim (measured ~rgb(17,17,17) at the
   button's edge on the desktop crop), where the plain default
   .btn:focus-visible outline (--color-industrial-900, ~rgb(21,21,21)) is
   essentially invisible — confirmed by sampling the actual rendered
   pixels, not assumed. Same fix already used sitewide for this exact
   problem: .section--dark .btn:focus-visible overrides to
   --color-focus-on-dark (base.css) — reused here rather than inventing a
   new pattern, since this section isn't literally .section--dark (that
   class implies a solid --color-bg-dark background, not a photo) but has
   the identical low-contrast-outline-on-dark-surface problem. */
.front-photo-feature .btn:focus-visible {
  outline-color: var(--color-focus-on-dark);
}
