/* Spenser Wayne Interiors — site styles. Reads every value from tokens.css. */

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

/* No gray box over a link as it's tapped on iPhone (it covered a whole tile for a moment) */
html { -webkit-text-size-adjust: 100%; -webkit-tap-highlight-color: transparent; }

/* The ground under iPhone Safari's bars (iOS 26; measured in the 26.3 simulator, 10/12). Safari
   fills its status bar with html's background where it can't show the page through it (the
   top of a page), tints the fade under its toolbar with it, and shows it past either end of
   the page. Body's own color would win over it, so body paints its ink as an image (same
   look, no color). js/site.js sets data-ground to what's under the bars: ink while the home's
   hero is up under the clock, or once scrolled, while the services band or the footer is at
   the screen's foot; paper otherwise (the light header, and every paper section, which an
   ink fade had hazed). Paper while the menu is open. Without JS: paper, ink on home.
   It changes on the menu's fade, not at once (Luke 10/12: the bars' tint jumped ahead of the
   menu): Safari reads it afresh every frame, so its bars fade with the page. */
html { background-color: var(--paper); transition: background-color var(--menu-duration) var(--ease-in-out); }
html[data-ground="ink"]:not(.menu-open),
html:not([data-ground]):has(.hero) { background-color: var(--ink); }

[hidden] { display: none !important; } /* hidden wins over any layout's display (the form's thank-you swap) */

/* The page is a column: a short page's main grows, so the footer sits at the window's foot */
body {
  display: flex; flex-direction: column; min-height: 100vh; min-height: 100svh;
  background: linear-gradient(var(--ink), var(--ink)); /* an image: see html above */
  color: var(--ink);
  font-family: var(--font-sans);
  font-weight: var(--weight-book);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

main { flex: 1 0 auto; background: var(--paper); }

a { color: inherit; text-decoration: none; }

/* Photos can't be dragged off the page or long-pressed to save (Luke 9/30) */
img { -webkit-user-drag: none; -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
/* Nor do links start a drag: a press that moved a few pixels on a trackpad began dragging the
   link instead of opening it, so the click never came (Luke 10/15) */
a { -webkit-user-drag: none; }

/* A photo's <picture> only offers its AVIF (tools/optimize.py): no box of its own, so the
   <img> lays out as if it weren't there */
picture { display: contents; }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap;
}

/* Lenis smooth scroll (js/site.js) */
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }
.lenis.lenis-stopped { overflow: hidden; }

/* Until General Sans is in, the header and hero type wait, then fade in (inline script in
   index.html's <head>). The first paint never shows the fallback font, whose narrower name
   wrapped the subline onto two lines before snapping back. Captions only hide: js/hero.js
   owns their opacity. Luke 10/12: only the header's type waits (the bar and the logo don't
   use the font, so they're there from the first paint), and only on the first page of a
   visit, so the header never blinks on a page change. */
.hero__intro { transition: opacity .5s var(--ease-out); }
html.fonts-wait :is(.site-nav, .site-header .button), html.fonts-wait .hero__intro { opacity: 0; }
html.fonts-in :is(.site-nav, .site-header .button) { animation: type-in .5s var(--ease-out); }
@keyframes type-in { from { opacity: 0; } } /* an animation, not a transition: the button has its own */
html.fonts-wait .hero__caption { visibility: hidden; }

/* Safari runs transitions as a page opens, from the page as it is before its styles are in:
   the menu panel faded out over each page, the ground faded in from white (Luke 10/12). The
   head script sets html.loading and js/site.js clears it a frame after it runs, so nothing
   transitions until the page is on the screen. */
html.loading, html.loading *, html.loading *::before, html.loading *::after { transition: none !important; }

