/* =========================================================================
 * DARWESH HOME -- ONE ROOM, ONE CAMERA
 * =========================================================================
 * Replaces css/home-luxury.css entirely. That file's failure was structural,
 * not decorative: it built the page out of ten sections, each painting its
 * own opaque background, which produced 5 hard seams, 2 flat colour bands
 * and 688px of dead gap. Measured, exactly 1 element in the whole page ever
 * crossed a section boundary -- so there was nothing to carry a visitor
 * across one.
 *
 * THE INVERSION. The page is no longer MADE OF sections. It is one
 * continuous environment, and the movements are content travelling through
 * it. Movements paint no background at all. There is therefore no y
 * coordinate at which a background can change: the seam count is zero by
 * construction rather than by tuning.
 *
 * Scoped to `body.world`. Nothing here applies to another page.
 * ========================================================================= */

body.world {
  /* --- DARK LUXURY REFINEMENT (color-only restyle, current pass) --------
     Replaces the light-luxury migration this comment used to describe.
     The world is dark-dominant again, but unlike the pre-light version,
     BOTH gradient recipes in .world-field below (.wf-navy / .wf-ivory)
     now come from the SAME dark family -- there is no true light/white
     zone left on Home at all. .wf-ivory keeps its old class name (it's
     an internal hook, not a rendered color) but now means "the lighter
     of two dark tiers" -- see the ramp comment further down for how that
     still produces real tonal separation (deep navy/obsidian vs. an
     elevated, slightly warmer dark) without ever going bright.
     Because neither tier is ever light, the --on-stone text-flip this
     file used to drive (ivory ink on navy vs. dark ink on white) has no
     light state left to flip to. It is pinned to a constant below (see
     --on-stone) rather than reworking every color-mix() call site that
     reads it -- each of those keeps its old two-branch shape, but the
     "on light" branch is now permanently unreachable, called out at each
     site rather than deleted, so this stays a color/token change and not
     a structural rewrite of section 2's rules.

     DARK LUXURY CORRECTION (follow-up pass): the dark family above was
     initially a navy one (#071D33/#0D263B/#132E45), which read as
     corporate blue at full-page scale -- flagged directly against the
     Intro overlay, which never used those values and reads correctly.
     Every hex below is now a genuinely neutral obsidian/charcoal instead
     (see css/cinematic.css's header comment for the full palette and
     its git-history/Intro provenance); "--w-navy" keeps its name only
     because renaming it would touch every consumer in this file for no
     visual gain -- the value itself is obsidian, never blue. */
  /* Ivory pearl marble. --w-navy / --w-ivory / --w-gold keep their
     historical names. Ivory field, pearl glass, graphite type,
     champagne only on small marks. */
  --w-navy:     #F6F1E8;
  --w-navy-hi:  #FBF7F0;
  --w-ivory:    #FBF7F0;
  --w-ivory-lo: #F6F1E8;

  --w-r-s: 12px;
  --w-r-m: 18px;
  --w-r-l: 26px;
  --w-r-hero: 32px;

  --w-platinum:  #FBF7F0;
  --w-silver:    #E3D8C8;
  --w-glass:     rgba(255, 255, 255, 0.58);
  --w-glass-mid: rgba(255, 255, 255, 0.76);
  --w-glass-border: #E3D8C8;
  --w-glass-hi:  rgba(255, 255, 255, 0.76);
  --w-gold:      #B49A6A;
  --w-gold-hi:   #D4C4A0;
  --w-gold-deep: #B49A6A;
  --w-green:     #2F4439;

  --w-ink:      #2F2A26;
  --w-ink-soft: #6E6258;
  --w-ink-dark: #2F2A26;
  --w-ink-dark-mute: #6E6258;
  --w-muted:    #6E6258;

  --w-hair:     rgba(42, 45, 49, 0.12);
  --w-hair-warm:rgba(185, 154, 99, 0.42);

  --w-ease:     cubic-bezier(.2, .8, .2, 1);
  --w-ease-out: cubic-bezier(.2, .8, .2, 1);
  --w-fast: 160ms;
  --w-mid: 200ms;
  --w-slow: 680ms;

  /* Depth. Three planes, assigned by MEANING (see §3), never by position. */
  --w-z-fore: 0px;
  --w-z-mid: -46px;
  --w-z-back: -130px;

  /* One spacing scale for the whole journey. */
  --w-air-s: clamp(1.5rem, 3vw, 2.5rem);
  --w-air-m: clamp(3rem, 6vw, 5.5rem);
  --w-air-l: clamp(5rem, 10vw, 9rem);

  background: var(--w-navy);
  color: var(--w-ink);
}
/* cinematic.css paints .cine-scope.bg-background dark at higher specificity
   than body.world. Home overrides only its own body so the light field
   is the page color, not a layer sitting on leftover obsidian. */
body.world.cine-scope.bg-background { background-color: #F6F1E8; color: #2F2A26; }
/* --journey is written by js/cine-scroll-3d.js onto the ROOT element: 0 at
   the top of the document, 1 at the bottom. Everything atmospheric derives
   from it. Declared here (not on body.world) so the JS value inherits down
   instead of being shadowed by a body-level declaration. */
:root { --journey: 0; --scroll-y: 0px; }

/* =========================================================================
 * 1. THE PERSISTENT WORLD
 * =========================================================================
 * One fixed element. It never scrolls, never repeats, and has no edge
 * anywhere in the document, so no scroll position can reveal a boundary.
 *
 * DARK LUXURY REFINEMENT. Both recipes below, .wf-navy and .wf-ivory, are
 * now from the same dark family -- there is no light station left on this
 * page at all, so the failure mode the previous two rebuilds each fought
 * (a text-color flip has to cross a mid-grey-on-mid-grey band somewhere in
 * a light<->dark crossfade -- measured once at 1.19:1, far below AA) can't
 * occur here: headings and body copy stay Warm Ivory for the whole journey
 * (see --on-stone below, now a constant), so nothing about this ramp has
 * to protect a flip that no longer exists.
 *
 * That frees the ramp to go back to FIVE alternating zones purely for
 * background DEPTH -- "main background -> slightly lighter section ->
 * dark card -> photographic section -> deep navy CTA", per the dark-
 * luxury brief's tonal-separation requirement, rather than the single
 * end-loaded ramp the light-luxury pass used. Only two actual background
 * recipes exist, .wf-navy (deep navy/obsidian) and .wf-ivory (an
 * elevated, slightly warmer dark card tone -- see the token block above
 * for why that name is now misleading but kept), cross-added below via
 * the same "running difference of cumulative ramps" technique as before:
 * the four ramps t1..t4 are each a narrow, independent crossfade window,
 * and because every zone boundary uses the same width, opacity_navy +
 * opacity_ivory telescopes to exactly 1 at every point in the journey by
 * construction, so there is still no seam and no darken/bloom at a
 * handover -- only which dark tier is momentarily dominant changes. */
/* --t1..--t4 / --navy-mix live on body.world. They no longer strictly have
   to (--on-stone is a constant now -- see below -- so nothing on this same
   element reads --navy-mix back), but declaring them here still means
   every descendant that DOES read them (.world-field's children, several
   levels down) inherits the value with zero extra wiring, so there is no
   reason to move them. */
body.world {
  /* DARK LUXURY REFINEMENT: back to five alternating zones (as the
     original pre-light-luxury version used), retuned so the DEEP navy/
     obsidian tier dominates rather than the elevated one -- per the
     brief's "55-65% deep navy/obsidian, 20-25% elevated dark/navy
     surfaces" balance. Zones, by --journey position:
       navy    [0,     0.12]  Hero
       elevated[0.20,  0.32]  Intent
       navy    [0.40,  0.64]  City Discovery + Properties (dark-card zone)
       elevated[0.72,  0.84]  Installments / Trust
       navy    [0.92,  1.0 ]  Departure / Footer close
     with an 0.08-wide crossfade at each boundary (t1..t4). Pure-navy time
     (.44) plus half of the four transition bands (.16) is ~60% of the
     journey; pure-elevated (.24) plus its half-share (.16) is ~40% --
     comfortably inside the target range once real photography (Hero
     image, city/property cards) supplies its own share of warm-ivory
     brightness on top. */
  --t1: clamp(0, calc((var(--journey) - 0.12) / 0.08), 1);
  --t2: clamp(0, calc((var(--journey) - 0.32) / 0.08), 1);
  --t3: clamp(0, calc((var(--journey) - 0.64) / 0.08), 1);
  --t4: clamp(0, calc((var(--journey) - 0.84) / 0.08), 1);
  --navy-mix: calc(1 - var(--t1) + var(--t2) - var(--t3) + var(--t4));
}
/* Clean ivory field. Flat. No silk, marble, or pattern. */
.world-field {
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
  isolation: isolate;
  background-color: #F6F1E8;
  background-image: none;
}
.world-field::before,
.world-field::after {
  content: none;
  display: none;
  background: none;
  background-image: none;
}
.world-field > i { display: none; }

/* Everything the visitor reads sits above the world. */
body.world main { position: relative; z-index: 1; }

/* THE OLD SCENE SURFACES ARE SWITCHED OFF HERE.
   css/cinematic.css still gives every [data-cine3d] scene a lit surface
   plane and an atmosphere layer -- the mechanism from the previous two
   passes, which is exactly the bordered rounded rectangle per section that
   this redesign exists to remove. They are neutralised rather than deleted
   from that file because cinematic.css is shared with login/signup and the
   other cinematic pages, which still use them correctly. */
body.world [data-cine3d="rail"]::before,
body.world [data-cine3d="rail"]::after,
body.world [data-cine3d="cards"]::before,
body.world [data-cine3d="cards"]::after,
body.world [data-cine3d="hero"]::after { content: none; display: none; }

/* AND THE SECTION MOTION ITSELF -- the actual source of the shutter.
   css/cinematic.css gives every [data-cine3d] scene a scroll-driven
   transform on the SECTION:

     [data-cine3d="rail"], [data-cine3d="cards"] {
       transform: perspective(1400px)
         translate3d(0, calc(var(--e) * 90px - var(--l) * 70px),
                        calc(var(--d) * -220px))
         scale(calc(1 - var(--e) * 0.06 - var(--l) * 0.08));
       opacity: calc(1 - var(--e) * 0.25 - var(--l) * 0.5); }

   90px of vertical travel, 220px of Z and a 0.92 scale, applied to a whole
   <section>. That is a rectangular panel moving as one object, and it is
   the largest movement on the page by an order of magnitude -- the
   `.w-arrive` block motion this pass removed was only ever riding on top of
   it. Measured before this rule existed: a .mv still carried y=-26.6px
   z=-41.7px at scrollY 5562 even after every Home-side transform was gone.

   Neutralised here rather than deleted from css/cinematic.css, which is
   loaded by all 33 pages for its palette and is left untouched by this
   pass. (index.html is in fact the only page carrying a data-cine3d
   attribute, so these rules are now inert everywhere -- but removing them
   is a wider change than fixing Home's scroll, and this pass does not make
   it.) Home's motion comes from the flow system in section 3 and nowhere
   else: one mechanism, not two competing ones. */
body.world [data-cine3d],
body.world [data-cine3d="hero"],
body.world [data-cine3d="hero-media"],
body.world [data-cine3d="rail"],
body.world [data-cine3d="cards"],
body.world [data-cine3d="promo"] {
  transform: none;
  opacity: 1;
  isolation: auto;
}
/* Note on ordering: .w-hero-plane carries BOTH data-cine3d="hero-media" and
   data-flow="visual", and the two selectors have identical specificity, so
   the flow rule wins only because section 3 comes later in this file. Do not
   move this block below it. Nothing here touches `position`: the hero plane
   is absolutely positioned and resetting that would drop it out of its
   composition entirely. */

/* =========================================================================
 * 2. MOVEMENTS
 * =========================================================================
 * A movement has NO background, NO border and NO fill. It is a region of
 * the journey, not a box. It carries only its own scroll progress (--mp,
 * 0 entering -> 1 leaving, written by the shared controller) which its
 * contents use to arrive and recede.
 *
 * Movements deliberately OVERLAP: each pulls up into the previous one so
 * the outgoing composition is still on screen while the next arrives. That
 * overlap is what replaces the old 688px of dead gap. ==================== */
body.world .mv {
  /* A movement is a LAYOUT container and nothing else. It has no progress
     value, no transform, no opacity and no z-index -- deliberately, because
     every one of those turns it into an animated rectangle. The old --mp
     alias (of --section-progress) lived here and drove `.w-arrive` /
     `.w-recede` / `.w-carry`; all three now read their own element's --fp
     instead, so nothing on this page is animated per-section any more. */
  position: relative;
  padding-block: var(--w-air-l);
  /* THE OVERLAP. Each movement pulls up into the previous one so the
     outgoing composition is still on screen while the next arrives -- this
     is what replaced the old 688px of dead gap between sections.
     Eased from -2.1x to -1.4x. At -2.1x the overlap (185px at desktop
     width) exceeded the movement's own top padding (144px), so two content
     boxes genuinely intersected. That was survivable only while the
     controller was writing a z-index to decide which won -- which is
     exactly the mechanism that made sections look like panels sliding over
     each other, and it is gone. At -1.4x the AIR overlaps and the CONTENT
     never does, so there is still no gap and nothing to stack. */
  margin-block-start: calc(var(--w-air-m) * -1.4);
}
body.world .mv:first-of-type { margin-block-start: 0; }
body.world .mv-in {
  width: 100%;
  max-width: 1340px;
  margin-inline: auto;
  padding-inline: clamp(1.25rem, 4vw, 4.5rem);
  position: relative;
}

/* Text tone no longer follows the world. --on-stone used to flip between
   "dark ink on a light ivory ground" (1) and "light ink on navy" (0) as
   --navy-mix crossed 0.5 -- see section 1's DARK LUXURY REFINEMENT comment
   for why that ground no longer exists: both .wf-navy and .wf-ivory are
   dark now, so there is nothing left to flip to. Pinned to a constant 0
   instead of deleting every color-mix() call site below: each keeps
   resolving to its var(--w-ink)/var(--w-ink-soft) ("light ink") branch
   for the whole journey, and the var(--w-ink-dark)/var(--w-ink-dark-mute)
   branch is unreachable dead code (documented at its declaration in the
   token block above), not a bug. */
body.world { --on-stone: 1; }
body.world .w-display,
body.world .w-h2,
body.world .w-h3 {
  color: color-mix(in oklab, var(--w-ink) calc((1 - var(--on-stone)) * 100%), var(--w-ink-dark));
}
body.world .w-body {
  color: color-mix(in oklab, var(--w-ink-soft) calc((1 - var(--on-stone)) * 100%), var(--w-ink-dark-mute));
}

/* The shadow exists for type sitting over photography (Hero), where it is
   still needed regardless of the world's own tone -- but a dark shadow
   under dark navy text on an ivory ground reads as a smudge, not depth.
   Scaled by (1 - on-stone) so it fades to nothing exactly where the text
   itself has flipped dark. */
body.world .w-display,
body.world .w-h2,
body.world .w-h3,
body.world .w-body {
  text-shadow: 0 1px 20px rgba(6, 6, 9, calc((1 - var(--on-stone)) * 0.72));
}
/* The eyebrow is the smallest, lightest-weight type on the page and often
   sits over a carried photograph, so it carries the strongest halo of
   anything here -- measured, not assumed. */
body.world .w-label {
  color: var(--w-gold-deep);
  /* Scaled by (1 - on-stone), same treatment as headings/body above: full
     halo over Departure's photography-on-navy, none over the light zones
     where a heavy black halo behind small gold caps would read as a smudge. */
  text-shadow:
    0 1px 3px rgba(6, 6, 9, calc((1 - var(--on-stone)) * 0.95)),
    0 2px 22px rgba(6, 6, 9, calc((1 - var(--on-stone)) * 0.85));
}

/* =========================================================================
 * 3. FLOW -- the scroll choreography. Elements, never sections.
 * =========================================================================
 * WHAT THIS REPLACED, AND WHY.
 *
 * The previous system animated whole compositions: `.w-arrive` moved an
 * entire copy block 34px up and 140px back in Z as one object, `.w-recede`
 * sank the outgoing half the same way, and js/cine-scroll-3d.js gave each
 * section a scroll-driven z-index so the centred one painted over its
 * neighbours. Every part of that was deliberate and every part of it was
 * wrong: a section is a rectangle, so animating one animates a rectangle,
 * and rectangles sliding over rectangles read as a shop shutter no matter
 * how gently they are eased. It is not a tuning problem. A block that moves
 * is a block you can see moving.
 *
 * So nothing here animates a `.mv`. Every value below is applied to a
 * single ELEMENT -- one headline, one photograph, one paragraph -- and each
 * element derives its progress from ITS OWN box (js/cine-scroll-3d.js's
 * flowProgress). Two elements in the same movement therefore hold different
 * progress at the same instant and drift apart by themselves. That is the
 * mechanism: no shared value exists for a block to move by.
 *
 * THE WINDOW. Each element's travel is split into three, and the middle one
 * is the point of the whole design:
 *
 *   0.06 -> 0.30   ENTER   rising in, becoming legible
 *   0.30 -> 0.74   HOLD    nothing moves at all
 *   0.74 -> 0.98   EXIT    going quiet as it leaves the top
 *
 * The hold spans the entire comfortable reading band, so text is never
 * moving or fading while it is being read -- the difference between motion
 * that supports content and motion that competes with it. The exit is what
 * keeps the promise that old content is gone before new content is
 * readable: an element only starts leaving once it is ~190px from the top
 * of the viewport, by which point the next one is still deep in its hold.
 *
 * --fp DEFAULTS TO 0.5, deliberately: mid-hold, fully settled, fully
 * opaque. If the controller never runs -- JS disabled, a script error, a
 * blocked file -- every element resolves to its finished state and the page
 * reads perfectly. An entrance animation must never be the thing that
 * decides whether content exists.
 *
 * The per-role windows below are overridden by setting --in-start/--in-len/
 * --out-start/--out-len rather than by redeclaring --in/--out. Custom
 * property substitution is lazy, so --in and --out resolve against whatever
 * the element's own window values are, and a role rule cannot lose a
 * specificity race with the base rule. ================================== */
body.world [data-flow] {
  --fp: 0.5;
  --fs: 0;            /* per-element stagger, in progress units (0 - 0.10) */
  --in-start: 0.06;
  --in-len: 0.18;
  --out-start: 0.74;
  --out-len: 0.24;
  --in:  clamp(0, calc((var(--fp) - var(--in-start) - var(--fs)) / var(--in-len)), 1);
  --out: clamp(0, calc((var(--fp) - var(--out-start)) / var(--out-len)), 1);
}

/* PRIMARY HEADLINE. Typography enters and leaves on its own account, with
   no scale and no depth -- letterforms distort under either and the eye
   reads it as the page zooming rather than as the line arriving. */
body.world [data-flow="lead"] {
  /* The 0.55 FLOOR on the entering half. A headline is content, not an
     effect: it must be legible from the moment it is on screen, and an
     entrance is a flourish on top of that. Measured on a 430px phone
     before this floor existed, "Verified & Recommended" sat at opacity
     0.887 while 70% of the way down the viewport -- already being read,
     still fading in. The floor applies only to the enter term, so the exit
     still takes it all the way down to 0.06 and old content really does
     leave. */
  opacity: calc((0.55 + var(--in) * 0.45) * (1 - var(--out) * 0.94));
  transform: translate3d(0, calc((1 - var(--in)) * 16px + var(--out) * -20px), 0);
}

/* PRIMARY VISUAL. The image changes crop and weight rather than travelling:
   a small scale either side of 1 plus a fade, which reads as the camera
   settling on it and then losing interest, not as a panel sliding past. */
body.world [data-flow="visual"] {
  opacity: calc((0.18 + var(--in) * 0.82) * (1 - var(--out) * 0.8));
  transform: translate3d(0, calc(var(--out) * -12px), 0)
             scale(calc(1.035 - var(--in) * 0.035 - var(--out) * 0.055));
}

/* SUPPORTING CONTENT. Leaves EARLIER than the headline it belongs to, so a
   composition empties in a considered order instead of all at once. */
body.world [data-flow="support"] {
  --out-start: 0.68;
  --out-len: 0.22;
  opacity: calc(var(--in) * (1 - var(--out)));
  transform: translate3d(0, calc((1 - var(--in)) * 12px + var(--out) * -14px), 0);
}

/* QUIET. Eyebrows, labels, fine print. Opacity carries almost all of it --
   these are the smallest type on the page and any real movement on them
   registers as flicker. */
body.world [data-flow="quiet"] {
  --in-len: 0.18;
  opacity: calc(var(--in) * (1 - var(--out)));
  transform: translate3d(0, calc((1 - var(--in)) * 8px), 0);
}

/* =========================================================================
 * 3b. DEPTH -- three planes, assigned by meaning
 * =========================================================================
 * FOREGROUND  the one thing to read or do now      -- full contrast, crisp
 * MIDGROUND   supporting content                   -- smaller, quieter
 * BACKGROUND  the world                            -- always soft
 * An element's plane is a property of WHAT IT IS, so depth encodes
 * hierarchy rather than decorating it.
 *
 * The Z distances are a third of what they were. At -140/-420px the
 * midground and background were far enough back to be read as separate
 * layers sitting behind the page -- literally "content stacked behind
 * content". Kept shallow, the same cue now reads as one composition with
 * soft and crisp parts, which is what depth is for here. ================ */
body.world .w-stage { perspective: 2600px; perspective-origin: 50% 46%; }
body.world .w-fore { transform: translateZ(var(--w-z-fore)); }
body.world .w-mid  { transform: translateZ(var(--w-z-mid)); opacity: 0.86; }
body.world .w-back { transform: translateZ(var(--w-z-back)); opacity: 0.62; filter: blur(1.1px); }

/* =========================================================================
 * 4. TYPOGRAPHY
 * ========================================================================= */
body.world .w-display {
  font-family: 'Plus Jakarta Sans', system-ui, sans-serif;
  font-weight: 700;
  font-size: clamp(2.6rem, 6.6vw, 5.6rem);
  line-height: 1.01;
  letter-spacing: -0.032em;
  text-wrap: balance;
  margin: 0;
}
body.world .w-h2 {
  font-family: 'Plus Jakarta Sans', system-ui, sans-serif;
  font-weight: 700;
  font-size: clamp(1.85rem, 3.6vw, 3.1rem);
  line-height: 1.08;
  letter-spacing: -0.024em;
  text-wrap: balance;
  margin: 0;
}
body.world .w-h3 {
  font-family: 'Plus Jakarta Sans', system-ui, sans-serif;
  font-weight: 700;
  font-size: clamp(1.05rem, 1.6vw, 1.4rem);
  line-height: 1.22;
  letter-spacing: -0.01em;
  margin: 0;
}
body.world .w-body {
  font-family: 'Inter', system-ui, sans-serif;
  font-size: clamp(0.975rem, 1.1vw, 1.1rem);
  line-height: 1.64;
  max-width: 58ch;
  margin: 0;
}
body.world .w-label {
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  margin: 0;
}
/* Sorani and Arabic are not English with other words in it: joined script
   sits lower, needs more leading, and is actively damaged by the tight
   negative tracking that makes the Latin display face architectural.
   js/i18n.js sets `dir` on <html>, never on <body> (see the note near
   .w-plane below) -- these rules were written as `body.world[dir="rtl"]`,
   which can never match, so they silently never applied: Kurdish/Arabic
   rendered at the Latin-tuned size/tracking/leading instead, which is
   what let the headline balloon past its intended box. Rescoped to
   `html[dir="rtl"] body.world`, the one selector shape that actually
   matches. */
html[dir="rtl"] body.world .w-display { letter-spacing: 0; line-height: 1.22; font-size: clamp(2.1rem, 5.4vw, 4.5rem); }
html[dir="rtl"] body.world .w-h2 { letter-spacing: 0; line-height: 1.34; }
html[dir="rtl"] body.world .w-h3 { letter-spacing: 0; line-height: 1.42; }
html[dir="rtl"] body.world .w-body { line-height: 1.9; }
/* Property Rails section headings -- a calmer marketplace scale than the
   shared .w-h2 (which is tuned for hero-adjacent sections like City
   Discovery/Services and stays untouched here). Scoped to its own class so
   only Premium/Affordable/Rent pick it up. Desktop ~30-36px, mobile
   ~24-28px, weight 600 -- a listing rail heading, not a hero headline. */
body.world .w-rail-title {
  font-family: 'Plus Jakarta Sans', system-ui, sans-serif;
  font-weight: 600;
  font-size: clamp(1.75rem, 2.2vw, 2.25rem);
  line-height: 1.15;
  letter-spacing: -0.012em;
  text-wrap: balance;
  margin: 0;
}
@media (max-width: 767px) {
  body.world .w-rail-title { font-size: clamp(1.5rem, 6vw, 1.75rem); }
}
html[dir="rtl"] body.world .w-rail-title { letter-spacing: 0; line-height: 1.3; }
html[dir="rtl"] body.world .w-label { letter-spacing: 0.12em; }

/* =========================================================================
 * 5. CONTROLS
 * =========================================================================
 * The button system from the previous pass tested well and is kept -- the
 * objection this round was composition, not controls. What changes is
 * PLACEMENT (one action per movement) and that every variant now reads
 * against a world that changes tone underneath it. ===================== */
body.world .w-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.6em;
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
  font-size: 0.9375rem; font-weight: 700; line-height: 1;
  padding: 0.95rem 1.6rem; min-height: 48px;
  border-radius: var(--w-r-m); border: 1px solid transparent;
  cursor: pointer; text-decoration: none;
  transition: background-color var(--w-fast) var(--w-ease), border-color var(--w-fast) var(--w-ease),
              color var(--w-fast) var(--w-ease), transform var(--w-fast) var(--w-ease);
}
body.world .w-btn-arrow { flex: none; transition: transform var(--w-mid) var(--w-ease-out); }
body.world .w-btn:hover .w-btn-arrow { transform: translateX(3px); }
html[dir="rtl"] body.world .w-btn-arrow { transform: scaleX(-1); }
html[dir="rtl"] body.world .w-btn:hover .w-btn-arrow { transform: scaleX(-1) translateX(3px); }

