/* Nails D'art & Spa. Mockup stylesheet, shared by every page.
   Palette per DESIGN.md section 3, verified against the shop's Google Business
   Profile photographs. Only --ink-muted moved, because #7C6E62 measured 4.4:1
   on paper and failed AA at 18px. */
:root{
  --paper:#F7F2EA; --surface:#FFFDF9; --surface-2:#F0E9DE;
  --ink:#2E241E; --ink-muted:#736A5E; --ink-faint:#A4988B;
  --wood:#8A5A3C; --line:#E2D8C8;
  --burgundy:#7E1C2B; --burgundy-h:#6A1624;
  --focus:#8A5A3C;
  --s1:8px; --s2:16px; --s3:24px; --s4:40px; --s5:64px; --s6:96px;
  --serif:"EB Garamond",Georgia,serif;
  --sans:"Be Vietnam Pro",system-ui,-apple-system,sans-serif;

  /* Type scale. The serif carries scale, the sans carries structure.
     Sizes are rem so they respect the reader's browser setting, and the
     three serif steps are fluid because headings are the only thing that
     should grow with the viewport. Body stays fixed.
     Adjacent serif steps are >= 1.25 apart. The serif sits far enough above
     the sans that a section heading can never read lighter than the medium
     weight sans beneath it, which is what went wrong before. */
  --t-display: clamp(2.5rem, 1.55rem + 3.6vw, 3.5rem);    /* 40 to 56 */
  --t-title:   clamp(2rem, 1.62rem + 1.5vw, 2.625rem);    /* 32 to 42 */
  --t-section: clamp(1.625rem, 1.45rem + 0.7vw, 2rem);    /* 26 to 32 */
  --t-sub:     1.3125rem;   /* 21 */
  --t-lead:    1.3125rem;   /* 21 */
  --t-body:    1.125rem;    /* 18 */
  --t-label:   1rem;        /* 16 */
}
*,*::before,*::after{box-sizing:border-box}
/* The hidden attribute must beat any display set by a class below. */
[hidden]{display:none!important}
html{background:var(--paper)}
body{margin:0;background:transparent;color:var(--ink);font:400 var(--t-body)/1.7 var(--sans);
     -webkit-font-smoothing:antialiased;font-kerning:normal;font-optical-sizing:auto}
/* Stucco. One asset, page ground only, 3 percent. DESIGN.md section 4. */
body::before{
  content:"";position:fixed;inset:0;z-index:-1;pointer-events:none;opacity:.03;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='220' height='220' filter='url(%23n)'/%3E%3C/svg%3E");
}
@media print{body::before{display:none}}

img{display:block;width:100%;height:auto;border-radius:2px}
a{color:inherit}
:focus-visible{outline:2px solid var(--focus);outline-offset:2px;border-radius:2px}

.wrap{max-width:1200px;margin:0 auto;padding:0 var(--s3)}
@media(min-width:768px){.wrap{padding:0 var(--s4)}}
.narrow{max-width:760px}

/* Type scale. DESIGN.md section 5.
   Line heights never go below 1.2 on a heading, because Vietnamese stacks a
   tone mark above a vowel that already carries a diacritic and it clips.
   The display was 1.15, which broke that rule on the one heading most likely
   to be translated. */
.display   {font:400 var(--t-display)/1.2  var(--serif);letter-spacing:-0.01em;margin:0}
.page-title{font:400 var(--t-title)/1.2    var(--serif);margin:0}
.section   {font:400 var(--t-section)/1.28 var(--serif);margin:0 0 var(--s4)}
.subsection{font:500 var(--t-sub)/1.4      var(--sans); margin:0}
.lead      {font:400 var(--t-lead)/1.6     var(--sans); margin:0}
.label     {font:500 var(--t-label)/1.4    var(--sans)}
.muted     {color:var(--ink-muted)}
.display,.page-title,.section,.subsection{text-wrap:balance}
.lead,.prose p,.quote blockquote{text-wrap:pretty}

