/* ============================================================
   KHEPRI — shared engine
   Five worlds, one grammar. Each page sets data-world on <body>
   and inherits its own palette; everything else is common.

   The page is dark now, deliberately. The old build was limestone
   because its argument was transparency. This one sells the dream,
   and a dream is lit from inside the frame.
   ============================================================ */

/* ---- fonts (self-hosted, shared across all pages) ---- */
@font-face{font-family:'Instrument Serif';font-style:normal;font-weight:400;font-display:swap;
  src:url("/khepri/fonts/instrument-latin.woff2") format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'Instrument Serif';font-style:normal;font-weight:400;font-display:swap;
  src:url("/khepri/fonts/instrument-latin-ext.woff2") format("woff2");
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}
@font-face{font-family:'Instrument Serif';font-style:italic;font-weight:400;font-display:swap;
  src:url("/khepri/fonts/instrument-italic-latin.woff2") format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'Space Grotesk';font-style:normal;font-weight:300 600;font-display:swap;
  src:url("/khepri/fonts/spacegrotesk-latin.woff2") format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'Space Grotesk';font-style:normal;font-weight:300 600;font-display:swap;
  src:url("/khepri/fonts/spacegrotesk-latin-ext.woff2") format("woff2");
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}

/* ---------------- the five worlds ---------------- */
:root,[data-world="accueil"]{
  --bg:#0F0D0B; --deep:#1A1512; --fg:#F6F0E6; --accent:#E8A24A; --accent-2:#C87F2C;
}
[data-world="turquie"]{  /* the hour before sunrise, then the burner */
  --bg:#130E1B; --deep:#241A2E; --fg:#F4EEF6; --accent:#FF7A3D; --accent-2:#D4552A;
}
[data-world="dubai"]{    /* gold on black glass */
  --bg:#090D18; --deep:#131C30; --fg:#F3EFE4; --accent:#DCA845; --accent-2:#B2801F;
}
[data-world="afrique"]{  /* dust, and the sun through it */
  --bg:#150F07; --deep:#251A0D; --fg:#F7EFE0; --accent:#E2762A; --accent-2:#B4551A;
}
[data-world="reunion"]{  /* basalt, and what runs through it */
  --bg:#0A0A0B; --deep:#171718; --fg:#F2EEE9; --accent:#FF5A1F; --accent-2:#C93D0C;
}
:root{
  --dim:color-mix(in srgb, var(--fg) 62%, transparent);
  --faint:color-mix(in srgb, var(--fg) 34%, transparent);
  --line:color-mix(in srgb, var(--fg) 15%, transparent);
  --display:'Instrument Serif',Georgia,serif;
  --sans:'Space Grotesk',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
  --ease:cubic-bezier(.22,1,.36,1);
}

*{margin:0;padding:0;box-sizing:border-box}
html{-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;scroll-behavior:smooth}
body{font-family:var(--sans);background:var(--bg);color:var(--fg);overflow-x:hidden;
  line-height:1.62;font-weight:300;font-size:clamp(.95rem,.9rem + .2vw,1.05rem);
  transition:background .8s var(--ease)}
img,video{display:block;max-width:100%}
a{color:inherit;text-decoration:none}
h1,h2,h3{font-family:var(--display);font-weight:400;line-height:1.02;letter-spacing:-.01em}
::selection{background:var(--accent);color:var(--bg)}
:focus-visible{outline:2px solid var(--accent);outline-offset:3px;border-radius:2px}
.wrap{width:min(1180px,90vw);margin-inline:auto}
.narrow{width:min(680px,90vw);margin-inline:auto}
.eyebrow{font-size:.66rem;font-weight:500;letter-spacing:.26em;text-transform:uppercase;color:var(--accent)}

/* ---- FR·EN ---- */
.lang-fr .t-en{display:none!important}
.lang-en .t-fr{display:none!important}
.lang{display:inline-flex;align-items:center;padding:3px;border-radius:100px;
  border:1px solid var(--line);background:color-mix(in srgb,var(--bg) 55%,transparent);
  backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);position:relative}
