/* =========================================================================
   Objektsidan — Villa Soludden
   Fristående presentation. Bilderna bär sidan; typografin håller ihop den.
   ========================================================================= */

/* ------------------------------------------------------------------ *
 * Navigation
 * ------------------------------------------------------------------ */

.obj-nav {
  position: fixed;
  /* Demoremsan ligger överst i dokumentet och scrollar bort. Så länge
     den syns kliver navigeringen ned under den. */
  top: var(--demo-bar-h, 0px);
  left: 0; right: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  gap: var(--sp-5);
  padding: 1.1rem var(--gutter);
  color: var(--sand-50);
  transition: background-color 500ms var(--ease-out),
              padding 500ms var(--ease-out),
              border-color 500ms var(--ease-out),
              color 500ms var(--ease-out);
  border-bottom: 1px solid transparent;
}
.obj-nav.is-stuck {
  top: 0;
  background: rgba(20, 19, 18, .92);
  border-bottom-color: rgba(255, 255, 255, .1);
  padding-block: 0.8rem;
  /* Ingen backdrop-filter: bakgrunden ligger redan på 92 % täckning, så
     oskärpan syns knappt men kostar en helskärmsoperation per bildruta. */
}
.obj-nav.is-hidden { transform: translateY(-110%); }
.obj-nav { transition-property: transform, background-color, padding, border-color, top; }

.obj-nav__name {
  font-family: var(--font-display);
  font-size: 1.3rem;
  letter-spacing: 0.01em;
  text-decoration: none;
  white-space: nowrap;
}
.obj-nav__links {
  display: none;
  gap: 1.9rem;
  margin-inline: auto;
  font-size: 0.8125rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.obj-nav__links a {
  text-decoration: none;
  color: rgba(255, 255, 255, .74);
  transition: color var(--dur-fast) var(--ease-out);
}
.obj-nav__links a:hover { color: #fff; }
.obj-nav__cta { margin-left: auto; }
@media (min-width: 60rem) {
  .obj-nav__links { display: flex; }
  .obj-nav__cta { margin-left: 0; }
}

/* ------------------------------------------------------------------ *
 * Hero
 * ------------------------------------------------------------------ */

/* Spår + sticky scen: js/scroll.js skriver --p under scrollvägen */
.obj-hero {
  position: relative;
  height: 168vh;
  background: var(--char-900);
}
@media (max-width: 47.99rem) { .obj-hero { height: 146vh; } }

.obj-hero__stage {
  position: sticky;
  top: 0;
  height: 100svh;
  display: flex;
  align-items: flex-end;
  overflow: hidden;
  color: var(--sand-50);
}
.obj-hero__media {
  position: absolute;
  inset: 0;
  overflow: hidden;
}
.obj-hero__media { animation: hero-settle 1900ms var(--ease-out) both; }
.obj-hero__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: scale(calc(1 + var(--p, 0) * 0.14)) translate3d(0, calc(var(--p, 0) * -2%), 0);
  will-change: transform;
}
/* Rastret gick .9 → .3 → .5 hela vägen upp: minsta värdet var 0,30, så
   HELA hero-fotot låg under en trettioprocentig hinna och himlen under
   femtio. Det är sidans viktigaste bild — ett hus i kvällssol — och den
   såg grå ut av ett raster som fanns för textens skull. Nu två lokala
   band: ett smalt i toppen som bär headern, ett i botten som bär namn,
   läge och pris. Mellan 16 % och 40 % av höjden är fotot orört, och det
   är där taklinjen och himlen ligger. */
.obj-hero__scrim {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to bottom, rgba(16, 15, 14, .40) 0%, rgba(16, 15, 14, .12) 9%, rgba(16, 15, 14, 0) 16%),
    linear-gradient(to top, rgba(16, 15, 14, .90) 0%, rgba(16, 15, 14, .52) 26%, rgba(16, 15, 14, .12) 46%, rgba(16, 15, 14, 0) 60%);
  opacity: calc(0.88 + var(--p, 0) * 0.12);
}
.obj-hero__inner {
  position: relative;
  z-index: 2;
  width: 100%;
  padding-bottom: clamp(3rem, 2rem + 5vw, 6rem);
  padding-top: 8rem;
  opacity: calc(1 - var(--p, 0) * 1.7);
  transform: translate3d(0, calc(var(--p, 0) * -60px), 0);
  will-change: transform, opacity;
}

.js .obj-hero__seq > * {
  opacity: 0;
  transform: translateY(18px);
  animation: hero-in 1100ms var(--ease-out) both;
  animation-delay: calc(340ms + var(--i, 0) * 130ms);
}
.obj-hero__label { color: rgba(255, 255, 255, .72); margin-bottom: 1.6rem; }
.obj-hero h1 {
  font-size: var(--t-display);
  line-height: 0.92;
  margin-bottom: 0.5rem;
}
.obj-hero__ort {
  font-size: clamp(1.05rem, 0.95rem + 0.6vw, 1.4rem);
  color: rgba(255, 255, 255, .8);
  font-style: italic;
  font-family: var(--font-display);
}
.obj-hero__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.9rem 2.2rem;
  margin-top: clamp(1.8rem, 1.2rem + 2vw, 3rem);
  padding-top: 1.6rem;
  border-top: 1px solid rgba(255, 255, 255, .22);
}
.obj-hero__sum {
  font-size: 0.9375rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .86);
}
.obj-hero__pris {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 1.2rem + 1.4vw, 2.2rem);
  margin-left: auto;
}
.obj-hero__pris small {
  display: block;
  font-family: var(--font-body);
  font-size: 0.6875rem;
  letter-spacing: var(--letter-label);
  text-transform: uppercase;
  color: rgba(255, 255, 255, .6);
  margin-bottom: 0.2rem;
}
.obj-hero__cta { margin-top: 2rem; }
.obj-hero__tag { position: absolute; top: 6.2rem; right: var(--gutter); z-index: 3; }

/* Scrollmarkör */
/* Scrollmarkör. Lodrät: etikett, hårfin linje, chevron. Mässing i
   stället för halvgenomskinligt vitt — den var i praktiken osynlig mot
   både skymningshimmel och upplyst fasad. Fortfarande 1 px stroke och
   ingen ram; den ska hittas, inte märkas. */
.obj-hero__scroll {
  position: absolute;
  left: var(--gutter);
  bottom: 1.4rem;
  z-index: 3;
  display: none;
  flex-direction: column;
  align-items: center;
  gap: 0.55rem;
  font-size: 0.625rem;
  letter-spacing: var(--letter-label);
  text-transform: uppercase;
  color: var(--brass-400);
  text-shadow: 0 1px 12px rgba(16, 15, 14, .55);
}
.obj-hero__scroll svg {
  width: 14px; height: 8px;
  filter: drop-shadow(0 1px 8px rgba(16, 15, 14, .5));
}
.obj-hero__scroll i {
  display: block;
  width: 1px; height: 2.2rem;
  background: linear-gradient(to bottom,
    rgba(203, 164, 105, 0), rgba(203, 164, 105, .95));
  transform-origin: top;
  /* Linjen dras ut och tillbaka över sju sekunder. Ingen studs, ingen
     förflyttning — bara en längd som andas. Det ska registreras
     undermedvetet, inte ses. */
  animation: cue 7s cubic-bezier(.4, 0, .2, 1) infinite;
}
@keyframes cue {
  0%, 100% { transform: scaleY(.55); opacity: .45; }
  50%      { transform: scaleY(1);   opacity: .9; }
}
@media (min-width: 62rem) and (min-height: 44rem) { .obj-hero__scroll { display: flex; } }

/* ------------------------------------------------------------------ *
 * Berättelse
 * ------------------------------------------------------------------ */

.story { display: grid; gap: clamp(2.5rem, 1.5rem + 5vw, 5rem); align-items: center; }
@media (min-width: 62rem) {
  .story { grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr); }
  .story__media { margin-right: calc(var(--gutter) * -1); }
}
.story__body { max-width: 34rem; display: grid; gap: 1.5rem; align-content: start; }
.story__body h2 { max-width: 15ch; }
.story__body p { color: var(--fg-muted); font-size: var(--t-lead); line-height: 1.62; }
.story__media { --media-ratio: 4 / 5; }
@media (max-width: 61.99rem) { .story__media { --media-ratio: 3 / 2; } }

