/* ==========================================================================
   TARAQI — project-b162.html (step 5B). Five page-specific pieces: the cover hero,
   the facilities list, the expanded unit mix, the payment sequence and the
   solo layout of the shared elevation sheet. The hero is the home page's hero mechanics (css/home.css) applied
   to a still; the head type inside it re-uses about.css's .about-title /
   .about-intro, and the rest of the page keeps the shared .about-grid rhythm.
   As of step 18 this page no longer uses .about-head — about.html still does. The section label, sand
   veil, contact band and button come from sections.css; the drawing itself from elevation.css + the shared
   include. Cream dominant below the hero — the first screen is the photograph,
   which is the step-18 decision, not a slip — one sand veil (facilities — the payment sequence
   it was written for came out at step 14, and .section-pay below is orphaned
   markup-side until a page reads it again), one burgundy band (contact). Every color is a token; logical properties only. The CSS state
   is the finished page — js/motion.js sets reveal from-states only when it
   will animate them.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Page rhythm — the stacked-layout gaps under the labels (below md) collapse
   inside the .about-grid at md+, same rule about.css applies to its bodies.
   -------------------------------------------------------------------------- */
@media (min-width: 768px) {
  .about-grid-body.amen-body,
  .about-grid-body.mix-body,
  .about-grid-body.pay-wrap { margin-block-start: 0; }
}

/* --------------------------------------------------------------------------
   0. Cover hero (step 18) — the B162 still, full viewport, with the page head
   over it. It replaces the contained .media-cover-page figure + .about-head
   pair this page opened on; about.html still uses that pair (sections.css §6),
   which is why neither of those rules moved.

   Every mechanic here is the home page's hero, not a parallel one:

     height   margin-block-start: var(--nav-h) + min-block-size 100dvh minus
              the bar, with a 100vh line first as the fallback for engines
              without dvh. The nav is position:fixed and transparent at the
              top of the page, so the margin is what keeps the picture out
              from under it — the bar sits on cream, exactly as on the home
              page. dvh is what makes the mobile URL bar a non-event: 100vh
              is the LARGE viewport, so on a phone it is taller than what is
              actually visible and the bottom of the hero sits under the
              browser chrome until the bar collapses. dvh tracks the visible
              viewport instead, so the hero is exactly one screen at both
              chrome states. It does resize as the bar collapses — that is
              the unit doing its job — and because the copy is centred it
              settles a few pixels rather than snapping a cut-off edge into
              view. Same trade the home page already took.

     overlay  the same three layers as .hero-media: the picture, a flat cream
              veil at 0.30, then a masked cream wash at 0.60 that holds full
              strength across the copy column and opens toward the far edge
              (below md it turns 90° and opens above and below the copy band).
              Same token, same opacities, same alpha-channel-not-a-colour
              trick. The mask STOPS are re-derived rather than copied — see
              the note on them below; the home page's numbers came off the
              Arabic brand tagline, which does not appear on this page.
              NOT a dark or burgundy gradient: this site's legibility layer is
              cream — it is what keeps brand rule 1 true over a photograph,
              and it is why the type here stays burgundy and ink rather than
              flipping to reversed-out cream.

     copy     vertically centred, inline-start aligned, inside .max-w-shell.

   Not guessed, and not eyeballed against a placeholder. Measured against the
   delivered still the same pessimistic way tools/hero-veil-contrast.py
   measures the home page — the DARKEST composited pixel inside each element's
   own box, not an average — by its sibling
   tools/project-hero-veil-contrast.py. The frame is a bright dusk grade, but
   it still carries true black (0,0,0) in the pergola slats, so the worst case
   is a black pixel behind the type and these numbers are a floor:

     status eyebrow (burgundy-dark)   5.37:1
     title          (burgundy-dark)   5.38:1
     intro copy     (ink)             6.93:1

   against a 4.5:1 floor, in both languages at 1440 and 375 — the same figures
   the home page reports, because it is the same veil over the same worst case.

   ---- the measured sweep, and what it moved (2026-09-09) ----

   The opacities are flat 0.20 + wash 0.65, and were 0.30 + 0.60. Behind the
   copy the two are the SAME strength — 1-(1-f)(1-w) is 72% either way, and
   every one of the twelve figures above is unchanged to the second decimal —
   but at the OPEN edge, where the facade is and where there is no type, this
   hero is now veiled 20% instead of 30%. A third less cream over the subject
   of the photograph at zero legibility cost. The move is only safe because
   `--census` shows every text box sitting at mask 1.0, i.e. inside the hold:
   where the mask is already full, the flat veil and the wash trade off
   exactly, so lowering one and raising the other is invisible to the type.

   It cannot go lighter than that. `--sweep` prints the whole AA frontier:
   the lightest composite that still clears 4.5:1 is 66.0% (flat 0.15 + wash
   0.60) at 4.53:1 — a 0.03 margin, no room for a re-crop or a copy edit —
   and 65.0% fails outright at 4.40:1. That floor is set by cream-over-black,
   because this frame bottoms out at true black inside the copy: only 0.071%
   of the whole frame is (0,0,0), and three of the twelve boxes contain no
   black pixel at all, but every box still reaches a minimum luminance of
   0.0003 or less, which composites the same as black to two decimals.

   The same sweep was run independently on the other two heroes and they do
   NOT share an open-edge answer, only the floor. about.html's daylight still
   took the identical 0.20 + 0.65 (css/about.css §0). The home page's footage
   did NOT: it is contrast-pinned like these two, but its loop contains a
   night terrace passage around t=20s whose open edge would fall from mean
   luminance 0.170 to 0.123 (bottom quartile 0.098 to 0.055), against 0.350
   to 0.306 for this still — so it keeps 0.30 + 0.60 on brand-rule grounds,
   not contrast ones. See the "Hero footage" block in css/home.css.
   The boxes it samples are the PAINTED text, not the layout box: .about-title
   is a 768px block holding 126px of ink, and sampling the empty remainder
   would have failed the check over a region with no glyphs in it.
   Re-run that tool if either opacity, either mask, the object-position or a
   type colour below changes, and paste the new figures here.

   The cream ratio on THIS page drops below the usual ≈60% for the first
   screen. That is the decision this step makes, not a regression: the page
   opens on the building, and cream returns as the field from the facilities
   list down. Rule 1 still holds on the page as a whole.
   -------------------------------------------------------------------------- */
.project-hero {
  background-color: var(--taraqi-cream);
  margin-block-start: var(--nav-h);
  min-block-size: calc(100vh - var(--nav-h));   /* fallback: no dvh support */
  min-block-size: calc(100dvh - var(--nav-h));  /* visible viewport, not the large one */
}

.project-hero-media {
  position: absolute;
  inset: 0;
  z-index: 0;               /* under .project-hero-content (z-index 1) */
  overflow: hidden;
}
.project-hero-media img,
.project-hero-video {
  display: block;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  object-position: 50% 55%;
}
@media (prefers-reduced-motion: reduce) {
  .project-hero-video { display: none; }
}
/* The poster is this layer's background at all times, not only under reduced
   motion: WebP where the browser takes it, the JPG otherwise. The video
   carries no `poster` attribute, so this is what shows before its first
   frame, whenever autoplay is refused, and under reduced motion — where
   the sources do not match at all and the file is never requested. It sits
   at the video's own object-position, so the hand-over does not jump.
   Villa 13's (step 3b-2) is the loop's first frame; B162 took the pattern at
   step 6 with the poster it already had. */
