/* =====================================================================
   Le Mas de Grâce — site stylesheet
   Aesthetic direction: editorial French farmhouse. Warm photography held
   inside a cool, quiet frame — hairline blue-grey rules, small-cap
   eyebrows, generous negative space, asymmetric photo/text bands. The
   mark is a drawing on paper; the page is the paper.

   Token values are AUTHORITATIVE from design/brand-canon.md §2.
   Do not hand-pick a colour that is not in this block.
   ===================================================================== */

/* ---------------------------------------------------------------------
   FONTS — NOT YET IN THE REPO.

   EB Garamond (SIL OFL) and Erode (Fontshare) are specified by
   brand-canon.md §3 and must be self-hosted as subset woff2 in
   site/fonts/ with their licence files alongside. Neither file exists
   yet (TODO.md §0). Until they land, the stacks below fall through to a
   close system serif and the page is fully legible.

   When the files arrive, uncomment this block. Nothing else changes —
   the type scale is already tuned against these metrics.

   The subset MUST preserve â (Grâce) and the small-cap-able Latin-1 set.

@font-face{
  font-family:"EB Garamond"; font-style:normal; font-weight:400;
  font-display:swap; src:url("../fonts/eb-garamond-400.woff2") format("woff2");
}
@font-face{
  font-family:"EB Garamond"; font-style:italic; font-weight:400;
  font-display:swap; src:url("../fonts/eb-garamond-400-italic.woff2") format("woff2");
}
@font-face{
  font-family:"Erode"; font-style:normal; font-weight:400;
  font-display:swap; src:url("../fonts/erode-400.woff2") format("woff2");
}
@font-face{
  font-family:"Erode"; font-style:normal; font-weight:500;
  font-display:swap; src:url("../fonts/erode-500.woff2") format("woff2");
}
--------------------------------------------------------------------- */

:root{
  /* --- colour (brand-canon.md §2) --- */
  --chalk:#F7F4EF;
  --linen:#EDE6DC;
  --papier:#FFFDFA;
  --ink:#26262B;
  --ink-soft:#4A4A50;
  --bleu:#8A97A6;
  --bleu-profond:#5E6E7E;
  --bleu-pale:#C9D2D8;
  --rule:rgba(138,151,166,.45);

  /* Scrim — carried over verbatim from the Salon guide. It was measured
     against this exact salon photograph's blown-out windows. Do not
     re-tune by eye (spec-stay.md §4.1). */
  --scrim:linear-gradient(to top,
      rgba(24,19,14,.82) 0%, rgba(24,19,14,.62) 34%,
      rgba(24,19,14,.22) 66%, rgba(24,19,14,0) 100%);
  --scrim-left:linear-gradient(to right,
      rgba(24,19,14,.62) 0%, rgba(24,19,14,.22) 46%, rgba(24,19,14,0) 72%);

  /* --- type --- */
  --font-display:"EB Garamond","Hoefler Text",Garamond,"Times New Roman",serif;
  --font-text:"Erode",Charter,"Bitstream Charter","Palatino Linotype",Palatino,Georgia,serif;

  /* TYPE SCALE — raised across the board, Grace's review 2026-08-06: every
     size on the page read too small. This block is the single place it is
     tuned; no component sets a raw px size any more.

     Two floors are load-bearing:
     · nothing a guest READS may fall below 16px at any viewport, so --fs-body
       and --fs-caption both floor at 17px and 16px. --fs-caption carries real
       prose (captions, room notes, the policy line, detail values), so it is
       body copy in everything but name and gets a body-copy floor.
     · --fs-sc and --fs-ui are set in all-small-caps, whose glyphs render at
       roughly 72% of the nominal size. 13px small-caps read as ~9px — that is
       why the eyebrows and the facts strip were the worst offenders. Floored
       at 16px so they land near a 12px cap-height.

     Canon §3 dropped --fs-h1 to clamp(34px,5.6vw,56px) because the headings
     came back too large; this raises it again but stays well under the
     clamp(40px,8.4vw,76px) she rejected. */
  --fs-h1:clamp(38px,6vw,62px);
  --fs-h2:clamp(30px,4vw,44px);
  --fs-h3:clamp(23px,2.4vw,28px);
  --fs-lead:clamp(19px,1.9vw,22px);
  --fs-body:clamp(17px,1.35vw,19px);
  --fs-quote:clamp(24px,3.4vw,34px);
  --fs-caption:clamp(16px,1.15vw,17px);
  --fs-sc:clamp(16px,1.15vw,17px);
  --fs-ui:clamp(16px,1.2vw,18px);

  --ls-sc:.18em; --ls-eyebrow:.26em; --lh-body:1.68;

  /* --- space --- */
  --pad-section:clamp(64px,8vw,120px);
  --pad-gutter:clamp(20px,5vw,88px);
  --maxw:1180px;
  --measure:34rem; --measure-lead:26rem;
  --rule-w:40px;
  --header-h:68px;

  /* Anchor landing offset. The whole sticky <header> is one block, and on
     mobile it is TWO rows — the bar plus the always-visible .subnav — so
     scroll-padding-top of (--header-h + 12px) dropped #write under it and the
     form heading landed behind the subnav. --header-total is written by JS from
     the header's measured height (site.js §0) and is exact at every breakpoint;
     the value here is the no-JS fallback and is deliberately generous. */
  --header-total:116px;

  /* Icon slot for the Highlights block. Real dimensions reserved now so
     commissioned icons drop in without a relayout (spec-stay.md §2b). */
  --icon-box:44px;
}

