/*
Theme Name: Glee North Coast
Theme URI: https://gleenorthcoast.com
Author: Tharaa Developments
Description: A bilingual, editorial landing theme for Glee North Coast by Tharaa Developments, at kilometre 58 on the Alexandria Matrouh road. Arabic is the primary site with full RTL; English runs at /en. The page opens on the widest view of the site and tightens toward the enquiry, and the four level master plan is the fact the whole layout is built to explain. Prices are never published: the enquiry form is the price list. No external requests; fonts and scripts are served locally. Integrates with Rank Math when it is active and stands in for it when it is not.
Version: 1.5.0
Requires at least: 6.0
Tested up to: 6.8
Requires PHP: 7.4
License: GNU General Public License v2 or later
Tags: one-column, custom-logo, rtl-language-support, translation-ready, block-styles
Text Domain: glee-north-coast
*/

/* ============================================================
   1. TOKENS
   Coastal, and light-led. The page is a white ground; sand is a
   band laid across it to separate one room from the next, and a
   deep teal band carries the sections that need weight. The four
   brand colours do not share the page equally: turquoise leads,
   sky answers it, sand holds the quiet, and coral appears once.

   Every pair below was measured against WCAG, not chosen by eye.
   The four brand values are fixed; the variants beside them exist
   only because a colour that works as a ground rarely works as
   text at the same value.
   ============================================================ */
:root{
  /* ---- the four, exactly as specified. Nothing else is a brand colour. */
  --turquoise:#2A9D8F;  /* primary   ~50% */
  --sky:#7DD3FC;        /* secondary ~25% */
  --sand:#F4E4C1;       /* neutral   ~20% */
  --coral:#FF6B6B;      /* micro accent, under 5%: one CTA, a rare badge */

  /* ---- grounds
     White is the page. Sand is a section band, not the page: a cream
     ground under the whole site is the brochure look this identity
     replaces, so sand earns its 20% by alternating, never by default. */
  --paper:#FFFFFF;      /* the page                                   */
  --paper-2:#F7FAFB;    /* a panel raised off the page                */
  --paper-3:#FFFFFF;    /* a card                                     */
  --band:var(--sand);   /* sand, as an alternating section band       */
  --sky-soft:#E4F4FE;   /* sky at panel strength, for quiet fills     */

  /* ---- text
     Neutral, not tinted. A teal-cast ink drags the whole page toward
     one hue and leaves turquoise nothing to be primary against. */
  --ink:#16191B;        /* body text, 17.7:1 on the page, 14.1:1 on sand */
  --ink-2:#0B0E0F;      /* headings                                   */
  --muted:#585F63;      /* secondary text, 6.5:1 page, 5.2:1 sand     */

  /* ---- turquoise, by role
     #2A9D8F is 3.32:1 on white: sound as a ground or a border, short
     of AA as body text. The two variants below are the measured
     answers, so the primary never has to be used at a size that fails. */
  --brand:var(--turquoise); /* grounds, rules, icons, large graphic type */
  --brand-deep:#1E7167; /* turquoise AS TEXT: 5.81:1 page, 4.63:1 sand */
  --brand-ink:#227E72;  /* turquoise AS A GROUND, carrying white 4.89:1 */

  /* ---- the deep band
     Derived from the primary rather than from black, so a dark section
     still reads as the same sea. */
  --deep:#0E3B37;
  --deep-2:#14514B;
  --on-deep:#F2FBFA;       /* text on a band, 11.7:1                  */
  --on-deep-muted:#A8C9C5; /* secondary on a band, 7.0:1              */

  /* ---- coral
     Carries ink, never white: white on coral is 2.78:1 and the primary
     CTA is the one control that cannot fail. Ink on coral is 6.36:1.
     The edge value exists for the single case of a hairline coral
     boundary on white, where flat coral is 2.78:1 and misses 3:1. */
  --coral-ink:#16191B;
  --coral-edge:#FF5959;    /* 3.08:1 on white, boundaries only        */

  --line:rgba(22,25,27,.16);
  --hair:rgba(22,25,27,.09);
  --line-inv:rgba(242,251,250,.22);
  --white:#fff;

  /* One radius for every framed surface on the site. Set here so the whole
     system moves together instead of each block carrying its own number. */
  --cut:14px;
  --cut-sm:10px;
  --cut-pill:999px;

  /* ---- families, served locally as WOFF2, no external request
     Fraunces            English display
     Manrope             English body, UI, and every number in both languages
     Noto Naskh Arabic   Arabic display
     Cairo               Arabic body and UI
     Each stack names the real family first and falls back to what a
     platform already ships, so the page is readable before a font
     file arrives. */
  --serif:"Glee Display",Fraunces,"Hoefler Text","Iowan Old Style",Constantia,Charter,"Palatino Linotype",Palatino,Georgia,serif;
  --sans:"Glee Sans",Manrope,"Avenir Next",Avenir,"Segoe UI Variable Text","Segoe UI",Inter,ui-sans-serif,-apple-system,system-ui,Roboto,"Helvetica Neue",Arial,sans-serif;

  /* Arabic is not an afterthought on a Latin stack: it has its own display and
     its own text face, chosen for Arabic rather than adapted from Latin. */
  --ar-display:"Glee Arabic Display","Noto Naskh Arabic","SF Arabic",Dubai,"Segoe UI",serif;
  --ar-sans:"Glee Arabic",Cairo,"SF Arabic",Dubai,"Noto Sans Arabic","Segoe UI",Tahoma,sans-serif;

  /* Numbers are Manrope in both languages: areas, distances, bedroom counts,
     payment figures and dimensions all read from one face, so a spec table
     lines up whichever language surrounds it. */
  --num:"Glee Sans",Manrope,"Avenir Next",Avenir,"Segoe UI Variable Text","Segoe UI",Inter,ui-sans-serif,system-ui,Arial,sans-serif;

  /* ---- typography scale
     Nine tokens, and nothing outside them. Each range below is the
     token's fluid range: the floor is what a phone gets, the ceiling
     is what a wide desktop gets. A size that is not one of these nine
     does not belong on the page. */
  --fs-display:clamp(3.5rem,6.4vw,4.5rem);   /* 600 */
  --fs-h1:clamp(2.5rem,4.4vw,3rem);          /* 600 */
  --fs-h2:clamp(2rem,3vw,2.25rem);           /* 500 */
  --fs-h3:clamp(1.5rem,2.2vw,1.75rem);       /* 500 */
  --fs-body-lg:1.125rem;                     /* 400 */
  --fs-body:1rem;                            /* 400 */
  --fs-small:.875rem;                        /* 400 */
  --fs-caption:.75rem;                       /* 400 */
  --fs-button:1rem;                          /* 600 */

  --fw-display:600;
  --fw-h1:600;
  --fw-h2:500;
  --fw-h3:500;
  --fw-body:400;
  --fw-button:600;

  /* Line heights are explicit on every token. A line box that depends on
     the font's own metrics moves when the webfont swaps in; an explicit
     one does not, which is where the CLS budget is won. */
  --lh-display:1.04;
  --lh-h:1.12;
  --lh-h-ar:1.35;   /* Naskh needs more room than the Latin face at the same size */
  --lh-tight:1.4;
  --lh-body:1.7;

  --s1:.45rem; --s2:.8rem; --s3:1.25rem; --s4:2rem;
  --s5:clamp(1.4rem,2.2vw,2rem);
  --s6:clamp(1.7rem,2.6vw,2.4rem);
  --s7:clamp(2rem,3.2vw,3rem);
  --s8:clamp(2.4rem,3.8vw,3.6rem);

  --gutter:clamp(1.35rem,5vw,5rem);
  --frame:1640px;
  --caption:38%;          /* the line every card and label hangs from */
  --rule:1px;

  /* ---- motion
     Organic rather than mechanical, which comes down to three things.

     One: every curve is asymmetric. ease-in-out is symmetric, which is
     exactly what makes a page feel machined — the element accelerates and
     decelerates identically, which nothing physical does. Everything here
     leaves fast and arrives slowly, with a long tail where the element
     bleeds off speed the way something with mass does.

     Two: duration follows visual weight. A full-bleed photograph and a
     caption do not arrive together, because they do not weigh the same. The
     mass steps below are the whole scale, and nothing outside them.

     Three: nothing lands dead. An arriving element passes a little beyond
     its resting place and settles back — the "drop and settle" in
     gl-settle below. It is 2 to 3 pixels, which is under conscious notice
     and is the entire difference between weight and a slide. It also reads
     with the page: on a site organised as a descent, things come to rest
     downward. */
  --e-settle:cubic-bezier(.22,1,.36,1);      /* the default arrival     */
  --e-drift:cubic-bezier(.16,1,.3,1);        /* heavy things, long tail */
  --e-lift:cubic-bezier(.34,.82,.32,1);      /* a pointer answer        */
  --e-glide:cubic-bezier(.4,.16,.16,1);      /* travel between states   */

  /* Duration by mass, not by category. */
  --d-xl:1.25s;     /* full bleed photography            */
  --d-l:.95s;       /* panels, cards, figures            */
  --d-m:.78s;       /* headings                          */
  --d-s:.58s;       /* labels, captions, small print     */
  --d-hover:.3s;    /* a card answering a pointer        */
  --d-page:.4s;     /* the page arriving                 */

  /* Retained so existing rules keep resolving while the redesign lands. */
  --ease:cubic-bezier(.22,1,.36,1);
  --ease-out-2:cubic-bezier(.22,1,.36,1);
  --ease-out-3:cubic-bezier(.22,1,.36,1);
  --ease-out-4:cubic-bezier(.16,1,.3,1);
  --ease-expo:cubic-bezier(.16,1,.3,1);
  --d-hero:var(--d-xl);
  --d-reveal:var(--d-l);
  --slow:var(--d-m);
}

/* ============================================================
   2. BASE
   ============================================================ */
*,*::before,*::after{box-sizing:border-box;}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth;}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto;}}
body{
  margin:0;background:var(--paper);color:var(--ink);
  /* iPhone: keep content out of the notch and the home indicator */
  padding-inline:env(safe-area-inset-left) env(safe-area-inset-right);
  font-family:var(--sans);font-size:var(--fs-body);line-height:1.78;
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
  overflow-x:hidden;
}
img,video{max-width:100%;display:block;height:auto;}
a{color:inherit;text-decoration:none;}
h1,h2,h3,h4{margin:0;font-weight:var(--fw-h1);line-height:var(--lh-h);letter-spacing:-.018em;}
p{margin:0;}
ol,ul,dl,dd{margin:0;padding:0;} li{list-style:none;}
button,input,select,textarea{font:inherit;color:inherit;}
:focus-visible{outline:2px solid var(--brand-deep);outline-offset:4px;}
/* The ring has to be visible on whatever it lands on: ink on the sand band,
   sky on the deep band. A single white ring was invisible on both. */
.room--warm :focus-visible{outline-color:var(--ink);}
.room--plan :focus-visible{outline-color:var(--sky);}
.skip{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;}
.skip:focus{width:auto;height:auto;clip:auto;clip-path:none;inset-inline-start:var(--gutter);top:.6rem;z-index:200;background:var(--ink);color:var(--paper);padding:.9rem 1.4rem;}
.fig,.ledger__v,.terms dd b,.reckon dd{
  font-family:var(--num);font-variant-numeric:tabular-nums lining-nums;letter-spacing:0;
}

/* ============================================================
   3. THE CAPTION LINE
   There is no twelve column grid. Everything hangs from one
   line at 38% of the frame, the way a wall card sits beside
   the work rather than under it.
   ============================================================ */
.frame{width:100%;max-width:var(--frame);margin-inline:auto;padding-inline:var(--gutter);}
.room{padding-block:var(--s7);position:relative;}
/* The masthead is 85px and becomes sticky on scroll. Without this, every
   link in the contents lands the reader underneath it. */
section[id]{scroll-margin-top:100px;}
.room--open{padding-block:var(--s8) var(--s7);}
.room--gallery{padding-block:var(--s7) var(--s6);}
/* Sand earns its share here and nowhere else: it is the band that separates
   one room from the next, alternating against the white page rather than
   sitting under the whole site. */
.room--warm{background:var(--band);}
.room--plan{background:var(--deep);color:var(--on-deep);}
.room--plan .prose,.room--plan .lede{color:var(--on-deep-muted);}
.room--plan .room__name{color:var(--on-deep-muted);}
.room--read{background:var(--sky-soft);padding-block:var(--s6) var(--s6);}
/* 244px is the rhythm between rooms. These two were 172 and 280, which is a
   stumble rather than a phrase. */
.room--gallery+.room--read{padding-top:var(--s7);}
.room--open+.room--wide{padding-top:var(--s6);}
/* A room that holds nothing but pictures needs no side margin at all. */
.room--folio{padding-block:var(--s7) var(--s8);}
.room--office{padding-block:var(--s8);}
.room--wide{padding-block:var(--s8) var(--s7);}
.key--wide{min-width:auto;}
.enquiry__say{position:relative;}
.pn-form{position:relative;}

/* ============================================================
   4. TYPOGRAPHY
   Nine tokens and nothing else. Every rule below names one of
   --fs-display / h1 / h2 / h3 / body-lg / body / small / caption
   / button, with the weight the scale assigns it. A rule that
   wants a tenth size wants the wrong size.
   ============================================================ */
h1,h2,h3,h4{font-family:var(--serif);}
[dir="rtl"] h1,[dir="rtl"] h2,[dir="rtl"] h3,[dir="rtl"] h4{font-family:var(--ar-display);}
/* A display line has to be allowed to break. At the token's floor of 3.5rem
   a long Arabic or German word would otherwise push the page sideways. */
.h-display,.h-wall,.h-room,.lede{overflow-wrap:break-word;}

.h-display{
  font-family:var(--serif);font-size:var(--fs-display);font-weight:var(--fw-display);
  line-height:var(--lh-display);letter-spacing:-.022em;text-wrap:balance;max-width:none;
}
.room__name{
  font-family:var(--sans);font-size:var(--fs-caption);font-weight:var(--fw-button);
  letter-spacing:.3em;text-transform:uppercase;color:var(--muted);
  line-height:var(--lh-body);margin-bottom:var(--s4);
}
/* The hero heading carried no size of its own and inherited body copy. It is
   the page's H1 and takes the H1 token. */
.h-arrival{
  font-family:var(--serif);font-size:var(--fs-h1);font-weight:var(--fw-h1);
  line-height:var(--lh-display);letter-spacing:-.02em;text-wrap:balance;
}
.arrival__line{font-size:var(--fs-body-lg);line-height:var(--lh-body);color:var(--ink);}
.h-wall,.h-room{
  font-family:var(--serif);font-size:var(--fs-h2);font-weight:var(--fw-h2);
  line-height:var(--lh-h);letter-spacing:-.018em;max-width:none;text-wrap:pretty;
}
.lede{
  font-family:var(--serif);font-size:var(--fs-h3);font-weight:var(--fw-h3);
  line-height:var(--lh-tight);letter-spacing:-.012em;
  color:var(--ink);margin-top:var(--s4);text-wrap:pretty;
}
/* The paragraph that follows a heading is the one a reader actually reads on
   a phone, so it sits at body-large rather than body. */
.prose,.card__note,.tally__item p,.ledger__d,.faq__a p{
  font-size:var(--fs-body-lg);font-weight:var(--fw-body);line-height:var(--lh-body);color:var(--ink);
}
.prose{max-width:76ch;margin-top:var(--s3);color:var(--muted);text-wrap:pretty;}
.rubric{
  font-size:var(--fs-small);font-weight:var(--fw-button);letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted);margin-top:var(--s5);padding-bottom:var(--s2);line-height:var(--lh-body);
  border-bottom:2px solid var(--brand);
}
.cap{
  margin-top:var(--s2);font-size:var(--fs-caption);letter-spacing:.18em;
  line-height:var(--lh-body);text-transform:uppercase;color:var(--muted);font-weight:var(--fw-button);}
/* The heading is first in the source and the label is painted above it, so a
   crawler and a screen reader both meet the heading before the kicker. */
.wall{max-width:none;display:flex;flex-direction:column;}
.wall .room__name{order:-1;}
@media (min-width:1024px){
  .wall .h-wall,.wall .h-room{max-width:none;margin-bottom:var(--s4);}
  .wall .lede{max-width:64ch;margin-top:0;}
  .wall .prose{max-width:76ch;margin-top:var(--s3);}
}

/* ============================================================
   5. BUTTONS
   ============================================================ */
.btn{
  display:inline-flex;align-items:center;justify-content:center;
  min-height:52px;padding:.9rem 2.1rem;
  background:var(--brand-ink);color:var(--white);border:var(--rule) solid var(--brand-ink);
  font-family:var(--sans);font-size:var(--fs-button);font-weight:var(--fw-button);
  line-height:1.2;letter-spacing:.06em;text-transform:uppercase;
  cursor:pointer;transition:background var(--d-hover) var(--ease-out-2),border-color var(--d-hover) var(--ease-out-2);
}
[dir="rtl"] .btn{font-family:var(--ar-sans);}
.btn:hover{background:var(--brand-deep);border-color:var(--brand-deep);}
/* Turquoise carries every action on the page. Coral carries exactly one —
   the enquiry submit — which is what keeps it under 5% and keeps it
   meaning "this is the thing to press" rather than "this is decorated".
   Ink on coral, never white: white on coral is 2.78:1 and this is the one
   control that is not allowed to fail. */
.ask .btn,
.folio__acts .btn:not(.btn--line),
.arrival__acts .btn:not(.btn--quiet){
  background:var(--brand-ink);color:var(--white);border-color:var(--brand-ink);
}
.ask .btn:hover,
.folio__acts .btn:not(.btn--line):hover,
.arrival__acts .btn:not(.btn--quiet):hover{
  background:var(--brand-deep);border-color:var(--brand-deep);color:var(--white);
}
.btn--send{
  width:100%;margin-top:var(--s5);
  background:var(--coral);color:var(--coral-ink);border-color:var(--coral);
}
.btn--send:hover{background:var(--coral-edge);border-color:var(--coral-edge);color:var(--coral-ink);}
.btn--quiet{background:transparent;color:var(--muted);border-color:var(--line);}
.btn--quiet:hover{background:transparent;border-color:var(--ink);color:var(--ink);}
.btn--line{background:transparent;color:var(--ink);border-color:var(--line);}
.btn--line:hover{background:var(--ink);color:var(--paper);border-color:var(--ink);}
.room--plan .key{border-color:var(--line-inv);color:var(--on-deep);}