.lang input{position:absolute;opacity:0;pointer-events:none}
.lang label{position:relative;z-index:1;padding:.34rem .6rem;border-radius:100px;cursor:pointer;
  font-size:.63rem;letter-spacing:.14em;font-weight:500;color:var(--dim);transition:color .4s var(--ease)}
.lang::before{content:'';position:absolute;top:3px;bottom:3px;left:3px;width:calc(50% - 3px);
  border-radius:100px;background:var(--accent);transition:transform .45s var(--ease)}
.lang.en::before{transform:translateX(100%)}
.lang input:checked + label{color:var(--bg)}

/* ---- reveals ---- */
.rv{opacity:0;transform:translateY(20px);transition:opacity .9s var(--ease),transform .9s var(--ease)}
.rv.on{opacity:1;transform:none}
@media (prefers-reduced-motion:reduce){
  .rv{opacity:1;transform:none;transition:none}
  html{scroll-behavior:auto}
  *{animation-duration:.01ms!important;animation-iteration-count:1!important}
}

/* ============================ NAV ============================ */
.nav{position:fixed;inset-inline:0;top:0;z-index:60;
  padding:calc(.8rem + env(safe-area-inset-top)) 0 .8rem;transition:background .5s var(--ease)}
.nav.solid{background:color-mix(in srgb,var(--bg) 86%,transparent);
  backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);box-shadow:0 1px 0 var(--line)}
.nav__in{display:flex;align-items:center;justify-content:space-between;gap:1rem}
.brand{display:inline-flex;align-items:center;gap:.55rem}
.brand svg{width:26px;height:26px;flex:none}
.brand__name{font-family:var(--display);font-size:1.3rem;letter-spacing:.2em;text-transform:uppercase;
  transform:translateY(.04em);white-space:nowrap}
.nav__right{display:flex;align-items:center;gap:.85rem}
.nav__cta{border:1px solid var(--fg);border-radius:100px;padding:.42rem .95rem;font-size:.66rem;
  letter-spacing:.14em;text-transform:uppercase;font-weight:500;transition:background .3s,color .3s}
.nav__cta:hover{background:var(--fg);color:var(--bg)}
@media(max-width:520px){.brand__name{font-size:1.08rem;letter-spacing:.15em}
  .nav__cta{padding:.38rem .7rem;font-size:.6rem}}

/* ======================= THE SHUTTER =========================
   Every plate on this site arrives the way the doors do in the
   hero film: a band of light that opens. --o runs 0 → 1 from
   scroll, and drives the aperture, the scale and the settle.
   ============================================================= */
.shutter{--o:0;position:relative;overflow:hidden;isolation:isolate;
  clip-path:inset(calc((1 - var(--o)) * 41%) 0 round 2px)}
.shutter > img,.shutter > video,.shutter > .mm{width:100%;height:100%;object-fit:cover;
  transform:scale(calc(1.14 - .14 * var(--o)));transform-origin:center 55%;will-change:transform}
@media (prefers-reduced-motion:reduce){
  .shutter{clip-path:none}
  .shutter > img,.shutter > video,.shutter > .mm{transform:none}
}

/* ============================ HERO ============================ */
.hero{position:relative;min-height:100svh;display:flex;flex-direction:column;justify-content:flex-end;
  overflow:hidden;isolation:isolate}
.hero__media{position:absolute;inset:0;z-index:-2;background:var(--deep) center/cover no-repeat}
.hero__media video{width:100%;height:100%;object-fit:cover;opacity:0;transition:opacity 1.2s var(--ease)}
.hero__media video.ready{opacity:1}
/* the copy corner always gets its own ground — pale type on a
   moving plate is never a colour problem, it is a contrast one */