/* Primary inverts across the tonal journey so it is always the highest
   contrast object in the frame, on night and on stone alike. */
body.world .w-btn--primary {
  background: rgba(255,255,255,.76);
  color: #2F2A26;
  border-color: rgba(198,164,106,.55);
  box-shadow: 0 8px 18px rgba(67,54,42,.10);
}
body.world .w-btn--primary:hover { transform: translateY(-1px); filter: none; border-color: rgba(185,154,99,.58); }
body.world .w-btn--primary:active { transform: translateY(0) scale(0.985); }
body.world .w-btn--ghost {
  background: rgba(255,255,255,.42);
  color: #2F2A26;
  border-color: rgba(255,255,255,.72);
}
body.world .w-btn--ghost:hover { border-color: rgba(185,154,99,.55); background: rgba(255,255,255,.66); }

body.world .w-action {
  display: inline-flex; align-items: center; gap: 0.5em; position: relative;
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
  font-size: 0.8125rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--w-gold-deep);
  text-decoration: none; padding: 0.6rem 0; min-height: 44px;
}
body.world .w-action::after {
  content: ''; position: absolute; inset-inline-start: 0; bottom: 0.4rem;
  width: 100%; height: 1px; background: currentColor;
  transform: scaleX(0); transform-origin: inline-start;
  transition: transform var(--w-mid) var(--w-ease-out);
}
body.world .w-action:hover::after { transform: scaleX(1); }
body.world .w-action svg { flex: none; transition: transform var(--w-mid) var(--w-ease-out); }
body.world .w-action:hover svg { transform: translateX(3px); }
html[dir="rtl"] body.world .w-action svg { transform: scaleX(-1); }

body.world .w-icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; flex: none; border-radius: 50%;
  border: 1px solid var(--w-glass-border);
  background: var(--w-glass);
  color: #2F2A26;
  cursor: pointer;
  transition: background-color var(--w-fast) var(--w-ease), border-color var(--w-fast) var(--w-ease), transform var(--w-fast) var(--w-ease);
}
body.world .w-icon-btn:hover { border-color: rgba(185,154,99,.5); background: rgba(255,255,255,.14); }
body.world .w-icon-btn:active { transform: scale(0.98); }
body.world .w-icon-btn svg { width: 18px; height: 18px; }
html[dir="rtl"] body.world .w-icon-btn svg { transform: scaleX(-1); }

/* Shared homepage listing-rail nav — same glass language as Browse Projects
   by City (.w-edge-glass), but for inline rail headers (no absolute float).
   Full 48×48 hit target; icon is decorative (pointer-events: none). */
body.world .w-rail-nav-btn {
  box-sizing: border-box;
  width: 48px;
  height: 48px;
  min-width: 48px;
  min-height: 48px;
  margin: 0;
  padding: 0;
  flex: none;
  border-radius: 50%;
  border: 1px solid color-mix(in oklab, rgba(185, 154, 99, 0.42) 60%, rgba(210, 200, 180, 0.35));
  background:
    linear-gradient(160deg,
      rgba(28, 32, 38, 0.42) 0%,
      rgba(18, 22, 28, 0.55) 48%,
      rgba(12, 14, 18, 0.62) 100%);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.22) inset,
    0 -1px 0 rgba(0, 0, 0, 0.18) inset,
    0 8px 22px -14px rgba(8, 10, 14, 0.45);
  backdrop-filter: blur(12px) saturate(1.05);
  -webkit-backdrop-filter: blur(12px) saturate(1.05);
  color: rgba(244, 241, 234, 0.92);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transition: background 140ms ease, border-color 140ms ease, box-shadow 140ms ease, transform 100ms ease;
  pointer-events: auto;
}
body.world .w-rail-nav-btn svg,
body.world .w-rail-nav-btn .w-edge-glass-ico {
  width: 18px;
  height: 18px;
  display: block;
  pointer-events: none;
  flex-shrink: 0;
}
body.world .w-rail-nav-btn:hover:not(:disabled) {
  background:
    linear-gradient(160deg,
      rgba(40, 46, 54, 0.52) 0%,
      rgba(24, 28, 34, 0.62) 100%);
  border-color: color-mix(in oklab, rgba(185, 154, 99, 0.55) 65%, rgba(230, 220, 200, 0.4));
  color: #F4F1EA;
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.28) inset,
    0 10px 24px -14px rgba(8, 10, 14, 0.5);
}
body.world .w-rail-nav-btn:active:not(:disabled) {
  transform: scale(0.96);
  background:
    linear-gradient(160deg,
      rgba(22, 26, 32, 0.58) 0%,
      rgba(14, 16, 20, 0.68) 100%);
}
body.world .w-rail-nav-btn:focus-visible {
  outline: 2px solid color-mix(in oklab, var(--w-gold) 75%, rgba(185, 154, 99, 0.5));
  outline-offset: 2px;
}
body.world .w-rail-nav-btn:disabled {
  opacity: 0.35;
  cursor: not-allowed;
  pointer-events: none;
}
html[dir="rtl"] body.world .w-rail-nav-btn svg { transform: scaleX(-1); }
html[data-dg-theme="light"] body.world .w-rail-nav-btn {
  background:
    linear-gradient(160deg,
      rgba(255, 252, 247, 0.88) 0%,
      rgba(244, 241, 234, 0.92) 100%);
  border-color: color-mix(in oklab, rgba(185, 154, 99, 0.45) 55%, rgba(47, 42, 38, 0.14));
  color: #2F2A26;
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.85) inset,
    0 8px 18px -12px rgba(47, 42, 38, 0.28);
}
html[data-dg-theme="light"] body.world .w-rail-nav-btn:hover:not(:disabled) {
  background:
    linear-gradient(160deg,
      rgba(255, 255, 255, 0.95) 0%,
      rgba(247, 243, 235, 0.98) 100%);
  border-color: rgba(185, 154, 99, 0.55);
  color: #1C1814;
}

/* Unified listing card (Quick Sale / Premium / Affordable) — Homle-inspired
   vertical photo card on Darwesh dark luxury tokens. */
body.world .home-property-card.is-rail {
  border-radius: 18px;
  border: 1px solid color-mix(in oklab, rgba(185, 154, 99, 0.22) 50%, rgba(210, 200, 180, 0.16));
  background: color-mix(in oklab, rgba(22, 26, 32, 0.92) 70%, rgba(12, 14, 18, 0.98));
  box-shadow: 0 14px 36px -18px rgba(0, 0, 0, 0.55);
  transition: transform 220ms var(--w-ease-out, ease), box-shadow 220ms ease, border-color 220ms ease;
}
body.world .home-property-card.is-rail:hover,
body.world .home-property-card.is-rail:focus-within {
  transform: translateY(-4px);
  border-color: color-mix(in oklab, var(--w-gold) 55%, rgba(185, 154, 99, 0.35));
  box-shadow: 0 22px 44px -18px rgba(0, 0, 0, 0.62);
}
body.world .home-property-card.is-rail .home-property-media {
  aspect-ratio: 4 / 3;
  border-radius: 18px 18px 0 0;
}
body.world .home-property-card.is-rail .w-rail-fav {
  width: 44px;
  height: 44px;
  min-width: 44px;
  min-height: 44px;
  top: 10px;
  inset-inline-end: 10px;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: rgba(8, 10, 14, 0.48);
  border: 1px solid rgba(244, 241, 234, 0.18);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  cursor: pointer;
  pointer-events: auto;
  transition: background 140ms ease, border-color 140ms ease, transform 100ms ease;
}
body.world .home-property-card.is-rail .w-rail-fav:hover {
  background: rgba(8, 10, 14, 0.68);
  border-color: rgba(185, 154, 99, 0.45);
}
body.world .home-property-card.is-rail .w-rail-fav:active { transform: scale(0.96); }
body.world .home-property-card.is-rail .w-rail-fav:focus-visible {
  outline: 2px solid var(--w-gold);
  outline-offset: 2px;
}
body.world .home-property-card.is-rail .w-rail-fav .material-symbols-outlined {
  pointer-events: none;
  font-size: 20px;
}
body.world .home-property-card.is-rail .home-property-badge {
  border-radius: 999px;
  padding: 5px 10px;
  font-weight: 650;
  letter-spacing: 0.04em;
}
html[data-dg-theme="light"] body.world .home-property-card.is-rail {
  background: rgba(255, 252, 247, 0.94);
  border-color: rgba(47, 42, 38, 0.1);
  box-shadow: 0 14px 32px -18px rgba(47, 42, 38, 0.22);
}

body.world .w-btn:focus-visible,
body.world .w-action:focus-visible,
body.world .w-icon-btn:focus-visible,
body.world .w-intent-card:focus-visible,
body.world .w-plane:focus-visible,
body.world .w-svc-plane:focus-visible {
  outline: 2px solid var(--w-gold); outline-offset: 3px;
}

/* =========================================================================
 * 6. HANDOFFS -- answer, aperture, recede
 * =========================================================================
 * Moves that physically span two movements. The old carry photograph that
 * used to sit behind Property Intent is gone; this section now uses the
 * page background. */

/* ANSWER -- a hairline plus a line of type that leaves one movement and is
   picked up by the next. The rule itself spans the boundary. */
body.world .w-answer {
  position: absolute;
  inset-inline-start: clamp(1.25rem, 4vw, 4.5rem);
  bottom: calc(var(--w-air-m) * -1);
  height: calc(var(--w-air-m) * 2);
  width: 1px;
  background: linear-gradient(180deg,
    color-mix(in oklab, var(--w-hair-warm) calc((1 - var(--on-stone)) * 100%), rgba(11,14,18,0.22)),
    transparent);
  z-index: -1;
  pointer-events: none;
}

