/**
 * Strona główna (Figma "Home-final" node 168:4572 / "Home-mobile-final" node
 * 256:7059, file psb03DxWhlw0g7kvzWHAKt). Page-specific sections — unlike
 * components.css these classes are only used on index.php, so they live in
 * their own file per the note in main.css.
 *
 * Reused existing components instead of rebuilding: .btn-underline for
 * every "Więcej/Zobacz/Wyślij"-style link, apartment-card.php for the
 * apartment grid, news-card.php for the Aktualności cards, contact-form.php
 * for Kontakt.
 *
 * Known simplifications from the Figma reference (see memory/project-scope.md
 * for the full list): hero uses one composited photo on desktop instead of
 * Figma's two stacked/duplicate image layers (the flattened screenshot looks
 * identical); the floor-selector's pill list and the "Wybierz piętro" mouse
 * icon are static, not wired to real per-floor data yet; the "as featured
 * in" logo row (168:4961) is Figma-template placeholder content (fake brand
 * names: SHELLS, kontrastr, ArtVenue...) — rebuilt as a generic marquee
 * structure, not the literal fake logos, ready to swap for real partner
 * logos later.
 */

/* ---------- Card scroll (mobile only) ---------- */
/* One full-screen card at a time, mobile only — since 2026-10-10 driven by
   our own controller (assets/js/card-stack.js, wired up in card-scroll.js),
   which replaced pagePiling.js (2026-10-04) and, before it, a hand-rolled
   position:sticky + CSS scroll-snap version. The stage/positioning rules
   (fixed stage, min-100vh cards, Safari toolbar space, dots) live in
   card-scroll.css; this block only themes the cards themselves.
   Desktop is untouched: #card-stack/.card-scroll__section become
   `display:contents` there (card-scroll.js also never starts the
   controller above the same breakpoint), so children render as plain flow
   children of <main>, identical to the pre-existing desktop layout. */
@media (min-width: 992px) {
  #card-stack,
  .card-scroll__section {
    display: contents;
  }
}

@media (max-width: 991.98px) {
  .card-scroll__section {
    background: var(--color-white);
    box-shadow: 0px -8px 24px rgba(17, 17, 26, 0.12);
    overflow: hidden;
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
    /* Top offset, centering and per-card heading layout now live in
       card-scroll.css (2026-10-05 unification) — keep them there. */
  }

  /* Contact form, trimmed to fit one card-scroll screen (2026-10-05, user
     report: the submit button was badly clipped — up to 150px off-screen
     on shorter phones) — then eased back up (2026-10-05, same day,
     follow-up user report: the first trim read as too cramped once
     combined with the centering above, which already reclaims unused
     space on taller screens without needing the form squeezed this hard).
     contact-form.php/its CSS (components.css) is a SHARED component
     reused on kontakt.php/o-nas.php/wizualizacje.php/wyszukiwarka.php/
     mieszkanie.php/aktualnosci.php/aktualnosc.php — none of this touches
     the component's own defaults, all scoped to just these 2 cards
     (Home's Kontakt card + Finansowanie's own contact-form card), via
     :is() rather than repeating every rule twice. */
  :is(.card-scroll__section--kontakt, .card-scroll__section--fin-kontakt) .contact-form--mobile {
    gap: 12px;
    padding: 20px 16px 24px;
  }

  :is(.card-scroll__section--kontakt, .card-scroll__section--fin-kontakt) .contact-form--mobile .contact-form__heading {
    margin-top: 4px;
    font-size: 30px;
  }

  :is(.card-scroll__section--kontakt, .card-scroll__section--fin-kontakt) .contact-form--mobile .contact-form__fields {
    gap: 8px;
  }

  :is(.card-scroll__section--kontakt, .card-scroll__section--fin-kontakt) .contact-form--mobile .contact-form__field {
    height: 40px;
  }

  :is(.card-scroll__section--kontakt, .card-scroll__section--fin-kontakt) .contact-form--mobile .contact-form__field--textarea {
    height: 65px;
    padding: 10px 4px;
  }

  :is(.card-scroll__section--kontakt, .card-scroll__section--fin-kontakt) .contact-form--mobile .contact-form__actions {
    gap: 10px;
  }

  :is(.card-scroll__section--kontakt, .card-scroll__section--fin-kontakt) .contact-form--mobile .contact-form__submit {
    height: 48px;
  }

  /* Footer brings its own spacing already (site-footer in footer.php) —
     the shared 24px card padding would just be extra, unwanted gap above
     the logo. */
  .card-scroll__section--footer {
    padding-top: 0;
  }

  /* Footer fills the whole card, same "background powinien pokrywać całość
     karty" treatment as Hero/Baner/Floorplan below (2026-10-05, user
     report: the card's white background showed through below the
     footer's own dark green, since <footer class="site-footer"> only
     ever took up its own natural content height — same root cause
     already solved for those other full-bleed cards, same fix: flex:1
     grows it to the full card height instead of just sitting within it).
     display:flex + align-items:center re-centers .site-footer__inner
     (already margin:0 auto horizontally) within whatever taller height
     that turns out to be. */
  .card-scroll__section--footer .site-footer {
    flex: 1;
    display: flex;
    align-items: center;
    /* Floor so centering can never push the logo up under the navbar on a
       shorter screen (2026-10-05, found via screenshot at 360x640: the
       centered brand lockup collided with the navbar's own logo) — same
       96px clearance (80px navbar + ~16px breathing room) Kontakt/
       Aktualności already reserve via their own padding-top, just applied
       as a floor here since this card also needs to center within
       whatever's left below it. */
    padding-top: 96px;
  }

  /* Trimmed mobile spacing (2026-10-05) — now that the footer is a plain
     card with no internal scroll of its own (see footer.php), its content
     needs to actually fit one screen like every other card, same
     constraint .home-progress/.home-apartments/.home-news were already
     trimmed for. .site-footer__inner--mobile is the shared component
     default (components.css, used identically on every other page too) —
     scoped to only this card so nothing else on the site is affected. */
  .card-scroll__section--footer .site-footer__inner--mobile {
    padding: 0 24px;
  }

  .card-scroll__section--footer .site-footer__title {
    margin-bottom: 14px;
  }

  .card-scroll__section--footer .site-footer__bottom--mobile {
    padding-top: 8px;
  }

  /* .site-footer__column's own 12px gap (components.css default, shared
     with the desktop footer) between a heading and its list, and between
     list items, is generous now that there are 2 columns' worth of it
     competing for the same reserved 96px-less space as everything else
     on this card. */
  .card-scroll__section--footer .site-footer__list {
    gap: 6px;
  }

  /* Label/links rows (components.css, uklad_footer_mobile.png layout):
     tighter vertical padding so the whole footer still fits one card. */
  .card-scroll__section--footer .site-footer__column {
    padding: 12px 0;
  }

  /* Hero fills the whole card, same "background powinien pokrywać całość
     karty" treatment as banner/floorplan below — its own photo/overlay
     already fill it via position:absolute;inset:0 (or, on Wizualizacje,
     IS the absolutely-positioned photo itself), it just needs the card to
     let it grow to the full available height instead of sizing to its own
     (irrelevant, now unused) explicit height. */
  .card-scroll__section--hero > * {
    flex: 1;
  }

  /* Baner: "background powinien pokrywać całość karty" — the photo/overlay
     (.home-banner__photo, .home-banner__overlay) already fill .home-banner
     itself via position:absolute;inset:0, but .home-banner only ever took
     up its own natural content height (~351px) — centered/top-aligned by
     the parent card's flex layout like any other card, leaving plain white
     space above/below the photo instead of the photo reaching the card's
     edges. flex:1 makes it grow to consume the ENTIRE card height instead
     of just being positioned within it, so the photo genuinely covers the
     whole card; .home-banner__content's own vertical centering (already
     align-items:center on .home-banner) re-centers the text within
     whatever that taller height turns out to be. */
  .card-scroll__section--banner .home-banner--mobile {
    flex: 1;
  }

  /* Floorplan: same "background powinien pokrywać całość karty" issue as
     .home-banner above, same fix (2026-09-08) — .home-floorplan__photo/
     __overlay already fill .home-floorplan--mobile itself via
     position:absolute;inset:0, but the section only ever took up its own
     natural content height. flex:1 makes it grow to the whole card height
     instead. */
  .card-scroll__section--floorplan .home-floorplan--mobile {
    flex: 1;
  }

}