.hero::after{content:'';position:absolute;inset:0;z-index:-1;pointer-events:none;
  background:
    /* the copy corner gets its own ground — the headline sits over a lit
       doorway, and pale type on a bright plate is a contrast problem, never
       a colour one */
    linear-gradient(100deg,color-mix(in srgb,var(--bg) 90%,transparent) 0%,
      color-mix(in srgb,var(--bg) 68%,transparent) 30%,
      color-mix(in srgb,var(--bg) 22%,transparent) 56%,transparent 72%),
    linear-gradient(180deg,color-mix(in srgb,var(--bg) 62%,transparent) 0%,transparent 26%,
      transparent 42%,color-mix(in srgb,var(--bg) 78%,transparent) 88%,var(--bg) 100%)}
.hero__in{padding-bottom:clamp(2.6rem,7vh,5rem);padding-top:8rem}
.hero h1{font-size:clamp(2.5rem,1.1rem + 6.6vw,6rem);max-width:14ch;margin:1.1rem 0 1.2rem}
.hero h1 em{font-style:italic;color:var(--accent)}
.hero__sub{max-width:44ch;color:var(--dim);font-size:clamp(1rem,.95rem + .3vw,1.12rem)}
.scroll-cue{margin-top:2.2rem;display:flex;align-items:center;gap:.7rem;font-size:.64rem;
  letter-spacing:.2em;text-transform:uppercase;color:var(--faint)}
.scroll-cue i{display:block;width:1px;height:38px;background:linear-gradient(var(--accent),transparent);
  animation:fall 2.4s var(--ease) infinite}
@keyframes fall{0%{transform:scaleY(0);transform-origin:top}
  55%{transform:scaleY(1);transform-origin:top}
  56%{transform:scaleY(1);transform-origin:bottom}
  100%{transform:scaleY(0);transform-origin:bottom}}

/* ==================== MASK MOTION (no video) ==================
   The plate does the moving. Nothing is drawn on top of the
   photograph — these layers are light, masked to regions painted
   from the plate's OWN pixels, so only the water and the polished
   floor can ever move. Masks share the plate's intrinsic size and
   its cover/center geometry, so they track the crop at every
   viewport with no breakpoints.
   ⚠️ The mask PNGs are RGBA with the mask in the ALPHA channel.
   A greyscale PNG has no alpha and would mask nothing at all.
   ============================================================= */
.mm{position:absolute;inset:0;pointer-events:none;z-index:0}
.mm i{position:absolute;inset:0;display:block;
  -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
  -webkit-mask-size:cover;mask-size:cover;
  -webkit-mask-position:center;mask-position:center}

/* ⚠️ The moving part is an INNER element driven by TRANSFORM, not the
   layer's own background-position. Chrome does not repaint a
   background-position animation on a masked, composited layer — the
   animation reports playState "running" and the computed value never
   changes, so the whole engine sits frozen while looking correct in
   devtools. Transforms are compositor-driven and always run. The mask
   stays on the static outer element, so alignment is untouched. */
.mm i{overflow:hidden}
.mm i > b{position:absolute;display:block;will-change:transform}

/* the jets — light rising. The band repeats every 40px and travels
   exactly one period, so the loop is seamless. */
.mm .water{-webkit-mask-image:url('/khepri/assets/dubai-water.png?v=2');
  mask-image:url('/khepri/assets/dubai-water.png?v=2');
  mix-blend-mode:screen;opacity:.75}
.mm .water > b{left:0;right:0;top:0;height:200%;
  background-image:repeating-linear-gradient(180deg,transparent 0 14px,
    rgba(255,244,214,.85) 14px 22px,transparent 22px 40px);
  animation:mmRise 3.1s linear infinite}
@keyframes mmRise{from{transform:translateY(0)}to{transform:translateY(-40px)}}

/* the floor — one broad reflection sloshed on ease-in-out rather than
   scrolled, because a linear loop is the tell that reads as a cheap
   animated background. */
.mm .floor{-webkit-mask-image:url('/khepri/assets/dubai-floor.png?v=2');
  mask-image:url('/khepri/assets/dubai-floor.png?v=2');
  mix-blend-mode:soft-light;opacity:.7}
.mm .floor > b{top:0;bottom:0;left:0;width:190%;
  background:linear-gradient(100deg,transparent 0%,rgba(255,226,168,.9) 34%,
    rgba(255,255,255,.75) 50%,rgba(255,214,140,.9) 66%,transparent 100%);
  animation:mmSlosh 11s cubic-bezier(.45,0,.55,1) infinite alternate}