/* APERTURE -- REMOVED, and the class kept only as a plain clipping box.
   It went through two versions and both were the same mistake twice. The
   first was a pair of opaque shutters that slid apart. The second replaced
   them with a scroll-driven radial mask, on the theory that a mask has no
   edges of its own so it could not read as a shutter. It still did: an
   opening that widens as you scroll is an iris, an iris is a door, and the
   content behind it is revealed rather than composed. "No visible edges" is
   not the same property as "does not behave like a shutter".
   What is left is a clip, so the gallery's own overflow stays contained on
   narrow viewports. Nothing about it is animated and no JS writes to it. */
/* min-width:0 undoes the grid item default (min-width:auto), which would
   otherwise size .w-city-layout's track -- and the whole page -- to fit
   .w-aperture's descendants' un-wrapped intrinsic content width (the classic
   CSS Grid/flex "blowout"). Harmless on the desktop cascade (every .w-plane
   there is position:absolute and contributes no intrinsic width at all);
   load-bearing on the mobile carousel, where .w-plane is a real in-flow flex
   item and this is what lets overflow-x:auto actually clip/scroll instead of
   the grid track stretching to fit all eight cards side by side. */
body.world .w-aperture { overflow: hidden; min-width: 0; }

/* =========================================================================
 * 7. ARRIVAL
 * ========================================================================= */
/* =========================================================================
 * VISUAL REBUILD (design-system Phase 2): centered full-bleed composition,
 * replacing the split dark-zone/image-plane layout above. Rebuilt to match
 * the approved Home reference -- a single continuous cinematic photograph
 * with a dark scrim for legibility, centered copy, no LTR/RTL mirroring
 * needed since a centered composition is symmetric by construction. The
 * photograph itself (URL, subject, licensing) is untouched -- only the
 * crop/position/overlay treatment around it changed. Real content below
 * the fold (Social Universe, Property Intent rail, Service Universe) is
 * out of scope for this pass and unchanged.
 * ========================================================================= */
/* .mv's own padding-block (var(--w-air-l), ~96-144px) is the spacing
   between ordinary movements -- correct for every section EXCEPT this
   first one, where it was leaving a dead gap of solid body background
   between the floating transparent navbar and the hero photograph (the
   navbar is `position:fixed` and genuinely transparent -- js/site-header.js
   -- so nothing was wrong there; the gap was this section starting 144px
   too low). Zeroing only the top half here lets .w-hero-plane's
   background-image reach true document y=0 and sit directly behind the
   glass rail, while padding-block-end (the gap before Quickstart) is
   untouched. */
body.world .mv[data-cine3d="hero"] { padding-block-start: 0; }
/* .mv-in (the shared content gutter every movement uses) was stacking its
   own padding-inline on TOP of .w-hero's own -- 40px effective margin on
   mobile instead of the intended 20px, squeezing the search input so
   narrow its placeholder text got clipped. .w-hero already establishes
   the hero's own gutter (its decorative elements are positioned relative
   to it), so .mv-in's copy of that padding is pure double-counting here. */
body.world .mv[data-cine3d="hero"] { padding-block: 6.25rem 0.25rem; }
body.world .mv[data-cine3d="hero"] .mv-in { padding-inline: 0; }
body.world .w-hero {
  position: relative;
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: flex-start;
  gap: 1.25rem;
  margin-inline: clamp(1rem, 3vw, 2.5rem);
  padding: clamp(1.35rem, 2.4vw, 2rem) clamp(1.15rem, 2.2vw, 1.75rem) clamp(0.75rem, 1.4vw, 1rem);
  overflow: hidden;
  border-radius: 32px;
  background: #FBF7F0;
  border: 1px solid #E3D8C8;
}
/* Non-photo hero. The plane is an architectural drawing: a faint massing
   silhouette, a few floor-plan lines, and one champagne accent. No
   photograph, no dense grid, no hologram. */
body.world .w-hero-plane {
  position: absolute;
  inset: 0;
  z-index: -2;
  background: #F6F1E8;
  background-image: none;
  -webkit-mask-image: none;
          mask-image: none;
}
/* Back layer: a few floor-plan lines, not a grid. */
body.world .w-hero-plane::after { content: none; background: none; }
/* The old stepped mass sat on the silk like a flat gray relief. Sun mode
   keeps the folds themselves and does not paint that shape. */
body.world .w-hero-plane::before { content: none; display: none; }
body.world .w-hero::before,
body.world .w-hero::after { content: none; display: none; }
/* Centered composition: one direction-agnostic anchor (align-items/
   justify-content: center) so a language switch (LTR <-> RTL) never
   shifts this block toward either edge -- flex-start/flex-end would
   flip automatically under dir="rtl" and move the whole hero sideways,
   which is exactly what this centered redesign must not do. */
body.world .w-hero-top {
  position: relative;
  display: block;
}
body.world .w-hero-copy {
  position: relative;
  z-index: 1;
  max-width: none;
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
  align-items: center;
  text-align: center;
  margin-inline: auto;
  padding: 0;
  border-radius: 0;
  background: none;
  border: 0;
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  --hero-ivory: #2F2A26;
  --hero-champagne: var(--w-gold);
}
body.world .w-hero-aside {
  position: absolute;
  inset-inline-end: 0;
  bottom: 0;
  z-index: 1;
  margin: 0;
  max-width: 13.5rem;
  text-align: end;
  color: #6E6258;
  font-size: 0.92rem;
  line-height: 1.45;
}
@media (max-width: 767px) {
  body.world .w-hero::before,
  body.world .w-hero::after { content: none; }
}
/* At the old 46rem measure "Building the Future." wrapped to a third
   line, turning a two-line brand statement into three and crowding the
   frame. The description/value-statement keep their own narrower reading
   widths (58ch / 38rem) below, so widening this outer box only gives the
   headline room -- it doesn't widen the body copy. */
/* Locked-reference headline: bold two-line sans, not the earlier serif
   pass -- the reference image is explicit and supersedes the prior
   editorial-serif decision for this one element. Scoped tightly to the
   hero headline only (other .w-h2/.w-h3 section headings elsewhere on
   this page are unaffected). Each line is a real, separately-colored
   child <span> already in the markup (data-i18n="index.heroLine1"/
   "index.heroLine2") holding plain semantic sentences -- no markup or
   presentation logic inside the translation strings. Wrapping is decided
   entirely by CSS below: one line per span on desktop where the content
   fits (nowrap), a balanced natural wrap on mobile. */
/* Hero headline only. English and Turkish use Manrope. Kurdish and
   Arabic override this below with Vazirmatn. Other .w-display rules on
   the page are unchanged; this block wins on the hero by specificity. */
body.world .w-hero-copy .w-display {
  font-family: 'Manrope', sans-serif;
  font-weight: 600;
  font-synthesis: none;
  line-height: 1.02;
  letter-spacing: -0.03em;
  max-width: none;
  width: 100%;
  text-align: center;
}
body.world .w-hero-copy .w-display span {
  display: block;
  white-space: nowrap;
}
body.world .w-hero-copy .w-display [data-i18n="index.heroLine1"] {
  color: var(--hero-ivory);
  font-size: clamp(56px, 5vw, 84px);
  letter-spacing: -0.03em;
}
body.world .w-hero-copy .w-display [data-i18n="index.heroLine2"] {
  color: var(--w-gold);
  background: none;
  font-size: clamp(46px, 4.3vw, 70px);
  letter-spacing: -0.03em;
  margin-top: 0.14em;
}
/* Kurdish and Arabic: a lighter Arabic-script face, a slightly smaller
   scale (the script is taller than Latin), open leading, and no negative
   tracking — negative letter-spacing breaks joined glyphs. dir is set on
   <html> by js/i18n.js. This beats the shared html[dir=rtl] .w-display
   size so the hero does not inherit the section-heading scale. */
html[dir="rtl"] body.world .w-hero-copy .w-display,
html[dir="rtl"] body.world .w-hero-copy .w-display [data-i18n="index.heroLine1"],
html[dir="rtl"] body.world .w-hero-copy .w-display [data-i18n="index.heroLine2"] {
  font-family: 'Vazirmatn', 'Noto Sans Arabic', sans-serif;
  font-weight: 500;
  font-synthesis: none;
  letter-spacing: 0;
  text-transform: none;
}
html[dir="rtl"] body.world .w-hero-copy .w-display [data-i18n="index.heroLine1"] {
  font-size: clamp(44px, 4.2vw, 68px);
  line-height: 1.16;
}
html[dir="rtl"] body.world .w-hero-copy .w-display [data-i18n="index.heroLine2"] {
  font-size: clamp(36px, 3.4vw, 56px);
  line-height: 1.18;
}
/* Description reads quieter than the headline -- lighter weight and a
   muted ivory/gray, never brighter than the headline -- with a measure
   narrower than .w-body's site-wide 58ch. Scoped to the hero only;
   .w-body itself (used by other movements on this page) is unchanged. */
body.world .w-hero-copy .w-body {
  max-width: 34rem;
  margin-inline: auto;
  font-family: 'Manrope', sans-serif;
  font-weight: 400;
  color: #6E6258;
  font-size: clamp(1rem, 0.35vw + 0.9rem, 1.125rem);
  line-height: 1.6;
  text-align: center;
  text-shadow: none;
}
html[dir="rtl"] body.world .w-hero-copy .w-body {
  font-family: 'Vazirmatn', 'Noto Sans Arabic', sans-serif;
  font-weight: 400;
  letter-spacing: 0;
  line-height: 1.75;
}

/* Eyebrow: softened to the same local champagne as the headline's second
   line, at reduced opacity so it supports the headline instead of
   competing with it -- scoped to the Hero only, the site-wide .w-label
   (used by other section eyebrows) is untouched. */
body.world .w-hero-copy .w-label {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--w-gold-deep);
  opacity: 1;
}
body.world .w-hero-copy .w-label::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #2F4439;
  box-shadow: 0 0 0 1px rgba(185,154,99,.7);
  flex: none;
}
body.world .w-hero-stage {
  position: relative;
  min-height: clamp(380px, 46vw, 560px);
  border-radius: 24px;
  overflow: hidden;
  background: #1C2128;
}
body.world .w-hero-photo,
body.world .w-hero-photo img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
body.world .w-hero-photo img {
  object-fit: cover;
  object-position: center center;
  transition: opacity 500ms ease;
}
body.world .w-hero-photo-night { opacity: 0; }
@media (prefers-reduced-motion: reduce) {
  body.world .w-hero-photo img { transition: none; }
}
body.world .w-hero-stage::after {
  content: '';
  position: absolute;
  inset: auto 0 0 0;
  height: 48%;
  background: linear-gradient(to top, rgba(20,16,12,.28), transparent);
  pointer-events: none;
}
body.world .w-hero-dock {
  position: absolute;
  z-index: 2;
  left: 50%;
  bottom: clamp(0.7rem, 1.6vw, 1.1rem);
  transform: translateX(-50%);
  width: min(720px, calc(100% - 1.5rem));
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.45rem;
}
body.world .w-hero-search {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  padding: 0.42rem;
  border-radius: 20px;
  background: rgba(255,255,255,.72);
  border: 1px solid rgba(227,216,200,.9);
  box-shadow: 0 10px 24px rgba(67,54,42,.12);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}
body.world .w-hero-modes {
  position: relative;
  display: flex;
  gap: 0.15rem;
  overflow-x: auto;
  scrollbar-width: none;
}
body.world .w-hero-modes::-webkit-scrollbar,
body.world .w-hero-suggest::-webkit-scrollbar { display: none; }
body.world .w-hero-mode-indicator {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 0;
  box-sizing: border-box;
  border-radius: 999px;
  background: color-mix(in srgb, #fff 82%, var(--w-gold) 18%);
  border: 1px solid color-mix(in srgb, var(--w-gold) 42%, transparent);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.72),
    0 4px 14px rgba(47,42,38,.08);
  backdrop-filter: blur(12px) saturate(115%);
  -webkit-backdrop-filter: blur(12px) saturate(115%);
  pointer-events: none;
}
body.world .w-hero-mode-indicator.is-ready {
  transition: transform 180ms cubic-bezier(.2,.8,.2,1), width 180ms cubic-bezier(.2,.8,.2,1), height 180ms cubic-bezier(.2,.8,.2,1);
}
body.world .w-hero-mode {
  position: relative;
  z-index: 1;
  flex: none;
  border: 0;
  background: transparent;
  color: var(--w-ink-soft);
  min-height: 38px;
  padding: 0 0.95rem;
  border-radius: 999px;
  font: inherit;
  font-size: 0.86rem;
  font-weight: 600;
  cursor: pointer;
  transition: color 180ms cubic-bezier(.2,.8,.2,1), transform 160ms cubic-bezier(.2,.8,.2,1);
}
body.world .w-hero-mode:hover { color: var(--w-ink); }
body.world .w-hero-mode:active { transform: scale(.98); }
body.world .w-hero-mode[aria-pressed="true"],
body.world .w-hero-mode[aria-pressed="true"]:hover {
  background: transparent;
  color: var(--w-ink);
  box-shadow: none;
}
body.world .w-hero-mode:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--w-gold) 55%, transparent);
  outline-offset: 2px;
}
body.world .w-hero-field {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  min-height: 46px;
  padding: 0 0.3rem 0 0.8rem;
  border-radius: 999px;
  background: rgba(255,255,255,.88);
  border: 1px solid #E3D8C8;
  transition: border-color 160ms cubic-bezier(.2,.8,.2,1), box-shadow 160ms cubic-bezier(.2,.8,.2,1);
}
body.world .w-hero-field:focus-within {
  border-color: rgba(198,164,106,.72);
  box-shadow: inset 0 0 0 1px rgba(198,164,106,.28);
}
body.world .w-hero-field input {
  flex: 1;
  min-width: 0;
  border: 0;
  background: transparent;
  color: #2F2A26;
  font: inherit;
  font-size: 0.95rem;
  outline: none;
}
body.world .w-hero-field input::placeholder { color: #6E6258; }
body.world .w-hero-locate,
body.world .w-hero-go {
  flex: none;
  width: 40px;
  height: 40px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  color: #2F2A26;
}
body.world .w-hero-locate { color: var(--w-gold); }
body.world .w-hero-go {
  border: 0;
  background: #2F2A26;
  color: #F6F1E8;
  cursor: pointer;
  transition: transform 160ms cubic-bezier(.2,.8,.2,1);
}
body.world .w-hero-go:hover { transform: translateX(2px); }
body.world .w-hero-go:active { transform: scale(.96); }
body.world .w-hero-suggest {
  display: flex;
  justify-content: safe center;
  flex-wrap: nowrap;
  gap: 0.4rem;
  width: 100%;
  overflow-x: auto;
  scrollbar-width: none;
  padding: 0.05rem 0.1rem 0.15rem;
}
body.world .w-hero-suggest a {
  flex: none;
  color: #6E6258;
  font-size: 0.78rem;
  font-weight: 600;
  min-height: 34px;
  display: inline-flex;
  align-items: center;
  padding: 0 0.75rem;
  border-radius: 999px;
  background: rgba(255,255,255,.42);
  border: 1px solid rgba(227,216,200,.85);
  box-shadow: 0 6px 16px rgba(67,54,42,.06);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  text-decoration: none;
  transition: transform 170ms cubic-bezier(.2,.8,.2,1), border-color 170ms cubic-bezier(.2,.8,.2,1), color 170ms cubic-bezier(.2,.8,.2,1), background-color 170ms cubic-bezier(.2,.8,.2,1);
}
body.world .w-hero-suggest a:hover {
  transform: translateY(-1px);
  border-color: rgba(198,164,106,.62);
  color: #2F2A26;
}
body.world .w-hero-suggest a:active {
  transform: scale(.97);
  background: rgba(198,164,106,.16);
  border-color: rgba(198,164,106,.72);
  color: #2F2A26;
}
html[dir="rtl"] body.world .w-hero-go svg { transform: scaleX(-1); }
html[dir="rtl"] body.world .w-hero-go:hover { transform: translateX(-2px); }
@media (prefers-reduced-motion: reduce) {
  body.world .w-hero-mode,
  body.world .w-hero-mode-indicator,
  body.world .w-hero-mode-indicator.is-ready,
  body.world .w-hero-field,
  body.world .w-hero-go,
  body.world .w-hero-suggest a { transition: none; }
  body.world .w-hero-mode:active,
  body.world .w-hero-go:hover,
  body.world .w-hero-go:active,
  body.world .w-hero-suggest a:hover,
  body.world .w-hero-suggest a:active { transform: none; }
}

/* ---- Brand-forward hero content: CTA row, values row, supporting
   statement. These sit inside .w-hero-copy, below the headline/description,
   and are deliberately quiet -- the headline is still the loudest thing in
   the frame; this content earns its place through restraint, not size. ---- */
body.world .w-hero-cta-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.85rem;
}
/* Narrower and slightly shorter than the site-wide .w-btn default (48px)
   so the CTAs read as supporting actions under the headline, not the
   loudest objects in the frame. */
body.world .w-hero-cta-row .w-btn { min-height: 45px; padding-inline: 1.35rem; font-size: 0.875rem; }
/* True-glass primary CTA -- near-zero fill, real blur, champagne carried
   only in the thin border/glow accent, never as an opaque colored fill --
   so the button reads as "this glass surface's action," not a separate
   solid gold disc dropped on top of it. */
body.world .w-hero-copy .w-btn--primary {
  background-color: rgba(255,255,255,.76);
  background-image: none;
  color: #2F2A26;
  border: 1px solid rgba(198,164,106,.55);
  box-shadow: 0 8px 18px rgba(67,54,42,.10);
  backdrop-filter: blur(10px) saturate(1.08);
  -webkit-backdrop-filter: blur(10px) saturate(1.08);
}
body.world .w-hero-copy .w-btn--primary:hover {
  filter: none;
  border-color: rgba(255,255,255,.55);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.4), 0 0 0 1px rgba(185,154,99,.28);
}
body.world .w-hero-copy .w-btn--ghost {
  background: rgba(255,255,255,.58);
  border-color: #E3D8C8;
  color: #2F2A26;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
body.world .w-hero-copy .w-btn--ghost:hover { border-color: rgba(185,154,99,.55); background: rgba(255,255,255,.66); }
/* Quickstart's own Search button gets the same smoked-glass treatment as
   the hero's CTAs (not the site-wide solid .w-btn--primary) so the two
   sections read as one continuous premium system. */
body.world .w-quickstart .w-btn--primary {
  background: linear-gradient(180deg, rgba(255,255,255,.66), rgba(227,225,220,.4));
  color: #2F2A26;
  border: 1px solid rgba(185,154,99,.42);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.22);
}
body.world .w-quickstart .w-btn--primary:hover { filter: none; border-color: rgba(185,154,99,.58); }
/* Values kicker — decorative flanking hairlines removed (stats refinement). */
body.world .w-hero-values {
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--w-gold);
  opacity: 1;
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.85rem;
}
body.world .w-hero-values::before,
body.world .w-hero-values::after {
  content: none !important;
  display: none !important;
  width: 0;
  height: 0;
  background: none;
}
/* Legacy trust-statement classes — markup removed from the compact
   stats strip; keep rules inert if any residual node appears. */