/* ------------------------------------------------------------------ *
 * Bostadsfakta
 * Inga rutor, inga linjer mellan cellerna. Talen står fritt i luften
 * och det är storleksskillnaden mot etiketten som gör läsningen — inte
 * ett rutnät som ritar upp sig självt. Siffrorna räknas upp en gång
 * när sektionen kommer in i vyn (js/objekt.js).
 * ------------------------------------------------------------------ */

.stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(2.75rem, 1.5rem + 5vw, 5rem) clamp(1.5rem, 0.5rem + 4vw, 4rem);
}
@media (min-width: 44rem) { .stats { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 74rem) { .stats { grid-template-columns: repeat(6, minmax(0, 1fr)); } }

.stat { display: grid; gap: 0.75rem; justify-items: start; }

.stat__num {
  font-family: var(--font-display);
  font-size: clamp(3rem, 1.9rem + 4.6vw, 5.25rem);
  line-height: 0.9;
  letter-spacing: -0.035em;
  /* Tabulära siffror: annars hoppar talet i sidled medan det räknas upp */
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}
.stat__label {
  font-size: 0.6875rem;
  letter-spacing: var(--letter-label);
  text-transform: uppercase;
  color: var(--fg-subtle);
}

/* ------------------------------------------------------------------ *
 * Galleri — magasinsrytm, inte rutnät
 * ------------------------------------------------------------------ */

.gallery {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: clamp(1rem, 0.6rem + 1.6vw, 2.2rem);
  align-items: start;
}
.shot { margin: 0; grid-column: span 12; }
.shot figcaption {
  margin-top: 0.9rem;
  font-size: 0.75rem;
  letter-spacing: var(--letter-label);
  text-transform: uppercase;
  color: var(--fg-subtle);
}
.shot .media { transition: transform 900ms var(--ease-out); }
.shot:hover .media { transform: translateY(-6px); }

@media (min-width: 54rem) {
  .shot--wide   { grid-column: span 8; }
  .shot--tall   { grid-column: span 4; }
  .shot--square { grid-column: span 6; }
  .shot--pano   { grid-column: span 12; }
  /* Förskjutningar som bryter rutnätskänslan */
  .shot--tall { margin-top: clamp(1.5rem, 4vw, 5rem); }
  .shot--square:nth-of-type(even) { margin-top: clamp(1rem, 3vw, 3.5rem); }
}

/* ------------------------------------------------------------------ *
 * Utvalda egenskaper — numrerade rader, inte kort
 * ------------------------------------------------------------------ */

.features { display: grid; gap: 0; border-top: 1px solid var(--line); }
.feature {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 1.2rem clamp(1.5rem, 1rem + 3vw, 4rem);
  padding-block: clamp(1.6rem, 1.2rem + 1.6vw, 2.4rem);
  border-bottom: 1px solid var(--line);
  align-items: baseline;
}
@media (min-width: 54rem) {
  .feature { grid-template-columns: auto minmax(0, 15rem) minmax(0, 1fr); }
  .feature__body { display: contents; }
}
.feature__no {
  font-size: 0.6875rem;
  letter-spacing: var(--letter-label);
  color: var(--accent);
  padding-top: 0.4rem;
}
.feature__title { font-family: var(--font-display); font-size: clamp(1.3rem, 1.1rem + 0.9vw, 1.9rem); }
.feature__body p { color: var(--fg-muted); max-width: 46ch; }

/* ------------------------------------------------------------------ *
 * Planritningar
 * ------------------------------------------------------------------ */

.plans { display: grid; gap: clamp(1.5rem, 1rem + 2.5vw, 3rem); }
@media (min-width: 54rem) { .plans { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.plan { margin: 0; }
.plan .media {
  --media-ratio: 7 / 5;
  background: var(--sand-50);
  border: 1px solid var(--line);
}
.plan .media img { object-fit: contain; }
.plan__cap {
  display: flex;
  align-items: baseline;
  gap: 1rem;
  margin-top: 1rem;
  padding-top: 0.9rem;
  border-top: 1px solid var(--line);
}
.plan__titel { font-family: var(--font-display); font-size: 1.25rem; }
.plan__yta { margin-left: auto; color: var(--fg-subtle); font-size: 0.875rem; }

/* ------------------------------------------------------------------ *
 * Området
 * ------------------------------------------------------------------ */

.area { display: grid; gap: clamp(2.5rem, 1.5rem + 4vw, 4.5rem); align-items: center; }
@media (min-width: 62rem) { .area { grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr); } }
.area__body { display: grid; gap: 1.4rem; align-content: start; max-width: 32rem; }
.area__body p { color: var(--fg-muted); font-size: var(--t-lead); line-height: 1.6; }
.area__map { --media-ratio: 7 / 5; border: 1px solid var(--line); }

.nearby-list { display: grid; gap: 0; margin-top: 0.6rem; }
.nearby {
  display: flex;
  align-items: baseline;
  gap: 1rem;
  padding-block: 0.8rem;
  border-bottom: 1px solid var(--line);
}
.nearby__label { color: var(--fg-muted); font-size: 0.9375rem; }
.nearby__value { margin-left: auto; font-weight: 600; font-size: 0.9375rem; }

/* ------------------------------------------------------------------ *
 * Mäklare
 * ------------------------------------------------------------------ */

.agent { display: grid; gap: clamp(2rem, 1.4rem + 3vw, 4rem); }
@media (min-width: 58rem) { .agent { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: center; } }

.agent__card { display: grid; gap: 1.4rem; align-content: start; }
.agent__namn { font-family: var(--font-display); font-size: clamp(2rem, 1.5rem + 2vw, 3rem); line-height: 1.05; }
.agent__titel { color: var(--fg-muted); }
.agent__citat {
  font-family: var(--font-display);
  font-style: italic;
  font-size: var(--t-lead);
  color: var(--fg-muted);
  max-width: 36ch;
  padding-left: 1.2rem;
  border-left: 1px solid var(--accent);
}
.agent__rows { display: grid; gap: 0; margin-top: 0.4rem; }
.agent__row {
  display: flex;
  align-items: baseline;
  gap: 1rem;
  padding-block: 0.95rem;
  border-bottom: 1px solid var(--line);
  text-decoration: none;
  transition: border-color var(--dur) var(--ease-out);
}
.agent__row:hover { border-color: var(--accent); }
.agent__row span:first-child {
  font-size: 0.6875rem;
  letter-spacing: var(--letter-label);
  text-transform: uppercase;
  color: var(--fg-subtle);
  min-width: 6.5rem;
}
.agent__row b { font-weight: 500; font-size: 1.0625rem; }
.agent__actions { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: 0.8rem; }

/* ------------------------------------------------------------------ *
 * Sidfot på objektsidan
 * ------------------------------------------------------------------ */

.obj-footer {
  background: var(--char-900);
  color: var(--sand-50);
  padding-block: clamp(3rem, 2rem + 4vw, 5rem);
}
.obj-footer__inner {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem 2.5rem;
  align-items: baseline;
  justify-content: space-between;
}
.obj-footer__name { font-family: var(--font-display); font-size: 1.5rem; }
.obj-footer__note {
  font-size: 0.875rem;
  color: rgba(255, 255, 255, .58);
  max-width: 46ch;
  line-height: 1.6;
}
.obj-footer__note a { color: var(--brass-400); }
.obj-footer__by { font-size: 0.8125rem; color: rgba(255, 255, 255, .5); }
.obj-footer__by a { color: rgba(255, 255, 255, .82); text-decoration: none; border-bottom: 1px solid rgba(255,255,255,.3); }

/* Sticky kontaktrad på mobil — spekulanten ska aldrig behöva leta */
.obj-sticky {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 55;
  display: flex;
  gap: 0.6rem;
  padding: 0.7rem var(--gutter) calc(0.7rem + env(safe-area-inset-bottom));
  background: rgba(20, 19, 18, .97);
  border-top: 1px solid rgba(255, 255, 255, .12);
  transform: translateY(110%);
  transition: transform 460ms var(--ease-out);
}
.obj-sticky.is-shown { transform: translateY(0); }
.obj-sticky .btn { flex: 1; padding-inline: 0.9rem; }
@media (min-width: 58rem) { .obj-sticky { display: none; } }

/* Bildtext under den bild som växer till fullbredd */
/* Materialraden är sista ordet före vattnet, inte en bildtext.
   Den låg i brödtextstorlek och grå ton i ett stort ljust band, och
   kedjan blev "stor bild → liten notis → stor video" — tre saker utan
   samband. Nu står den i display-serif i mellanstorlek, som en kort
   replik som avslutar materialsekvensen och lämnar över till vattnet.
   Ingen ny komponent: samma element, rätt vikt. */
.expand__cap {
  margin-top: clamp(1.6rem, 1rem + 2vw, 2.75rem);
  max-width: 26ch;
  color: var(--fg);
  font-family: var(--font-display);
  font-size: clamp(1.4rem, 1rem + 1.6vw, 2.25rem);
  line-height: 1.2;
  letter-spacing: -0.015em;
  text-wrap: balance;
}

/* Samma åtstramning på objektsidans hero */
@media (max-width: 47.99rem) {
  /* Demoremsan ligger ovanför den fästa scenen och skjuter ned den lika
     mycket i början av sidan. Utan kompensationen hamnar knappen under
     skärmkanten precis när besökaren landar. */
  .obj-hero__inner { padding-top: 4rem; padding-bottom: calc(1.6rem + var(--demo-bar-h, 0px)); }
  .obj-hero h1 { margin-bottom: 0.3rem; font-size: clamp(2.5rem, 1.2rem + 5.8vw, 3.2rem); line-height: 1; }
  .obj-hero__label { margin-bottom: 0.9rem; }
  .obj-hero__ort { font-size: 1.0625rem; }
  .obj-hero__meta { margin-top: 1.1rem; padding-top: 0.9rem; }
  .obj-hero__cta { margin-top: 1.1rem; }
  .obj-hero__cta .btn { width: 100%; }
  /* Remsan högst upp säger redan exakt samma sak. Två märkningar ovanpå
     varandra äter en fjärdedel av skärmen utan att tillföra något. */
  .obj-hero__tag { display: none; }
  /* Kompaktare remsa: tre rader text i toppen trycker ned hela huset */
  .demo-bar {
    font-size: 0.75rem;
    line-height: 1.4;
    padding: 0.55rem var(--gutter);
    text-align: left;
  }
}

/* ------------------------------------------------------------------ *
 * Galleri: fäst huvudbild, rumslistan bredvid
 * Bilderna ligger som lager och byts av scrollmotorn — samma mekanik
 * som signatursekvensen på startsidan.
 * ------------------------------------------------------------------ */

.rooms { position: relative; height: 440vh; }
@media (max-width: 61.99rem) { .rooms { height: 380vh; } }

.rooms__stage {
  position: sticky;
  top: 0;
  height: 100svh;
  display: flex;
  align-items: center;
  overflow: hidden;
}

.rooms__grid {
  display: grid;
  gap: clamp(1.5rem, 1rem + 3vw, 4rem);
  align-items: center;
  width: 100%;
}
@media (min-width: 62rem) {
  .rooms__grid { grid-template-columns: minmax(0, 1.45fr) minmax(0, 0.62fr); }
}

/* Bildstapeln */
.rooms__media {
  position: relative;
  aspect-ratio: 3 / 2;
  overflow: hidden;
  background: var(--bg-sunken);
}
/* På desktop får bilden ta höjden i stället för att sitta i en liten
   ruta mitt på skärmen. Det är huset som är produkten. */
@media (min-width: 62rem) {
  .rooms__media { aspect-ratio: auto; height: min(80vh, 50rem); }
}
.roomshot {
  position: absolute;
  inset: 0;
  margin: 0;
  overflow: hidden;
  opacity: 1;
}
/* 104 % bas, skalas bara ner — aldrig upp */
.roomshot img {
  position: absolute;
  top: 50%; left: 50%;
  width: 104%; height: 104%;
  object-fit: cover;
  transform-origin: center;
  backface-visibility: hidden;
}
.rooms__stage.is-live .roomshot img { will-change: transform; }

/* Bildbytet: en mjuk ljuskant som stiger, inte ett svep.
   ------------------------------------------------------------------
   Principen från förra passet är riktig och behålls: nästa bild är helt
   ogenomskinlig, så två fotografier blandas aldrig över hela rutan och
   ingen dubbelexponering uppstår.

   Men clip-path ger en rakbladsrak kant. I skarpt läge stod två helt
   olika rum kant i kant mitt i vyn med en knivskarp lodrät linje mellan
   sig — det läser som en övergångsmall, inte som film. Att kanterna
   dessutom växlade riktning (vänster, höger, vänster) förstärkte
   intrycket av ett effektpaket.

   Därför mask-image i stället för clip-path: samma täckande avslöjande,
   men kanten är en toning på 22 % av höjden. Bara det smala bandet är
   halvgenomskinligt, aldrig hela bilden. Alla lager stiger nedifrån —
   ett språk, inte fem. Det läser som ljus som vandrar upp genom rummet.

   Fönstret är också dubbelt så långt som förut och centrerat kring det
   ögonblick då rumsnamnet växlar, i stället för att avslutas där. */
.roomshot:nth-of-type(n+2) {
  /* 4 %, inte 22. Ett brett toningsband ar en crossfade i utdragen
     form: over en femtedel av bilden syns tva fotografier samtidigt, och
     pa komplex arkitektur last det som dubbelexponering. Fyra procent ar
     tillrackligt for att kanten inte ska bli en mekanisk hArfin linje,
     men for smalt for att nagon yta ska uppfattas som blandad. */
  --mjuk: 4%;
  -webkit-mask-image: linear-gradient(to top,
    #000 calc(var(--wipe, 0) * (100% + var(--mjuk)) - var(--mjuk)),
    transparent calc(var(--wipe, 0) * (100% + var(--mjuk))));
  mask-image: linear-gradient(to top,
    #000 calc(var(--wipe, 0) * (100% + var(--mjuk)) - var(--mjuk)),
    transparent calc(var(--wipe, 0) * (100% + var(--mjuk))));
}
.roomshot:nth-of-type(2) { --wipe: clamp(0, calc((var(--p, 0) * 5 - 0.25) / 0.5), 1); }
.roomshot:nth-of-type(3) { --wipe: clamp(0, calc((var(--p, 0) * 5 - 1.25) / 0.5), 1); }
.roomshot:nth-of-type(4) { --wipe: clamp(0, calc((var(--p, 0) * 5 - 2.25) / 0.5), 1); }
.roomshot:nth-of-type(5) { --wipe: clamp(0, calc((var(--p, 0) * 5 - 3.25) / 0.5), 1); }
.roomshot:nth-of-type(6) { --wipe: clamp(0, calc((var(--p, 0) * 5 - 4.25) / 0.5), 1); }

.roomshot:nth-of-type(1) img { transform: translate3d(-50%, -50%, 0) scale(calc(1 - var(--l0, 1) * 0.038)); }
.roomshot:nth-of-type(2) img { transform: translate3d(-50%, -50%, 0) scale(calc(1 - var(--l1, 0) * 0.038)); }
.roomshot:nth-of-type(3) img { transform: translate3d(-50%, -50%, 0) scale(calc(1 - var(--l2, 0) * 0.038)); }
.roomshot:nth-of-type(4) img { transform: translate3d(-50%, -50%, 0) scale(calc(1 - var(--l3, 0) * 0.038)); }
.roomshot:nth-of-type(5) img { transform: translate3d(-50%, -50%, 0) scale(calc(1 - var(--l4, 0) * 0.038)); }
.roomshot:nth-of-type(6) img { transform: translate3d(-50%, -50%, 0) scale(calc(1 - var(--l5, 0) * 0.038)); }

/* Sidospalten */
.rooms__side { display: grid; gap: 1.2rem; align-content: center; }
.rooms__side h2 { max-width: 12ch; }

.rooms__list { list-style: none; padding: 0; display: grid; gap: 0; margin-top: 0.6rem; }

.room {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 0.2rem 1.1rem;
  padding-block: 0.85rem;
  border-top: 1px solid var(--line);
  align-items: baseline;
  transition: opacity 500ms var(--ease-out);
}
.room:last-child { border-bottom: 1px solid var(--line); }
.room__no {
  font-size: 0.6875rem;
  letter-spacing: var(--letter-label);
  color: var(--fg-subtle);
  transition: color 500ms var(--ease-out);
}
.room__titel {
  font-family: var(--font-display);
  font-size: clamp(1.15rem, 1rem + 0.7vw, 1.6rem);
  line-height: 1.2;
}
.room__text {
  color: var(--fg-muted);
  font-size: 0.9375rem;
  line-height: 1.55;
  max-height: 0;
  overflow: hidden;
  opacity: 0;
  transition: max-height 600ms var(--ease-out), opacity 400ms var(--ease-out), margin-top 600ms var(--ease-out);
}

/* Den aktiva raden fälls ut och de övriga tonas ned */
@media (min-width: 62rem) {
  .rooms__list .room { opacity: .42; }
  .rooms__stage[data-step="0"] .room:nth-child(1),
  .rooms__stage[data-step="1"] .room:nth-child(2),
  .rooms__stage[data-step="2"] .room:nth-child(3),
  .rooms__stage[data-step="3"] .room:nth-child(4),
  .rooms__stage[data-step="4"] .room:nth-child(5),
  .rooms__stage[data-step="5"] .room:nth-child(6) { opacity: 1; }

  .rooms__stage[data-step="0"] .room:nth-child(1) .room__no,
  .rooms__stage[data-step="1"] .room:nth-child(2) .room__no,
  .rooms__stage[data-step="2"] .room:nth-child(3) .room__no,
  .rooms__stage[data-step="3"] .room:nth-child(4) .room__no,
  .rooms__stage[data-step="4"] .room:nth-child(5) .room__no,
  .rooms__stage[data-step="5"] .room:nth-child(6) .room__no { color: var(--accent); }

  .rooms__stage[data-step="0"] .room:nth-child(1) .room__text,
  .rooms__stage[data-step="1"] .room:nth-child(2) .room__text,
  .rooms__stage[data-step="2"] .room:nth-child(3) .room__text,
  .rooms__stage[data-step="3"] .room:nth-child(4) .room__text,
  .rooms__stage[data-step="4"] .room:nth-child(5) .room__text,
  .rooms__stage[data-step="5"] .room:nth-child(6) .room__text {
    max-height: 8rem;
    opacity: 1;
    margin-top: 0.35rem;
  }
}

/* Mobil: bilden överst, en rad i taget under — ingen lång lista att
   scrolla förbi medan bilden står stilla. */
@media (max-width: 61.99rem) {
  .rooms__stage { align-items: center; padding-top: 0; }
  .rooms__grid { gap: 1.1rem; }
  /* Bilden ska äga skärmen, inte sitta som en liten ruta i mitten */
  .rooms__media { aspect-ratio: auto; height: min(56vh, 30rem); }
  .rooms__side { gap: 0.7rem; }
  .rooms__side h2 { display: none; }
  .rooms__side .label { display: block; }
  .rooms__list { position: relative; min-height: 7.5rem; margin-top: 0.2rem; }
  /* Förloppslinje under raden, mobilens motsvarighet till stegen */
  .rooms__list::before,
  .rooms__list::after {
    content: "";
    position: absolute;
    left: 0; right: 0; bottom: 0;
    height: 2px;
  }
  .rooms__list::before { background: var(--line); }
  .rooms__list::after {
    background: var(--accent);
    transform-origin: left;
    transform: scaleX(var(--p, 0));
  }
  /* Alla sex rader ligger absolut ovanpå varandra och byts med opacitet.
     Med en symmetrisk 500 ms-toning var både den utgående och den
     inkommande raden halvsynliga samtidigt — och eftersom de delar samma
     yta lade sig "Badrum" ovanpå "Master suite" och brödtexterna korsade
     varandra. Oläsbart, och just på sidans viktigaste sektion.

     Lösningen är att inte låta tonningarna överlappa: den gamla raden
     försvinner på 180 ms, den nya börjar först efter 200 ms. Bytet läser
     fortfarande som en mjuk övertoning, men bara en rad är läsbar i taget.
     visibility följer med så att bortdold text inte kan läsas upp av en
     skärmläsare eller fångas av träffytan. */
  .room {
    position: absolute;
    inset: 0 0 auto 0;
    border: 0;
    opacity: 0;
    visibility: hidden;
    padding-block: 0;
    transition: opacity 180ms var(--ease-out), visibility 0s linear 180ms;
  }
  .room:last-child { border-bottom: 0; }
  .room__text { max-height: none; opacity: 1; overflow: visible; margin-top: 0.35rem; }
  .rooms__stage[data-step="0"] .room:nth-child(1),
  .rooms__stage[data-step="1"] .room:nth-child(2),
  .rooms__stage[data-step="2"] .room:nth-child(3),
  .rooms__stage[data-step="3"] .room:nth-child(4),
  .rooms__stage[data-step="4"] .room:nth-child(5),
  .rooms__stage[data-step="5"] .room:nth-child(6) {
    opacity: 1;
    visibility: visible;
    transition: opacity 320ms var(--ease-out) 200ms, visibility 0s linear 200ms;
  }
  .roomshot img { width: 103%; height: 103%; }
}

/* På telefon ska luft vara en paus, inte en tom skärm. Den första
   berättelsen och de informationsrika slutsektionerna får därför ett
   tätare redaktionellt tempo än desktopversionen. */
@media (max-width: 47.99rem) {
  #bostaden.section,
  #planritningar.section,
  #omradet.section { padding-block: 4.5rem; }
  #bostaden .story { gap: 2.5rem; }
  /* Bilden ligger redan efter all text och behöver ingen dold väntzon.
     Den sena masktriggern såg ut som flera hundra pixlar saknat innehåll. */
  .js #bostaden .mask-reveal { clip-path: inset(0 0 0 0); }
  .js #bostaden .mask-reveal img {
    transform: translate3d(-50%, -50%, 0) scale(0.943);
  }
}

@media (prefers-reduced-motion: reduce) {
  .rooms { height: auto; }
  .rooms__stage { position: relative; height: auto; padding-block: var(--section-y); }
  .roomshot { position: relative; opacity: 1 !important; }
  .roomshot:nth-of-type(n+2) { display: none; }
  .roomshot img { position: relative; top: 0; left: 0; width: 100%; height: 100%; transform: none !important; }
  .rooms__list .room { opacity: 1 !important; position: relative; inset: auto; padding-block: 0.85rem; }
  .room__text { max-height: none !important; opacity: 1 !important; overflow: visible; }
}

/* Samma undantag som i scroll.css: galleribilderna ritas 103–104 %
   breda och får inte klippas av `img { max-width: 100% }` i base.css. */
.roomshot img,
.obj-hero__media img { max-width: none; max-height: none; }

/* ------------------------------------------------------------------ *
 * Filmlager
 * Videon monteras av js/media.js ovanpå stillbilden och tonas in först
 * när en bildruta finns. Stillbilden ligger kvar under — den är poster
 * och fallback, och den syns om filen aldrig laddar.
 * ------------------------------------------------------------------ */

/* :where() ger noll specificitet. Utan det skrev .cine över
   .obj-hero__media { position: absolute } — de har samma vikt och .cine
   står senare i filen — och heron krympte från 1425x900 till 714x476.
   Så här får varje värdelement behålla sin egen positionering. */
:where(.cine) { position: relative; }
.cine__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 900ms var(--ease-out);
  pointer-events: none;
}
.cine--spelar .cine__video { opacity: 1; }