@media (min-width:900px){ :root{ --header-h:82px; --header-total:82px; } }

/* ---------------------------------------------------------------------
   reset
   --------------------------------------------------------------------- */
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%; scroll-behavior:smooth; scroll-padding-top:calc(var(--header-total) + 20px)}
body{
  margin:0; background:var(--chalk); color:var(--ink);
  font:400 var(--fs-body)/var(--lh-body) var(--font-text);
  overflow-x:hidden;
  -webkit-font-smoothing:antialiased;
}
img,svg,video{max-width:100%; display:block}
h1,h2,h3,h4,p,ul,ol,dl,dd,figure,fieldset,legend{margin:0}
ul{padding:0; list-style:none}
fieldset{border:0; padding:0; min-width:0}
a{color:var(--bleu-profond); text-underline-offset:.22em; text-decoration-thickness:1px}
a:focus-visible,button:focus-visible,input:focus-visible,textarea:focus-visible,
summary:focus-visible,[tabindex]:focus-visible{
  outline:2px solid var(--bleu-profond); outline-offset:3px;
}
::selection{background:var(--bleu-pale); color:var(--ink)}

/* ---------------------------------------------------------------------
   atoms
   --------------------------------------------------------------------- */
.wrap{max-width:var(--maxw); margin-inline:auto; padding-inline:var(--pad-gutter)}
.wrap--narrow{max-width:860px}

.section{padding-block:var(--pad-section)}
.section--linen{background:var(--linen)}
.section--papier{background:var(--papier)}

/* --bleu-profond on --chalk is 4.78:1 but only 4.23:1 on --linen, and the
   eyebrows sit on both grounds. One value that passes AA everywhere beats two
   that drift, so they take --ink-soft: 8.02:1 on chalk, 7.10:1 on linen. The
   quiet-label reading is carried by size, small caps and tracking, not colour. */
.eyebrow{
  font:400 var(--fs-sc)/1.3 var(--font-text);
  font-variant-caps:all-small-caps; letter-spacing:var(--ls-eyebrow);
  text-transform:lowercase; color:var(--ink-soft);
}
.eyebrow--c{text-align:center}

/* The name, wherever it is live type, is small-capped (brand-canon §1). */
.name{font-variant-caps:all-small-caps; letter-spacing:.04em}

.hairline{width:var(--rule-w); height:1px; background:var(--bleu); border:0; margin:18px 0 26px}
.hairline--c{margin-inline:auto}

h1,.h1{font:400 var(--fs-h1)/1.10 var(--font-display); letter-spacing:-.005em}
h2,.h2{font:400 var(--fs-h2)/1.16 var(--font-display); letter-spacing:0}
h3,.h3{font:400 var(--fs-h3)/1.24 var(--font-display)}

.lead{font-size:var(--fs-lead); line-height:1.62; max-width:var(--measure-lead)}
.body{max-width:var(--measure)}
.body p + p{margin-top:1.05em}
.caption{
  font:italic 400 var(--fs-caption)/1.5 var(--font-text);
  color:var(--ink-soft); margin-top:10px;
}

/* Placeholder copy. Every prose slot on this site is one of these until
   Grace's copywriter replaces it. The dotted rule is deliberate — it must
   be impossible to mistake filler for finished copy. */
.ph{
  color:var(--ink-soft);
  background:rgba(138,151,166,.09);
  border-bottom:1px dotted var(--bleu);
  padding:0 .16em;
  font-style:normal;
}
.ph--light{color:rgba(255,255,255,.86); background:rgba(255,255,255,.13); border-bottom-color:rgba(255,255,255,.5)}

/* ---------------------------------------------------------------------
   CTA — one label on the whole site: "Write to Grace"
   --------------------------------------------------------------------- */
/* --papier on --bleu was 2.93:1 — the site's only CTA failed AA outright. The
   fill moves to --bleu-profond (5.16:1), which canon §2 already lists for
   "small type on pale grounds"; hover darkens to --ink-soft (8.67:1) since
   there is no darker blue in the palette. --bleu keeps rules and ornament. */
.cta{
  display:inline-flex; align-items:center; justify-content:center;
  background:var(--bleu-profond); color:var(--papier);
  font:500 var(--fs-ui)/1 var(--font-text);
  font-variant-caps:all-small-caps; letter-spacing:var(--ls-sc);
  text-decoration:none; padding:15px 30px; border:0; border-radius:1px;
  cursor:pointer; transition:background-color .18s ease, transform .18s ease;
}
.cta:hover{background:var(--ink-soft)}
.cta:active{transform:translateY(1px)}
.cta--lg{padding:19px 42px; font-size:clamp(18px,1.5vw,21px)}
.cta--sm{padding:11px 20px; font-size:var(--fs-sc)}
.cta--ghost{
  background:transparent; color:var(--bleu-profond);
  box-shadow:inset 0 0 0 1px var(--rule);
}
.cta--ghost:hover{background:transparent; color:var(--ink); box-shadow:inset 0 0 0 1px var(--bleu)}