/* Page entrance (Luke 10/12, third pass: the sweep down the screen read as a scan). The page
   comes in line by line. The header stays put, the one thing that carries over from the last
   page, and what's on the screen rises into place in reading order: each line of type, photo,
   field or button fades in as it rises --enter-rise, a row at a time (things side by side come
   in together), --enter-stagger apart. Nothing below the screen moves, and nothing on scroll.
   The head script (tools/build-pages.py, index.html) sets html.enter, so the page opens as
   blank paper under the header. js/enter.js (not deferred, so it runs as the page is read)
   waits for the font if it isn't in yet (at most 800ms), gives each line its row's delay
   (--enter-delay) and sets html.entering. The type doesn't wait for the photos
   (Luke 10/15: it left the page blank for a second): one still loading waits unseen over its
   frame's backdrop (.enter-img) and fades in when it arrives (.enter-img-in), so none pops in.
   On home only the name and subline come in; the photo is there from the start. Reduced
   motion: a short fade, all at once. */
html.enter:not(:has(.hero)) :is(main > *, .site-footer), html.enter .hero__intro > * { opacity: 0; }
html.entering .enter-line {
  animation: enter-rise var(--enter-duration) var(--enter-ease) both, enter-fade var(--enter-fade) var(--ease-fade) both;
  animation-delay: var(--enter-delay);
}
/* The rules between the lines rise and fade in with the row they sit in, as the type does. A
   cell's ::before/::after line moves itself; a border can't move apart from its box, so it
   waits unseen while a copy of it (.enter-ghost, js/site.js) comes in in its place */