/* ------------------------------------------------------------------ *
 * Helskärmsmoment
 * Tre andhämtningar där bilden tar hela vyn och texten är en rad. De
 * bär också dag → kväll-bågen: de två första ljusa, den sista mörk och
 * på väg in i avslutningen.
 * ------------------------------------------------------------------ */

.moment {
  position: relative;
  height: 100svh;
  min-height: 34rem;
  overflow: hidden;
  display: grid;
  align-items: end;
  background: var(--char-900);
  color: var(--sand-50);
}
.moment__media { position: absolute; inset: 0; }
.moment__media img,
.moment__media picture { width: 100%; height: 100%; display: block; }
.moment__bild {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Mycket lätt push-in. Fyra procent över hela genomfarten — det ska
     kännas som djup, inte som en rörelse man tittar på. */
  transform: scale(1.06) translate3d(0, var(--par, 0), 0);
}

/* Slöjan finns för textkontrast, inte för stämning. Den låg tidigare
   som ett svagt mörker över hela bilden inklusive himlen (.12 på mitten,
   .30 upptill) och tog ljuset ur fotografiet. Nu bara ett band underifrån
   där raden står — resten av bilden lämnas som fotografen tog den. */
.moment__scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(to top,
    rgba(16, 15, 14, .72) 0%,
    rgba(16, 15, 14, .30) 26%,
    rgba(16, 15, 14, 0) 56%);
}
/* Samma fel som i heron: .30 i toppen betyder att hela bilden mörkas.
   Det mörka momentet tål ett kraftigare band i botten — texten står mot
   ett redan skumt foto — men bandet ska ta slut. */