/* ---------- Hero ---------- */
/* z-index:0 here (not just position:relative) so this section establishes
   its OWN stacking context — without it, the sticky building/headline
   inside (z-index 0/1/2) don't stay contained: since .home-hero itself has
   no explicit z-index, those descendant z-index values get compared
   directly against .home-features' own z-index:1 in the shared outer
   context, and the building (z-index:2) was winning and painting over the
   top of the feature cards during the hero's exit-scroll phase (caught via
   Playwright screenshots at the hero/features scroll boundary — the cards'
   top halves, icon+first line of text, were rendering hidden behind the
   still-exiting hero photo). Giving the section itself a z-index scopes
   its descendants' stacking to stay inside it, so .home-features (a later
   sibling with its own higher z-index) reliably paints on top again. */
.home-hero {
  position: relative;
  z-index: 0;
}

.home-hero__media {
  position: relative;
  overflow: hidden;
}

.home-hero__sky,
.home-hero__building {
  display: block;
  width: 100%;
  object-fit: cover;
}

.home-hero__fade {
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, #fff 6.25%, rgba(241, 241, 241, 0.6) 18.75%, rgba(255, 255, 255, 0) 40%);
  pointer-events: none;
}

.home-hero__headline {
  left: 50%;
  transform: translateX(-50%);
  margin: 0;
  font-family: var(--font-family-hero-heading);
  font-weight: var(--fw-regular);
  color: var(--color-primary);
  text-align: center;
  line-height: normal;
}

.home-hero__headline em {
  font-family: var(--font-family-hero-heading);
  font-weight: var(--fw-medium);
  font-style: italic;
}

/* Home page only: navbar floats transparently over the hero photo instead
   of sitting in normal flow above it (matches Screeny/Home-desktop.png
   reference) — desktop only, mobile keeps the normal in-flow navbar. */
@media (min-width: 992px) {
  .page-home .site-navbar {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    z-index: 10;
  }

  /* Sticky-after-hero (2026-08-25) — see components.css for the shared
     .site-navbar--stuck animation. This selector's extra specificity
     (three classes vs. the rule above's two) is what lets `position:fixed`
     win over `position:absolute` regardless of stylesheet load order. */
  .page-home .site-navbar.site-navbar--stuck {
    position: fixed;
  }
}

/* Mobile-only companion (2026-09-08, user request, mobile-only work) —
   same fix already applied to .page-o-nas/.page-wizualizacje/
   .page-finansowanie/.page-aktualnosci's own navbar: this page's overlay
   used to be desktop-only like every other page's rule (see the file
   comment above this block, now half-stale — "mobile keeps the normal
   in-flow navbar" was the ORIGINAL convention this whole recurring fix
   has been overriding page by page), so on mobile the navbar sat in
   normal flow ABOVE the hero (pushing it down) instead of floating over
   it. See the comment on .page-wizualizacje .site-navbar in
   wizualizacje.css for why this deliberately breaks that original
   pattern. No sticky-after-hero companion for mobile yet, same known gap
   as the other four pages (main.js's stuck-class observer only fires when
   desktopQuery.matches). */
@media (max-width: 991.98px) {
  .page-home .site-navbar {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    z-index: 10;
  }
}

/* Desktop hero scroll effect (2026-08-24) — sticky-backdrop +
   sticky-bottom-building mechanism analyzed live from
   apple.com/pl/environment/'s hero and refined on a first (reverted)
   attempt on the floor-selector section elsewhere on this page:
     - .home-hero__scene is position:absolute (inset:0) so it contributes
       0px to .home-hero__runway's flow height — this keeps
       .home-hero__headline's own static (pre-stick) offset simple ("top
       of the runway"), independent of whatever the scene's content does.
       Sticky siblings that share flow space couple their static offsets
       together, which is what caused problems on the first attempt.
     - .home-hero__building is position:sticky; bottom:0 rather than
       position:absolute; bottom:0 — plain absolute+bottom never actually
       stops moving (constant 1:1 rate with scroll for the wrapper's whole
       height), so it just scrolls fully away once it looks right.
       sticky+bottom genuinely catches and HOLDS once scrolling would push
       it below the viewport, until the scene's own top scrolls past.
     - All three sticky layers get an explicit integer z-index (each then
       forms its own isolated stacking context, so paint order is fully
       deterministic): backdrop 0, headline 1, building 2 — the building
       visually covers the headline as it rises, per user's explicit
       request (opposite of the floor-selector's card, which had to stay
       on top since it holds real interactive buttons; this headline is
       decorative text). The navbar's existing z-index:10 safely beats all
       three. */
.home-hero--desktop {
  /* Building's rendered aspect ratio (3543x1973 asset -> 1973/3543 =
     0.5569) expressed as vw so width:100% keeps it undistorted at any
     width, capped with min() at the asset's own native pixel height so it
     can't stretch past source resolution — the same "native-size ceiling"
     lesson as this hero's own previous max-height:1854px, now generalized
     into a variable so the runway's scroll-distance calc() below always
     agrees with the image's actual rendered height (capped or not), never
     drifting out of sync.
     Asset re-exported 2026-08-25 (user report: building looked "too small,
     doesn't scale" on 2K+ monitors) from 2048x1140 up to its own original
     pre-downscale source, 3543x1973 (found unused in an old scratchpad,
     confirmed pixel-identical composition to the live 2048px asset it
     replaced — just not yet downsized) — this raises the ceiling where the
     building stops growing from 2048px viewport width to 3543px, covering
     every common desktop size (1920/2560/2880/3440 ultrawide) and leaving
     only a small gap at true 4K (3840px). Past 3543px wide, the same
     "stops scaling" ceiling reapplies at a smaller scale — a real, disclosed
     residual limit of this fix (see memory/project-scope.md), not something
     fixable in CSS without an even-higher-resolution source render. */
  --hero-building-h: min(55.69vw, 1973px);
  /* Reduced from a full 100vh (2026-08-24, user request) so a sliver of
     the building is already visible on page load instead of the very
     first screen being pure sky — .home-hero__backdrop's own height, and
     the matching first term in the runway's height calc below, both read
     from this one variable so they can't drift out of sync. */
  --hero-screen-h: 85vh;
}

.home-hero--desktop .home-hero__runway {
  position: relative;
  /* overflow:clip is load-bearing, not decorative — see the note on
     .home-hero__sky below for the full story: .home-hero__sky is
     deliberately taller than its own sticky box, and CSS sticky math
     guarantees that content will always be ~120px short of finishing its
     exit scroll by the time this runway ends, no matter how the runway's
     height is padded (proven, not guessed — padding the runway shifts the
     sticky release point later by the exact same amount, so the shortfall
     never closes). Clipping it here means that leftover 120px physically
     can't render past this box's own edge, so it can never bleed into
     .home-features below regardless of the timing mismatch. Confirmed
     this doesn't break position:sticky on any descendant (backdrop,
     building, headline) — sticky sticks relative to the nearest *scrolling*
     ancestor (the viewport here), not the nearest overflow:clip one. */
  overflow: clip;
  /* var(--hero-screen-h): distance .home-hero__backdrop stays pinned
     before the building catches up (matches its own height).
     + var(--hero-building-h): distance the building takes, rising at a
     normal 1:1 scroll rate, from off-screen to flush with the viewport
     bottom (fully risen, covering the headline).
     + 60vh: extra runway with no new content, so once fully risen the
     building visually HOLDS before the section releases into
     .home-features. First value to tune if the hold feels too long/short
     once seen live — doesn't require restructuring anything else. */
  height: calc(var(--hero-screen-h) + var(--hero-building-h) + 60vh);
  height: calc(var(--hero-screen-h) + var(--hero-building-h) + 60dvh);
}

.home-hero--desktop .home-hero__scene {
  position: absolute;
  inset: 0;
  /* No background here — a sky-blue fill was tried here first (2026-08-24)
     but it covered this element's FULL box, which spans the entire tall
     .home-hero__runway (thousands of px, not just the area near the
     building's top edge) — .home-features overlaps up into the runway's
     very last 170px (its own `margin-top:-170px`), and since
     .home-features has no background of its own around its cards, that
     scene-wide blue fill bled through as a visible band below the cards
     (Screeny/problem-home-3.png). Moved to .home-hero__building itself
     next, which had its own problem (see the note there); the fix that
     actually stuck is on .home-hero__backdrop below. */
}

.home-hero--desktop .home-hero__backdrop {
  position: sticky;
  top: 0;
  z-index: 0;
  height: var(--hero-screen-h);
}