html.entering .enter-before::before {
  animation: enter-rise var(--enter-duration) var(--enter-ease) var(--enter-delay-before) both, enter-fade var(--enter-fade) var(--ease-fade) var(--enter-delay-before) both;
}
html.entering .enter-after::after {
  animation: enter-rise var(--enter-duration) var(--enter-ease) var(--enter-delay-after) both, enter-fade var(--enter-fade) var(--ease-fade) var(--enter-delay-after) both;
}
html.entering .enter-rule { border-color: transparent !important; }
.enter-ghost { position: absolute; pointer-events: none; }
img.enter-img { opacity: 0; }
img.enter-img-in { animation: enter-fade var(--enter-fade) var(--ease-fade) both; }
@keyframes enter-rise { from { translate: 0 var(--enter-rise); } }
@keyframes enter-fade { from { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  html.entering .enter-line, img.enter-img-in { animation: enter-fade .4s var(--ease-fade) both; }
  html.entering .enter-before::before, html.entering .enter-after::after { animation: enter-fade .4s var(--ease-fade) both; }
}
/* With a mouse, the last page also fades out under the header as this one opens (a view
   transition between the pages). Not on phones and tablets: through the fade, iPhone Safari
   draws its bars flat in the new page's ground, an ink band over the last page on the way to
   home, and drops the photo under its toolbar (Luke 10/12, tested in the iOS 26 simulator). */
@media (hover: hover) and (pointer: fine) { @view-transition { navigation: auto; } }
/* The new page takes clicks while it fades in: the fade's layer over it swallowed them, so a
   quick click on the next link in the bar did nothing (Luke 10/15) */
::view-transition { pointer-events: none; }

/* How far a cover that's part of the page (the menu) runs past the screen at either end, under
   Safari's status bar and toolbar and past a rubber-band pull */
:root { --cover-over: 160px; }

/* ---------- Header ---------- */
/* Fixed at the top (once js/site.js runs; without JS it sits over the hero and scrolls away).
   Two copies, laid out identically: the clear one (paper type on the photo) and a light one
   (paper background, ink type, hairline, the logo). As the hero's bottom edge rises through
   the header, site.js clips the clear copy to above the edge and the light copy to below
   it, so the header turns light exactly where the page does. --p is that progress, 0 to 1.
   Pages without a hero are written with the light header alone and already fixed
   (tools/build-pages.py), so it's the same header from the first paint (Luke 10/12). */

.site-header {
  position: absolute; inset: 0 0 auto; z-index: 5;
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center;
  padding: var(--header-pad-y) var(--gutter);
  color: var(--paper);
}
.has-sticky-header .site-header { position: fixed; }
html.has-sticky-header { scroll-padding-top: var(--header-height, 88px); } /* anchors land below it */
/* Its height, from its parts (the logo or the button, whichever is taller, plus the padding),
   so what sits under it is placed right on the first paint. Luke 10/12: js/site.js used to
   measure it after the first paint, which moved every page up 6px (23px on phones). */
:root { --header-height: calc(max(var(--logo-height), var(--text-button) + 2 * var(--button-pad-y)) + 2 * var(--header-pad-y)); }

/* iPhone Safari's status bar (iOS 26; WebKit's fixed container edges, read 10/12): it looks for
   a fixed bar across the top of the screen (a hit test at its top middle, which ignores
   clipping and pointer-events but not visibility). If it finds one, it fills the status bar
   with the bar's background-color, or with the colour the bar paints there, and keeps that
   colour for as long as the same bar is found; if it finds none, it shows the page under the
   status bar. A hidden <header> it keeps finding, so the light copy is a <div>. And it looks
   again only when a fixed element comes or goes. So the clear copy has no background at all
   and paints nothing at its top edge (the status bar shows the photo, and over the hero, the
   menu's panel as it fades in); the light copy is out of the layout, not just clipped away,
   while the hero is under the whole header (.is-away, js/site.js), so it's found only once
   it's showing, and then the status bar takes its paper; and js/site.js makes Safari look
   again when the light copy fills the bar. Its paper is an image, not a background-color, so
   while the edge crosses Safari goes by what it paints, not the colour it would have. */
.site-header--light { background: linear-gradient(var(--paper), var(--paper)); color: var(--ink); }
.site-header--light.is-away { display: none; }
.site-header--light::after { /* hairline, drawn in as the edge crosses */
  /* A border, as every other rule on the page (Luke 10/1: it read heavier than them as a
     filled 1.5px box, which a browser can smear across two pixels; a border it rounds the
     same way everywhere) */
  content: ""; position: absolute; inset: auto 0 0;
  border-top: var(--hairline-width) solid var(--hairline); opacity: var(--p, 1);
}

/* The logo (Brand/SWI - Logo.svg). On desktop it shows only on the light header. A stroke thickens its
   hairline letters so they hold up at this size (--logo-stroke); overflow stays visible so
   the stroke isn't cut at the SVG's edges. */
.site-logo { grid-column: 1; justify-self: start; display: block; }
.site-logo svg {
  display: block; height: var(--logo-height); width: auto; overflow: visible;
  fill: currentColor; stroke: currentColor; stroke-width: var(--logo-stroke); stroke-linejoin: round;
}
/* Over the hero on desktop the hero's own name stands in for it; the compact header (up to 900)
   shows it over the hero too, in paper (Luke 10/12: always there, as on every other page) */
@media (min-width: 901px) { .site-header:not(.site-header--light) .site-logo { visibility: hidden; } }
/* No slide of its own (Luke 10/1: it rose at a different pace from the bar and crowded the
   rule): the edge uncovers it in place, with the nav, the button and the rule */
.site-logo:focus-visible { outline: 1px solid currentColor; outline-offset: var(--focus-offset); }

.site-nav { grid-column: 2; display: flex; justify-content: center; gap: var(--nav-gap); font-size: var(--text-nav); font-weight: var(--weight-nav); letter-spacing: var(--tracking-nav); }
.site-nav a { position: relative; transition: opacity var(--duration-quick) var(--ease-out); }
.site-nav a:hover { opacity: .65; }
/* Each link takes clicks across the bar's full height and half the gap either side, not only on
   its word (Luke 10/15: the words are 23px tall, and a click that landed just off one, or drifted
   off it as the trackpad was pressed, went nowhere) */
.site-nav a::after { content: ""; position: absolute; inset: calc((var(--header-height, 88px) - 100%) / -2) calc(var(--nav-gap) / -2); }
/* No mark on the page you're on (Luke 10/12: no indicator, only the hover). The links keep
   aria-current, so screen readers still say which page it is. */

.button {
  display: inline-flex; align-items: center;
  padding: var(--button-pad-y) var(--button-pad-x);
  border-radius: var(--radius-button);
  font-size: var(--text-button); font-weight: var(--weight-button); letter-spacing: var(--tracking-nav); line-height: 1;
  white-space: nowrap; /* a label never breaks onto two lines (the phone header's did at 375) */
  transition: background-color var(--duration-quick) var(--ease-out), color var(--duration-quick) var(--ease-out);
  cursor: pointer; /* also on "Book a consultation", a placeholder <a> with no href until booking exists */
}
.button--paper { background: var(--paper); color: var(--ink); }
/* Ink: the primary button on paper (a form's submit; the light header's is css below) */
.button--ink { background: var(--ink); color: var(--paper); border: 0; font-family: inherit; }
.button--ink:hover { background: rgba(var(--ink-rgb), .84); }
.button:focus-visible { outline: 1px solid currentColor; outline-offset: var(--focus-offset); }
.button--ink:focus-visible { outline-color: var(--ink); }
.button:disabled { opacity: .72; cursor: progress; } /* a form's button while it sends */
/* Large: the statement's size at the button's own proportions (its padding, in em). The menu's
   Book a consultation (Luke 10/12: larger, to sit with the menu's big links) */
.button--large { font-size: var(--text-statement); letter-spacing: var(--tracking-statement); padding: .65em .94em; }
/* Secondary: an outline in the current color, same size as a filled button (the line is an
   inset shadow, not a border). Hover washes it faintly so it never reads as primary. */
.button--secondary { box-shadow: inset 0 0 0 var(--hairline-width) currentColor; }
.button--secondary:hover { background: color-mix(in srgb, currentColor 9%, transparent); } /* on paper or ink */
.site-header .button { grid-column: 3; justify-self: end; }
.button--paper:hover { background: rgba(var(--paper-rgb), .82); }
/* The header's button: over the hero an outline in paper, so the photos lead (Luke 10/1: the
   paper fill was too harsh there); on the light header it fills in, ink with paper type */
.site-header--light .button--secondary { background: var(--ink); color: var(--paper); box-shadow: none; }
.site-header--light .button--secondary:hover { background: rgba(var(--ink-rgb), .84); }

/* The menu button (the compact header, up to 900; Luke 10/12: an icon, not the word): three bars
   in the hairline's weight, its right edge on the gutter. Open, the outer two cross and the
   middle one goes (js/site.js sets aria-expanded). Its hit area runs past the bars, to a
   finger's size, without adding to the header's height. */
.menu-toggle {
  display: none; position: relative;
  width: var(--menu-icon-w); height: var(--menu-icon-h); padding: 0;
  background: none; border: 0; color: inherit;
  cursor: pointer;
  transition: opacity var(--duration-quick) var(--ease-out);
}
.menu-toggle::before { content: ""; position: absolute; inset: calc((var(--menu-icon-h) - 44px) / 2) calc((var(--menu-icon-w) - 44px) / 2); } /* 44px square */
/* Each change runs in two steps, after Apple's (tokens.css --menu-icon-*): the transition is
   the one for where it's going. Closing (this one): the X turns back, then the bars slide
   apart and the middle one comes back between them. */
.menu-toggle__bars > span {
  position: absolute; left: 0; right: 0; top: calc(50% - var(--hairline-width) / 2);
  border-top: var(--hairline-width) solid currentColor;
  transition:
    rotate var(--menu-icon-turn-back) var(--ease-icon-turn),
    translate var(--menu-icon-slide) var(--ease-icon-slide) var(--menu-icon-overlap),
    opacity var(--menu-icon-slide) linear var(--menu-icon-overlap);
}
/* Opening: the bars slide together onto the middle one, which goes as they meet, then turn */
.menu-toggle[aria-expanded="true"] .menu-toggle__bars > span {
  transition:
    translate var(--menu-icon-slide) var(--ease-icon-slide),
    rotate var(--menu-icon-turn) var(--ease-icon-turn) var(--menu-icon-overlap),
    opacity 0s linear var(--menu-icon-slide);
}
.menu-toggle__bars > span:first-child { translate: 0 calc(var(--menu-icon-h) / -2 + var(--hairline-width) / 2); }
.menu-toggle__bars > span:last-child { translate: 0 calc(var(--menu-icon-h) / 2 - var(--hairline-width) / 2); }
.menu-toggle[aria-expanded="true"] .menu-toggle__bars > span:first-child { translate: none; rotate: 45deg; }
.menu-toggle[aria-expanded="true"] .menu-toggle__bars > span:nth-child(2) { opacity: 0; }
.menu-toggle[aria-expanded="true"] .menu-toggle__bars > span:last-child { translate: none; rotate: -45deg; }
@media (hover: hover) { .menu-toggle:hover { opacity: .65; } } /* a phone keeps :hover after a tap, which left it faded */
.menu-toggle:focus-visible { outline: 1px solid currentColor; outline-offset: var(--focus-offset); }
@media (prefers-reduced-motion: reduce) { .menu-toggle__bars > span { transition: none; } }

/* ---------- Hero ---------- */

.hero {
  position: relative;
  height: 100vh; height: calc(var(--hero-h, 100svh) + var(--hero-runway, 0px)); min-height: 560px;
  overflow: hidden;
  color: var(--paper);
  background: var(--ink);
}
/* iPhone Safari, portrait (Luke 10/12: the photo has to fill the whole screen, top and bottom).
   Safari draws page content behind its toolbar, so the photo runs on under it: 58px past the
   large viewport, Safari's own strip, the same on every Face ID iPhone (measured in the iOS
   26.3 simulator; ~/.claude/playbooks/ios26-liquid-glass-bars.md). The status bar shows the page
   only when there's page above the screen, so the photo also runs --hero-runway above it, and
   the page opens scrolled to the runway's foot (index.html, after the hero; js/site.js eases
   it back there if you pull down into it). The script cuts the runway to the status bar's own
   height, all it needs (120px is the fallback). Native scroll snapping can't hold the page
   there instead: after a flick into the top, iOS jumps back in one frame (tested 10/12). The type stays in the screen's first view: the name
   in the middle of it, the caption the gutter above the toolbar. */
/* The screen's height under the status bar: the large viewport, and on an iPhone in portrait
   Safari's toolbar strip under it too (the menu covers it all) */
:root { --screen-h: 100vh; }
@supports (-webkit-touch-callout: none) {
  @media (max-width: 600px) and (orientation: portrait) {
    :root {
      --screen-h: calc(100lvh + 58px); --hero-h: var(--screen-h); --hero-runway: 120px;
      /* the middle of the whole screen, status bar and all (--hero-top-inset, the status bar's
         height, measured by the script after the hero) */
      --hero-center: calc(var(--hero-runway) + (var(--hero-h) - var(--hero-top-inset, 0px)) / 2);
    }
  }
}

/* Stage = everything that parallaxes on scroll-out (photos, shading, captions), as on
   Here & Away. js/hero.js drives the swipe (clip + scale) with inline styles; the
   rules below are only the starting state before it runs. */
.hero__stage { position: absolute; inset: 0; }
.hero__slides {
  position: absolute; inset: 0; isolation: isolate;
  opacity: 0; transform: scale(1.04);
  transition: opacity 1.4s var(--ease-out), transform 2.8s var(--ease-out);
}
.hero.is-loaded .hero__slides { opacity: 1; transform: none; }

/* Each slide = the photo (clipped + scaled by js/hero.js) and its caption, which sits
   outside the clip so the next photo wipes up over the old caption, as on Here & Away. */
.hero__slide { position: absolute; inset: 0; overflow: hidden; z-index: 0; }
.hero__slide:first-child { z-index: 2; }
.hero__photo { position: absolute; inset: 0; }
.hero__slide:not(:first-child) .hero__photo { clip-path: inset(100% 0% 0% 0%); transform: scale(1.1); }
.hero__slide img {
  display: block; width: 100%; height: 100%;
  object-fit: cover; object-position: var(--focus, center);
}

/* Soft shading for the white type, the mockup's gradients eased back now that the photos
   carry a photo-wide grade (tools/grade-hero.py). It rides on each photo so it wipes in
   with it and stays under the caption. Phones get more from the left, where the type
   crosses the middle of the photo. */
.hero__photo::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    linear-gradient(to bottom, rgba(var(--scrim), .34) 0, rgba(var(--scrim), .1) 130px, rgba(var(--scrim), 0) 240px),
    linear-gradient(to top, rgba(var(--scrim), .3) 0, rgba(var(--scrim), 0) 260px),
    linear-gradient(to right, rgba(var(--scrim), .22) 0, rgba(var(--scrim), 0) 50%);
}