.textlink{
  font-variant-caps:all-small-caps; letter-spacing:var(--ls-sc);
  font-size:var(--fs-ui); color:var(--bleu-profond); text-decoration:none;
  border-bottom:1px solid var(--rule); padding-bottom:3px;
  transition:border-color .18s ease, color .18s ease;
}
.textlink:hover{color:var(--ink); border-bottom-color:var(--bleu)}

/* ---------------------------------------------------------------------
   image frames — fixed aspect, cover crop, linen ground while loading
   --------------------------------------------------------------------- */
.frame{
  position:relative; overflow:hidden; background:var(--linen);
  margin:0;
}
.frame img{width:100%; height:100%; object-fit:cover}
.frame--45{aspect-ratio:4/5}
.frame--32{aspect-ratio:3/2}
.frame--11{aspect-ratio:1/1}
.frame--43{aspect-ratio:4/3}

/* ---------------------------------------------------------------------
   header
   --------------------------------------------------------------------- */
.header{
  position:sticky; top:0; z-index:60;
  background:rgba(247,244,239,.92);
  backdrop-filter:saturate(140%) blur(8px);
  border-bottom:1px solid var(--rule);
}
.header__bar{
  max-width:var(--maxw); margin-inline:auto;
  padding-inline:var(--pad-gutter);
  min-height:var(--header-h);
  display:flex; align-items:center; gap:16px;
}
.header__home{flex:0 0 auto; display:block; line-height:0}
.header__home img{height:26px; width:auto}
.header__home .lockup--wide{display:none}
@media (min-width:900px){
  .header__home img{height:34px}
  .header__home .lockup--tight{display:none}
  .header__home .lockup--wide{display:block}
}

.nav{margin-left:auto; display:flex; align-items:center; gap:clamp(14px,2vw,30px)}
.nav__list{display:none}
@media (min-width:900px){ .nav__list{display:flex; align-items:center; gap:30px} }
.nav__item{position:relative}
.nav__link{
  font:400 var(--fs-ui)/1 var(--font-text);
  font-variant-caps:all-small-caps; letter-spacing:var(--ls-sc);
  color:var(--ink-soft); text-decoration:none; background:none; border:0;
  padding:8px 0; cursor:pointer;
}
.nav__link:hover{color:var(--ink)}
/* Story and Explore are post-launch (sitemap.md). They are shown as inert
   labels rather than links so nothing on the page 404s.
   --bleu-pale on the header ground was 1.40:1 — invisible. --bleu-profond is
   4.78:1 and still reads as a different, quieter register than the live links
   because it is a hue shift rather than a tint. */
.nav__link[aria-disabled="true"]{color:var(--bleu-profond); cursor:default}
/* The SOON marker was 9px --bleu on chalk: 2.71:1, and the client could not
   see it at all. Now --bleu-profond (4.78:1) and never smaller than 12px. */
.nav__soon{
  /* font-variant-caps is reset: the parent's all-small-caps would shrink these
     already-uppercase letters to ~72% again, undoing the size bump. */
  font-variant-caps:normal; font-size:max(12px,.72em);
  letter-spacing:.12em; vertical-align:.45em;
  margin-left:6px; color:var(--bleu-profond);
}

/* Stay's children. Desktop: a dropdown panel on hover/focus-within, using
   @starting-style + allow-discrete so there is no JS state machine
   (motion-spec.md §5). Mobile: a second, always-visible row. */
.nav__sub{
  display:flex; gap:22px; align-items:center;
  padding:0; margin:0;
}
@media (min-width:900px){
  .nav__sub{
    display:none; position:absolute; top:calc(100% + 6px); left:50%;
    translate:-50% 0; flex-direction:column; gap:0; min-width:190px;
    background:var(--papier); border:1px solid var(--rule);
    box-shadow:0 12px 34px rgba(38,38,43,.10); padding:8px 0;
    opacity:0; translate:-50% -6px;
    transition:opacity .18s ease, translate .18s ease, display .18s allow-discrete;
  }
  .nav__item:hover .nav__sub,
  .nav__item:focus-within .nav__sub{display:flex; opacity:1; translate:-50% 0}
  @starting-style{
    .nav__item:hover .nav__sub,
    .nav__item:focus-within .nav__sub{opacity:0; translate:-50% -6px}
  }
  .nav__sub .nav__link{padding:9px 20px; width:100%}
  .nav__sub .nav__link:hover{background:var(--linen)}
}

.subnav{
  border-top:1px solid var(--rule);
  overflow-x:auto; -webkit-overflow-scrolling:touch;
  scrollbar-width:none;
}
.subnav::-webkit-scrollbar{display:none}
.subnav .nav__sub{
  max-width:var(--maxw); margin-inline:auto;
  padding:11px var(--pad-gutter); white-space:nowrap;
}
@media (min-width:900px){ .subnav{display:none} }

/* ---------------------------------------------------------------------
   1 — hero
   --------------------------------------------------------------------- */