body.world .w-hero-value-statement,
body.world .w-hero-value-statement-short { display: none !important; }
html[dir="rtl"] body.world .w-hero-values { letter-spacing: 0.1em; }

/* ---- Quickstart: compact honest stats under the hero.
   No panel chrome, decorative hairlines, or trust paragraph. */
body.world .w-quickstart {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0;
  /* Owner: nudge six-metric strip ~35px lower vs hero/search (desktop). */
  margin-top: calc(0.15rem + 35px);
  padding: clamp(0.65rem, 1.4vw, 1rem) 0 clamp(0.55rem, 1.2vw, 0.85rem);
  border: none;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
body.world .w-quickstart::before { content: none; display: none; }

/* Stats -> Social -> Intent rhythm. AUDIT (measured live via
   getBoundingClientRect(), not section boxes):
   Gap A (Stats -> Social) was 126px desktop / 94px mobile, made of two
   pieces: (1) the Social <section>'s own Tailwind `mt-10 md:mt-16` utility
   (40px/64px, a real adjacent-section margin -- Social is a plain
   <section>, not a `.mv` sibling, so it never adopted the shared overlap
   formula) and (2) ~54px/62px of orbit self-centering INSIDE .so-stage
   (stage height minus tile height, halved -- carousel geometry, never
   touched here, only measured to separate it from (1)). Only (1) is
   adjustable within this task's scope.
   Gap B (Social -> Intent) was actually NEGATIVE on desktop (-35px, real
   overlap) and undersized on mobile (24px against a 44-60px target).
   Root cause: .w-intent-section never got its own adjacent-pair override
   for this boundary (unlike its own City Discovery boundary, fixed
   earlier) -- it still uses the generic, unscoped `.mv` formula
   (margin-block-start: calc(var(--w-air-m) * -1.4) desktop /
   calc(var(--w-air-s) * -1) mobile, in the shared rule + the max-width:
   767px block later in this file). That generic pull-up assumes every
   sibling donates the same padding-based overlap room every other `.mv`
   pair does -- Social isn't a `.mv` section and doesn't, so the formula
   overshoots straight into Intent's own visible eyebrow text.
   Fix: two scoped adjacent-sibling overrides, layered on the EXISTING
   formulas via calc() (never replacing them with new ones), targeting
   only this one Stats->Social->Intent chain -- no other section's
   spacing changes. */
body.world .w-quickstart + section {
  margin-top: 1.375rem; /* 22px -- was the plain 4rem (64px) Tailwind utility */
}
body.world .w-quickstart + section + .w-intent-section {
  margin-block-start: calc(var(--w-air-m) * -1.4 + clamp(6.5rem, 7.7vw, 7.5rem) - clamp(2.05rem, 2.2vw, 2.35rem));
}
@media (max-width: 767px) {
  body.world .w-quickstart + section {
    margin-top: 0.375rem; /* 6px -- was the plain 2.5rem (40px) Tailwind utility */
  }
  body.world .w-quickstart + section + .w-intent-section {
    margin-block-start: calc(var(--w-air-s) * -1 + clamp(1.5rem, 7vw, 2rem) - clamp(0.95rem, 2.5vw, 1.2rem));
  }
}

/* ---- Property-type chips: quick, functional entry points into the real
   map.html filter (?types=house etc., the same URL param map.html's own
   readUrlStateIntoFilters() already reads for its Home Type drawer) --
   not decorative, every chip is a real working link. ---- */
body.world .w-chips { display: flex; flex-wrap: wrap; gap: 0.5rem; justify-content: center; margin-top: 0; }
/* Refinement pass: lighter, smaller compact filters -- near-transparent
   glass with a thin champagne hairline, not the earlier heavier tinted
   pill. Selected/hover state stays a subtle champagne emphasis, never a
   solid gold fill. */
body.world .w-chip {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 40px; padding: 0 14px; border-radius: var(--w-r-s);
  background: var(--w-glass);
  border: 1px solid var(--w-glass-border);
  color: #2F2A26; font-family: 'Inter', system-ui, sans-serif; font-size: 0.875rem; font-weight: 500;
  text-decoration: none; backdrop-filter: blur(10px) saturate(1.05);
  transition: border-color var(--w-fast) var(--w-ease), background-color var(--w-fast) var(--w-ease), transform var(--w-fast) var(--w-ease);
}
body.world .w-chip svg { width: 14px; height: 14px; flex: none; }
body.world .w-hero-copy .w-chip {
  border-color: rgba(185,154,99,.28);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.16);
}
body.world .w-hero-copy .w-chip svg { color: var(--w-gold); }
body.world .w-chip:hover { border-color: rgba(185,154,99,.55); background: rgba(255,255,255,.7); transform: translateY(-1px); }
body.world .w-chip:focus-visible { outline: 2px solid var(--w-gold); outline-offset: 2px; }

/* ---- Stat strip: six metrics (loadHeroStats). Numbers dominate;
   labels stay small underneath. Unavailable visitors/deals stay as a dash. ---- */
body.world .w-stats {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  justify-items: center;
  align-items: start;
  column-gap: clamp(0.75rem, 2vw, 1.75rem);
  row-gap: clamp(1rem, 2.2vw, 1.35rem);
  width: 100%;
  max-width: 68rem;
  margin: 0 auto;
}
@media (max-width: 1100px) {
  body.world .w-stats { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
  body.world .w-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); max-width: 22rem; }
}
body.world .w-stat {
  text-align: center;
  min-width: 0;
  max-width: 11rem;
  width: 100%;
}
body.world .w-stat-num {
  display: block;
  font-family: 'Plus Jakarta Sans', 'IBM Plex Sans', system-ui, sans-serif;
  font-weight: 700;
  font-size: clamp(2.85rem, 4.2vw, 4.15rem);
  letter-spacing: -0.035em;
  color: #1F242B;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  min-height: 1em;
}
body.world .w-quickstart .w-stat-num:not(.is-loading) {
  background: none;
  -webkit-background-clip: unset;
  background-clip: unset;
  -webkit-text-fill-color: #1F242B;
  color: #1F242B;
}
body.world .w-stat-label {
  display: block;
  margin-top: 0.4rem;
  font-family: 'IBM Plex Sans', 'Inter', system-ui, sans-serif;
  font-size: 0.68rem;
  font-weight: 550;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #7A828C;
}
body.world .w-stat-num.is-loading {
  color: #9AA1AA;
  -webkit-text-fill-color: #9AA1AA;
}
/* Visitors / Views: no trusted source yet — neutral dash only. */
body.world .w-stat--unavailable .w-stat-num {
  color: #A8AFB8;
  background: none;
  -webkit-text-fill-color: #A8AFB8;
  font-weight: 500;
}
body.world .w-stat-note,
body.world .w-stats-mini { display: none !important; }

/* =========================================================================
 * 8. INTENT -- a stable row of five compact cards
 * =========================================================================
 * Replaces the old "one wall, five panels" design (full-bleed vertical
 * strips that dramatically expanded on hover, collapsing their siblings).
 * That interaction and that height are both explicitly rejected by the
 * approved brief -- this section must read as a calm, premium selector,
 * not a giant gallery. Five equal-width landscape cards, gap between them
 * (not a hairline seam), each with its own radius/shadow/glass edge. The
 * row NEVER changes shape on hover/focus -- only the interacted card lifts
 * a few pixels, its own image zooms slightly, and its own arrow nudges --
 * every sibling stays exactly where it is. */
body.world .w-intent-row {
  display: flex;
  align-items: stretch;
  width: 100%;
  gap: clamp(12px, 1.4vw, 18px);
}
body.world .w-intent-card {
  position: relative;
  flex: 1 1 0%;
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  height: clamp(210px, 13vw, 230px);
  border-radius: var(--w-r-l);
  overflow: hidden;
  text-decoration: none;
  padding: 1.1rem;
  border: 1px solid rgba(185,154,99,.28);
  box-shadow: 0 14px 30px -18px rgba(34,39,45,.18);
  transition: transform 200ms cubic-bezier(.2,.8,.2,1), border-color 200ms cubic-bezier(.2,.8,.2,1), box-shadow 200ms cubic-bezier(.2,.8,.2,1);
}
body.world .w-intent-media {
  position: absolute; inset: 0; z-index: 0;
  background-image: var(--img); background-size: cover; background-position: center;
  transform: scale(1.02);
  filter: saturate(0.82) contrast(1.03);
  transition: transform 220ms cubic-bezier(.2,.8,.2,1), filter 220ms cubic-bezier(.2,.8,.2,1);
}
body.world .w-intent-scrim {
  position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(0deg, rgba(27,30,34,0.58) 0%, rgba(27,30,34,0.18) 42%, rgba(27,30,34,0) 70%);
}
body.world .w-intent-icon {
  position: relative; z-index: 2;
  display: flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; margin-bottom: 0.6rem;
  border-radius: var(--w-r-s);
  border: 1px solid rgba(185,154,99,.35);
  background: rgba(255,255,255,.62);
  backdrop-filter: blur(6px);
  color: #2F2A26;
}
body.world .w-intent-icon svg { width: 17px; height: 17px; }
body.world .w-intent-body {
  position: relative; z-index: 2;
  display: flex; flex-direction: column; gap: 0.2rem;
}
body.world .w-intent-name {
  font-family: 'Plus Jakarta Sans', system-ui, sans-serif;
  font-weight: 600; font-size: clamp(1.0625rem, 1.2vw, 1.25rem);
  letter-spacing: -0.01em; color: #F4F1EA;
}
body.world .w-intent-desc {
  display: flex; align-items: center; gap: 0.35rem;
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
  font-size: clamp(0.8125rem, 0.9vw, 0.875rem); font-weight: 500; color: rgba(191,198,207,.82);
  transition: color 200ms cubic-bezier(.2,.8,.2,1);
}
body.world .w-intent-arrow {
  flex: none;
  transition: transform 200ms cubic-bezier(.2,.8,.2,1);
}
html[dir="rtl"] body.world .w-intent-arrow { transform: scaleX(-1); }
@media (hover: hover) {
  body.world .w-intent-card:hover,
  body.world .w-intent-card:focus-visible {
    transform: translateY(-3px);
    border-color: var(--w-glass-hi);
    box-shadow: 0 16px 32px -18px rgba(0,0,0,.55);
  }
  body.world .w-intent-card:hover .w-intent-media,
  body.world .w-intent-card:focus-visible .w-intent-media {
    transform: scale(1.03); filter: saturate(0.92) contrast(1.02);
  }
  body.world .w-intent-card:hover .w-intent-desc,
  body.world .w-intent-card:focus-visible .w-intent-desc {
    color: rgba(244,239,231,.92);
  }
  body.world .w-intent-card:hover .w-intent-arrow,
  body.world .w-intent-card:focus-visible .w-intent-arrow {
    transform: translateX(3px);
  }
  html[dir="rtl"] body.world .w-intent-card:hover .w-intent-arrow,
  html[dir="rtl"] body.world .w-intent-card:focus-visible .w-intent-arrow {
    transform: scaleX(-1) translateX(3px);
  }
}

/* Section-scoped overrides: this section must stay visibly more compact
   than the shared .mv/.w-h2 defaults (which are tuned for taller Home
   sections) -- an additive class on the element, rather than editing the
   shared rules, keeps every other Home section untouched. */
body.world .mv.w-intent-section { padding-block: clamp(4.5rem, 6vw, 5.5rem); }
body.world .w-intent-heading { font-size: clamp(2.1rem, 3vw, 2.5rem); font-weight: 600; }
body.world .w-intent-nav { display: none; }

/* =========================================================================
 * 9. CITY DISCOVERY -- compact editorial city cards
 * =========================================================================
 * Replaces the wide, eight-deep cascade (fanning out to thin, near-invisible
 * slivers, and a section tall enough to feel like a separate microsite) with
 * a tighter system: one large active card plus exactly one neighbour on
 * each side -- js/city-gallery.js's paint() writes a data-near="0|1" flag
 * per plane (near = |offset| <= 1) and everything past that is fully
 * hidden here, not just dim. Split composition unchanged: copy on one side,
 * cards on the other; arrows/dots/keyboard/click and the real
 * projects.html?city=X routes are the same existing controller, untouched.
 *
 * ON IMAGERY -- still the honest part, unchanged in substance. No file in
 * this repository is a real, licensed photograph of Kirkuk, Erbil, or any
 * of the other six cities -- there is no per-city photography asset to
 * draw from at all (confirmed: images/ holds only brand marks and flag
 * icons). Labelling a stock or placeholder image as a specific city would
 * be a false claim about a place, so a plane's face is still NOT a
 * photograph pretending to be that city -- per the brief's own fallback
 * ("use an honest neutral architectural/city placeholder rather than
 * misrepresenting another city"), it is a brighter, warmer composed
 * sky-and-skyline light-field, deterministic per city via --h/--s/--l, with
 * the city NAME as the dominant readable element. `--img` remains an
 * optional first layer: the day a real, licensed per-city photograph
 * exists, dropping it into that one custom property adopts it with no
 * other redesign. ========================================================= */
body.world .w-city-layout {
  display: grid;
  grid-template-columns: minmax(0, 0.72fr) minmax(0, 1.28fr);
  gap: clamp(1.5rem, 3vw, 3rem);
  align-items: center;
}
body.world .w-city-copy { display: flex; flex-direction: column; gap: 0.6rem; }
body.world .w-city-copy .w-h2 { font-size: clamp(2.375rem, 3vw, 2.75rem); }
body.world .w-city-copy .w-body { font-size: clamp(0.9375rem, 1vw, 1rem); }
@media (max-width: 1023px) {
  body.world .w-city-layout { grid-template-columns: 1fr; }
  body.world .w-city-copy { margin-bottom: 1.25rem; }
  /* One column means the wall has no side column to fan into, so it goes
     back to fanning symmetrically from the centre. */
  body.world .w-gallery { justify-content: center; }
}

/* BUG FIX (not a redesign): flex-start anchored the active card (--o:0,
   translateX 0) to this container's own left edge, leaving zero room for
   the previous neighbour (negative --o, translateX negative) to peek --
   it always cascaded straight off the container's left boundary, fully
   hidden, at every index (not just index 0 -- confirmed live). Centering
   gives both the previous and next neighbour's translateX equal room
   inside this SAME container -- card width/height, step distance, scale,
   opacity, section spacing and the copy column are all untouched, so
   "previous + active + next" now shows the way the design already
   intended once neither side is starved of room. */
body.world .w-gallery {
  position: relative;
  min-height: clamp(430px, 30vw, 470px);
  display: flex; align-items: center; justify-content: center;
  touch-action: pan-y;
}
body.world .w-wall {
  position: relative;
  width: 100%; height: 100%;
  display: flex; align-items: center; justify-content: center;
}
body.world .w-plane {
  position: absolute;
  width: clamp(340px, 22vw, 380px);
  height: clamp(420px, 30vw, 460px);
  border-radius: var(--w-r-l);
  overflow: hidden;
  text-decoration: none;
  box-shadow: 0 14px 30px -18px rgba(11, 14, 18, 0.3);
  /* --o is the plane's signed offset from the focused city, written by the
     gallery controller. Position is a pure function of it: a horizontal
     cascade, not a rotated wall. z-index falls with distance so the focused
     card always reads as the one in front. Anything past one step away is
     cut to opacity 0 by the data-near rule below -- editorial and compact,
     not a wall of cards disappearing into the dark.
     --dir flips the cascade's physical direction for RTL (below): raw
     translateX is never direction-aware on its own, and the gallery sits on
     the LEFT of its copy column in RTL (the grid's columns mirror with the
     page), so without this the cascade would shift cards rightward -- into
     the copy text -- instead of mirroring away from it as it does in LTR. */
  --dir: 1;
  --step: clamp(250px, 17vw, 290px);
  transform:
    translateX(calc(var(--o) * var(--step) * var(--dir)))
    translateY(calc(min(abs(var(--o)), 1) * 12px))
    scale(calc(1 - min(abs(var(--o)), 1) * 0.1));
  z-index: calc(30 - abs(var(--o)));
  opacity: calc(1 - min(abs(var(--o)), 1) * 0.42);
  /* Motion-only: transform + opacity (compositor-friendly). No box-shadow
     tween — shadow snaps with focus tier to avoid paint-heavy frames. */
  transition:
    transform 280ms cubic-bezier(0.22, 1, 0.36, 1),
    opacity 280ms cubic-bezier(0.22, 1, 0.36, 1);
}
/* The hard cutoff: js/city-gallery.js's paint() sets data-near="0" once a
   plane is more than one step from focus. Past that point it must not just
   dim -- three cards read as "editorial and compact"; six or seven fading
   sliver still reads as the rejected wall. */
body.world .w-plane[data-near="0"] { opacity: 0; pointer-events: none; }
/* html[dir="rtl"], not body[dir="rtl"]: js/i18n.js only ever sets the dir
   attribute on document.documentElement, never on body (confirmed live --
   document.body.getAttribute('dir') is null even while its computed
   direction is rtl), so a body[dir="rtl"] selector here would silently
   never match. */