.moment--mork .moment__scrim {
  background: linear-gradient(to top,
    rgba(16, 15, 14, .90) 0%,
    rgba(16, 15, 14, .56) 30%,
    rgba(16, 15, 14, .18) 52%,
    rgba(16, 15, 14, 0) 70%);
}

/* Bredden kommer från .shell, som elementet också bär. Här läggs bara
   staplingen och bottenluften på. */
.moment__inner {
  position: relative;
  z-index: 2;
  padding-bottom: clamp(3rem, 2rem + 6vw, 7rem);
}
.moment__text {
  font-family: var(--font-display);
  font-size: clamp(2rem, 1.15rem + 3.6vw, 4rem);
  line-height: 1.06;
  letter-spacing: -0.025em;
  max-width: 17ch;
  text-wrap: balance;
  opacity: 0;
  transform: translate3d(0, 1.4rem, 0);
  transition: opacity 1400ms var(--ease-out), transform 1400ms var(--ease-out);
}
.moment__text.is-revealed { opacity: 1; transform: none; }

@media (max-width: 47.99rem) {
  /* På telefon centreras raden i stället för att hänga i underkant.
     Skälet är den fasta visningsknappen längst ned: en bottenankrad text
     passerar bakom den under en del av scrollningen, och det finns ingen
     bottenmarginal som håller i alla scrollägen. Centrerat är dessutom
     en bättre komposition på en hög smal skärm — raden får luft över och
     under i stället för att tryckas ned i ett hörn. */
  /* Texten flyttas tillbaka till underkanten. Den centrerades en gång för
     att undvika den fasta visningsraden — men den raden finns inte längre
     på demot (data-real-only), och centrerad text kräver slöja mitt i
     bilden. Med texten nere räcker ett band underifrån, och himlen och
     horisonten får vara rena. Det är skillnaden mellan ett foto som
     lever och ett som ligger under en grå hinna. */
  .moment { align-items: end; }
  .moment__inner { padding-bottom: 3.25rem; }
  .moment__scrim {
    background: linear-gradient(to top,
      rgba(16, 15, 14, .80) 0%,
      rgba(16, 15, 14, .42) 22%,
      rgba(16, 15, 14, .06) 46%,
      rgba(16, 15, 14, 0) 62%);
  }
}