.hero{position:relative; background:var(--ink)}
.hero__media{position:relative; height:clamp(520px,92svh,880px); overflow:hidden}
.hero__media img{width:100%; height:100%; object-fit:cover}
.hero__scrim{position:absolute; inset:0; background:var(--scrim); pointer-events:none}
@media (min-width:900px){
  .hero__scrim{background:var(--scrim-left),var(--scrim)}
}
.hero__inner{
  position:absolute; inset:auto 0 0 0;
  padding:0 var(--pad-gutter) clamp(44px,7vw,84px);
  max-width:var(--maxw); margin-inline:auto;
  display:flex; flex-direction:column; align-items:center; text-align:center;
}
@media (min-width:900px){
  .hero__inner{align-items:flex-start; text-align:left; left:0; right:0}
}
/* CENTRE ON THE INK, NOT THE CANVAS (brand-canon.md §4, TODO.md §2a).
   Both lock-up files carry baked-in padding, and it is asymmetric, so the
   canvas box lies about where the artwork is. Measured off the source PNGs
   rather than taken from the doc's rounded figures:

     stacked    1500x762   ink 100,78 -> 1400,656   pad L6.67 R6.67 T10.24 B13.91
     horizontal 3039x470   ink 151,84 -> 2929,395   pad L4.97 R3.62 T17.87 B15.96

   The padding is cancelled with negative margins derived from the file's own
   aspect ratio, so the compensation stays exact at every width. Percentage
   margins would resolve against the container's INLINE size, not the image's
   height, so the height is recomputed in calc() instead. */
/* Widths are re-set because the lock-ups are wider-per-unit-of-type than the
   plain wordmark they replace (6.47:1 and 1.97:1 against 5.45:1). Held at the
   old width the lettering would have shrunk — the opposite of what the review
   asked for. These keep the NAME at the size Grace approved: 340px matches
   canon §4's own arithmetic for a 390px viewport (~168px tall, wordmark ~286px,
   above the ~240px legibility floor); 510px is 430 x 6.466/5.449. */
.hero__lockup{
  --lockup-w:min(340px,88vw);
  --lockup-h:calc(var(--lockup-w) / (1500 / 762));
  /* aspect-ratio, not the width/height attributes: <picture> swaps in a
     3039x470 file above 900px while the attributes still say 1500x762, and
     without this the box would resize when the desktop file lands. */
  width:var(--lockup-w); height:auto; aspect-ratio:1500 / 762;
  margin-top:calc(var(--lockup-h) * -0.1024);
  margin-bottom:calc(26px - var(--lockup-h) * 0.1391);
}
@media (min-width:900px){
  /* One <img>, swapped by <picture>, so the aspect ratio and therefore the
     padding compensation both change at this breakpoint. */
  .hero__lockup{
    --lockup-w:min(510px,48vw);
    --lockup-h:calc(var(--lockup-w) / (3039 / 470));
    aspect-ratio:3039 / 470;
    margin-top:calc(var(--lockup-h) * -0.1787);
    margin-bottom:calc(22px - var(--lockup-h) * 0.1596);
    margin-left:calc(var(--lockup-w) * -0.0497);
  }
}
.hero h1{color:var(--chalk); max-width:20ch; text-wrap:balance}
.hero__cta{margin-top:clamp(26px,3vw,38px)}
.hero__scrollcue{
  position:absolute; bottom:14px; left:50%; translate:-50% 0;
  width:1px; height:38px; background:linear-gradient(to bottom,transparent,var(--bleu-pale));
}

/* ---------------------------------------------------------------------
   2 — introduction + facts strip
   --------------------------------------------------------------------- */
.intro{text-align:center}
.intro .body{margin-inline:auto; text-align:center}
.facts{
  margin-top:clamp(36px,5vw,58px);
  border-top:1px solid var(--rule); border-bottom:1px solid var(--rule);
  padding:18px 0;
  display:flex; flex-wrap:wrap; justify-content:center;
  gap:6px clamp(10px,2vw,22px);
  font:500 var(--fs-sc)/1.5 var(--font-text);
  font-variant-caps:all-small-caps; letter-spacing:var(--ls-eyebrow);
  color:var(--ink-soft);   /* was --bleu-profond, 4.78:1 → 8.02:1 */
}
.facts li{display:flex; align-items:center; gap:clamp(10px,2vw,22px)}
/* the separator was --bleu-pale at 1.40:1 */
.facts li:not(:last-child)::after{content:"·"; color:var(--bleu-profond); letter-spacing:0}
.facts li:first-child{color:var(--ink)}

/* ---------------------------------------------------------------------
   2b — highlights
   --------------------------------------------------------------------- */
.highlights{
  display:grid; gap:clamp(30px,4vw,48px);
  grid-template-columns:1fr;
}
@media (min-width:760px){ .highlights{grid-template-columns:repeat(3,1fr)} }
.highlight{display:flex; gap:18px; align-items:flex-start}
@media (min-width:760px){ .highlight{flex-direction:column; gap:16px} }
/* Icon slot. Reserved at final dimensions and filled with the LE mark;
   commissioned icons replace the contents, not the box (spec §2b). */
.highlight__icon{
  flex:0 0 auto;
  width:var(--icon-box); height:var(--icon-box);
  display:flex; align-items:center; justify-content:center;
  border:1px solid var(--rule);
}
.highlight__icon img{height:60%; width:auto; opacity:.85}
.highlight__label{
  font:500 var(--fs-ui)/1.3 var(--font-text);
  font-variant-caps:all-small-caps; letter-spacing:var(--ls-sc);
  color:var(--ink);
}
.highlight__text{font-size:var(--fs-caption); color:var(--ink-soft); margin-top:7px; line-height:1.6}

/* ---------------------------------------------------------------------
   3 — the rooms
   --------------------------------------------------------------------- */