.project-hero-media--b162 {
  background-image: url("../assets/images/hero-b162-poster.jpg");
  background-image: image-set(
    url("../assets/images/hero-b162-poster.webp") type("image/webp"),
    url("../assets/images/hero-b162-poster.jpg") type("image/jpeg"));
  background-size: cover;
  background-position: 50% 55%;
}
.project-hero-media--villa13 {
  background-image: url("../assets/images/hero-villa13-poster.jpg");
  background-image: image-set(
    url("../assets/images/hero-villa13-poster.webp") type("image/webp"),
    url("../assets/images/hero-villa13-poster.jpg") type("image/jpeg"));
  background-size: cover;
  background-position: 50% 55%;
}
/* Flat veil, then the directional wash — .hero-media's two pseudo-elements.
   0.20 + 0.65 composites to the same 72% behind the copy as the 0.30 + 0.60
   this shipped with, and leaves the open edge a third clearer. See the sweep
   note above before changing either number. */
.project-hero-media::before,
.project-hero-media::after {
  content: "";
  position: absolute;
  inset: 0;
  background-color: var(--taraqi-cream);
  pointer-events: none;
}
.project-hero-media::before { opacity: 0.20; }
/* Directional wash — full strength across the copy column, then opening so
   the building is genuinely legible past it. The stops are DERIVED, the way
   css/home.css derives its own: measure the widest painted line and hold the
   wash that far before letting it fall away. Here that line is the intro
   paragraph — 46.5% of the hero from the copy edge in English, 44.6% in
   Arabic (Range.getBoundingClientRect on the text, not the block's layout
   box) — so the hold is 48% and the ramp is the same 20 points wide the home
   page uses. It is NOT the home page's 62%: that number was measured off the
   Arabic brand tagline, which is the widest line on the site and is not on
   this page. Copying it would have washed the facade — the subject of the
   photograph — for copy that is not there. */