html[dir="rtl"] body.world .w-plane { --dir: -1; }
/* The face: a real, verified photograph of the city's own named landmark
   (--img, set per city in js/city-gallery.js), covering and centered like
   an <img object-fit:cover> would. The radial/linear gradient layers behind
   it are the pre-photo abstract fallback -- kept only so a plane with no
   `img` (should one ever be removed) still renders something coherent
   instead of a transparent hole; they're fully hidden under any real,
   opaque photo. */
body.world .w-plane-face {
  position: absolute; inset: 0; z-index: 0;
  background:
    var(--img, none),
    radial-gradient(48% 32% at 74% 16%, hsla(44, 78%, 91%, 0.6), transparent 72%),
    linear-gradient(180deg,
      hsl(var(--h) calc(var(--s) * 1%) calc(var(--l) * 1% + 50%)) 0%,
      hsl(calc(var(--h) - 6) calc(var(--s) * 1%) calc(var(--l) * 1% + 34%)) 48%,
      hsl(calc(var(--h) - 12) calc(var(--s) * 1%) calc(var(--l) * 1% + 16%)) 100%);
  background-size: cover;
  background-position: center;
}
/* Deep-graphite material, not a dark wash: a shorter, lighter bottom-only
   gradient so the photograph stays visible across the top two-thirds of the
   card -- "do NOT make cards overly dark; the city image must remain
   visible", per the brief -- while the name/CTA text over the bottom still
   has enough contrast to read. */
body.world .w-plane-scrim {
  position: absolute; inset: 0; z-index: 0;
  background: linear-gradient(0deg, rgba(8, 10, 14, 0.74) 0%, rgba(8, 10, 14, 0.3) 36%, transparent 64%);
}
body.world .w-plane-body {
  position: absolute; inset-inline: 0; bottom: 0; z-index: 1;
  padding: 1.2rem 1.3rem 1.35rem;
  display: flex; flex-direction: column; gap: 0.35rem;
}
body.world .w-plane-name {
  font-family: 'Plus Jakarta Sans', system-ui, sans-serif;
  font-weight: 600; font-size: 1.25rem; letter-spacing: -0.015em; color: #F4F1EA;
  text-shadow: 0 1px 12px rgba(4,4,7,0.9);
}
body.world .w-plane-note {
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
  font-size: 0.625rem; font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase;
  color: rgba(191,198,207,0.82);
}
/* Every visible card (active + the one neighbour on each side) shows its
   own CTA now -- with only 3 cards ever on screen, per-card clarity reads
   better than a reveal-on-select mechanic built for a wall of eight. */
body.world .w-plane-go {
  margin-top: 0.5rem; display: inline-flex; align-items: center; gap: 0.45rem;
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
  font-size: 0.75rem; font-weight: 600; letter-spacing: 0.04em;
  color: #F4F1EA;
}
/* The focused card still carries the "obviously selected" language --
   forward (no offset/scale-down), a restrained shadow and a soft platinum
   ring. The photograph stays fully visible. */
body.world .w-plane[data-focus="1"] {
  opacity: 1;
  box-shadow: 0 22px 40px -18px rgba(34, 39, 45, 0.18), 0 0 0 1px rgba(185,154,99,.62) inset;
}
body.world .w-plane[data-focus="1"] .w-plane-name { font-size: 1.5rem; }
html[dir="rtl"] body.world .w-plane-go svg { transform: scaleX(-1); }

body.world .w-gallery-nav {
  display: flex; align-items: center; justify-content: center; gap: 0.9rem;
  margin-top: 1.25rem;
  flex-wrap: wrap;
}

/* Floating edge glass Prev/Next — Services + City carousels only.
   Physical left = Previous (<), physical right = Next (>). Chevrons do
   not flip in RTL; step(-1)/step(1) keep established carousel semantics. */
body.world .w-city-stage-wrap {
  position: relative;
  width: 100%;
}
body.world .w-edge-glass {
  position: absolute;
  top: 50%;
  z-index: 40;
  box-sizing: border-box;
  width: 48px;
  height: 48px;
  min-width: 48px;
  min-height: 48px;
  margin: 0;
  padding: 0;
  border-radius: 50%;
  border: 1px solid color-mix(in oklab, rgba(185, 154, 99, 0.42) 60%, rgba(210, 200, 180, 0.35));
  background:
    linear-gradient(160deg,
      rgba(28, 32, 38, 0.42) 0%,
      rgba(18, 22, 28, 0.55) 48%,
      rgba(12, 14, 18, 0.62) 100%);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.22) inset,
    0 -1px 0 rgba(0, 0, 0, 0.18) inset,
    0 8px 22px -14px rgba(8, 10, 14, 0.45);
  backdrop-filter: blur(12px) saturate(1.05);
  -webkit-backdrop-filter: blur(12px) saturate(1.05);
  color: rgba(244, 241, 234, 0.92);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transform: translateY(-50%);
  transition: background 140ms ease, border-color 140ms ease, box-shadow 140ms ease, transform 100ms ease;
  /* Own the hit target — no child overlays. */
  pointer-events: auto;
}
body.world .w-edge-glass.is-prev { left: 0; right: auto; }
body.world .w-edge-glass.is-next { right: 0; left: auto; }
body.world .w-edge-glass-ico,
body.world .w-edge-glass svg {
  width: 18px;
  height: 18px;
  display: block;
  pointer-events: none;
  flex-shrink: 0;
}
body.world .w-edge-glass:hover {
  background:
    linear-gradient(160deg,
      rgba(40, 46, 54, 0.52) 0%,
      rgba(24, 28, 34, 0.62) 100%);
  border-color: color-mix(in oklab, rgba(185, 154, 99, 0.55) 65%, rgba(230, 220, 200, 0.4));
  color: #F4F1EA;
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.28) inset,
    0 10px 24px -14px rgba(8, 10, 14, 0.5);
}
body.world .w-edge-glass:active {
  transform: translateY(-50%) scale(0.96);
  background:
    linear-gradient(160deg,
      rgba(22, 26, 32, 0.58) 0%,
      rgba(14, 16, 20, 0.68) 100%);
}
body.world .w-edge-glass:focus-visible {
  outline: 2px solid color-mix(in oklab, var(--w-gold) 75%, rgba(185, 154, 99, 0.5));
  outline-offset: 2px;
}
body.world .w-edge-glass:disabled {
  opacity: 0.35;
  cursor: not-allowed;
  pointer-events: none;
}
body.world .w-edge-glass:disabled:hover,
body.world .w-edge-glass:disabled:active {
  background:
    linear-gradient(160deg,
      rgba(28, 32, 38, 0.42) 0%,
      rgba(18, 22, 28, 0.55) 48%,
      rgba(12, 14, 18, 0.62) 100%);
  border-color: color-mix(in oklab, rgba(185, 154, 99, 0.42) 60%, rgba(210, 200, 180, 0.35));
  transform: translateY(-50%);
}
/* Replaces the old one-dot-per-city row (busy at 8 cities) with a compact
   "01 / 08" counter over a thin progress line -- still says exactly where
   you are and how many cities there are, without eight small targets. */
body.world .w-gallery-progress {
  display: flex; align-items: center; gap: 0.6rem;
  min-width: 120px;
}
body.world .w-gallery-count {
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
  font-size: 0.75rem; font-weight: 600; letter-spacing: 0.03em;
  font-variant-numeric: tabular-nums;
  color: color-mix(in oklab, var(--w-ink) calc((1 - var(--on-stone)) * 100%), var(--w-ink-dark));
  white-space: nowrap;
}
body.world .w-gallery-count [data-city-current] { color: var(--w-gold-deep); }
body.world .w-gallery-count-sep {
  margin-inline: 0.2em;
  color: color-mix(in oklab, var(--w-hair) calc((1 - var(--on-stone)) * 100%), rgba(11,14,18,0.32));
}
body.world .w-gallery-track {
  position: relative;
  width: 84px; height: 2px; border-radius: 2px;
  background: color-mix(in oklab, var(--w-hair) calc((1 - var(--on-stone)) * 100%), rgba(11,14,18,0.18));
  overflow: hidden;
}
/* inset-inline-start is a logical property -- it already resolves to the
   fill's growth-from-start edge in either direction (left in LTR, right in
   RTL) with no separate RTL rule needed. */
body.world .w-gallery-fill {
  position: absolute; inset-block: 0; inset-inline-start: 0;
  width: 0%; border-radius: 2px;
  background: var(--w-gold);
  transition: width 280ms cubic-bezier(0.22, 1, 0.36, 1);
}

/* Section-scoped padding: content-driven, not the taller shared .mv default
   -- an additive class on the element, rather than editing the shared rule,
   keeps every other Home section untouched. Tightened further than the
   Intent Selector above it (60-72px desktop / 48-52px mobile) per final
   polish -- no min-height/100vh anywhere in this section, so this padding
   plus the cards' own height is the section's entire vertical footprint. */
body.world .mv.w-city-section { padding-block: clamp(3.75rem, 5vw, 4.5rem); overflow-x: clip; }
/* BUG FIX (not a spacing change): the shared .mv negative-margin overlap
   system (section 2 above, margin-block-start: calc(var(--w-air-m) * -1.4))
   assumes a section's own padding-block absorbs that pull-up so only AIR
   overlaps the next section, never content. This section's padding-block is
   intentionally shorter than the shared default (comment above), so the
   next .mv genuinely overlaps ~49px into this section's own box in normal
   layout -- verified live via getBoundingClientRect(). Being the later DOM
   sibling, it was painting over this section's Next/Prev arrows, silently
   eating real pointer clicks (the focus/counter logic itself was always
   correct -- programmatic .click() proved that). Giving this section a
   z-index (its .mv parent rule already sets position:relative) is a
   stacking-order-only fix: no padding, margin, size or position value
   changes, so nothing moves on screen -- it only decides which layer wins
   the pre-existing overlap band. */
body.world .mv.w-city-section { z-index: 2; }

/* Home section-spacing refinement: Intent Selector -> City Discovery sat at
   only ~37px of actual visible air on desktop (Intent's own narrowed 86px
   bottom padding + City's 72px top padding, minus the shared -1.4x overlap
   pull-up above) -- both sections read as visually correct on their own,
   but the boundary between them read as compressed/attached rather than as
   two distinct movements. Fixed the ONLY way that's safe here: adding to
   this ONE adjacent-sibling pair's margin-block-start (still ordinary
   margin flow, never absolute positioning), never touching either
   section's own approved internal layout, padding, or any other section's
   boundary. Every other Home section boundary was audited against this one
   and already lands in one of two consistent existing tiers (~95px where
   one side uses the narrower content-driven padding, ~167px where both
   sides use the shared default) -- this was the one real outlier.

   Micro-refinement pass: the first pass's delta (+72-96px desktop,
   +52-68px mobile) measured correct but slightly too generous once seen
   live next to the rest of the rhythm -- tuned down to a smaller clamp()
   so the two sections read as one continuous experience while keeping
   real breathing room (target ~100-108px desktop / ~88-96px mobile
   content gap, still layered on the existing overlap formula via calc(),
   never a from-scratch value). */
body.world .w-intent-section + .w-city-section {
  margin-block-start: calc(var(--w-air-m) * -1.4 + clamp(4rem, 4.5vw, 4.5rem));
  /* Nearly-invisible atmosphere, not a transition band -- a very faint,
     tightly-contained champagne/graphite glow that fades out well before
     it could read as a separate rectangular block or a hard edge. */
  background: radial-gradient(90% 38% at 50% 0%, rgba(156, 132, 96, 0.08), transparent 55%);
}
@media (max-width: 767px) {
  body.world .w-intent-section + .w-city-section {
    margin-block-start: calc(var(--w-air-s) * -1 + clamp(1.25rem, 4vw, 1.75rem));
  }
}

/* =========================================================================
 * 10. PROPERTIES, SERVICES, OFFER, DEPARTURE
 * =========================================================================
 * All open compositions. A property card keeps an edge because a listing IS
 * a discrete object; nothing else does. */

/* Quick Sale section atmosphere -- purely decorative, non-spacing (no
   margin/padding here, so every already-approved Stats/Social/Intent/
   City/Services/Property-Rails boundary in this file is untouched). A
   faint warm glow anchored behind the heading, same "atmosphere, not a
   rectangular block" language as the Intent->City transition above, plus
   a small pulse dot (aria-hidden, no new copy) next to the heading text
   as the section's only "live/urgent" cue -- no fabricated countdown or
   claim, since no such data exists on a listing. */
body.world .w-quicksale-section { position: relative; }
body.world .w-quicksale-section::before {
  content: ''; position: absolute; inset-block-start: 0; inset-inline: 10%; height: 60%;
  background: radial-gradient(60% 100% at 20% 0%, rgba(156, 132, 96, 0.10), transparent 70%);
  pointer-events: none; z-index: 0;
}
body.world .w-quicksale-section .mv-in { position: relative; z-index: 1; }
body.world .w-quicksale-heading { display: flex; align-items: center; gap: 0.6rem; }
body.world .w-quicksale-pulse {
  flex: none; width: 8px; height: 8px; border-radius: 999px;
  background: var(--w-gold); box-shadow: 0 0 0 3px rgba(156, 132, 96, 0.22);
}

/* Desktop-only: tighten the Quick Sale -> Premium boundary specifically.
   Wrapped in min-width:768px because this selector's specificity (0,2,2)
   would otherwise beat the generic mobile ".mv" override (0,2,1) and leak
   into mobile spacing, which must stay untouched. */
@media (min-width: 768px) {
  body.world .w-quicksale-section + section {
    margin-block-start: calc(var(--w-air-m) * -1.4 - 24px);
  }
}

body.world .w-rail {
  display: flex; gap: clamp(1rem, 1.6vw, 1.5rem);
  overflow-x: auto; scroll-snap-type: x mandatory;
  /* Programmatic scrolls (the prev/next buttons, keyboard) glide instead of
     teleporting. Does not affect wheel/trackpad/touch input, which the
     browser drives natively. */
  scroll-behavior: smooth;
  /* A swipe that runs past the last card stays in the rail: it must not
     chain to the page (sideways page rubber-banding on iOS, back/forward
     navigation on some trackpads). */
  overscroll-behavior-x: contain;
  padding-block: 0.25rem 1rem; scrollbar-width: none;
}
body.world .w-rail::-webkit-scrollbar { display: none; }
body.world .w-rail > * { scroll-snap-align: start; }
/* The buttons already pass behavior:'auto' under reduced motion; this keeps
   the CSS layer agreeing, since 'auto' defers to scroll-behavior. */
@media (prefers-reduced-motion: reduce) {
  body.world .w-rail { scroll-behavior: auto; }
}

/* Desktop prev/next rail controls. Absolutely positioned against .mv-in
   (already position:relative) so they sit beside the section heading
   without taking part in its box model -- the heading's own layout and
   spacing are exactly what they were before these exist. Two PHYSICAL
   buttons (chevron always points the way it sits on screen); which scroll
   direction each performs is resolved live from text direction in
   js/carousel.js, so RTL is a behavior swap, never a mirrored icon.
   Mobile relies on swipe alone, per spec -- hidden below the same
   min-width:1024px cutoff already used elsewhere in this file (see the
   max-width:1023px rules above) for the tablet/desktop split. */
body.world .w-rail-nav { display: none; }
@media (min-width: 1024px) {
  body.world .w-rail-nav {
    display: flex; gap: 0.5rem;
    position: absolute; top: 0.2rem; inset-inline-end: 0;
  }
}
body.world .w-rail-nav .w-icon-btn:disabled {
  opacity: 0.35; cursor: default;
}
body.world .w-rail-nav .w-icon-btn:disabled:hover { border-color: inherit; }
/* Property Rails only: sit the prev/next controls INLINE next to "View
   All" in the same header row instead of absolutely-pinned top-right of
   the section (the default .w-rail-nav behavior above, kept as-is for
   Quick Sale so it is not touched). Modifier class, not a rule change --
   .w-rail-nav's own default stays exactly what it was. */
@media (min-width: 1024px) {
  body.world .w-rail-nav.is-inline { position: static; top: auto; inset-inline-end: auto; }
}

/* Empty state: no panel, no fill. Type and one action, standing in the
   world -- so zero listings looks composed rather than broken. */
body.world .w-empty {
  display: flex; flex-direction: column; align-items: flex-start; gap: 1.1rem;
  padding-block: var(--w-air-s);
  max-width: 34rem;
}
body.world .w-empty-actions { display: flex; flex-wrap: wrap; gap: 0.8rem; }
body.world .w-rail:has(.w-empty) { display: block; overflow: visible; }
/* Property Rails' compact empty state (see renderPropertyRail's
   compactEmpty option) -- a small inline message, never the full .w-empty
   panel three times over. */
body.world .w-rail-empty-compact {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .65rem .85rem;
  padding-block: 1.1rem;
  max-width: 36rem;
}
body.world .w-rail-empty-icon {
  color: var(--w-gold);
  flex: none;
}
body.world .w-rail-empty-copy {
  margin: 0;
  flex: 1 1 12rem;
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
  font-size: .9rem;
  color: var(--w-ink-soft);
}
body.world .w-btn--sm {
  min-height: 36px;
  padding-inline: 0.95rem;
  font-size: 0.78rem;
}
body.world .w-rail:has(.w-rail-empty-compact) { display: block; overflow: visible; }

/* Buy/Rent discovery: Rent mode still hides sale rails. Properties for Rent
   stays visible after Affordable Homes in the default Buy browse stack. */
body.world[data-home-deal="rent"] [data-home-rail="sale"] {
  display: none !important;
}