.rooms{
  display:grid; gap:clamp(22px,3vw,28px);
  grid-template-columns:1fr;
  margin-top:clamp(34px,4vw,52px);
}
@media (min-width:900px){ .rooms{grid-template-columns:repeat(3,1fr)} }

.room{
  position:relative; text-align:left;
  background:var(--papier); border:1px solid var(--rule);
  padding:0 0 22px; cursor:pointer; width:100%;
  font:inherit; color:inherit;
  transition:box-shadow .22s ease, border-color .22s ease;
}
.room:hover{box-shadow:0 16px 40px rgba(38,38,43,.09); border-color:var(--bleu)}
.room .frame{border-bottom:1px solid var(--rule)}
.room img{transition:scale .5s cubic-bezier(.2,.7,.3,1)}
.room:hover img{scale:1.03}
.room__body{padding:20px clamp(18px,2vw,24px) 0; position:relative}
.room__name{font:400 var(--fs-h3)/1.2 var(--font-display)}
.room__note{font-size:var(--fs-caption); color:var(--ink-soft); margin-top:9px; line-height:1.6}
.room__more{
  display:inline-block; margin-top:14px;
  font:400 var(--fs-sc)/1 var(--font-text);
  font-variant-caps:all-small-caps; letter-spacing:var(--ls-sc);
  color:var(--bleu-profond);
}
/* LE mark, corner detail (spec §3) */
.room__mark{
  position:absolute; right:clamp(18px,2vw,24px); top:20px;
  height:34px; width:auto; opacity:.5;
}

/* --- room dialog --- */
.roomdlg{
  border:0; padding:0; max-width:min(980px,94vw); width:100%;
  max-height:92svh; background:var(--papier); color:var(--ink);
  box-shadow:0 30px 90px rgba(24,19,14,.32);
  opacity:0; translate:0 16px;
  transition:opacity .24s ease, translate .24s ease, display .24s allow-discrete, overlay .24s allow-discrete;
}
.roomdlg[open]{opacity:1; translate:0 0}
@starting-style{ .roomdlg[open]{opacity:0; translate:0 16px} }
.roomdlg::backdrop{background:rgba(24,19,14,0); transition:background .24s ease, display .24s allow-discrete, overlay .24s allow-discrete}
.roomdlg[open]::backdrop{background:rgba(24,19,14,.62)}
@starting-style{ .roomdlg[open]::backdrop{background:rgba(24,19,14,0)} }

.roomdlg__scroll{max-height:92svh; overflow-y:auto; overscroll-behavior:contain}
.roomdlg__hero{position:relative}
.roomdlg__hero .frame{aspect-ratio:3/2}
@media (max-width:640px){ .roomdlg__hero .frame{aspect-ratio:4/5} }
.roomdlg__close{
  position:absolute; top:14px; right:14px; z-index:2;
  width:40px; height:40px; border:0; border-radius:50%;
  background:rgba(255,253,250,.92); color:var(--ink);
  font:400 24px/1 var(--font-text); cursor:pointer;
}
.roomdlg__close:hover{background:var(--papier)}
.roomdlg__body{padding:clamp(24px,3.4vw,40px)}
.roomdlg__name{font:400 var(--fs-h2)/1.14 var(--font-display)}
.roomdlg__facts{
  margin-top:22px; padding-top:18px; border-top:1px solid var(--rule);
  display:grid; gap:12px 28px; grid-template-columns:1fr;
}
@media (min-width:640px){ .roomdlg__facts{grid-template-columns:repeat(2,1fr)} }
.roomdlg__facts dt{
  font:500 var(--fs-sc)/1.4 var(--font-text);
  font-variant-caps:all-small-caps; letter-spacing:var(--ls-eyebrow);
  color:var(--bleu-profond);
}
.roomdlg__facts dd{font-size:var(--fs-caption); color:var(--ink-soft); margin-top:3px}

/* gallery — bounded horizontal snap track (motion-spec §3) */
.gallery{
  margin-top:28px; display:flex; gap:12px;
  overflow-x:auto; scroll-snap-type:x mandatory;
  padding-bottom:10px; overscroll-behavior-x:contain;
}
.gallery .frame{
  flex:0 0 auto; scroll-snap-align:start;
  width:min(78vw,320px); aspect-ratio:2/3;
}
.gallery .frame--land{aspect-ratio:3/2; width:min(88vw,470px)}

.roomdlg__foot{
  margin-top:26px; padding-top:20px; border-top:1px solid var(--rule);
  display:flex; flex-wrap:wrap; gap:14px; align-items:center;
  justify-content:space-between;
}
.roomdlg__nav{display:flex; gap:8px}
.roomdlg__nav button{
  background:none; border:1px solid var(--rule); color:var(--bleu-profond);
  font:400 var(--fs-sc)/1 var(--font-text);
  font-variant-caps:all-small-caps; letter-spacing:var(--ls-sc);
  padding:11px 16px; cursor:pointer;
}
.roomdlg__nav button:hover{border-color:var(--bleu); color:var(--ink)}

/* ---------------------------------------------------------------------
   4 — the house
   --------------------------------------------------------------------- */