/* ------------------------------------------------------------------ *
 * Lightbox
 * ------------------------------------------------------------------ */

body.lb-oppen { overflow: hidden; }

.lb {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: none;
  place-items: center;
  background: #0A0A09;
  padding: clamp(1rem, 0.5rem + 3vw, 3.5rem);
}
.lb.is-oppen { display: grid; animation: lb-in 320ms var(--ease-out) both; }
@keyframes lb-in { from { opacity: 0; } to { opacity: 1; } }

.lb__scen {
  margin: 0;
  display: grid;
  justify-items: center;
  gap: 1.25rem;
  max-width: 100%;
  max-height: 100%;
}
.lb__scen img {
  max-width: min(96vw, 1800px);
  max-height: 82svh;
  width: auto;
  height: auto;
  object-fit: contain;
}
.lb__cap {
  font-size: 0.8125rem;
  color: rgba(255, 255, 255, .58);
  text-align: center;
  max-width: 52ch;
  line-height: 1.5;
}

.lb__stang,
.lb__nav {
  position: absolute;
  display: grid;
  place-items: center;
  background: none;
  border: 0;
  color: rgba(255, 255, 255, .62);
  cursor: pointer;
  transition: color var(--dur) var(--ease-out), transform var(--dur) var(--ease-out);
}
.lb__stang:hover, .lb__nav:hover { color: #fff; }
.lb__stang:focus-visible,
.lb__nav:focus-visible { outline: 2px solid var(--brass-400); outline-offset: 4px; color: #fff; }

.lb__stang { top: clamp(1rem, 0.5rem + 2vw, 2.25rem); right: clamp(1rem, 0.5rem + 2vw, 2.25rem); width: 2.75rem; height: 2.75rem; }
.lb__stang svg { width: 15px; height: 15px; }

.lb__nav { top: 50%; transform: translateY(-50%); width: 3.5rem; height: 4.5rem; }
.lb__nav svg { width: 26px; height: 26px; }
.lb__nav--f { left: clamp(0.25rem, 0.5vw, 1.5rem); }
.lb__nav--n { right: clamp(0.25rem, 0.5vw, 1.5rem); }
.lb__nav--f:hover { transform: translateY(-50%) translateX(-3px); }
.lb__nav--n:hover { transform: translateY(-50%) translateX(3px); }

.lb__raknare {
  position: absolute;
  bottom: clamp(1rem, 0.5rem + 2vw, 2.25rem);
  left: 50%;
  transform: translateX(-50%);
  font-size: 0.6875rem;
  letter-spacing: var(--letter-label);
  color: rgba(255, 255, 255, .5);
  font-variant-numeric: tabular-nums;
}

@media (max-width: 47.99rem) {
  /* Pilarna tar plats från bilden på en telefon. Svep bläddrar i
     stället — knapparna finns kvar men flyttas ned i kanten. */
  .lb__nav { top: auto; bottom: clamp(0.75rem, 2vw, 1.5rem); transform: none; width: 3rem; height: 3rem; }
  .lb__nav--f { left: 18%; }
  .lb__nav--n { right: 18%; }
  .lb__nav--f:hover, .lb__nav--n:hover { transform: none; }
  .lb__scen img { max-height: 74svh; }
}

@media (prefers-reduced-motion: reduce) {
  .lb.is-oppen { animation: none; }
  .moment__text { transition-duration: 1ms; }
  .moment__bild { transform: scale(1.02); }
}

/* ------------------------------------------------------------------ *
 * Hero — ny hierarki
 * Namn, plats, pris. Inget mer. Knappen som stod här tidigare var det
 * enda gränssnittselementet ovanpå bilden, och den drog ned hela vyn
 * till en annons. Scrollhinten längst ned gör samma jobb tystare.
 * ------------------------------------------------------------------ */

.obj-hero__pris {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 1.1rem + 1.6vw, 2.25rem);
  letter-spacing: -0.02em;
  margin-top: clamp(1.5rem, 1rem + 2vw, 2.75rem);
  color: var(--sand-50);
}

/* Placering och tillstånd. Utseendet ligger samlat längre upp i filen —
   det fanns tidigare två fullständiga regeluppsättningar för samma
   element från olika pass, och den senare skrev tyst över den nyare
   färgsättningen. Här står nu bara det som är unikt för placeringen.

   Demoremsan ovanför navigeringen är 69 px hög och trycker ned hela
   scenen. Scenen är 100svh, så dess underkant hamnar under vyns
   underkant och allt som ankras där följer med ut ur bild — markören
   låg på y 857 i en vy som slutar vid 844. --demo-bar-h sätts av
   js/objekt.js och är 0 på ett skarpt objekt utan remsa. */
.obj-hero__scroll {
  right: var(--gutter);
  bottom: calc(clamp(1.5rem, 1rem + 2vw, 2.75rem) + var(--demo-bar-h, 0px));
  text-decoration: none;
  transition: color var(--dur) var(--ease-out), opacity var(--dur) var(--ease-out);
}
.obj-hero__scroll:hover { color: var(--sand-50); }
.obj-hero__scroll:focus-visible { outline: 1px solid var(--brass-400); outline-offset: 6px; }
.obj-hero__scroll i {
  /* Linjen andas i stället för att studsa. */
  animation: hint 4200ms var(--ease-out) infinite;
  transform-origin: top;
}
@keyframes hint {
  0%, 100% { transform: scaleY(.5);  opacity: .55; }
  45%      { transform: scaleY(1);   opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .obj-hero__scroll i { animation: none; transform: scaleY(1); opacity: .6; }
}
@media (max-width: 47.99rem) {
  /* På telefon visas bara linjen, centrerad i underkanten. Texten
     "Upptäck objektet" var det som tidigare krockade med prisraden —
     den gjorde markören 170 px bred i en 390 px vy. Utan etikett är
     den 1 px bred och står mitt emellan prisraden till vänster och
     kanten till höger, med drygt sjuttio pixlar luft åt båda håll. */
  .obj-hero__scroll {
    display: flex;
    left: 50%;
    right: auto;
    transform: translateX(-50%);
    /* Demoremsan trycker ned hela scenen 69 px. Scenen är 100svh, så
       dess underkant hamnar under vyns underkant och allt som ankras
       där följer med ut ur bild. --demo-bar-h sätts av js/objekt.js
       och är 0 på ett skarpt objekt utan remsa. */
    bottom: calc(1.1rem + var(--demo-bar-h, 0px));
    gap: 0;
  }
  .obj-hero__scroll span { display: none; }   /* bara linje och chevron */
  .obj-hero__scroll i { height: 1.6rem; }
}

/* ------------------------------------------------------------------ *
 * Avslutning
 * Sista sektionen ska bära lika mycket som heron. Rubriken sätts i
 * samma storleksregister som objektets namn; mäklarkortet ligger under
 * som upplysning, inte som huvudsak.
 * ------------------------------------------------------------------ */

.finale {
  display: grid;
  justify-items: center;
  text-align: center;
  gap: 1.5rem;
  max-width: 44rem;
  margin-inline: auto;
  padding-bottom: clamp(3.5rem, 2rem + 6vw, 7rem);
}
.finale__rubrik {
  font-family: var(--font-display);
  font-size: clamp(2.5rem, 1.5rem + 4.4vw, 5rem);
  line-height: 1.02;
  letter-spacing: -0.03em;
  max-width: 14ch;
  text-wrap: balance;
}
.finale__lead {
  font-size: var(--t-lead);
  line-height: 1.6;
  color: var(--fg-muted);
  max-width: 40ch;
}

/* ------------------------------------------------------------------ *
 * Dag → kväll
 * Resan genom huset går från förmiddagsljus till skymning. Det sker
 * inte med ett filter över sidan utan med bakgrundstonen under
 * innehållet: fyra steg, alla inom samma sandpalett, så små att man
 * inte ska lägga märke till dem — bara känna att det mörknar.
 * Helskärmsmomenten bär samma båge med sitt bildval.
 * ------------------------------------------------------------------ */

.tid--morgon      { background: var(--sand-50); }
.tid--dag         { background: var(--sand-100); }
.tid--eftermiddag { background: var(--sand-200); }

/* ------------------------------------------------------------------ *
 * Filmisk rörelse utan film
 * ------------------------------------------------------------------ *
 * Utan riktig video måste rörelsen komma från stillbilden. Två lager
 * arbetar oberoende av varandra:
 *
 *   <picture>  ambient drift — går hela tiden, oavsett scroll
 *   <img>      scrolldriven skala och parallax — som tidigare
 *
 * Att skilja dem åt är hela poängen. Låg man båda på samma element
 * skulle scrolltransformen skriva över driften varje bildruta.
 *
 * Takten är medvetet nästan omärklig: 34 sekunder från ytterläge till
 * ytterläge, fyra procent. Det ska läsas som att bilden andas, inte som
 * en Ken Burns-panorering i ett bildspel. En besökare ska inte kunna
 * peka på rörelsen — bara känna att vyn lever.
 * ------------------------------------------------------------------ */

.obj-hero__media picture {
  display: block;
  width: 100%;
  height: 100%;
  animation: drift 34s ease-in-out infinite alternate;
  transform-origin: 52% 46%;
}

/* Kvällsmomentet får samma behandling, men långsammare och åt andra
   hållet, så att de två inte rör sig i takt när man scrollar förbi. */
#moment-kvall .moment__media picture {
  display: block;
  width: 100%;
  height: 100%;
  animation: drift 46s ease-in-out infinite alternate-reverse;
  transform-origin: 46% 54%;
}

@keyframes drift {
  from { transform: scale(1); }
  to   { transform: scale(1.04); }
}

@media (prefers-reduced-motion: reduce) {
  .obj-hero__media picture,
  #moment-kvall .moment__media picture { animation: none; }
}

/* ------------------------------------------------------------------ *
 * Avsändaren
 * Houseflare står över objektets namn i viskningsstorlek — en byline,
 * inte en tillbaka-knapp. Pilen är ritad för hand i 1 px så att den
 * väger lika lite som texten; en ikon ur ett bibliotek hade blivit
 * tjockare än bokstäverna bredvid.
 * ------------------------------------------------------------------ */

.obj-nav__vanster {
  display: grid;
  gap: 0.3rem;
  justify-items: start;
  min-width: 0;
}

.obj-nav__avsandare {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  text-decoration: none;
  font-size: 0.5625rem;
  font-weight: 400;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: inherit;
  opacity: 0.62;
  transition: opacity var(--dur) var(--ease-out);
}
.obj-nav__avsandare svg {
  width: 12px;
  height: 10px;
  flex: none;
  /* Pilen kryper in mot texten vid hover — rörelsen är två pixlar och
     ska knappt märkas, bara antyda riktningen hem. */
  transition: transform var(--dur) var(--ease-out);
}
.obj-nav__avsandare:hover { opacity: 1; }
.obj-nav__avsandare:hover svg { transform: translateX(-2px); }
.obj-nav__avsandare:focus-visible {
  outline: 1px solid currentColor;
  outline-offset: 4px;
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .obj-nav__avsandare:hover svg { transform: none; }
}

@media (max-width: 47.99rem) {
  /* På telefon är utrymmet i navigeringsraden knappt. Avsändaren blir
     ännu mindre, men försvinner inte — det är enda vägen tillbaka utan
     webbläsarens bakåtknapp. */
  .obj-nav__avsandare { font-size: 0.5rem; letter-spacing: 0.2em; gap: 0.4rem; }
  .obj-nav__avsandare svg { width: 10px; height: 9px; }

  /* Bylinen över namnet är rätt på desktop, där headern bara syns en
     stund. På mobil ligger headern kvar hela vägen ned, och två rader
     gjorde den 74 px hög — en permanent list över var åttonde bildpunkt
     av skärmen. På en rad, med en hårfin avdelare, blir den ungefär
     hälften och läser som en enda tyst rad i stället för ett block. */
  .obj-nav__vanster {
    display: flex;
    align-items: center;
    gap: 0.55rem;
  }
  .obj-nav__name {
    font-size: 0.875rem;
    line-height: 1.1;
    padding-left: 0.55rem;
    border-left: 1px solid rgba(255, 255, 255, .2);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
}

/* Den fasta visningsraden ligger över innehållet. Sidfoten får därför en
   marginal som motsvarar radens höjd plus telefonens gestindikator, så
   att inget någonsin kan bli permanent övertäckt längst ned. */
/* Villkoret är viktigt. Codex gav visningsraden data-real-only, så
   js/objekt.js plockar bort den på demot — och då blev marginalen bara
   88 px dött utrymme längst ned på mobilen. :has() gör att luften bara
   finns när raden faktiskt gör det. Saknas :has()-stöd uteblir
   marginalen, vilket är exakt hur sidan såg ut innan. */
@media (max-width: 57.99rem) {
  body:has(.obj-sticky) .obj-footer {
    padding-bottom: calc(5.5rem + env(safe-area-inset-bottom));
  }
}

/* Demot avslutas som ett signerat designkoncept, inte som en låtsasannons. */
.demo-finale {
  display: grid;
  justify-items: center;
  gap: 1rem;
  text-align: center;
}
.demo-finale__note {
  max-width: 46ch;
  color: rgba(255, 255, 255, .54);
  font-size: 0.8125rem;
  line-height: 1.6;
}

/* ------------------------------------------------------------------ *
 * Galleriet i helskärm  (desktop)
 * ------------------------------------------------------------------ *
 * Sektionen är sidans längsta — 4,4 skärmhöjder av de 17 — men bilden
 * satt i en spalt på knappt halva bredden med gräddfärgad yta runt om.
 * Den del av sidan som scrollar längst levererade alltså minst.
 *
 * Nu tar bilden hela scenen och texten lägger sig över den som en
 * filmtextremsa. Ingen ny funktion, inga nya bilder — samma sex foton,
 * men i den storlek de förtjänar. Det är här WOW ska sitta.
 * ------------------------------------------------------------------ */

@media (min-width: 62rem) {
  .rooms__stage { align-items: flex-end; }

  /* Bilden bryter ut ur .shell och fyller scenen. Scenen är sticky och
     bildar därmed containing block för den absoluta positioneringen. */
  .rooms__media {
    position: absolute;
    inset: 0;
    height: auto;
    aspect-ratio: auto;
    z-index: 0;
  }

  /* Läsbarhet: mörkret ligger bara där texten står, inte över hela
     fotot. En jämn slöja hade grumlat arkitekturen i onödan. */
  /* Slöjan måste bära ända upp till rubriken och vara tät nog för att
     hålla även mot ett soligt fönsterparti — de ljusaste bilderna i
     galleriet är det som sätter nivån, inte de mörkaste. */
  /* Slöjan sitter på SCENEN, inte på .shell. Låg den på griden blev den
     lika bred som textspalten — och på 2560 px betydde det 1137 px
     obehandlad gräddyta på sidorna. Scenen är sticky och därmed
     positionerad, så både bild och slöja kan fylla hela vyn. */
  /* Slöjan låg som ett jämnt mörkerlager över 68 % av bilden och tog
     livet ur interiörerna — ett dyrt, ljust hem blev grått. Texten står
     bara nere till vänster, så mörkret behöver bara finnas där. Två
     gradienter i stället för en: ett band underifrån och ett från
     vänsterkanten. Bildens övre högra två tredjedelar lämnas orörda. */
  .rooms__stage::after {
    content: "";
    position: absolute;
    inset: 0;
    background:
      linear-gradient(to top,
        rgba(16, 15, 14, .78) 0%,
        rgba(16, 15, 14, .40) 24%,
        rgba(16, 15, 14, 0) 54%),
      linear-gradient(to right,
        rgba(16, 15, 14, .42) 0%,
        rgba(16, 15, 14, .10) 34%,
        rgba(16, 15, 14, 0) 58%);
    pointer-events: none;
    z-index: 1;
  }

  /* INGEN position:relative här. Griden ligger i .shell, och hade den
     varit positionerad skulle den bli containing block för bilden och
     klippa den till spaltbredden. */
  .rooms__grid {
    grid-template-columns: minmax(0, 1fr);
    align-items: end;
    padding-bottom: clamp(2.5rem, 1.5rem + 4vw, 5rem);
    min-height: 100svh;
    align-content: end;
  }

  .rooms__side {
    position: relative;
    z-index: 2;
    color: var(--sand-50);
    max-width: 34rem;
    gap: 0.9rem;
  }
  .rooms__side h2 { max-width: 14ch; }
  .rooms__side .label--rule { color: rgba(255, 255, 255, .72); }
  .rooms__side .label--rule::before { background: rgba(255, 255, 255, .42); }

  /* Indexet blir en rad tunna linjer i stället för en tabell — en
     förloppsindikator som går att läsa, inte en lista att plöja. */
  /* Indexet får hela spaltbredden. Instängt i 30 rem blev kolumnerna
     80 px breda och raden såg hoptryckt ut bredvid en bild i 1440 px. */
  .rooms__list {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    gap: clamp(1rem, 0.5rem + 1.5vw, 2.25rem);
    margin-top: 1.8rem;
    max-width: none;
  }
  .rooms__list .room {
    border: 0;
    border-top: 1px solid rgba(255, 255, 255, .26);
    padding-block: 0.7rem 0;
    grid-template-columns: minmax(0, 1fr);
    gap: 0.25rem;
    opacity: .38;
    transition: opacity 420ms var(--ease-out), border-color 420ms var(--ease-out);
  }
  .rooms__list .room:last-child { border-bottom: 0; }
  .room__text { display: none; }          /* rubriken räcker i indexet */
  .room__no { font-size: 0.5625rem; color: rgba(255, 255, 255, .6); }
  .room__titel { font-size: 0.9375rem; }

  .rooms__stage[data-step="0"] .room:nth-child(1),
  .rooms__stage[data-step="1"] .room:nth-child(2),
  .rooms__stage[data-step="2"] .room:nth-child(3),
  .rooms__stage[data-step="3"] .room:nth-child(4),
  .rooms__stage[data-step="4"] .room:nth-child(5),
  .rooms__stage[data-step="5"] .room:nth-child(6) {
    opacity: 1;
    border-top-color: var(--brass-400);
  }
}

/* ------------------------------------------------------------------ *
 * Galleriet utan rörelse
 * Vid prefers-reduced-motion görs .rooms__stage om till vanligt flöde
 * med height:auto. En absolut positionerad bildyta med inset:0 skulle
 * då kollapsa till noll höjd och sektionen bli tom. Reglerna nedan
 * står sist i filen och vinner därför över helskärmsblocket ovan.
 * ------------------------------------------------------------------ */

@media (prefers-reduced-motion: reduce) {
  .rooms__media {
    position: relative;
    inset: auto;
    height: min(70vh, 40rem);
  }
  .rooms__grid {
    min-height: 0;
    padding-bottom: 0;
    grid-template-columns: minmax(0, 1fr);
    gap: 2rem;
  }
  .rooms__stage::after { display: none; }   /* ingen slöja utan överlagring */
  .rooms__side { color: var(--fg); max-width: none; }
  .rooms__side .label--rule { color: var(--fg-subtle); }
  .rooms__side .label--rule::before { background: var(--line-strong); }

  /* Indexet blir en läsbar lista igen, med sina beskrivningar */
  .rooms__list { grid-auto-flow: row; margin-top: 1rem; }
  .rooms__list .room {
    grid-template-columns: auto minmax(0, 1fr);
    gap: 0.2rem 1.1rem;
    border-top: 1px solid var(--line);
    padding-block: 0.85rem;
  }
  .room__text { display: block; }
  .room__no { color: var(--fg-subtle); }
}

/* ------------------------------------------------------------------ *
 * Utsiktsmomentet — rörelsen bär idén
 * ------------------------------------------------------------------ *
 * Tidigare låg här en stor bild med en liten bildtext över. Bilden var
 * bra, texten var en caption, och tillsammans blev det ingenting man
 * mindes.
 *
 * Nu är sektionen scrolldriven. Bilden börjar hårt beskuren inne i
 * rummet och öppnar sig mot glaspartiet medan man passerar — arton
 * procent skala över hela genomfarten. Texten kommer först när
 * öppningen är påbörjad, inte när sektionen råkar snudda vyn.
 *
 * Poängen: huset är ritat kring utsikten, och scrollen gör det
 * påståendet i stället för att bildtexten ska behöva göra det.
 * ------------------------------------------------------------------ */

#moment-utsikt .moment__bild {
  transform: scale(calc(1.20 - var(--p, 0) * 0.18)) translate3d(0, var(--par, 0), 0);
  transform-origin: 62% 58%;   /* öppnar ut mot glaspartiet, inte från mitten */
}

/* Texten träder in mellan 38 % och 62 % av genomfarten — mitt i
   öppningen, när det finns något att sätta ord på. */
#moment-utsikt .moment__text {
  --in: clamp(0, calc((var(--p, 0) - 0.38) / 0.24), 1);
  opacity: var(--in);
  transform: translate3d(0, calc((1 - var(--in)) * 1.4rem), 0);
  transition: none;
}

