/* KAMRA — design system.
 *
 * The idea: qamar, the moon you steer by — carried by the crescent mark rather
 * than by the palette. Light is the default, because photographs of rooms are
 * the content here and they read better against a warm light ground; the dark
 * theme is the same room at night and is one click away. Everything below is
 * tokens first, components second, so the two themes are one stylesheet.
 *
 * Motion rule, enforced throughout: transform and opacity only. Nothing here
 * animates a property that triggers layout.
 */

/* ============================================================ 1. tokens  */

:root{
  /* --- light, the default -------------------------------------------
   * Property photography is the content here, and photographs read
   * better against a warm light ground than against black. The dark
   * theme below is unchanged and one click away on the toggle. */
  --paper:#F6F5F1;
  --surface:#FFFFFF;
  --surface-2:#FFFFFF;
  --surface-3:#F1EFE9;
  --ink:#121A17;
  --muted:#5A6B63;
  --line:#DCD8CE;
  --line-soft:#E9E6DE;
  --accent:#157350;
  --accent-ink:#0C4631;
  --accent-wash:#E8F0EA;
  --brass:#8A5D18;
  --on-accent:#FFFFFF;
  --danger:#B3261E;

  /* Glass is one recipe used in a few places, never as decoration on its own. */
  --glass:rgba(246,245,241,.82);
  --glass-line:rgba(18,26,23,.08);
  --glow:rgba(21,115,80,.07);

  --shadow-sm:0 1px 2px rgba(18,26,23,.05);
  --shadow:0 1px 2px rgba(18,26,23,.04), 0 12px 32px -18px rgba(18,26,23,.3);
  --shadow-lg:0 2px 6px rgba(18,26,23,.05), 0 32px 64px -28px rgba(18,26,23,.34);

  color-scheme:light;

  /* --- type ---------------------------------------------------------- */
  --font-display:"Instrument Serif", "Iowan Old Style", Georgia, serif;
  --font-body:"Karla", ui-sans-serif, system-ui, "Segoe UI", Helvetica, Arial, sans-serif;
  --font-mono:"IBM Plex Mono", ui-monospace, "SFMono-Regular", Consolas, monospace;

  --step--2:clamp(.68rem,.66rem + .1vw,.74rem);
  --step--1:clamp(.78rem,.76rem + .1vw,.84rem);
  --step-0:clamp(1rem,.97rem + .15vw,1.08rem);
  --step-1:clamp(1.2rem,1.1rem + .4vw,1.42rem);
  --step-2:clamp(1.65rem,1.4rem + 1vw,2.25rem);
  --step-3:clamp(2.3rem,1.8rem + 2.2vw,3.7rem);
  --step-4:clamp(3rem,2rem + 4.4vw,6.2rem);
  --step-5:clamp(3.6rem,2.1rem + 6.4vw,8.4rem);

  /* --- rhythm -------------------------------------------------------- */
  --radius:14px;
  --radius-sm:8px;
  --radius-lg:22px;
  --gutter:clamp(16px,3vw,28px);

  /* --- motion -------------------------------------------------------- */
  --ease-out:cubic-bezier(.16,1,.3,1);
  --ease:cubic-bezier(.4,0,.2,1);
  --t-fast:.18s;
  --t:.32s;
  --t-slow:.72s;
}

/* The dark theme, reached only by the toggle.
 *
 * Deliberately NOT wired to prefers-color-scheme. Most people run their OS in
 * dark, so honouring it would mean most visitors never see the light design —
 * which is the one this site is built around, and the one the photographs are
 * lit for. The toggle is one click and the choice is remembered, so anyone who
 * wants dark gets it and keeps it. To follow the OS instead, duplicate this
 * block inside `@media (prefers-color-scheme:dark){ :root:not([data-theme="light"]){ … } }`.
 */
:root[data-theme="dark"]{
  --paper:#080C0B;
  --surface:#0D1412;
  --surface-2:#131C19;
  --surface-3:#1A2521;
  --ink:#E9F0EC;
  --muted:#8A9D95;
  --line:#233029;
  --line-soft:#19231F;
  --accent:#5BC994;
  --accent-ink:#92E0BB;
  --accent-wash:#0F221A;
  --brass:#D9A758;
  --on-accent:#04110B;
  --danger:#F2B8B5;
  --glass:rgba(13,20,18,.72);
  --glass-line:rgba(233,240,236,.08);
  --glow:rgba(91,201,148,.16);
  --shadow-sm:0 1px 2px rgba(0,0,0,.5);
  --shadow:0 2px 4px rgba(0,0,0,.4), 0 18px 44px -24px rgba(0,0,0,.95);
  --shadow-lg:0 4px 8px rgba(0,0,0,.4), 0 40px 80px -32px rgba(0,0,0,1);
  color-scheme:dark;
}

/* ============================================================ 2. base    */

*,*::before,*::after{box-sizing:border-box}

html{scroll-behavior:smooth}

body{
  margin:0;
  background:var(--paper);
  color:var(--ink);
  font-family:var(--font-body);
  font-size:var(--step-0);
  line-height:1.6;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  overflow-x:hidden;
}

/* The aurora: two very soft radial washes pinned behind everything. Fixed and
   composited, so it costs nothing on scroll. In light mode it all but vanishes. */
body::before{
  content:"";position:fixed;inset:0;z-index:-1;pointer-events:none;
  background:
    radial-gradient(60% 50% at 78% 4%, var(--glow), transparent 70%),
    radial-gradient(45% 40% at 8% 32%, var(--accent-wash), transparent 72%);
  opacity:.85;
}

img,svg,video,canvas{max-width:100%}
img{height:auto}
[hidden]{display:none!important}

h1,h2,h3,h4{margin:0;text-wrap:balance}
h1,h2{font-family:var(--font-display);font-weight:400;line-height:.98;letter-spacing:-.022em}
h1{font-size:var(--step-4)}
h2{font-size:var(--step-3)}
h3{font-family:var(--font-body);font-size:var(--step-1);font-weight:600;line-height:1.3;letter-spacing:-.005em}
p{margin:0}
a{color:inherit}
em{font-style:italic;color:var(--brass)}

::selection{background:var(--accent);color:var(--on-accent)}

:focus-visible{outline:2px solid var(--accent);outline-offset:3px;border-radius:3px}
:focus:not(:focus-visible){outline:none}

/* Keyboard users get a way past the header on every page. */
.skip{
  position:absolute;inset-inline-start:-9999px;top:0;z-index:200;
  background:var(--accent);color:var(--on-accent);
  padding:12px 20px;border-radius:0 0 var(--radius-sm) 0;
  font-family:var(--font-mono);font-size:var(--step--1);letter-spacing:.08em;text-transform:uppercase;
  text-decoration:none;
}
.skip:focus{inset-inline-start:0}

/* ============================================================ 3. motion  */

/* Reveal on scroll. The element is already in the DOM and readable; JS only
   adds .is-in. Without JS the no-js rule below leaves everything visible.
 *
 * The offsets live in custom properties rather than in the transform itself,
 * because a property card is both a .reveal and a .tilt and only one rule can
 * own `transform`. Everything that moves an element composes these three, so
 * the two effects add up instead of cancelling each other out. Changing a
 * variable jumps its value, but the transform that reads it is transitioned,
 * so the movement still interpolates.
 */
.reveal{
  --rv-x:0px; --rv-y:22px; --rv-s:1;
  opacity:0;
  transform:translate3d(var(--rv-x),var(--rv-y),0) scale(var(--rv-s));
  transition:opacity var(--t-slow) var(--ease-out), transform var(--t-slow) var(--ease-out);
  transition-delay:var(--d,0ms);
  will-change:opacity,transform;
}
.reveal--left{--rv-x:-26px;--rv-y:0px}
.reveal--scale{--rv-y:0px;--rv-s:.965}
.reveal.is-in{--rv-x:0px;--rv-y:0px;--rv-s:1;opacity:1;will-change:auto}