@keyframes mmSlosh{from{transform:translateX(-47%)}to{transform:translateX(0)}}




@media (prefers-reduced-motion:reduce){
  .mm i > b{animation:none}
  .mm{opacity:.4}
}

/* ======================= DESTINATION PANELS ================== */
.worlds{padding:clamp(4rem,10vh,7rem) 0 2rem}
.world{display:block;position:relative;margin-bottom:clamp(3rem,7vh,6rem)}
.world__frame{aspect-ratio:16/9;border-radius:2px;background:var(--deep)}
@media(max-width:700px){.world__frame{aspect-ratio:4/5}}
.world__body{display:flex;flex-wrap:wrap;align-items:baseline;justify-content:space-between;
  gap:.6rem 1.6rem;margin-top:1.1rem}
.world__name{font-size:clamp(2rem,1.3rem + 3vw,3.6rem);line-height:1}
.world__meta{font-size:.66rem;letter-spacing:.2em;text-transform:uppercase;color:var(--faint)}
.world__line{width:100%;color:var(--dim);max-width:52ch;margin-top:.2rem}
.world__go{display:inline-flex;align-items:center;gap:.5rem;margin-top:.9rem;font-size:.68rem;
  letter-spacing:.15em;text-transform:uppercase;font-weight:500;color:var(--accent)}
.world__go span{display:block;width:26px;height:1px;background:var(--accent);
  transition:width .4s var(--ease)}
.world:hover .world__go span{width:46px}
@media(hover:none){.world:hover .world__go span{width:26px}}

/* ======================= PROSE BEATS ========================= */
.beat{padding:clamp(3.5rem,9vh,6rem) 0}
.beat h2{font-size:clamp(1.7rem,1.2rem + 2.2vw,2.9rem);max-width:20ch;margin-bottom:1.1rem}
.beat p{color:var(--dim);max-width:54ch;line-height:1.72}
.beat p + p{margin-top:1rem}

/* ---- the honest-price beat: what survives of the old build ---- */
.pledge{border-top:1px solid var(--line);border-bottom:1px solid var(--line);
  padding:clamp(2.2rem,5vh,3.4rem) 0;margin:clamp(2rem,5vh,3rem) 0}
.pledge b{font-family:var(--display);font-size:clamp(1.3rem,1rem + 1.4vw,2rem);
  display:block;margin-bottom:.7rem;font-weight:400}
.pledge p{color:var(--dim);max-width:56ch}

/* ============================ PRICE ========================== */
.price{margin-top:1.6rem;padding-top:1.3rem;border-top:1px solid var(--line)}
.price__n{font-family:var(--display);font-size:clamp(1.8rem,1.4rem + 1.5vw,2.6rem);line-height:1;display:block}
.price__inc{font-size:.78rem;color:var(--faint);margin-top:.5rem;line-height:1.55;max-width:46ch}
.price__note{font-size:.72rem;color:var(--accent);margin-top:.7rem}

.btn{display:inline-flex;align-items:center;gap:.5rem;border:1px solid var(--fg);border-radius:100px;
  padding:.62rem 1.2rem;font-size:.68rem;letter-spacing:.14em;text-transform:uppercase;font-weight:500;
  transition:background .3s var(--ease),color .3s var(--ease),transform .18s var(--ease)}
.btn:hover{background:var(--fg);color:var(--bg)}
.btn:active{transform:translateY(1px) scale(.99)}
.btn--fill{background:var(--accent);border-color:var(--accent);color:var(--bg)}
.btn--fill:hover{background:var(--accent-2);border-color:var(--accent-2);color:var(--bg)}
@media(hover:none){.btn:hover{background:transparent;color:inherit}
  .btn--fill:hover{background:var(--accent);color:var(--bg)}}