/* Room + project, bottom-left on the page gutter (locked, Luke 9/30); rolls with each
   change (js/hero.js). A link to the project: on hover the caption slides up out of its
   line and "View this project" with an arrow rises into its place, the same flip as Crescent's
   portfolio cards, without the underline. No text-shadow: the clip would cut its glow.
   Each line travels a little past its own height (--flip-travel), so no descender or
   ascender is left showing at the clip's edge (Luke 9/30: a sliver of the "g" in "Sitting"
   stayed visible above "View this project"). */
.hero__caption {
  position: absolute; z-index: 1;
  left: var(--gutter); bottom: var(--gutter);
  font-size: var(--text-body); font-weight: var(--weight-body);
  letter-spacing: var(--tracking-body); line-height: var(--leading-text); /* not --leading-body (under 1): the flip's clip would cut descenders */
}
.hero__slide:not(:first-child) .hero__caption { opacity: 0; }
.hero__caption:focus-visible { outline: 1px solid var(--paper); outline-offset: 4px; }
.hero__flip { display: grid; overflow: hidden; --flip-travel: .3em; }
.hero__flip > * { grid-area: 1 / 1; transition: translate var(--duration) var(--ease-out); }
.hero__flip-view {
  display: inline-flex; align-items: center; gap: .3em;
  translate: 0 calc(100% + var(--flip-travel)); white-space: nowrap;
}
.hero__flip-view svg { width: .75em; height: auto; flex: none; }
.hero__caption:hover .hero__flip-text,
.hero__caption:focus-visible .hero__flip-text { translate: 0 calc(-100% - var(--flip-travel)); }
.hero__caption:hover .hero__flip-view,
.hero__caption:focus-visible .hero__flip-view { translate: 0 0; }