/* Two ways content can never end up stranded invisible: JS switched off
   entirely (.no-js, set in the markup and removed by the head script), and
   JS that was meant to run but did not (.reveal-all, set by the head script's
   failsafe timer when site.js has not reported in). */
html.no-js .reveal,
html.reveal-all .reveal{opacity:1;--rv-x:0px;--rv-y:0px;--rv-s:1}

/* Parallax targets: JS writes --py, the element only ever moves on the GPU. */
.parallax{transform:translate3d(0,var(--py,0px),0);will-change:transform}

/* Tilt: JS writes the two angles, CSS owns the composition — including the
   reveal offsets above, so a card can arrive and then tilt. site.js clears
   --d once a card has arrived, otherwise the stagger delay would also delay
   the card settling back flat when the pointer leaves. */
.tilt{
  transform:perspective(900px) translate3d(var(--rv-x,0px),var(--rv-y,0px),0)
            rotateX(var(--rx,0deg)) rotateY(var(--ry,0deg)) scale(var(--rv-s,1));
  transition:transform var(--t) var(--ease-out), opacity var(--t-slow) var(--ease-out);
  transition-delay:var(--d,0ms);
}
.tilt.is-tilting{transition:transform .08s linear;transition-delay:0ms}

@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{
    animation-duration:.001ms!important;animation-iteration-count:1!important;
    transition-duration:.001ms!important;scroll-behavior:auto!important;
  }
  .reveal,.tilt{opacity:1!important;transform:none!important}
  .parallax{transform:none!important}
}

/* ============================================================ 4. layout  */

.wrap{
  width:100%;max-width:1240px;margin-inline:auto;
  padding-inline-start:max(var(--gutter),env(safe-area-inset-left,0px));
  padding-inline-end:max(var(--gutter),env(safe-area-inset-right,0px));
}
.wrap--wide{max-width:1480px}
.wrap--narrow{max-width:860px}

.band{padding-block:clamp(56px,8vw,128px);position:relative}
.band--tight{padding-block:clamp(36px,4.5vw,64px)}
.band--surface{background:var(--surface)}
.band--wash{background:var(--accent-wash)}

/* A hairline that fades out at both ends — used between bands. */
.rule{height:1px;border:0;margin:0;background:linear-gradient(to right,transparent,var(--line),transparent)}
.ticks{height:12px;background-image:repeating-linear-gradient(to right,var(--line) 0 1px,transparent 1px 28px)}

/* --- bento ---------------------------------------------------------- */
/* Twelve columns, dense packing, and each tile declares its own span.
   Below 720px every tile is full width, which is the only thing that works. */
.bento{
  display:grid;grid-template-columns:repeat(12,1fr);
  gap:clamp(12px,1.4vw,18px);grid-auto-flow:dense;
}
.bento__tile{
  grid-column:span 4;
  position:relative;overflow:hidden;min-width:0;
  background:var(--surface-2);
  border:1px solid var(--line-soft);
  border-radius:var(--radius);
  padding:clamp(20px,2.4vw,32px);
  display:flex;flex-direction:column;gap:12px;
  isolation:isolate;
  transition:border-color var(--t) var(--ease), background var(--t) var(--ease);
}
.bento__tile:hover{border-color:var(--line);background:var(--surface-3)}
.bento__tile--lg{grid-column:span 6}
.bento__tile--xl{grid-column:span 8}
.bento__tile--full{grid-column:1/-1}
.bento__tile--accent{
  background:linear-gradient(150deg,var(--accent-wash),var(--surface-2));
  border-color:color-mix(in srgb,var(--accent) 24%,transparent);
}
/* The faint number behind a tile's content. Same isolation trick as the
   button sheen, so it stays under the text wherever it sits in the markup. */
.bento__ghost{
  position:absolute;inset-inline-end:-.06em;bottom:-.34em;z-index:-1;
  font-family:var(--font-display);font-size:clamp(5rem,9vw,9rem);line-height:1;
  color:var(--ink);opacity:.045;pointer-events:none;user-select:none;
}
@media (max-width:1000px){
  .bento__tile,.bento__tile--lg{grid-column:span 6}
  .bento__tile--xl{grid-column:1/-1}
}
@media (max-width:720px){
  .bento__tile,.bento__tile--lg,.bento__tile--xl{grid-column:1/-1}
}

.cols{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:clamp(20px,3vw,40px)}
.split{display:grid;grid-template-columns:1fr 1fr;gap:clamp(24px,4.5vw,72px);align-items:center}
.split--start{align-items:start}
@media (max-width:860px){.split{grid-template-columns:1fr}}

.stack{display:flex;flex-direction:column;gap:18px;min-width:0}
.stack--sm{gap:10px}
.stack--lg{gap:26px}

/* ============================================================ 5. header  */

.site-head{
  position:sticky;top:0;z-index:50;
  background:var(--glass);
  -webkit-backdrop-filter:saturate(180%) blur(16px);
  backdrop-filter:saturate(180%) blur(16px);
  border-bottom:1px solid var(--glass-line);
  transition:border-color var(--t) var(--ease), box-shadow var(--t) var(--ease);
}
/* JS adds .is-stuck once the page has scrolled, so the bar only asserts
   itself when there is content behind it. */
.site-head.is-stuck{box-shadow:var(--shadow);border-bottom-color:var(--line-soft)}
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .site-head{background:var(--surface)}
}

.site-head__in{display:flex;align-items:center;gap:18px;min-height:72px;position:relative}

.brand{
  display:inline-flex;align-items:center;gap:10px;text-decoration:none;
  font-family:var(--font-display);font-size:1.5rem;letter-spacing:.1em;
}
.brand svg{flex:none;overflow:visible}
.brand__moon{transition:transform var(--t-slow) var(--ease-out)}
.brand:hover .brand__moon{transform:rotate(-18deg)}

.nav{display:flex;align-items:center;gap:6px;margin-inline-start:auto}
.nav a{
  position:relative;text-decoration:none;
  font-family:var(--font-mono);font-size:var(--step--2);letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted);padding:10px 12px;border-radius:999px;
  transition:color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.nav a:not(.btn):hover{color:var(--ink);background:var(--surface-2)}
/* The underline grows from the centre rather than wiping in from one side. */
.nav a:not(.btn)::after{
  content:"";position:absolute;inset-inline:12px;bottom:4px;height:1px;
  background:var(--brass);transform:scaleX(0);transform-origin:50% 50%;
  transition:transform var(--t) var(--ease-out);
}
.nav a:not(.btn):hover::after,
.nav a:not(.btn)[aria-current="page"]::after{transform:scaleX(1)}
.nav a[aria-current="page"]{color:var(--ink)}
/* The CTA keeps its own colour even when it is the current page. Without the
   second selector here, aria-current wins on /contact and paints near-white
   text onto the light green pill — 1.77:1, unreadable. */
.nav a.btn,
.nav a.btn[aria-current="page"]{color:var(--on-accent);margin-inline-start:8px}
.nav .btn::after{display:none}

.nav-toggle,.theme-toggle{
  background:none;border:1px solid var(--line);border-radius:999px;color:var(--ink);
  font:inherit;font-family:var(--font-mono);font-size:var(--step--2);
  letter-spacing:.1em;text-transform:uppercase;cursor:pointer;
  transition:border-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease), transform var(--t-fast) var(--ease-out);
}
.nav-toggle:hover,.theme-toggle:hover{border-color:var(--ink)}
.theme-toggle{
  display:inline-grid;place-items:center;width:40px;height:40px;padding:0;flex:none;margin-inline-start:4px;
}
.theme-toggle:active{transform:scale(.92)}
.theme-toggle svg{width:17px;height:17px;display:block}
/* One button, two glyphs: the icon shows the theme you would switch TO, so on
   the light default it offers a moon and in dark it offers a sun. */
.theme-toggle .i-sun{display:none}
.theme-toggle .i-moon{display:block}
:root[data-theme="dark"] .theme-toggle .i-sun{display:block}
:root[data-theme="dark"] .theme-toggle .i-moon{display:none}

.nav-toggle{display:none;padding:10px 18px}