.home-hero--desktop .home-hero__sky {
  /* Taller than its own sticky parent (.home-hero__backdrop) on purpose —
     real photo texture (clouds, gradient) then sits behind the building's
     own irregular/partly-transparent top edge (thin roof support posts
     read as opaque well above where the main roof surface does), instead
     of a hard seam or a flat fallback color (both tried and reverted —
     see memory/project-scope.md). This is safe from bleeding into
     .home-features below ONLY because .home-hero__runway now has
     `overflow: clip` — without that, this same extra height causes CSS
     sticky's exit math to fall permanently short by this same amount, no
     matter how the runway's own height is padded (proven — see the note
     on .home-hero__runway).
     Height is 100vh, not "var(--hero-screen-h) + a small buffer" — this
     changed (2026-08-24) once .home-hero__building got a max-width (see
     its own note below): past its native-resolution ceiling (originally
     ~2048px viewport width, raised to ~3543px on 2026-08-25) the building
     no longer spans the full width, so at scroll=0 there are bare side
     margins where the building never reaches, at ANY vertical position.
     Those margins only ever get covered by THIS image — a buffer sized
     just for the seam in the center (which is all a smaller value like
     "+120px" was covering) fell short of the true viewport height on
     wide screens, leaving a white gap in the bottom corners (2K+ user
     report). 100vh always reaches the actual fold regardless of viewport
     size, and comfortably covers the smaller center-seam requirement too
     (100vh − var(--hero-screen-h) is 15vh, i.e. well over 120px on any
     viewport taller than ~800px) — one value that satisfies both needs
     instead of two separately-tuned ones. */
  height: 100vh;
  height: 100dvh;
  object-position: center top;
}

.home-hero--desktop .home-hero__building {
  position: sticky;
  /* top, not bottom:0 — `position:sticky; bottom:0` was tried first and
     turned out to mean the OPPOSITE of what's wanted here: it clamps the
     element to its flush-bottom position IMMEDIATELY (any time its normal
     static position would render below that point, which is true from
     scroll=0), then releases into normal 1:1 movement afterward — so the
     building was already fully visible on page load with no rise at all
     (confirmed via getBoundingClientRect at scroll=0). `top` sticky is
     the correct tool for "hidden, rises at a normal scroll rate, then
     catches and holds": before engaging it just follows normal in-flow
     scroll (starting off-screen below, since its static offset is 100vh),
     and it only catches once continued scrolling would push it above this
     top value — which is chosen so the building's BOTTOM lands exactly
     flush with the viewport bottom once caught. */
  top: calc(100vh - var(--hero-building-h));
  top: calc(100dvh - var(--hero-building-h));
  z-index: 2;
  height: var(--hero-building-h);
  /* max-width caps this at the asset's own native width (3543px, raised
     2026-08-25 from 2048px alongside the higher-res re-export — see the
     --hero-building-h note above) — --hero-building-h already caps the
     HEIGHT at the native pixel height, but width was still a bare 100%
     (uncapped) from the shared rule above, so past that same viewport
     width the box kept growing wider while height stayed pinned — a box
     aspect ratio wider than the image's own, which made object-fit:cover
     crop the building's sides to fill the too-wide box (user report, 2K+
     screens). Same "native-size ceiling" lesson already applied via
     --hero-building-h and used elsewhere this session — just missing on
     this axis until now. margin:0 auto centers it once width is capped
     (plain margin-based centering, not the left:50%+transform trick — that
     one has already misbehaved on a sticky element earlier in this file). */
  max-width: 3543px;
  margin: 0 auto;
  object-position: center bottom;
  /* No mask-image, no background-color, and the source asset is uncropped
     (2026-08-24 — see memory/project-scope.md for the full back-and-forth:
     two crop attempts, a scene-wide background-color fallback, and a
     building-level background-color fallback were each tried and reverted
     in turn, before landing on the real fix). The building's own alpha
     channel has a soft, irregular top edge — thin roof support posts read
     as opaque well above where the main roof surface does (~5% of the
     image's own height, ~60px at any realistic rendered size) — so
     positioning this element's box flush against the sky originally
     exposed that as a visible gap once the "peek at load" feature (below)
     put it right at the viewport boundary. The fix that stuck lives on
     .home-hero__backdrop's own height (the extra +80px baked into
     --hero-screen-h) — real photo texture from the sky sits behind this
     entire edge, so nothing here needs its own fallback fill. */
}

.home-hero--desktop .home-hero__headline {
  position: sticky;
  /* Nudged down from an initial 260px estimate (user feedback, 2026-08-24:
     read as sitting a bit too high right after page load). A near-top pin
     (not the old top:25.5% viewport centering) also keeps this sticky
     element's post-unstick "trailing distance" (roughly elementHeight +
     topOffset) short — a large centering offset roughly doubles it, which
     is what made the floor-selector card's exit feel awkward on the first
     attempt.
     A bare 340px looked right at 1920x1080 (confirmed correct by the user)
     but "too high" at 2K+ (2026-08-25 report) because a fixed px value is a
     SHRINKING percentage of viewport height as that height grows past 1080
     (measured: 31.5% at 1080p, only 15.7% at 3840x2160) — the headline's
     on-screen position is relative to the viewport, so it needs to scale
     with viewport HEIGHT, not stay a constant pixel offset. Switched to
     max(340px, 31.5vh): 31.5% is exactly 340/1080, so this is a no-op at
     1920x1080 and anything SHORTER than 1080px tall (the 340px floor wins,
     matching the "a bit smaller is already fine" report unchanged) — only
     engages and scales the offset down proportionally on taller-than-1080
     viewports (2560x1440 -> ~454px, 3840x2160 -> ~680px), keeping the same
     ~31.5%-down visual position at any height instead of drifting toward
     the top edge. */
  top: 340px;
  top: max(340px, 31.5vh);
  top: max(340px, 31.5dvh);
  /* left:0;right:0;margin:auto instead of the shared rule's
     left:50%;transform:translateX(-50%) — that percentage-left +
     transform combo, which centers a position:absolute element correctly
     (see the --mobile variant, unchanged), produced a wildly wrong
     horizontal offset once this became position:sticky (confirmed via
     getBoundingClientRect probing: left:720px alone rendered at x=260,
     not 720 — an empirical sticky quirk with percentage-based left,
     not a spec detail worth chasing further). left:0/right:0 + auto
     margins is the classic, reliable way to center a fixed-width block
     regardless of position value. */
  left: 0;
  right: 0;
  margin: 0 auto;
  transform: none;
  z-index: 1;
  width: min(1180px, 85%);
  font-size: 64px;
}

/* Mobile hero: static, no scroll animation, single flat photo (2026-08-27,
   user requests across two follow-ups):
   1. The sticky rising-building effect ported from desktop was buggy/heavy
      on mobile: "animacja się bugguje i jest zbyt ciężka nie ma co
      kombinować" — replaced with a plain stacked-image layout first
      (no runway/scene/sticky layers).
   2. That still wasn't fully static: `height:100dvh` (dynamic viewport
      height) genuinely changes value in real time as a mobile browser's
      toolbar collapses/expands during scroll — since object-fit:cover
      images resize with their box, this reads as a lingering animation
      even with no CSS transition/animation involved. Fixed by switching to
      `100svh` (SMALL viewport height — the stable, toolbar-always-visible
      minimum, which never changes mid-scroll) instead of 100dvh.
   3. The building cutout (home-hero-mobile-accent.png) was dropped
      entirely per "bez nakładającego się budynku" — home-hero-mobile.png
      (the "sky" asset) is actually a complete standalone photo (full sky +
      meadow + benches/people, no building) so it works fine alone as a
      single flat background with nothing layered over it.
   The Hero -> Card 1 handoff (originally its own position:sticky hand-roll,
   point 4 here until 2026-10-04) is now just pagePiling.js transitioning
   between its first two sections like any other card boundary — see the
   "Card scroll" block above for the current mechanism; .card-scroll__section--hero
   > * (flex:1) is what makes this section fill its whole card now. */
/* 100vh, not 100svh (2026-10-10, user request): the card-stack stage is
   100lvh tall and runs under Safari's bottom bar, so a 100svh photo left a
   white strip below it on iOS. 100vh = the large viewport in Safari and is
   just as stable as svh (never changes mid-gesture, unlike dvh). */
.home-hero--mobile .home-hero__media {
  position: relative;
  height: 100vh;
}

/* position:absolute background layer (2026-09-08 fix) — was a normal-flow
   block (.home-hero__sky's shared base rule: display:block;width:100%)
   that only happened to fill .home-hero__media because its own height:100%
   matched the media box's explicit 100svh exactly; same fix already
   applied to .onas-hero__video/.wiz-hero__photo/.finansowanie-hero__video/
   .aktualnosci-hero__video. */