/* The block is as wide as the name; the subline wraps inside that width (Luke 9/30).
   Desktop sits it --hero-intro-x in from the left (tokens.css; In Common With's offset); phones use the gutter.
   --hero-intro-y is how far down the block's middle sits (50% = the vertical center). */
.hero__intro {
  position: absolute; z-index: 2;
  left: var(--hero-intro-x, var(--gutter)); top: var(--hero-intro-y, 50%); transform: translateY(-50%);
  width: fit-content; max-width: calc(100% - 2 * var(--gutter));
  text-shadow: 0 0 18px rgba(var(--scrim), .3);
}
.hero__title {
  font-size: var(--text-display);
  font-weight: var(--weight-display);
  line-height: var(--leading-display);
  letter-spacing: var(--tracking-display);
  white-space: nowrap;
}
/* Slide indicator: one short bar per image; the active one fills while it holds */
.hero__progress {
  position: absolute; z-index: 3;
  right: calc(var(--gutter) - 10px); top: 50%; transform: translateY(-50%);
  display: flex; flex-direction: column;
}
.hero__tick {
  display: block; padding: 4px 10px;
  background: none; border: 0; cursor: pointer;
}
.hero__tick-track {
  display: block; width: 3px; height: 30px; overflow: hidden;
  background: rgba(var(--paper-rgb), .3);
  transition: background-color var(--duration-quick) var(--ease-out);
}
.hero__tick:hover .hero__tick-track { background: rgba(var(--paper-rgb), .55); }
.hero__tick:focus-visible { outline: 1px solid var(--paper); outline-offset: 2px; }
.hero__tick-fill {
  display: block; width: 100%; height: 100%;
  background: var(--paper);
  transform: scaleY(0); transform-origin: top;
}