.key{
  min-height:44px;min-width:44px;padding:.6rem 1.1rem;background:transparent;
  border:var(--rule) solid currentColor;color:inherit;cursor:pointer;
  font-family:var(--sans);font-size:var(--fs-caption);font-weight:var(--fw-button);
  letter-spacing:.18em;text-transform:uppercase;line-height:1.2;
  transition:background var(--d-hover) var(--ease-out-2);
}
.key:hover{background:rgba(242,251,250,.12);}

/* ============================================================
   7. ARRIVAL
   Type on the ground, the photograph directly beneath it and
   inside the same screen. Nothing sits on top of anything.
   ============================================================ */
.arrival,.hero{
  min-height:94svh;display:grid;grid-template-rows:auto 1fr;
  align-content:start;padding-top:var(--s4);
}
.arrival__type{
  width:100%;max-width:var(--frame);margin-inline:auto;
  padding-inline:var(--gutter);padding-bottom:0;
}
.wordmark{font-family:var(--serif);font-size:var(--fs-display);line-height:.94;letter-spacing:-.035em;}
.wordmark__a{display:block;}
.wordmark__b{
  display:block;font-family:var(--sans);font-size:var(--fs-body-lg);font-weight:var(--fw-button);
  letter-spacing:.4em;text-transform:uppercase;line-height:1;
  margin-top:.75em;padding-top:.8em;border-top:var(--rule) solid var(--line);
  max-width:15em;color:var(--ink);
}
.arrival__line{
  font-family:var(--serif);font-size:var(--fs-body-lg);line-height:1.45;
  max-width:none;margin-top:var(--s3);color:var(--ink-2);
}
.arrival__acts{display:flex;flex-wrap:wrap;gap:var(--s2);margin-top:var(--s4);}
/* A picture pressed against a button reads as a background. The pause is
   what lets it be read as a photograph. */
.arrival__plate{margin:var(--s4) 0 0;align-self:end;overflow:hidden;}
.arrival__plate img{width:100%;height:auto;}
/* The caption sits above the wave in the stack and clear of it in space: the
   wave is drawn over the bottom edge of the picture, so a caption tight to that
   edge reads as if it were cut by it even when nothing overlaps. */
.arrival__plate .cap{
  width:100%;max-width:var(--frame);margin-inline:auto;padding-inline:var(--gutter);
  position:relative;z-index:3;margin-top:var(--s3);
}
@media (min-width:1024px){
  .arrival{grid-template-rows:auto auto;align-content:space-between;}
  /* Capping the height turned a 1.78 picture into a 3.08 letterbox, which is
     not a gentle crop. Hanging the plate from the caption line instead keeps
     the whole frame and still puts it inside the first screen. */
  /* Full width, at its own proportions. The fold cuts it, which is an
     invitation to scroll rather than a crop of the photograph. */
  .arrival__plate{width:100%;}
  /* Capped so the opening picture and the line under it both sit inside the
     first screen. Left at its natural height it filled the viewport on a wide
     display and the caption fell below the fold. */
  .arrival__plate img{width:100%;height:48vh;object-fit:cover;object-position:center;}
}

.broad{
  margin:0 calc(var(--gutter) * -1) var(--s6);
  overflow:hidden;
}
.broad img{width:100%;height:auto;}
.room--warm .broad{margin-top:var(--s6);}
.broad--after{margin-top:var(--s6);margin-bottom:0;}
/* On a wide screen a full bleed picture ran taller than the fold and pushed
   the reading down the page. Capping the height and letting the picture crop
   to it keeps the same width without the section becoming a scroll of its own. */
@media (min-width:1024px){
  .broad{max-height:44vh;}
  .broad img{height:44vh;object-fit:cover;object-position:center;}
}

/* ============================================================
   8. LEDGER
   ============================================================ */
.ledger{margin-top:var(--s6);border-top:var(--rule) solid var(--line);}
.ledger__cap{font-size:var(--fs-caption);font-weight:var(--fw-button);letter-spacing:.28em;text-transform:uppercase;color:var(--muted);padding-block:var(--s3);}
.ledger__row{
  display:grid;grid-template-columns:1fr auto;align-items:baseline;column-gap:var(--s4);
  padding-block:var(--s3);border-top:var(--rule) solid var(--hair);
}
.ledger__k{font-size:var(--fs-small);}
.ledger__v{font-family:var(--serif);font-size:var(--fs-body-lg);line-height:1;grid-row:span 2;}
.ledger__v i{font-style:normal;font-size:var(--fs-small);margin-inline-start:.2em;}
.ledger__n{grid-column:1;font-size:var(--fs-caption);letter-spacing:.16em;text-transform:uppercase;color:var(--muted);font-weight:var(--fw-button);}
@media (min-width:1024px){
  .ledger{display:grid;grid-template-columns:1fr 1fr;column-gap:var(--s6);border-top:var(--rule) solid var(--line);}
  .ledger__cap{grid-column:1 / -1;}
}

/* ============================================================
   9. HANGING A WORK
   The picture keeps its own proportions and is given room. The
   wall card sits beside it on the caption line, never over it.
   ============================================================ */
.hang{display:grid;gap:var(--s5);}
.hang__work{margin:0;}
.hang__shot{display:block;overflow:hidden;}
.hang__map{margin:0;}
.hang__map img{width:100%;height:auto;}
.hang__work .cap{margin-bottom:var(--s5);}
.hang__work img{width:100%;height:auto;}
.card{position:relative;display:flex;flex-direction:column;}
.card .room__name{margin-bottom:var(--s3);order:-1;}
.hang--textonly{max-width:74ch;}
/* The developer's mark sits beside the copy on a wide screen and under it on a
   narrow one. It is a brand mark, not a photograph, so it is capped rather than
   stretched and never fills its column. */
.dev-mark{margin:0;display:flex;align-items:center;justify-content:center;}
.dev-mark img{width:200px;max-width:60%;height:auto;}
@media (min-width:1024px){
  .hang{grid-template-columns:1fr;row-gap:var(--s5);}
  .card{max-width:none;}
  .card .lede{max-width:64ch;}
  .card .prose{max-width:76ch;}
  .card .reckon{columns:2;column-gap:var(--s6);}
}
.reckon{margin-top:var(--s3);}
.reckon dt{padding-top:var(--s3);font-size:var(--fs-small);}
.reckon dd{margin:0;padding-bottom:var(--s3);border-bottom:var(--rule) solid var(--hair);
  font-size:var(--fs-caption);letter-spacing:.14em;text-transform:uppercase;color:var(--muted);font-weight:var(--fw-button);}

/* ============================================================
   10. TALLY
   ============================================================ */
.tally{margin-top:var(--s6);counter-reset:tally;}
.tally__item{counter-increment:tally;padding-block:var(--s4);border-top:var(--rule) solid var(--line);display:grid;gap:var(--s2);}
.tally__item::before{content:counter(tally,decimal-leading-zero);font-family:var(--num);font-size:var(--fs-caption);letter-spacing:.2em;color:var(--brand-deep);font-weight:var(--fw-button);}
.tally__item h3{font-family:var(--serif);font-size:var(--fs-body-lg);}
.tally__item p{color:var(--muted);max-width:70ch;text-wrap:pretty;}
@media (min-width:1024px){
  .tally{display:grid;grid-template-columns:1fr 1fr;column-gap:var(--s6);}
  .tally__item{grid-template-columns:3rem 1fr;align-items:start;}
  .tally__item::before{grid-row:span 2;padding-top:.4rem;}
  .tally__item p{grid-column:2;}
}

/* ============================================================
   11. RAILS
   One shape for every run of things: gallery plates and unit
   cards. Same frame, same gap, same controls, one size.
   ============================================================ */
.rail{position:relative;margin-top:var(--s6);}
.rail__track{
  display:flex;gap:var(--s3);
  overflow-x:auto;overscroll-behavior-x:contain;
  scroll-snap-type:x proximity;scroll-padding-inline:0;
  padding-bottom:var(--s3);
  scrollbar-width:thin;scrollbar-color:var(--line) transparent;
}
.rail__track.is-dragging{scroll-snap-type:none;cursor:grabbing;}
.rail__track:focus-visible{outline-offset:6px;}
.rail__keys{display:flex;gap:.5rem;margin-top:var(--s3);}
.rail__foot{
  display:flex;align-items:center;justify-content:space-between;
  gap:var(--s3);margin-top:var(--s3);flex-wrap:wrap;
}
.rail__foot .rail__keys{margin-top:0;}
.rail__foot .rail__hint{margin:0;}
.rail__key{
  width:52px;height:52px;display:grid;place-items:center;
  background:none;border:var(--rule) solid var(--line);color:var(--ink);
  cursor:pointer;transition:background var(--slow) var(--ease),color var(--slow) var(--ease);
}
.rail__key:hover:not(:disabled){background:var(--ink);color:var(--paper);}
.rail__key:disabled{opacity:.3;cursor:default;}
[dir="rtl"] .rail__key svg{transform:scaleX(-1);}

/* every plate the same frame */
/* ------------------------------------------------ the gallery
   One proportion, one size, wide gaps, no scrollbar. The pictures are the
   largest thing in the room and the run is pushed rather than clicked. */
.rail__track--gallery{
  gap:clamp(24px,4vw,48px);
  scrollbar-width:none;
  -ms-overflow-style:none;
  cursor:grab;
}
.rail__track--gallery::-webkit-scrollbar{display:none;}
.rail__track--gallery.is-dragging{cursor:grabbing;}
.rail__track img{-webkit-user-drag:none;user-select:none;}
.plate{margin:0;flex:0 0 clamp(280px,82vw,680px);scroll-snap-align:start;}
.plate img{
  width:100%;aspect-ratio:3/2;object-fit:cover;object-position:50% 45%;
  transition:transform .8s var(--ease);
}
@media (hover:hover){
  .plate:hover img{transform:translateY(-6px) scale(1.02);}
}
@media (min-width:700px){
  .plate{flex-basis:clamp(560px,46vw,680px);}
}
.rail__hint{
  display:flex;align-items:center;justify-content:center;gap:.9rem;
  margin-top:var(--s4);
  font-size:var(--fs-caption);letter-spacing:.22em;text-transform:uppercase;color:var(--muted);font-weight:var(--fw-button);}
.rail__hint span{font-family:var(--sans);opacity:.6;}
@media (prefers-reduced-motion:reduce){.plate img{transition:none;}}

/* every unit card the same frame, picture then figures then actions */
.unit{
  flex:0 0 84%;scroll-snap-align:start;
  display:flex;flex-direction:column;
  background:var(--paper);
  border:var(--rule) solid var(--line);
}
.room--warm .unit,.room--read .unit{background:var(--paper);}
.unit__media img{width:100%;aspect-ratio:3/2;object-fit:cover;}
.unit__name{
  font-family:var(--serif);font-size:var(--fs-body-lg);
  padding:var(--s3) var(--s4) 0;
}
.unit .spec{margin:var(--s3) var(--s4) 0;border-top:var(--rule) solid var(--line);}
/* A mark against each spec row. Sized to the label, muted to the same weight,
   and inline-flex so it never disturbs the baseline of the type beside it. */
.unit .spec dt{display:flex;align-items:center;gap:.45em;}
.unit .spec dt svg{flex:0 0 auto;width:15px;height:15px;opacity:.55;}
.unit .spec>div{padding-block:.4rem;}
.unit .spec dt{font-size:var(--fs-caption);font-weight:var(--fw-button);}
.unit .spec .fig{font-size:var(--fs-body-lg);}
.unit__acts{display:flex;flex-wrap:wrap;gap:.5rem;padding:var(--s3) var(--s4) var(--s4);margin-top:auto;}
.unit__acts .btn{flex:1 1 auto;min-height:46px;padding:.7rem 1rem;font-size:var(--fs-caption);font-weight:var(--fw-button);}

@media (min-width:700px){
  .unit{flex-basis:calc((100% - var(--s3)) / 2);}
}
@media (min-width:1100px){
  .unit{flex-basis:calc((100% - var(--s3) * 2) / 3);}
}

.gal-slider{width:100%;}

.lightbox{border:0;padding:0;max-width:min(1180px,94vw);width:100%;background:var(--paper);color:var(--ink);}
.lightbox::backdrop{background:rgba(14,59,55,.86);}
.lightbox__bar{
  display:flex;align-items:center;justify-content:space-between;gap:var(--s3);
  padding:var(--s3) var(--s4);border-bottom:var(--rule) solid var(--line);
}
.lightbox__bar h3{font-family:var(--serif);font-size:var(--fs-body-lg);}
/* The plans are portrait and taller than they are wide, so the image keeps its
   own ratio and is capped against the viewport rather than the dialog width:
   a full width portrait plan would otherwise run past the bottom of the screen. */
.lightbox img{width:100%;height:auto;max-height:72vh;object-fit:contain;display:block;background:var(--sky-soft);}
.lightbox__detail{padding:var(--s4);}
.lightbox__detail .spec{margin-top:0;}
@media (min-width:900px){
  .lightbox__detail{display:grid;grid-template-columns:repeat(3,1fr);gap:0 var(--s5);padding:var(--s4) var(--s5) var(--s5);}
  .lightbox__detail .spec{border-top:0;display:contents;}
  .lightbox__detail .spec>div{display:grid;gap:.3rem;padding-block:var(--s3);
    border-top:var(--rule) solid var(--line);border-bottom:0;}
  .lightbox__detail .spec dd{text-align:start;}
}

/* ============================================================
   12. THE PLAN
   ============================================================ */
.plan{margin-top:var(--s6);}
.plan__stage{position:relative;overflow:hidden;background:#0E3B37;cursor:grab;touch-action:none;}
.plan__stage.is-dragging{cursor:grabbing;}
.plan__stage.is-zoomed{cursor:grab;}
.plan__stage:not(.is-zoomed){cursor:zoom-in;}
.plan__stage.is-zoomed{cursor:grab;}
.plan__stage img{-webkit-user-drag:none;user-select:none;}
.plan__inner{position:relative;transform-origin:50% 50%;transition:transform 1.1s var(--ease);will-change:transform;}
.plan__inner.is-live{transition:none;}
.plan__inner img{display:block;width:100%;height:auto;}
.pin{position:absolute;transform:translate(-50%,-50%);}
.pin__n{
  width:30px;height:30px;display:grid;place-items:center;border-radius:50%;
  background:var(--paper);color:var(--deep);
  font-family:var(--num);font-size:var(--fs-caption);font-weight:var(--fw-button);
  box-shadow:0 0 0 5px rgba(242,251,250,.24);
}

.plan__bar{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:var(--s3);padding-top:var(--s3);}
.plan__hint{font-size:var(--fs-caption);letter-spacing:.1em;color:rgba(242,251,250,.56);font-weight:var(--fw-body);}
.plan__keys{display:flex;gap:.4rem;}
@media (min-width:900px){
  /* The plan is a portrait drawing. It keeps its own shape and the legend
     stands beside it rather than under a very tall column. */
  .plan{display:grid;grid-template-columns:minmax(0,1.15fr) 1fr;column-gap:var(--s6);align-items:start;}
  .plan__stage{grid-column:1;grid-row:1 / 3;}
  .legend{grid-column:2;grid-row:1;margin-top:0;grid-template-columns:1fr;}
  .plan__bar{grid-column:2;grid-row:2;}
}

.legend{display:grid;gap:0;margin-top:var(--s4);counter-reset:legend;}
.legend__row{
  counter-increment:legend;
  display:grid;grid-template-columns:2.2rem 1fr;gap:.2rem var(--s3);
  padding-block:var(--s3);border-top:var(--rule) solid var(--line-inv);
}
.legend__row::before{
  content:counter(legend);grid-row:span 2;
  font-family:var(--num);font-size:var(--fs-caption);font-weight:var(--fw-button);color:var(--brand-deep);padding-top:.15rem;
}
.legend__t{font-family:var(--serif);font-size:var(--fs-body);font-weight:var(--fw-body);}
.legend__d{font-size:var(--fs-small);color:rgba(242,251,250,.66);}
@media (min-width:900px){.legend{grid-template-columns:1fr 1fr;column-gap:var(--s6);}}

/* ============================================================
   13. COLLECTIONS
   ============================================================ */
.collection{
  display:grid;gap:var(--s2);margin-top:var(--s7);padding-bottom:var(--s4);
  border-bottom:var(--rule) solid var(--line);counter-increment:collection;
}
.room{counter-reset:collection;}
.collection__t{font-family:var(--serif);font-size:var(--fs-h2);}
.collection__t::before{
  content:counter(collection,decimal-leading-zero);display:block;
  font-family:var(--num);font-size:var(--fs-caption);letter-spacing:.24em;color:var(--brand-deep);margin-bottom:var(--s2);font-weight:var(--fw-button);}
.collection__d{color:var(--muted);max-width:76ch;text-wrap:pretty;}
.ask{
  display:grid;gap:var(--s3);justify-items:start;
  margin-top:var(--s6);padding-top:var(--s5);border-top:var(--rule) solid var(--line);
}
.ask__t{font-family:var(--serif);font-size:var(--fs-h2);text-wrap:pretty;}
@media (min-width:900px){
  .ask{grid-template-columns:1fr auto;align-items:center;gap:var(--s5);}
}


/* ============================================================
   14. THE FILM
   ============================================================ */
.reel{position:relative;margin-top:var(--s6);background:var(--deep);}
/* The supplied film is a 720x1280 vertical cut. Poured into a full width
   block it was painted 1440 wide, which is twice its source and produced a
   2561px tall section that swallowed the page. It runs at its own shape,
   capped at the source width, inside a dark band. */
.reel--portrait{
  max-width:560px;margin-inline:auto;
  aspect-ratio:9/16;overflow:hidden;
}
.reel--portrait video{width:100%;height:100%;object-fit:contain;background:var(--deep);}
.reel--portrait .reel__cover img{width:100%;height:100%;object-fit:cover;}
.reel video{width:100%;height:auto;display:block;}
.reel__cover{position:static;width:100%;padding:0;border:0;background:none;cursor:pointer;}
.js .reel__cover{position:absolute;inset:0;}
html:not(.js) .reel video{display:block;}
.reel__cover img{width:100%;height:100%;object-fit:cover;}
.reel__cover.is-gone{display:none;}
.reel__blocked{
  position:absolute;left:50%;bottom:12%;transform:translateX(-50%);
  width:min(84%,34ch);text-align:center;
  background:rgba(14,59,55,.88);color:var(--paper);
  font-family:var(--sans);font-size:var(--fs-small);line-height:1.5;
  padding:.7rem .9rem;border-radius:2px;
}
.reel__go{position:absolute;inset-inline-start:50%;top:50%;transform:translate(-50%,-50%);
  width:76px;height:76px;display:grid;place-items:center;border-radius:50%;
  background:rgba(242,251,250,.92);color:var(--deep);transition:opacity var(--slow) var(--ease);}
[dir="rtl"] .reel__go{transform:translate(50%,-50%);}

/* ============================================================
   15. TERMS
   ============================================================ */
.terms{margin-top:var(--s5);}
.terms>div{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s4);
  padding-block:var(--s4);border-top:var(--rule) solid var(--line);}