.home-hero--mobile .home-hero__sky {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;
}

/* Shrunk further per user follow-up (74% -> 40% -> 22%) — the white fade
   at the top kept reading as too large. Same gradient stops (see the
   shared .home-hero__fade rule above), just applied over a smaller box so
   it clears up sooner. */
.home-hero--mobile .home-hero__fade {
  height: 22%;
}

/* Smoother fade (2026-10-10, user: "wygląda nie zbyt ładnie") — the shared
   3-stop gradient above read as a hard white band with a grey middle step
   (rgba(241,241,241,.6)) and a visible edge where it ended. Mobile now uses
   pure white with an eased (ease-in-out-like) opacity curve spread over a
   taller box, so there's no visible start or end line. Desktop keeps the
   shared rule. */
.home-hero--mobile .home-hero__fade {
  height: 30%;
  background: linear-gradient(
    to bottom,
    rgba(255, 255, 255, 1) 0%,
    rgba(255, 255, 255, 0.987) 8.1%,
    rgba(255, 255, 255, 0.951) 15.5%,
    rgba(255, 255, 255, 0.896) 22.5%,
    rgba(255, 255, 255, 0.825) 29%,
    rgba(255, 255, 255, 0.741) 35.3%,
    rgba(255, 255, 255, 0.648) 41.2%,
    rgba(255, 255, 255, 0.55) 47.1%,
    rgba(255, 255, 255, 0.45) 52.9%,
    rgba(255, 255, 255, 0.352) 58.8%,
    rgba(255, 255, 255, 0.259) 64.7%,
    rgba(255, 255, 255, 0.175) 71%,
    rgba(255, 255, 255, 0.104) 77.5%,
    rgba(255, 255, 255, 0.049) 84.5%,
    rgba(255, 255, 255, 0.013) 91.9%,
    rgba(255, 255, 255, 0) 100%
  );
}

.home-hero--mobile .home-hero__headline {
  position: absolute;
  top: 24%;
  width: 90%;
  font-size: 36px;
}

/* ---------- Features row (desktop only — omitted on mobile per Figma) ---------- */
/* Horizontal max-width/centering/side-padding now come from the shared
   .section-column class (see base.css) — only the special negative
   top-margin (pulling this grid up over the hero) stays here. */
.home-features {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 24px;
  margin-top: -170px;
}

.home-features__card {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 32px;
  background: var(--color-white);
  border: 1px solid var(--color-border);
  border-radius: 50px;
  padding: 32px 16px;
  text-align: center;
}

.home-features__icon {
  display: block;
  width: auto;
  height: 36px;
}

.home-features__text {
  margin: 0;
  font-family: var(--font-family-base);
  /* "Body Regular Medium" tokenized type style (2026-08-25, user request) —
     same tokens/pattern already used for .home-progress__status: 16px/1.4
     mobile -> 20px/normal desktop, at --fw-medium. Was a hardcoded
     20px/bold with no responsive mobile value of its own (relied on
     shrinking via the grid's own narrower columns instead). */
  font-weight: var(--fw-medium);
  font-size: var(--fs-body-md);
  line-height: var(--lh-body-md);
  color: var(--color-primary);
}

/* ---------- Building progress status ---------- */
.home-progress {
  padding: 96px 0 48px;
}

/* Full-bleed hairline (Screeny/sekcje2.png shows this spanning the whole
   page width, unlike the text below it which stays in the same 1320px
   column as every other section). */
.home-progress__line {
  width: 100%;
  border-top: 1px solid var(--color-border);
}

/* Mobile-only heading (2026-09-08, user request — explicitly scoped to
   mobile work only). Hidden by default and only switched back on inside
   the max-width:991.98px block below, rather than the other way around,
   so desktop stays untouched even if a future edit adds rules in between. */
.home-progress__heading,
.home-progress__eyebrow {
  display: none;
}

/* Horizontal max-width/centering/side-padding now come from the shared
   .section-column class (see base.css). */

.home-progress__row {
  display: flex;
}

.home-progress__item {
  position: relative;
  flex: 1;
  padding: 24px 32px 0 0;
  text-align: center;
}

/* First column is the "active" step — a bolder, darker segment sitting
   exactly on top of the shared hairline, covering only its own column's
   width, matching Screeny/sekcje2.png. */
.home-progress__active-bar {
  position: absolute;
  top: -1px;
  left: 0;
  right: 32px;
  height: 3px;
  background: var(--color-primary);
}

/* Font sizes are the tokenized "Body Small" / "Body Regular Medium" type
   styles (tokens.css --fs-body-sm / --fs-body-md, same ones .text-body-sm /
   .text-body-md expose as utilities) rather than hand-picked pixel values —
   both tokens already carry their own mobile vs. desktop (992px) value, so
   no separate mobile override is needed here; the mobile breakpoint simply
   picks up each token's mobile value automatically. */
.home-progress__building {
  margin: 0 0 8px;
  font-family: var(--font-family-base);
  font-weight: var(--fw-medium);
  font-size: var(--fs-body-sm);
  line-height: var(--lh-body-sm);
  color: var(--color-primary);
}

.home-progress__status {
  margin: 0;
  font-family: var(--font-family-base);
  font-weight: var(--fw-medium);
  font-size: var(--fs-body-md);
  line-height: var(--lh-body-md);
  color: var(--color-primary);
}

@media (max-width: 991.98px) {
  /* Padding bumped 48px -> 72px (2026-08-27, user request: more breathing
     room now that this card has real headroom — see .card-scroll__section
     in the "Card scroll" block above). */
  .home-progress {
    padding: 72px 0;
  }

  .home-progress__line {
    display: none;
  }

  /* Eyebrow+heading pair styled after .home-apartments__intro — but that
     component's own mobile heading size isn't its base 24px rule (that
     gets overridden further down in ITS OWN OWN media query, see
     .home-apartments__heading below: 2026-08-27 bumped it to the
     --fs-h1/--lh-h1 token scale, 36px, "większe fonty ze styli"). Matching
     .home-apartments__intro means matching that actually-computed mobile
     size, not the pre-override base value (real mismatch caught by the
     user comparing the two live, 2026-09-08). */
  .home-progress__eyebrow {
    display: block;
    margin: 0 0 8px;
    font-family: var(--font-family-base);
    font-weight: var(--fw-bold);
    color: var(--color-primary);
    font-size: 14px;
  }

  .home-progress__heading {
    display: block;
    /* 16px -> 32px -> 40px (2026-09-08, user request: more room before
       .home-progress__row below — same value applied to
       .home-apartments__heading's own mobile margin-bottom right below,
       for a consistent rhythm across the stacked mobile cards). */
    margin: 0 0 40px;
    font-family: var(--font-family-base);
    font-weight: var(--fw-bold);
    color: var(--color-black);
    font-size: var(--fs-h1);
    line-height: var(--lh-h1);
  }

  /* Vertical timeline rail (2026-08-27, from a supplied reference
     screenshot — Screeny/) replacing the old per-item horizontal
     hairline: a single continuous thin line runs down the left edge of
     the whole list (::before below), with a thicker, primary-colored
     segment overlaid on top of it for the active item only
     (.home-progress__active-bar, repurposed from its desktop-only role as
     a horizontal overlay bar — see the shared rule above, unchanged there
     — into a vertical one here). Text switches from centered to
     left-aligned, indented past the rail.
     gap/padding-left bumped 28px -> 36px same session as the section
     padding above — keep .home-progress__active-bar's left offset (below)
     matched to this value, they have to agree. */
  .home-progress__row {
    position: relative;
    flex-direction: column;
    gap: 36px;
    padding-left: 36px;
  }

  .home-progress__row::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 2px;
    background: var(--color-border);
  }

  .home-progress__item {
    padding: 0;
    text-align: left;
  }

  .home-progress__item--active {
    position: relative;
  }

  /* top:0;bottom:0 (no explicit height) stretches this to match its
     parent item's own content height automatically, whatever that turns
     out to be for the active item's specific text. left:-36px pulls it
     back out of the item's own box to line up exactly with the row's
     ::before rail above (the item itself sits 36px in, from the row's
     own padding-left — must match .home-progress__row's padding-left). */
  .home-progress__active-bar {
    display: block;
    position: absolute;
    left: -36px;
    right: auto;
    top: 0;
    bottom: 0;
    height: auto;
    width: 4px;
  }

  /* Bigger fonts (2026-08-27, user request) — one step up the token scale
     from what desktop's own shared rule uses (body-sm/body-md), matching
     the same "bump to the next size up" treatment already applied to
     .home-apartments__heading. */
  .home-progress__building {
    margin-bottom: 10px;
    font-size: var(--fs-body-md);
    line-height: var(--lh-body-md);
    color: var(--color-secondary);
  }

  .home-progress__status {
    font-size: var(--fs-body-lg);
    line-height: var(--lh-body-lg);
    font-weight: var(--fw-bold);
  }
}