.hero__lede {
  margin-top: 14px;
  font-size: var(--text-body);
  font-weight: var(--weight-body);
  letter-spacing: var(--tracking-body);
  line-height: var(--leading-body);
  width: 0; min-width: 100%; /* adds nothing to the block's width, then fills it */
}


/* ---------- Compact header and the menu (tablet and phone) ---------- */
/* Up to 900 the four links don't fit between the logo and the button (they ran into it from
   761 to about 860), so the header is the logo at left and the menu button at right (Luke
   10/12: the word Menu beside the big button looked bad; the button moved into the menu), and
   the links open in the menu: KOBU's, a paper panel under the header with the links large at
   top left. The header stays on top while it's open (on home it turns light, even over the
   hero), the bars crossed in the same place. The links are the statement style at the menu's
   size; the button and the studio's email and phone sit at the foot. */

@media (max-width: 900px) {
  .site-header { display: flex; justify-content: space-between; align-items: center; }
  .site-nav, .site-header .button { display: none; }
  .menu-toggle { display: block; }
}

/* One layer that fades in and out as a whole (Luke 10/12, second pass: over the hero, Safari's
   bars turned white first, then the light header, then the panel faded in, and back in pieces).
   The panel is part of the page, not fixed (Safari clips a fixed layer at its toolbar): js/site.js sets it where the
   screen is when it opens (--menu-top; the page is still while it's open), and it runs
   --cover-over past the screen under Safari's status bar and toolbar, so Safari shows it fading
   there with the rest. The header stays as it is: over the hero its type and bars turn ink and
   its hairline comes in, on the same fade. Closed, it's display: none (the fade still runs:
   display switches discretely, after the fade out and before the fade in). Its foot sits the
   tiles' space above the screen's foot, clear of Safari's toolbar (100dvh is what's above it). */