/* ============================ CONTACT ======================== */
.contact{padding:clamp(3.5rem,9vh,6rem) 0 clamp(4rem,10vh,7rem);background:var(--deep)}
.contact h2{font-size:clamp(1.8rem,1.3rem + 2.2vw,2.9rem);margin-bottom:.8rem;max-width:18ch}
.contact .lead{color:var(--dim);max-width:44ch;margin-bottom:2.2rem}
.form{display:grid;gap:1.05rem;max-width:600px}
.f2{display:grid;grid-template-columns:1fr 1fr;gap:1.05rem}
@media(max-width:560px){.f2{grid-template-columns:1fr}}
.field label{display:block;font-size:.6rem;letter-spacing:.18em;text-transform:uppercase;
  color:var(--faint);margin-bottom:.4rem}
.field select,.field input{width:100%;background:transparent;color:var(--fg);border:0;
  border-bottom:1px solid var(--line);padding:.58rem 0;font-family:var(--sans);font-size:.98rem;
  font-weight:300;border-radius:0;-webkit-appearance:none;appearance:none;transition:border-color .3s}
.field select option{background:#14100D;color:#F6F0E6}
.field input:focus,.field select:focus{outline:none;border-bottom-color:var(--accent)}
.field input::placeholder{color:color-mix(in srgb,var(--fg) 26%,transparent)}
.contact__meta{margin-top:2.4rem;padding-top:1.5rem;border-top:1px solid var(--line);
  font-size:.76rem;color:var(--faint);line-height:1.7}

/* ============================ FOOTER ========================= */
footer{padding:2.6rem 0 calc(4.4rem + env(safe-area-inset-bottom));font-size:.74rem;color:var(--faint)}
.foot__row{display:flex;flex-wrap:wrap;gap:.6rem 1.6rem;justify-content:space-between;align-items:baseline}
.credit a{border-bottom:1px solid color-mix(in srgb,currentColor 38%,transparent);transition:color .3s}
.credit a:hover{color:var(--fg)}
.demo-note{margin-top:1.3rem;padding-top:1.1rem;border-top:1px solid var(--line);
  font-size:.7rem;line-height:1.65;max-width:66ch}

/* back to the gallery — 44px touch area without reflowing the pill */
.sn-back{position:fixed;left:max(1rem,env(safe-area-inset-left));
  bottom:calc(1rem + env(safe-area-inset-bottom));z-index:70;display:inline-flex;align-items:center;
  gap:.4rem;padding:.5rem .9rem;border-radius:999px;background:color-mix(in srgb,var(--bg) 82%,transparent);
  color:var(--fg);font-size:.64rem;letter-spacing:.12em;text-transform:uppercase;
  border:1px solid var(--line);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);
  transition:transform .25s var(--ease),opacity .3s var(--ease);opacity:.9}
.sn-back::after{content:'';position:absolute;left:0;right:0;top:50%;transform:translateY(-50%);height:44px}
.sn-back:hover{transform:translateY(-1px);opacity:1}
.sn-back.tuck{opacity:0;pointer-events:none;transform:translateY(8px)}
@media print{.sn-back{display:none}}

/* a destination page's way home */
.up{display:inline-flex;align-items:center;gap:.5rem;font-size:.66rem;letter-spacing:.16em;
  text-transform:uppercase;color:var(--dim);margin-bottom:1.2rem}
.up:hover{color:var(--accent)}

/* Dubaï is the only world without a film, so the plate itself breathes.
   Scaling the media wrapper carries the mask layers with it, so the
   regions stay locked to the photograph. */
[data-world="dubai"] .hero__media{animation:kenburns 13s ease-in-out infinite alternate;
  will-change:transform;transform-origin:40% 66%}
/* 5.5% over 26s is 0.1% a second — technically animating, humanly
   invisible. This plate has no film, so the PLATE has to be the motion:
   a push that actually arrives, anchored low and centre so the escalator
   and the fountain are what grow. The masked layers ride inside it. */
@keyframes kenburns{from{transform:scale(1) translateY(0)}
  to{transform:scale(1.085) translateY(-1.1%)}}
@media (prefers-reduced-motion:reduce){
  [data-world="dubai"] .hero__media{animation:none}
}