@media (max-width:980px){
  .nav-toggle{display:inline-block;margin-inline-start:auto}
  .theme-toggle{order:3}
  .nav{
    position:absolute;inset-inline:0;top:100%;margin:0;
    flex-direction:column;align-items:stretch;gap:0;
    background:var(--surface);border-bottom:1px solid var(--line);
    padding:8px max(var(--gutter),env(safe-area-inset-left,0px)) 22px;
    box-shadow:var(--shadow-lg);
  }
  .nav a{
    padding:15px 2px;border-radius:0;border-bottom:1px solid var(--line-soft);
    font-family:var(--font-body);font-size:1.05rem;text-transform:none;letter-spacing:0;
  }
  .nav a:not(.btn):hover{background:none}
  .nav a:not(.btn)::after{display:none}
  .nav .btn{margin:18px 0 0;border-radius:999px;justify-content:center}
}

/* ============================================================ 6. parts   */

.btn{
  position:relative;overflow:hidden;isolation:isolate;
  display:inline-flex;align-items:center;justify-content:center;gap:8px;
  font-family:var(--font-mono);font-size:var(--step--1);letter-spacing:.1em;text-transform:uppercase;
  padding:14px 26px;border-radius:999px;border:1px solid var(--accent);
  background:var(--accent);color:var(--on-accent);text-decoration:none;cursor:pointer;
  transition:transform var(--t) var(--ease-out), box-shadow var(--t) var(--ease), background var(--t) var(--ease), border-color var(--t) var(--ease), color var(--t) var(--ease);
}
/* A sheen that crosses the button once on hover. The button isolates itself
   and this sits at z-index -1, which in a stacking context paints after the
   element's own background but before its text — so no label needs wrapping
   in a span to stay on top, and the sheen never intercepts a click. */
.btn::before{
  content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  background:linear-gradient(110deg,transparent 20%,rgba(255,255,255,.26) 50%,transparent 80%);
  transform:translateX(-120%);
}
.btn:hover::before{transform:translateX(120%);transition:transform .66s var(--ease-out)}
.btn:hover{transform:translateY(-2px);box-shadow:0 12px 28px -12px var(--accent)}
.btn:active{transform:translateY(0)}
.btn--ghost{background:transparent;color:var(--ink);border-color:var(--line)}
.btn--ghost:hover{background:var(--surface-2);border-color:var(--ink);box-shadow:none}
.btn--ghost::before{display:none}
.btn--sm{padding:9px 16px;font-size:var(--step--2)}
.btn--danger{background:transparent;color:var(--danger);border-color:var(--danger)}
.btn--danger:hover{background:var(--danger);color:var(--paper);border-color:var(--danger);box-shadow:none}
.btn--danger::before{display:none}

.eyebrow{
  font-family:var(--font-mono);font-size:var(--step--2);letter-spacing:.22em;text-transform:uppercase;
  color:var(--brass);display:flex;align-items:center;gap:12px;
}
.eyebrow::before{content:"";width:28px;height:1px;background:currentColor;flex:none}
.eyebrow a{text-decoration:none}

.lede{font-size:var(--step-1);line-height:1.5;color:var(--muted);max-width:56ch}
.prose{max-width:66ch;display:flex;flex-direction:column;gap:16px;color:var(--muted)}
/* .prose is a column of paragraphs. Put the class on a <p> itself and that <p>
   becomes a flex container, which blockifies every inline child — an <em> mid
   sentence then gets its own line and the sentence falls apart into fragments.
   A paragraph carrying the class stays a paragraph. */
p.prose{display:block}
.prose strong{color:var(--ink);font-weight:600}
.num{font-family:var(--font-mono);font-size:var(--step--2);letter-spacing:.18em;color:var(--brass)}
.count{font-family:var(--font-mono);font-size:var(--step--1);letter-spacing:.1em;color:var(--muted);margin-inline-start:auto}

/* ============================================================ 7. hero    */

.hero{
  display:grid;grid-template-columns:1.05fr .95fr;
  gap:clamp(24px,4vw,64px);align-items:center;
  padding-block:clamp(36px,4.5vw,64px);position:relative;
}
.hero__copy{display:flex;flex-direction:column;gap:22px;min-width:0;position:relative;z-index:2}
/* step-4, not step-5. The larger step is magazine-cover size and pushed the
   search panel off the first screen — on a property site that panel being
   reachable matters more than the headline being enormous. */
.hero h1{font-size:var(--step-4)}
.hero h1 em{display:block;color:var(--accent);font-style:italic}
.hero__actions{display:flex;flex-wrap:wrap;gap:12px}
.hero__art{min-width:0;position:relative;aspect-ratio:1/1}
.hero__art svg{width:100%;height:auto;display:block}


.coords{
  font-family:var(--font-mono);font-size:var(--step--2);letter-spacing:.12em;
  color:var(--muted);display:flex;flex-wrap:wrap;gap:20px;
}
@media (max-width:880px){
  .hero{grid-template-columns:1fr;gap:30px}
  /* Headline first on a phone, photograph under it. The carousel keeps its
     full width here — it is the product, not decoration, so it does not get
     shrunk the way the old abstract hero art did. */
  .hero__copy{order:1}
  .showcase{order:2}
  .hero__art{order:2;aspect-ratio:1/1;width:min(320px,72vw);margin-inline:auto}
}
@media (max-width:560px){
  /* A tall arch eats a phone screen, so it loses some height here without
     losing the shape. */
  .shots{aspect-ratio:4/5}
  .showcase .shots{width:min(100%,290px)}
}

/* ============================================================ 8. stats   */

.stats{
  display:grid;grid-template-columns:repeat(4,1fr);
  border:1px solid var(--line-soft);border-radius:var(--radius);
  background:var(--surface-2);overflow:hidden;
}
.stat{
  padding:24px 22px;border-inline-end:1px solid var(--line-soft);
  display:flex;flex-direction:column;gap:6px;
  transition:background var(--t) var(--ease);
}
.stat:hover{background:var(--surface-3)}
.stat:last-child{border-inline-end:0}
.stat b{
  font-family:var(--font-display);font-size:var(--step-2);font-weight:400;line-height:1;
  font-variant-numeric:tabular-nums;
}
.stat span{
  font-family:var(--font-mono);font-size:var(--step--2);letter-spacing:.14em;
  text-transform:uppercase;color:var(--muted);
}
@media (max-width:720px){
  .stats{grid-template-columns:repeat(2,1fr)}
  .stat:nth-child(2n){border-inline-end:0}
  .stat:nth-child(-n+2){border-bottom:1px solid var(--line-soft)}
}

/* ============================================================ 9. heads   */

.sec-head{
  display:flex;flex-wrap:wrap;align-items:flex-end;justify-content:space-between;
  gap:20px;margin-bottom:clamp(28px,3.5vw,48px);
}
.sec-head__text{display:flex;flex-direction:column;gap:14px;min-width:0}

/* ============================================================ 10. cards  */

.grid-props{display:grid;grid-template-columns:repeat(auto-fill,minmax(285px,1fr));gap:clamp(14px,1.8vw,22px)}