.mobile-menu {
  position: absolute; left: 0; right: 0; z-index: 4; /* under the header (5) */
  top: calc(var(--menu-top, 0px) - var(--cover-over));
  height: calc(var(--screen-h) + 2 * var(--cover-over));
  flex-direction: column; justify-content: space-between; gap: var(--space-tiles);
  padding: calc(var(--cover-over) + var(--header-height, 88px) + var(--space-page-top)) var(--gutter) calc(var(--cover-over) + var(--screen-h) - 100dvh + var(--space-tiles));
  background: var(--paper); color: var(--ink);
  display: none; opacity: 0;
  transition-property: opacity, display; transition-duration: var(--menu-duration); transition-timing-function: var(--ease-in-out);
  transition-behavior: allow-discrete;
}
/* A phone turned on its side has no room for it all: the panel the screen's height, scrolling */
@media (max-height: 520px) {
  .mobile-menu {
    position: fixed; inset: 0; height: auto;
    padding: calc(var(--header-height, 88px) + var(--space-page-top)) var(--gutter) var(--space-tiles);
    overflow-y: auto; overscroll-behavior: contain;
  }
}
.mobile-menu.is-open { display: flex; opacity: 1; }
@starting-style { .mobile-menu.is-open { opacity: 0; } }
@media (min-width: 901px) { .mobile-menu.is-open { display: none; } }
.mobile-menu__nav {
  display: flex; flex-direction: column; align-items: flex-start;
  font-size: var(--text-menu); font-weight: var(--weight-statement); letter-spacing: var(--tracking-statement); line-height: var(--leading-menu);
}
.mobile-menu__nav a { transition: opacity var(--duration-quick) var(--ease-out); }
@media (hover: hover) { .mobile-menu__nav a:hover { opacity: .65; } }
.mobile-menu__nav a:first-child { margin-top: calc(-1 * var(--cap-gap)); } /* the header's rule to its capitals is the page top, as on every page */
.mobile-menu a:focus-visible { outline: 1px solid currentColor; outline-offset: var(--focus-offset); }
/* The foot: Book a consultation, large (Luke 10/12: the email and phone are gone) */
.mobile-menu__cta { align-self: flex-start; }
/* Open over the hero: the clear header's type and bars turn ink and its hairline comes in, with
   the panel's fade (past the hero the light header is already ink on paper) */