.terms dt{font-size:var(--fs-caption);letter-spacing:.18em;text-transform:uppercase;color:var(--muted);font-weight:var(--fw-button);}
.terms dd{margin:0;font-family:var(--serif);font-size:var(--fs-h2);line-height:1;}
.terms dd i{font-style:normal;font-size:var(--fs-small);margin-inline-start:.1em;}
.ledgerwall{display:grid;gap:var(--s5);}
@media (min-width:1024px){
  .ledgerwall{grid-template-columns:1fr 1fr;column-gap:var(--s6);align-items:start;}
  .card--plain{grid-column:1 / -1;}
  .card--plain .prose{max-width:none;}
  .terms{grid-column:1 / -1;margin-top:var(--s5);}
}

/* ============================================================
   16. THE OFFICE
   ============================================================ */
.enquiry{display:grid;gap:var(--s6);}
.direct{display:flex;flex-wrap:wrap;gap:var(--s4);margin-top:var(--s5);}
.direct a{min-height:44px;min-width:44px;display:inline-flex;align-items:center;gap:.6rem;
  font-size:var(--fs-caption);letter-spacing:.16em;text-transform:uppercase;
  border-bottom:var(--rule) solid var(--line);font-weight:var(--fw-button);}
.direct a:hover{border-color:var(--ink);}
.direct__where{margin-top:var(--s4);font-size:var(--fs-small);color:var(--muted);}
.fields{display:grid;gap:var(--s4);}
.cell{display:grid;gap:.35rem;}
.cell>span{font-size:var(--fs-caption);letter-spacing:.18em;text-transform:uppercase;color:var(--muted);font-weight:var(--fw-button);}
.cell input,.cell select,.cell textarea,
.pn-form--plugin input[type="text"],.pn-form--plugin input[type="tel"],
.pn-form--plugin input[type="email"],.pn-form--plugin select,.pn-form--plugin textarea{
  width:100%;min-height:48px;padding:.7rem 0;background:none;color:var(--ink);
  border:0;border-bottom:var(--rule) solid var(--line);border-radius:0;
  transition:border-color var(--slow) var(--ease);
}
.cell textarea,.pn-form--plugin textarea{min-height:96px;resize:vertical;}
/* The select was the only control still wearing the operating system. The
   element stays native to the keyboard and to assistive technology; only the
   arrow is drawn, so the form reads as one piece. */