.masthead{border-bottom:1px solid var(--line)}
.masthead .wrap{display:flex;align-items:center;justify-content:space-between;gap:var(--s3);min-height:88px;flex-wrap:wrap}
.wordmark{font:400 1.5rem/1.3 var(--serif);color:var(--wood);text-decoration:none}
.nav{display:flex;gap:var(--s3);align-items:center;flex-wrap:wrap}
.nav a{font:400 var(--t-body)/1.7 var(--sans);text-decoration:none;min-height:52px;display:inline-flex;align-items:center}
.nav a:hover{color:var(--ink-muted)}
.nav a[aria-current="page"]{text-decoration:underline;text-underline-offset:6px;text-decoration-thickness:1px}

.btn{display:inline-flex;align-items:center;justify-content:center;min-height:52px;padding:0 var(--s3);
     border-radius:4px;font:500 var(--t-body)/1.4 var(--sans);text-decoration:none;cursor:pointer;border:1px solid transparent}
.btn-primary{background:var(--burgundy);color:var(--surface);border-color:var(--burgundy)}
.btn-primary:hover{background:var(--burgundy-h);border-color:var(--burgundy-h)}
.btn-primary[disabled]{background:var(--surface-2);color:var(--ink-faint);border-color:var(--line);cursor:not-allowed}
.btn-secondary{background:transparent;color:var(--ink);border-color:var(--line)}
.btn-secondary:hover{background:var(--surface-2)}
.btn-quiet{font:400 var(--t-body)/1.7 var(--sans);text-decoration:underline;text-underline-offset:4px;
           text-decoration-thickness:1px;display:inline-flex;align-items:center;min-height:52px;
           background:none;border:0;padding:0;cursor:pointer;color:var(--ink)}

section{padding:var(--s5) 0}
@media(min-width:768px){section{padding:var(--s6) 0}}
.page-head{padding:var(--s5) 0 0}
.page-head .lead{margin-top:var(--s2);color:var(--ink-muted);max-width:760px}

/* Social row. Text links, never icons, so nothing competes with the action. */
.social{display:flex;gap:var(--s3);justify-content:center;flex-wrap:wrap;margin-top:var(--s3)}
.social a{min-height:52px;display:inline-flex;align-items:center;text-decoration:underline;
          text-underline-offset:4px;text-decoration-thickness:1px}
.social a:hover{color:var(--ink-muted)}

/* Hero slider. Scroll snap, no library, no autoplay. Controls under the
   photograph, never over it. DESIGN.md section 8. */
.slides{display:flex;overflow-x:auto;scroll-snap-type:x mandatory;scroll-behavior:smooth;
        scrollbar-width:none;-ms-overflow-style:none}
.slides::-webkit-scrollbar{display:none}
/* Hero.
   The photograph is shown almost whole and the text overlaps its foot, rather
   than the text living inside the picture's height and eating most of it. Only
   the last fifth of the image is fully covered; the ramp above that leaves the
   picture readable, so about eighty percent of the shot stays visible. The
   awning, the flower pots, the iron chairs and the pavement all survive, which
   they did not when the veil was sized to the text.

   The ramp resolves to solid --paper before the first line of text, so nothing
   is ever set over live photography. DESIGN.md section 8 permits text on a
   photograph only when a solid panel is behind it, and the resolved veil is
   that panel. Recorded in DESIGN.md section 3 as the one gradient in the system.

     --hero-h        how tall the picture is
     --hero-veil-h   how far up from its foot the fade reaches
     --hero-overlap  how far the text rides up over the picture

   The invariant: hidden band = --hero-veil-h * (1 - solid stop) must equal
   --hero-overlap, or the headline lands on a ramp that has not finished. */
:root{
  --hero-h:min(66vh,700px);
  --hero-veil-h:57%;   /* of the picture height */
  --hero-solid:65%;    /* where the ramp finishes inside the veil */
  --hero-overlap:18%;  /* of the picture height, must stay under 20 */
}
.hero{position:relative;isolation:isolate;padding:0}
.hero-media{position:relative;z-index:0}
.slides{display:flex;overflow-x:auto;scroll-snap-type:x mandatory;scroll-behavior:smooth;
        scrollbar-width:none;-ms-overflow-style:none}
.slides::-webkit-scrollbar{display:none}
.slides img{flex:0 0 100%;width:100%;height:var(--hero-h);aspect-ratio:auto;
            object-fit:cover;object-position:50% 46%;scroll-snap-align:start;border-radius:0}