/* Services: an editorial column of rules, not a grid of boxes. */
body.world .w-list { display: flex; flex-direction: column; }
body.world .w-row {
  display: flex; align-items: center; gap: 1.1rem;
  padding: 1.15rem 0;
  border-block-end: 1px solid color-mix(in oklab, var(--w-hair) calc((1 - var(--on-stone)) * 100%), rgba(11,14,18,0.14));
  text-decoration: none;
  transition: padding-inline-start var(--w-mid) var(--w-ease-out);
}
body.world .w-row:first-child { border-block-start: 1px solid color-mix(in oklab, var(--w-hair) calc((1 - var(--on-stone)) * 100%), rgba(11,14,18,0.14)); }
body.world .w-row:hover { padding-inline-start: 0.6rem; }
body.world .w-row svg:first-child { flex: none; color: var(--w-gold); }
body.world .w-row-text { display: flex; flex-direction: column; gap: 0.1rem; min-width: 0; }
body.world .w-row-cue { margin-inline-start: auto; flex: none; opacity: 0.5; transition: transform var(--w-mid) var(--w-ease-out), opacity var(--w-fast) var(--w-ease); }
body.world .w-row:hover .w-row-cue { opacity: 1; transform: translateX(4px); }
html[dir="rtl"] body.world .w-row-cue { transform: scaleX(-1); }
html[dir="rtl"] body.world .w-row:hover .w-row-cue { transform: scaleX(-1) translateX(4px); }

/* The offer's own design now lives in css/offer-banner.css, shared by
   Home, offer.html and the Admin preview. Home only has to give the
   component room. */
body.world [data-offer-section] { margin-bottom: var(--w-air-m); }

/* Trust: a typographic list. No hairline grid, no cells, no boxes. */
body.world .w-trust { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--w-air-s) clamp(1.5rem,4vw,3.5rem); }
body.world .w-trust-item { display: flex; flex-direction: column; gap: 0.5rem; max-width: 34ch; }
body.world .w-trust-item svg { color: var(--w-gold); }

/* Departure. Quiet: type and two actions standing in the dusk. */
body.world .w-departure { display: flex; flex-direction: column; align-items: flex-start; gap: 1.3rem; padding-block: var(--w-air-m); }
body.world .w-departure-actions { display: flex; flex-wrap: wrap; gap: 0.8rem; }

/* =========================================================================
 * SERVICES DISCOVERY -- cover-flow layered card system
 * =========================================================================
 * Card DATA/content is unchanged (real SERVICE_CATALOG, real routes, real
 * i18n) -- this pass changed only HOW the cards are presented. Desktop is
 * a true cover-flow: one fully-visible active card, its immediate
 * neighbours ~60% visible sitting partly behind it, and a further ring of
 * cards showing only a narrow sliver -- js/home-services.js's paint()
 * computes each card's --tx/--scale/opacity/filter/z-index per tier
 * (three discrete tiers, not one continuous falloff) directly in JS, read
 * against the card's own rendered width so the cascade stays
 * proportionally correct across its clamp() range.
 * .w-svc-* exists only here, on Home.
 * Card content lives entirely inside the card (image, small category
 * icon, title, one-line description, "Explore Service ->"), per the
 * original brief -- no duplicate title/description block below the
 * carousel. ============================================================ */
body.world .w-services-section .w-aperture { overflow: visible; }
body.world .w-svc-copy {
  max-width: 34rem; margin-inline: auto; margin-bottom: var(--w-air-s);
  display: flex; flex-direction: column; align-items: center; gap: 0.6rem;
  text-align: center;
}
body.world .w-svc-copy .w-h2 { font-size: clamp(2.375rem, 3vw, 2.75rem); }
body.world .w-svc-copy .w-body { font-size: clamp(0.9375rem, 1vw, 1rem); max-width: 44ch; margin-inline: auto; }

/* Stage wrap: positioning context for floating edge-glass Prev/Next and a
   width roughly matched to the cover-flow cluster so controls sit at the
   carousel edges, not the far section gutters. */
body.world .w-svc-stage-wrap {
  position: relative;
  max-width: 54rem;
  margin-inline: auto;
  overflow: visible;
}
body.world .w-svc-gallery {
  position: relative;
  min-height: clamp(410px, 28vw, 450px);
  display: flex; align-items: center; justify-content: center;
  touch-action: pan-y;
}
body.world .w-svc-wall {
  position: relative; width: 100%; height: 100%;
  display: flex; align-items: center; justify-content: center;
  /* Gives the children's rotateY real foreshortening -- without a
     perspective on the shared parent, rotateY just skews the flat card
     rather than reading as depth along a curved path. */
  perspective: 1400px;
}
/* Rotating cover-flow: card content/data/routes are unchanged (see
   js/home-services.js) -- only HOW each card is placed changed. Position
   is a pure function of four JS-computed custom properties -- --tx
   (translateX), --ty (a small downward arc as cards move outward), --ry
   (rotateY, angling each card to face the centre) and --scale -- all
   already RTL-aware and pixel/degree-exact against the rendered card's
   own width, rather than a single --o formula:
     tier 0 (active):    --tx 0,   --ty 0,   --ry 0deg,        --scale 1    -- fully visible, facing forward
     tier 1 (neighbour):  ~60% of card width,  ~10px,  ~14deg (8deg mobile), --scale ~0.92 -- ~55-65% visible, curved inward
     tier 2 (outer):      a further ~25% beyond that, ~16px, ~22deg (14deg mobile), --scale ~0.85 -- narrow sliver
   opacity/z-index/filter are also set directly per card in paint() (not
   derived here), since three distinct tiers -- not one continuous
   falloff -- is what "far-left sliver -> partial -> ACTIVE -> partial ->
   far-right sliver" actually means. */
body.world .w-svc-plane {
  position: absolute;
  width: clamp(300px, 20vw, 330px);
  height: clamp(400px, 28vw, 440px);
  border-radius: var(--w-r-l);
  overflow: hidden;
  text-decoration: none;
  cursor: pointer;
  box-shadow: 0 14px 30px -18px rgba(11, 14, 18, 0.3);
  transform-style: preserve-3d;
  backface-visibility: hidden;
  transform: translateX(var(--tx, 0px)) translateY(var(--ty, 0px)) rotateY(var(--ry, 0deg)) scale(var(--scale, 1));
  /* Motion-only: transform + opacity. Filter/box-shadow snap (filter
     tween was a primary sluggishness source — forces paint each frame). */
  transition:
    transform 280ms cubic-bezier(0.22, 1, 0.36, 1),
    opacity 280ms cubic-bezier(0.22, 1, 0.36, 1);
}
/* A partially-visible card reading slightly clearer on hover/focus signals
   it's interactive (clicking it recentres it) without touching its
   JS-driven base opacity value, which stylesheet specificity can't safely
   override without !important against an inline style. */
body.world .w-svc-plane:not([data-focus="1"]):hover,
body.world .w-svc-plane:not([data-focus="1"]):focus-visible {
  filter: saturate(1) brightness(1.08) !important;
}
/* Photo-first: real service photography (--img, service-catalog.js's
   `photo` field) covers a muted, deterministic fallback gradient -- only
   ever visible on the two catalog entries with no photo yet (maintenance,
   installment). */
body.world .w-svc-plane-face {
  position: absolute; inset: 0; z-index: 0;
  background:
    var(--img, none),
    radial-gradient(48% 32% at 74% 16%, hsla(44, 78%, 91%, 0.55), transparent 72%),
    linear-gradient(180deg,
      hsl(var(--h) calc(var(--s) * 1%) calc(var(--l) * 1% + 46%)) 0%,
      hsl(calc(var(--h) - 6) calc(var(--s) * 1%) calc(var(--l) * 1% + 30%)) 48%,
      hsl(calc(var(--h) - 12) calc(var(--s) * 1%) calc(var(--l) * 1% + 14%)) 100%);
  background-size: cover;
  background-position: center;
}
/* Shorter, lighter bottom-only gradient (matches City Discovery's own
   correction): the photograph stays visible, not overly darkened, while
   the title/description/CTA over the bottom still read clearly. */
body.world .w-svc-plane-scrim {
  position: absolute; inset: 0; z-index: 0;
  background: linear-gradient(0deg, rgba(27, 30, 34, 0.58) 0%, rgba(27, 30, 34, 0.18) 42%, transparent 70%);
}
/* Small category icon -- a restrained glass chip over the image, never a
   large centered emblem competing with the photograph. */