.prop{
  display:flex;flex-direction:column;min-width:0;padding:0;
  background:var(--surface-2);border:1px solid var(--line-soft);
  border-radius:var(--radius);overflow:hidden;
  text-align:start;font:inherit;color:inherit;cursor:pointer;text-decoration:none;
  transition:border-color var(--t) var(--ease), box-shadow var(--t) var(--ease), background var(--t) var(--ease);
}
.prop:hover{border-color:color-mix(in srgb,var(--accent) 50%,transparent);box-shadow:var(--shadow-lg);background:var(--surface-3)}
.prop__art{position:relative;aspect-ratio:4/3;background:var(--surface-3);overflow:hidden}
.prop__art img,.prop__art svg{width:100%;height:100%;display:block;object-fit:cover}
/* The image, not the card, takes the zoom — the border stays crisp. */
.prop__art img{transition:transform .7s var(--ease-out)}
.prop:hover .prop__art img{transform:scale(1.055)}
/* A gradient scrim so the tag stays legible over a bright photograph. */
.prop__art::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(to bottom,rgba(0,0,0,.34),transparent 42%);
}
.prop__tag{
  position:absolute;top:12px;inset-inline-start:12px;z-index:1;
  font-family:var(--font-mono);font-size:var(--step--2);letter-spacing:.12em;text-transform:uppercase;
  background:var(--glass);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);
  color:var(--ink);padding:6px 11px;border-radius:999px;border:1px solid var(--glass-line);
}
.prop__body{padding:18px;display:flex;flex-direction:column;gap:10px;flex:1}
.prop__title{
  font-family:var(--font-body);font-size:1rem;line-height:1.35;font-weight:600;margin:0;
  transition:color var(--t-fast) var(--ease);
}
.prop:hover .prop__title{color:var(--accent-ink)}
.prop__place{
  font-family:var(--font-mono);font-size:var(--step--2);letter-spacing:.1em;
  color:var(--muted);text-transform:uppercase;
}
.price{font-family:var(--font-mono);font-size:1.06rem;font-variant-numeric:tabular-nums;color:var(--ink)}
.price small{font-size:var(--step--2);letter-spacing:.12em;color:var(--muted);text-transform:uppercase}
.specs{
  display:flex;flex-wrap:wrap;gap:14px;margin-top:auto;padding-top:14px;
  border-top:1px solid var(--line-soft);
  font-family:var(--font-mono);font-size:var(--step--2);color:var(--muted);font-variant-numeric:tabular-nums;
}

/* ============================================================ 11. forms  */

.filters{
  display:flex;flex-wrap:wrap;gap:10px;align-items:center;
  padding:16px;background:var(--surface-2);
  border:1px solid var(--line-soft);border-radius:var(--radius);
}
.chip{
  font-family:var(--font-mono);font-size:var(--step--2);letter-spacing:.12em;text-transform:uppercase;
  padding:10px 16px;border-radius:999px;border:1px solid var(--line);
  background:transparent;color:var(--muted);cursor:pointer;text-decoration:none;
  display:inline-flex;align-items:center;
  transition:color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease), transform var(--t-fast) var(--ease-out);
}
.chip:hover{color:var(--ink);border-color:var(--ink);transform:translateY(-1px)}
.chip[aria-pressed="true"]{background:var(--accent);border-color:var(--accent);color:var(--on-accent)}

.field{display:flex;flex-direction:column;gap:7px;min-width:0}
.field label{
  font-family:var(--font-mono);font-size:var(--step--2);letter-spacing:.14em;
  text-transform:uppercase;color:var(--muted);
}
.field input,.field select,.field textarea{
  font-family:var(--font-body);font-size:.98rem;color:var(--ink);
  background:var(--surface);border:1px solid var(--line);
  border-radius:var(--radius-sm);padding:13px 14px;width:100%;
  transition:border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.field input::placeholder,.field textarea::placeholder{color:var(--muted);opacity:.7}
.field input:focus,.field select:focus,.field textarea:focus{
  outline:none;border-color:var(--accent);
  box-shadow:0 0 0 3px color-mix(in srgb,var(--accent) 18%,transparent);
}
.field textarea{resize:vertical;min-height:130px}

/* .field label is uppercase mono by default, which is wrong for a sentence. */
.field.consent label{
  display:flex;gap:11px;align-items:flex-start;
  font-family:var(--font-body);font-size:.9rem;line-height:1.5;
  letter-spacing:normal;text-transform:none;color:var(--ink);cursor:pointer;
}
.field.consent input{width:auto;flex:0 0 auto;margin-top:.3em;padding:0;accent-color:var(--accent)}
.form-note{font-size:.85rem;color:var(--muted);margin:0}
.form-note a{color:var(--accent-ink)}

/* ============================================================ 12. blocks */

.feature{display:flex;flex-direction:column;gap:10px;min-width:0}
.feature h3{font-size:1.08rem}
.feature p{color:var(--muted);font-size:.96rem}

.ledger{display:flex;flex-direction:column;border-top:1px solid var(--line)}
.ledger__row{
  display:grid;grid-template-columns:88px 1fr;gap:24px;
  padding:26px 14px;border-bottom:1px solid var(--line-soft);align-items:start;
  transition:background var(--t) var(--ease);
}
.ledger__row:hover{background:var(--surface-2)}
.ledger__row > div{min-width:0;display:flex;flex-direction:column;gap:7px}
.ledger__row p{color:var(--muted);font-size:.96rem}
@media (max-width:620px){.ledger__row{grid-template-columns:1fr;gap:8px}}

.checks{
  list-style:none;margin:0;padding:0;
  display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:13px 30px;
}
.checks li{display:flex;gap:11px;font-size:.96rem;color:var(--muted);min-width:0}
.checks li::before{content:"";flex:none;width:6px;height:6px;margin-top:9px;border-radius:50%;background:var(--brass)}

.card{
  background:var(--surface-2);border:1px solid var(--line-soft);
  border-radius:var(--radius);padding:clamp(22px,3vw,34px);
  display:flex;flex-direction:column;gap:16px;min-width:0;
}

.plate{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(112px,1fr));gap:1px;
  background:var(--line-soft);border:1px solid var(--line-soft);
  border-radius:var(--radius);overflow:hidden;margin:0;
}
.plate div{background:var(--surface-2);padding:15px;display:flex;flex-direction:column;gap:5px}
.plate dt{font-family:var(--font-mono);font-size:var(--step--2);letter-spacing:.14em;text-transform:uppercase;color:var(--muted)}
.plate dd{margin:0;font-size:.98rem;font-variant-numeric:tabular-nums}

.art-frame{
  aspect-ratio:16/9;overflow:hidden;border:1px solid var(--line-soft);
  border-radius:var(--radius);background:var(--surface-2);
}
.art-frame img,.art-frame svg{width:100%;height:100%;display:block;object-fit:cover}

/* ============================================================ 13. journal*/

.posts{display:flex;flex-direction:column;border-top:1px solid var(--line)}
.post{
  display:grid;grid-template-columns:160px 1fr auto;gap:26px;align-items:baseline;
  padding:26px 14px;border-bottom:1px solid var(--line-soft);text-decoration:none;
  transition:background var(--t) var(--ease), padding-inline-start var(--t) var(--ease-out);
}
.post:hover{background:var(--surface-2);padding-inline-start:24px}
.post time{
  font-family:var(--font-mono);font-size:var(--step--2);letter-spacing:.1em;
  text-transform:uppercase;color:var(--muted);
}
.post h3{font-size:1.14rem;font-weight:600;min-width:0;transition:color var(--t-fast) var(--ease)}
.post:hover h3{color:var(--accent-ink)}
.post span{
  font-family:var(--font-mono);font-size:var(--step--2);letter-spacing:.1em;
  color:var(--brass);text-transform:uppercase;
}
@media (max-width:700px){.post{grid-template-columns:1fr;gap:8px}.post:hover{padding-inline-start:14px}}

.article-body{display:flex;flex-direction:column;gap:16px;color:var(--muted);font-size:1.04rem;line-height:1.75}
.article-body p{max-width:64ch}

/* ============================================================ 14. footer */

.site-foot{
  background:var(--surface);border-top:1px solid var(--line);
  padding-block:clamp(48px,6vw,88px);margin-top:clamp(48px,7vw,112px);
}
.site-foot a{color:var(--muted);text-decoration:none;transition:color var(--t-fast) var(--ease)}
.site-foot a:hover{color:var(--ink)}
.foot-grid{display:grid;grid-template-columns:1.6fr 1fr 1fr 1.3fr;gap:36px}
.foot-col{display:flex;flex-direction:column;gap:11px;min-width:0;font-size:.93rem;color:var(--muted)}
.foot-col h4{
  margin:0;font-family:var(--font-mono);font-size:var(--step--2);letter-spacing:.16em;
  text-transform:uppercase;color:var(--ink);font-weight:400;
}
.foot-note{
  display:flex;flex-wrap:wrap;gap:12px;justify-content:space-between;
  margin-top:40px;padding-top:22px;border-top:1px solid var(--line-soft);
  font-family:var(--font-mono);font-size:var(--step--2);letter-spacing:.1em;color:var(--muted);
}
@media (max-width:820px){.foot-grid{grid-template-columns:repeat(2,1fr)}}
@media (max-width:520px){.foot-grid{grid-template-columns:1fr}}