.houserow{
  display:grid; gap:clamp(20px,3vw,44px); align-items:center;
  grid-template-columns:1fr;
}
.houserow + .houserow{margin-top:clamp(56px,7vw,96px)}
@media (min-width:900px){
  .houserow{grid-template-columns:1.15fr .85fr}
  .houserow:nth-child(even) .houserow__media{order:2}
}
.houserow__text h3{margin-bottom:4px}

.vignettes{
  margin-top:clamp(56px,7vw,96px);
  display:grid; gap:12px; grid-template-columns:repeat(3,1fr);
}

/* full-bleed band */
.band{position:relative; background:var(--ink)}
.band .frame{aspect-ratio:4/5; max-height:78svh}
@media (min-width:760px){ .band .frame{aspect-ratio:21/9} }
.band__scrim{position:absolute; inset:0; background:var(--scrim); pointer-events:none}
.band__quote{
  position:absolute; inset:auto 0 0 0; padding:0 var(--pad-gutter) clamp(34px,5vw,64px);
  max-width:var(--maxw); margin-inline:auto;
}
.band__quote p{
  font:italic 400 var(--fs-quote)/1.34 var(--font-display);
  color:var(--chalk); max-width:22ch;
}
/* Desktop only: the quote centres in the photograph instead of sitting low
   (Grace's review). It is already left-aligned; this only moves it vertically.
   The mobile block below 760px is approved as-is and is left untouched — which
   is why this is scoped to the same breakpoint the band's aspect ratio uses.
   Centred text needs cover at mid-height, where the bottom-up --scrim has
   thinned out, so --scrim-left is layered in. That is not a re-tune: it is the
   same token, used for the same job, as the desktop hero. */
@media (min-width:760px){
  .band__scrim{background:var(--scrim-left),var(--scrim)}
  .band__quote{
    inset:0; display:flex; flex-direction:column; justify-content:center;
    padding-block:clamp(34px,5vw,64px);
  }
}

/* ---------------------------------------------------------------------
   5 — write to grace (the inquiry form)
   --------------------------------------------------------------------- */
.formwrap{
  max-width:660px; margin-inline:auto; margin-top:clamp(30px,4vw,46px);
  background:var(--papier); border:1px solid var(--rule);
  padding:clamp(24px,4vw,48px);
}
/* The three rules alone did not read as "there are multiple steps" — Grace's
   review. They stay (she liked the restraint); a plain worded count is set
   beside them and carries the meaning. No stepper component. */
.steps{
  display:flex; gap:12px; align-items:center;
  font:500 var(--fs-sc)/1 var(--font-text);
  font-variant-caps:all-small-caps; letter-spacing:var(--ls-eyebrow);
  color:var(--bleu-profond); margin-bottom:26px;   /* --bleu was 2.93:1 */
}
.steps__count{flex:0 0 auto; white-space:nowrap}
.steps__rules{flex:1 1 auto; display:flex; gap:8px; align-items:center}
.steps__rules span{flex:1; height:1px; background:var(--bleu-pale)}
.steps__rules span.is-on{background:var(--bleu-profond)}

.screen[hidden]{display:none}
/* Moved OUT of .formwrap and up into the description copy, Grace's review
   2026-08-06 — recorded in design/booking-platform.md §Screen 1. It still
   reads before the fields, which is the requirement. */
.policy{
  max-width:var(--measure); margin:26px auto 0; text-align:left;
  background:var(--linen); border-left:2px solid var(--bleu);
  padding:16px 18px; font-size:var(--fs-caption); line-height:1.62;
  color:var(--ink-soft);
}
.section--linen .policy{background:var(--papier)}
.field + .field{margin-top:18px}
.fieldrow{display:grid; gap:18px; grid-template-columns:1fr}
@media (min-width:560px){ .fieldrow{grid-template-columns:1fr 1fr} }
.field label{
  display:block; margin-bottom:7px;
  font:500 var(--fs-sc)/1.4 var(--font-text);
  font-variant-caps:all-small-caps; letter-spacing:var(--ls-eyebrow);
  color:var(--bleu-profond);
}
.field input,.field textarea{
  width:100%; font:400 var(--fs-body)/1.5 var(--font-text); color:var(--ink);
  background:var(--chalk); border:1px solid var(--rule); border-radius:1px;
  padding:12px 13px;
}
.field input:focus,.field textarea:focus{border-color:var(--bleu); outline-offset:1px}
.field textarea{min-height:130px; resize:vertical}
.field small{display:block; margin-top:6px; font-size:var(--fs-caption); color:var(--ink-soft)}

.err{
  margin-top:16px; font-size:var(--fs-caption); color:var(--ink);
  background:rgba(138,151,166,.16); border-left:2px solid var(--bleu-profond);
  padding:11px 14px;
}
.err[hidden]{display:none}

/* Continue/Send sits right, Back stays left (Grace's review). With one button
   the row has no Back, so justify-content:flex-end puts it right on its own;
   with two, margin-inline-end:auto pushes Back back to the left. */
.formnav{display:flex; gap:12px; align-items:center; margin-top:26px; justify-content:flex-end}
.formnav .cta{flex:0 0 auto}
.formnav .cta--ghost{margin-inline-end:auto}
/* the right-pointing arrow on Continue */
.cta__arrow{margin-left:.6em; font-variant-caps:normal; line-height:1}

/* honeypot — off-screen but NOT display:none, and untabbable */
.hp{
  position:absolute; width:1px; height:1px; overflow:hidden;
  clip-path:inset(50%); white-space:nowrap;
}