@media (prefers-reduced-motion: reduce) {
  /* Utan rörelse blir det en stilla bild med sin rad. */
  #moment-utsikt .moment__bild { transform: scale(1.02); }
  #moment-utsikt .moment__text { --in: 1; opacity: 1; transform: none; }
}

/* ------------------------------------------------------------------ *
 * Mobilens egen rytm
 * ------------------------------------------------------------------ *
 * Desktopluften översatt rakt av blir för mycket på en 390 px skärm.
 * Här dras den in där den bara var tomrum, och läggs på där den gör
 * något — bilderna får mer plats, mellanrummen mindre.
 * ------------------------------------------------------------------ */

@media (max-width: 47.99rem) {
  /* Statistiken slutade 60 px före sektionsslut och galleriets scen
     lade ytterligare 100 px luft ovanför bilden. Sammanlagt en 160 px
     bred gräddremsa mellan sista siffran och första bilden — det var
     den som läste som saknat innehåll. */
  .stats { gap: 2.25rem 1.5rem; }
  .section--tight:has(.stats) { padding-bottom: 2.25rem; }

  /* Bilden äger mer av skärmen och scenen slutar centrera bort luften
     ovanför den. 64vh i stället för 56vh — på en hög smal skärm är det
     skillnaden mellan ett bildblock och en bild. */
  .rooms__media { height: min(64vh, 34rem); }
  .rooms__stage { align-items: center; padding-top: 1rem; }
}