.cell select,.phone-combo__cc{
  appearance:none;-webkit-appearance:none;
  padding-inline-end:1.8rem;cursor:pointer;
  background-image:linear-gradient(45deg,transparent 50%,currentColor 50%),
                   linear-gradient(135deg,currentColor 50%,transparent 50%);
  background-size:6px 6px,6px 6px;
  background-position:right 0.75rem center,right 0.42rem center;
  background-repeat:no-repeat;
}
[dir="rtl"] .cell select,[dir="rtl"] .phone-combo__cc{
  padding-inline-end:1.8rem;
  background-position:left 0.42rem center,left 0.75rem center;
  background-image:linear-gradient(135deg,transparent 50%,currentColor 50%),
                   linear-gradient(45deg,currentColor 50%,transparent 50%);
}
.cell input:focus,.cell select:focus,.cell textarea:focus{border-color:var(--brand-deep);}
.phone-combo{display:grid;grid-template-columns:auto 1fr;gap:var(--s2);align-items:end;}
.phone-combo__cc{max-width:9.5rem;}
.agree{display:flex;align-items:flex-start;gap:.7rem;font-size:var(--fs-small);color:var(--muted);}
.agree input{width:20px;height:20px;flex:0 0 20px;margin-top:.35rem;accent-color:var(--brand-deep);}
.hp{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;}
.form-msg{margin-top:var(--s3);font-size:var(--fs-small);min-height:1.4em;}
.form-msg.is-ok{color:var(--brand-ink);} .form-msg.is-err{color:#1E7167;}
.pn-form--plugin input[type="submit"],.pn-form--plugin button[type="submit"]{
  min-height:52px;padding:.9rem 2rem;background:transparent;color:var(--ink);
  border:var(--rule) solid var(--ink);cursor:pointer;letter-spacing:.18em;text-transform:uppercase;}
@media (min-width:1024px){
  .enquiry{grid-template-columns:1fr 1fr;column-gap:var(--s6);align-items:start;}
  .enquiry__say{grid-column:1 / -1;}
  .pn-form{grid-column:1 / -1;}
  .enquiry__say .h-wall{margin-bottom:var(--s4);}
  .fields{grid-template-columns:1fr 1fr;column-gap:var(--s4);}
  .cell--wide,.agree{grid-column:1 / -1;}
}

/* ============================================================
   17. FAQ
   ============================================================ */
.faq{margin-top:var(--s5);border-top:var(--rule) solid var(--line);counter-reset:faq;}
.faq__item{border-bottom:var(--rule) solid var(--hair);counter-increment:faq;}
.faq summary{display:flex;gap:var(--s4);align-items:baseline;cursor:pointer;list-style:none;
  padding-block:var(--s4);font-family:var(--serif);font-size:var(--fs-body-lg);}
.faq summary::-webkit-details-marker{display:none;}
.faq summary::before{content:counter(faq,decimal-leading-zero);font-family:var(--num);
  font-size:var(--fs-caption);letter-spacing:.2em;color:var(--brand-deep);flex:0 0 2.2rem;line-height:2.4;font-weight:var(--fw-button);}
.faq__a{padding:0 0 var(--s4) calc(2.2rem + var(--s4));}
[dir="rtl"] .faq__a{padding:0 calc(2.2rem + var(--s4)) var(--s4) 0;}
.faq__a p{color:var(--muted);max-width:82ch;text-wrap:pretty;}
.faq__item[open] summary{color:var(--brand-ink);}
@media (min-width:1024px){
  .faq{max-width:none;}
}

/* ============================================================
   19. FALLBACK PAGES
   ============================================================ */
.section{padding-block:var(--s7);}
.prose h1{font-family:var(--serif);font-size:var(--fs-h2);max-width:20ch;}
.prose__body{max-width:64ch;margin-top:var(--s4);color:var(--muted);}
.prose__cta{margin-top:var(--s5);}
.prose__nav{display:flex;flex-wrap:wrap;gap:var(--s3);margin-top:var(--s5);padding-top:var(--s3);
  border-top:var(--rule) solid var(--line);}
.prose__nav a{min-height:44px;min-width:44px;display:inline-flex;align-items:center;
  font-size:var(--fs-caption);letter-spacing:.16em;text-transform:uppercase;color:var(--muted);font-weight:var(--fw-button);}
.label{display:block;font-size:var(--fs-caption);font-weight:var(--fw-button);letter-spacing:.28em;
  text-transform:uppercase;color:var(--muted);margin-bottom:var(--s3);}

/* ============================================================
   20. MOTION
   Ranked by what each piece of the page has to explain. The
   easing curves are GSAP's, read off its easing definitions
   rather than lifted from one of its demos; the durations and
   the sequencing are this site's.
   ============================================================ */
/* Motion is ranked, not sprinkled. A section gets one arrival, a card answers
   a pointer, a figure counts because the figure means something, and the hero
   gets the only cinematic moment on the site. Anything that does not help the
   reader understand sequence is not here.

   Two budget rules govern all of it:
   - Only opacity and transform are animated. Neither triggers layout, so the
     reveal cannot contribute to CLS however many sections are on the page.
   - Nothing is hidden unless JavaScript has confirmed it is running. The
     hidden state hangs off .js, and main.js shows everything unconditionally
     after four seconds, so a failed script leaves a fully readable page
     rather than a blank one. */

/* ---- the arrival: drop and settle
   Not a slide. The element comes down from a little above its place, passes
   it by two or three pixels, and settles back — which is what anything with
   mass does when it lands, and what separates this from the 20px rise every
   other page uses. The overshoot is deliberately under conscious notice.

   --gl-y and --gl-d let one keyframe serve every weight: the distance and
   the duration change with the mass of the thing arriving, the shape of the
   motion does not. --gl-delay is written by main.js, which computes the
   stagger rather than multiplying an index by a constant. */
@keyframes gl-settle{
  0%   {opacity:0;transform:translate3d(0,calc(var(--gl-y,16px) * -1),0);}
  58%  {opacity:1;transform:translate3d(0,2.5px,0);}
  100% {opacity:1;transform:none;}
}

.js .reveal{opacity:0;}
.js .reveal.is-in{
  animation:gl-settle var(--gl-d,var(--d-l)) var(--e-settle) both;
  animation-delay:var(--gl-delay,0ms);
}
/* Weight classes. A photograph does not arrive at the speed of a caption. */
.js .reveal--xl.is-in{--gl-d:var(--d-xl);--gl-y:26px;}
.js .reveal--l.is-in {--gl-d:var(--d-l); --gl-y:20px;}
.js .reveal--m.is-in {--gl-d:var(--d-m); --gl-y:15px;}
.js .reveal--s.is-in {--gl-d:var(--d-s); --gl-y:10px;}

/* Children arrive on a stagger main.js computes: the gaps compress as the
   group fills rather than repeating one constant, and each element carries a
   few milliseconds of its own derived from its index — never from a random
   number, so the sequence is identical on every load. */
.js .reveal [data-stagger]>*{opacity:0;}
.js .is-in [data-stagger]>*,
.js [data-stagger].is-in>*{
  animation:gl-settle var(--gl-d,var(--d-m)) var(--e-settle) both;
  animation-delay:var(--gl-delay,0ms);
  --gl-y:13px;
}

/* ---- hero: the one cinematic entrance
   Self-completing, so it needs no JavaScript to finish and cannot strand the
   masthead or the headline at opacity 0. The photograph is the heaviest thing
   on the page and settles last. */
@keyframes gl-arrive{
  0%   {opacity:0;transform:translate3d(0,-18px,0) scale(.988);}
  60%  {opacity:1;transform:translate3d(0,3px,0) scale(1);}
  100% {opacity:1;transform:none;}
}
.js .arrival__type{animation:gl-arrive var(--d-l) var(--e-settle) both;}
.js .arrival__plate{animation:gl-arrive var(--d-xl) var(--e-drift) both;animation-delay:90ms;}

/* ---- page: a fade and nothing more */
@keyframes gl-page{from{opacity:0;}to{opacity:1;}}
.js body{animation:gl-page var(--d-page) var(--ease-out-2) both;}

/* ---- cards: a restrained lift, no scale
   6px and a shadow is a card acknowledging the pointer. A scale is a card
   asking for attention it has not earned. */
.card,.unit{transition:transform var(--d-hover) var(--e-lift),box-shadow var(--d-hover) var(--e-lift);}
@media (hover:hover){
  .card:hover,.unit:hover{transform:translate3d(0,-6px,0);box-shadow:0 14px 30px rgba(22,25,27,.11);}
}
.card:focus-within,.unit:focus-within{transform:translate3d(0,-6px,0);box-shadow:0 14px 30px rgba(22,25,27,.11);}

/* ---- the wave, once
   Earned rather than decorative: it is the edge between the hero photograph
   and the page below it, which is the one place on the site where a coastline
   is literally what the reader is looking at. It is a static mask, not an
   animation, and it is drawn as an inline data URI so it costs no request. */
.arrival{position:relative;--wave-fill:var(--paper);}
.arrival::after{
  content:"";position:absolute;inset-inline:0;bottom:-1px;height:clamp(16px,2vw,30px);
  pointer-events:none;z-index:2;background:var(--wave-fill);
  -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 100' preserveAspectRatio='none'%3E%3Cpath d='M0 62c140-34 260-34 400 0s260 34 400 0 260-34 400 0 200 26 240 20v18H0Z' fill='%23000'/%3E%3C/svg%3E");
          mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 100' preserveAspectRatio='none'%3E%3Cpath d='M0 62c140-34 260-34 400 0s260 34 400 0 260-34 400 0 200 26 240 20v18H0Z' fill='%23000'/%3E%3C/svg%3E");
  -webkit-mask-size:100% 100%;mask-size:100% 100%;
  -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
}
/* The wave has to be painted in whatever colour follows it, and the hero can
   only look forward with :has(). Where that is unsupported the fill stays
   --paper, which is the common case anyway. */
.arrival:has(+.room--warm){--wave-fill:var(--band);}
.arrival:has(+.room--plan){--wave-fill:var(--deep);}

[data-drift]{overflow:hidden;}
[data-drift] img{will-change:transform;}

/* Every animation on the site, without exception, stops here. */
@media (prefers-reduced-motion:reduce){
  .js .reveal,.js .reveal.is-in,
  .js .reveal [data-stagger]>*,
  .js .is-in [data-stagger]>*,
  .js [data-stagger].is-in>*{
    opacity:1;transform:none;transition:none;animation:none;
  }
  .js .arrival__type,.js .arrival__plate,.js body{animation:none;}
  /* The descent stops being scroll-driven and becomes a plain stack. */
  .descent__stage{position:static;height:auto;}
  .descent__level{opacity:1;transform:none;animation:none;transition:none;}
  .descent__water,.descent__marker{transition:none;animation:none;}
  [data-drift] img{transform:none!important;}
  .card,.unit,.plan__inner,.btn,.key{transition:none!important;}
  .card:hover,.unit:hover,.card:focus-within,.unit:focus-within{transform:none;box-shadow:none;}
}

/* ============================================================
   6. MASTHEAD
   Set like a publication's masthead: a hairline, the mark
   centred beneath it, and the two controls out in the margins.
   The section list is not here; it opens as a full page index.
   ============================================================ */
.masthead{
  position:relative;z-index:90;
  padding-top:calc(var(--s3) + env(safe-area-inset-top));
  display:grid;grid-template-columns:1fr auto 1fr;align-items:center;
  gap:var(--s3);padding:var(--s3) var(--gutter);
  background:var(--paper);border-bottom:var(--rule) solid var(--hair);
}
.masthead__mark{justify-self:center;display:inline-flex;align-items:center;min-height:44px;line-height:0;}
.masthead__index-t{display:inline-block;}
.logo__by{font-size:var(--fs-caption);letter-spacing:.22em;text-transform:uppercase;color:var(--muted);margin-inline-start:.5rem;font-weight:var(--fw-button);}
.masthead__mark img{height:30px;width:auto;}
.masthead__lang{
  justify-self:start;min-height:44px;display:inline-flex;align-items:center;
  font-family:var(--sans);font-size:var(--fs-small);font-weight:var(--fw-button);
  letter-spacing:.14em;text-transform:uppercase;color:var(--ink);
  border:var(--rule) solid var(--line);border-radius:2px;padding:.5rem .95rem;
  transition:background .3s var(--ease),border-color .3s var(--ease);
}
.masthead__lang:hover,.masthead__lang:focus-visible{
  background:var(--paper-2);border-color:var(--ink);color:var(--ink);
}
/* The switcher shows the OTHER language, so it is sized by its own lang
   attribute rather than by the direction of the page it sits on. */
.masthead__lang[lang="ar"]{text-transform:none;letter-spacing:.02em;font-size:var(--fs-small);}
.masthead__lang:hover{color:var(--ink);}
/* Both controls in the masthead were set at .66rem, which is smaller than any
   other text on the page and read as fine print rather than as the two things
   a visitor is meant to press. They are larger now, and the contents toggle is
   drawn as a bordered control so it looks pressable rather than decorative. */
.masthead__index{
  justify-self:end;min-height:44px;
  display:inline-flex;align-items:center;gap:.7rem;
  background:none;cursor:pointer;
  border:var(--rule) solid var(--line);border-radius:2px;
  padding:.5rem .95rem;
  font-family:var(--sans);font-size:var(--fs-small);font-weight:var(--fw-button);
  letter-spacing:.18em;text-transform:uppercase;color:var(--ink);
  transition:background .3s var(--ease),border-color .3s var(--ease);
}
.masthead__index:hover,.masthead__index:focus-visible{
  background:var(--paper-2);border-color:var(--ink);
}
.masthead__index-r{
  display:block;width:22px;height:2px;background:currentColor;
  box-shadow:0 6px 0 currentColor,0 -6px 0 currentColor;
  transition:box-shadow .4s var(--ease);
}
.masthead__index[aria-expanded="true"] .masthead__index-r{box-shadow:0 0 0 currentColor;}
.masthead__index:hover .masthead__index-r{box-shadow:0 8px 0 currentColor;}
.masthead.is-stuck{position:sticky;top:0;}
@media (min-width:900px){
  .masthead__mark img{height:38px;}
}

/* ------------------------------------------------ the index page */
.index-page{
  position:fixed;inset:0;z-index:100;background:var(--paper);color:var(--ink);
  display:grid;grid-template-rows:1fr auto;
  padding:var(--s7) var(--gutter) var(--s5);
  opacity:0;visibility:hidden;
  transition:opacity .6s var(--ease),visibility .6s;
}
.index-page.is-open{opacity:1;visibility:visible;}
.index-page__inner{align-self:center;width:100%;max-width:var(--frame);margin-inline:auto;}
.index-page__cap{
  font-size:var(--fs-caption);font-weight:var(--fw-button);letter-spacing:.34em;text-transform:uppercase;
  color:var(--muted);padding-bottom:var(--s3);border-bottom:var(--rule) solid var(--line);
}
.index-page__list{display:flex;flex-direction:column;counter-reset:idx;}
.index-page__list a{
  counter-increment:idx;
  display:grid;grid-template-columns:3.4rem 1fr;align-items:baseline;
  min-height:56px;padding-block:var(--s2);
  border-bottom:var(--rule) solid var(--hair);
  transition:color .5s var(--ease);
}
.index-page__list a:hover{color:var(--brand-ink);}
.index-page__list a::before{content:counter(idx,decimal-leading-zero);
  font-family:var(--num);font-size:var(--fs-caption);letter-spacing:.2em;color:var(--brand-deep);font-weight:var(--fw-button);}
.index-page__list a{font-family:var(--serif);font-size:var(--fs-h2);line-height:1.1;}
.index-page__lang{
  display:inline-flex;align-items:center;min-height:44px;min-width:44px;margin-top:var(--s4);
  font-size:var(--fs-caption);letter-spacing:.24em;text-transform:uppercase;color:var(--muted);font-weight:var(--fw-button);}
.index-page__close{
  position:absolute;top:var(--s4);inset-inline-end:var(--gutter);
  width:52px;height:52px;display:grid;place-items:center;
  background:none;border:var(--rule) solid var(--line);color:var(--ink);
  cursor:pointer;transition:background var(--slow) var(--ease),color var(--slow) var(--ease);
}
.index-page__close:hover{background:var(--ink);color:var(--paper);}
@media (min-width:900px){
  .index-page__list{
    display:grid;grid-template-columns:1fr 1fr;column-gap:var(--s7);
  }
}

/* ============================================================
   18. COLOPHON
   The page ends the way a publication ends: the mark set large,
   one line of imprint, the contents once across the width, and
   the legal line last. No column grid, no icon row.
   ============================================================ */
.colophon{background:var(--deep);color:var(--paper);padding-block:var(--s5) var(--s4);}
.colophon__mark{display:block;}
.colophon__mark img{height:clamp(38px,4.6vw,54px);width:auto;}
.colophon__mark .logo__by{color:rgba(168,201,197,.55);}
.colophon__mark .logo__name{font-family:var(--serif);font-size:var(--fs-h1);}
.colophon__imprint{
  margin-top:var(--s3);max-width:60ch;
  font-family:var(--serif);font-size:var(--fs-body);line-height:1.5;
  color:rgba(242,251,250,.8);
}
.colophon__contents{
  display:flex;flex-wrap:wrap;gap:0 var(--s5);
  margin-top:var(--s6);padding-top:var(--s3);
  border-top:var(--rule) solid var(--line-inv);
}
.colophon__contents a{
  min-height:44px;min-width:44px;display:inline-flex;align-items:center;justify-content:center;
  font-size:var(--fs-caption);letter-spacing:.2em;text-transform:uppercase;
  color:rgba(242,251,250,.66);transition:color .5s var(--ease);font-weight:var(--fw-button);}
.colophon__contents a:hover{color:var(--paper);}
.colophon__reach{display:flex;gap:.5rem;margin-top:var(--s4);}
.reach{
  width:52px;height:52px;display:grid;place-items:center;
  border:var(--rule) solid var(--line-inv);color:var(--paper);
  transition:background .5s var(--ease),color .5s var(--ease),border-color .5s var(--ease);
}
.reach:hover{background:var(--paper);color:var(--deep);border-color:var(--paper);}
.reach--wa:hover{background:#227E72;color:#fff;border-color:#227E72;}
.colophon__social{display:flex;gap:.5rem;margin-top:var(--s3);}
.colophon__social a{
  width:44px;height:44px;display:grid;place-items:center;
  border:var(--rule) solid var(--line-inv);color:var(--paper);
}
.colophon__social a:hover{background:var(--paper);color:var(--deep);}
.colophon__legal{
  margin-top:var(--s4);padding-top:var(--s3);
  border-top:var(--rule) solid var(--line-inv);
  font-size:var(--fs-caption);color:rgba(242,251,250,.46);font-weight:var(--fw-body);}
@media (min-width:1024px){
  .colophon .frame{
    display:grid;grid-template-columns:minmax(28ch,1fr) auto;
    column-gap:var(--s6);row-gap:var(--s4);align-items:start;
  }
  .colophon__mark{grid-column:1;}
  .colophon__imprint{grid-column:1;max-width:56ch;}
  .colophon__reach{grid-column:2;grid-row:1 / 3;justify-self:end;margin-top:0;}
  .colophon__social{grid-column:1;}
  .colophon__legal{grid-column:1 / -1;}
}

/* ------------------------------------------------ one standing action */
.standing{display:none;}
@media (min-width:901px){
  .standing{
    display:flex;flex-direction:column;gap:.55rem;
    position:fixed;inset-inline-end:var(--s3);top:50%;z-index:80;
    transform:translateY(-50%);
    background:none;border:0;box-shadow:none;
    transition:transform var(--slow) var(--ease),opacity var(--slow) var(--ease);
  }
  .standing.is-away{opacity:0;transform:translateY(-50%) translateX(100%);pointer-events:none;}
  [dir="rtl"] .standing.is-away{transform:translateY(-50%) translateX(-100%);}
  /* Three marks of equal weight. None of them outranks the others.
     Ink on the page, turquoise only on hover: three standing turquoise
     discs read as a warning rather than an invitation, and the accent is
     worth more spent on the action being taken. */
  /* Geometry only. The colour is set once, outside this query, so the rail
     cannot drift between breakpoints again. */
  .standing a{
    width:52px;height:52px;display:grid;place-items:center;
    font-size:0;line-height:0;overflow:hidden;
  }
}
.dock{
  position:fixed;inset-inline:0;bottom:0;z-index:80;
  padding-bottom:env(safe-area-inset-bottom);
  display:grid;grid-template-columns:repeat(3,1fr);
  background:var(--brand-deep);
  border-top:0;
  box-shadow:0 -14px 34px -26px rgba(14,59,55,.5);
  transition:transform var(--slow) var(--ease);
}
.dock.is-away{transform:translateY(100%);}
.burger{color:inherit;}
.dock__call,.dock__wa,.dock__go,.standing__act,.cta-rail__wa{color:inherit;}
.dock a{
  min-height:62px;display:flex;align-items:center;justify-content:center;
  color:var(--paper);background:none;
  border-inline-end:var(--rule) solid rgba(242,251,250,.22);
}
.dock a:last-child{border-inline-end:0;}
.dock a:active{background:var(--brand-deep);}
@media (min-width:901px){.dock{display:none;}}
@media (max-width:900px){body{padding-bottom:calc(62px + env(safe-area-inset-bottom));}}

/* ============================================================
   21. ARABIC
   ============================================================ */
body.pn-ar{direction:rtl;}
/* Arabic takes its own faces. The numeric stack is left alone so figures stay
   tabular and line up down the page. */
[dir="rtl"] body,body.pn-ar{font-family:var(--ar-sans);}
[dir="rtl"] .wordmark,[dir="rtl"] .h-wall,[dir="rtl"] .h-room,
[dir="rtl"] .lede,[dir="rtl"] .arrival__line,[dir="rtl"] .collection__t,
[dir="rtl"] .unit__name,[dir="rtl"] .ask__t,[dir="rtl"] .faq summary,
[dir="rtl"] .legend__t,[dir="rtl"] .terms dd,[dir="rtl"] .ledger__v,
[dir="rtl"] .tally__item h3,[dir="rtl"] .lightbox__bar h3,
[dir="rtl"] .colophon__imprint,[dir="rtl"] .pin__note b{
  font-family:var(--ar-display);
}
[dir="rtl"] .room__name,[dir="rtl"] .rubric,[dir="rtl"] .cap,
[dir="rtl"] .btn,[dir="rtl"] .key,[dir="rtl"] .rail__hint,
[dir="rtl"] .cell>span,[dir="rtl"] .spec dt,[dir="rtl"] .terms dt{
  font-family:var(--ar-sans);
}
/* The Arabic page swaps both families. Figures keep the numeric face, because
   the digits are Latin and are compared against one another. */
[dir="rtl"] body,[dir="rtl"] .prose,[dir="rtl"] p,[dir="rtl"] li,
[dir="rtl"] dt,[dir="rtl"] dd,[dir="rtl"] label,[dir="rtl"] input,
[dir="rtl"] select,[dir="rtl"] textarea,[dir="rtl"] .btn,[dir="rtl"] .key,
[dir="rtl"] .room__name,[dir="rtl"] .rubric,[dir="rtl"] .cap,
[dir="rtl"] .nav a,[dir="rtl"] .rail__hint{font-family:var(--ar-sans);}
[dir="rtl"] .wordmark,[dir="rtl"] .h-wall,[dir="rtl"] .h-room,
[dir="rtl"] .lede,[dir="rtl"] .arrival__line,[dir="rtl"] .collection__t,
[dir="rtl"] .unit__name,[dir="rtl"] .ledger__v,[dir="rtl"] .terms dd,
[dir="rtl"] .faq summary,[dir="rtl"] .legend__t,[dir="rtl"] .ask__t,
[dir="rtl"] .tally__item h3,[dir="rtl"] .lightbox__bar h3,
[dir="rtl"] .colophon__imprint{font-family:var(--ar-display);}
[dir="rtl"] .fig,[dir="rtl"] .legend__row::before,
[dir="rtl"] .faq summary::before,[dir="rtl"] .pin__n{font-family:var(--num);}
/* Arabic letterforms carry their own rhythm; tracking meant for Latin caps
   pulls them apart. */
[dir="rtl"] .room__name,[dir="rtl"] .rubric,[dir="rtl"] .cap,
[dir="rtl"] .rail__hint{letter-spacing:.08em;}
[dir="rtl"] .wordmark,[dir="rtl"] .h-wall,[dir="rtl"] .h-room{letter-spacing:0;line-height:1.3;}
[dir="rtl"] .h-wall,[dir="rtl"] .h-room,[dir="rtl"] .wordmark{font-weight:var(--fw-h2);}
[dir="rtl"] .display,[dir="rtl"] .wordmark,[dir="rtl"] h1,[dir="rtl"] h2,
[dir="rtl"] h3,[dir="rtl"] h4{letter-spacing:0;line-height:1.28;}
[dir="rtl"] .wordmark{line-height:1.02;}
[dir="rtl"] [dir="rtl"] [dir="rtl"] .lede{}
[dir="rtl"] .index,[dir="rtl"] .rubric,[dir="rtl"] .ledger__n,
[dir="rtl"] .spec dt,[dir="rtl"] .terms dt,[dir="rtl"] .cell>span{letter-spacing:.06em;}
[dir="rtl"] .wordmark__b{letter-spacing:.16em;}
[dir="rtl"] .btn,[dir="rtl"] .key,[dir="rtl"] .nav a,[dir="rtl"] .lang,
[dir="rtl"] .direct a,[dir="rtl"] .mbar a,[dir="rtl"] .cta-rail a{letter-spacing:.04em;}
/* Values that are only ever figures stay left to right. */
[dir="rtl"] .terms dd,[dir="rtl"] .phone-combo input,
[dir="rtl"] .cell input[type="email"]{
  direction:ltr;unicode-bidi:isolate;text-align:start;
}
/* These hold a figure on one row and an Arabic sentence on the next, so the
   direction is inherited and the run is isolated instead of forced. */
[dir="rtl"] .ledger__v,[dir="rtl"] .reckon dd,[dir="rtl"] .spec dd{
  unicode-bidi:isolate;text-align:start;
}
[dir="rtl"] .spec dd{text-align:end;}


/* ============================================================
   RESIDENCES AS A GRID
   Two cards per collection do not overflow a desktop rail, so the
   arrows had nothing to scroll and sat there dead. The collection
   is a grid instead: everything visible, nothing to push.
   ============================================================ */
.units{position:relative;}
.units-grid{
  display:grid;gap:var(--s4);margin-top:var(--s6);
  grid-template-columns:1fr;
}
@media (min-width:760px){ .units-grid{grid-template-columns:repeat(2,1fr);} }
@media (min-width:1240px){ .units-grid{grid-template-columns:repeat(2,1fr);gap:var(--s5);} }
.units-grid > .unit{flex:none;width:auto;max-width:none;}


/* ============================================================
   HORIZONTAL FIRST
   The house rule for this build and the ones after it: read
   across before reading down. Everything that was a stack of
   full width rows becomes a run of columns on a desktop and a
   snap rail on a phone, so a thumb moves sideways instead of
   scrolling past twelve identical bands.
   ============================================================ */

/* --- the eight figures: a row, not a list ------------------- */
.ledger__row{grid-template-columns:1fr auto;}
@media (min-width:620px){
  .ledger{display:grid;grid-template-columns:repeat(2,1fr);column-gap:var(--s5);}
  .ledger__cap{grid-column:1 / -1;}
}
@media (min-width:1100px){
  .ledger{grid-template-columns:repeat(4,1fr);column-gap:var(--s4);}
  .ledger__row{
    grid-template-columns:1fr;align-items:start;row-gap:.35rem;
    padding-block:var(--s3) var(--s4);
  }
  .ledger__v{grid-row:auto;order:-1;font-size:var(--fs-h1);line-height:1;}
  .ledger__k{font-size:var(--fs-caption);letter-spacing:.16em;text-transform:uppercase;color:var(--muted);font-weight:var(--fw-button);}
}

/* --- the amenities: three across, a rail on a phone --------- */
@media (max-width:759px){
  .tally{
    display:flex;gap:var(--s3);overflow-x:auto;
    scroll-snap-type:x proximity;overscroll-behavior-x:contain;
    padding-bottom:var(--s3);scrollbar-width:none;
  }
  .tally::-webkit-scrollbar{display:none;}
  .tally__item{
    flex:0 0 76%;scroll-snap-align:start;
    border-top:var(--rule) solid var(--line);
  }
}
@media (min-width:760px){
  .tally{display:grid;grid-template-columns:repeat(2,1fr);column-gap:var(--s5);}
}
@media (min-width:1100px){
  .tally{grid-template-columns:repeat(3,1fr);column-gap:var(--s5);}
}

/* --- the questions: two columns of answers ------------------ */
@media (min-width:1024px){
  .faq{columns:2;column-gap:var(--s6);}
  .faq__item{break-inside:avoid;}
}

/* --- the payment terms: a row of four ----------------------- */
@media (min-width:760px){
  .terms{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--s4);}
  .terms>div{
    display:block;padding-block:var(--s3) var(--s4);
    border-top:var(--rule) solid var(--line);
  }
  .terms>div dt{font-size:var(--fs-caption);letter-spacing:.16em;text-transform:uppercase;color:var(--muted);font-weight:var(--fw-button);}
  .terms>div dd{margin:.4rem 0 0;font-family:var(--num);font-size:var(--fs-h2);line-height:1;}
}

/* --- picture beside its card, not above it ------------------ */
@media (min-width:1024px){
  .hang{grid-template-columns:1.15fr .85fr;column-gap:var(--s6);align-items:center;}
  .hang--textonly{grid-template-columns:1fr;max-width:78ch;}
  .hang--dev{grid-template-columns:1fr minmax(0,320px);column-gap:var(--s6);align-items:center;}
  .dev-mark img{width:260px;max-width:100%;}
}

/* --- the residences: a rail on a phone, a pair on a desktop -- */
@media (max-width:759px){
  .units-grid{
    display:flex;gap:var(--s3);overflow-x:auto;
    scroll-snap-type:x proximity;overscroll-behavior-x:contain;
    padding-bottom:var(--s3);scrollbar-width:none;
  }
  .units-grid::-webkit-scrollbar{display:none;}
  .units-grid > .unit{flex:0 0 82%;scroll-snap-align:start;}
}

/* --- the distances table reads across ----------------------- */
@media (min-width:760px){
  .hang__map + .card .ledger,
  #location .ledger{grid-template-columns:repeat(2,1fr);}
}
@media (min-width:1240px){
  #location .ledger{grid-template-columns:repeat(3,1fr);}
}


/* --- masthead on a narrow phone ----------------------------
   The horizontal lockup is wider than the stacked one it
   replaced, and at 390px it walked straight into the contents
   label. The mark shrinks and the word "contents" drops to its
   rule, which is what the burger already means. */
@media (max-width:600px){
  .masthead{gap:var(--s2);}
  .masthead__mark img{height:20px;max-width:34vw;object-fit:contain;object-position:center;}
  .masthead__index,.masthead__lang{padding:.42rem .6rem;font-size:var(--fs-caption);letter-spacing:.08em;font-weight:var(--fw-button);}
  .masthead__index{gap:.5rem;}
  /* The comment above says the word drops to its rule on a phone; it never
     did, and the English label pushed the masthead 3px past the viewport at
     390. The burger already carries the meaning, so the word goes and the
     accessible name is kept on the button. */
  .masthead__index-t{
    position:absolute;width:1px;height:1px;margin:-1px;
    overflow:hidden;clip-path:inset(50%);white-space:nowrap;
  }
  .masthead{grid-template-columns:auto 1fr auto;}
  .masthead__mark{justify-self:center;}
  .masthead__lang[lang="ar"]{font-size:var(--fs-small);}
}


/* --- the arrival on a phone --------------------------------
   94svh reserved a screen the type did not fill, so the two
   actions floated in the middle of nothing and the photograph
   sat below the fold twice over. The screen is given back to
   the picture, and the two actions sit side by side. */
@media (max-width:759px){
  /* Still one screen, as the arrival is meant to be, but the rows are
     sized by their content so the picture takes the slack instead of a gap. */
  .arrival,.hero{min-height:86svh;grid-template-rows:auto 1fr;}
  .arrival__acts{flex-wrap:nowrap;}
  .arrival__acts .btn{flex:1 1 0;text-align:center;padding-inline:.6rem;}
  .arrival__plate{margin-top:var(--s3);}
}


/* ============================================================
   HORIZONTAL, FURTHER
   The remaining verticality was the head of every section: a
   label, a heading, a standfirst and two paragraphs, each one
   full width and stacked. They now sit as two columns, so the
   reader crosses the page before dropping down it.
   ============================================================ */
@media (min-width:1024px){
  .wall{
    display:grid;
    grid-template-columns:minmax(0,.92fr) minmax(0,1.08fr);
    column-gap:var(--s6);align-items:start;
  }
  .wall .room__name{grid-column:1;grid-row:1;order:0;margin-bottom:var(--s2);}
  .wall .h-wall,.wall .h-room{grid-column:1;grid-row:2;margin-bottom:0;max-width:none;}
  .wall .lede{grid-column:2;grid-row:2;margin-top:0;max-width:48ch;}
  .wall .prose{grid-column:2;max-width:64ch;margin-top:var(--s3);}
}

/* the card head, same treatment */
@media (min-width:1024px){
  .card:not(.card--plain) .lede{max-width:48ch;}
  .ledgerwall .card{display:grid;grid-template-columns:1fr;}
}

/* --- four across where there is room ------------------------ */
@media (min-width:1420px){
  .tally{grid-template-columns:repeat(4,1fr);}
  #location .ledger{grid-template-columns:repeat(3,1fr);}
}
@media (min-width:1420px){
  .faq{columns:3;}
}

/* --- the gallery runs wider plates so fewer bands are needed - */
@media (min-width:1024px){
  .plate{flex-basis:clamp(520px,38vw,700px);}
}

/* --- amenity rail on tablets too, not just phones ----------- */
@media (min-width:760px) and (max-width:1023px){
  .tally{grid-template-columns:repeat(2,1fr);column-gap:var(--s4);}
}

/* --- the enquiry form fields sit across ---------------------- */
@media (min-width:760px){
  .fields{display:grid;grid-template-columns:repeat(2,1fr);gap:var(--s3) var(--s4);}
  .cell--wide{grid-column:1 / -1;}
}


/* ============================================================
   RESIDENCE CARDS ON A PHONE
   The spec list stacked its label above its value, so each of the
   six rows cost two lines and a card ran past 1300px on an 844px
   screen. A card taller than the screen cannot be compared with
   the one beside it, which is the whole point of a rail. The rows
   read across now, which halves the card and matches the standing
   rule that this site lays out horizontally rather than stacking.
   ============================================================ */
@media (max-width:759px){
  .unit .spec>div{
    display:grid;grid-template-columns:1fr auto;
    align-items:baseline;gap:var(--s2);
    padding-block:.55rem;
    border-bottom:var(--rule) solid var(--hair);
  }
  .unit .spec>div:last-child{border-bottom:0;}
  .unit .spec dt{margin:0;font-size:var(--fs-caption);line-height:1.3;font-weight:var(--fw-body);}
  .unit .spec dd{margin:0;text-align:end;font-size:var(--fs-small);line-height:1.35;}
  .unit .spec .fig{font-size:var(--fs-body);}
  /* 82% left a clipped sliver of the next card with two letters of its
     heading showing. 86% with the gutter as scroll padding shows a clean
     edge instead, and still says there is another card. */
  .units-grid{padding-inline:var(--gutter);margin-inline:calc(var(--gutter) * -1);
    scroll-padding-inline-start:var(--gutter);}
  .units-grid > .unit{flex:0 0 86%;}
}


/* ============================================================
   THE TWO BANDS
   The page is white. Two kinds of band are laid across it, and
   they are no longer the same band: --plan carries the deep teal
   that gives the photography something to sit against, and --warm
   carries sand, which is where the palette's 20% is actually
   spent. Under the previous identity both were dark, so pointing
   --warm at sand without splitting these rules would have left
   pale-on-pale text across the whole section.
   ============================================================ */

.room--plan{background:var(--deep);color:var(--on-deep);}
.room--plan .prose,.room--plan .lede,
.room--plan .tally__item p,
.room--plan .card__note,
.room--plan .cap,
.room--plan .ledger__d,
.room--plan dt{color:var(--on-deep-muted);}
.room--plan .tally__item h3,
.room--plan .ledger__v,
.room--plan dd{color:var(--on-deep);}
.room--plan .room__name{color:var(--sky);}
.room--plan .h-room,.room--plan .h-wall{color:var(--on-deep);}
.room--plan .legend__t{color:var(--on-deep);}
.room--plan .key{border-color:var(--line-inv);color:var(--on-deep);}
.room--plan .key:hover{background:var(--deep-2);}
.room--plan :focus-visible{outline-color:var(--sky);}
/* Buttons and keys carry their own ground and their own measured text
   colour, so the band's link rule must not reach them: .room--x a beats .btn
   on specificity and would repaint a turquoise button in link colour. */
.room--plan a:not(.btn):not(.key):not(.rail__key){color:var(--sky);}

/* Sand is a light ground, so it takes the page's own ink rather than the
   inverted set. Ink on sand is 14.1:1, muted 5.2:1, turquoise-as-text 4.6:1. */
.room--warm{background:var(--band);color:var(--ink);}
.room--warm .prose,.room--warm .lede,
.room--warm .tally__item p,
.room--warm .card__note,
.room--warm .cap,
.room--warm .ledger__d,
.room--warm dt{color:var(--muted);}
.room--warm .tally__item h3,
.room--warm .ledger__v,
.room--warm dd{color:var(--ink);}
.room--warm .room__name{color:var(--muted);}
.room--warm .h-room,.room--warm .h-wall{color:var(--ink);}
.room--warm .legend__t{color:var(--ink);}
.room--warm .key{border-color:var(--line);color:var(--ink);}
.room--warm .key:hover{background:rgba(22,25,27,.06);}
.room--warm a:not(.btn):not(.key):not(.rail__key){color:var(--brand-deep);}

.colophon{background:var(--deep);color:var(--on-deep);}
.colophon a{color:var(--on-deep);}
.colophon .logo__name,.colophon__mark .logo__name{color:var(--on-deep);}
.colophon .prose,.colophon p{color:var(--on-deep-muted);}

/* The map plate sits on the dark band, so it needs no surface of its own. */
.plan,.hang__map,.plan__inner{background:transparent;}


/* ============================================================
   THE ENQUIRY, SET INTO THE PAGE
   The form read as one more section in the column. It is now a
   recessed panel in its own colour, so the eye finds it without
   having to be told, and so the page ends on an action rather
   than on more reading.
   ============================================================ */

.room--office{
  background:var(--paper-2);
  border-block:var(--rule) solid var(--line);
}
.room--office .frame{
  background:var(--paper-3);
  border:var(--rule) solid var(--line);
  border-radius:3px;
  padding:clamp(28px,4vw,64px);
  box-shadow:0 1px 0 rgba(22,25,27,.04), 0 24px 60px -40px rgba(22,25,27,.5);
}
.room--office .h-room,.room--office .h-wall{color:var(--ink);}
.room--office .room__name{color:var(--brand-deep);}
.room--office .prose,.room--office .lede{color:var(--muted);}

/* ============================================================
   ICON CONTROLS
   Every icon-only control gets a real target and a state that
   says it is pressable. An icon with no affordance reads as
   decoration, which is the reported symptom.
   ============================================================ */

a:has(> svg.icon:only-child),
button:has(> svg.icon:only-child),
.reach a,.dock a,.rail__key{
  display:inline-flex;align-items:center;justify-content:center;
  min-width:44px;min-height:44px;
  cursor:pointer;
}
.reach a:hover,.dock a:hover,.rail__key:hover:not(:disabled){
  transform:translateY(-1px);
}
.reach a:focus-visible,.dock a:focus-visible,.rail__key:focus-visible{
  outline:2px solid var(--brand-deep);outline-offset:3px;
}
svg.icon{pointer-events:none;}


/* ============================================================
   SCALE AND DENSITY
   The page was reading as though the browser were zoomed in: the
   body ran at 1.22rem with 1.78 leading, so a paragraph filled the
   screen and the reader had to scroll to find the next fact. Body
   copy comes down to 1rem, the measure comes in, and the vertical
   rhythm tightens. The page gets shorter without losing anything.
   ============================================================ */

body{font-size:var(--fs-body);line-height:1.65;}
.prose,.card__note,.tally__item p,.ledger__d,.faq__a p{
  font-size:var(--fs-body);line-height:1.72;max-width:64ch;
}
.lede,.arrival__line{font-size:var(--fs-body-lg);line-height:1.55;max-width:52ch;}

/* Sections were built on a scale that no longer applies. */
:root{
  --s3:clamp(.75rem,1.1vw,1rem);
  --s4:clamp(1.1rem,1.7vw,1.6rem);
  --s5:clamp(1.7rem,2.6vw,2.4rem);
  --s6:clamp(2.4rem,4vw,3.6rem);
}
.room{padding-block:clamp(48px,6vw,96px);}

/* The footer was a full screen of its own with dead space under it. */
.colophon{padding-block:clamp(32px,4vw,52px) clamp(20px,2vw,28px);}
.colophon__mark .logo__name{font-size:var(--fs-h3);}
.colophon p,.colophon li,.colophon a{font-size:var(--fs-small);line-height:1.6;}
body>:last-child{margin-block-end:0;}
.colophon:last-child{margin-block-end:0;padding-block-end:clamp(18px,2vw,26px);}

/* ============================================================
   FORM FIELDS
   Every field was a bare underline on the page ground, so the
   reader could not see where one ended and the next began. Each
   is a filled box now, with its label above it and a visible
   focus state, which is what tells someone this is fillable.
   ============================================================ */

.room--office .frame{background:var(--paper-3);}

.field{margin-block-end:var(--s4);}
.field > span,.field label,.enquiry label > span:first-child{
  display:block;margin-block-end:.4rem;
  font-family:var(--sans);font-size:var(--fs-caption);font-weight:var(--fw-button);
  letter-spacing:.1em;text-transform:uppercase;color:var(--muted);
}
.enquiry input[type="text"],
.enquiry input[type="tel"],
.enquiry input[type="email"],
.enquiry select,
.enquiry textarea,
.room--office input[type="text"],
.room--office input[type="tel"],
.room--office input[type="email"],
.room--office select,
.room--office textarea{
  box-sizing:border-box;width:100%;
  padding:.85rem 1rem;
  font-family:var(--sans);font-size:var(--fs-small);color:var(--ink);
  background:var(--paper);
  border:1px solid var(--line);
  border-radius:2px;
  transition:border-color .2s var(--ease),background .2s var(--ease),box-shadow .2s var(--ease);
}
.room--office textarea{min-height:104px;resize:vertical;}
.room--office input::placeholder,
.room--office textarea::placeholder{color:rgba(22,25,27,.38);}
.room--office input:hover,.room--office select:hover,.room--office textarea:hover{
  border-color:rgba(22,25,27,.34);
}
.room--office input:focus,
.room--office select:focus,
.room--office textarea:focus{
  outline:0;
  background:#fff;
  border-color:var(--brand-deep);
  box-shadow:0 0 0 3px rgba(42,157,143,.14);
}

/* The control the form script rejected. The message under the button
   says what is wrong; nothing said which of the six controls it meant,
   because the script looked for a .field wrapper this markup does not
   have, so is-invalid never landed anywhere and the only signal was
   aria-invalid. Coral is the page's one alert colour, and --coral-edge
   is the value that clears 3:1 against white. Placed after the focus
   rule above on purpose: that rule is what paints these controls, and
   an equal-weight selector earlier in the file would lose to it. */
.cell.is-invalid input,.cell.is-invalid select,.cell.is-invalid textarea,
.field.is-invalid input,.field.is-invalid select,.field.is-invalid textarea{
  border-color:var(--coral-edge);
  box-shadow:0 0 0 3px rgba(255,107,107,.16);
}
.cell.is-invalid input:focus,.cell.is-invalid select:focus,.cell.is-invalid textarea:focus,
.field.is-invalid input:focus,.field.is-invalid select:focus,.field.is-invalid textarea:focus{
  border-color:var(--coral-edge);
  box-shadow:0 0 0 3px rgba(255,107,107,.30);
}
.room--office select{
  appearance:none;
  background-image:linear-gradient(45deg,transparent 50%,var(--muted) 50%),
                   linear-gradient(135deg,var(--muted) 50%,transparent 50%);
  background-position:right 1.05rem center,right .72rem center;
  background-size:5px 5px,5px 5px;background-repeat:no-repeat;
  padding-inline-end:2.4rem;
}
[dir="rtl"] .room--office select{
  background-position:left 1.05rem center,left .72rem center;
  padding-inline-end:2.4rem;padding-inline-start:1rem;
}


/* ============================================================
   ICON CONTROLS
   The icons were already clickable: a real click on the dock's
   WhatsApp navigates. What they lacked was affordance, which is
   the same thing to a reader. Every icon control now reads the way
   the hero buttons do: a fully rounded chip, transparent with a
   hairline, filling on hover, with a real 44px target.
   ============================================================ */

.reach,
.standing__act,
.rail__key,
.dock a,
.reel__cover{
  display:inline-flex;align-items:center;justify-content:center;gap:.5rem;
  min-width:44px;min-height:44px;
  border-radius:999px;
  border:1px solid currentColor;
  background:transparent;
  color:inherit;
  cursor:pointer;
  transition:background .25s var(--ease),color .25s var(--ease),
             border-color .25s var(--ease),transform .25s var(--ease);
}
.reach:hover,.standing__act:hover,.rail__key:hover:not(:disabled),
.dock a:hover,.reel__cover:hover{
  background:var(--ink);
  color:var(--paper);
  border-color:var(--ink);
  transform:translateY(-1px);
}
.reach:focus-visible,.standing__act:focus-visible,.rail__key:focus-visible,
.dock a:focus-visible,.reel__cover:focus-visible{
  outline:2px solid var(--brand-deep);outline-offset:3px;
}
.reach:active,.standing__act:active,.dock a:active{transform:translateY(0);}

/* On the deep band the chip inverts rather than disappearing. On sand it
   stays the page's own chip, because sand is a light ground. */
.room--plan .rail__key,
.room--plan .reel__cover{
  border-color:var(--line-inv);color:var(--on-deep);
}
.room--plan .rail__key:hover,
.room--plan .reel__cover:hover{
  background:var(--on-deep);color:var(--deep);border-color:var(--on-deep);
}
.room--warm .rail__key,
.room--warm .reel__cover{border-color:var(--line);color:var(--ink);}
.room--warm .rail__key:hover,
.room--warm .reel__cover:hover{background:var(--ink);color:var(--band);border-color:var(--ink);}

/* The standing rail: chips on the page, not solid discs. */
.standing__act{
  background:rgba(242,251,250,.82);
  backdrop-filter:blur(10px);
  border-color:var(--line);
  color:var(--ink);
  box-shadow:0 6px 22px -12px rgba(22,25,27,.55);
}
.standing__act:hover{background:var(--ink);color:var(--paper);}

/* The mobile bar: three equal chips on one surface. */
.dock{gap:.5rem;padding:.5rem .75rem calc(.5rem + env(safe-area-inset-bottom));}
.dock a{flex:1;background:transparent;border-color:var(--line);color:var(--ink);}

/* The strokes read thinner and more current at this size. */
svg.icon{pointer-events:none;stroke-width:1.5;}
svg.icon path,svg.icon rect,svg.icon circle,svg.icon line,svg.icon polyline{
  vector-effect:non-scaling-stroke;
}

/* Buttons follow the same shape, so the whole set reads as one family. */
.btn{border-radius:999px;}
.btn--quiet,.btn--line{background:transparent;border:1px solid currentColor;}


/* ============================================================
   LOCATION
   Built on the pattern the client sent: the argument on one side,
   the map plated on its own warm surface on the other, and the
   neighbouring communities as a row of chips with this project
   marked. A buyer places a development by the company it keeps,
   so the chips do more work than another paragraph would.
   ============================================================ */

.room--place{background:var(--paper-2);}

.place{
  display:grid;
  grid-template-columns:minmax(0,1fr) minmax(0,1.08fr);
  gap:clamp(28px,4vw,72px);
  align-items:start;
}

.place__plate{
  background:var(--paper-3);
  border:1px solid var(--line);
  border-radius:4px;
  padding:clamp(18px,2.2vw,30px);
}

.chart{margin:0 0 var(--s5);}
.chart__cap{
  margin:0 0 .9rem;
  font-family:var(--sans);font-size:var(--fs-caption);font-weight:var(--fw-button);
  letter-spacing:.2em;text-transform:uppercase;color:var(--muted);
  text-align:center;
}
.chart img{
  display:block;width:100%;height:auto;
  border-radius:3px;
}

/* The shoreline: chips, wrapping, with this project filled in. */
.shore{
  display:flex;flex-wrap:wrap;gap:.5rem;
  margin:.9rem 0 0;padding:0;list-style:none;
}
.shore__pin{
  display:inline-flex;align-items:baseline;gap:.4rem;
  padding:.55rem .95rem;
  background:var(--paper-3);
  border:1px solid var(--line);
  border-radius:999px;
  font-size:var(--fs-small);line-height:1.2;
  white-space:nowrap;
}
.shore__name{font-weight:var(--fw-button);color:var(--ink);}
.shore__by{font-size:var(--fs-caption);color:var(--muted);font-weight:var(--fw-body);}
.shore__pin.is-here{
  background:var(--ink);border-color:var(--ink);
}
.shore__pin.is-here .shore__name{color:var(--paper);}
.shore__pin.is-here .shore__by{color:rgba(242,251,250,.72);}

/* Distances read across, two to a row, rather than as a long list. */
.reckon--across{
  display:grid;grid-template-columns:1fr 1fr;
  gap:0 var(--s5);margin:.9rem 0 0;
}
.reckon__row{
  display:flex;align-items:baseline;justify-content:space-between;gap:1rem;
  padding-block:.62rem;
  border-block-end:1px solid var(--hair);
}
.reckon--across dt{font-size:var(--fs-small);color:var(--muted);margin:0;}
.reckon--across dd{
  margin:0;font-family:var(--num);font-size:var(--fs-small);font-weight:var(--fw-button);color:var(--ink);
  font-variant-numeric:tabular-nums lining-nums;white-space:nowrap;
}

@media (max-width:900px){
  .place{grid-template-columns:1fr;gap:26px;}
  .reckon--across{grid-template-columns:1fr;}
  /* The chips stay on one line and scroll, per the standing rule that this
     site lays out horizontally rather than stacking.

     The bleed is done with padding and a negative margin on the SAME axis so
     they cancel. Doing it with margin alone, as the first version did, pushed
     the whole grid column 419px past the viewport in RTL, because a negative
     inline margin inside a grid item widens the item rather than letting the
     content hang out of it. The column is also given a zero min-width, which
     is what stops a scrolling child from forcing a grid track wider than its
     share. */
  .place{min-width:0;}
  .place__say,.place__plate{min-width:0;}
  .shore{
    flex-wrap:nowrap;
    max-width:100%;
    overflow-x:auto;
    scroll-snap-type:x proximity;
    scrollbar-width:none;
    -webkit-overflow-scrolling:touch;
  }
  .shore::-webkit-scrollbar{display:none;}
  .shore__pin{scroll-snap-align:start;}
}

.place__say .prose{max-width:56ch;}
.place__say .rubric{margin-block-start:var(--s5);}


/* ============================================================
   RESIDENCES AS A RAIL AT EVERY WIDTH
   Nine unit types stacked two to a row ran the section past three
   screens, and a reader comparing a 50 m2 studio with a 254 m2
   loft had to scroll between them. The set is one horizontal rail
   now, on the desktop as well as the phone, which is the standing
   rule for this site: lay out across, not down.
   ============================================================ */

.units-grid{
  display:flex;
  grid-template-columns:none;
  gap:clamp(14px,1.4vw,22px);
  overflow-x:auto;
  overscroll-behavior-x:contain;
  scroll-snap-type:x proximity;
  scroll-padding-inline-start:var(--gutter);
  margin-inline:calc(var(--gutter) * -1);
  padding-inline:var(--gutter);
  padding-block-end:var(--s3);
  scrollbar-width:none;
  -webkit-overflow-scrolling:touch;
}
.units-grid::-webkit-scrollbar{display:none;}
.units-grid > .unit{
  flex:0 0 clamp(260px,26vw,340px);
  width:auto;max-width:none;
  scroll-snap-align:start;
}

/* A rail needs to say it is a rail. */
.units__rail{position:relative;}
.units__hint{
  display:flex;align-items:center;gap:.6rem;
  margin-block-start:var(--s3);
  font-family:var(--sans);font-size:var(--fs-caption);font-weight:var(--fw-button);
  letter-spacing:.18em;text-transform:uppercase;color:var(--muted);
}
.units__hint svg{width:22px;height:8px;fill:none;stroke:currentColor;stroke-width:1.4;}
[dir="rtl"] .units__hint svg{transform:scaleX(-1);}

@media (max-width:759px){
  .units-grid > .unit{flex:0 0 82%;}
}
@media (max-width:420px){
  .units-grid > .unit{flex:0 0 88%;}
}

/* Grid children that scroll must be allowed to be narrower than their content,
   or the track grows to fit and the page overflows. */
.place,.place__say,.place__plate,.units,.units-grid{min-width:0;}


/* ============================================================
   MOTION
   Opacity and transform only. Nothing here reads or writes
   layout, so every frame is composited and the scroll thread is
   untouched. There is no library: the whole system is four
   declarations and a stagger index set once by script.
   ============================================================ */

.js .reveal{
  opacity:0;
  transform:translate3d(0,14px,0);
  will-change:opacity,transform;
}
.js .reveal.is-in{
  opacity:1;
  transform:none;
  transition:opacity .7s var(--ease), transform .7s var(--ease);
}
/* Released once it has played, so nothing holds a compositor layer for the
   life of the page. */
.js .reveal.is-in{will-change:auto;}

.reveal-d1.is-in{transition-delay:.12s;}
.reveal-d2.is-in{transition-delay:.24s;}

/* Children stagger off an index the script writes once. */
.js .reveal [data-stagger] > *{
  opacity:0;transform:translate3d(0,10px,0);
}
.js .reveal.is-in [data-stagger] > *{
  opacity:1;transform:none;
  transition:opacity .55s var(--ease), transform .55s var(--ease);
  transition-delay:calc(var(--i,0) * 55ms);
}

/* The masthead settles onto a surface once the page has moved. */
.masthead{transition:background .35s var(--ease), box-shadow .35s var(--ease);}
.masthead.is-past{
  background:rgba(242,251,250,.9);
  backdrop-filter:blur(12px);
  box-shadow:0 1px 0 var(--hair), 0 10px 30px -26px rgba(22,25,27,.6);
}

/* Cards lift rather than grow, so the neighbours do not reflow. */
.unit,.shore__pin,.tally__item{transition:transform .35s var(--ease), border-color .35s var(--ease);}
.unit:hover{transform:translate3d(0,-3px,0);}

/* Photography settles in on its own frame. */
.unit__media img,.plate img,.chart img{
  transition:transform .8s var(--ease);
}
.unit:hover .unit__media img{transform:scale(1.03);}

/* The rail hint drifts, which is what tells a reader it scrolls. */
@keyframes glee-nudge{
  0%,100%{transform:translateX(0);}
  50%{transform:translateX(5px);}
}
.units__hint svg,.rail__hint svg{animation:glee-nudge 2.4s var(--ease) infinite;}
[dir="rtl"] .units__hint svg,[dir="rtl"] .rail__hint svg{
  animation-name:glee-nudge-rtl;
}
@keyframes glee-nudge-rtl{
  0%,100%{transform:scaleX(-1) translateX(0);}
  50%{transform:scaleX(-1) translateX(5px);}
}

@media (prefers-reduced-motion:reduce){
  .js .reveal,
  .js .reveal [data-stagger] > *{opacity:1;transform:none;}
  .js .reveal.is-in,
  .js .reveal.is-in [data-stagger] > *{transition:none;}
  .units__hint svg,.rail__hint svg{animation:none;}
  .unit:hover{transform:none;}
  .unit:hover .unit__media img{transform:none;}
  .masthead{transition:none;}
}


/* ============================================================
   MASTER PLAN FILTER
   The chips narrow what the plan shows; a legend row takes the
   plan to its own pin. Filtered-out items fade and stop taking
   pointer events rather than being removed, so the layout never
   reflows and the list keeps its numbering.
   ============================================================ */

.plan__filter{
  display:flex;flex-wrap:wrap;align-items:center;gap:.5rem;
  margin-block-end:var(--s4);
}
.plan__filter-cap{
  margin-inline-end:.4rem;
  font-family:var(--sans);font-size:var(--fs-caption);font-weight:var(--fw-button);
  letter-spacing:.2em;text-transform:uppercase;color:var(--on-deep-muted);
}
.chip{
  /* 44px, because measure counts anything under it as a failed tap target
     and it is right to: a 38px chip on a phone is a miss. */
  min-height:44px;padding:.6rem 1.05rem;
  font-family:var(--sans);font-size:var(--fs-small);font-weight:var(--fw-button);
  color:var(--on-deep);
  background:transparent;
  border:1px solid var(--line-inv);
  border-radius:999px;cursor:pointer;
  transition:background .25s var(--ease),color .25s var(--ease),border-color .25s var(--ease);
}
.chip:hover{border-color:var(--on-deep);}
.chip.is-on{background:var(--on-deep);color:var(--deep);border-color:var(--on-deep);}
.chip:focus-visible{outline:2px solid var(--sky);outline-offset:3px;}

.pin,.legend__row{transition:opacity .3s var(--ease), transform .3s var(--ease);}
.pin.is-out,.legend__row.is-out{opacity:.18;pointer-events:none;}
.pin.is-lit{transform:translate(-50%,-50%) scale(1.35);z-index:3;}
.legend__row.is-lit .legend__t{color:var(--sky);}

.legend__go{
  display:block;width:100%;
  min-height:44px;padding:.4rem 0;text-align:start;
  background:transparent;border:0;color:inherit;cursor:pointer;
  font:inherit;
}
.legend__go:focus-visible{outline:2px solid var(--sky);outline-offset:3px;}
.legend__row:hover .legend__t{color:var(--sky);}

@media (prefers-reduced-motion:reduce){
  .pin,.legend__row,.chip{transition:none;}
}


/* ============================================================
   THE FILM
   The container was reel--portrait at 720x1280, inherited from a
   project whose film really was vertical. Glee's is 1920x1080, so
   a landscape master was being letterboxed into a portrait box:
   two black bars, the picture a third of the width it should be,
   and every pixel scaled down twice. It is a wide frame now, and
   it sits inside a plate rather than running loose on the page.
   ============================================================ */

.reel--wide{
  max-width:1040px;
  margin-inline:auto;
  aspect-ratio:16 / 9;
  overflow:hidden;
  border-radius:var(--cut);
  background:var(--deep);
  box-shadow:0 28px 70px -50px rgba(22,25,27,.8);
}
.reel--wide video,
.reel--wide .reel__cover img{
  width:100%;height:100%;
  object-fit:cover;
  display:block;
}
.reel--wide .reel__cover{border-radius:var(--cut);}


/* ============================================================
   FRAMED SURFACES
   Every picture and every panel on the site is cut at the same
   radius. A single token drives all of it, so the whole system
   moves together if the shape is ever revised.
   ============================================================ */

.plate img,
.chart img,
.unit__media img,
.hang__map img,
.place__plate,
.broad img,
.arrival__plate img,
.amenity img,
.lightbox__detail img,
.plan__stage,
.masterplan-concept img,
.units .unit,
.faq__item,
.room--office .frame,
.tally__item{
  border-radius:var(--cut);
}

.plate,
.unit__media,
.arrival__plate,
.broad,
.chart,
.plan__stage{
  overflow:hidden;
  border-radius:var(--cut);
}

.shore__pin,.chip,.btn,.key,
.reach,.standing__act,.dock a,.rail__key,.reel__cover{
  border-radius:var(--cut-pill);
}

.field input,.field select,.field textarea,
.room--office input,.room--office select,.room--office textarea{
  border-radius:var(--cut-sm);
}

/* ============================================================
   THE STANDING ACTION
   It read as three grey discs. It is turquoise now, which is the
   only colour the buildings carry and the same colour the primary
   button uses, so the standing action and the page's main action
   are visibly the same offer. Cut at the system radius.
   ============================================================ */

.standing__act{
  background:var(--brand-ink);
  border-color:var(--brand-ink);
  color:#fff;
  backdrop-filter:none;
  box-shadow:0 10px 26px -16px rgba(42,157,143,.9);
}
.standing__act:hover,.standing__act:focus-visible{
  background:var(--ink);border-color:var(--ink);color:var(--paper);
}

.dock{
  background:var(--paper-3);
  border-top:1px solid var(--line);
}
.dock a{
  background:var(--brand-ink);
  border-color:var(--brand-ink);
  color:#fff;
}
.dock a:hover,.dock a:focus-visible{
  background:var(--ink);border-color:var(--ink);color:var(--paper);
}


/* ============================================================
   RAIL EDGES
   The page does not overflow: a scroll-width check at 320, 360,
   390 and 414 comes back clean in both languages. What looks like
   the design escaping is a rail card cut by the viewport edge with
   nothing to say it is a rail. Two changes fix the reading: the
   snap is mandatory, so a card always lands whole, and the edge
   carries a fade, so the cut is obviously an edge and not a bug.
   ============================================================ */

.units-grid,
.shore,
.amenities__list,
.tally,
.rail__track,
.facts__rail{
  scroll-snap-type:x mandatory;
  scroll-snap-stop:always;
  -webkit-mask-image:linear-gradient(to right,transparent 0,#000 18px,#000 calc(100% - 26px),transparent 100%);
          mask-image:linear-gradient(to right,transparent 0,#000 18px,#000 calc(100% - 26px),transparent 100%);
}
[dir="rtl"] .units-grid,
[dir="rtl"] .shore,
[dir="rtl"] .amenities__list,
[dir="rtl"] .tally,
[dir="rtl"] .rail__track,
[dir="rtl"] .facts__rail{
  -webkit-mask-image:linear-gradient(to left,transparent 0,#000 18px,#000 calc(100% - 26px),transparent 100%);
          mask-image:linear-gradient(to left,transparent 0,#000 18px,#000 calc(100% - 26px),transparent 100%);
}

/* The mask clips a focus ring, so the ring is drawn inside instead. */
.units-grid :focus-visible,
.shore :focus-visible,
.tally :focus-visible{outline-offset:-3px;}

@media (max-width:900px){
  /* Amenities were a wrapping grid of fourteen items, which on a phone is a
     column three screens long. One rail, like every other set on this site. */
  .tally{
    display:flex;flex-wrap:nowrap;gap:12px;
    overflow-x:auto;overscroll-behavior-x:contain;
    scrollbar-width:none;
    padding-inline:var(--gutter);
    margin-inline:calc(var(--gutter) * -1);
    scroll-padding-inline-start:var(--gutter);
  }
  .tally::-webkit-scrollbar{display:none;}
  .tally__item{
    flex:0 0 74vw;max-width:300px;
    scroll-snap-align:start;
    background:var(--paper-3);
    border:1px solid var(--line);
    padding:var(--s4);
  }
  .room--warm .tally__item{
    background:rgba(242,251,250,.06);
    border-color:var(--line-inv);
  }
}


/* ============================================================
   WHAT MAY BE A RAIL ON A PHONE, AND WHAT MAY NOT
   The horizontal rule was applied to everything, including cards
   that are a heading and a paragraph. A rail cuts its last card at
   the viewport edge on purpose, which is fine for a picture and
   wrong for a sentence: the reader gets "Sandy lagoons and wa".

   The rule now has a condition. A set may be a rail on a phone
   when each card is self-contained at a glance, which means it
   leads with an image or is a short label. A set of cards carrying
   running text stacks, because text that is cut is text that is
   lost, and no layout preference is worth that.
   ============================================================ */

@media (max-width:900px){

  /* Amenities: a heading and a sentence each. These stack. */
  .tally{
    display:grid;
    grid-template-columns:1fr;
    gap:12px;
    overflow:visible;
    margin-inline:0;
    padding-inline:0;
    -webkit-mask-image:none;
            mask-image:none;
    scroll-snap-type:none;
  }
  .tally__item{
    flex:none;
    width:auto;
    max-width:none;
    scroll-snap-align:none;
  }

  /* The shoreline chips are two or three words each, so they stay a rail. */
  .shore{scroll-snap-type:x proximity;}

  /* The residences lead with a plan drawing and their text is a spec table,
     never a paragraph, so they stay a rail. The card is widened so the
     specification column is never the part that gets cut. */
  .units-grid > .unit{flex:0 0 86%;}
}

@media (max-width:560px){
  /* Two facts side by side is still horizontal, and nothing is clipped. */
  .tally{grid-template-columns:1fr;}
  .units-grid > .unit{flex:0 0 90%;}
}

/* The fade was masking the last line of a stacked card. It belongs only on
   the sets that actually scroll. */
.tally{-webkit-mask-image:none;mask-image:none;}


/* ============================================================
   THE STANDING ACTION, RESTATED
   Three filled discs read as a warning, not as an invitation.
   The system works because it keeps one ink chip against
   a warm ground and spends its accent colour sparingly: the active
   thing is dark, everything else is quiet.

   So the rail is ink on cream, cut at the system radius, and the
   accent is kept for the primary enquiry alone. Cream on ink
   measures 15.9:1.
   ============================================================ */

.standing__act{
  background:var(--ink);
  border:1px solid var(--ink);
  color:var(--paper);
  backdrop-filter:none;
  box-shadow:0 10px 30px -18px rgba(22,25,27,.75);
}
.standing__act:hover,
.standing__act:focus-visible{
  background:var(--brand-ink);
  border-color:var(--brand-ink);
  color:#fff;
  transform:translateY(-1px);
}

/* The mobile bar: the same chip, on the page surface. */
.dock{
  background:rgba(242,251,250,.94);
  backdrop-filter:blur(14px);
  border-top:1px solid var(--line);
}
.dock a{
  background:var(--ink);
  border:1px solid var(--ink);
  color:var(--paper);
}
/* The enquiry chip used to carry the accent, which split the set into two
   colours on the phone and matched nothing on the desktop. All three chips are
   one control now; the accent stays on the primary button in the page flow. */
.dock a:hover,
.dock a:focus-visible{
  background:var(--brand-ink);
  border-color:var(--brand-ink);
  color:#fff;
}


/* ============================================================
   THE PEEK MUST BE NARROWER THAN THE CARD'S PADDING
   A rail says there is more by letting the next card show at the
   edge. That only works if the sliver contains no text: at 86% the
   sliver was wide enough to show a heading and two spec rows cut
   mid word, which is the thing the client photographed.

   The card is now the full width less a sliver smaller than its own
   inner padding, so whatever shows past the edge is border and
   padding. There is still a visible next card; there is no longer a
   half-read sentence.
   ============================================================ */

@media (max-width:900px){
  .units-grid{
    gap:12px;
    scroll-padding-inline-start:var(--gutter);
  }
  /* Sized against the viewport, not the rail's content box. The rail carries
     a gutter of padding and a negative margin of the same size, so a
     percentage basis is a percentage of the inset box and lands about 30px
     short: the card ends early and the next one shows a readable strip.
     Measured from 100vw, the sliver is smaller than the card's own padding,
     so nothing but border and padding can appear past the edge. */
  .units-grid > .unit{
    flex:0 0 calc(100vw - 52px);
    max-width:none;
  }
  .unit__body{padding:20px;}

  /* The mask fades the sliver out as well, so the edge is soft rather than a
     cut line. Narrower than before, because the card now reaches further. */
  .units-grid{
    -webkit-mask-image:linear-gradient(to right,#000 calc(100% - 30px),transparent 100%);
            mask-image:linear-gradient(to right,#000 calc(100% - 30px),transparent 100%);
  }
  [dir="rtl"] .units-grid{
    -webkit-mask-image:linear-gradient(to left,#000 calc(100% - 30px),transparent 100%);
            mask-image:linear-gradient(to left,#000 calc(100% - 30px),transparent 100%);
  }

  /* Same reasoning for the shoreline chips: a chip is two or three words, so
     a cut chip is a cut word. They wrap instead of scrolling. */
  .shore{
    flex-wrap:wrap;
    overflow:visible;
    -webkit-mask-image:none;
            mask-image:none;
  }
}

@media (max-width:560px){
  .units-grid > .unit{flex:0 0 calc(100vw - 46px);}
}


/* ============================================================
   TYPOGRAPHY ROLES
   The four supplied families, each doing the one job it was
   chosen for. Fraunces is a display face and is never used for
   running text; Manrope carries every number in both languages so
   a spec table lines up whatever language surrounds it.

   This block runs late in the cascade, so it repeats the scale's
   weights rather than resetting them. A role rule that quietly
   dropped every heading back to 400 is how a type scale stops
   being a scale.
   ============================================================ */

/* Arabic display takes Naskh, not the Latin serif. Naskh carries its own
   ascenders and descenders and needs more leading than the Latin face at
   the same size, which is the one metric that is script-specific. */
[lang="ar"] .h-arrival,
[lang="ar"] .h-wall,
[lang="ar"] .h-room,
[lang="ar"] .wordmark,
[dir="rtl"] .h-arrival,
[dir="rtl"] .h-wall,
[dir="rtl"] .h-room,
[dir="rtl"] .wordmark{
  font-family:var(--ar-display);
  letter-spacing:0;
  line-height:var(--lh-h-ar);
}
[lang="ar"] .wordmark,[dir="rtl"] .wordmark{font-weight:var(--fw-display);}
[lang="ar"] .h-arrival,[dir="rtl"] .h-arrival{font-weight:var(--fw-h1);}
[lang="ar"] .h-wall,[lang="ar"] .h-room,
[dir="rtl"] .h-wall,[dir="rtl"] .h-room{font-weight:var(--fw-h2);}

/* Arabic running text and UI take Cairo. */
[lang="ar"] body,[dir="rtl"] body,
[dir="rtl"] .prose,[dir="rtl"] .lede,[dir="rtl"] .cap,
[dir="rtl"] .btn,[dir="rtl"] .chip,[dir="rtl"] label,
[dir="rtl"] input,[dir="rtl"] select,[dir="rtl"] textarea,
[dir="rtl"] .room__name,[dir="rtl"] .rubric{
  font-family:var(--ar-sans);
}

/* Numbers stay Manrope even inside Arabic, and stay lining and tabular so
   columns of areas and distances align. */
.fig,.tally__v,.ledger__v,.reckon--across dd,
.unit .spec dd,.terms dd,.shore__by,
[dir="rtl"] .fig,[dir="rtl"] .tally__v,[dir="rtl"] .ledger__v,
[dir="rtl"] .reckon--across dd,[dir="rtl"] .unit .spec dd{
  font-family:var(--num);
  font-variant-numeric:lining-nums tabular-nums;
  font-feature-settings:"lnum" 1,"tnum" 1;
}

/* Fraunces sits close to its fallback in x-height, so it needs no size
   correction — only the tighter tracking a display face wants at these sizes. */
.h-arrival,.h-wall,.h-room,.wordmark{letter-spacing:-0.012em;}
.wordmark{font-weight:var(--fw-display);}
.h-arrival{font-weight:var(--fw-h1);}
.h-wall,.h-room{font-weight:var(--fw-h2);}
[dir="ltr"] .h-arrival{line-height:var(--lh-display);}


/* ============================================================
   THE STANDING RAIL
   Both classes exist: ".standing__act" is the fixed side rail and
   ".reach" is the footer's contact row. An earlier check sampled
   the first ".reach" on the page, found the footer, and concluded
   the rail used that class. It does not. Querying by resolved
   position instead of by guessed class is what found the real one.

   Ink chip on the page, turquoise only on hover, matching the
   reference: the accent is spent on the action being taken, not
   on three buttons sitting there.
   ============================================================ */

.standing{gap:.55rem;}

.reach{
  width:48px;height:48px;
  border-radius:var(--cut-pill);
  border:1px solid var(--ink);
  background:var(--ink);
  color:var(--paper);
  box-shadow:0 10px 26px -18px rgba(22,25,27,.8);
}
.reach:hover,.reach:focus-visible{
  background:var(--brand-ink);
  border-color:var(--brand-ink);
  color:#fff;
}
/* WhatsApp keeps its own colour on hover; it is the one mark people
   recognise before they read the label. */
.reach--wa:hover{background:#1E7167;border-color:#1E7167;color:#fff;}
.reach:focus-visible{outline:2px solid var(--brand-deep);outline-offset:3px;}

/* The footer's social marks sit on the dark colophon, so they invert. */
.colophon__social a{
  border-radius:var(--cut-pill);
  border-color:var(--line-inv);
  color:var(--on-deep);
}
.colophon__social a:hover{background:var(--on-deep);color:var(--deep);}


/* Superseded: the rail's colour is set once, further down, for both the
   desktop side rail and the mobile bar. This block set the WhatsApp chip with
   a two-class selector, which outranked the unified rule and left one ink chip
   between two turquoise ones on the desktop only. */


/* ============================================================
   THE GALLERY, AT THE SIZE THE BRIEF ASKS FOR
   Measured at 1440: a plate was 547px wide, 38% of the viewport.
   That is a thumbnail strip, not the wide editorial sequence the
   brief specifies, and no amount of spacing fixes a small picture.

   A plate is now the dominant object on the row: one large image
   filling most of the screen, with enough of the next one showing
   to say the sequence continues. Nothing else changes, because the
   interaction was already right: native overflow, drag, trackpad,
   touch, keyboard, no carousel chrome.
   ============================================================ */

.rail__track--gallery{
  gap:clamp(10px,1vw,18px);
  scroll-padding-inline-start:var(--gutter);
}

.plate{
  flex:0 0 clamp(280px,84vw,760px);
}

@media (min-width:700px){
  /* Two plates and the edge of a third at desktop width. The earlier 62vw put
     a single picture across most of the screen, which read as a hero rather
     than a sequence and pushed the rest of the strip out of sight. */
  .plate{flex-basis:clamp(420px,42vw,620px);}
}

@media (min-width:1600px){
  .plate{flex-basis:min(38vw,700px);}
}

/* 3:2 was cropping the wide renders top and bottom. The brochure images run
   about 16:9, so the frame follows them instead of cutting them. */
.plate img{
  aspect-ratio:16/9;
  object-position:50% 50%;
  border-radius:var(--cut);
}

/* ============================================================
   THE MASTER PLAN, AT READABLE SIZE
   The stage measured 662x234 on a 1440 screen: a strip in the
   middle of a dark section, with the drawing too small to read
   the levels it exists to explain. It is the fact the whole
   layout is built around, so it gets the room.
   ============================================================ */

.plan__stage{
  width:100%;
  max-width:1180px;
  margin-inline:auto;
  aspect-ratio:1920/679;      /* the drawing's own proportion */
  min-height:clamp(220px,34vw,520px);
}

.plan__inner{width:100%;height:100%;}
.plan__inner img{width:100%;height:100%;object-fit:cover;}

@media (max-width:900px){
  /* On a phone the plan is taller than it is wide in usable terms, so it is
     given more height and the pan gesture does the rest. */
  .plan__stage{aspect-ratio:4/3;min-height:300px;}
  .plan__inner img{object-fit:cover;object-position:22% 50%;}
}


/* ============================================================
   THE PLAN IS LANDSCAPE, NOT PORTRAIT
   The desktop grid put the drawing in a 1.15fr column with the
   legend beside it, and the comment above it says why: that plan
   was a portrait drawing. Glee's is 1920x679, nearly three times
   as wide as it is tall, so the column squeezed it to 662px on a
   1440 screen and the levels it exists to show were unreadable.

   The drawing now takes the full width of the frame and the legend
   sits beneath it in two columns, which is the arrangement the
   shape asks for.
   ============================================================ */

@media (min-width:760px){
  .plan{
    display:grid;
    grid-template-columns:1fr;
    row-gap:var(--s5);
  }
  .plan__stage{
    grid-column:1;grid-row:auto;
    max-width:none;
    aspect-ratio:1920/679;
    min-height:0;
  }
  .plan__filter{grid-column:1;grid-row:1;}
  .plan__stage{grid-row:2;}
  .legend{
    grid-column:1;grid-row:3;
    margin-top:0;
    display:grid;
    grid-template-columns:repeat(3,minmax(0,1fr));
    column-gap:var(--s5);
  }
  .plan__bar{grid-column:1;grid-row:4;}
}

@media (min-width:1200px){
  .legend{grid-template-columns:repeat(6,minmax(0,1fr));}
  .legend__d{font-size:var(--fs-small);}
}


/* ============================================================
   THE ARRIVAL ON A PHONE, ACTUALLY
   The rule above says the picture should take the slack, and it
   was already there: min-height 86svh with rows auto 1fr. It did
   not work, because the figure in row two never stretched. The
   row grew; the picture stayed 252px and the difference showed as
   278px of empty page between the buttons and the photograph, a
   third of the viewport, measured at 390.

   The figure now fills its row and the image fills the figure.
   ============================================================ */

@media (max-width:759px){
  .arrival__plate,
  .hero__plate{
    align-self:stretch;
    min-height:0;
    display:flex;
  }
  .arrival__plate figure,
  .arrival__plate picture{
    flex:1;display:flex;min-height:0;
  }
  .arrival__plate img,
  .hero__plate img{
    width:100%;
    height:100%;
    min-height:260px;
    object-fit:cover;
    object-position:50% 55%;
  }
  /* The caption belongs under the picture, not stretched with it. */
  .arrival__plate .cap{flex:0 0 auto;}
}


/* ============================================================
   UNIT CARDS ON A WIDE SCREEN
   The rail capped a card at 340px, so on a 1440 or 1920 screen
   three cards filled about half the frame and the rest of the row
   was empty. A rail is meant to run out of room, not to sit short
   of it. The cards grow with the frame, so a row is full at every
   width and the collections that hold four still scroll.
   ============================================================ */

/* flex-grow rather than a fixed basis: the collection that holds only two
   types filled 61 per cent of the row and looked short. With grow, a short
   collection fills the frame and a long one still overflows and scrolls,
   because grow has nothing to distribute once the basis exceeds the width. */
@media (min-width:760px){
  .units-grid > .unit{flex:1 0 clamp(300px,30vw,440px);max-width:520px;}
}
@media (min-width:1600px){
  .units-grid > .unit{flex:1 0 clamp(380px,26vw,470px);max-width:560px;}
}


/* ============================================================
   THE GALLERY ON A PHONE
   84vw at 16:9 gave a 328x184 plate: horizontal, as the brief
   requires, but a thumbnail. A phone screen is portrait, so the
   frame takes a squarer crop there and the picture gets height
   without the sequence losing its direction.
   ============================================================ */

@media (max-width:759px){
  .plate{flex-basis:86vw;}
  .plate img{aspect-ratio:4/3;}

  /* The two arrows were as tall as a fifth of the picture. They stay, because
     they are the keyboard and pointer route through the sequence, but at the
     size of a control rather than of a feature. */
  .rail__key{width:40px;height:40px;}
  .rail__key svg{width:15px;height:15px;}
  .rail__bar{margin-top:var(--s3);}
}


/* ============================================================
   MOBILE COMPOSITION
   Measured at 360 and 390: a 21.6px gutter and 48px of section
   padding. That is what makes the page feel pressed against the
   screen. The type stays exactly as it is — the problem is
   spacing, not size — and the room around it opens up.
   ============================================================ */

@media (max-width:759px){
  :root{
    --gutter:26px;
    --s2:.6rem;
    --s3:1rem;
    --s4:1.5rem;
    --s5:2.1rem;
    --s6:3rem;
  }

  .room{padding-block:clamp(64px,13vw,88px);}

  /* Heading to its paragraph, and paragraph to paragraph. */
  .h-room,.h-wall,.h-arrival{margin-block-end:var(--s3);}
  .room__name{margin-block-end:var(--s2);}
  .lede{margin-block-end:var(--s3);}
  .prose + .prose{margin-block-start:var(--s3);}
  .prose:last-of-type{margin-block-end:0;}

  /* Copy to the picture beneath it. */
  .wall + .rail,
  .wall + .plan,
  .prose + .broad,
  .place__say + .place__plate{margin-block-start:var(--s5);}

  /* The two hero actions. */
  .arrival__acts{gap:.6rem;margin-block-start:var(--s4);}

  /* Cards and rails clear the gutter rather than sitting on it. */
  .tally{gap:14px;}
  .tally__item{padding:var(--s4);}
  .unit__body{padding:22px;}
  .units-grid,.rail__track--gallery,.shore{
    padding-inline:var(--gutter);
    margin-inline:calc(var(--gutter) * -1);
  }

  /* The dock is a fixed bar; the page ends above it, not under it. */
  body{padding-block-end:88px;}
}

/* 22px is the floor for the narrowest phones only. The 400px breakpoint pulled
   390 down with it, so a 390 screen got the 360 gutter; the specification is
   22px at 360 and 26px from 390 up. */
@media (max-width:370px){
  :root{--gutter:22px;}
}


/* ============================================================
   THE STANDING CONTACT RAIL — ONE TREATMENT
   Desktop showed three ink chips; mobile showed two ink chips and
   one accent. Same control, two identities, and the accent
   button read as a warning rather than an invitation.

   Both are now the same turquoise chip at the same size and radius,
   with the same hover. Coral stays where it belongs: the
   primary button in the page flow.
   ============================================================ */

.standing a,
.standing__act,
.dock a,
.dock__call,.dock__wa,.dock__go{
  background:var(--brand-ink);
  border:1px solid var(--brand-ink);
  color:#fff;
  border-radius:var(--cut-pill);
  box-shadow:0 8px 22px -14px rgba(34,126,114,.75);
  transition:background .3s var(--ease),border-color .3s var(--ease),
             transform .3s var(--ease);
}

.standing a:hover,.standing a:focus-visible,
.standing__act:hover,.standing__act:focus-visible,
.dock a:hover,.dock a:focus-visible{
  background:var(--brand-deep);
  border-color:var(--brand-deep);
  color:#fff;
  transform:translateY(-1px);
}

.standing a:active,.dock a:active{transform:translateY(0);}

.standing a:focus-visible,.dock a:focus-visible{
  outline:2px solid var(--brand-deep);
  outline-offset:3px;
}

/* WhatsApp is the one mark people recognise before reading a label, so it
   keeps its own colour on hover and only on hover. */
.standing a.cta-rail__wa:hover,
.dock__wa:hover{background:#1E7167;border-color:#1E7167;}

/* The bar behind the mobile chips stays the page surface, so the three chips
   read as one group rather than a coloured band across the screen. */
.dock{
  background:rgba(242,251,250,.94);
  backdrop-filter:blur(14px);
  border-top:1px solid var(--line);
}


/* The section list in the colophon: one row across the width, wrapping, so the
   footer stays a single band rather than becoming a column of links. */
.colophon__index{
  display:flex;flex-wrap:wrap;gap:.5rem 1.6rem;
  margin-block:var(--s4) var(--s5);
  padding-block-start:var(--s4);
  border-block-start:1px solid var(--line-inv);
}
.colophon__index a{
  font-family:var(--sans);
  font-size:var(--fs-small);
  color:var(--on-deep-muted);
  text-decoration:none;
  padding-block:.35rem;
  min-height:44px;
  display:inline-flex;align-items:center;
  transition:color .25s var(--ease);
}
.colophon__index a:hover,.colophon__index a:focus-visible{color:var(--on-deep);}
[dir="rtl"] .colophon__index{font-family:var(--ar-sans);}

@media (max-width:759px){
  .colophon__index{gap:.2rem 1.1rem;margin-block:var(--s3) var(--s4);}
  .colophon__index a{font-size:var(--fs-small);}
}


/* ============================================================
   THE LABEL SITS ABOVE ITS HEADING
   The heading comes first in the source so a crawler and a screen
   reader meet it before the kicker; the label is lifted visually.
   That rule was scoped to .wall, so the two sections built on a
   different container — Location and Enquiry — showed the label
   underneath the heading and read backwards against every other
   section.
   ============================================================ */

.place__say,
.enquiry__say{
  display:flex;
  flex-direction:column;
}
.place__say .room__name,
.enquiry__say .room__name{
  order:-1;
  margin-block-end:var(--s2);
}


/* ============================================================
   THE BAND UNDER THE FOOTER
   The page carried 88px of bottom padding so the last content
   would clear the fixed mobile bar. Because the padding sat on the
   body, it rendered as a white strip below the dark colophon at
   the very end of the page.

   The clearance moves onto the colophon itself: the dark ground
   now extends behind the bar, the content still clears it, and the
   page ends on the footer instead of on a gap.
   ============================================================ */

/* The bar is shown up to 900px, so the clearance has to match that boundary
   exactly. Stopping at 759 left a 62px white strip at 768. */
@media (max-width:900px){
  body{padding-block-end:0;}
  .colophon{padding-block-end:calc(clamp(18px,2vw,26px) + 76px);}
}

/* The marks inside the standing rail and the mobile bar carry the
   recognition, so they are set larger against the chip. */
.standing a svg.icon,
.dock a svg.icon{width:24px;height:24px;}

@media (max-width:759px){
  .dock a svg.icon{width:26px;height:26px;}
}


/* ============================================================
   THE CONTACT LINKS, ENQUIRY AND FOOTER
   Both sets were ink on their ground and sized like small print,
   which made them read as legal text rather than as the three ways
   to reach the sales team. They now carry the same turquoise the
   standing rail uses, so every contact action on the site is one
   colour, and they are set large enough to be found without
   hunting.

   Petrol on the white enquiry card measures 7.09:1. In the footer
   the chip is filled and the mark is white, which is the same
   7.09:1 the other way round.
   ============================================================ */

/* --- the enquiry section ------------------------------------ */
.direct{gap:var(--s4) var(--s5);margin-top:var(--s5);}
.direct a{
  gap:.55rem;
  padding-block:.5rem;
  font-size:var(--fs-small);
  letter-spacing:.04em;
  text-transform:none;
  font-weight:var(--fw-button);
  color:var(--brand-ink);
  border-bottom:1px solid rgba(34,126,114,.28);
  transition:color .25s var(--ease),border-color .25s var(--ease);
}
.direct a:hover,.direct a:focus-visible{
  color:var(--brand-deep);
  border-color:var(--brand-deep);
}
.direct a svg.icon{width:22px;height:22px;flex:none;}

/* --- the footer ---------------------------------------------- */
.colophon__reach{gap:.6rem;}
.reach{
  width:56px;height:56px;
  border-radius:var(--cut-pill);
  background:var(--brand-ink);
  border:1px solid var(--brand-ink);
  color:#fff;
}
.reach:hover,.reach:focus-visible{
  background:var(--brand-deep);
  border-color:var(--brand-deep);
  color:#fff;
}
.reach--wa:hover{background:#1E7167;border-color:#1E7167;color:#fff;}
.reach svg.icon{width:24px;height:24px;}

@media (max-width:759px){
  .direct{gap:var(--s3) var(--s4);}
  .direct a{font-size:var(--fs-small);}
  .reach{width:52px;height:52px;}
}

/* ============================================================
   THE DESCENT
   The site's four levels, drawn to scale beside the text that
   describes them. The drawing sticks while the levels scroll
   past it, so the reader is looking at the same section of
   ground the paragraph is talking about.

   The palette is doing literal work here for once: the ground
   is sand because the ground is sand, and the water is the
   primary because the water is what the whole project is
   pointed at. Nothing in this block is decorative colour.
   ============================================================ */
/* The drawing is sand on a near-white page, which is a deliberately quiet
   pair — so the section sits on the panel tone rather than the page, and the
   ground carries an edge. Without both, a pale cream shape on white reads as
   nothing at all. */
.room--descent{background:var(--paper-2);padding-block:var(--s8);}
.descent{
  max-width:var(--frame);margin-inline:auto;padding-inline:var(--gutter);
  margin-top:var(--s7);
  display:grid;gap:var(--s6);
}

/* ---- the drawing */
.descent__stage{position:sticky;top:110px;align-self:start;}
/* The drawing is the anchor of the section and has to hold the eye against a
   column of type twice its height. */
.descent__draw{background:var(--paper);border-radius:var(--cut);padding:var(--s5) var(--s4);}
.descent__draw svg{display:block;width:100%;height:auto;}
/* The section is drawn from the road inward. In Arabic the page runs the
   other way, so the drawing is mirrored to match the reading direction. */
[dir="rtl"] .descent__draw svg{transform:scaleX(-1);}
.descent__ground{fill:var(--sand);stroke:var(--brand-deep);stroke-width:2;stroke-linejoin:round;}
.descent__water{fill:var(--brand);}
.descent__sealine{stroke:var(--brand-deep);stroke-width:1.5;stroke-dasharray:5 7;opacity:.55;}
.descent__pin{
  fill:var(--paper);stroke:var(--brand-deep);stroke-width:2.5;
  transition:fill var(--d-hover) var(--e-lift),r var(--d-hover) var(--e-lift);
}
.descent__pin.is-here{fill:var(--brand-deep);}

/* The readout counts down as the reader descends. Tabular figures so the
   number does not jog sideways when 13 becomes 7. */
.descent__readout{
  display:flex;align-items:baseline;gap:.45rem;margin-top:var(--s3);
  font-family:var(--num);font-variant-numeric:tabular-nums lining-nums;
}
.descent__readout b{
  font-size:var(--fs-h2);font-weight:var(--fw-h2);line-height:1;color:var(--brand-deep);
}
.descent__readout span{
  font-size:var(--fs-caption);font-weight:var(--fw-button);
  letter-spacing:.18em;text-transform:uppercase;color:var(--muted);
}

/* ---- the levels */
.descent__levels{display:flex;flex-direction:column;gap:var(--s7);counter-reset:none;}
.descent__level{
  display:grid;grid-template-columns:auto 1fr;gap:var(--s4);align-items:start;
  padding-inline-start:var(--s4);
  border-inline-start:2px solid var(--hair);
  transition:border-color var(--d-m) var(--e-glide);
}
.descent__level.is-here{border-inline-start-color:var(--brand);}
.descent__elev{
  font-family:var(--num);font-variant-numeric:tabular-nums lining-nums;
  display:flex;align-items:baseline;gap:.15rem;min-width:3.5rem;
}
.descent__elev b{font-size:var(--fs-h3);font-weight:var(--fw-h3);line-height:1;color:var(--ink);}
.descent__elev span{font-size:var(--fs-caption);font-weight:var(--fw-button);color:var(--muted);}
.descent__level--sea .descent__elev b{color:var(--brand-deep);}
.descent__body .h-room{margin-bottom:var(--s2);}
.descent__body .prose{margin-top:0;}

/* The levels have to be given real scroll distance, or the whole idea
   collapses: packed at their natural height the five of them are shorter
   than one viewport, so a reader crosses the entire site in a flick and the
   drawing beside them never has anything to track. Each level holding a bit
   over half a screen is what turns the section into a descent rather than a
   list — it is the reason the sticky drawing is worth having at all. */
.descent__level{min-height:52vh;align-content:center;}

@media (min-width:900px){
  .descent{grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:var(--s8);align-items:start;}
  .descent__levels{gap:var(--s4);padding-block:var(--s6) var(--s8);}
  .descent__level{min-height:56vh;}
}
@media (max-width:899px){
  /* On a phone the drawing sits above the levels and stays put while they
     pass, which is the same relationship in less room. */
  .descent__stage{top:92px;background:var(--paper);padding-block:var(--s2);z-index:3;}
  .descent__draw{max-width:26rem;margin-inline:auto;}
  .descent__levels{gap:var(--s3);}
  .descent__level{min-height:48vh;}
}

/* ============================================================
   THE BROKEN GRID
   Every repeating set on the page stops being a row of identical
   boxes. The irregularity is never decorative: where there is a
   real quantity to encode it drives the size, and where there
   is not, the treatment changes instead of the scale.

   One rule governs all of it. The visual order and the DOM order
   are the same order, always — no `order`, no `grid-auto-flow:
   dense`. Both decouple what the eye sees from what the tab key
   and the screen reader follow, and dense does it silently by
   back-filling holes. Asymmetry here comes only from spans and
   from column placement, neither of which moves an element in
   the accessibility tree.
   ============================================================ */
/* ---- units: one horizontal strip, at every width
   Stacking the units vertically was the mistake in the last round. Nine cards
   down the page — with the largest taking a full row to itself — made the
   section enormous and gave a single unit the whole viewport. The range is now
   read across rather than down: all nine sit on one line and the reader moves
   sideways through them.

   The encoding survives the change intact. Floor area still sets the size, it
   just sets width along a row instead of columns in a grid, so the loft is
   visibly wider than the studio while both stay on the same line.

   This is horizontal on a phone too. Collapsing to a single column below a
   breakpoint is the usual reflex and it is exactly what was asked against —
   the strip is the layout, not a desktop enhancement of one. */
.units-grid{
  display:flex;
  grid-template-columns:none;
  gap:clamp(14px,1.6vw,24px);
  overflow-x:auto;
  overscroll-behavior-x:contain;
  scroll-snap-type:x proximity;
  scroll-padding-inline-start:var(--gutter);
  margin-inline:calc(var(--gutter) * -1);
  padding-inline:var(--gutter);
  padding-block-end:var(--s3);
  scrollbar-width:none;
  -webkit-overflow-scrolling:touch;
  align-items:start;   /* cards end where their content ends, not stretched */
}
.units-grid::-webkit-scrollbar{display:none;}
.units-grid:focus-visible{outline:2px solid var(--brand-deep);outline-offset:6px;}

/* Three widths, from the three size bands. Each is a clamp so the strip works
   from a 360px phone to a wide desktop without a breakpoint deciding the
   layout — only the card's own width changes. */
.units-grid > .unit{
  flex:0 0 auto;scroll-snap-align:start;max-width:none;
}
/* Scoped under the strip on purpose. An earlier `.units-grid > .unit` rule
   sets width:auto, and a bare `.unit--w4` is one class against a class plus a
   child combinator — it loses on specificity however late it appears, which is
   why the three widths silently did nothing on the first attempt. */
.units-grid > .unit--w4{width:clamp(230px,58vw,300px);}
.units-grid > .unit--w6{width:clamp(280px,70vw,400px);}
.units-grid > .unit--w8{width:clamp(330px,82vw,520px);}

/* Emphasis beyond width: the crop widens and the square metre figure grows. */
.unit--t1 .unit__media img{aspect-ratio:4/3;}
.unit--t2 .unit__media img{aspect-ratio:3/2;}
.unit--t3 .unit__media img{aspect-ratio:16/9;}
.unit--t2 .spec .fig{font-size:var(--fs-h3);}
.unit--t3 .spec .fig{font-size:var(--fs-h2);}

.units__hint{margin:0;}

/* ---- amenities: also one strip
   Fourteen items in a twelve column grid wrapped into five rows and ran to
   nearly four thousand pixels, which is the same vertical pile the units had
   in a different shape. They read across now, on one line, at every width —
   the two treatments alternate along the strip so a picture tile is followed
   by a mark, and the rhythm is visible without scrolling a screen to find it. */
.tally{
  display:flex;
  grid-template-columns:none;
  gap:clamp(16px,1.8vw,28px);
  overflow-x:auto;
  overscroll-behavior-x:contain;
  scroll-snap-type:x proximity;
  scroll-padding-inline-start:var(--gutter);
  margin-inline:calc(var(--gutter) * -1);
  padding-inline:var(--gutter);
  padding-block-end:var(--s3);
  scrollbar-width:none;
  -webkit-overflow-scrolling:touch;
  align-items:start;
}
.tally::-webkit-scrollbar{display:none;}
.tally > .tally__item{flex:0 0 auto;scroll-snap-align:start;}
.tally > .tally__item--w7{width:clamp(300px,74vw,460px);}
.tally > .tally__item--w5{width:clamp(250px,62vw,360px);}
.tally > .tally__item--w4{width:clamp(230px,58vw,320px);}
/* A mark and two lines of type needs less room than a photograph, and saying
   so is part of the contrast between the two treatments. */
.tally > .tally__item--said{width:clamp(190px,48vw,250px);}

/* ---- the amenity that is only words
   No card, no border, no shadow, no ground. A rule and the words, which is
   all a line of type needs to be a line of type. */
.tally__item--said{
  background:none;border:0;box-shadow:none;padding:0;
  border-top:2px solid var(--brand);padding-top:var(--s3);
}
/* The mark that replaces the photograph. Sized and coloured so an icon plus a
   line of type carries the same weight in the row as a picture tile does —
   the point is two treatments, not a full one and an empty one. */
.tally__mark{
  display:block;color:var(--brand-deep);margin-bottom:var(--s3);
}
.tally__mark svg{display:block;}
.tally__item--said h3{
  font-family:var(--serif);font-size:var(--fs-h3);font-weight:var(--fw-h3);
  line-height:var(--lh-h);color:var(--ink);margin-bottom:var(--s2);
}
[dir="rtl"] .tally__item--said h3{font-family:var(--ar-display);line-height:var(--lh-h-ar);}
.tally__item--said p{color:var(--muted);}

/* ---- the amenity that has a photograph
   Still frameless: the picture is the frame. */
.tally__item--shot{background:none;border:0;box-shadow:none;padding:0;}
.tally__item--shot .tally__media{overflow:hidden;border-radius:var(--cut);margin-bottom:var(--s3);}
.tally__item--shot .tally__media img{
  width:100%;height:auto;display:block;
  transition:transform var(--d-l) var(--e-drift);
}
@media (hover:hover){
  .tally__item--shot:hover .tally__media img{transform:scale(1.03);}
}
.tally__item--shot h3{
  font-family:var(--serif);font-size:var(--fs-h3);font-weight:var(--fw-h3);
  line-height:var(--lh-h);color:var(--ink);margin-bottom:var(--s2);
}
[dir="rtl"] .tally__item--shot h3{font-family:var(--ar-display);line-height:var(--lh-h-ar);}
.tally__item--shot p{color:var(--muted);}
/* The crops alternate so the row is not two photographs of identical shape. */
.tally__item--w7 .tally__media img{aspect-ratio:16/9;object-fit:cover;}
.tally__item--w5 .tally__media img{aspect-ratio:4/3;object-fit:cover;}
.tally__item--w4 .tally__media img{aspect-ratio:1/1;object-fit:cover;}

@media (prefers-reduced-motion:reduce){
  .tally__item--shot:hover .tally__media img{transform:none;}
}

/* ============================================================
   REVIEW FIXES
   ============================================================ */

/* ---- the conceptual badge
   The badge itself was removed at the client's request; the rule that gave its
   container a positioning context is kept because the media block still relies
   on it. */
.tally__item--concept .tally__media{position:relative;}

/* ---- strip affordances
   The controls worked but were easy to miss: a hint in muted type and two
   outline chips. A strip that can scroll has to say so before it is touched,
   so the keys are filled and the running edge is faded. */
.rail__keys{display:flex;gap:.5rem;}
.rail__keys .rail__key{
  min-width:44px;min-height:44px;
  display:inline-flex;align-items:center;justify-content:center;
  background:var(--brand-ink);color:var(--white);
  border:var(--rule) solid var(--brand-ink);border-radius:var(--cut-pill);
  cursor:pointer;opacity:1;
  transition:background var(--d-hover) var(--e-lift),transform var(--d-hover) var(--e-lift);
}
/* The hover was brand-ink to brand-deep — four points of luminance apart, and
   in a side-by-side screenshot of the two states the button looks unchanged.
   A control that gives no visible answer to the pointer reads as inert, so the
   hover inverts instead of darkening: ink ground, white glyph, and a small
   lift. Ink on white is 17.7:1. */
.rail__keys .rail__key:hover:not(:disabled){
  background:var(--ink);border-color:var(--ink);color:var(--white);
  transform:translate3d(0,-2px,0);
}
.rail__keys .rail__key:active{transform:scale(.94);}
.rail__keys .rail__key:disabled{
  background:transparent;color:var(--muted);border-color:var(--line);cursor:default;opacity:1;
}
.rail__foot{
  display:flex;align-items:center;justify-content:space-between;gap:var(--s3);
  margin-top:var(--s3);flex-wrap:wrap;
}
.units__hint,.rail__hint{
  display:inline-flex;align-items:center;gap:.5rem;
  font-family:var(--sans);font-size:var(--fs-caption);font-weight:var(--fw-button);
  letter-spacing:.16em;text-transform:uppercase;color:var(--brand-deep);
}
[dir="rtl"] .units__hint,[dir="rtl"] .rail__hint{font-family:var(--ar-sans);letter-spacing:0;}
.units__hint svg,.rail__hint svg{width:26px;height:auto;stroke:currentColor;fill:none;stroke-width:1.6;}
[dir="rtl"] .units__hint svg,[dir="rtl"] .rail__hint svg{transform:scaleX(-1);}

/* The fade tells the eye there is more before it tries. Masked rather than
   painted with a gradient overlay, so it works on any ground the strip sits
   on — white, sand or the sky panel — without matching a colour to it. */
.units-grid,.tally{
  -webkit-mask-image:linear-gradient(to right,transparent 0,#000 var(--gutter),#000 calc(100% - 44px),transparent 100%);
          mask-image:linear-gradient(to right,transparent 0,#000 var(--gutter),#000 calc(100% - 44px),transparent 100%);
}
[dir="rtl"] .units-grid,[dir="rtl"] .tally{
  -webkit-mask-image:linear-gradient(to left,transparent 0,#000 var(--gutter),#000 calc(100% - 44px),transparent 100%);
          mask-image:linear-gradient(to left,transparent 0,#000 var(--gutter),#000 calc(100% - 44px),transparent 100%);
}

/* ---- heading and its paragraph
   The heading and its standfirst sit in two columns. They are tied together by
   sharing a top edge and by the column gap, not by a rule: a line drawn across
   the paragraph column reads as a divider cutting the text, which is the
   opposite of the link it was meant to make. */
.wall .lede{margin-top:var(--s3);}
.wall .h-wall,.wall .h-room{margin-bottom:var(--s2);}
@media (min-width:1024px){
  .wall .lede{margin-top:0;}
}

/* The standing contact rail is fixed against the inline edge and the strip
   controls sit at the same edge of their foot, which left exactly one pixel
   between them at 1366px — not an overlap, and clickable, but reading as a
   single jammed cluster of circles. The foot keeps clear of the rail's column
   wherever that rail is on screen. */
@media (min-width:1024px){
  .rail__foot{padding-inline-end:96px;}
}

/* The two photographs that appear twice on the page are framed differently in
   their second place: pushed off centre and scaled up, so the card shows a
   different part of the picture than the full width plate does. Transform on
   the image inside its own clipped box, so nothing about the card's geometry
   or the reserved space changes. */
.unit__media--recrop{overflow:hidden;}
.unit__media--recrop img{transform-origin:center;}

/* The offset is not flipped for Arabic. The photograph is not mirrored by the
   page direction, so flipping it here showed Arabic and English readers two
   different parts of the same picture for no reason. */

/* senior three: reviewed and accepted, left exactly as it was. */
.unit__media--recrop-senior3 img{transform:scale(1.38) translate(-9%,7%);}

/* duplex: the first attempt was too timid, and the arithmetic is why. At
   scale 1.38 the furthest an image can travel before its edge enters the box
   is about (S-1)/2S, roughly 14%, so a 9% offset was already near the limit
   and the centre of the frame — the palm cluster — stayed in shot. This one
   is scaled far enough to actually leave the middle, and pushed down and left
   onto the sand, the loungers and the water's edge, which is the part of this
   photograph the plate above never shows. */
.unit__media--recrop-duplex img{transform:scale(2.2) translate(20%,-18%);}