.hero-veil{position:absolute;inset:auto 0 0 0;height:var(--hero-veil-h);z-index:1;
  pointer-events:none;
  background:linear-gradient(to bottom,
    rgba(247,242,234,0) 0%,
    rgba(247,242,234,0.45) 34%,
    rgb(247,242,234) var(--hero-solid),
    rgb(247,242,234) 100%)}
.hero-text{position:relative;z-index:2;margin:calc(var(--hero-h) * -0.18) auto 0;
           text-align:center;max-width:760px;padding:0 var(--s3) var(--s4)}
.hero-text .display{font-size:clamp(2rem,1.35rem + 2.6vw,3rem)}
.hero-text .lead{margin-top:var(--s2);color:var(--ink-muted)}
.hero-text .btn{margin-top:var(--s3)}
.hero .dots{justify-content:center;padding-top:var(--s2)}

/* On a phone the text block is nearly as tall as any sensible hero, so there is
   no room to overlay it on a panel that has fully resolved. Rather than set the
   headline over live photography, narrow screens stack: photograph, then text on
   the page ground. The veil is only a wider-screen treatment. */
@media(max-width:767px){
  .slides img{height:auto;aspect-ratio:16/9;object-position:50% 50%}
  .hero-veil{display:none}
  .hero-text{margin-top:0;max-width:none;padding:var(--s4) var(--s3) 0}
}
@media(prefers-reduced-motion:reduce){.slides{scroll-behavior:auto}}
.dots{display:flex;gap:var(--s1);padding-top:var(--s2)}
.dot{width:52px;height:52px;display:grid;place-items:center;background:none;border:0;padding:0;cursor:pointer}
.dot i{width:10px;height:10px;border-radius:50%;background:var(--line);display:block}
.dot[aria-current="true"] i{background:var(--surface-2);outline:2px solid var(--wood);outline-offset:2px}

.grid{display:grid;grid-template-columns:repeat(2,1fr);gap:var(--s1)}
@media(min-width:768px){.grid{grid-template-columns:repeat(3,1fr)}}
.tile{display:block;border-radius:2px;overflow:hidden}
.tile img{aspect-ratio:4/5;object-fit:cover}

/* The polish rack. Small colour swatches in even rows inside a thin double
   rule, taken from the frame on the wall. The one framed element on this page. */
.rack{border:1px solid var(--line);padding:var(--s1);border-radius:2px;margin-bottom:var(--s4)}
.rack-inner{border:1px solid var(--line);padding:var(--s2);border-radius:2px;
            display:flex;flex-wrap:wrap;gap:var(--s1)}
.swatch{width:52px;height:52px;display:grid;place-items:center;background:none;border:0;padding:0;cursor:pointer}
.swatch i{width:26px;height:26px;border-radius:50%;display:block;border:1px solid var(--line)}
.swatch[aria-pressed="true"] i{outline:2px solid var(--wood);outline-offset:3px}
.rack-foot{display:flex;justify-content:space-between;align-items:center;gap:var(--s3);
           flex-wrap:wrap;margin-top:var(--s2)}

.services{border-top:1px dotted var(--line);max-width:760px}
.service{display:block;padding:var(--s3) 0;border-bottom:1px dotted var(--line);text-decoration:none}
.service .meta{display:flex;justify-content:space-between;gap:var(--s3);margin-top:var(--s1);
               color:var(--ink-muted);font-variant-numeric:tabular-nums}
/* The qualifier stays secondary, the price does not. It is the one thing a
   visitor is scanning the column for, so it keeps full ink. Colour is the
   only property that changes between the two. */
.service .meta>span:last-child{color:var(--ink)}
/* Some menu items carry no qualifier at all. Two lines then stranded the price
   under an empty row, so those collapse to a single baseline instead. */
.service.solo{display:flex;justify-content:space-between;align-items:baseline;gap:var(--s3)}
.service.solo .meta{margin-top:0}

.quotes,.strengths{display:grid;grid-template-columns:1fr;gap:var(--s4);max-width:760px}
.quote{margin:0}
.quote blockquote{margin:0;font:400 var(--t-lead)/1.6 var(--sans)}
.quote figcaption{margin-top:var(--s1);color:var(--ink-muted)}