/* ------------------------------------------------------------------ *
 * "Bostaden" på telefon — egen art direction
 * ------------------------------------------------------------------ *
 * Desktoplayouten översatt rakt av gav: rubrik, två stycken, och sedan
 * en bild på 231 px i en vy på 844. Bilden blev en illustration till
 * texten i stället för sidans nästa moment, och sekvensen läste som en
 * responsiv artikel — text, JPG, luft, JPG.
 *
 * Här får mobilen en egen komposition. Bilden går ut i kanterna, blir
 * mer än dubbelt så hög, och de två bilderna i följd får olika vikt:
 * först en hög stående som äger skärmen, sedan den breda interiören.
 * Rytm i stället för staplade rektanglar.
 * ------------------------------------------------------------------ */

@media (max-width: 47.99rem) {
  .story { gap: 1.75rem; }

  /* Ut i kanterna. .shell har gutter-padding, så bilden dras ut med
     samma mått åt båda håll. */
  .story__media {
    --media-ratio: 4 / 5;
    margin-inline: calc(var(--gutter) * -1);
    width: calc(100% + var(--gutter) * 2);
  }

  /* Texten behöver inte lika mycket luft under sig när bilden kommer
     direkt efter och tar över skärmen. */
  .story__body { gap: 1.15rem; }

  /* Den breda interiörbilden får ligga kvar i sin ram — kontrasten mot
     den utfallande stående bilden ovanför är hela poängen. */
  .expand__frame { margin-top: 0; }
}