.site-header:not(.site-header--light) { transition: color var(--menu-duration) var(--ease-in-out); }
.site-header:not(.site-header--light)::after {
  content: ""; position: absolute; inset: auto 0 0;
  border-top: var(--hairline-width) solid var(--hairline);
  opacity: 0; transition: opacity var(--menu-duration) var(--ease-in-out);
}
html.menu-open .site-header { color: var(--ink); }
html.menu-open .site-header:not(.site-header--light)::after { opacity: 1; }

@media (max-width: 600px) {
  /* The same room above the logo as below it to the hairline, which sits inside the bottom
     padding (Luke 10/12: it read as more on top, under Safari's status bar) */
  .site-header { padding: calc(var(--header-pad-y-phone) - var(--hairline-width)) var(--gutter) var(--header-pad-y-phone); }
  .site-logo svg { height: var(--logo-height-phone); }
  .menu-toggle { --menu-icon-w: var(--menu-icon-w-phone); --menu-icon-h: var(--menu-icon-h-phone); }
  .hero__title { font-size: var(--text-display-phone); }
  /* The name runs the screen's width less the slide bars (tokens.css --text-display-phone), the
     subline smaller and lighter under it, wrapping inside the name's width as on desktop (Luke
     10/12: the two read too alike). The block's middle is the screen's (--hero-center; the
     middle of the small viewport where Safari's isn't known), as are the slide bars. */
  .hero__intro { left: var(--gutter); top: var(--hero-center, 50svh); }
  .hero__progress { top: var(--hero-center, 50svh); }
  .hero__lede {
    font-size: var(--text-lede-phone); font-weight: var(--weight-book);
    line-height: var(--leading-statement); /* two lines here: .95 (one line's) set them touching */
    text-wrap: balance;
  }
  /* The caption the gutter above the first view's foot, wherever the photo ends under it */
  .hero { --hero-under: calc(var(--hero-h, 100svh) - 100svh); }
  .hero__caption { bottom: calc(var(--hero-under) + var(--gutter)); }
  :root { --header-height: calc(var(--logo-height-phone) + 2 * var(--header-pad-y-phone) - var(--hairline-width)); }
  /* The top and bottom shading start at the first view's edges (above and below them, under
     Safari's bars, the photo keeps the edge's shade) */
  .hero__photo::after {
    background:
      linear-gradient(to bottom, rgba(var(--scrim), .34) var(--hero-runway, 0px), rgba(var(--scrim), .1) calc(var(--hero-runway, 0px) + 130px), rgba(var(--scrim), 0) calc(var(--hero-runway, 0px) + 240px)),
      linear-gradient(to top, rgba(var(--scrim), .3) var(--hero-under), rgba(var(--scrim), 0) calc(var(--hero-under) + 260px)),
      linear-gradient(to right, rgba(var(--scrim), .34) 0, rgba(var(--scrim), .16) 70%, rgba(var(--scrim), .08) 100%);
  }
  .hero__tick-track { height: 22px; }
}

@media (prefers-reduced-motion: reduce) {
  .hero__slides { transform: none; transition: opacity .6s linear; }
  .hero__flip > * { transition: none; }
}