/* ---------- Partners / "as featured in" marquee ---------- */
/* Shared container for both variants below — real height/spacing/edge-fade
   live here so switching between them (see public/index.php) doesn't shift
   layout. */
.home-partners {
  height: 64px;
  margin: 16px 0 48px;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 64px, #000 calc(100% - 64px), transparent);
  mask-image: linear-gradient(to right, transparent, #000 64px, #000 calc(100% - 64px), transparent);
}

/* Fallback shown until an admin uploads at least one real logo via the
   Materiały admin tab (2026-09-11) — the flattened export of Figma's
   "Component 2" (168:4961), a single 1760x32 tile of all 5 original logos,
   tiled with background-repeat and scrolled via background-position. Kept
   as-is (not rebuilt into individual files) since those 5 logos only ever
   existed as this one flattened sprite. */
.home-partners--legacy {
  background-image: url("/assets/img/home-partners-strip.webp");
  background-repeat: repeat-x;
  background-size: auto 40px;
  animation: home-partners-scroll 24s linear infinite;
}

@keyframes home-partners-scroll {
  from { background-position-x: 0; }
  to { background-position-x: -2200px; }
}

/* Admin-managed variant (2026-09-11) — real <img> logos, one per row in
   the DB (see PartnerzyRepository), driven by the exact same JS marquee
   engine as Wizualizacje's category carousels ([data-marquee-track] in
   main.js: duplicate the item set, autoplay via requestAnimationFrame,
   pause on hover) instead of a CSS background loop, since each logo is now
   its own element rather than one flattened sprite. */
.home-partners__track {
  display: flex;
  align-items: center;
  height: 100%;
  width: max-content;
  will-change: transform;
}

.home-partners__item {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  /* 96px → 152px (2026-10-10, owner request: more air between partner logos).
     Kept as margin-right on EVERY item (incl. the last) so the duplicated
     marquee track still loops seamlessly. */
  margin-right: 152px;
}

/* 2026-09-11, user request, sized up twice — first pass 24px->32px felt
   still too small, second pass here (32px->42px, more gap) is the current
   size. .home-partners' own height grew alongside both passes (40px->48px->
   64px) so the logo always sits with visible breathing room, not edge-to-edge. */
.home-partners__item img {
  height: 42px;
  width: auto;
  display: block;
  object-fit: contain;
}

@media (prefers-reduced-motion: reduce) {
  .home-partners--legacy {
    animation: none;
  }
  .home-partners__track {
    transform: none !important;
  }
}

/* A bit more breathing room above the marquee on desktop specifically, per
   user request — mobile's tighter 16px top margin (from the base rule
   above) is untouched. */
@media (min-width: 992px) {
  .home-partners {
    margin-top: 64px;
  }
}

@media (max-width: 991.98px) {
  /* Top margin 24px -> 48px (2026-10-10, user request: more space between
     the "Etapy powstania" list and the logo carousel). */
  .home-partners {
    margin: 48px 0 24px;
  }

  /* Smaller, tighter-packed logos (2026-08-27, user request, mobile only) —
     background-size scales the WHOLE repeating sprite tile down (logos and
     the gaps baked between them in the source image both shrink together,
     which is exactly "smaller + closer" in one property since they're not
     independently adjustable — it's one flattened image, not separate logo
     elements). Own animation (not the shared @keyframes above) since the
     tile's rendered width scales down proportionally with its height
     (1760x32 native, so width = 1760 * renderedHeight/32) — the desktop
     keyframe's -2200px end value only lines up with the desktop 40px
     height; this scoped keyframe recomputes it for 28px (1760 * 28/32 =
     1540) so the loop still seams cleanly instead of jumping. */
  .home-partners--legacy {
    background-size: auto 28px;
    animation-name: home-partners-scroll-mobile;
  }

  .home-partners__item img {
    height: 32px;
  }

  .home-partners__item {
    margin-right: 112px; /* was 72px (2026-10-10, owner request) */
  }
}

@keyframes home-partners-scroll-mobile {
  from { background-position-x: 0; }
  to { background-position-x: -1540px; }
}

/* ---------- Apartments ---------- */
/* Full-width now (not capped/padded itself) so .home-apartments__grid's
   containing block is genuinely the viewport, not an already-1320px-capped
   box — that's what lets the grid compute its own left inset with 100%
   instead of the scrollbar-sensitive 100vw (see the grid rule below). The
   eyebrow/heading and footer get their column from .section-column
   (applied in index.php) instead. */
.home-apartments {
  padding: 48px 0;
}

.home-apartments__eyebrow {
  margin: 0 0 8px;
  font-family: var(--font-family-base);
  font-weight: var(--fw-bold);
  color: var(--color-primary);
  font-size: 14px;
}

.home-apartments__heading {
  margin: 0 0 32px;
  font-family: var(--font-family-base);
  font-weight: var(--fw-bold);
  color: var(--color-black);
  font-size: 24px;
}

/* Horizontal scroll-snap carousel (2026-08-27: extended to all breakpoints
   — was previously desktop-only with a `flex-wrap:wrap` mobile fallback
   that stacked cards into rows; user asked for a swipeable carousel on
   mobile too, "statyczna karuzela" i.e. no button chrome, pure swipe/
   scroll — .carousel-controls is already hidden below 992px, unchanged). */
.home-apartments__grid {
  display: flex;
  flex-wrap: nowrap;
  gap: 24px;
  padding: 0 32px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  scrollbar-width: none;
  /* Left edge matches the standard column's inset exactly — same formula
     .section-column resolves to, but computed here against 100% of this
     grid's own containing block (.home-apartments, genuinely full-width)
     instead of 100vw — see the min-width:992px block below (pre-2026-08-27)
     for the full rationale, unchanged, now just applying at every width. */
  padding-left: max(32px, calc((100% - 1320px) / 2 + 32px));
  padding-right: 32px;
  scroll-padding-left: max(32px, calc((100% - 1320px) / 2 + 32px));
}

.home-apartments__grid::-webkit-scrollbar {
  display: none;
}

.home-apartments__grid > * {
  flex-shrink: 0;
  scroll-snap-align: start;
}

.home-apartments__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-top: 32px;
}

.carousel-controls {
  display: flex;
  gap: 12px;
}

/* No circle/border chrome — the icon itself is the button (user feedback,
   2026-08-20: the round white/bordered chip around the arrow icon was
   dropped, keeping only enough padding for a comfortable click target). */
.carousel-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 8px;
  border: none;
  background: none;
  cursor: pointer;
}

/* Figma "Arrows" component (node 459:11454) — the raw exported SVGs both
   came back as the same un-rotated down-chevron shape (Figma's asset
   export doesn't carry a parent group's rotation transform), so the
   left/right versions were reconstructed by hand-rotating that path ±90°
   rather than trusting the export directly. */
.carousel-btn img {
  display: block;
  width: auto;
  height: 24px;
}

.carousel-btn:hover img,
.carousel-btn:focus-visible img {
  opacity: 0.6;
}

@media (min-width: 992px) {
  .home-apartments__heading {
    font-size: 42px;
  }
}

@media (max-width: 991.98px) {
  .carousel-controls {
    display: none;
  }
}

/* Trimmed spacing + card photo height (2026-08-27, mobile only) — same
   "must fit one screen" constraint as .home-news (see .card-scroll__section
   in the "Card scroll" block above): needed real headroom below real mobile viewport
   heights (browser toolbar chrome shrinks the visible area well below the
   844px this was first measured against — a phone with the toolbar
   expanded was reporting the Kontakt card cut off). Card media
   aspect-ratio is a SHARED component default (.apartment-card--mobile is
   reused on other pages) — scoped to `.home-apartments .apartment-card--mobile`
   so only this carousel row is affected, same technique as the news card. */