.project-hero-media::after {
  opacity: 0.65;
  -webkit-mask-image: linear-gradient(to right, #000 0%, #000 48%, transparent 68%);
          mask-image: linear-gradient(to right, #000 0%, #000 48%, transparent 68%);
}
[dir="rtl"] .project-hero-media::after {
  -webkit-mask-image: linear-gradient(to left, #000 0%, #000 48%, transparent 68%);
          mask-image: linear-gradient(to left, #000 0%, #000 48%, transparent 68%);
}
/* Below md the copy spans the full width, so there is no far edge to open up
   along the inline axis — the wash turns 90°. Derived the same way: the copy
   band runs 33%–73% of the hero's height in English and 38%–68% in Arabic, so
   it holds 28%–78% and opens above and below, where the crown of the building
   and the forecourt sit.
   The [dir="rtl"] rule above is a class heavier than the bare selector and a
   media query adds no specificity of its own, so this has to repeat it — the
   same trap css/home.css documents, and the same fix. */
@media (max-width: 767px) {
  .project-hero-media::after,
  [dir="rtl"] .project-hero-media::after {
    -webkit-mask-image: linear-gradient(to bottom, rgb(0 0 0 / 0.40) 0%, #000 28%, #000 78%, rgb(0 0 0 / 0.45) 100%);
            mask-image: linear-gradient(to bottom, rgb(0 0 0 / 0.40) 0%, #000 28%, #000 78%, rgb(0 0 0 / 0.45) 100%);
  }
}

.project-hero-content { position: relative; z-index: 1; }
/* The head's own top margin is what the .about-head padding used to supply;
   inside a centred flex hero the block is centred instead, so the h1 keeps
   only the gap to the eyebrow above it. */
.project-hero-content .about-title { margin-block-start: 1.5rem; }
.project-hero-content .about-intro { max-inline-size: 52ch; }
/* The project's address (client-supplied: B162 2026-10-07, Villa 13
   2026-10-08): one line under the hero title on both project pages, and
   again at the head of the location section. Burgundy
   dark for the same reason as the eyebrow below. */
.project-address {
  margin: 1rem 0 0;
  max-inline-size: 52ch;
  font-size: 1rem;
  font-weight: 500;
  line-height: 1.8;
  color: var(--taraqi-burgundy-dark);
}
.project-address + .about-intro { margin-block-start: 0.75rem; }
/* The status eyebrow drops from --taraqi-burgundy to --taraqi-burgundy-dark
   here, and only here. It is the one measured failure this hero produced:
   #9B4753 over the veiled still reads 2.77:1 against the 4.5:1 floor, because
   the picture carries true black (0,0,0 — the pergola slats) and cream at 72%
   over black is the darkest this backdrop ever gets. #5C2530 over that same
   worst-case pixel is 5.37:1. Size and weight still separate the eyebrow from
   the h1; on cream, everywhere else on the site, .section-label keeps its
   lighter burgundy. */
.project-hero-content .section-label { color: var(--taraqi-burgundy-dark); }

/* --------------------------------------------------------------------------
   2. Facilities & amenities — six qualitative specification lines from the
   B162 brochure, on the page's one sand veil. Same drafting idiom as the unit
   mix below: a hairline opens each item, no box, no shadow, the same pointer-
   only hover on the rule. The glyph leads the line rather than sitting inside
   it, so it gets its own row above the text at every width — a 1.75rem drawing
   reads as a drawing; the mix's inline 17px glyphs read as punctuation, which
   is what they are.

   The list is the meaning here: every glyph restates the sentence under it,
   so the <ul> carries the content and the icons are aria-hidden. Marker off,
   padding off — the hairline is the only thing that should mark an item.
   -------------------------------------------------------------------------- */
.section-amenities {
  background-color: var(--taraqi-sand-veil);
  /* Phase 4c: the band is opened by .about-rule (css/about.css), so the top
     padding is the About bands' clamp(3rem, 7vh, 4.5rem) and the rule's own
     margin carries the gap to the label — one rhythm for every rule. */
  padding-block: clamp(3rem, 7vh, 4.5rem);   /* phase 4d: bottom trimmed to .about-split's */
}
.amen-body { margin-block-start: 2rem; }
.amen-grid {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  row-gap: 2.5rem;
}
.amen-item {
  border-block-start: 1px solid var(--taraqi-line);
  padding-block-start: 1.25rem;
  transition: border-color var(--dur-micro) var(--ease-rise);
}
.amen-icons {
  display: block;
  color: var(--taraqi-burgundy);
}
.amen-icon {
  display: block;
  inline-size: 1.75rem;
  block-size: 1.75rem;
}
.amen-text {
  margin: 0.875rem 0 0;
  max-inline-size: 34ch;
  font-size: 1rem;
  line-height: 1.8;
  color: var(--taraqi-ink);
}

@media (min-width: 768px) {
  .amen-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    column-gap: 2rem;
  }
  /* Seven lines since the 2026-10-02 data lock: wherever the grid is three
     columns, a lone last item sits in the middle column (3 + 3 + 1, centred)
     instead of orphaned at the start. Keyed on the count, not on the seventh
     item, so it holds if the list changes length again. */
  .amen-item:last-child:nth-child(3n + 1) { grid-column: 2; }
}

@media (hover: hover) and (pointer: fine) {
  .amen-item:hover { border-block-start-color: var(--taraqi-burgundy); }
}

/* --------------------------------------------------------------------------
   2b. Getting there (step 5b) — a location map and the drive times beside it.

   Layout: from md the map takes the inline-start seven columns and the list
   the five beside it, so the pair mirrors with the language; below md the
   map runs full width above the list. Nothing in the section scrolls
   sideways.

   THE MAP (js/location-map.js draws it; the geometry is per-project data).
   A drawing on the page's own cream inside a hairline, in the drafting
   idiom of the plans. Its box is direction: ltr — geography is not mirrored
   for Arabic — while its text keeps the document's direction.
   Two scales live in it. Roads are in map units and scale with the figure;
   their weight is held by --map-k (map units per CSS pixel, written by the
   script), so a main road is 2px and a minor one 1px at every width.
   Everything else sits in a "pin" the script scales by the same factor, so
   the px values below ARE screen pixels: a label is 11–12px on a phone and
   on a desktop alike. No label is ever scaled below 11px; below md the
   .loc-minor ones are simply not shown, so the rest have room.
   NO non-scaling-stroke: the roads are dashed while they draw, and with it
   the browser measures the dash in pixels but the path in map units.

   Colour: main roads ink at 32%, minor roads sand; labels ink (road names
   80%, districts 70% — 5.4:1 on cream at the weakest); landmarks, rings and
   the connector in burgundy. Every label carries a cream halo so it reads
   across a road.
   -------------------------------------------------------------------------- */
.section-nearby {
  padding-block: clamp(2.5rem, 6vh, 4rem) clamp(3.5rem, 8vh, 5.5rem);
}
.nearby-layout {
  display: grid;
  gap: 2.5rem;
  margin-block-start: 2rem;
}
.nearby-map { margin: 0; min-inline-size: 0; }
@media (min-width: 768px) {
  .nearby-layout {
    grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
    gap: clamp(2rem, 4vw, 4rem);
    align-items: start;
  }
}

.loc-map {
  position: relative;
  direction: ltr;
  aspect-ratio: var(--map-ratio, 6 / 5);
  border: 1px solid var(--taraqi-line);
  background-color: var(--taraqi-cream);
  overflow: hidden;
}
.loc-map-svg {
  display: block;
  inline-size: 100%;
  block-size: 100%;
}
html[dir="rtl"] .loc-map-svg { direction: rtl; }

.loc-road {
  fill: none;
  stroke: var(--taraqi-ink);
  stroke-opacity: 0.32;
  stroke-width: calc(2px * var(--map-k, 1));
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: stroke var(--dur-micro) var(--ease-rise), stroke-opacity var(--dur-micro) var(--ease-rise);
}
.loc-road--minor {
  stroke: var(--taraqi-sand);
  stroke-opacity: 1;
  stroke-width: calc(1px * var(--map-k, 1));
}
.loc-road.is-active {
  stroke: var(--taraqi-burgundy);
  stroke-opacity: 1;
  stroke-width: calc(3px * var(--map-k, 1));
}
/* pathLength="1" on every road: one dash is the whole line while it draws
   (js/motion.js line()). Only then — a finished map is never dashed. */
.loc-map.is-drawing .loc-road { stroke-dasharray: 1; }

/* Labels. text-anchor is physical here by way of data-edge — "l": the text
   starts at its point and runs right; "r": it ends there — and each is the
   opposite keyword in a right-to-left line. */
.loc-map text {
  fill: var(--taraqi-ink);
  text-anchor: middle;
  paint-order: stroke;
  stroke: var(--taraqi-cream);
  stroke-width: 3px;
  stroke-linejoin: round;
}
.loc-map text[data-edge="l"] { text-anchor: start; }
.loc-map text[data-edge="r"] { text-anchor: end; }
html[dir="rtl"] .loc-map text[data-edge="l"] { text-anchor: end; }
html[dir="rtl"] .loc-map text[data-edge="r"] { text-anchor: start; }
.loc-label {
  font-size: 12px;
  font-weight: 500;
  transition: fill var(--dur-micro) var(--ease-rise);
}
.loc-road-name {
  font-size: 11px;
  font-weight: 600;
  fill-opacity: 0.8;
  transition: fill var(--dur-micro) var(--ease-rise);
}
/* A road that is a row of the list: its name answers with it. */
.loc-road-label.is-active .loc-road-name {
  font-weight: 700;
  fill: var(--taraqi-burgundy-dark);
  fill-opacity: 1;
}
.loc-district {
  font-size: 11px;
  font-weight: 500;
  fill-opacity: 0.7;
}
html[lang="en"] .loc-district {
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.loc-map .loc-marker-name {
  font-size: 20px;              /* the display face's floor (brand rule 5) */
  fill: var(--taraqi-burgundy-dark);
}

/* Landmarks. */
.loc-landmark { transition: opacity var(--dur-micro) var(--ease-rise); }
.loc-dot {
  fill: var(--taraqi-burgundy);
  stroke: var(--taraqi-cream);
  stroke-width: 1.5px;
  transition: r var(--dur-micro) var(--ease-rise);
}
/* A place beyond the edge of the drawing: an open dot. */
.loc-landmark--edge .loc-dot {
  fill: var(--taraqi-cream);
  stroke: var(--taraqi-burgundy);
}
.loc-map.has-active .loc-landmark:not(.is-active) { opacity: 0.45; }
.loc-landmark.is-active .loc-dot { r: 5.5px; }
.loc-landmark.is-active .loc-label {
  font-weight: 700;
  fill: var(--taraqi-burgundy-dark);
}

/* The connector — from the project's marker to the place a row names. */
.loc-link {
  stroke: var(--taraqi-burgundy);
  stroke-width: calc(1.25px * var(--map-k, 1));
  stroke-dasharray: calc(4px * var(--map-k, 1)) calc(4px * var(--map-k, 1));
  stroke-linecap: butt;
  opacity: 0;
}
.loc-link.is-on { opacity: 1; }

/* The project's marker — the brochures' concentric rings — and the other
   project's smaller, open one. */
.loc-ring {
  fill: none;
  stroke: var(--taraqi-burgundy);
  stroke-width: 1.25px;
}
.loc-marker .loc-ring:last-of-type { fill: var(--taraqi-cream); }
.loc-core { fill: var(--taraqi-burgundy); }
.loc-other .loc-ring { fill: var(--taraqi-cream); }
.loc-pulse {
  fill: none;
  stroke: var(--taraqi-burgundy);
  stroke-width: 1px;
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
}
/* The slow pulse: only once the entrance has finished (.is-live), and never
   under reduced motion. A map with the "find the location" links
   (.has-directions, js/directions.js) runs it in GSAP instead, and there
   hovering or focusing the pin link widens the rings. */
@media (prefers-reduced-motion: no-preference) {
  .loc-map.is-live:not(.has-directions) .loc-pulse { animation: loc-pulse 3.2s var(--ease-rise) infinite; }
}
@keyframes loc-pulse {
  0%   { transform: scale(1);   opacity: 0.55; }
  70%  { transform: scale(2.1); opacity: 0; }
  100% { transform: scale(2.1); opacity: 0; }
}
.loc-marker .loc-ring {
  transform-box: fill-box;
  transform-origin: center;
  transition: transform var(--dur-micro) var(--ease-rise);
}
.loc-map.is-pin-on .loc-marker .loc-ring { transform: scale(1.22); }
.loc-map.is-pin-on .loc-marker .loc-ring:last-of-type { transform: scale(1.35); }

/* The other project's name: a real link, laid over its ring (the drawing is
   role="img"). --at-x / --at-y are its ring's centre as percentages of the
   figure; the box is direction: ltr, so inline-start is the map's west. The
   link covers the ring and is a full 44px tall for a thumb. */
.loc-other-link {
  position: absolute;
  inset-inline-start: var(--at-x, 0);
  inset-block-start: var(--at-y, 0);
  transform: translate(-14px, -50%);
  display: inline-flex;
  align-items: center;
  min-block-size: 2.75rem;
  padding-inline-start: 28px;
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1.4;
  white-space: nowrap;
  color: var(--taraqi-burgundy-dark);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.25em;
}
.loc-other-link--w {
  transform: translate(calc(-100% + 14px), -50%);
  padding-inline: 0 28px;
}
.loc-other-link:hover { color: var(--taraqi-burgundy); }

@media (max-width: 767px) {
  .loc-minor { display: none; }
}

/* --------------------------------------------------------------------------
   2b′. Find the location (js/directions.js) — the map and the drive-times
   column link out to Google Maps. Every link here opens a new tab.

   OVER THE MAP, all real links laid on the drawing (it is role="img"):
   the frame link fills it and opens the place; the pin link is a 48px
   target on the project's marker (--marker-x / --marker-y, written by
   js/location-map.js) and opens directions, with a cream card above it on
   hover and keyboard focus; the pill (touch only) and the cursor badge
   (fine pointer only, never under reduced motion) complete it. The map's
   box is direction: ltr, so a child that must follow the language sets its
   own direction and its logical insets turn with it.
   -------------------------------------------------------------------------- */
.loc-frame-link {
  position: absolute;
  inset: 0;
}
.loc-frame-link:focus-visible { outline-offset: -4px; }

.loc-pin-link {
  position: absolute;
  inset-inline-start: var(--marker-x, 50%);
  inset-block-start: var(--marker-y, 50%);
  inline-size: 3rem;
  block-size: 3rem;
  border-radius: 50%;
  transform: translate(-50%, -50%);
}
.loc-pin-link:focus-visible { outline-offset: 2px; }

.loc-pin-card {
  position: absolute;
  inset-inline-start: 50%;
  inset-block-end: calc(100% + 0.25rem);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.125rem;
  padding: 0.5rem 0.875rem 0.5625rem;
  border: 1px solid var(--taraqi-sand);
  border-radius: 0.375rem;
  background-color: var(--taraqi-cream);
  box-shadow: 0 8px 20px -10px rgba(92, 37, 48, 0.35), 0 1px 3px rgba(92, 37, 48, 0.08);
  white-space: nowrap;
  text-align: center;
  pointer-events: none;
  opacity: 0;
  transform: translate(-50%, 4px);
  transition:
    opacity var(--dur-micro) var(--ease-rise),
    transform var(--dur-micro) var(--ease-rise);
}
html[dir="rtl"] .loc-pin-card > * { direction: rtl; }
.loc-pin-link:hover .loc-pin-card,
.loc-pin-link:focus-visible .loc-pin-card {
  opacity: 1;
  transform: translate(-50%, 0);
}
.loc-pin-card-title {
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1.4;
  color: var(--taraqi-ink);
}
.loc-pin-card-cta {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1.4;
  color: var(--taraqi-burgundy-dark);
}

/* Icons: 1em line-work; the arrows point the way the line reads. */
.loc-icon { display: inline-flex; flex: none; }
.loc-icon svg { inline-size: 1em; block-size: 1em; }
html[dir="rtl"] .loc-icon--arrow,
html[dir="rtl"] .loc-icon--out,
html[dir="rtl"] .loc-icon--nav { transform: scaleX(-1); }

/* Touch: a persistent pill in the bottom corner across from the pin
   (js/directions.js adds .loc-pill--east when the pin is in the west half).
   Its box keeps the map's ltr, so its insets are the map's west and east in
   both languages; in Arabic only its content runs right to left. */
.loc-pill {
  position: absolute;
  inset-block-end: 0.75rem;
  inset-inline-start: 0.75rem;
  display: none;
  align-items: center;
  gap: 0.5rem;
  min-block-size: 2.75rem;
  padding: 0 1rem;
  border-radius: 9999px;
  background-color: var(--taraqi-burgundy-dark);
  color: var(--taraqi-cream);
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.25;
  box-shadow: 0 8px 18px -10px rgba(92, 37, 48, 0.55);
}
.loc-pill--east {
  inset-inline-start: auto;
  inset-inline-end: 0.75rem;
}
html[dir="rtl"] .loc-pill { flex-direction: row-reverse; }
html[dir="rtl"] .loc-pill > span { direction: rtl; }
.loc-pill:active { background-color: var(--taraqi-burgundy); }
@media (hover: none), (pointer: coarse) {
  .loc-pill { display: inline-flex; }
}

/* Fine pointer: the badge that follows the cursor over the frame. */
.loc-badge {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  inline-size: 6.5rem;
  block-size: 6.5rem;
  border-radius: 50%;
  background-color: var(--taraqi-burgundy-dark);
  color: var(--taraqi-cream);
  box-shadow: 0 12px 24px -12px rgba(92, 37, 48, 0.6);
  pointer-events: none;
  opacity: 0;
}
.loc-badge-text {
  display: block;
  max-inline-size: 5.25rem;
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1.3;
  text-align: center;
}
html[dir="rtl"] .loc-badge-text { direction: rtl; }
.loc-badge-text .loc-icon {
  display: inline-block;
  margin-inline-start: 0.25rem;
  vertical-align: -0.125em;
}
@media (hover: none), (pointer: coarse), (prefers-reduced-motion: reduce) {
  .loc-badge { display: none; }
}

/* BESIDE THE MAP, under the drive times: a hairline closes the list, then
   the address with a copy button, a reserved line for its "copied" note (so
   nothing below moves), and the two ways out. */
.loc-find {
  padding-block-start: 1.5rem;
  border-block-start: 1px solid var(--taraqi-line);
}
.loc-address {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
}
.loc-address-text {
  margin: 0;
  font-size: 1rem;
  line-height: 1.7;
  color: var(--taraqi-ink);
}
.loc-copy {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  inline-size: 2.75rem;
  block-size: 2.75rem;
  margin-block-start: -0.375rem;
  padding: 0;
  border: 1px solid var(--taraqi-line);
  border-radius: 50%;
  background: none;
  color: var(--taraqi-burgundy-dark);
  cursor: pointer;
  transition:
    border-color var(--dur-micro) var(--ease-rise),
    color var(--dur-micro) var(--ease-rise);
}
.loc-copy svg { inline-size: 1.125rem; block-size: 1.125rem; }
.loc-copy:hover,
.loc-copy.is-done { border-color: var(--taraqi-burgundy); color: var(--taraqi-burgundy); }
.loc-toast {
  display: block;
  min-block-size: 1.375rem;
  margin-block: 0.25rem 0.75rem;
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1.375rem;
  color: var(--taraqi-burgundy-dark);
  opacity: 0;
  transition: opacity var(--dur-micro) var(--ease-rise);
}
.loc-toast.is-shown { opacity: 1; }
.loc-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem 1.5rem;
}
/* The primary pill: the nav's Register interest button, size for size
   (rounded-full px-5 py-2.5 text-sm font-semibold — css/shell.css .nav-cta). */
.loc-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.625rem 1.25rem;
  border-radius: 9999px;
  background-color: var(--taraqi-burgundy-dark);
  color: var(--taraqi-cream);
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.25rem;
  transition: background-color var(--dur-micro) var(--ease-rise);
}
.loc-btn:hover { background-color: var(--taraqi-burgundy); }
.loc-text-link {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.25rem;
  color: var(--taraqi-burgundy-dark);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.25em;
  transition: color var(--dur-micro) var(--ease-rise);
}
.loc-text-link:hover { color: var(--taraqi-burgundy); }
.loc-copy-scratch {
  position: fixed;
  inset-block-start: 0;
  inset-inline-start: 0;
  opacity: 0;
  pointer-events: none;
}
.loc-find + .nearby-note { margin-block-start: 1.5rem; }

/* Under the map and under the list: one quiet line each. */
.nearby-note {
  margin: 1.25rem 0 0;
  max-inline-size: 46ch;
  font-size: 0.875rem;
  line-height: 1.8;
  color: var(--taraqi-ink);
  opacity: 0.75;
}
.nearby-map .nearby-note { margin-block-start: 0.875rem; }

/* The drive times. Each row is a button — pointing at it, focusing it or
   pressing it marks its landmark on the map (js/location-map.js) — under
   the same hairline .amen-item uses: the two sections are both lists of
   short brochure facts. The place carries the meaning and is set first at
   body weight; the time sits at the row's far end in the display face. */
.nearby-list {
  margin: 0;
  padding: 0;
  list-style: none;
}
.nearby-item {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1.25rem;
  inline-size: 100%;
  margin: 0;
  padding: 1rem 0;
  border: 0;
  border-block-start: 1px solid var(--taraqi-line);
  background: none;
  font: inherit;
  color: inherit;
  text-align: start;
  cursor: pointer;
  transition: border-color var(--dur-micro) var(--ease-rise);
}
.nearby-place {
  font-size: 1rem;
  line-height: 1.6;
  color: var(--taraqi-ink);
  transition: color var(--dur-micro) var(--ease-rise);
}
.nearby-time {
  flex: none;
  font-size: 1.375rem;          /* 22px — above the display face's 20px floor */
  line-height: 1.3;
  white-space: nowrap;
  color: var(--taraqi-burgundy-dark);
}
.nearby-item.is-active { border-block-start-color: var(--taraqi-burgundy); }
.nearby-item.is-active .nearby-place { color: var(--taraqi-burgundy-dark); }
/* A pinned row says so: a burgundy dot leads its place. */
.nearby-item[aria-pressed="true"] .nearby-place::before {
  content: "";
  display: inline-block;
  inline-size: 0.375rem;
  block-size: 0.375rem;
  margin-inline-end: 0.625rem;
  border-radius: 50%;
  background-color: var(--taraqi-burgundy);
  vertical-align: middle;
}
@media (hover: hover) and (pointer: fine) {
  .nearby-item:hover { border-block-start-color: var(--taraqi-burgundy); }
}

/* --------------------------------------------------------------------------
   3. The unit mix — B162's seven confirmed types in three groups, stacked in
   the building's own order: ground level, typical floors, penthouse level.
   Each group carries the shared .section-label eyebrow and its own grid —
   three across for the ground group, two for each pair, one per row below
   md, all on the existing breakpoint. A hairline opens each column: the
   drafting idiom, not a card.

   Hover belongs to pointer devices only. On a touchscreen :hover latches
   after the tap and leaves a card stuck lit, so both states live inside a
   (hover: hover) query. Both are transitions on tokens, so the reduced-motion
   rule in tokens.css flattens them to 0.01ms with nothing declared here.
   -------------------------------------------------------------------------- */
.section-mix {
  background-color: var(--taraqi-cream);
  padding-block: clamp(2rem, 5vh, 3.5rem) clamp(4rem, 9vh, 6rem);
}
.mix-body { margin-block-start: 2rem; }

/* Photo strip — horizontal scroll of unit photographs */
.mix-strip {
  margin-block-end: clamp(2rem, 4vh, 3rem);
}
.mix-strip-track {
  display: flex;
  gap: 1rem;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
  scrollbar-color: var(--taraqi-sand) transparent;
  padding-block-end: 0.5rem;
}
/* Below md the thin sand scrollbar rendered as a stray sand rule under the
   first caption; touch scrolling needs no bar (phase 4b). md+ keeps it. */
@media (max-width: 767px) {
  .mix-strip-track { scrollbar-width: none; }
  .mix-strip-track::-webkit-scrollbar { display: none; }
}
.mix-strip-item {
  flex: 0 0 18rem;
  scroll-snap-align: start;
  margin: 0;
}
.mix-strip-item img {
  display: block;
  inline-size: 100%;
  block-size: 12rem;
  object-fit: cover;
  border-radius: 4px;
}
/* The frame hugs its picture. .media-frame-photo's 4 / 3 is 13.5rem tall at
   this width, which left 1.5rem of the frame's sand veil showing as a band
   under every 12rem picture; the caption is the figcaption, outside it. */
.mix-strip-item .media-frame { aspect-ratio: auto; }
.mix-strip-caption {
  margin-block-start: 0.5rem;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--taraqi-ink);
  opacity: 0.75;
}

/* Unified card grid — 7 cards in a responsive layout */
.mix-grid-unified {
  display: grid;
  row-gap: 2rem;
  margin-block-start: 1.5rem;
}
.mix-unit {
  border-block-start: 1px solid var(--taraqi-line);
  padding-block-start: 1rem;
  transition: border-color var(--dur-micro) var(--ease-rise);
}
.mix-badge {
  display: inline-block;
  margin-block-end: 0.5rem;
  padding: 0.125rem 0.5rem;
  font-size: 0.6875rem;
  line-height: 1.5;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--taraqi-burgundy);
  border: 1px solid var(--taraqi-burgundy);
  border-radius: 2px;
  /* Phase 4b: opacity 0.85 read at 4.08:1 (burgundy at 11px on cream);
     at full strength it is 5.46:1. */
}
html[lang="ar"] .mix-badge { letter-spacing: 0; text-transform: none; }
.mix-type {
  margin: 0;
  font-size: clamp(1.25rem, 2vw, 1.625rem);
  line-height: 1.3;
  color: var(--taraqi-burgundy-dark);
}
html[lang="ar"] .mix-type { line-height: 1.6; }
/* English unit names run long ("Ground Duplex with Private Garden") in a
   four-column grid: a step under display-m, at the serif's 20px floor. */
html[lang="en"] .mix-type { font-size: clamp(1.25rem, 1.4vw, 1.375rem); }
.mix-area {
  margin: 0.375rem 0 0;
  font-size: 1.125rem;
  line-height: 1.5;
  color: var(--taraqi-burgundy-dark);
}
.mix-area .ltr-num {
  transform-origin: 0 50%;
  transition: transform var(--dur-micro) var(--ease-rise);
}
[dir="rtl"] .mix-area .ltr-num { transform-origin: 100% 50%; }
.mix-status {
  margin: 0.375rem 0 0;
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--taraqi-ink);
  opacity: 0.75;
}
.mix-fit {
  margin: 0.75rem 0 0;
  max-inline-size: 34ch;
  font-size: 0.875rem;
  line-height: 1.8;
  color: var(--taraqi-ink);
}

/* "View plan" button at the bottom of each card */
.mix-view-plan {
  display: inline-block;
  margin-block-start: 0.75rem;
  padding: 0;
  border: none;
  background: none;
  font-family: inherit;
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--taraqi-burgundy);
  cursor: pointer;
  transition: color var(--dur-micro) var(--ease-rise);
  text-decoration: underline;
  text-decoration-color: transparent;
  text-underline-offset: 0.2em;
}
.mix-view-plan:hover,
.mix-view-plan:focus-visible {
  color: var(--taraqi-burgundy-dark);
  text-decoration-color: currentColor;
}
.mix-view-plan[aria-expanded="true"] { color: var(--taraqi-burgundy-dark); }
.mix-unit.is-active { border-block-start-color: var(--taraqi-burgundy); }