.copyable{font-family:var(--font-mono);font-size:.85rem;word-break:break-word;color:var(--ink)}
.copy-btn{
  font-family:var(--font-mono);font-size:var(--step--2);letter-spacing:.12em;text-transform:uppercase;
  background:none;border:1px solid var(--line);border-radius:999px;color:var(--muted);
  padding:5px 12px;cursor:pointer;text-decoration:none;display:inline-flex;align-items:center;
  transition:color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.copy-btn:hover{color:var(--ink);border-color:var(--ink)}

/* ============================================================ 15. states */

.empty{
  border:1px dashed var(--line);border-radius:var(--radius);
  padding:clamp(26px,4vw,48px);display:flex;flex-direction:column;gap:10px;
  align-items:flex-start;color:var(--muted);background:var(--surface-2);
}
.empty b{font-family:var(--font-display);font-size:var(--step-1);font-weight:400;color:var(--ink)}

.toast{
  position:fixed;z-index:90;
  inset-inline-start:max(var(--gutter),env(safe-area-inset-left,0px));
  bottom:calc(var(--gutter) + env(safe-area-inset-bottom,0px));
  background:var(--surface-3);color:var(--ink);border:1px solid var(--line);
  padding:13px 20px;border-radius:999px;
  font-family:var(--font-mono);font-size:var(--step--1);letter-spacing:.08em;
  box-shadow:var(--shadow-lg);
  animation:toast-in .4s var(--ease-out);
}
@keyframes toast-in{from{opacity:0;transform:translate3d(0,14px,0)}to{opacity:1;transform:none}}

/* ============================================================ 16. drawer */

.drawer{position:fixed;inset:0;z-index:80;display:flex;justify-content:flex-end}
.drawer__scrim{
  position:absolute;inset:0;border:0;padding:0;cursor:pointer;
  background:rgba(4,10,8,.6);
  -webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px);
}
.drawer__panel{
  position:relative;width:min(540px,100%);background:var(--surface);overflow-y:auto;
  border-inline-start:1px solid var(--line);display:flex;flex-direction:column;gap:18px;
  padding-inline-start:max(22px,env(safe-area-inset-left,0px));
  padding-inline-end:max(22px,env(safe-area-inset-right,0px));
  padding-top:calc(24px + env(safe-area-inset-top,0px));
  padding-bottom:calc(32px + env(safe-area-inset-bottom,0px));
}
.drawer__close{
  align-self:flex-end;background:none;border:1px solid var(--line);border-radius:999px;
  color:var(--ink);font-family:var(--font-mono);font-size:var(--step--2);
  letter-spacing:.12em;text-transform:uppercase;padding:8px 15px;cursor:pointer;
}
.drawer__art{aspect-ratio:16/10;border:1px solid var(--line-soft);border-radius:var(--radius);overflow:hidden}
.drawer__art img,.drawer__art svg{width:100%;height:100%;display:block;object-fit:cover}

/* ============================================================ 17. trust   */

/* A row of partner / portal names. Text, not images: nobody has supplied logo
   files, and an <img> with no asset behind it is a broken site. Swap the span
   for an <img> inside the same <a> when real marks arrive. */
.logos{
  display:flex;flex-wrap:wrap;align-items:center;justify-content:center;
  gap:clamp(22px,4vw,56px);
  padding:22px 0;
}
.logos a,.logos span{
  font-family:var(--font-display);font-size:clamp(1.05rem,1.8vw,1.4rem);
  letter-spacing:.04em;color:var(--muted);text-decoration:none;
  opacity:.75;transition:opacity var(--t) var(--ease), color var(--t) var(--ease);
}
.logos a:hover{opacity:1;color:var(--ink)}
.logos img{max-height:30px;width:auto;filter:grayscale(1);opacity:.7}

/* ============================================================ 18. process */

/* Four steps with a hairline running behind them. The line is a ::before on
   the track rather than a border on each step, so it never breaks at the gaps
   and it disappears cleanly when the steps stack. */
.process{
  display:grid;grid-template-columns:repeat(4,1fr);
  gap:clamp(16px,2.4vw,30px);position:relative;
}
.process::before{
  content:"";position:absolute;inset-inline:0;top:19px;height:1px;
  background:linear-gradient(to right,transparent,var(--line) 12%,var(--line) 88%,transparent);
}
.step{display:flex;flex-direction:column;gap:12px;min-width:0;position:relative}
.step__dot{
  width:38px;height:38px;flex:none;border-radius:50%;
  display:grid;place-items:center;
  background:var(--paper);border:1px solid var(--line);
  font-family:var(--font-mono);font-size:var(--step--2);letter-spacing:.06em;color:var(--brass);
  transition:border-color var(--t) var(--ease), color var(--t) var(--ease), background var(--t) var(--ease);
}
.step:hover .step__dot{border-color:var(--accent);color:var(--accent);background:var(--accent-wash)}
.step h3{font-size:1.04rem}
.step p{color:var(--muted);font-size:.94rem}
@media (max-width:860px){
  .process{grid-template-columns:1fr 1fr}
  .process::before{display:none}
}
@media (max-width:540px){.process{grid-template-columns:1fr}}

/* ============================================================ 19. quotes  */

.quotes{display:grid;grid-template-columns:repeat(auto-fit,minmax(290px,1fr));gap:clamp(14px,1.8vw,22px)}
.quote{
  background:var(--surface-2);border:1px solid var(--line-soft);
  border-radius:var(--radius);padding:clamp(22px,2.6vw,32px);
  display:flex;flex-direction:column;gap:18px;min-width:0;
  transition:border-color var(--t) var(--ease), background var(--t) var(--ease);
}
.quote:hover{border-color:var(--line);background:var(--surface-3)}
.quote blockquote{
  margin:0;font-family:var(--font-display);font-size:var(--step-1);
  line-height:1.4;color:var(--ink);
}
.quote blockquote::before{content:"\201C";color:var(--brass);margin-inline-end:.08em}
.quote blockquote::after{content:"\201D";color:var(--brass)}
.quote figcaption{display:flex;align-items:center;gap:13px;margin-top:auto}
/* A monogram, not a stock face. Initials are honest; a stranger's photograph
   attached to a client quote is not. */
.quote__who{
  width:40px;height:40px;flex:none;border-radius:50%;
  display:grid;place-items:center;
  background:var(--accent-wash);border:1px solid var(--line);
  font-family:var(--font-mono);font-size:.8rem;letter-spacing:.04em;color:var(--accent-ink);
}
.quote__name{display:flex;flex-direction:column;gap:2px;min-width:0}
.quote__name b{font-size:.94rem;font-weight:600}
.quote__name span{
  font-family:var(--font-mono);font-size:var(--step--2);letter-spacing:.1em;
  text-transform:uppercase;color:var(--muted);
}

/* ============================================================ 20. gallery */

/* Every third tile goes wide, which breaks the grid out of a plain run of
   squares without needing a masonry library or any JS. */