@media (max-width: 991.98px) {
  .home-apartments {
    padding: 24px 0;
  }

  /* Bumped to the --fs-h1/--lh-h1 token scale (2026-08-27, user request:
     "większe fonty ze styli" — now that the full-screen card has plenty of
     headroom, the old --fs-h2-equivalent 24px heading reads too small
     against all the empty space around it. */
  .home-apartments__heading {
    /* 40px -> 20px (2026-10-05, user report: the "Zobacz wszystkie
       mieszkania" button was getting clipped on shorter phones) — the
       100vh-experiment headroom this 40px was tuned for turned out not to
       hold on real shorter devices after all; see the "Card scroll" block
       above for the fuller story. */
    margin-bottom: 12px;
    font-size: var(--fs-h1);
    line-height: var(--lh-h1);
  }

  /* 28px -> 10px, same reason as the heading margin above. */
  .home-apartments__footer {
    margin-top: 10px;
  }

  .home-apartments .apartment-card--mobile .apartment-card__media {
    /* 3/2 -> 2/1 (2026-10-05, user report: the "Zobacz wszystkie
       mieszkania" button was still clipped on shorter phones) — shorter
       photo band buys back real height without touching the shared
       component default (4/3) used elsewhere. */
    aspect-ratio: 2 / 1;
  }

  .home-apartments .apartment-card--mobile .apartment-card__body {
    padding: 10px;
    gap: 6px;
  }
}

/* ---------- Floor selector: budynek → piętro → mieszkania ---------- */
/* Rebuilt 2026-10-18 (user request) as three steps driven by
   assets/js/home-floorplan.js — see the note above the section in
   index.php. Shared rules first, then desktop, then mobile. */

.home-floorplan__step.is-leaving {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
}

.home-floorplan [data-floorplan-stage].is-animating {
  overflow: hidden;
}

.home-floorplan [data-floorplan-focus]:focus {
  outline: none;
}

/* Ring on the step heading only for keyboard users (.is-keyboard, set by
   home-floorplan.js) — after a tap/click some browsers (Safari) would
   still treat the programmatic focus as :focus-visible. */
.home-floorplan.is-keyboard [data-floorplan-focus]:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 4px;
}

.home-floorplan__eyebrow {
  margin: 0 0 6px;
  font-family: var(--font-family-base);
  font-weight: var(--fw-bold);
  color: var(--color-primary);
  font-size: 14px;
}

.home-floorplan__title {
  margin: 0 0 6px;
  font-family: var(--font-family-base);
  font-weight: var(--fw-bold);
  color: var(--color-black);
  font-size: 26px;
  line-height: 1.2;
}

.home-floorplan__instructions {
  margin: 0 0 16px;
  font-family: var(--font-family-base);
  font-weight: var(--fw-regular);
  color: var(--color-black);
  font-size: 13px;
}

/* Back button — always on the left (user request). */
.home-floorplan__back {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  border: 1px solid var(--color-border);
  border-radius: 999px;
  background: var(--color-white);
  padding: 10px 18px;
  font-family: var(--font-family-base);
  font-weight: var(--fw-bold);
  font-size: 14px;
  color: var(--color-black);
  cursor: pointer;
  box-shadow: 0 4px 16px rgba(22, 22, 22, 0.08);
  transition: border-color 0.2s ease, color 0.2s ease;
}

.home-floorplan__back:hover {
  border-color: var(--color-primary);
  color: var(--color-primary);
}

.home-floorplan__back:focus-visible,
.home-floorplan__building:focus-visible,
.home-floorplan__list button:focus-visible,
.home-floorplan__floor-switch button:focus-visible,
.home-floorplan__option:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

/* Status pill: "Oddany" filled, "W planach" outlined. */
.home-floorplan__status {
  display: inline-block;
  border: 1px solid var(--color-secondary);
  border-radius: 12px;
  padding: 2px 10px;
  font-family: var(--font-family-base);
  font-weight: var(--fw-bold);
  font-size: 12px;
  color: var(--color-secondary);
}

.home-floorplan__status.is-available {
  border-color: var(--color-primary);
  background: var(--color-primary);
  color: var(--color-white);
}

/* ===== Desktop ===== */
/* Negative top margin so the photo tucks slightly under the apartments
   section above it (user request, 2026-08-24) — kept from the old
   static version. */
.home-floorplan--desktop {
  position: relative;
  margin: -24px 0 0;
}

.home-floorplan--desktop .home-floorplan__stage {
  position: relative;
  overflow: hidden;
}

.home-floorplan--desktop .home-floorplan__step {
  position: relative;
}

.home-floorplan__bg {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1920 / 981;
  object-fit: cover;
}

/* Step 1: aerial render + hover zones. The render (3840×1962 after the
   top crop) and the SVG viewBox share one aspect ratio with
   .home-floorplan__bg, so the polygons line up at every width. */
.home-floorplan__map {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.home-floorplan__shape {
  fill: transparent;
  stroke: transparent;
  stroke-width: 8;
  stroke-linejoin: round;
  pointer-events: all;
  transition: fill 0.25s ease, stroke 0.25s ease;
}

.home-floorplan__shape.is-available {
  cursor: pointer;
}

.home-floorplan__shape.is-hover {
  fill: rgba(121, 133, 118, 0.35);
  stroke: var(--color-white);
  stroke-dasharray: 28 18;
}

.home-floorplan__shape.is-available.is-hover {
  fill: rgba(64, 81, 59, 0.45);
  stroke-dasharray: none;
}

/* Tips sit just above each roof (polygon top centre, in % of the image).
   At rest only the building name shows; hover/focus unfolds the details. */
.home-floorplan__tip {
  position: absolute;
  z-index: 2;
  transform: translate(-50%, calc(-100% - 14px));
  background: var(--color-white);
  border-radius: 20px;
  padding: 8px 16px;
  text-align: center;
  box-shadow: 0 8px 24px rgba(22, 22, 22, 0.12);
  pointer-events: none;
  transition: box-shadow 0.25s ease;
}

.home-floorplan__tip::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -7px;
  width: 14px;
  height: 14px;
  background: var(--color-white);
  transform: translateX(-50%) rotate(45deg);
}

.home-floorplan__tip--1c { left: 19.3%; top: 32.8%; }
.home-floorplan__tip--1b { left: 50.2%; top: 32.1%; }
.home-floorplan__tip--1a { left: 80.7%; top: 31.6%; }

.home-floorplan__tip-name {
  margin: 0;
  font-family: var(--font-family-base);
  font-weight: var(--fw-bold);
  font-size: 15px;
  color: var(--color-black);
}

.home-floorplan__tip-details {
  /* max-width too, so the resting tip is only as wide as the name. */
  max-width: 0;
  max-height: 0;
  margin: 0 auto;
  opacity: 0;
  overflow: hidden;
  transition: max-width 0.3s ease, max-height 0.3s ease, opacity 0.2s ease, margin 0.3s ease;
}

.home-floorplan__tip.is-hover {
  box-shadow: 0 12px 32px rgba(22, 22, 22, 0.2);
}

.home-floorplan__tip.is-hover .home-floorplan__tip-details {
  max-width: 320px;
  max-height: 140px;
  opacity: 1;
  margin-top: 6px;
}

.home-floorplan__tip-info {
  margin: 6px 0 0;
  font-family: var(--font-family-base);
  font-size: 13px;
  color: var(--color-black);
  white-space: nowrap;
}

.home-floorplan__tip-cta {
  margin: 4px 0 0;
  font-family: var(--font-family-base);
  font-weight: var(--fw-bold);
  font-size: 13px;
  color: var(--color-primary);
}

/* Step 1 card: bottom-left over the lawn, below the buildings. Same inset
   as .section-column (100%, not 100vw — see .home-floorplan__card). */
.home-floorplan__picker {
  position: absolute;
  z-index: 2;
  left: max(32px, calc((100% - 1320px) / 2 + 32px));
  bottom: 24px;
  display: flex;
  align-items: center;
  gap: 24px;
  max-width: calc(100% - 64px);
  background: var(--color-white);
  border: 1px solid var(--color-border);
  border-radius: 32px;
  padding: 20px 24px;
}

.home-floorplan__picker .home-floorplan__instructions {
  margin: 0;
}

.home-floorplan__buildings {
  display: flex;
  gap: 10px;
  list-style: none;
  margin: 0;
  padding: 0;
}

.home-floorplan__building {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 150px;
  border: 1px solid var(--color-border);
  border-radius: 26px;
  padding: 10px 18px;
  font-family: var(--font-family-base);
  color: var(--color-black);
  text-decoration: none;
  transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease;
}

.home-floorplan__building-name {
  font-weight: var(--fw-bold);
  font-size: 15px;
}

.home-floorplan__building-meta {
  font-size: 12px;
  color: var(--color-secondary);
  transition: color 0.2s ease;
}

.home-floorplan__building.is-available {
  border-color: var(--color-primary);
}