/* ------------------------------------------------------------------ *
 * "Bostaden" på telefon — två bilder, två roller
 * ------------------------------------------------------------------ *
 * Tidigare: text, bild, luft, bild — två JPG-filer i följd, alltså exakt
 * formen på en responsiv artikel. Nu får de olika vikt och funktion.
 *
 *   FÖRSTA (stående, utfallande):  arkitekturen, höjden, glaset.
 *                                  Äger skärmen, edge to edge.
 *   ANDRA  (liggande, indragen):   rummet, materialen, ljusets riktning.
 *                                  Sitter i sin ram och läses som detalj.
 *
 * Kontrasten mellan utfallande och inramad är hela rytmen. Mellanrummet
 * mellan dem är kort — pausen ska vara ett andetag, inte en lucka.
 * ------------------------------------------------------------------ */

@media (max-width: 47.99rem) {
  /* Den utfallande bilden får djupare format så arkitekturen får höjd */
  #bostaden .story__media { --media-ratio: 3 / 4; }

  /* Andetaget mellan bilderna, inte en lucka */
  #bostaden { padding-bottom: 1.5rem; }
  .expand { padding-top: 1.5rem; }

  /* Andra bilden: ramen hade width:100% från grundregeln, så
     margin-inline sköt ut den utanför skärmen i stället för att dra in
     den — den renderades 390 px bred och 293 px hög, alltså en remsa
     utan egen roll. width:auto låter marginalen faktiskt beskära den.
     Asymmetrin är avsiktlig: bilden är indragen från VÄNSTER och går ut
     i högerkanten. Första bilden äger hela skärmen stående; den här
     ligger förskjuten och kvadratisk. Två bilder, två format, två
     roller — inte "bild ett" och "bild två". */
  .expand__frame {
    width: auto;
    margin-left: 2.75rem;
    margin-right: 0;
    aspect-ratio: 1 / 1;
  }
  /* Ridåerna smalnar med den smalare ramen */
  .expand__bar--l, .expand__bar--r { width: 9%; }
  .expand__bar--t, .expand__bar--b { height: 9%; }

  /* Materialraden hamnar i vänsterkanten under den förskjutna bilden
     och stänger kompositionen som ett L. */
  .expand__cap { margin-top: 1.35rem; max-width: 18ch; }
}

/* ------------------------------------------------------------------ *
 * Mobil header — alltid tillgänglig, aldrig påträngande
 * Headern låg tidigare under samma is-hidden-regel som desktop och
 * försvann helt vid nedåtscroll. På mobil är den nu kvar permanent.
 * Tre lägen: över hero (nästan osynlig ram), efter scroll (translucent
 * charcoal med hårfin linje), och vilande (nedtonad efter stillhet).
 * ------------------------------------------------------------------ */
@media (max-width: 47.99rem) {
  .obj-nav.is-hidden { transform: none; }

  .obj-nav {
    padding-block: 0.85rem;
    padding-top: calc(0.85rem + env(safe-area-inset-top));
    transition: background-color 420ms var(--ease-out),
                border-color 420ms var(--ease-out),
                opacity 520ms var(--ease-out),
                padding 420ms var(--ease-out),
                top 420ms var(--ease-out);
  }

  /* Efter scroll: charcoal på 78 % och en enda hårfin linje. Ingen
     stor glaspanel — bara tillräckligt för att bära texten mot foto. */
  .obj-nav.is-stuck {
    background: rgba(20, 19, 18, .78);
    border-bottom-color: rgba(255, 255, 255, .09);
    padding-block: 0.7rem;
    padding-top: calc(0.7rem + env(safe-area-inset-top));
  }
  @supports (backdrop-filter: blur(6px)) {
    .obj-nav.is-stuck {
      background: rgba(20, 19, 18, .62);
      backdrop-filter: blur(10px) saturate(115%);
    }
  }

  /* Vilande: nedtonad, men aldrig borta och aldrig oklickbar. */
  .obj-nav.is-idle { opacity: 0.5; }
}

@media (prefers-reduced-motion: reduce) {
  .obj-nav.is-idle { opacity: 1; }
}

/* Platsraden i footern. Objektets namn ensamt avslutade sidan lite
   tvärt — namn och läge tillsammans läser som en signatur. */
.obj-footer__plats {
  margin-top: 0.35rem;
  font-size: 0.75rem;
  letter-spacing: var(--letter-label);
  text-transform: uppercase;
  color: var(--fg-muted);
}