body.world .w-svc-plane-icon {
  position: absolute; inset-block-start: 0.9rem; inset-inline-start: 0.9rem; z-index: 1;
  width: 34px; height: 34px; border-radius: var(--w-r-s);
  display: flex; align-items: center; justify-content: center;
  background: rgba(255,255,255,.62);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  border: 1px solid rgba(185,154,99,.35);
}
body.world .w-svc-plane-icon .material-symbols-outlined { font-size: 18px; color: #2F2A26; }
body.world .w-svc-plane-body {
  position: absolute; inset-inline: 0; bottom: 0; z-index: 1;
  padding: 1.2rem 1.3rem 1.35rem;
  display: flex; flex-direction: column; gap: 0.35rem;
}
body.world .w-svc-plane-title {
  font-family: 'Plus Jakarta Sans', system-ui, sans-serif;
  font-weight: 600; font-size: 1.2rem; letter-spacing: -0.015em; color: #F4F1EA;
  text-shadow: 0 1px 12px rgba(4,4,7,0.9);
}
body.world .w-svc-plane-desc {
  font-family: 'Inter', system-ui, sans-serif;
  font-size: 0.8rem; line-height: 1.42;
  color: rgba(191,198,207,0.86);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
body.world .w-svc-plane-go {
  margin-top: 0.35rem; display: inline-flex; align-items: center; gap: 0.45rem;
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
  font-size: 0.75rem; font-weight: 600; letter-spacing: 0.04em;
  color: var(--w-gold-hi);
}
body.world .w-svc-plane[data-focus="1"] {
  opacity: 1;
  box-shadow: 0 22px 40px -18px rgba(34, 39, 45, 0.18), 0 0 0 1px rgba(185,154,99,.62) inset;
}
body.world .w-svc-plane[data-focus="1"] .w-svc-plane-title { font-size: 1.4rem; }
html[dir="rtl"] body.world .w-svc-plane-go svg { transform: scaleX(-1); }
/* .w-svc-arrow-prev/-next swap physical sides under RTL via their own
   inset-inline-start/end (logical, no override needed) -- but each
   button's chevron SVG path is a fixed shape, so without this it stays
   pointing the same screen direction after the swap and both arrows end
   up pointing inward at each other instead of outward, away from the
   card cluster, same fix already applied to .w-svc-plane-go above. */
html[dir="rtl"] body.world .w-svc-arrow svg { transform: scaleX(-1); }

body.world .w-svc-gallery-nav {
  display: flex; align-items: center; justify-content: center; gap: 0.9rem;
  margin-top: 1.25rem;
  flex-wrap: wrap;
}
/* "01 / 07" counter + thin progress line -- same cleaner interaction
   language as City Discovery's pagination, not a row of tiny dots. */
body.world .w-svc-gallery-progress { display: flex; align-items: center; gap: 0.6rem; min-width: 120px; }
body.world .w-svc-gallery-count {
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
  font-size: 0.75rem; font-weight: 600; letter-spacing: 0.03em;
  font-variant-numeric: tabular-nums;
  color: color-mix(in oklab, var(--w-ink) calc((1 - var(--on-stone)) * 100%), var(--w-ink-dark));
  white-space: nowrap;
}
body.world .w-svc-gallery-count [data-svc-current] { color: var(--w-gold-deep); }
body.world .w-svc-gallery-count-sep { margin-inline: 0.2em; color: color-mix(in oklab, var(--w-hair) calc((1 - var(--on-stone)) * 100%), rgba(11,14,18,0.32)); }
body.world .w-svc-gallery-track {
  position: relative; width: 84px; height: 2px; border-radius: 2px;
  background: color-mix(in oklab, var(--w-hair) calc((1 - var(--on-stone)) * 100%), rgba(11,14,18,0.18));
  overflow: hidden;
}
/* inset-inline-start is a logical property -- already resolves to the
   fill's growth-from-start edge in either direction, no separate RTL
   rule needed (see City Discovery's identical .w-gallery-fill comment). */
body.world .w-svc-gallery-fill {
  position: absolute; inset-block: 0; inset-inline-start: 0;
  width: 0%; border-radius: 2px; background: var(--w-gold);
  transition: width 280ms cubic-bezier(0.22, 1, 0.36, 1);
}

/* Legacy flanking arrows retired — edge glass uses .w-edge-glass. */
body.world .w-svc-arrow { display: none !important; }

/* Section-scoped padding: content-driven, same 60-72px desktop / 48-52px
   mobile rhythm as City Discovery immediately above it -- no min-height,
   no 100vh, so this padding plus the cards' own height is the section's
   entire vertical footprint. */
body.world .mv.w-services-section { padding-block: clamp(3.75rem, 5vw, 4.5rem); }

/* Challenges sits on the shared movement rhythm. No extra pull. */
body.world .w-challenges {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(260px, 0.85fr);
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: center;
}
body.world .w-challenges-copy {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.9rem;
  max-width: 38rem;
}
body.world .w-challenges-copy .w-body { max-width: 42rem; }
body.world .w-challenge-panel {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: flex-end;
  gap: 1.15rem;
  min-height: 240px;
  padding: clamp(1.5rem, 3vw, 2.25rem);
  border-radius: 28px;
  background: var(--w-glass);
  border: 1px solid var(--w-glass-border);
  box-shadow: 0 12px 28px rgba(67,54,42,.10);
}
body.world .w-challenge-empty {
  margin: 0;
  color: var(--w-muted);
  font-size: 1.05rem;
  line-height: 1.5;
}
body.world .w-challenge-kicker {
  margin: 0;
  color: var(--w-gold-deep);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}
body.world .w-challenge-title {
  margin: 0.35rem 0 0;
  font-size: clamp(1.5rem, 2vw, 2rem);
  letter-spacing: -0.03em;
  line-height: 1.15;
}
body.world .w-challenge-title a {
  color: inherit;
  text-decoration: none;
}
body.world .w-challenge-desc,
body.world .w-challenge-meta,
body.world .w-challenge-prize {
  margin: 0.55rem 0 0;
  color: var(--w-muted);
  line-height: 1.5;
}
body.world .w-challenge-panel .w-btn { min-height: 48px; }
@media (max-width: 860px) {
  body.world .w-challenges { grid-template-columns: 1fr; gap: 1.75rem; }
  body.world .w-challenge-panel { min-height: 0; }
  body.world .w-challenge-panel .w-btn { width: 100%; justify-content: center; }
}

/* =========================================================================
 * 11. HEADER
 * ========================================================================= */
/* The shared header (js/site-header.js) paints its own surface. Home does
   not restyle it. */

/* =========================================================================
 * 12. MOBILE -- the same world, fewer planes
 * =========================================================================
 * Not a stacked desktop. Continuity, atmosphere, hierarchy and every
 * handoff survive; what reduces is plane count (2 not 3), travel distance,
 * and blur cost. The world becomes ABSOLUTE rather than FIXED: a fixed
 * full-viewport painted layer is the classic mobile scroll-jank trap, and
 * the continuity requirement is satisfied either way because the element
 * still has no edge inside the document. ============================== */
@media (max-width: 767px) {
  body.world .world-field,
  body.world .w-hero-plane {
    background: #F6F1E8;
    background-image: none;
  }
  body.world .world-field::before,
  body.world .world-field::after,
  body.world .w-hero-plane::after { content: none; display: none; background: none; }
  body.world .w-hero-plane::before { box-shadow: 0 8px 18px rgba(70,65,55,.08); }

  body.world .mv { padding-block: var(--w-air-m); margin-block-start: calc(var(--w-air-s) * -1); }
  body.world .mv[data-cine3d="hero"] { padding-block: 5.75rem 0.25rem; }
  body.world .w-hero {
    min-height: 0;
    margin-inline: 0.75rem;
    padding: 1.15rem 0.9rem 0.75rem;
    border-radius: 24px;
  }
  body.world .w-hero-aside {
    position: static;
    text-align: center;
    max-width: 28rem;
    margin-inline: auto;
  }
  body.world .w-hero-stage { min-height: 460px; border-radius: 18px; }
  body.world .w-hero-dock { width: calc(100% - 1rem); }
  body.world .w-hero-mode { min-height: 44px; }
  body.world .w-hero-field { min-height: 48px; }
  body.world .w-hero-go { width: 44px; height: 44px; }
  body.world .w-hero-suggest { justify-content: flex-start; }
  body.world .w-hero-suggest a { min-height: 44px; }
  body.world .w-hero-plane {
    -webkit-mask-image: none;
            mask-image: none;
  }
  /* Mobile hero refinements: the headline was reading too tall/crowded --
     a smaller clamp ceiling + tighter line-height keeps the two-line
     headline from wrapping into a third, and every element below gets
     its own considered spacing rather than one flat gap, so nothing
     feels stacked on top of its neighbour. */
  /* Final polish: even tighter inter-group rhythm than the previous
     pass -- the whole block reads noticeably smaller now, so 12-18px
     compounded was starting to feel loose again. */
  body.world .w-hero-copy { gap: 0.7rem; max-width: 100%; }
  body.world .w-hero-copy .w-display [data-i18n="index.heroLine1"] { font-size: clamp(30px, 9vw, 44px); }
  body.world .w-hero-copy .w-display [data-i18n="index.heroLine2"] { font-size: clamp(22px, 6.5vw, 32px); }
  html[dir="rtl"] body.world .w-hero-copy .w-display [data-i18n="index.heroLine1"] { font-size: clamp(28px, 8vw, 40px); line-height: 1.16; }
  html[dir="rtl"] body.world .w-hero-copy .w-display [data-i18n="index.heroLine2"] { font-size: clamp(20px, 5.6vw, 28px); line-height: 1.2; }
  /* Mobile: let each line wrap again (desktop's nowrap is undone here),
     and balance the break instead of the browser's default greedy wrap
     -- "More Than" / "Property." rather than an uneven "More" / "Than
     Property.". text-wrap:balance degrades gracefully to a normal wrap
     in browsers that don't support it yet. */
  body.world .w-hero-copy .w-display span { white-space: nowrap; }
  @media (max-width: 359px) {
    body.world .w-hero-copy .w-display [data-i18n="index.heroLine2"] { font-size: 20px; }
  }
  /* Slightly warmer + higher-contrast than the desktop dimming without
     going bright white -- still clearly secondary to the headline. */
  body.world .w-hero-copy .w-body { max-width: 20.5rem; font-size: clamp(0.875rem, 3.4vw, 1rem); line-height: 1.6; color: #6E6258; }
  /* Property-type chips: a 2x2 grid reads calmer at phone width than a
     4-up row that would wrap unevenly -- sized as compact filter controls,
     not full-width CTAs. */
  body.world .w-hero-copy .w-chips { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0.45rem; width: 100%; max-width: 19rem; }
  body.world .w-hero-copy .w-chip { justify-content: center; min-height: 35px; padding-inline: 10px; font-size: 0.8rem; }
  /* CTAs stack full-width so both read as equally reachable, one-thumb
     targets rather than a cramped side-by-side pair. */
  body.world .w-hero-cta-row { flex-direction: column; width: 100%; max-width: 19rem; gap: 0.55rem; }
  body.world .w-hero-cta-row .w-btn { width: 100%; justify-content: center; padding-inline: 1.2rem; min-height: 43px; font-size: 0.85rem; }
  body.world .w-hero-values { font-size: 0.625rem; letter-spacing: 0.18em; }
  body.world .w-quickstart {
    /* Owner: proportional extra air above stats on mobile (~16–24px). */
    margin-top: calc(0.35rem + clamp(1rem, 4.5vw, 1.5rem));
    padding: 0.55rem 0 0.45rem;
    border-radius: 0;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
  /* Six stats: 2×3 on phones; unavailable remain neutral dashes. */
  body.world .w-quickstart .w-stats {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem 1rem;
    width: 100%;
    max-width: 22rem;
    margin-inline: auto;
  }
  body.world .w-quickstart .w-stat { min-width: 0; width: 100%; }
  body.world .w-quickstart .w-stats .w-stat--unavailable { display: block; }
  body.world .w-quickstart .w-stat-num { font-size: clamp(2.2rem, 8.5vw, 2.7rem); }
  body.world .w-quickstart .w-stat-label { font-size: 0.58rem; letter-spacing: 0.11em; margin-top: 0.32rem; }
}

/* Short mobile screens (iPhone SE and similar, <=700px tall): compress the
   space above the stats so the hero copy keeps room above the screen edge. */
@media (max-width: 767px) and (max-height: 700px) {
  body.world .w-hero { padding-block-start: 1.15rem; }
  body.world .w-hero-copy { gap: 0.6rem; }
  body.world .w-hero-copy .w-display [data-i18n="index.heroLine1"] { font-size: clamp(28px, 8vw, 36px); }
  body.world .w-hero-copy .w-display [data-i18n="index.heroLine2"] { font-size: clamp(20px, 6vw, 28px); }
  body.world .w-hero-copy .w-body { -webkit-line-clamp: 2; display: -webkit-box; -webkit-box-orient: vertical; overflow: hidden; }
}

@media (max-width: 767px) {
  /* Intent: native horizontal snap carousel. Each card is 85vw with a
     14px gap, so the next card stays visible (about 11% of the screen)
     without becoming a full-bleed slide. Arrows and dots live in
     .w-intent-nav and are hidden from desktop. */
  body.world .w-intent-section { overflow-x: clip; }
  body.world .w-intent-row {
    width: 100vw;
    max-width: 100vw;
    margin-inline: calc(50% - 50vw);
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-padding-inline-start: 0;
    scrollbar-width: none;
    gap: 14px;
    padding-block: 4px;
    touch-action: pan-x pan-y;
    overscroll-behavior-x: contain;
  }
  body.world .w-intent-row::-webkit-scrollbar { display: none; }
  body.world .w-intent-row::after {
    content: '';
    flex: 0 0 calc(15vw - 14px);
    scroll-snap-align: none;
  }
  body.world .w-intent-card {
    flex: 0 0 85vw;
    width: 85vw;
    max-width: 85vw;
    scroll-snap-align: start;
    height: clamp(215px, 50vw, 235px);
    padding-bottom: 1.1rem;
    scroll-margin-block-end: env(safe-area-inset-bottom, 0px);
  }
  body.world .w-intent-nav {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    margin-top: 14px;
  }
  body.world .w-intent-arrows { display: flex; align-items: center; justify-content: center; gap: 16px; }
  body.world .w-intent-step {
    width: 40px; height: 40px; border-radius: 999px; flex: none;
    display: inline-flex; align-items: center; justify-content: center;
    color: #2F2A26; background: var(--w-glass); cursor: pointer;
    border: 1px solid var(--w-glass-border);
    transition: background-color 180ms cubic-bezier(.2,.8,.2,1), border-color 180ms cubic-bezier(.2,.8,.2,1), opacity 180ms cubic-bezier(.2,.8,.2,1);
  }
  body.world .w-intent-step:hover { border-color: var(--w-glass-hi); background: rgba(255,255,255,.1); }
  body.world .w-intent-step:disabled { opacity: 0.35; cursor: default; background: transparent; border-color: var(--w-glass-border); pointer-events: none; }
  body.world .w-intent-step:focus-visible { outline: 2px solid var(--w-gold-hi); outline-offset: 3px; }
  html[dir="rtl"] body.world .w-intent-step svg { transform: scaleX(-1); }
  body.world .w-intent-dots { display: flex; align-items: center; justify-content: center; gap: 8px; }
  body.world .w-intent-dot {
    width: 6px; height: 6px; padding: 0; border-radius: 999px; border: 0; cursor: pointer;
    background: rgba(217,221,227,.28);
    transition: background-color 180ms cubic-bezier(.2,.8,.2,1), transform 180ms cubic-bezier(.2,.8,.2,1);
  }
  body.world .w-intent-dot.is-active,
  body.world .w-intent-dot[aria-current="true"] { background: var(--w-gold-hi); transform: scale(1.15); }
  body.world .w-intent-dot:focus-visible { outline: 2px solid var(--w-gold-hi); outline-offset: 3px; }
  body.world .mv.w-intent-section { padding-block: clamp(3rem, 12vw, 3.5rem); }
  body.world .w-intent-heading { font-size: clamp(1.75rem, 7vw, 2.125rem); }

  /* City gallery: a completely different mobile composition, not the
     desktop cascade squeezed down. A real horizontally-scrolling,
     snap-to-center carousel -- #cityWall (the '.w-gallery' div) becomes the
     scroll container itself, so native touch drag, arrows, dots and
     keyboard (js/city-gallery.js) all move the same one source of truth.
     Every plane is a normal in-flow flex item here, not the absolutely
     positioned cascade card -- the data-near cutoff and --o transform from
     the desktop rules are switched off below rather than fought. */
  body.world .mv.w-city-section { padding-block: clamp(3rem, 12vw, 3.25rem); overflow-x: clip; }
  body.world .w-city-copy .w-h2 { font-size: clamp(1.75rem, 7vw, 2rem); }
  body.world .w-city-copy .w-body { font-size: 0.875rem; }
  body.world .w-aperture { overflow: visible; }
  /* Edge controls sit on the carousel frame; keep hit targets ≥44px without
     covering the focused card's title/CTA band. */
  body.world .w-city-stage-wrap {
    overflow: visible;
  }
  body.world .w-city-stage-wrap > .w-edge-glass,
  body.world .w-svc-stage-wrap > .w-edge-glass {
    width: 44px;
    height: 44px;
    min-width: 44px;
    min-height: 44px;
  }
  body.world .w-city-stage-wrap > .w-edge-glass.is-prev { left: 4px; }
  body.world .w-city-stage-wrap > .w-edge-glass.is-next { right: 4px; }
  body.world .w-svc-stage-wrap {
    max-width: none;
    width: 100vw;
    margin-inline: calc(50% - 50vw);
    overflow: visible;
  }
  /* Parent already full-bleed — do not double the viewport breakout. */
  body.world .w-svc-stage-wrap .w-svc-gallery { margin-inline: 0; }
  body.world .w-svc-stage-wrap > .w-edge-glass.is-prev { left: 6px; }
  body.world .w-svc-stage-wrap > .w-edge-glass.is-next { right: 6px; }
  body.world .w-gallery {
    --city-gutter: clamp(1.25rem, 4vw, 4.5rem);
    display: block;
    min-height: 0;
    overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none;
    overscroll-behavior-x: contain;
    /* touch-action:pan-y (desktop/tablet cascade, above) would block the
       browser's own horizontal scroll-snap drag here -- auto lets it
       decide per-axis, exactly what a real horizontal scroller needs while
       still passing vertical drags up to scroll the page. */
    touch-action: auto;
    padding-inline: var(--city-gutter);
    margin-inline: calc(var(--city-gutter) * -1);
    scroll-padding-inline: var(--city-gutter);
  }
  body.world .w-gallery::-webkit-scrollbar { display: none; }
  body.world .w-wall { display: flex; width: max-content; height: auto; gap: 12px; }
  body.world .w-plane {
    position: relative;
    width: auto;
    height: clamp(320px, 78vw, 420px);
    flex: 0 0 84vw;
    max-width: 420px;
    border-radius: var(--w-r-l);
    scroll-snap-align: center;
    transform: none !important;
    opacity: 1 !important;
    z-index: auto;
  }
  body.world .w-plane-name { font-size: 1.125rem; }
  body.world .w-plane[data-focus="1"] .w-plane-name { font-size: 1.25rem; }
  body.world .w-gallery-nav { margin-top: 0.75rem; }

  /* Services: the SAME rotating cover-flow as desktop (js/home-services.js
     computes one transform model on every breakpoint) -- only sized down
     and lighter-rotated for portrait. Only one card is fully readable;
     left/right show a small curved portion, outer cards are mostly
     hidden. .w-svc-gallery breaks out to the full viewport width (its
     parent .mv-in carries side padding that would otherwise squeeze the
     sliver's room) and clips there, so a peeking card is cropped cleanly
     at the screen edge instead of ever forcing page-level horizontal
     scroll -- there is no native scroll container to rely on any more. */
  body.world .mv.w-services-section { padding-block: clamp(3rem, 12vw, 3.25rem); }
  body.world .w-svc-copy { max-width: 100%; padding-inline: 0.5rem; }
  body.world .w-svc-copy .w-h2 { font-size: clamp(1.75rem, 7vw, 2rem); }
  body.world .w-svc-copy .w-body { font-size: 0.875rem; }
  body.world .w-svc-gallery {
    /* Logical margin-inline (not left/margin-left + position:relative --
       verified live: that physical-property trick anchors a block wider
       than its container to the CONTAINING BLOCK'S opposite physical edge
       under dir:rtl, landing the whole gallery off-centre instead of
       full-bleed) -- equal negative margin on both logical sides expands
       symmetrically to the viewport regardless of writing direction. */
    margin-inline: calc(50% - 50vw);
    min-height: clamp(285px, 40vw, 305px);
    overflow: hidden;
  }
  /* Narrower than the old 80vw -- at 80vw the active card left almost no
     room on either side, so a neighbour's peek was either near-zero or, once
     scaled/rotated, wildly uneven between the two sides. At 74vw the fixed
     (100vw - 74vw)/2 = 13vw side margin this full-bleed layout leaves on
     each edge is what actually determines how much of a neighbour peeks out
     (clipped by the viewport edge, not by translateX) -- same amount on
     both sides by construction, verified live. */
  body.world .w-svc-plane { width: 74vw; height: clamp(285px, 40vw, 305px); }
  body.world .w-svc-plane-title { font-size: 1.05rem; }
  body.world .w-svc-plane[data-focus="1"] .w-svc-plane-title { font-size: 1.15rem; }
  body.world .w-svc-gallery-nav { margin-top: 0.75rem; }

  body.world .w-trust { grid-template-columns: 1fr; }
  body.world .w-empty-actions { width: 100%; }
  body.world .w-empty-actions .w-btn { flex: 1 1 auto; }
  body.world { padding-bottom: env(safe-area-inset-bottom, 0px); }
}

@media (min-width: 768px) and (max-width: 1023px) {
  /* No override needed for .w-intent-row here: the base five-equal-card
     flex row (section 8) already fits this width without hiding any
     card. */
  body.world .w-hero-aside {
    position: static;
    max-width: 22rem;
    margin: 0.75rem auto 0;
    text-align: center;
  }
}

/* =========================================================================
 * 12. FOOTER -- Deep Navy close
 * =========================================================================
 * The footer sits AFTER the journey (--journey has already reached 1 by
 * the time it's on screen, so the world-field is already fully navy
 * behind it) but it is its own opaque element, not part of the fixed
 * field -- css/cinematic.css's `.cine-scope .home-footer` rule gives it a
 * light ivory surface (correct for every OTHER page that reuses the same
 * component), which this overrides specifically for Home, per the
 * approved HOME COLOR FLOW ("Footer = Deep Navy"). Text/link colors
 * inside it get their own explicit on-navy values rather than reading
 * --on-stone, since the footer never sits anywhere but the end of the
 * journey -- it has no tonal ambiguity to resolve. ======================= */
body.world .home-footer {
  background: #F6F1E8;
  border-top: 1px solid rgba(42, 46, 52, 0.08);
}
body.world .home-section-link { color: #6E6258; }
body.world .home-section-link:hover { color: var(--w-gold); }
body.world .home-footer-word { color: var(--w-gold-deep); }
body.world .home-footer-tagline,
body.world .home-footer-link,
body.world .home-footer-bottom { color: #6E6258; }
body.world .home-footer-heading { color: #2F2A26; }
body.world .home-footer-link:hover { color: var(--w-gold-deep); }
body.world .home-footer-bottom { border-top-color: rgba(42, 46, 52, 0.08); }

@media (max-width: 767px) {
  body.world .w-chip,
  body.world .w-icon-btn,
  body.world .w-hero-copy .w-btn--primary,
  body.world .w-hero-copy .w-btn--ghost {
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
  }
}

/* =========================================================================
 * 13. REDUCED MOTION
 * =========================================================================
 * The world, the tonal journey and every composition remain. Only the
 * movement stops: planes rest at their designed positions, and the gallery
 * still changes focus -- instantly instead of gliding. ================== */
@media (prefers-reduced-motion: reduce) {
  body.world .w-plane,
  body.world .w-svc-plane,
  body.world .w-intent-card,
  body.world .w-intent-media,
  body.world .w-intent-arrow,
  body.world .w-intent-desc,
  body.world .w-btn,
  body.world .w-btn-arrow,
  body.world .w-action::after,
  body.world .w-row,
  body.world .w-row-cue,
  body.world .w-icon-btn,
  body.world .w-edge-glass { transition: none; }
  /* Every choreographed element rests at its finished state. The controller
     also parks --fp at 0.5 and never attaches a scroll listener, so this is
     belt and braces rather than the only defence. */
  body.world [data-flow] { transform: none !important; opacity: 1 !important; }
  body.world .w-hero-plane::before,
  body.world .world-field::before,
  body.world .world-field::after { transform: none !important; }
  body.world .w-hero-plane { background-position: center, center, center, center 24%; }
  /* Belt and braces for the mobile city carousel's native scroll-snap: JS
     already asks for instant (not smooth) scrollIntoView when this media
     query matches (js/city-gallery.js's prefersReducedMotion()), this just
     covers any native browser-driven snap settling too. */
  body.world .w-gallery { scroll-behavior: auto; }
}

/* =========================================================================
 * MOON — flat luxury black. No silk, marble, or pattern.
 * Sun (html[data-dg-theme="light"]) keeps the ivory field above.
 * ========================================================================= */
html:not([data-dg-theme="light"]) body.world {
  --w-navy: #0D0F12;
  --w-navy-hi: #252B33;
  --w-ivory: #15191E;
  --w-ivory-lo: #0D0F12;
  --w-platinum: #D7DBE0;
  --w-silver: #1C2128;
  --w-glass: rgba(30,35,42,.68);
  --w-glass-mid: #1C2128;
  --w-glass-border: rgba(215,219,224,.12);
  --w-glass-hi: rgba(215,219,224,.12);
  --w-gold: #B49A6A;
  --w-gold-hi: #D7DBE0;
  --w-gold-deep: #B49A6A;
  --w-ink: #F1F3F5;
  --w-ink-soft: #A5ABB3;
  --w-ink-dark: #F1F3F5;
  --w-ink-dark-mute: #A5ABB3;
  --w-muted: #A5ABB3;
  --w-hair: rgba(215,219,224,.12);
  --w-hair-warm: rgba(180,154,106,.40);
  --on-stone: 1;
  background: #0D0F12;
  color: #F1F3F5;
}
html:not([data-dg-theme="light"]) body.world.cine-scope.bg-background {
  background-color: #0D0F12;
  background-image: none;
  color: #F1F3F5;
}
html:not([data-dg-theme="light"]) .world-field {
  background: #0D0F12;
  background-image: none;
}
html:not([data-dg-theme="light"]) .world-field::before,
html:not([data-dg-theme="light"]) .world-field::after {
  content: none;
  display: none;
  background: none;
  background-image: none;
  filter: none;
  transform: none;
}
html:not([data-dg-theme="light"]) .world-field .wf-navy,
html:not([data-dg-theme="light"]) .world-field .wf-ivory,
html:not([data-dg-theme="light"]) .world-field .wf-vignette {
  display: none;
  background: none;
  opacity: 0;
}
html:not([data-dg-theme="light"]) body.world .w-hero {
  background: #0D0F12;
  border-color: rgba(215,219,224,.12);
}
html:not([data-dg-theme="light"]) body.world .w-hero-plane {
  background: #0D0F12;
  background-image: none;
}
html:not([data-dg-theme="light"]) body.world .w-hero-plane::after { background: none; }
html:not([data-dg-theme="light"]) body.world .w-hero-photo-day { opacity: 0; }
html:not([data-dg-theme="light"]) body.world .w-hero-photo-night { opacity: 1; }
html:not([data-dg-theme="light"]) body.world .w-hero-aside { color: #A5ABB3; }
html:not([data-dg-theme="light"]) body.world .w-hero-search,
html:not([data-dg-theme="light"]) body.world .w-hero-field {
  background: rgba(24,28,33,.82);
  border-color: rgba(215,219,224,.12);
  color: #F1F3F5;
}
html:not([data-dg-theme="light"]) body.world .w-hero-search {
  box-shadow: 0 12px 28px rgba(0,0,0,.24);
}
html:not([data-dg-theme="light"]) body.world .w-hero-mode { color: #A5ABB3; background: transparent; }
html:not([data-dg-theme="light"]) body.world .w-hero-mode:hover,
html:not([data-dg-theme="light"]) body.world .w-hero-mode[aria-pressed="true"],
html:not([data-dg-theme="light"]) body.world .w-hero-mode[aria-pressed="true"]:hover {
  background: transparent;
  color: #F1F3F5;
  box-shadow: none;
}
html:not([data-dg-theme="light"]) body.world .w-hero-mode-indicator {
  background: color-mix(in srgb, #252B33 88%, var(--w-gold) 12%);
  border-color: color-mix(in srgb, var(--w-gold) 42%, transparent);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.06),
    0 4px 14px rgba(0,0,0,.24);
  backdrop-filter: blur(14px) saturate(115%);
  -webkit-backdrop-filter: blur(14px) saturate(115%);
}
html:not([data-dg-theme="light"]) body.world .w-hero-field:focus-within {
  border-color: rgba(180,154,106,.55);
  box-shadow: inset 0 0 0 1px rgba(180,154,106,.22);
}
html:not([data-dg-theme="light"]) body.world .w-hero-suggest a {
  background: rgba(30,35,42,.46);
  border-color: rgba(215,219,224,.16);
  color: #D7DBE0;
  box-shadow: 0 6px 16px rgba(0,0,0,.16);
}
html:not([data-dg-theme="light"]) body.world .w-hero-suggest a:hover,
html:not([data-dg-theme="light"]) body.world .w-hero-suggest a:active {
  border-color: rgba(180,154,106,.55);
  color: #F1F3F5;
}
html:not([data-dg-theme="light"]) body.world .w-hero-suggest a:active {
  background: rgba(180,154,106,.16);
}
html:not([data-dg-theme="light"]) body.world .w-hero-field input { color: #F1F3F5; }
html:not([data-dg-theme="light"]) body.world .w-hero-field input::placeholder { color: #A5ABB3; }
html:not([data-dg-theme="light"]) body.world .w-hero-locate { color: #B49A6A; }
html:not([data-dg-theme="light"]) body.world .w-hero-go { background: #D7DBE0; color: #0D0F12; }
html:not([data-dg-theme="light"]) body.world .w-hero-copy {
  background: none;
  background-image: none;
  border-color: transparent;
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
html:not([data-dg-theme="light"]) body.world .w-hero-copy {
  --hero-ivory: #F1F3F5;
  --hero-champagne: #B49A6A;
}
html:not([data-dg-theme="light"]) body.world .w-hero-copy .w-display [data-i18n="index.heroLine2"] {
  color: #B49A6A;
  background: none;
  -webkit-text-fill-color: #B49A6A;
}
html:not([data-dg-theme="light"]) body.world .w-hero-copy .w-chip svg { color: #B49A6A; }
html:not([data-dg-theme="light"]) body.world .w-quickstart {
  background: transparent;
  border-color: transparent;
  box-shadow: none;
}
html:not([data-dg-theme="light"]) body.world .w-quickstart::before {
  content: none;
  display: none;
}
html:not([data-dg-theme="light"]) body.world .w-hero-copy .w-body,
html:not([data-dg-theme="light"]) body.world .w-stat-label,
html:not([data-dg-theme="light"]) body.world .home-section-link,
html:not([data-dg-theme="light"]) body.world .home-footer-tagline,
html:not([data-dg-theme="light"]) body.world .home-footer-link,
html:not([data-dg-theme="light"]) body.world .home-footer-bottom {
  color: #A5ABB3;
}
html:not([data-dg-theme="light"]) body.world .w-btn--primary,
html:not([data-dg-theme="light"]) body.world .w-hero-copy .w-btn--primary,
html:not([data-dg-theme="light"]) body.world .w-quickstart .w-btn--primary,
html:not([data-dg-theme="light"]) body.world .w-btn--ghost,
html:not([data-dg-theme="light"]) body.world .w-hero-copy .w-btn--ghost,
html:not([data-dg-theme="light"]) body.world .w-chip,
html:not([data-dg-theme="light"]) body.world .w-icon-btn,
html:not([data-dg-theme="light"]) body.world .w-intent-step {
  background: rgba(30,35,42,.68);
  background-image: none;
  color: #F1F3F5;
  border-color: rgba(215,219,224,.12);
}
html:not([data-dg-theme="light"]) body.world .w-btn--primary,
html:not([data-dg-theme="light"]) body.world .w-hero-copy .w-btn--primary,
html:not([data-dg-theme="light"]) body.world .w-quickstart .w-btn--primary {
  border-color: rgba(180,154,106,.45);
}
html:not([data-dg-theme="light"]) body.world .w-btn--ghost:hover,
html:not([data-dg-theme="light"]) body.world .w-hero-copy .w-btn--ghost:hover,
html:not([data-dg-theme="light"]) body.world .w-chip:hover,
html:not([data-dg-theme="light"]) body.world .w-icon-btn:hover {
  background: rgba(255,255,255,.08);
  border-color: rgba(180,154,106,.45);
  color: #F1F3F5;
}
html:not([data-dg-theme="light"]) body.world .w-edge-glass {
  border-color: rgba(180, 154, 106, 0.38);
  background:
    linear-gradient(160deg,
      rgba(48, 54, 62, 0.55) 0%,
      rgba(28, 33, 38, 0.72) 100%);
  color: #E8EBF0;
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.1) inset,
    0 8px 20px -14px rgba(0, 0, 0, 0.5);
}
html:not([data-dg-theme="light"]) body.world .w-edge-glass:hover {
  background:
    linear-gradient(160deg,
      rgba(58, 64, 72, 0.62) 0%,
      rgba(34, 40, 46, 0.78) 100%);
  border-color: rgba(180, 154, 106, 0.5);
  color: #E6C989;
}
html:not([data-dg-theme="light"]) body.world .w-quickstart .w-stat-num:not(.is-loading) {
  background: none;
  -webkit-text-fill-color: #F1F3F5;
  color: #F1F3F5;
}
html:not([data-dg-theme="light"]) body.world .w-stat-num { color: #F1F3F5; }
html:not([data-dg-theme="light"]) body.world .w-stat-num.is-loading {
  color: #8B929B;
  -webkit-text-fill-color: #8B929B;
}
html:not([data-dg-theme="light"]) body.world .w-stat--unavailable .w-stat-num {
  color: rgba(165,171,179,.45);
  -webkit-text-fill-color: rgba(165,171,179,.45);
}
html:not([data-dg-theme="light"]) body.world .w-intent-icon,
html:not([data-dg-theme="light"]) body.world .w-svc-plane-icon {
  background: rgba(30,35,42,.68);
  border-color: rgba(215,219,224,.12);
  box-shadow: none;
}
html:not([data-dg-theme="light"]) body.world .w-intent-icon,
html:not([data-dg-theme="light"]) body.world .w-svc-plane-icon .material-symbols-outlined {
  color: #F1F3F5;
}
html:not([data-dg-theme="light"]) body.world .home-footer {
  background: #15191E;
  background-image: none;
  border-top-color: rgba(215,219,224,.12);
}
html:not([data-dg-theme="light"]) body.world .w-challenge-panel {
  box-shadow: 0 12px 28px rgba(0,0,0,.24);
}

/* =========================================================================
 * Homele rails — Quick Sale, Premium, Affordable Homes, Properties for Rent.
 * Fixed card geometry (~310×330). Outer arrows beside the card row.
 * Rent / Map / other sections keep their own rules.
 * ========================================================================= */
body.world {
  --homele-gap: 44px;
  --homele-rail-pad: 8px;
  --homele-head-gap: 22px;
  --homele-card-w: 310px;
  --homele-card-gap: 18px;
  --homele-media-h: 200px;
  --homele-edge: 52px;
}
@media (min-width: 768px) {
  body.world { --homele-gap: 60px; }
}
@media (min-width: 1024px) {
  body.world { --homele-gap: 80px; }
}

body.world .w-homele-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin: 0 0 calc(var(--homele-head-gap) - 6px);
}
body.world .w-homele-head .w-h2,
body.world .w-homele-head .w-rail-title { margin: 0; }
body.world .w-homele-stage {
  position: relative;
  /* Room for 48×48 outer arrows outside the rail. */
  padding-inline: var(--homele-edge);
}
body.world .w-homele-rail {
  gap: var(--homele-card-gap);
  margin-inline: 0;
  padding-block: 4px var(--homele-rail-pad);
  min-width: 0;
}
/* Square 48×48 hit target; circular face is decorative so corner clicks
   still land on the <button> (border-radius:50% would punch hit-testing). */
body.world .w-homele-edge {
  position: absolute;
  top: 50%;
  z-index: 6;
  transform: translateY(-50%);
  box-sizing: border-box;
  width: 48px;
  height: 48px;
  min-width: 48px;
  min-height: 48px;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
  color: rgba(244, 241, 234, 0.92);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  pointer-events: auto;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}
body.world .w-homele-edge-face {
  box-sizing: border-box;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  border: 1px solid color-mix(in oklab, rgba(185, 154, 99, 0.42) 60%, rgba(210, 200, 180, 0.35));
  background:
    linear-gradient(160deg,
      rgba(28, 32, 38, 0.42) 0%,
      rgba(18, 22, 28, 0.55) 48%,
      rgba(12, 14, 18, 0.62) 100%);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.22) inset,
    0 -1px 0 rgba(0, 0, 0, 0.18) inset,
    0 8px 22px -14px rgba(8, 10, 14, 0.45);
  backdrop-filter: blur(12px) saturate(1.05);
  -webkit-backdrop-filter: blur(12px) saturate(1.05);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}
body.world .w-homele-edge svg,
body.world .w-homele-edge .w-edge-glass-ico,
body.world .w-homele-edge path {
  pointer-events: none !important;
  width: 18px;
  height: 18px;
  display: block;
}
body.world .w-homele-edge--left { left: 0; right: auto; }
body.world .w-homele-edge--right { right: 0; left: auto; }
body.world .w-homele-edge:hover:not(:disabled) .w-homele-edge-face {
  background:
    linear-gradient(160deg,
      rgba(40, 46, 54, 0.52) 0%,
      rgba(24, 28, 34, 0.62) 100%);
  border-color: color-mix(in oklab, rgba(185, 154, 99, 0.55) 65%, rgba(230, 220, 200, 0.4));
}
body.world .w-homele-edge:active:not(:disabled) { transform: translateY(-50%) scale(0.96); }
body.world .w-homele-edge:focus-visible {
  outline: 2px solid color-mix(in oklab, var(--w-gold) 75%, rgba(185, 154, 99, 0.5));
  outline-offset: 2px;
}
html[dir="rtl"] body.world .w-homele-edge svg { transform: none; }
body.world .w-homele-edge:disabled {
  opacity: 0.35;
  cursor: not-allowed;
  pointer-events: none;
}
html[data-dg-theme="light"] body.world .w-homele-edge { color: #2F2A26; }
html[data-dg-theme="light"] body.world .w-homele-edge-face {
  background:
    linear-gradient(160deg,
      rgba(255, 252, 247, 0.88) 0%,
      rgba(244, 241, 234, 0.92) 100%);
  border-color: color-mix(in oklab, rgba(185, 154, 99, 0.45) 55%, rgba(47, 42, 38, 0.14));
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.85) inset,
    0 8px 18px -12px rgba(47, 42, 38, 0.28);
}
body.world .w-homele-stage:has(.w-rail-empty-compact) .w-homele-edge,
body.world .w-homele-stage:has(.w-empty) .w-homele-edge {
  visibility: hidden;
  pointer-events: none;
}
body.world .w-homele-stage:has(.w-rail-empty-compact),
body.world .w-homele-stage:has(.w-empty) {
  padding-inline: 0;
}

/* End of a card row → next of these three headings. */
body.world .w-quicksale-section.w-homele-section { padding-block-end: 0; }
body.world .w-quicksale-section.w-homele-section + section.mv {
  margin-block-start: 0;
  padding-block-start: calc(var(--homele-gap) - var(--homele-rail-pad));
}
body.world .w-homele-block + .w-homele-block {
  margin-top: calc(var(--homele-gap) - var(--homele-rail-pad) - var(--w-air-s));
}

/* Fixed Homele card width — never stretch to fill empty slots. */
body.world .w-homele-rail > .homele-card {
  flex: 0 0 min(var(--homele-card-w), 100%);
  width: min(var(--homele-card-w), 100%);
  max-width: 100%;
  min-width: 0;
  height: auto;
  min-height: 320px;
}

body.world .homele-card {
  display: flex;
  flex-direction: column;
  border-radius: 20px;
  overflow: hidden;
  background: #14181f;
  border: 1px solid rgba(244, 241, 234, 0.08);
  box-shadow: 0 16px 36px -22px rgba(0, 0, 0, 0.72);
  color: #F4F1EA;
  text-decoration: none;
}
body.world .homele-card--skeleton { pointer-events: none; min-height: 320px; }
body.world .homele-media {
  position: relative;
  flex: none;
  margin: 10px 10px 0;
  height: var(--homele-media-h);
  min-height: var(--homele-media-h);
  border-radius: 16px;
  overflow: hidden;
  background: #10141a;
}
body.world .homele-slide {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: none;
  pointer-events: none;
}
body.world .homele-slide.is-active { display: block; }
body.world .homele-hit {
  position: absolute;
  inset: 0;
  z-index: 1;
}
body.world .homele-fallback {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 12px;
  text-align: center;
  color: #A8A29A;
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
  font-size: 11px;
  line-height: 1.35;
  background:
    radial-gradient(80% 80% at 50% 20%, rgba(185, 154, 99, 0.16), transparent 60%),
    #12161c;
}
body.world .homele-fallback[hidden] { display: none; }
body.world .homele-badge {
  position: absolute;
  top: 12px;
  right: 12px;
  left: auto;
  z-index: 3;
  pointer-events: none;
  background: #e11d48;
  color: #fff;
  border-radius: 999px;
  padding: 4px 10px;
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
  font-size: 11px;
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: 0;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.22);
}
body.world .homele-badge.is-rent { background: #e11d48; }
body.world .homele-badge.is-sale { background: #e11d48; }
body.world .homele-photo-btn {
  position: absolute;
  top: 50%;
  z-index: 3;
  transform: translateY(-50%);
  width: 36px;
  height: 36px;
  min-width: 36px;
  min-height: 36px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: rgba(255, 255, 255, 0.94);
  color: #1c1917;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.28);
  cursor: pointer;
  pointer-events: auto;
}
body.world .homele-photo-btn--prev { left: 8px; right: auto; }
body.world .homele-photo-btn--next { right: 8px; left: auto; }
body.world .homele-photo-btn svg,
body.world .homele-photo-btn path { pointer-events: none !important; display: block; }
html[dir="rtl"] body.world .homele-photo-btn svg { transform: none; }
body.world .homele-photo-btn:hover { background: #fff; }
body.world .homele-photo-btn:focus-visible {
  outline: 2px solid var(--w-gold);
  outline-offset: 2px;
}
body.world .homele-dots {
  position: absolute;
  left: 44px;
  right: 44px;
  bottom: 10px;
  z-index: 3;
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 2px;
  pointer-events: none;
}
body.world .homele-dot {
  pointer-events: auto;
  width: 14px;
  height: 14px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
body.world .homele-dot::after {
  content: '';
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.55);
}
body.world .homele-dot.is-active::after { background: #fff; width: 6px; height: 6px; }
body.world .homele-copy {
  display: flex;
  flex-direction: column;
  gap: 6px;
  flex: 1 1 auto;
  min-width: 0;
  padding: 12px 14px 14px;
  text-decoration: none;
  color: inherit;
}
body.world .homele-copy:focus-visible {
  outline: 2px solid var(--w-gold);
  outline-offset: -2px;
}
body.world .homele-line {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
  min-width: 0;
}
body.world .homele-title {
  margin: 0;
  min-width: 0;
  flex: 1 1 auto;
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
  font-size: 14.5px;
  font-weight: 650;
  line-height: 1.35;
  color: #F4F1EA;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
body.world .homele-pricebox { flex: none; text-align: end; }
body.world .homele-price,
body.world .homele-period,
body.world .homele-loc {
  margin: 0;
}
body.world .homele-price {
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
  font-size: 15.5px;
  font-weight: 700;
  line-height: 1.3;
  color: #F4F1EA;
  white-space: nowrap;
}
body.world .homele-period {
  font-size: 11px;
  line-height: 1.3;
  color: #A8A29A;
}
body.world .homele-loc {
  display: flex;
  align-items: center;
  gap: 5px;
  min-height: 1.25em;
  min-width: 0;
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
  font-size: 12.5px;
  line-height: 1.35;
  color: #A8A29A;
}
body.world .homele-loc-ico {
  flex: none;
  display: inline-flex;
  opacity: 0.85;
}
body.world .homele-loc-text {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
body.world .homele-specs {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 18px;
  margin-top: auto;
  padding-top: 4px;
  color: #C8C2B8;
}
body.world .homele-spec {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
  font-size: 12.5px;
  line-height: 1;
  white-space: nowrap;
}
body.world .homele-spec svg { flex: none; opacity: 0.85; }

html[data-dg-theme="light"] body.world .homele-card {
  background: #fff;
  border-color: rgba(47, 42, 38, 0.1);
  box-shadow: 0 14px 32px -20px rgba(47, 42, 38, 0.28);
  color: #1C1814;
}
html[data-dg-theme="light"] body.world .homele-media { background: #F3EEE6; }
html[data-dg-theme="light"] body.world .homele-title,
html[data-dg-theme="light"] body.world .homele-price { color: #1C1814; }
html[data-dg-theme="light"] body.world .homele-loc,
html[data-dg-theme="light"] body.world .homele-period,
html[data-dg-theme="light"] body.world .homele-specs { color: #6E6258; }
html[data-dg-theme="light"] body.world .homele-fallback {
  color: #6E6258;
  background: #F6F1E8;
}
html[data-dg-theme="light"] body.world .homele-badge {
  background: #e11d48;
  color: #fff;
}