.thanks{text-align:center; padding:clamp(14px,3vw,30px) 0}
.thanks img{width:74px; margin:0 auto 20px; opacity:.75}

.formnote{
  text-align:center; margin-top:22px;
  font-size:var(--fs-caption); color:var(--ink-soft);
}

/* ---------------------------------------------------------------------
   6 — details preview
   --------------------------------------------------------------------- */
.detailgrid{
  display:grid; gap:0; grid-template-columns:1fr;
  margin-top:clamp(28px,3.5vw,42px);
  border-top:1px solid var(--rule);
}
@media (min-width:760px){ .detailgrid{grid-template-columns:1fr 1fr; column-gap:clamp(30px,4vw,60px)} }
.detailrow{
  display:flex; gap:18px; justify-content:space-between; align-items:baseline;
  padding:15px 0; border-bottom:1px solid var(--rule);
}
.detailrow dt{
  font:500 var(--fs-sc)/1.4 var(--font-text);
  font-variant-caps:all-small-caps; letter-spacing:var(--ls-eyebrow);
  color:var(--bleu-profond); flex:0 0 auto;
}
.detailrow dd{font-size:var(--fs-caption); color:var(--ink-soft); text-align:right}

/* ---------------------------------------------------------------------
   7 — footer
   --------------------------------------------------------------------- */
.footer{position:relative; background:var(--linen); overflow:hidden; padding-block:clamp(56px,7vw,92px)}
.footer__rose{
  position:absolute; right:-9%; bottom:-24%;
  width:min(560px,86vw); opacity:.34; pointer-events:none;
  mix-blend-mode:multiply;
}
.footer__inner{position:relative; text-align:center}
.footer__mark{width:min(300px,68vw); margin:0 auto 26px}
.footer address{font-style:normal; font-size:var(--fs-caption); line-height:1.9; color:var(--ink-soft)}
.footer address a{color:var(--bleu-profond)}
.footer__legal{
  margin-top:28px; padding-top:20px; border-top:1px solid var(--rule);
  font-size:var(--fs-caption); color:var(--ink-soft);
}

/* ---------------------------------------------------------------------
   the floating card (spec §6)
   --------------------------------------------------------------------- */
.stickycard{
  position:fixed; z-index:55;
  background:var(--papier); border:1px solid var(--bleu);
  display:none;
  opacity:0; transition:opacity .24s ease, translate .24s ease,
                        display .24s allow-discrete;
}
.stickycard.is-in{display:block; opacity:1; translate:0 0}

/* MOBILE — a floating card, not a bottom bar. Grace's review 2026-08-06: the
   old full-bleed bar merged into the bottom edge of the viewport and she did
   not notice it was there. It is now inset from all three edges so the page
   shows through underneath it, and it carries a real drop shadow so it reads
   as sitting above the page rather than welded to it. Safe-area inset is kept
   and the JS that hides it over the footer is untouched. */
.stickycard{
  left:var(--pad-gutter); right:var(--pad-gutter);
  bottom:calc(16px + env(safe-area-inset-bottom));
  padding:14px 16px;
  box-shadow:0 10px 20px rgba(38,38,43,.13), 0 22px 54px rgba(38,38,43,.22);
  translate:0 calc(100% + 24px);
}
.stickycard.is-in{translate:0 0}
@starting-style{ .stickycard.is-in{opacity:0; translate:0 calc(100% + 24px)} }
.stickycard__inner{
  display:flex; align-items:center; gap:14px;
  max-width:var(--maxw); margin-inline:auto;
}
.stickycard__art{flex:0 0 auto; width:44px; opacity:.92}
.stickycard__title{
  font:400 var(--fs-h3)/1.2 var(--font-display); flex:1 1 auto;
}
.stickycard__dismiss{
  flex:0 0 auto; width:34px; height:34px; border:0; background:none;
  color:var(--ink-soft); font:400 22px/1 var(--font-text); cursor:pointer;
}

/* DESKTOP — bottom-right corner, not right-edge-centred (Grace's review). */
@media (min-width:900px){
  .stickycard{
    left:auto; right:26px; bottom:26px; top:auto;
    width:214px; padding:20px 18px 18px;
    box-shadow:0 12px 24px rgba(38,38,43,.12), 0 28px 64px rgba(38,38,43,.24);
    translate:0 22px;
  }
  .stickycard.is-in{translate:0 0}
  @starting-style{ .stickycard.is-in{opacity:0; translate:0 22px} }
  .stickycard__inner{flex-direction:column; text-align:center; gap:12px}
  .stickycard__art{width:88px; margin-inline:auto}
  .stickycard__title{flex:0 0 auto}
  .stickycard__dismiss{position:absolute; top:4px; right:4px}
}

/* ---------------------------------------------------------------------
   motion (motion-spec.md)
   Everything here is additive: content is visible at rest. If the
   @supports fails or JS never runs, the page is a plain, complete page.
   --------------------------------------------------------------------- */