.gallery{display:grid;grid-template-columns:repeat(4,1fr);gap:clamp(10px,1.2vw,16px)}
.shot{
  position:relative;display:block;overflow:hidden;min-width:0;
  aspect-ratio:1/1;border-radius:var(--radius);
  border:1px solid var(--line-soft);background:var(--surface-2);
  text-decoration:none;
  transition:border-color var(--t) var(--ease), box-shadow var(--t) var(--ease);
}
.shot:nth-child(3n+1){grid-column:span 2;aspect-ratio:2/1}
.shot:hover{border-color:color-mix(in srgb,var(--accent) 50%,transparent);box-shadow:var(--shadow-lg)}
.shot img{width:100%;height:100%;object-fit:cover;display:block;transition:transform .8s var(--ease-out)}
.shot:hover img{transform:scale(1.06)}
.shot__cap{
  position:absolute;inset-inline:0;bottom:0;padding:14px;
  display:flex;flex-direction:column;gap:3px;
  background:linear-gradient(to top,rgba(0,0,0,.76),transparent);
  opacity:0;transform:translateY(8px);
  transition:opacity var(--t) var(--ease), transform var(--t) var(--ease-out);
}
.shot:hover .shot__cap,.shot:focus-visible .shot__cap{opacity:1;transform:none}
.shot__cap b{color:#fff;font-size:.88rem;font-weight:600;line-height:1.3}
.shot__cap span{
  font-family:var(--font-mono);font-size:var(--step--2);letter-spacing:.1em;
  text-transform:uppercase;color:rgba(255,255,255,.78);
}
/* A caption that only exists on hover is invisible to a touch screen, which
   has no hover — so below the tablet breakpoint it is simply always on. */
@media (hover:none){.shot__cap{opacity:1;transform:none}}
@media (max-width:860px){.gallery{grid-template-columns:repeat(2,1fr)}}
@media (max-width:460px){
  .gallery{grid-template-columns:1fr}
  .shot,.shot:nth-child(3n+1){grid-column:span 1;aspect-ratio:4/3}
}

/* ============================================================ 21. signup  */

/* Paired form fields. Two up where there is room, one up where there is not —
   two 50% columns inside a card on a phone leaves inputs too narrow to type
   a real email address into. */
.form-row{display:grid;grid-template-columns:1fr 1fr;gap:14px}
@media (max-width:620px){.form-row{grid-template-columns:1fr}}

.signup{display:flex;flex-wrap:wrap;gap:10px;align-items:flex-start}
.signup .field{flex:1 1 240px}
.signup .btn{flex:none;align-self:stretch}
.signup__note{
  flex-basis:100%;font-size:.84rem;color:var(--muted);margin:0;
}
.signup__note a{color:var(--accent-ink)}
.said{
  flex-basis:100%;margin:0;padding:12px 16px;border-radius:var(--radius-sm);
  font-size:.9rem;border:1px solid var(--accent);background:var(--accent-wash);color:var(--ink);
}
.said--bad{border-color:var(--danger);background:transparent}

/* ============================================================ 22. locate  */

/* A drawn location card, not an embedded map. The privacy notice promises no
   third-party trackers and a Google Maps iframe is exactly that; this links
   out to a map instead, which loads nothing until the visitor asks. */
.locate{
  display:grid;grid-template-columns:1.1fr .9fr;gap:clamp(20px,3vw,44px);
  align-items:stretch;
}
.locate__card{
  background:var(--surface-2);border:1px solid var(--line-soft);
  border-radius:var(--radius);padding:clamp(22px,3vw,34px);
  display:flex;flex-direction:column;gap:20px;min-width:0;
}
.locate__rows{display:flex;flex-direction:column;gap:16px}
.locate__row{display:flex;flex-direction:column;gap:4px;min-width:0}
.locate__plan{
  position:relative;overflow:hidden;min-height:260px;
  border:1px solid var(--line-soft);border-radius:var(--radius);
  background:var(--surface-2);
}
.locate__plan svg{width:100%;height:100%;display:block}
@media (max-width:860px){.locate{grid-template-columns:1fr}}

/* ============================================================ 24. hero shot */

/* The hero leads with photography, but not in a portal's rounded rectangle
   with arrows on the sides. The frame is a Moorish arch — Tétouan's own
   architecture, and the one shape on this page that could not belong to
   anybody else's site. Navigation is a strip of thumbnails underneath: you
   can see what you are moving to, which arrows never tell you.

   Slides are stacked and crossfaded rather than translated along a track: no
   width maths, no clones, and any number of slides works. The whole thing
   degrades to the first slide with no JavaScript at all. */
.shots{
  position:relative;overflow:hidden;min-width:0;
  /* 4/5 rather than 3/4: tall enough to read as an arch, short enough that
     the hero does not push the search panel below the fold. */
  aspect-ratio:4/5;
  /* A dome on top, a gentle radius at the floor. The horizontal/vertical
     split is what keeps it an arch instead of a lozenge. */
  border-radius:48% 48% var(--radius) var(--radius) / 34% 34% var(--radius) var(--radius);
  background:var(--surface-3);
  box-shadow:var(--shadow-lg);
}
/* A hairline following the arch, set just inside it. */
.shots::before{
  content:"";position:absolute;inset:0;z-index:3;pointer-events:none;
  border:1px solid color-mix(in srgb,var(--brass) 46%,transparent);
  border-radius:inherit;
}
.shots__slide{
  position:absolute;inset:0;display:block;text-decoration:none;
  opacity:0;visibility:hidden;
  transition:opacity .9s var(--ease-out), visibility 0s linear .9s;
}
.shots__slide.is-on{opacity:1;visibility:visible;transition:opacity .9s var(--ease-out)}
/* Without JS nothing gets .is-on, so the first slide has to stand alone. */
html.no-js .shots__slide:first-child{opacity:1;visibility:visible}
.shots__slide img{width:100%;height:100%;object-fit:cover;display:block}
.shots__slide::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(to top,rgba(0,0,0,.82) 0%,rgba(0,0,0,.35) 32%,transparent 62%);
}

/* The arch and its thumbnail strip travel together. */
.showcase{display:flex;flex-direction:column;min-width:0;align-items:stretch}
.showcase .shots{width:min(100%,336px);margin-inline:auto}

/* The card sitting on the photograph. Always legible because of the scrim
   above, in both themes, regardless of how bright the photo is. The extra
   bottom padding keeps the price clear of the arch's rounded floor. */
.shots__card{
  position:absolute;inset-inline:0;bottom:0;z-index:2;
  padding:clamp(18px,2.4vw,26px) clamp(18px,2.4vw,26px) clamp(22px,3vw,30px);
  display:flex;flex-direction:column;gap:7px;
}
.shots__place{
  font-family:var(--font-mono);font-size:var(--step--2);letter-spacing:.16em;
  text-transform:uppercase;color:var(--brass);
}
:root[data-theme="dark"] .shots__place{color:var(--brass)}
.shots__title{
  font-family:var(--font-display);font-size:clamp(1.15rem,2vw,1.6rem);
  line-height:1.2;color:#fff;margin:0;
}
.shots__price{
  font-family:var(--font-mono);font-size:1.02rem;color:#fff;
  font-variant-numeric:tabular-nums;
}

/* The thumbnail strip. Each one is itself a small arch, so the navigation is
   made of the same shape as the thing it navigates. */
.shots__strip{
  display:flex;gap:10px;margin-top:14px;
  justify-content:center;flex-wrap:wrap;
}
.shots__thumb{
  width:58px;height:72px;padding:0;cursor:pointer;overflow:hidden;
  border:1px solid var(--line);background:var(--surface-3);
  border-radius:46% 46% 6px 6px / 30% 30% 6px 6px;
  opacity:.52;
  transition:opacity var(--t) var(--ease), border-color var(--t) var(--ease), transform var(--t) var(--ease-out);
}
.shots__thumb img{width:100%;height:100%;object-fit:cover;display:block}
.shots__thumb:hover{opacity:.82;transform:translateY(-2px)}
.shots__thumb[aria-current="true"]{
  opacity:1;border-color:var(--brass);
  box-shadow:0 0 0 3px color-mix(in srgb,var(--brass) 22%,transparent);
}
@media (max-width:560px){.shots__thumb{width:46px;height:58px}}

/* Reassurance ticks under the hero buttons. */
.assure{
  display:flex;flex-wrap:wrap;gap:10px 22px;
  font-size:.88rem;color:var(--muted);
}
.assure span{display:inline-flex;align-items:center;gap:7px}
.assure span::before{
  content:"";width:14px;height:14px;flex:none;border-radius:50%;
  background:var(--accent-wash);
  border:1px solid color-mix(in srgb,var(--accent) 50%,transparent);
}

/* ============================================================ 25. search */

/* The search panel straddles the hero and the content below it, which is what
   makes it read as the page's primary action rather than another section. */