.mix-icons {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  margin-inline-end: 0.5rem;
  vertical-align: -0.3em;
  color: var(--taraqi-burgundy);
}
.mix-icon {
  display: block;
  inline-size: 1.0625rem;
  block-size: 1.0625rem;
}
.mix-icon path,
.amen-icon path {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5px;
  stroke-linecap: butt;
  stroke-linejoin: miter;
  vector-effect: non-scaling-stroke;
}
[dir="rtl"] .mix-icon-bed { transform: scaleX(-1); }

@media (min-width: 480px) {
  .mix-grid-unified {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: 1.5rem;
  }
}

@media (min-width: 768px) {
  .mix-grid-unified {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    column-gap: 2rem;
  }
}

@media (min-width: 1024px) {
  .mix-grid-unified {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

@media (hover: hover) and (pointer: fine) {
  .mix-unit:hover { border-block-start-color: var(--taraqi-burgundy); }
  .mix-unit:hover .mix-area .ltr-num { transform: scale(1.05); }
}

/* --------------------------------------------------------------------------
   4. Payment — the four terms as a short sequence on the sand veil, read in
   order: down payment → term → cadence → delivery. Figures in the display
   face over quiet labels; a drawn hairline arrow carries the eye from one to
   the next (horizontal md+, vertical below). Under it, one plain line on
   what the contract states. No table, no calculator.
   -------------------------------------------------------------------------- */
.section-pay {
  background-color: var(--taraqi-sand-veil);
  padding-block: clamp(3rem, 7vh, 4.5rem) clamp(4rem, 9vh, 6rem);
}
.pay-wrap { margin-block-start: 2rem; }
.pay-seq {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2.75rem;
}
.pay-step {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}
.pay-value {
  font-size: clamp(1.5rem, 1.9vw, 1.75rem);  /* overrides .display's clamp; serif floor 20px holds */
  line-height: 1.3;
  white-space: nowrap;                       /* one line per step — the sequence reads across */
  color: var(--taraqi-burgundy-dark);
}
html[lang="ar"] .pay-value { line-height: 1.6; }
.pay-key {
  font-size: 0.875rem;
  font-weight: 500;
  line-height: 1.5;
  color: var(--taraqi-burgundy-dark);
}

/* The arrow between steps — a hairline with a chevron head, drawn with
   borders so it needs no glyph and no image. Logical properties place it
   after each step in the writing direction; the chevron's rotation flips
   under RTL so it always points onward. Stacked (below md): downward. */
.pay-step:not(:last-child)::after {
  content: "";
  position: absolute;
  inset-block-end: -2.05rem;
  inset-inline-start: 2px;
  inline-size: 1px;
  block-size: 1.375rem;
  background-color: var(--taraqi-burgundy);
}
.pay-step:not(:last-child)::before {
  content: "";
  position: absolute;
  inset-block-end: -2.1rem;
  inset-inline-start: -1px;
  inline-size: 7px;
  block-size: 7px;
  border-block-end: 1px solid var(--taraqi-burgundy);
  border-inline-end: 1px solid var(--taraqi-burgundy);
  transform: rotate(45deg);
}
[dir="rtl"] .pay-step:not(:last-child)::before { transform: rotate(-45deg); }

@media (min-width: 768px) {
  .pay-seq {
    flex-direction: row;
    align-items: flex-start;
    gap: 3.25rem;
  }
  .pay-step { flex-shrink: 0; }
  .pay-step:not(:last-child)::after {
    inset-block-end: auto;
    inset-inline-start: auto;
    inset-inline-end: -2.6rem;
    inset-block-start: 1.1rem;
    inline-size: 1.75rem;
    block-size: 1px;
  }
  .pay-step:not(:last-child)::before {
    inset-block-end: auto;
    inset-inline-start: auto;
    inset-inline-end: -2.65rem;
    inset-block-start: calc(1.1rem - 3px);
    border-block-end: 0;
    border-block-start: 1px solid var(--taraqi-burgundy);
  }
}

.pay-note {
  margin-block-start: 2.5rem;
  padding-block-start: 1.25rem;
  border-block-start: 1px solid var(--taraqi-line);
  max-inline-size: 60ch;
  font-size: 1.0625rem;
  line-height: 1.9;
  color: var(--taraqi-ink);
}

/* --------------------------------------------------------------------------
   5. «لوحة الرسم» / The Drawing Board (step 8; rebuilt step 11) — the pinned
   sheet, the title block beside it, and the three schematic unit diagrams
   beneath it.

   THE CSS STATE IS THE FINISHED SCENE: the elevation drawn at full weight,
   the camera at rest, all three diagrams complete and named. js/board.js
   sets its from-states only past the reduced-motion guard, so reduced motion
   and no-GSAP both render this — a whole drafting sheet, not a degraded one.
   -------------------------------------------------------------------------- */
.board {
  position: relative;
  display: flex;
  align-items: center;
  background-color: var(--taraqi-cream);
  min-block-size: 100vh;
  min-block-size: 100dvh;
  padding-block-start: var(--nav-h);
  /* 1rem, plus the sticky register bar on phones (0 from md up) — js/board.js
     fits the sheet inside this padding, so the note never sits under it. */
  padding-block-end: calc(1rem + var(--cta-bar-h, 0px));
  overflow: hidden;
}

/* Phones: when js/board.js has to scale the block to fit, it fills the
   padding box exactly and the label lands flush under the header. A rem of
   air above it, inside the padding the fit already measures. */
@media (max-width: 767px) {
  .board { padding-block-start: calc(var(--nav-h) + 1rem); }
}

.board-inner { display: grid; row-gap: 1.5rem; align-items: center; }
@media (min-width: 768px) {
  .board-inner { grid-template-columns: 14rem minmax(0, 1fr); column-gap: 3.5rem; }
}

.board-heading {
  margin: 0;
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1.4;
  color: var(--taraqi-burgundy);
}
html[lang="en"] .board-heading {
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

/* The title block — what the sheet is a drawing of. One building now, so it
   simply states it; nothing swaps during the scrub. */
.board-specs { margin-block-start: 1.75rem; }
.board-spec-name {
  margin: 0;
  font-size: clamp(1.375rem, 2.2vw, 1.875rem);  /* overrides .display's clamp; serif floor 20px holds */
  color: var(--taraqi-burgundy-dark);
}
html[lang="ar"] .board-spec-name { line-height: 1.6; }   /* Aref Ruqaa carries harakat */
.board-spec-line {
  margin: 0.4rem 0 0;
  font-size: 1rem;
  line-height: 1.6;
  color: var(--taraqi-ink);
}

/* The stage — the sheet, then the diagrams, then the line that says what the
   diagrams are. One column: they are read in that order at every width. */
.board-stage { display: flex; flex-direction: column; min-inline-size: 0; }
.board-sheet { inline-size: 100%; }
/* Phase 2 zooms inside the viewBox — the sheet must clip the spill
   (elevation.css leaves .elevation-svg overflow visible; this loads later
   and wins the tie). */
.board-svg { overflow: hidden; }
/* The sheet is width-driven (a 1.711:1 drawing at 100% of its column), which
   at a 1440x900 desktop makes it 556px tall — and the stage still owes room
   to the three diagrams and their note inside one pinned viewport. Cap its
   height against the viewport instead of the column: the drawing keeps its
   aspect and letterboxes within the box, so it simply draws smaller on a
   short screen rather than pushing the diagrams out of the pin. The 27rem is
   the rest of the stage — navbar, diagram row, note and padding. */
.board-svg {
  max-block-size: calc(100vh - 27rem);
  max-block-size: calc(100dvh - 27rem);
}

/* --------------------------------------------------------------------------
   The three schematic diagrams. A rule, not a box — the drafting idiom.
   Equal columns, so no diagram is drawn
   larger than another: they carry typology, never area (js/board-b162.js).
   -------------------------------------------------------------------------- */
.board-plans {
  list-style: none;
  margin: 1.75rem 0 0;
  padding: 1.25rem 0 0;
  border-block-start: 1px solid var(--taraqi-line);
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1.5rem;
}
.board-plan { min-inline-size: 0; }
/* Villa 13's board draws four (.board--four): four equal columns from md. */
@media (min-width: 768px) {
  .board--four .board-plans { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
.board-plan-figure { inline-size: 100%; max-inline-size: 11rem; }
.plan-svg { display: block; inline-size: 100%; block-size: auto; overflow: visible; }
.board-plan-name {
  margin: 0.75rem 0 0;
  font-size: clamp(1.25rem, 1.5vw, 1.5rem);  /* overrides .display's clamp; serif floor 20px holds */
  color: var(--taraqi-burgundy-dark);
}
html[lang="ar"] .board-plan-name { line-height: 1.6; }
.board-plan-area {
  margin: 0.2rem 0 0;
  font-size: 0.9375rem;
  line-height: 1.6;
  color: var(--taraqi-ink);
}

/* Says out loud what the register says on paper: these are not plans. It
   stays until real plans replace the diagrams. */
.board-plans-note {
  margin: 1.25rem 0 0;
  font-size: 0.8125rem;
  line-height: 1.6;
  color: var(--taraqi-ink);
  opacity: 0.72;
}

/* Below md the two-column grid collapses: the heading and the title block
   read first, then the stage. Nothing re-lays out during the scrub — the
   diagrams keep their three columns and only tighten. */
@media (max-width: 767px) {
  .board-col { display: contents; }
  .board-heading { order: 0; }
  .board-specs { order: 1; margin-block-start: 0.75rem; }
  .board-stage { order: 2; }
  .board-spec-line { font-size: 0.9375rem; }
  /* Three across does not survive here: at ~100px a column, "Single-floor
     apartment" wraps to three lines while "Duplex apartment" takes two, and
     the area figures stop lining up. the serif's 20px floor means the type
     cannot shrink to fit, so the row turns instead — one diagram per line,
     drawing beside its name, which also gives the names room to read. */
  /* Phase 4b: the pinned board ran 826px tall in an 812px viewport in
     English. The stage's own gaps are trimmed here — row gap, diagram
     spacing, note margin — so the note clears the viewport's bottom edge by
     the section's 1rem padding or more. */
  .board-inner { row-gap: 1rem; }
  .board-plans {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.75rem;
    margin-block-start: 1rem;
    padding-block-start: 0.75rem;
  }
  .board-plan {
    display: grid;
    grid-template-columns: 6rem minmax(0, 1fr);
    grid-template-rows: auto auto;
    column-gap: 1rem;
    align-items: center;
  }
  .board-plan-figure {
    grid-column: 1;
    grid-row: 1 / -1;
    max-inline-size: none;
    align-self: center;
  }
  .board-plan-name {
    grid-column: 2;
    grid-row: 1;
    align-self: end;
    margin: 0;
    font-size: 1.25rem;   /* 20px — the serif floor, exactly */
  }
  .board-plan-area {
    grid-column: 2;
    grid-row: 2;
    align-self: start;
    font-size: 0.8125rem;
  }
  /* Four rows, not three (Villa 13): a smaller figure column keeps the
     pinned board inside an 812px viewport, the note clear of its foot. */
  .board--four .board-plan { grid-template-columns: 5rem minmax(0, 1fr); }
  .board--four .board-plans { gap: 0.5rem; }
  .board-plans-note {
    margin-block-start: 0.75rem;
    font-size: 0.75rem;
  }
}

/* Reduced motion (and print-like contexts): not pinned — a normal section
   showing the finished sheet and all three diagrams, free to be as tall as
   it needs. Deliberate, not degraded. */
@media (prefers-reduced-motion: reduce) {
  .board {
    min-block-size: 0;
    padding-block: calc(var(--nav-h) + 2.5rem) 4rem;  /* clear of the fixed navbar */
  }
  .board-inner { grid-template-columns: none; }
  .board-col { display: contents; }
  .board-heading { order: 0; }
  .board-specs { order: 1; margin-block-start: 1rem; }
  .board-stage { order: 2; }
}

/* --------------------------------------------------------------------------
   Photos moved to .mix-strip (horizontal scroll strip above the card grid).
   The old .mix-photo / .mix-photo-duo / .mix-photo-pair rules are removed.
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   The entrance lobby, under the facilities & amenities list (step 18). Not a
   manifest slot and not a unit: it is the building's shared entrance, so it
   takes no caption — .media-caption stays the one place a photograph names
   the unit it belongs to. Capped the same way the unit photographs are, for
   the same reason: the six specification lines above it are the section.
   -------------------------------------------------------------------------- */
.amen-photo {
  margin-block-start: 2.5rem;
  max-inline-size: 36rem;
}
/* Phase 4c: the figure is the homepage's framed figure (.about-teaser-figure,
   css/sections.css), which brings the 14px outline offset on the block end
   and inline end; the UA's figure inline margins are reset here, as About
   resets them on its splits. The frame keeps this photograph's own 4:3 —
   the delivered lobby frame is landscape and would lose its glazed wall to
   the portrait 4:5. */
figure.amen-photo { margin-inline-start: 0; }
.amen-photo .about-teaser-media { aspect-ratio: 4 / 3; }
@media (max-width: 767px) {
  .amen-photo { margin-block-start: 2rem; max-inline-size: none; }
}
/* Phase 4d: from md up the picture leaves the list column for the label's.
   The label column widens from 10 / 13 to 9 / 13 (four columns, ~400px in
   the 1280px shell) for this section only; the label keeps its end
   alignment on row 1 and the figure takes row 2 beneath it, the list
   spanning both rows on the other side. The 14px outline offset falls
   toward the inline end, into the shell gutter — mirrored in RTL by
   css/sections.css. */
@media (min-width: 768px) {
  .section-amenities .about-grid-label { grid-column: 9 / 13; grid-row: 1; }
  .section-amenities .amen-body { grid-row: 1 / span 2; }
  .amen-photo {
    grid-column: 9 / 13;
    grid-row: 2;
    align-self: start;
    justify-self: stretch;
    margin-block-start: 1.75rem;
    max-inline-size: none;
  }
}

/* --------------------------------------------------------------------------
   «المساقط» / Plans — one client floor plan per unit type, with the
   brochure's own room dimensions beside it. Un-numbered on purpose: this
   sheet's §0–§6 are the page's original sections and two live comments
   (project-b162.html and js/board.js) already point at those numbers, so a new
   block joins the step-added tail below rather than renumbering them.

   The drawings are reproduced, not restyled — client artwork keeps its own
   greys. Cream still carries the page: the plans sit on it with no frame,
   no tint and no sand veil, so a run of seven tall white drawings does not
   turn the section into a gallery wall.

   The height cap is the whole layout problem. These plans are roughly 1:3 —
   given a column's width they would each stand ~800px tall, and seven of
   them would be the page. So the image is capped by HEIGHT and takes
   whatever width that leaves (inline-size: auto against max-block-size),
   which is why the <img> carries no aspect-ratio class: each plan keeps its
   own ratio and is never cropped. A floor plan cropped to a shared box is a
   different building.

   That cap makes the labels inside the drawing unreadable, which is by
   design: the readable, translatable, selectable data is the <dl> beside
   it. The drawing shows the shape; the list states the figures.
   -------------------------------------------------------------------------- */
/* --------------------------------------------------------------------------
   Accordion panels (merged unit mix + plans) — one panel open at a time.
   -------------------------------------------------------------------------- */
.plans-lead {
  margin: 2.5rem 0 0;   /* phase 4b: now sits under the cards, above the panels */
  max-inline-size: 52ch;
  font-size: 1.0625rem;
  line-height: 1.9;
  color: var(--taraqi-ink);
}

.plans-accordion {
  margin-block-start: 1.25rem;
}

.plans-panel {
  border-block-start: 1px solid var(--taraqi-line);
  overflow: hidden;
  /* js/unit-accordion.js scrolls the opened panel to block start; the nav
     is fixed, so without this the panel header sat under it (phase 4b).
     --nav-h is 64px below md and 96px from md up. */
  scroll-margin-block-start: calc(var(--nav-h) + 16px);
}
.plans-panel[hidden] { display: none; }
.plans-panel.is-opening,
.plans-panel.is-closing { display: block; }

.plans-panel-header {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5rem 1.5rem;
  padding-block: 1.25rem 0.75rem;
}
.plans-type {
  margin: 0;
  font-size: clamp(1.5rem, 2.2vw, 1.875rem);
  line-height: 1.3;
  color: var(--taraqi-burgundy-dark);
}
html[lang="ar"] .plans-type { line-height: 1.6; }
.plans-area {
  margin: 0;
  font-size: 1.25rem;
  line-height: 1.5;
  color: var(--taraqi-burgundy-dark);
}
.plans-panel-close {
  margin-inline-start: auto;
  padding: 0.25rem 0.75rem;
  border: 1px solid var(--taraqi-line);
  border-radius: 2px;
  background: none;
  font-family: inherit;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--taraqi-ink);
  cursor: pointer;
  transition: border-color var(--dur-micro) var(--ease-rise),
              color var(--dur-micro) var(--ease-rise);
}
.plans-panel-close:hover,
.plans-panel-close:focus-visible {
  border-color: var(--taraqi-burgundy);
  color: var(--taraqi-burgundy-dark);
}

.plans-panel-body {
  padding-block-end: 2rem;
}

/* Sheet tabs for multi-sheet units (Ground Duplex) */
.plans-sheet-tabs {
  display: flex;
  gap: 0;
  margin-block-end: 1.25rem;
  border-block-end: 1px solid var(--taraqi-line);
}
.plans-tab {
  padding: 0.5rem 1rem;
  border: none;
  border-block-end: 2px solid transparent;
  background: none;
  font-family: inherit;
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--taraqi-ink);
  opacity: 0.65;
  cursor: pointer;
  transition: opacity var(--dur-micro) var(--ease-rise),
              border-color var(--dur-micro) var(--ease-rise);
}
.plans-tab:hover { opacity: 1; }
.plans-tab.is-active {
  opacity: 1;
  color: var(--taraqi-burgundy-dark);
  border-block-end-color: var(--taraqi-burgundy);
}

.plans-sheet {
  margin-block-start: 1.75rem;
  display: grid;
  row-gap: 1.5rem;
}
.plans-sheet[hidden] { display: none; }
.plans-sheet + .plans-sheet { margin-block-start: clamp(2.25rem, 5vh, 3rem); }

.plans-figure { margin: 0; }
.plans-figure .plan-sheet-svg {
  display: block;
  margin-inline: auto;
  inline-size: auto;
  block-size: 60vh;
  max-inline-size: 100%;
}
/* A sheet with a `fit` extent (js/unit-plans-svg.js) keeps the scale it
   had at that extent: its size is the frame it USED to fit — box-w × box-h,
   the same box every other sheet fills — scaled by how much the extent grew.
   The frame changes shape; the rooms and labels inside it do not shrink.
   On phones the box is the figure's own width × 60vh, as above — and the
   sheet never exceeds the column (step 3b-3): a sheet whose held scale would
   make it wider than the figure is drawn at the figure's width instead, its
   height following its own proportions, so nothing scrolls sideways. The
   shared scale is a desktop rule; below md the column wins. */
.plans-sheet-fit .plans-figure {
  container-type: inline-size;
}
.plans-figure .plan-sheet-svg[data-plan-fit] {
  --box-w: 100cqi;
  --box-h: 60vh;
  inline-size: min(100cqi,
                   calc(var(--box-w) * var(--plan-w) / var(--fit-w)),
                   calc(var(--box-h) * var(--plan-w) / var(--fit-h)));
  block-size: min(calc(100cqi * var(--plan-h) / var(--plan-w)),
                  calc(var(--box-w) * var(--plan-h) / var(--fit-w)),
                  calc(var(--box-h) * var(--plan-h) / var(--fit-h)));
  max-inline-size: none;
}

.elevation-svg .el-wall {
  stroke-width: 2.5px;
  stroke-linecap: square;
}
.elevation-svg .el-outdoor {
  fill: var(--taraqi-sand-veil);
  fill-rule: evenodd;
  stroke-width: 1px;
  stroke-dasharray: 5 4;
  opacity: 0.9;
}
.elevation-svg .el-beyond {
  stroke-width: 1px;
  stroke-dasharray: 5 4;
  opacity: 0.45;
}
.plan-label {
  --plan-label-size: 4.6px;
  fill: var(--taraqi-ink);
  stroke: none;
  font-size: calc(var(--plan-label-size) * var(--plan-label-scale, 1));
  font-weight: 500;
  letter-spacing: 0;
}
html[lang="ar"] .plan-label { --plan-label-size: 4.4px; }

.plans-dims { margin: 0; }
.plans-dim {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1.5rem;
  border-block-end: 1px solid var(--taraqi-line);
  padding-block: 0.5rem;
}
.plans-dim dt {
  font-size: 0.9375rem;
  line-height: 1.6;
  color: var(--taraqi-ink);
}
.plans-dim dd {
  margin: 0;
  font-size: 0.9375rem;
  line-height: 1.6;
  white-space: nowrap;
  color: var(--taraqi-burgundy-dark);
}

.plans-note {
  margin: 0.75rem 0 0;
  font-size: 0.8125rem;
  line-height: 1.6;
  color: var(--taraqi-ink);
  opacity: 0.75;
}

.plans-unit-notes {
  margin: 1.25rem 0 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
}
.plans-flag {
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--taraqi-burgundy);
}

.plans-unit-line {
  margin: 2.5rem 0 0;
  max-inline-size: 68ch;
  font-size: 0.8125rem;
  line-height: 1.8;
  color: var(--taraqi-ink);
  opacity: 0.7;
}
/* The finishing standard leads the closing run: full ink, one size up from
   the muted metres line under it (phase 4d). */
.plans-delivery { opacity: 1; font-size: 0.9375rem; }
.plans-delivery + .plans-unit-line { margin-block-start: 0.75rem; }

@media (min-width: 768px) {
  .plans-sheet {
    grid-template-columns: minmax(0, 15rem) minmax(0, 1fr);
    column-gap: clamp(2rem, 4vw, 3.5rem);
    align-items: start;
  }
  .plans-figure .plan-sheet-svg { block-size: 40rem; }
  /* Desktop: the box is the figure column's 15rem × 40rem, and a fit sheet's
     column widens to the sheet instead of letterboxing it (2026-10-02). */
  .plans-sheet-fit { grid-template-columns: max-content minmax(0, 1fr); }
  .plans-sheet-fit .plans-figure { container-type: normal; overflow-x: visible; }
  .plans-figure .plan-sheet-svg[data-plan-fit] {
    --box-w: 15rem;
    --box-h: 40rem;
    inline-size: min(calc(var(--box-w) * var(--plan-w) / var(--fit-w)),
                     calc(var(--box-h) * var(--plan-w) / var(--fit-h)));
    block-size: min(calc(var(--box-w) * var(--plan-h) / var(--fit-w)),
                    calc(var(--box-h) * var(--plan-h) / var(--fit-h)));
  }
  .plans-spec { padding-block-start: 0.25rem; }
}