@supports (animation-timeline:view()){
  @media (prefers-reduced-motion:no-preference){
    .rise{
      animation:rise-in linear both;
      animation-timeline:view();
      animation-range:entry 4% cover 26%;
    }
    .wipe{
      animation:clip-wipe linear both;
      animation-timeline:view();
      animation-range:entry 2% cover 30%;
    }
    .rooms .room:nth-child(2){animation-delay:0s; animation-range:entry 0% cover 32%}
    .rooms .room:nth-child(3){animation-range:entry -4% cover 34%}
    .draw{
      animation:rule-draw linear both;
      animation-timeline:view();
      animation-range:entry 10% cover 22%;
    }
  }
}
@keyframes rise-in{
  from{opacity:0; transform:translateY(26px)}
  to{opacity:1; transform:none}
}
@keyframes clip-wipe{
  from{clip-path:inset(14% 0 0 0); opacity:.55}
  to{clip-path:inset(0 0 0 0); opacity:1}
}
@keyframes rule-draw{ from{width:0} to{width:var(--rule-w)} }

/* hero: scale-and-settle, no parallax (it competes with the drone video
   that replaces this still) */
@media (prefers-reduced-motion:no-preference){
  .hero__media img{animation:settle 1400ms cubic-bezier(.2,.7,.3,1) both}
}
@keyframes settle{ from{scale:1.06} to{scale:1} }

/* Same-document view transition: the card photo morphs into the dialog
   hero. Names are assigned in JS so only one pair is live at a time. */
::view-transition-old(room-hero),
::view-transition-new(room-hero){
  animation-duration:.36s; mix-blend-mode:normal;
}

@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;
  }
  .hero__media img{animation:none; scale:1}
  .room:hover img{scale:1}
  .rise,.wipe{opacity:1; transform:none; clip-path:none}
  .draw{width:var(--rule-w)}
  .stickycard{translate:none}
  .stickycard.is-in{translate:none}
}

/* off-screen sections are not laid out until needed */
/* .defer previously carried content-visibility:auto with a 900px intrinsic-size
   estimate. Removed 2026-08-06: the estimate is wrong for every section, so the
   document grew 6972 -> 9208px while an in-page scroll was in flight and every
   "Write to Grace" click landed ~2340px short of #write. The anchor is the whole
   conversion path; the perf win on an 8-section page with correctly-sized lazy
   images did not come close to paying for it. Do not reintroduce without
   per-section contain-intrinsic-size AND an anchor-landing test. */
.defer{}

.visually-hidden{
  position:absolute; width:1px; height:1px; overflow:hidden;
  clip-path:inset(50%); white-space:nowrap;
}

/* ---------------------------------------------------------------------
   /details/ shell
   --------------------------------------------------------------------- */
.page-head{padding-block:clamp(48px,7vw,96px) clamp(30px,4vw,48px); text-align:center}
.dtable{width:100%; border-collapse:collapse; margin-top:20px}
.dtable th,.dtable td{
  text-align:left; padding:14px 0; border-bottom:1px solid var(--rule);
  vertical-align:top; font-size:var(--fs-caption); line-height:1.65;
}
.dtable th{
  width:38%; font:500 var(--fs-sc)/1.5 var(--font-text);
  font-variant-caps:all-small-caps; letter-spacing:var(--ls-eyebrow);
  color:var(--bleu-profond);
}
.dtable td{color:var(--ink-soft)}
.amenities{
  margin-top:20px; display:grid; gap:10px 30px;
  grid-template-columns:1fr;
}
@media (min-width:640px){ .amenities{grid-template-columns:repeat(2,1fr)} }
@media (min-width:960px){ .amenities{grid-template-columns:repeat(3,1fr)} }
.amenities li{
  font-size:var(--fs-caption); color:var(--ink-soft);
  padding-bottom:9px; border-bottom:1px solid var(--rule);
}
.dblock + .dblock{margin-top:clamp(46px,6vw,78px)}

/* ---------------------------------------------------------------------
   APPENDED BY THE MARKUP PASS — four gaps the stylesheet did not cover.
   Nothing above this rule was altered.
   --------------------------------------------------------------------- */

/* <picture> is an inline wrapper the layout above does not expect: it breaks
   `.frame img{height:100%}` and `.hero__media img{height:100%}` by sitting
   between the sized box and the image. display:contents removes it from
   layout while keeping art direction. */
picture{display:contents}

/* The reset sets `img{max-width:100%}` but not `height:auto`, so every image
   that carries real width/height attributes (required for CLS) and is then
   sized by a CSS `width` kept its attribute height — .stickycard__art was
   1500px tall, .footer__mark and .footer__rose likewise. Every deliberate
   height in this stylesheet is set through a class selector, which still
   wins on specificity (.frame img, .hero__media img, .header__home img,
   .highlight__icon img, .room__mark). */
img{height:auto}

/* A room card is a <button>, so its boxes have to be <span>s (button content
   model is phrasing content). Give them their block layout back. */
.room .frame,.room__body,.room__name,.room__note{display:block}

/* The sticky card's CTA is "a plain header, set beneath the facade"
   (spec-stay.md §6) — it is an <a>, so it needs the link chrome removed. */
.stickycard__title{color:var(--ink); text-decoration:none}
.stickycard__title:hover{color:var(--bleu-profond)}

/* two spacing utilities: the "All the details →" link under .detailgrid,
   and centring a --measure-width block inside a centred section. */
.moreline{margin-top:26px}
.centred{margin-inline:auto}

/* `.field + .field{margin-top:18px}` also matches the two fields inside a
   .fieldrow grid, which staggered check-out below check-in. */
.fieldrow > .field + .field{margin-top:0}