.home-floorplan__building.is-available:hover,
.home-floorplan__building.is-available.is-hover {
  background: var(--color-primary);
  color: var(--color-white);
}

.home-floorplan__building.is-available:hover .home-floorplan__building-meta,
.home-floorplan__building.is-available.is-hover .home-floorplan__building-meta {
  color: rgba(255, 255, 255, 0.85);
}

.home-floorplan__building.is-hover:not(.is-available) {
  background: var(--color-bg);
}

/* Step 2: the previous building photo + floor card (right). */
.home-floorplan__back-row {
  position: absolute;
  z-index: 2;
  top: 24px;
  left: max(32px, calc((100% - 1320px) / 2 + 32px));
}

.home-floorplan__card {
  position: absolute;
  top: 50%;
  /* 100%, not 100vw: this resolves against the full-width stage, so it
     always matches .section-column's inset exactly — 100vw includes the
     scrollbar gutter and drifted this card a few pixels. */
  right: max(32px, calc((100% - 1320px) / 2 + 32px));
  transform: translateY(-50%);
  width: min(360px, 30%);
  background: var(--color-white);
  border: 1px solid var(--color-border);
  border-radius: 32px;
  padding: 24px 28px;
  text-align: center;
}

.home-floorplan__list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  list-style: none;
  margin: 0;
  padding: 0;
}

.home-floorplan--desktop .home-floorplan__list button {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  border: 1px solid var(--color-border);
  border-radius: 26px;
  background: var(--color-white);
  padding: 11px 20px;
  font-family: var(--font-family-base);
  font-weight: var(--fw-bold);
  font-size: 15px;
  color: var(--color-black);
  cursor: pointer;
  transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease;
}

.home-floorplan__count {
  font-weight: var(--fw-regular);
  font-size: 13px;
  color: var(--color-secondary);
}

.home-floorplan--desktop .home-floorplan__list button:hover,
.home-floorplan--desktop .home-floorplan__list button.active {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: var(--color-white);
}

.home-floorplan--desktop .home-floorplan__list button:hover .home-floorplan__count,
.home-floorplan--desktop .home-floorplan__list button.active .home-floorplan__count {
  color: rgba(255, 255, 255, 0.85);
}

/* Step 3: apartment cards. At least as tall as the photo steps (so the
   section doesn't jump), taller when the cards need it. */
.home-floorplan--desktop .home-floorplan__step--apartments {
  display: flex;
  flex-direction: column;
  justify-content: center;
  aspect-ratio: 1920 / 981;
  padding: 32px 0 40px;
  background: var(--color-white);
}

/* .section-column as a flex item would shrink to its content (base.css). */
.home-floorplan--desktop .home-floorplan__step--apartments > .section-column {
  width: 100%;
}

.home-floorplan__heading-row {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
  margin: 20px 0 24px;
}

.home-floorplan__heading-row .home-floorplan__title {
  margin: 0;
  font-size: 32px;
}

.home-floorplan__floor-switch {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.home-floorplan__floor-switch button {
  border: 1px solid var(--color-border);
  border-radius: 999px;
  background: var(--color-white);
  padding: 8px 16px;
  font-family: var(--font-family-base);
  font-weight: var(--fw-bold);
  font-size: 14px;
  color: var(--color-black);
  cursor: pointer;
  transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease;
}

.home-floorplan__floor-switch button:hover {
  border-color: var(--color-primary);
}

.home-floorplan__floor-switch button[aria-pressed="true"] {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: var(--color-white);
}

/* Same scroller as .home-apartments__grid (left edge on the column). */
.home-floorplan__track {
  display: flex;
  flex-wrap: nowrap;
  gap: 24px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  padding-left: max(32px, calc((100% - 1320px) / 2 + 32px));
  padding-right: 32px;
  scroll-padding-left: max(32px, calc((100% - 1320px) / 2 + 32px));
}

.home-floorplan__track::-webkit-scrollbar {
  display: none;
}

.home-floorplan__track > * {
  flex-shrink: 0;
  scroll-snap-align: start;
}

.home-floorplan__track .apartment-card--desktop {
  width: 400px;
}

.home-floorplan__track-controls {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 16px;
}

.home-floorplan__track-controls[hidden] {
  display: none;
}

.home-floorplan--desktop .home-floorplan__empty {
  padding-top: 24px;
  padding-bottom: 24px;
}

.home-floorplan--desktop .home-floorplan__empty-title {
  max-width: 640px;
  margin: 0 0 12px;
  font-family: var(--font-family-base);
  font-weight: var(--fw-bold);
  font-size: 32px;
  line-height: 1.2;
  color: var(--color-black);
}

.home-floorplan__empty-text {
  margin: 0 0 24px;
  font-family: var(--font-family-base);
  font-size: 16px;
  color: var(--color-secondary);
}

/* ===== Mobile ===== */
/* Photo + green tint as the section's own full-bleed background
   (2026-09-08, same technique as .home-banner); only the content steps
   change (2026-10-18). */
.home-floorplan--mobile {
  position: relative;
  overflow: hidden;
  /* display:flex + align-items:center — content lands in the vertical
     centre of the card (flex:1 in the "Card scroll" block above grows the
     section to the full card height). */
  display: flex;
  align-items: center;
  padding: 20px 16px;
}

.home-floorplan__photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.home-floorplan__overlay {
  position: absolute;
  inset: 0;
  background: rgba(64, 81, 59, 0.5);
}

.home-floorplan__content {
  position: relative;
  z-index: 1;
  width: 100%;
  /* All steps share one grid cell and each is centred on its own
     (2026-10-18): steps differ in height, so with a single centred box the
     content's centre moved during a transition and the slide ran
     diagonally. Now every step's centre stays on the card's centre and the
     slide is purely horizontal. */
  display: grid;
  align-items: center;
}

.home-floorplan--mobile .home-floorplan__step {
  grid-area: 1 / 1;
  min-width: 0;
}

/* The desktop "leaving" rule (absolute) isn't needed in the shared cell. */
.home-floorplan--mobile .home-floorplan__step.is-leaving {
  position: relative;
  width: auto;
}

.home-floorplan--mobile .home-floorplan__step {
  text-align: center;
}

.home-floorplan--mobile .home-floorplan__back {
  display: flex;
  width: fit-content;
  margin: 0 auto 20px 0;
  padding: 8px 16px;
}

.home-floorplan--mobile .home-floorplan__eyebrow {
  color: var(--color-white);
  opacity: 0.9;
}

.home-floorplan--mobile .home-floorplan__title {
  margin: 0 0 8px;
  color: var(--color-white);
  font-size: 36px;
}

.home-floorplan--mobile .home-floorplan__hint {
  margin: 0 0 32px;
  font-family: var(--font-family-base);
  font-weight: var(--fw-regular);
  color: var(--color-white);
  font-size: 14px;
  opacity: 0.95;
}

/* One option per row, narrower than the screen (2026-09-08 decisions). */
.home-floorplan--mobile .home-floorplan__list {
  display: grid;
  grid-template-columns: 1fr;
  gap: 8px;
}

.home-floorplan__option {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  width: 75%;
  margin: 0 auto;
  border: 1px solid var(--color-border);
  border-radius: 26px;
  background: var(--color-white);
  padding: 10px 12px;
  font-family: var(--font-family-base);
  font-weight: var(--fw-medium);
  font-size: 14px;
  color: var(--color-black);
  text-decoration: none;
  cursor: pointer;
}

.home-floorplan__option-name {
  font-weight: var(--fw-bold);
  font-size: 15px;
}

.home-floorplan__option-meta {
  font-size: 12px;
  color: var(--color-secondary);
}

.home-floorplan__option.active {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: var(--color-white);
}

.home-floorplan__option.active .home-floorplan__option-meta {
  color: rgba(255, 255, 255, 0.85);
}

.home-floorplan__option.is-planned {
  background: rgba(255, 255, 255, 0.15);
  border-color: rgba(255, 255, 255, 0.5);
  color: var(--color-white);
  cursor: default;
}

.home-floorplan__option.is-planned .home-floorplan__option-meta {
  color: rgba(255, 255, 255, 0.85);
}

.home-floorplan__option--link {
  font-weight: var(--fw-bold);
}

.home-floorplan--mobile .home-floorplan__step--apartments .home-floorplan__hint {
  margin-bottom: 16px;
}

/* Cards bleed to the screen edges and scroll sideways; [data-carousel-
   track] tells card-stack.js to leave horizontal swipes alone. */
.home-floorplan--mobile .home-floorplan__track {
  gap: 12px;
  margin: 0 -16px;
  padding: 0 16px;
  scroll-padding-left: 16px;
  text-align: left;
}

.home-floorplan--mobile .home-floorplan__track .apartment-card--mobile {
  width: 80vw;
  max-width: 297px;
}

.home-floorplan--mobile .home-floorplan__empty-title {
  margin: 8px 0 12px;
  font-family: var(--font-family-base);
  font-weight: var(--fw-bold);
  font-size: 24px;
  line-height: 1.25;
  color: var(--color-white);
}

/* ---------- Promo banner ---------- */
.home-banner {
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: center;
}

.home-banner__photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.home-banner__overlay {
  position: absolute;
  inset: 0;
  background: rgba(64, 81, 59, 0.5);
}

/* Horizontal max-width/centering/side-padding come from the shared
   .section-column class (see base.css), applied alongside this in
   index.php — only display/vertical-padding stay here. width:100% is
   still needed locally, though: this element is a flex ITEM of
   .home-banner (display:flex), and without an explicit width a flex item
   shrinks to its content's size and only treats max-width as an upper
   bound — see the note on .section-column in base.css. */
.home-banner__content {
  position: relative;
  z-index: 1;
  width: 100%;
  display: flex;
  /* flex-end, not center (2026-08-25, user request) — aligns the button
     to the bottom edge of the eyebrow+heading block instead of the
     vertical center of the whole row. */
  align-items: flex-end;
  justify-content: space-between;
  /* wrap (2026-08-25 follow-up): without this, a narrow-but-still-desktop
     viewport (~992-1060px) had no room left for both
     .home-banner__intro's full first line AND the button, so the intro
     (a shrinkable flex item with no minimum of its own) got squeezed
     narrower than that line needed — reopening the exact "B," orphaned
     onto its own line bug .home-banner__intro's flex-shrink:0 below is
     meant to prevent. Wrapping lets the button drop to its own line
     instead of stealing width from the heading. */
  flex-wrap: wrap;
  gap: 32px;
  padding-top: 48px;
  padding-bottom: 48px;
}

.home-banner__intro {
  /* Stops the heading's first line from being squeezed narrower than it
     needs (see the wrap note above) — the button wraps below instead. */
  flex-shrink: 0;
}

.home-banner__eyebrow {
  margin: 0 0 8px;
  font-family: var(--font-family-base);
  font-weight: var(--fw-bold);
  color: var(--color-white);
  font-size: 20px;
}

.home-banner__heading {
  margin: 0;
  font-family: var(--font-family-base);
  font-weight: var(--fw-bold);
  color: var(--color-white);
  font-size: 42px;
  /* 700px -> 740px (2026-08-25, user feedback): at 700px "Część usługowa
     dla inwestycji bloku B," (measured 715px wide at this font) was just
     15px too wide to fit the first line, so it orphaned "B," alone onto
     line 2 — an awkward break in the middle of the block's own name/label.
     740px is enough room for that whole first line to fit together (the
     row still has plenty of space before the button — .home-banner__content
     uses justify-content:space-between, not a tight fit), while the
     heading still wraps (the full sentence is ~1070px, well past 740px),
     just at the sentence's own natural break instead of mid-label. */
  max-width: 740px;
}

.home-banner .btn-underline__label,
.home-banner .btn-underline__underline {
  color: var(--color-white);
}

.home-banner .btn-underline__underline {
  background-color: var(--color-white);
}

@media (max-width: 991.98px) {
  .home-banner__content {
    flex-direction: column;
    align-items: flex-start;
    padding-top: 40px;
    padding-bottom: 40px;
  }

  .home-banner__heading {
    font-size: 36px;
  }
}

/* ---------- Aktualności (news) ---------- */
/* Full-width now — see the identical note on .home-apartments above for
   why (lets .home-news__grid compute its left inset with 100% instead of
   the scrollbar-sensitive 100vw). Heading/footer get .section-column
   applied in the markup instead. */
.home-news {
  padding: 48px 0;
}

.home-news__heading {
  margin: 0 0 32px;
  font-family: var(--font-family-base);
  font-weight: var(--fw-bold);
  color: var(--color-black);
  font-size: 24px;
  max-width: 700px;
}

/* Horizontal scroll-snap carousel (2026-08-27: extended to all breakpoints
   — see the identical change + rationale on .home-apartments__grid above). */
.home-news__grid {
  display: flex;
  flex-wrap: nowrap;
  gap: 24px;
  padding: 0 32px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  scrollbar-width: none;
  padding-left: max(32px, calc((100% - 1320px) / 2 + 32px));
  padding-right: 32px;
  scroll-padding-left: max(32px, calc((100% - 1320px) / 2 + 32px));
}

.home-news__grid::-webkit-scrollbar {
  display: none;
}

.home-news__grid > * {
  flex-shrink: 0;
  scroll-snap-align: start;
}

.home-news__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-top: 32px;
}