.artists{display:grid;grid-template-columns:1fr;gap:var(--s4)}
@media(min-width:768px){.artists{grid-template-columns:repeat(3,1fr);gap:var(--s3)}}
.portrait-pending{aspect-ratio:4/5;background:var(--surface-2);border:1px solid var(--line);
                  border-radius:2px;display:flex;align-items:flex-end;padding:var(--s2)}
.portrait-pending span{color:var(--ink-faint)}
.artist h3{margin:var(--s2) 0 var(--s1)}
.artist p{margin:0;color:var(--ink-muted)}

.visit{display:grid;grid-template-columns:1fr;gap:var(--s4)}
@media(min-width:900px){.visit{grid-template-columns:1fr 1fr;gap:var(--s5)}}
.visit h3{margin:0 0 var(--s2)}
.visit h3 ~ h3{margin-top:var(--s4)}
.visit p,.visit address{margin:0;font-style:normal}
.map{width:100%;aspect-ratio:3/2;border:1px solid var(--line);border-radius:2px;background:var(--surface-2)}
/* Beside the address column the map is the shorter of the two, which left a
   large empty right hand side. Let it fill the row instead of holding a ratio. */
@media(min-width:900px){
  .visit>div:last-child{display:flex}
  .visit .map{aspect-ratio:auto;height:100%;min-height:420px}
}

/* Featured image, a thin double rule with 8px between the rules.
   One per page maximum. DESIGN.md section 7. */
.framed{border:1px solid var(--line);padding:var(--s1);border-radius:2px}
.framed>div{border:1px solid var(--line);padding:var(--s1);border-radius:2px}

.two-col{display:grid;grid-template-columns:1fr;gap:var(--s5)}
@media(min-width:900px){.two-col{grid-template-columns:1fr 1fr;gap:var(--s6)}}
.prose{max-width:70ch}
.prose p{margin:0 0 var(--s3)}

/* Booking. Four steps, one screen each on mobile. DESIGN.md section 9. */
.step[hidden]{display:none}
.pick{display:block;width:100%;text-align:left;background:var(--surface);border:1px solid var(--line);
      border-radius:4px;padding:var(--s2) var(--s3);min-height:52px;cursor:pointer;font:inherit;color:inherit}
.pick + .pick{margin-top:var(--s1)}
.pick .meta{display:flex;justify-content:space-between;gap:var(--s3);color:var(--ink-muted);
            margin-top:var(--s1);font-variant-numeric:tabular-nums}
.pick[aria-pressed="true"]{border-color:var(--wood);background:var(--surface-2)}
.chips{display:flex;flex-wrap:wrap;gap:var(--s1)}
.chip{min-height:52px;min-width:88px;padding:0 var(--s2);border:1px solid var(--line);border-radius:4px;
      background:var(--surface);font:400 var(--t-body)/1.4 var(--sans);font-variant-numeric:tabular-nums;
      color:var(--ink);cursor:pointer}
.chip[aria-pressed="true"]{border-color:var(--wood);background:var(--surface-2)}
.chip[disabled]{color:var(--ink-faint);background:var(--surface-2);cursor:not-allowed;text-decoration:line-through}
.field{margin-bottom:var(--s3);max-width:520px}
.field label{display:block;margin-bottom:var(--s1)}
.field input,.field textarea{width:100%;min-height:52px;padding:var(--s2);border:1px solid var(--line);
      border-radius:4px;background:var(--surface);font:400 var(--t-body)/1.4 var(--sans);color:var(--ink)}
.field textarea{min-height:120px;line-height:1.7}
.total{border-top:1px solid var(--line);margin-top:var(--s4);padding-top:var(--s3);
       display:flex;justify-content:space-between;gap:var(--s3);flex-wrap:wrap;align-items:flex-end}
.actions{display:flex;gap:var(--s2);align-items:center;flex-wrap:wrap;margin-top:var(--s4)}
.empty{color:var(--ink-muted)}

.foot{border-top:1px solid var(--line);padding:var(--s5) 0;margin-top:var(--s6)}
.foot .wrap{display:flex;justify-content:space-between;gap:var(--s4);flex-wrap:wrap}
.foot a{min-height:52px;display:inline-flex;align-items:center;text-decoration:none}
.foot a:hover{color:var(--ink-muted)}
.foot ul{list-style:none;margin:0;padding:0}
.foot .fine{color:var(--ink-muted);font-size:var(--t-label);margin-top:var(--s4)}