.search{
  position:relative;z-index:4;
  margin-top:clamp(-56px,-4vw,-28px);
  background:var(--surface);border:1px solid var(--line-soft);
  border-radius:var(--radius-lg);box-shadow:var(--shadow-lg);
  padding:clamp(16px,1.8vw,22px);
  display:grid;grid-template-columns:repeat(4,1fr) auto;
  gap:clamp(10px,1.2vw,16px);align-items:end;
}
.search .field label{font-size:var(--step--2);letter-spacing:.12em}
.search .btn{height:46px;white-space:nowrap}
/* On the search page the panel is not straddling a hero, so it sits in the
   flow with no overlap and a quieter shadow. */
.search--flat{margin-top:0;box-shadow:var(--shadow);background:var(--surface-2)}

@media (max-width:980px){
  .search{grid-template-columns:repeat(2,1fr);margin-top:clamp(-32px,-3vw,-18px)}
  .search--flat{margin-top:0}
  .search .btn{grid-column:1/-1}
}
@media (max-width:520px){.search{grid-template-columns:1fr}}

/* ============================================================ 26. card+ */

/* The richer property card: a deal badge and quick facts over the photograph,
   then price, type, title, and chips for the things people actually filter on. */
.prop__badge{
  position:absolute;top:12px;inset-inline-start:12px;z-index:2;
  font-family:var(--font-mono);font-size:var(--step--2);letter-spacing:.12em;
  text-transform:uppercase;padding:6px 12px;border-radius:999px;
  background:var(--accent);color:var(--on-accent);
}
.prop__badge--rent{background:var(--brass);color:#fff}
:root[data-theme="dark"] .prop__badge--rent{color:var(--on-accent)}
/* Reserved or gone: stated plainly and without the accent, so it does not
   compete with the properties that are still available. */
.prop__badge--off{background:rgba(0,0,0,.62);color:#fff;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px)}

.prop__onshot{
  position:absolute;inset-inline-start:12px;bottom:12px;z-index:2;
  display:flex;flex-wrap:wrap;gap:7px;
}
.prop__onshot span{
  display:inline-flex;align-items:center;gap:5px;
  font-family:var(--font-mono);font-size:var(--step--2);letter-spacing:.08em;
  padding:5px 10px;border-radius:999px;
  background:rgba(0,0,0,.56);color:#fff;
  -webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);
}

.prop__row{display:flex;align-items:baseline;justify-content:space-between;gap:10px;flex-wrap:wrap}
.prop__kind{
  font-family:var(--font-mono);font-size:var(--step--2);letter-spacing:.1em;
  text-transform:uppercase;color:var(--muted);
  padding:4px 10px;border-radius:999px;background:var(--surface-3);
}
.prop .price{color:var(--accent-ink);font-size:1.12rem}

.prop__facts{
  display:flex;flex-wrap:wrap;gap:8px;
  padding-top:12px;margin-top:auto;border-top:1px solid var(--line-soft);
}
.prop__facts span{
  display:inline-flex;align-items:center;gap:6px;
  font-family:var(--font-mono);font-size:var(--step--2);letter-spacing:.06em;
  color:var(--muted);padding:5px 10px;border-radius:999px;
  border:1px solid var(--line-soft);
}
.prop__facts span.is-amen{
  border-color:color-mix(in srgb,var(--brass) 42%,transparent);
  color:var(--brass);
}
.prop__cta{
  margin-top:12px;display:inline-flex;align-items:center;justify-content:center;
  font-family:var(--font-mono);font-size:var(--step--2);letter-spacing:.12em;
  text-transform:uppercase;padding:11px 18px;border-radius:999px;
  background:var(--accent-wash);color:var(--accent-ink);
  border:1px solid color-mix(in srgb,var(--accent) 34%,transparent);
  transition:background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.prop:hover .prop__cta{background:var(--accent);color:var(--on-accent);border-color:var(--accent)}

/* ============================================================ 27. build  */

/* Renovation and construction. These are jobs, not listings, so they get a
   different card: a drawn plate on top rather than a photograph, because
   nobody has supplied before/after photography yet and a stock kitchen would
   be a claim about work we did not do. */
.works{display:grid;grid-template-columns:repeat(4,1fr);gap:clamp(12px,1.4vw,18px)}
@media (max-width:1000px){.works{grid-template-columns:repeat(2,1fr)}}
@media (max-width:560px){.works{grid-template-columns:1fr}}

.work{
  display:flex;flex-direction:column;min-width:0;overflow:hidden;
  background:var(--surface-2);border:1px solid var(--line-soft);
  border-radius:var(--radius);text-decoration:none;color:inherit;
  transition:border-color var(--t) var(--ease), box-shadow var(--t) var(--ease), transform var(--t) var(--ease-out);
}
.work:hover{
  border-color:color-mix(in srgb,var(--brass) 50%,transparent);
  box-shadow:var(--shadow);transform:translateY(-3px);
}
.work__plate{
  aspect-ratio:16/10;background:var(--accent-wash);
  border-bottom:1px solid var(--line-soft);overflow:hidden;
}
.work__plate svg,.work__plate img{width:100%;height:100%;display:block;object-fit:cover}
.work__plate img{transition:transform .7s var(--ease-out)}
.work:hover .work__plate img{transform:scale(1.05)}
.work__body{padding:20px;display:flex;flex-direction:column;gap:9px;flex:1}
.work__body h3{font-size:1.05rem}
.work__body p{color:var(--muted);font-size:.93rem}
.work__more{
  margin-top:auto;padding-top:12px;
  font-family:var(--font-mono);font-size:var(--step--2);letter-spacing:.12em;
  text-transform:uppercase;color:var(--brass);
  display:inline-flex;align-items:center;gap:7px;
}
.work:hover .work__more{color:var(--accent-ink)}

/* ============================================================ 28. reads  */

/* Journal cards. The old row list read as a changelog; this reads as
   something worth opening — picture first, then the title, then enough of
   the excerpt to decide on. */
.reads{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(14px,1.8vw,22px)}
@media (max-width:900px){.reads{grid-template-columns:repeat(2,1fr)}}
@media (max-width:600px){.reads{grid-template-columns:1fr}}

.read{
  display:flex;flex-direction:column;min-width:0;overflow:hidden;
  background:var(--surface-2);border:1px solid var(--line-soft);
  border-radius:var(--radius);text-decoration:none;color:inherit;
  transition:border-color var(--t) var(--ease), box-shadow var(--t) var(--ease);
}
.read:hover{border-color:color-mix(in srgb,var(--accent) 46%,transparent);box-shadow:var(--shadow-lg)}
.read__shot{aspect-ratio:16/9;overflow:hidden;background:var(--surface-3);position:relative}
.read__shot img,.read__shot svg{width:100%;height:100%;object-fit:cover;display:block}
.read__shot img{transition:transform .7s var(--ease-out)}
.read:hover .read__shot img{transform:scale(1.05)}
.read__body{padding:18px;display:flex;flex-direction:column;gap:9px;flex:1}
.read__when{
  font-family:var(--font-mono);font-size:var(--step--2);letter-spacing:.12em;
  text-transform:uppercase;color:var(--muted);
}
.read__body h3{font-size:1.06rem;line-height:1.35;transition:color var(--t-fast) var(--ease)}
.read:hover .read__body h3{color:var(--accent-ink)}
.read__body p{color:var(--muted);font-size:.92rem;line-height:1.55}
.read__more{
  margin-top:auto;padding-top:12px;
  font-family:var(--font-mono);font-size:var(--step--2);letter-spacing:.12em;
  text-transform:uppercase;color:var(--brass);
}

/* ============================================================ 29. arabic */

/* Every directional rule above is a logical property — inline-start rather
   than left — so dir="rtl" on <html> mirrors the whole layout on its own.
   What follows is only the handful of things logical properties cannot know
   about: which typefaces to use, and which way an arrow points. */

:root[lang="ar"]{
  /* Amiri is a Naskh with the same editorial weight Instrument Serif carries
     in Latin; IBM Plex Sans Arabic is the sibling of the mono already loaded.
     Both keep their Latin fallbacks for brand names and stray English. */
  --font-display:"Amiri", "Noto Naskh Arabic", Georgia, serif;
  --font-body:"IBM Plex Sans Arabic", "Noto Sans Arabic", ui-sans-serif, system-ui, sans-serif;
}

/* Arabic script sits taller and needs more room between lines than Latin at
   the same size, and it has no uppercase — so the wide letter-spaced caps
   used for eyebrows and labels are meaningless and merely hard to read. */
:root[lang="ar"] body{line-height:1.85}
:root[lang="ar"] h1,
:root[lang="ar"] h2{line-height:1.3;letter-spacing:0}
:root[lang="ar"] h3{line-height:1.5}
:root[lang="ar"] .eyebrow,
:root[lang="ar"] .num,
:root[lang="ar"] .prop__kind,
:root[lang="ar"] .prop__place,
:root[lang="ar"] .shots__place,
:root[lang="ar"] .read__when,
:root[lang="ar"] .foot-col h4,
:root[lang="ar"] .field label,
:root[lang="ar"] .stat span,
:root[lang="ar"] .work__more,
:root[lang="ar"] .read__more,
:root[lang="ar"] .btn,
:root[lang="ar"] .chip,
:root[lang="ar"] .copy-btn,
:root[lang="ar"] .nav a{
  text-transform:none;
  letter-spacing:0;
  font-family:var(--font-body);
}
/* Prices, areas and dates stay in the mono and stay in Western digits —
   Morocco writes 1,550,000, not the Eastern numerals. */
:root[lang="ar"] .price,
:root[lang="ar"] .shots__price,
:root[lang="ar"] .plate dd,
:root[lang="ar"] .specs,
:root[lang="ar"] .prop__facts span,
:root[lang="ar"] .prop__onshot span,
:root[lang="ar"] .coords{
  font-family:var(--font-mono);
  direction:ltr;
  /* unicode-bidi isolates the number so a price never scrambles the sentence
     it sits inside when the two directions meet. */
  unicode-bidi:isolate;
}

/* An arrow is a direction, so it has to turn around with the text. It lives
   here rather than in the markup for exactly that reason. */
.work__more::after{content:" \2192"}
[dir="rtl"] .work__more::after{content:" \2190"}

/* The eyebrow's leading rule sits before the text in either direction once
   it is a flex item, so nothing is needed there — but the bento's ghost
   numeral is positioned, and reads better tucked into the far corner. */
[dir="rtl"] .bento__ghost{transform:scaleX(-1)}

/* The hero arch is symmetrical, and so is the thumbnail strip, so neither
   needs flipping. The property photographs are not mirrored either: a
   photograph is not a direction. */

/* ============================================================ 30. langs  */

.lang-pick{
  display:inline-flex;align-items:center;gap:2px;
  border:1px solid var(--line);border-radius:999px;padding:3px;flex:none;
}
.lang-pick a{
  display:inline-flex;align-items:center;
  font-family:var(--font-mono);font-size:var(--step--2);letter-spacing:.06em;
  color:var(--muted);text-decoration:none;
  padding:6px 11px;border-radius:999px;
  transition:color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.lang-pick a:hover{color:var(--ink)}
.lang-pick a[aria-current="true"]{background:var(--accent);color:var(--on-accent)}
/* The Arabic option is set in Arabic, so it needs the Arabic face even on an
   English page — otherwise it renders in a fallback that looks nothing like
   the rest of the site. */
.lang-pick a[lang="ar"]{font-family:"IBM Plex Sans Arabic","Noto Sans Arabic",sans-serif;letter-spacing:0}

@media (max-width:980px){
  .lang-pick{order:2}
}

/* ============================================================ 31. finish */

/* Six small motions. None of them is decoration for its own sake — each one
   answers a question the visitor would otherwise have to guess at: did that
   click register, is the page changing, has the image loaded, where did the
   link take me. Every one is transform/opacity and every one is off under
   prefers-reduced-motion, at the bottom of this section. */

/* --- 1. between pages ------------------------------------------------
   A hard cut between pages is the loudest "unfinished" tell a site has.
   One rule gives same-origin navigations a crossfade in browsers that
   support it; everywhere else the navigation is exactly as it was. */
@view-transition { navigation: auto; }
::view-transition-old(root),
::view-transition-new(root){ animation-duration:.26s; animation-timing-function:var(--ease-out) }

/* --- 2. anchors land where you can see them --------------------------
   The header is sticky and 72px tall, so #build and #enquire were putting
   their own heading underneath it. Every anchor target now reserves that
   much room above itself. */
:target,
[id="build"], [id="buy"], [id="sell"], [id="rent"], [id="let"], [id="beyond"],
[id="enquire"], [id="newsletter"], [id="main"]{
  scroll-margin-top:calc(72px + 24px);
}

/* --- 3. press ---------------------------------------------------------
   Hover says "this is clickable". Press says "I heard you" — the half
   second before the next page arrives, which is exactly when a visitor
   wonders whether the click landed. */
.btn:active{transform:translateY(1px) scale(.985)}
.chip:active,.copy-btn:active,.shots__thumb:active{transform:scale(.95)}
.prop:active,.work:active,.read:active{transform:scale(.993)}
.prop,.work,.read{transition:border-color var(--t) var(--ease), box-shadow var(--t) var(--ease),
  background var(--t) var(--ease), transform var(--t-fast) var(--ease-out)}

/* --- 4. photographs arrive instead of popping ------------------------
   Guarded twice: the effect only exists once JS is alive (html.js), and
   the head failsafe that rescues .reveal rescues these too, so a dead
   script can never leave the page imageless. */
html.js img.shot-in{opacity:0;transform:scale(1.02);
  transition:opacity .6s var(--ease-out), transform .9s var(--ease-out)}
html.js img.shot-in.is-loaded{opacity:1;transform:none}
html.reveal-all img.shot-in{opacity:1!important;transform:none!important}

/* --- 5. the numbers count ---------------------------------------------
   Tabular figures so the width does not jitter while they climb. */
.stat b{font-variant-numeric:tabular-nums}

/* --- and the submit button that says it is working -------------------- */
.btn.is-sending{
  pointer-events:none;            /* the second click is the one that double-sends */
  opacity:.82;
}
.btn.is-sending::after{
  content:"";width:13px;height:13px;flex:none;
  border:2px solid currentColor;border-top-color:transparent;border-radius:50%;
  animation:spin .62s linear infinite;
}
@keyframes spin{to{transform:rotate(360deg)}}

/* --- 6. the mobile menu opens instead of appearing -------------------- */
@media (max-width:980px){
  .nav:not([hidden]) a{animation:menu-in .34s var(--ease-out) both}
  .nav:not([hidden]) a:nth-child(1){animation-delay:.02s}
  .nav:not([hidden]) a:nth-child(2){animation-delay:.06s}
  .nav:not([hidden]) a:nth-child(3){animation-delay:.10s}
  .nav:not([hidden]) a:nth-child(4){animation-delay:.14s}
  .nav:not([hidden]) a:nth-child(5){animation-delay:.18s}
  /* The admin header is not a menu and must not cascade. */
  .nav--static a{animation:none!important}
}
@keyframes menu-in{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}

/* Everything above, off. */
@media (prefers-reduced-motion:reduce){
  @view-transition { navigation: none; }
  .btn:active,.chip:active,.copy-btn:active,.shots__thumb:active,
  .prop:active,.work:active,.read:active{transform:none}
  html.js img.shot-in{opacity:1;transform:none;transition:none}
  .nav:not([hidden]) a{animation:none}
  /* A spinner frozen by the global animation override reads as broken,
     so the button keeps the word and drops the circle. */
  .btn.is-sending::after{display:none}
}

/* ============================================================ 32. print  */

@media print{
  body::before,.site-head,.site-foot,.theme-toggle,.nav-toggle{display:none!important}
  .reveal{opacity:1!important;transform:none!important}
  body{background:#fff;color:#000}
}