@media (min-width: 992px) {
  .home-news__heading {
    font-size: 42px;
  }
}

/* Trimmed spacing + card height (2026-08-27, mobile only) — this section is
   one of the mobile cards (.card-scroll__section, see the "Card scroll"
   block above in this file): its natural content needs to fit within one
   screen (no internal-scroll escape hatch — see footer.php's 2026-10-05
   note on why pp-scrollable was dropped) and this section came in ~107px
   over budget. Must come AFTER the base rules above (same specificity — an
   earlier placement got silently overridden by them). .news-card--mobile's
   own min-height is a SHARED component default used on other pages too
   (aktualnosci.php etc.) — scoped the shrink to `.home-news
   .news-card--mobile` specifically so only this carousel row is affected. */
@media (max-width: 991.98px) {
  .home-news {
    padding: 16px 0;
  }

  .home-news__heading {
    margin: 0 0 16px;
  }

  .home-news__footer {
    margin-top: 12px;
  }

  .home-news .news-card--mobile {
    min-height: 400px;
  }

  .home-news .news-card--mobile .news-card__media {
    height: 140px;
  }

  /* Extra top clearance + shorter cards, this carousel only (2026-10-05,
     user report: the navbar — position:absolute, 80px tall, see
     .site-navbar — was overlapping the heading, which only had the shared
     24px card padding + 16px of .home-news's own top padding above it,
     40px total). Pushed to 72px here to match .home-progress's own
     clearance (the other card whose heading sits right under the navbar);
     .home-news's own rule above stays untouched since it's a shared
     component used on aktualnosci.php/mieszkanie.php/o-nas.php/
     aktualnosc.php too. The extra ~56px is paid for by shrinking the cards
     a further 60px/30px (don't touch the component's own shared default,
     520px/180px in components.css — same scoped-override pattern already
     used for the 400px/140px values here) so the card still fits one
     screen. */
  .card-scroll__section--news .home-news {
    padding-top: 72px;
  }

  /* These two were accidentally left unscoped in the first pass (2026-10-05)
     — `.home-news .news-card--mobile` with no `.card-scroll__section--news`
     ancestor also matches mieszkanie.php/o-nas.php/aktualnosc.php's own
     plain (non-card-scroll) use of .home-news, shrinking their cards too
     without being asked to. Scoped now, same as padding-top right above.
     min-height isn't actually the binding constraint here — this card's
     own text content (title + 3-line excerpt + date/link footer, with
     their own padding/gaps) already renders taller than either the
     original 400px or this value, so min-height is just a floor that
     never kicks in. The real lever for making the card shorter is the
     photo height below, which IS directly additive to the rendered
     height.

     Media height eased back up from an initial 40px (2026-10-05, same
     day, follow-up user report: "wcześniej wszystko było za duże a teraz
     jest zbyt ściśnięte") — 100px is the middle ground between the
     original 140px (too tall once the navbar-clearance padding above was
     added) and the first trim pass's 40px (too cramped); the new
     justify-content:center on this card (above) also reclaims unused
     space on taller screens, so it doesn't need to be squeezed this hard
     to fit short ones. */
  .card-scroll__section--news .home-news .news-card--mobile {
    min-height: 320px;
  }

  .card-scroll__section--news .home-news .news-card--mobile .news-card__media {
    height: 100px;
  }

  .card-scroll__section--news .home-news .news-card--mobile .news-card__body {
    padding: 16px;
    gap: 8px;
  }

  .card-scroll__section--news .home-news__heading {
    margin-bottom: 12px;
  }

  .card-scroll__section--news .home-news__footer {
    margin-top: 10px;
  }
}

@media (max-width: 991.98px) {
  .home-news .carousel-controls {
    display: none;
  }
}
