/* Frozen Moments site template — TEMPLATE VERSION 114 */
/* ============================================================
   Frozen Moments Photography — site template
   All colour, type and spacing decisions live in :root.
   The StudioFlow Brand Kit will eventually write these values.
   ============================================================ */

:root{
  /* v91 — THE SITE DESIGNER'S VARIABLES. Every theme-level colour and font is read through a
     --sf-* variable; the value after the comma is what the site has always used, so with nothing set
     the site is exactly as it was. Two things can set them, in this order: the export's Theme card
     (FM.theme, written by applyTheme) and then StudioFlow's Site Designer (site-design.json). Nothing
     else should write --ink, --paper and the rest directly any more. */
  --ink:var(--sf-text,#14171a);
  --ink-soft:var(--sf-text-soft,#3d444b);
  --paper:var(--sf-bg,#faf9f7);
  --paper-2:var(--sf-bg-alt,#f0eeea);
  --line:var(--sf-line,#dcd8d1);
  --accent:var(--sf-accent,#2f5d62);      /* deep coastal teal */
  --accent-warm:#b98b4e;  /* brass, used sparingly */
  --white:#ffffff;

  --font-display:var(--sf-font-heading,"Playfair Display",Georgia,serif);
  --font-body:var(--sf-font-body,"DM Sans",system-ui,-apple-system,"Segoe UI",sans-serif);

  --step--1:0.82rem;
  --step-0:1rem;
  --step-1:1.3rem;
  --step-2:1.8rem;
  --step-3:2.6rem;
  --step-4:clamp(2.6rem,6vw,4.6rem);

  --gutter:clamp(1.25rem,5vw,5rem);
  --radius:var(--sf-radius,2px);
  --shadow:0 24px 60px rgba(20,23,26,.16);

  /* The button's colours. DELIBERATELY NO FALLBACK HERE: an unset --sf-* leaves these invalid, so
     every rule that reads them falls back to its OWN default exactly as before (the ghost button's
     hover text, the closing band's button and so on each have a different one). */
  --btn-bg:var(--sf-button);
  --btn-fg:var(--sf-button-text);
  --btn-hover-bg:var(--sf-button-hover);
  --btn-hover-fg:var(--sf-button-hover-text);
  --btn-radius:var(--sf-button-radius);
}

*{box-sizing:border-box}
html,body{max-width:100%;overflow-x:hidden}
html{scroll-behavior:smooth}
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *{animation:none!important;transition:none!important}
}
body{
  margin:0;background:var(--paper);color:var(--ink);
  font-family:var(--font-body);font-size:var(--step-0);line-height:1.6;
  -webkit-font-smoothing:antialiased;
}
img{display:block;max-width:100%}
a{color:inherit}
h1,h2,h3{font-family:var(--font-display);font-weight:500;line-height:1.1;margin:0;color:var(--sf-heading,inherit)}
h1{font-size:var(--step-4)}
h2{font-size:var(--step-3)}
h3{font-size:var(--step-1)}
p{margin:0 0 1em}
:focus-visible{outline:2px solid var(--accent-warm);outline-offset:3px}

/* ---------- header ---------- */
.site-header{
  position:sticky;top:0;z-index:60;
  display:flex;align-items:center;justify-content:space-between;
  gap:1rem;padding:.45rem var(--gutter);   /* v62 — given up to the logo; the bar's height is unchanged */
  background:color-mix(in srgb,var(--paper) 92%,transparent);backdrop-filter:blur(10px);
  border-bottom:1px solid var(--line);
}
.site-header.on-dark{background:transparent;border-bottom-color:transparent;color:var(--white)}
.brand{display:flex;align-items:center;gap:.6rem;text-decoration:none;font-weight:600;letter-spacing:.02em}
.brand-mark{
  display:grid;place-items:center;width:32px;height:32px;
  background:var(--ink);color:var(--paper);font-size:.72rem;letter-spacing:.06em;
}
.nav{display:flex;align-items:center;gap:1.6rem}
.nav a{text-decoration:none;font-size:var(--step--1);letter-spacing:.06em;text-transform:uppercase}
.nav a:not(.button):hover{color:var(--accent)}
.menu-toggle{display:none;background:none;color:inherit;border:1px solid var(--line);padding:.45rem .8rem;font:inherit;font-size:var(--step--1);cursor:pointer}
.cart-pill{
  display:inline-flex;align-items:center;gap:.4rem;border:1px solid var(--line);
  padding:.4rem .7rem;text-decoration:none;font-size:var(--step--1)
}
.cart-pill b{font-weight:600}

/* ---------- buttons ---------- */
.button{
  display:inline-block;padding:.85rem 1.6rem;
  /* g235 — buttons are PILLS, and their four colours are theme keys. Kirk: "Buttons i want them in
     the shape of pills...and have the option to change hover and standard colour". Each falls back
     to what the site did before, so a theme saved without them looks exactly as it does today. */
  background:var(--btn-bg,var(--ink));color:var(--btn-fg,var(--paper));
  text-decoration:none;border:1px solid var(--btn-bg,var(--ink));
  border-radius:var(--btn-radius,999px);
  font-size:var(--step--1);letter-spacing:.08em;text-transform:uppercase;
  font-family:inherit;cursor:pointer;transition:background .2s,color .2s,border-color .2s;
}
.button:hover{
  background:var(--btn-hover-bg,var(--accent));color:var(--btn-hover-fg,var(--btn-fg,var(--paper)));
  border-color:var(--btn-hover-bg,var(--accent));
}
.button[disabled]{opacity:.4;cursor:not-allowed}
/* v45 — Kirk: "two of the buttons ... just look black and no font colour inside ... and hover does
   nothing". g244 fixed the HOVER and left the RESTING state alone, which is why they are fine on
   one page and unreadable on another: `color:inherit` takes whatever the section around them is,
   so on a dark band they were dark text on a transparent background — black on black.
   They now take the Theme card's button colours like the solid one, outlined instead of filled, so
   all three buttons agree wherever they are put and there is ONE place to change them. */
.button-ghost{
  background:transparent;
  color:var(--btn-bg,var(--ink));
  border-color:var(--btn-bg,var(--ink));
}
/* g244 — THE UNREADABLE HOVER. Kirk: "the other 2 turn black and leave black font so they cannot
   be read and i have no idea where to correct this."
   `background:currentColor` resolves against the colour set IN THE SAME RULE — so background became
   var(--paper) and the text became var(--paper) too: identical, invisible. A self-referencing
   colour looks clever and is a trap, because the value it refers to is the one being replaced.
   Now the outline buttons hover to the SAME pair as the solid one, from the Theme card's button
   colours, so all three behave alike and there is one place to change them. */
.button-ghost:hover{
  background:var(--btn-hover-bg,var(--accent));
  color:var(--btn-hover-fg,var(--paper));
  border-color:var(--btn-hover-bg,var(--accent));
}
.button-small{padding:.55rem 1rem}
.button-wide{width:100%;text-align:center}

/* ---------- hero ---------- */
.hero{position:relative;min-height:88vh;display:grid;align-items:end;color:var(--white);overflow:hidden}
.hero>img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
/* v66 — NO DARKENING OVER THE TOP OF THE PICTURE. Kirk asked for the full-frame
   wash to go: it made every hero read as a grey photograph. The gradient now
   starts transparent and only builds in the bottom 45%, where the words are.
   Readability comes from text-shadow on the words themselves rather than from
   dimming the whole frame — the shadow follows the letters, so it costs the
   photograph nothing. --he-scrim-* keep it adjustable (renamed in v70 — see the note at
   the gallery banner for why). */
.hero-overlay{position:absolute;inset:0;background:linear-gradient(180deg,
  rgba(20,23,26,var(--he-scrim-top,0)) 0%,
  rgba(20,23,26,var(--he-scrim-top,0)) 55%,
  rgba(20,23,26,var(--he-scrim-bottom,.72)) 100%)}
.hero-content h1,.hero-content p,.hero-content .eyebrow{
  text-shadow:0 1px 3px rgba(12,14,16,.55),0 2px 14px rgba(12,14,16,.35)}
.hero-content{position:relative;padding:0 var(--gutter) 7rem;max-width:44rem}
.hero-content p{color:rgba(255,255,255,.86)}
.hero-actions{display:flex;flex-wrap:wrap;gap:.75rem;margin-top:1.8rem}
.eyebrow{
  font-size:var(--step--1);letter-spacing:.22em;text-transform:uppercase;
  margin:0 0 .9rem;color:rgba(255,255,255,.7)
}
.eyebrow.dark{color:var(--accent)}
.scroll-cue{
  position:absolute;right:var(--gutter);bottom:2rem;text-decoration:none;
  font-size:var(--step--1);letter-spacing:.16em;text-transform:uppercase;opacity:.8
}

/* ---------- generic sections ---------- */
.section{padding:clamp(4rem,9vw,8rem) var(--gutter)}
.section-heading{max-width:38rem;margin-bottom:3rem}
.intro-grid{display:grid;grid-template-columns:1fr 1fr;gap:clamp(2rem,6vw,6rem);align-items:end}
.lead{font-size:var(--step-1);color:var(--ink-soft)}
.text-link{
  text-decoration:none;border-bottom:1px solid var(--accent);padding-bottom:2px;
  font-size:var(--step--1);letter-spacing:.08em;text-transform:uppercase
}

/* ---------- gallery strip ---------- */

/* ---------- feature band ---------- */
.feature-band{
  display:grid;grid-template-columns:1fr 1fr;gap:clamp(2rem,6vw,5rem);align-items:center;
  padding:clamp(4rem,9vw,8rem) var(--gutter);background:var(--ink);color:var(--paper)
}
.feature-band h2{margin-bottom:1rem}
.feature-band p{color:color-mix(in srgb,var(--paper) 75%,transparent)}
.room-mini{display:block}
.mini-art{line-height:0}
.mini-art img{width:100%;height:auto;display:block}

/* ---------- services ---------- */
.service-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:2.5rem}
.service-grid article{border-top:1px solid var(--line);padding-top:1.2rem}
.service-grid span{display:block;font-size:var(--step--1);letter-spacing:.16em;color:var(--accent);margin-bottom:.7rem}
.service-grid h3{margin-bottom:.5rem}
.service-grid p{color:var(--ink-soft);font-size:.94rem}
.service-grid a{text-decoration:none;font-size:var(--step--1);letter-spacing:.08em;text-transform:uppercase;border-bottom:1px solid var(--accent)}

/* ---------- about ---------- */
.about-section{display:grid;grid-template-columns:minmax(0,.85fr) minmax(0,1.15fr);align-items:start;gap:clamp(2rem,6vw,5rem);align-items:center;padding:clamp(4rem,9vw,8rem) var(--gutter);background:var(--paper-2)}
.about-image img{width:100%;height:auto;display:block}
.about-copy p{color:var(--ink-soft)}
.about-copy h2{margin-bottom:1.2rem}

/* ---------- contact ---------- */
.contact-section{padding:clamp(4rem,9vw,8rem) var(--gutter);background:var(--ink);color:var(--paper);text-align:center}
.contact-actions{display:flex;justify-content:center;flex-wrap:wrap;gap:.75rem;margin:2rem 0 1.5rem}
.location{font-size:var(--step--1);letter-spacing:.1em;text-transform:uppercase;color:color-mix(in srgb,var(--paper) 60%,transparent)}

/* ---------- footer ---------- */
footer{
  display:flex;justify-content:space-between;flex-wrap:wrap;gap:1rem;
  padding:1.6rem var(--gutter);font-size:var(--step--1);
  color:var(--ink-soft);border-top:1px solid var(--line)
}

/* ============================================================
   STORE
   ============================================================ */
.page-head{padding:clamp(3rem,7vw,5.5rem) var(--gutter) 2rem;max-width:52rem}
.page-head h1{font-size:var(--step-3);margin-bottom:.8rem}
.page-head p{color:var(--ink-soft);max-width:36rem}

.filter-bar{
  display:flex;flex-wrap:wrap;gap:.5rem;padding:0 var(--gutter) 2rem;
  border-bottom:1px solid var(--line);margin-bottom:2.5rem
}
.filter{
  background:none;border:1px solid var(--line);padding:.45rem .95rem;cursor:pointer;
  font:inherit;font-size:var(--step--1);letter-spacing:.06em;text-transform:uppercase;
  border-radius:var(--radius);transition:.2s
}
.filter[aria-pressed="true"]{background:var(--ink);color:var(--paper);border-color:var(--ink)}

.art-grid{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));
  gap:clamp(1.5rem,3vw,2.5rem);padding:0 var(--gutter) 5rem
}
.art-card{text-decoration:none;display:block}
.art-card .frame{background:var(--paper-2);overflow:hidden;aspect-ratio:3/2}
.art-card img{width:100%;height:100%;object-fit:cover;transition:transform .7s ease}
.art-card:hover img{transform:scale(1.04)}
.art-card h3{font-size:var(--step-1);margin:.9rem 0 .2rem}
.art-card .meta{font-size:var(--step--1);color:var(--ink-soft);letter-spacing:.04em}

/* ============================================================
   PRODUCT / CONFIGURATOR
   ============================================================ */
.product-layout{
  display:grid;grid-template-columns:1.15fr .85fr;gap:clamp(2rem,5vw,4.5rem);
  padding:clamp(2rem,5vw,4rem) var(--gutter) 5rem;align-items:start
}
.product-stage{position:sticky;top:5.5rem;display:grid;gap:1.2rem}
.stage-art{
  background:var(--paper-2);display:grid;place-items:center;padding:clamp(1.5rem,4vw,3.5rem);
  min-height:min(60vh,520px)
}

.config h1{font-size:var(--step-2);margin-bottom:.3rem}
.config .sub{font-size:var(--step--1);letter-spacing:.14em;text-transform:uppercase;color:var(--accent);margin-bottom:1.6rem}
.config .blurb{color:var(--ink-soft);margin-bottom:2rem}

.step{border-top:1px solid var(--line);padding:1.5rem 0}
.step-label{display:flex;align-items:baseline;justify-content:space-between;gap:1rem;margin-bottom:.9rem}
.step-label h2{font-family:var(--font-body);font-size:var(--step--1);letter-spacing:.14em;text-transform:uppercase;font-weight:600}
.step-label .chosen{font-size:var(--step--1);color:var(--ink-soft)}

.opts{display:flex;flex-wrap:wrap;gap:.5rem}
.opt{
  background:var(--white);border:1px solid var(--line);padding:.6rem .95rem;cursor:pointer;
  font:inherit;font-size:.92rem;border-radius:var(--radius);transition:.15s;text-align:left
}
.opt:hover{border-color:var(--ink-soft)}
.opt[aria-pressed="true"]{border-color:var(--ink);box-shadow:inset 0 0 0 1px var(--ink)}
.opt .price-hint{display:block;font-size:var(--step--1);color:var(--ink-soft);margin-top:.15rem}
.opt-wide{flex:1 1 46%}
.opt-wide b{display:block;font-weight:600}
.opt-wide small{color:var(--ink-soft)}

.addon{
  display:flex;gap:.8rem;align-items:flex-start;border:1px solid var(--line);
  background:var(--white);padding:.85rem 1rem;cursor:pointer;border-radius:var(--radius);margin-bottom:.5rem
}
.addon input{margin-top:.28rem;accent-color:var(--accent)}
.addon b{display:block;font-weight:600}
.addon small{color:var(--ink-soft)}
.addon .cost{margin-left:auto;white-space:nowrap}

.swatches{display:flex;gap:.5rem;margin-top:.7rem}
.swatch{width:30px;height:30px;border-radius:50%;border:2px solid var(--line);cursor:pointer}
.swatch[aria-pressed="true"]{outline:2px solid var(--ink);outline-offset:2px}

.summary{border-top:1px solid var(--ink);padding-top:1.4rem;margin-top:.5rem}
.summary .line{display:flex;justify-content:space-between;font-size:.94rem;color:var(--ink-soft);margin-bottom:.35rem}
.summary .total{display:flex;justify-content:space-between;align-items:baseline;font-size:var(--step-2);font-family:var(--font-display);margin:.7rem 0 1.2rem}
.note{font-size:var(--step--1);color:var(--ink-soft);margin-top:.9rem}

/* ============================================================
   CART
   ============================================================ */
.cart-wrap{padding:0 var(--gutter) 5rem;max-width:60rem}
.cart-row{display:grid;grid-template-columns:88px 1fr auto;gap:1.2rem;align-items:center;border-bottom:1px solid var(--line);padding:1.2rem 0}
.cart-row img{width:88px;height:88px;object-fit:cover;background:var(--paper-2)}
.cart-row .spec{font-size:var(--step--1);color:var(--ink-soft)}
.cart-row .remove{background:none;border:none;font:inherit;font-size:var(--step--1);color:var(--ink-soft);cursor:pointer;text-decoration:underline}
.cart-total{display:flex;justify-content:space-between;align-items:baseline;font-family:var(--font-display);font-size:var(--step-2);margin:1.5rem 0}
.empty{padding:3rem 0;color:var(--ink-soft)}
/* v77 — --ca-note-bg is its OWN background, independent of #cartPage's, because a note meant to
   stay legible needs to be settable separately from whatever page background Kirk picks; --ca-body-fg
   is the SAME "Body colour" field #cartPage's paragraphs already use — this page has no other prose
   for it to mean, so one field does both without a second, easily-forgotten control. Both fall back
   to exactly what shipped before this build, so nothing changes until he opens the new card. */
.checkout-note{background:var(--ca-note-bg,var(--paper-2));padding:1.2rem;font-size:.92rem;color:var(--ca-body-fg,var(--ca-fg,var(--ink-soft)));margin-top:1.5rem}

/* ============================================================
   RESPONSIVE
   ============================================================ */
@media (max-width:900px){
  .intro-grid,.feature-band,.about-section,.product-layout{grid-template-columns:1fr}
  
  .product-stage{position:static}
  .nav{
    position:absolute;top:100%;right:0;left:0;flex-direction:column;align-items:stretch;
    gap:0;background:var(--paper);border-bottom:1px solid var(--line);padding:.5rem var(--gutter) 1rem;
    display:none
  }
  .nav.open{display:flex}
  .nav a{padding:.75rem 0;border-bottom:1px solid var(--line)}
  .nav a.button{margin-top:.8rem;text-align:center;border-bottom:1px solid var(--ink)}
  .menu-toggle{display:block}
  .site-header.on-dark{background:color-mix(in srgb,var(--paper) 92%,transparent);color:var(--ink);border-bottom:1px solid var(--line)}
  .hero-content{padding-bottom:5rem}
}

/* ============================================================
   HOME — logo, news, split cards
   ============================================================ */
/* v62 — THE LOGO KEEPS ITS COLOURS EVERYWHERE, AND IS BIGGER WITHOUT A TALLER HEADER.
   Kirk: "why is the logo in the upper left corner monochromatic in some areas of the site and looking
   coloured in others? I would prefer it always looks coloured and larger if possible (without making
   the header bigger)."
   `filter:brightness(0) invert(1)` was flattening it to a white silhouette on every dark header —
   which is what a one-colour logo needs and his is not. Removed in both places it was applied.
   BIGGER WITHOUT A TALLER HEADER is arithmetic: the header's height is its padding plus the logo, so
   the logo grows by exactly what the padding gives up. 46px + .9rem padding and 60px + .45rem come out
   within a pixel of each other, so the bar does not move while the mark gains a third. */
.brand-logo{height:60px;width:auto;filter:none}
.site-header.on-dark .brand-logo,
.site-header.solid-dark .brand-logo{filter:none}

.news-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:clamp(1.5rem,3vw,2.5rem)}
.news-card{background:var(--white);border:1px solid var(--line)}
.news-card img{width:100%;aspect-ratio:3/2;object-fit:cover}
.news-body{padding:1.2rem 1.3rem 1.5rem}
.news-card .when{font-size:var(--step--1);letter-spacing:.14em;text-transform:uppercase;color:var(--accent);margin-bottom:.4rem}
.news-card h3{margin-bottom:.5rem}
.news-card p{color:var(--ink-soft);font-size:.94rem;margin:0}

.split-cards{display:grid;grid-template-columns:1fr 1fr;gap:1px;background:var(--line)}
.split-card{position:relative;display:block;text-decoration:none;color:var(--white);aspect-ratio:16/10;overflow:hidden;background:var(--ink)}
.split-card img{width:100%;height:100%;object-fit:cover;opacity:.72;transition:transform .8s ease,opacity .4s}
.split-card:hover img{transform:scale(1.04);opacity:.6}
.split-card span{position:absolute;inset:auto 0 0 0;display:grid;gap:.3rem;padding:clamp(1.5rem,3vw,2.5rem);background:linear-gradient(transparent,rgba(20,23,26,.8))}
.split-card small{font-size:var(--step--1);letter-spacing:.2em;text-transform:uppercase;opacity:.8}
.split-card b{font-family:var(--font-display);font-size:var(--step-2);font-weight:500}
.split-card em{font-style:normal;font-size:.94rem;color:rgba(255,255,255,.78)}

.contact-lead{max-width:38rem;margin:0 auto 0;color:color-mix(in srgb,var(--paper) 75%,transparent)}

@media (max-width:1100px){}
@media (max-width:900px){
  .split-cards{grid-template-columns:1fr}
  .brand-logo{height:48px}   /* v62 — grown in step with the desktop size */
}

/* ============================================================
   HEADER DROPDOWNS
   ============================================================ */
.drop{position:relative}
.drop-toggle{
  background:none;border:none;padding:0;font:inherit;color:inherit;cursor:pointer;
  font-size:var(--step--1);letter-spacing:.06em;text-transform:uppercase
}
.drop-toggle::after{content:" ▾";opacity:.6}
.drop-toggle:hover{color:var(--accent)}
.site-header.on-dark .drop-toggle:hover{color:var(--white)}
.drop-menu{
  display:none;position:absolute;top:calc(100% + .9rem);left:50%;transform:translateX(-50%);
  min-width:240px;background:var(--paper);border:1px solid var(--line);box-shadow:var(--shadow);
  padding:.4rem 0;z-index:80
}
.drop.open .drop-menu{display:block}
.drop-menu a{
  display:block;padding:.65rem 1.1rem;text-decoration:none;color:var(--ink);
  font-size:.9rem;letter-spacing:0;text-transform:none
}
/* v74 (WEBSITE CHAT) — the hover text was coloured with --accent, which is meant for buttons
   and small accents, not guaranteed to read against a light background. Some themes set accent
   to a pale colour (the Frozen Moments light blue used on buttons is one), which then went
   pale-on-pale here and disappeared. A dedicated hover-text token defaults to --ink -- guaranteed
   dark -- and can still be overridden per theme if a site wants its accent here deliberately.
   CARRIED INTO v75 from the website chat's v74, which was a DIFFERENT v74 from this branch's.
   See VERSION.txt: two v74s existed and v75 is the merge of both. */
/* v92 — HOVER READABLE ON ANY MENU BACKGROUND, LIGHT OR DARK, WITH NO CLASS NEEDED.
   The hover used to paint --paper-2 behind --ink. A dark theme that sets a dark paper and a light ink
   but leaves paper-2 alone got light grey behind light text: the item vanished. The tint is now taken
   from the link's OWN text colour (currentColor), so it is always the same hue as the text and always
   behind it, whatever the theme. The text keeps its resting colour. --nav-hover-bg / --nav-hover-fg
   still override. `.nav .drop-menu a` is there to beat `.nav a:not(.button):hover` (accent colour),
   which was also reaching these links. */
.drop-menu a:hover,.drop-menu a:focus-visible,
.nav .drop-menu a:not(.button):hover,.nav .drop-menu a:not(.button):focus-visible{
  background:var(--nav-hover-bg,color-mix(in srgb,currentColor 14%,transparent));
  color:var(--nav-hover-fg,var(--ink))
}
.drop-menu a:focus-visible{outline:2px solid currentColor;outline-offset:-2px}
.drop-menu .drop-all{border-top:1px solid var(--line);margin-top:.3rem;font-size:var(--step--1);letter-spacing:.08em;text-transform:uppercase;color:var(--ink-soft)}

@media (max-width:900px){
  .drop{width:100%}
  .drop-toggle{display:block;width:100%;text-align:left;padding:.75rem 0;border-bottom:1px solid var(--line)}
  .drop-menu{position:static;transform:none;border:none;box-shadow:none;background:color-mix(in srgb,var(--ink) 5%,var(--paper));min-width:0}
  .drop.open .drop-menu{display:block}
}

/* ============================================================
   GALLERY HUB
   ============================================================ */
.page-head.wide{max-width:60rem}
.hub{display:grid;gap:1px;background:var(--line);border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
.hub-card{
  display:grid;grid-template-columns:1fr 1fr;background:var(--paper);text-decoration:none;
  align-items:stretch;transition:background .3s
}
.hub-card:nth-child(even){direction:rtl}
.hub-card:nth-child(even)>*{direction:ltr}
.hub-card:hover{background:var(--paper-2)}
.hub-img{overflow:hidden;background:var(--paper-2)}  /* v59 — the aspect-ratio here read `--hub-shape`, which nothing sets any more and which
     `.hub-img{aspect-ratio:auto}` below has overruled since v38. A rule that cannot apply,
     reading a variable nobody writes, is how the tile shapes looked built for four versions. */
.hub-img img{width:100%;height:100%;object-fit:cover;transition:transform .9s ease}
.hub-card:hover .hub-img img{transform:scale(1.05)}
.hub-body{display:flex;flex-direction:column;justify-content:center;gap:.6rem;padding:clamp(1.8rem,4vw,3.5rem)}
.hub-num{
  font-family:var(--font-display);font-size:var(--step-1);color:var(--accent);
  border-bottom:2px solid var(--accent);align-self:flex-start;padding-bottom:.2rem
}
.hub-body h2{font-size:var(--step-2)}
.hub-body p{color:var(--ink-soft);margin:0;max-width:34rem}
.hub-meta{font-size:var(--step--1);letter-spacing:.1em;text-transform:uppercase;color:var(--accent);margin-top:.5rem}

/* ============================================================
   ONE GALLERY
   ============================================================ */
.g-band{
  position:relative;min-height:58vh;display:grid;align-items:end;color:var(--white);
  background-size:cover;background-position:center
}
/* ============================================================================================
   v75 — THE GALLERY BAND TAKES THE TILE'S OWN SHAPE, NOT A SEPARATE VOCABULARY.
   ============================================================================================
   Kirk: "i would be fine if they keep the same orientation as the tile."

   The four names are `tileShape()`'s own — short/standard/tall/whole — read straight off site.js,
   not translated into the service hero's `short/standard/tall/full`. Two hero-shaped things on this
   site already use two different fourth names (`.s-hero[data-height="full"]`, below); giving the
   band a THIRD spelling of the same idea would only be one more place the words could drift apart.
   This block owns its own selector and its own numbers instead, so nothing here can disturb the
   service hero, which already works and was not what he asked to change — only the FIGURES are
   deliberately the same, for the reason the site's own comment on tileShape() gives: one vocabulary
   reading the same wherever he meets it.
   base `.g-band{min-height:58vh}` above stays as the fallback for the one case data-height is ever
   absent — a page built before this shipped, still sitting in a browser cache. */
.g-band[data-height="short"]{min-height:36vh}
.g-band[data-height="standard"]{min-height:52vh}
.g-band[data-height="tall"]{min-height:72vh}
.g-band[data-height="whole"]{min-height:88vh;background-size:contain;background-repeat:no-repeat;background-color:var(--ink)}
/* Letterboxed against the ink background exactly as the service hero's "whole picture" is, so a
   collection that chooses this shape reads the same wherever it is met on the site. */
.g-band[data-height="whole"]::after{background:linear-gradient(180deg,
  rgba(20,23,26,var(--gy-scrim-top,.25)),rgba(20,23,26,var(--gy-scrim-bottom,.8)))}
/* v67 — the same treatment as the home and service heroes: nothing over the top
   of the picture, darkening only in the bottom 45% where the words are, and the
   words carrying their own shadow.

   v70 — RENAMED from --gb-scrim-* to --gy-scrim-*. `gb` was a name I invented in v67 that belongs
   to no area, so nothing wrote it and no picker could reach it: a variable that reads as adjustable
   and is not. `gy` is the gallery page's own prefix, and applySections already writes the
   scrim-top/scrim-bottom suffix for every area — so this needs no new writer. Same for the home
   hero, --hero-scrim-* -> --he-scrim-*. */
.g-band::after{content:"";position:absolute;inset:0;background:linear-gradient(180deg,
  rgba(20,23,26,var(--gy-scrim-top,0)) 0%,
  rgba(20,23,26,var(--gy-scrim-top,0)) 55%,
  rgba(20,23,26,var(--gy-scrim-bottom,.8)) 100%)}
.g-band h1,.g-band h2,.g-band p,.g-band .eyebrow,.g-band .g-band-inner{
  text-shadow:0 1px 3px rgba(12,14,16,.55),0 2px 14px rgba(12,14,16,.35)}
.g-band-inner{position:relative;z-index:1;padding:0 var(--gutter) clamp(2.5rem,6vw,5rem);max-width:46rem}
/* v69 — THE GALLERY BANNER JOINS THE OTHER TWO. It had neither its own size nor its own colour, and
   worse, `.g-band h1` is (0,2,0) against `#galleryPage h1` at (1,0,1) — so the page heading size won
   here and the banner could not be sized at all. Same fault the service banner had, same fix, and now
   all three banners behave alike. */
#galleryPage .g-band h1,.g-band h1{font-size:var(--gy-hero-size,var(--step-4));margin-bottom:.8rem}
#galleryPage .g-band h1,.g-band h1{color:var(--gy-hero-fg,var(--gy-heading-fg,var(--gy-fg,var(--sf-heading,inherit))))}
.g-intro{color:rgba(255,255,255,.82);font-size:var(--step-1)}
#galleryPage .eyebrow{color:var(--accent);filter:brightness(1.7)}

.works{padding:clamp(3rem,7vw,6rem) var(--gutter)}
.work{text-decoration:none;display:block;color:inherit}
.work-img{overflow:hidden;background:var(--paper-2)}
.work-img img{width:100%;display:block;transition:transform .9s ease}
.work:hover .work-img img{transform:scale(1.03)}
.work-cap h3{margin:.2rem 0 .3rem;font-size:var(--step-1)}
.work-cap p{color:var(--ink-soft);font-size:.94rem;margin:0 0 .4rem}
.work-no{font-size:var(--step--1);letter-spacing:.16em;color:var(--accent)}
.work-price{font-size:var(--step--1);letter-spacing:.08em;text-transform:uppercase;border-bottom:1px solid var(--accent);padding-bottom:2px}

/* layout 1 — full bleed, one at a time */
.works-fullbleed{display:grid;gap:clamp(3rem,7vw,6rem);padding-left:0;padding-right:0}
.works-fullbleed .work-img img{max-height:86vh;object-fit:cover;width:100%}
.works-fullbleed .work-cap{display:flex;flex-wrap:wrap;align-items:baseline;gap:.4rem 1.5rem;padding:1.2rem var(--gutter) 0}
.works-fullbleed .work-cap p{flex:1 1 22rem}

/* layout 2 — masonry columns */
.works-masonry{column-count:3;column-gap:clamp(1rem,2vw,2rem)}
.works-masonry .work{break-inside:avoid;margin-bottom:clamp(1rem,2vw,2rem)}
.works-masonry .work-cap{padding-top:.7rem}
@media (max-width:1000px){.works-masonry{column-count:2}}
@media (max-width:640px){.works-masonry{column-count:1}}

/* layout 3 — even plates with wide gutters */
.works-plates{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:clamp(2rem,5vw,4.5rem)}
.works-plates .work-img{aspect-ratio:3/2}
.works-plates .work-img img{height:100%;object-fit:cover}
.works-plates .work-cap{text-align:center;padding-top:1rem}

/* layout 4 — editorial rows, image and text side by side */
.works-editorial{display:grid;gap:clamp(3rem,6vw,5rem)}
.works-editorial .work{display:grid;grid-template-columns:1.3fr 1fr;gap:clamp(1.5rem,4vw,3.5rem);align-items:center}
.works-editorial .work:nth-child(even){grid-template-columns:1fr 1.3fr}
.works-editorial .work:nth-child(even) .work-img{order:2}
.works-editorial .work-cap p{font-size:var(--step-0)}
@media (max-width:800px){.works-editorial .work,.works-editorial .work:nth-child(even){grid-template-columns:1fr}
  .works-editorial .work:nth-child(even) .work-img{order:0}}

.other-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:1rem}
.other-card{position:relative;display:block;text-decoration:none;color:var(--white);aspect-ratio:3/2;overflow:hidden;background:var(--ink)}
.other-card img{width:100%;height:100%;object-fit:cover;opacity:.75;transition:.5s}
.other-card:hover img{opacity:.55;transform:scale(1.05)}
.other-card span{position:absolute;inset:auto 0 0 0;padding:1rem;font-family:var(--font-display);font-size:var(--step-1);background:linear-gradient(transparent,rgba(20,23,26,.8))}

/* ============================================================
   SERVICES
   ============================================================ */
.svc-grid{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(340px,1fr));
  gap:1px;background:var(--line);border-top:1px solid var(--line);border-bottom:1px solid var(--line)
}
.svc-tile{position:relative;display:block;text-decoration:none;color:var(--white);aspect-ratio:16/10;overflow:hidden;background:var(--ink)}
.svc-tile img{width:100%;height:100%;object-fit:cover;opacity:.66;transition:transform .9s ease,opacity .4s}
.svc-tile:hover img{transform:scale(1.06);opacity:.5}
.svc-label{position:absolute;inset:0;display:flex;flex-direction:column;justify-content:flex-end;gap:.4rem;padding:clamp(1.3rem,2.5vw,2rem);background:linear-gradient(transparent 40%,rgba(20,23,26,.8))}
.svc-label b{font-family:var(--font-display);font-size:var(--step-2);font-weight:500;line-height:1.05}
.svc-label em{font-style:normal;font-size:.9rem;color:rgba(255,255,255,.8);opacity:0;transform:translateY(6px);transition:.35s}
.svc-tile:hover .svc-label em{opacity:1;transform:none}
@media (hover:none){.svc-label em{opacity:1;transform:none}}

.s-hero{position:relative;min-height:52vh;display:grid;align-items:end;color:var(--white);background-size:cover;background-position:center}
/* v62 — THE SCRIM IS A SETTING NOW. Kirk: "Hero picture on portraits page is greyed over, I want it
   to look clean and bright." The gradient exists so white words stay readable over any photograph, so
   it cannot simply go — but it was fixed at 45%-85% for every service whatever the picture, and over
   a bright portrait that reads as a grey wash. `--sv-scrim-top` and `--sv-scrim-bottom` default to
   ZERO at the top — the wash Kirk asked us to remove — with the darkening built only in the bottom
   45% where the words sit. The words carry a text-shadow instead, which follows the letters and
   costs the photograph nothing. A service that wants the old look sets --sv-scrim-top itself. */
.s-hero::after{content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,
    rgba(20,23,26,var(--sv-scrim-top,0)) 0%,
    rgba(20,23,26,var(--sv-scrim-top,0)) 55%,
    rgba(20,23,26,var(--sv-scrim-bottom,.85)))}
/* v67 — the hero heading has its own size, separate from the page's heading
   size, because a hero sits over a photograph and wants a different scale from
   a heading on a plain background. Falls back to what it has always been. */
/* v68 — THE ID HAD TO BE IN THE SELECTOR OR THIS RULE COULD NEVER WIN.
   `#servicePage h1` is (1,0,1) and `.s-hero-inner h1` is (0,2,0); an id beats any number of
   classes, so as written the banner headline still took `--sv-heading-size` and the new setting
   did nothing on the only page it exists for. Same for the home banner against `#homeHero h1`.
   The class-only form is kept beside it for any page that has the banner without the id. */
#servicePage .s-hero-inner h1,.s-hero-inner h1{font-size:var(--sv-hero-size,var(--step-4))}
#homeHero .hero-content h1,.hero-content h1{font-size:var(--he-hero-size,var(--step-4))}
/* v69 — THE BANNER HEADING'S OWN COLOUR. It sits on a photograph and has to be readable there; the
   same heading on the page below sits on his background colour and has different needs. Falls back
   to the area's heading colour, then to its text colour, so an area where this is unset behaves
   exactly as it did before this existed. The id is in the selector for the same reason it is in the
   size rule above: #servicePage h1 is (1,0,1) and would otherwise win. */
#servicePage .s-hero-inner h1,.s-hero-inner h1{color:var(--sv-hero-fg,var(--sv-heading-fg,var(--sv-fg,var(--sf-heading,inherit))))}
#homeHero .hero-content h1,.hero-content h1{color:var(--he-hero-fg,var(--he-heading-fg,var(--he-fg,var(--sf-heading,inherit))))}
.s-hero-inner h1,.s-hero-inner p,.s-hero-inner .eyebrow,.s-blurb{
  text-shadow:0 1px 3px rgba(12,14,16,.55),0 2px 14px rgba(12,14,16,.35)}
.s-hero-inner{position:relative;z-index:1;padding:0 var(--gutter) clamp(2rem,5vw,4rem);max-width:44rem}
.s-blurb{color:rgba(255,255,255,.85);font-size:var(--step-1)}
.s-body{max-width:52rem}
.s-actions{display:flex;flex-wrap:wrap;gap:.75rem;margin-top:1.5rem}

/* ============================================================
   ROOM PREVIEW
   ============================================================ */
.room-panel{border:1px solid var(--line);background:var(--white);padding:1.1rem 1.2rem 1.3rem}
.room-head{display:flex;align-items:baseline;justify-content:space-between;gap:1rem;margin-bottom:.9rem}
.room-head h2{font-family:var(--font-body);font-size:var(--step--1);letter-spacing:.14em;text-transform:uppercase;font-weight:600}
.room-upload{font-size:var(--step--1);color:var(--accent);border-bottom:1px solid var(--accent);cursor:pointer}
.room-stage{position:relative;overflow:hidden;background:var(--paper-2);aspect-ratio:4/3;touch-action:none}
.room-stage>img{width:100%;height:100%;object-fit:cover}
.room-hint{
  position:absolute;inset:auto 0 0 0;margin:0;padding:.7rem 1rem;font-size:var(--step--1);
  background:rgba(20,23,26,.7);color:#fff
}
.room-controls{display:flex;align-items:center;gap:.7rem;margin-top:.9rem;font-size:var(--step--1)}
.room-controls label{color:var(--ink-soft);white-space:nowrap}
.room-controls input[type=range]{flex:1;accent-color:var(--accent)}
.room-controls output{min-width:3.2rem;text-align:right}
.caption{font-size:var(--step--1);color:var(--ink-soft);margin:.7rem 0 0}
.sub-quiet{font-size:var(--step--1);color:var(--ink-soft);margin-bottom:1.4rem}
.config .sub a{text-decoration:none;border-bottom:1px solid var(--accent)}

/* ============================================================
   THE MOUNT — print, mat, bevel, floating frame, all to scale
   ============================================================ */
.stage-art{
  background:var(--paper-2);display:grid;place-items:center;
  padding:clamp(1.2rem,3vw,2.4rem);min-height:min(56vh,480px)
}
.mount{max-width:100%;filter:drop-shadow(0 18px 40px rgba(20,23,26,.22))}
.mount img{
  display:block;max-width:100%;max-height:min(52vh,470px);width:auto;height:auto
}
.mount.portrait img{max-height:min(62vh,560px)}

/* floating frame: an outer face with a shaded recess behind it */
.pf-frame{border-style:solid;border-width:0;border-color:#1c1c1c;background:#1c1c1c}
.pf-frame.on{box-shadow:inset 0 0 0 1px rgba(255,255,255,.08)}
.pf-gap{padding:0;background:#0d0e10}
.pf-gap.on{box-shadow:inset 0 6px 14px rgba(0,0,0,.75), inset 0 -3px 8px rgba(0,0,0,.5)}

/* mat: a board laid over the print, cut with a bevelled window */
.pf-mat{padding:0;background:#fff}
.pf-mat.has-mat{box-shadow:0 1px 2px rgba(0,0,0,.18)}
.pf-bevel{border-style:solid;border-width:0;border-color:transparent;line-height:0}
.pf-bevel.on{
  /* the exposed core of the board is white even when the mat surface is black */
  border-color:#fdfcf9 #efece5 #e2ded4 #f7f5f0;
  box-shadow:inset 0 1px 3px rgba(0,0,0,.28), 0 0 0 1px rgba(0,0,0,.10)
}
.mount-caption{font-size:var(--step--1);color:var(--ink-soft);text-align:center;margin:.9rem 0 0}

.swatch.custom{
  background-image:conic-gradient(from 210deg,#8d6a4a,#5c7a6a,#7d6f9a,#a2564f,#8d6a4a);
  background-clip:padding-box
}
.swatch-note{font-size:var(--step--1);color:var(--ink-soft);margin:.5rem 0 0}

/* ============================================================
   ROOM VIEWS
   ============================================================ */
.room-panel{border:1px solid var(--line);background:var(--white);padding:1.1rem 1.2rem 1.3rem}
.room-stage{position:relative;overflow:hidden;background:var(--paper-2);margin:0 auto;transition:max-width .25s}
.room-stage>img{width:100%;height:auto;display:block}

.room-strip{display:flex;gap:.5rem;flex-wrap:wrap;margin-top:.8rem}
.room-thumb{
  width:64px;height:48px;border:1px solid var(--line);background-size:cover;background-position:center;
  cursor:pointer;padding:0;border-radius:var(--radius)
}
.room-thumb[aria-pressed="true"]{outline:2px solid var(--ink);outline-offset:2px}
.strip-empty{font-size:var(--step--1);color:var(--ink-soft);margin:0}

.work-edition{display:block;font-size:var(--step--1);color:var(--accent);margin-top:.35rem;letter-spacing:.04em}
.edition-note{font-size:var(--step--1);color:var(--accent);border-left:2px solid var(--accent);padding-left:.7rem;margin:-.6rem 0 1.4rem}

.svc-blank{position:absolute;inset:0;background:linear-gradient(160deg,var(--ink),var(--accent))}
.about-section .about-image[hidden]{display:none}

/* per-service gallery strip */
.svc-shots{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:1rem}
.svc-shot{display:block;overflow:hidden;background:var(--paper-2);aspect-ratio:3/2}
.svc-shot img{width:100%;height:100%;object-fit:cover;transition:transform .7s ease}
.svc-shot:hover img{transform:scale(1.04)}

/* custom colour is a request, not a swatch */
.custom-colour{border:1px dashed var(--line);border-radius:var(--radius);padding:.8rem 1rem;margin-top:.6rem;background:var(--white)}
.custom-colour.on{border-style:solid;border-color:var(--accent)}
.custom-head{display:flex;gap:.8rem;align-items:flex-start;cursor:pointer;margin:0}
.custom-head input{margin-top:.28rem;accent-color:var(--accent)}
.custom-head b{display:block;font-weight:600}
.custom-head small{color:var(--ink-soft)}
.custom-head .cost{margin-left:auto;white-space:nowrap}
.custom-input{margin-top:.7rem;width:100%;padding:.6rem .8rem;border:1px solid var(--line);font:inherit;border-radius:var(--radius)}

/* owner-only room slot */
.studio-badge{display:inline-block;font-size:.6rem;letter-spacing:.14em;text-transform:uppercase;background:var(--accent);color:#fff;padding:.15rem .45rem;border-radius:3px;vertical-align:middle;margin-left:.4rem}
.room-slot{border:1px dashed var(--line);border-radius:var(--radius);padding:1.4rem;text-align:center;background:var(--paper-2)}
.room-slot p{margin:0 0 .4rem;font-size:var(--step--1);color:var(--ink-soft)}
.room-slot b{color:var(--ink)}
.slot-upload{display:inline-block;margin-top:.6rem;border:1px solid var(--ink);padding:.5rem 1rem;font-size:var(--step--1);letter-spacing:.06em;text-transform:uppercase;cursor:pointer}
.slot-upload:hover{background:var(--ink);color:var(--paper)}

/* ============================================================
   DARK HEADER — theme.header === "dark"
   ============================================================ */
.site-header.solid-dark{background:var(--ink);border-bottom-color:rgba(255,255,255,.12);color:var(--paper)}
/* v62 — see the note by `.brand-logo`: his logo is not a one-colour mark and must not be flattened. */
.site-header.solid-dark .drop-menu{background:var(--ink);border-color:rgba(255,255,255,.14)}
.site-header.solid-dark .drop-menu a{color:var(--paper)}
.site-header.solid-dark .drop-menu a:hover{background:rgba(255,255,255,.08);color:#fff}
.site-header.solid-dark .button{background:var(--paper);color:var(--ink);border-color:var(--paper)}
.site-header.solid-dark .button:hover{background:var(--accent);border-color:var(--accent);color:#fff}
.site-header.solid-dark.on-dark{background:transparent;border-bottom-color:transparent}
@media (max-width:900px){
  .site-header.solid-dark .nav{background:var(--ink)}
  .site-header.solid-dark .nav a{border-bottom-color:rgba(255,255,255,.12)}
  .site-header.solid-dark .menu-toggle{border-color:rgba(255,255,255,.3)}
}

/* ============================================================
   CONTACT
   ============================================================ */
.contact-layout{display:grid;grid-template-columns:1fr 1fr;gap:clamp(2rem,6vw,5rem);
  padding:clamp(3rem,7vw,6rem) var(--gutter) 5rem;align-items:start}
.contact-intro h1{margin-bottom:1rem}
.contact-intro .lead{color:var(--ink-soft);max-width:32rem}
.contact-direct{display:flex;flex-wrap:wrap;gap:.6rem;margin:1.8rem 0}
.contact-facts{display:grid;gap:1rem;border-top:1px solid var(--line);padding-top:1.5rem;margin-top:1.5rem}
.contact-facts div{display:grid;gap:.15rem}
.contact-facts b{font-size:var(--step--1);letter-spacing:.14em;text-transform:uppercase;color:var(--accent);font-weight:600}
.contact-facts span{color:var(--ink-soft)}

.contact-form{background:var(--white);border:1px solid var(--line);padding:clamp(1.4rem,3vw,2.2rem)}
.contact-form label{display:block;margin-bottom:1rem;font-size:var(--step--1);letter-spacing:.06em;
  text-transform:uppercase;color:var(--ink-soft)}
.contact-form label small{text-transform:none;letter-spacing:0;opacity:.7}
.contact-form input,.contact-form select,.contact-form textarea{
  display:block;width:100%;margin-top:.4rem;padding:.7rem .8rem;border:1px solid var(--line);
  font:inherit;font-size:1rem;color:var(--ink);background:var(--paper);border-radius:var(--radius);
  text-transform:none;letter-spacing:0
}
.contact-form input:focus,.contact-form select:focus,.contact-form textarea:focus{
  outline:none;border-color:var(--accent);box-shadow:0 0 0 3px rgba(47,93,98,.12)}
.contact-form textarea{resize:vertical}
.field-row{display:grid;grid-template-columns:1fr 1fr;gap:1rem}
.field-row[hidden]{display:none}
.contact-form .note.warn{color:#a2564f}
@media (max-width:900px){.contact-layout,.field-row{grid-template-columns:1fr}}

/* ============================================================
   MOBILE
   The desktop layout is a two-column reading order: picture on the left,
   decisions on the right. On a phone that has to become a sequence, and
   the sequence matters -- see it, choose it, then the room views. The
   price and the button must never scroll out of reach while choosing.
   ============================================================ */

/* cart lives in the collapsed menu on desktop, on the bar itself on mobile */
.cart-pill.on-bar{display:none}
@media (max-width:900px){
  .cart-pill.in-nav{display:none}
  .cart-pill.on-bar{
    display:inline-flex;align-items:center;gap:.35rem;order:2;margin-left:auto;margin-right:.6rem;
    border:1px solid var(--line);padding:.42rem .6rem;text-decoration:none;border-radius:var(--radius)
  }
  .site-header.on-dark .cart-pill.on-bar,
  .site-header.solid-dark .cart-pill.on-bar{border-color:rgba(255,255,255,.35)}
  .menu-toggle{order:3}
  .brand{order:1}
  .nav{order:4}
}

@media (max-width:900px){
  /* the stage and the room panel are siblings in one column on desktop; on a
     phone they need the choices between them, so the wrapper steps aside */
  .product-layout{display:flex;flex-direction:column;gap:1.5rem}
  .product-stage{display:contents}
  .stage-art{order:1}
  .mount-caption{order:2}
  .config{order:3}
  .room-panel{order:4}

  /* price and button stay put while you work through the options */
  .summary{
    position:sticky;bottom:0;z-index:40;background:var(--paper);
    border-top:1px solid var(--ink);margin:0 calc(var(--gutter) * -1);
    padding:1rem var(--gutter) calc(1rem + env(safe-area-inset-bottom));
    box-shadow:0 -10px 24px rgba(20,23,26,.10)
  }
  .summary .total{margin:.3rem 0 .8rem;font-size:var(--step-1)}
  .summary .note{display:none}
  #summaryLines{max-height:5.2rem;overflow:auto}

  /* touch targets */
  .swatch{width:42px;height:42px}
  .opt{padding:.75rem 1rem;font-size:1rem}
  .opt-wide{flex-basis:100%}
  .addon{padding:1rem}
  .filter{padding:.6rem 1.1rem}
  .room-thumb{width:78px;height:58px}

  /* a display-size slider is meaningless at one column */
  #roomSizeControls label[for="roomScale"],
  #roomScale, #roomScaleOut{display:none}

  .stage-art{min-height:0;padding:1rem}
  .mount img{max-height:52vh}
  .mount.portrait img{max-height:60vh}
  .hero{min-height:78vh}
  .hero-content{padding-bottom:4rem}
  .g-band{min-height:46vh}
  .s-hero{min-height:42vh}
  .works-fullbleed .work-img img{max-height:70vh}
  footer{flex-direction:column;gap:.4rem}
}

/* very small screens: stop the two-up option grid squeezing */
@media (max-width:420px){
  .opts{gap:.4rem}
  .export-figures{grid-template-columns:1fr 1fr}
  .hero{min-height:70vh}
  .contact-form{padding:1.1rem}
}

/* landscape phones are short, not narrow -- vh-based heights get silly */
@media (max-height:520px) and (orientation:landscape){
  .hero{min-height:100vh}
  .g-band,.s-hero{min-height:80vh}
  .mount img,.mount.portrait img{max-height:74vh}
}

/* ============================================================
   SERVICE PAGE BLOCKS
   ============================================================ */
.s-hero-inner.at-bottom{max-width:34rem}
.s-hero-actions{display:flex;flex-wrap:wrap;gap:.7rem;margin-top:1.6rem}
.s-block.section{padding-top:clamp(3rem,6vw,5rem);padding-bottom:clamp(3rem,6vw,5rem)}
.s-block h2{margin-bottom:.8rem}
.s-block .lead{max-width:44rem;color:var(--ink-soft)}
.s-text .button{margin-top:1.2rem}

/* a plain list of extras */
.pricelist{display:grid;gap:0;max-width:40rem;border-top:1px solid var(--line)}
.pricelist div{display:flex;justify-content:space-between;gap:1rem;align-items:baseline;
  padding:.85rem .2rem;border-bottom:1px solid var(--line)}
.pricelist span{color:var(--ink-soft)}
.pricelist b{font-family:var(--font-display);font-size:var(--step-1);white-space:nowrap}

/* picture one side, words the other */
.feature-split{display:grid;grid-template-columns:1fr 1fr;gap:clamp(1.5rem,4vw,4rem);
  align-items:center;padding:clamp(3rem,6vw,5rem) var(--gutter);background:var(--sv-block-bg,var(--paper-2))}
.feature-split.flip .fs-img{order:2}
.fs-img img{width:100%;aspect-ratio:4/3;object-fit:cover}
.fs-copy h2{margin-bottom:.8rem}
/* v78 — Kirk: "I don't see where to edit the background to the created section." He was right, and
   only about the background: `#servicePage p{color:var(--sv-body-fg,var(--sv-fg,inherit))}` already
   wins here by specificity (an ID beats a class regardless of source order — checked against a real
   CSS engine, not assumed), so the paragraph and heading colours were already following his existing
   Body colour and Heading colour fields correctly. The rule that used to sit here,
   `.fs-copy p{color:var(--ink-soft)}`, never actually applied for that same reason and is removed
   rather than left as something that looks load-bearing and is not.
   THE BACKGROUND HAD NO SUCH RULE TO FALL BACK ON — `.feature-split` set it directly, with nothing
   more specific competing and nothing less specific to inherit from, so there was truly nowhere for
   a setting to reach. `--sv-block-bg` is new, shared across every "Picture and words" block on a
   service (not one per block instance \u2014 a service with several of these would need several
   near-identical cards for no real benefit, the same reasoning the free tools page's alternating
   bands already rest on), and falls back to exactly --paper-2, today's appearance, so nothing changes
   until he actually sets it. */
.fs-copy p{max-width:34rem}

/* v65 — THE WORDS SIT IN THE MIDDLE of the space beside the picture.

   The grid has centred its two columns since v11, so on a plain feature block
   this changed nothing. The void Kirk saw came from MY OWN v64 addition: the
   thumbnail strip spans both columns, which makes the grid two ROWS, and a row
   is as tall as its tallest cell — so the copy was centred in a cell it had
   been stretched to fill. Centring inside .fs-copy fixes it whether or not
   thumbnails are present.

   The measure is capped too: a couple of sentences stretched across a half-page
   column reads as an accident beside a photograph. Applies whichever side the
   picture is on — the flip only reorders. */
/* v68 — Kirk: "I want the words centered rather than left aligned."
   Centring the TEXT as well as the column. The measure cap stays — a centred paragraph running the
   full width of the column is harder to read than a left-aligned one, not easier — so the capped
   box is centred in the space with `margin-inline:auto` rather than sitting against the left edge
   with centred text inside it, which would look like a mistake. The button follows the words. */
.fs-copy{display:flex;flex-direction:column;justify-content:center;text-align:center}
.fs-copy > *{max-width:var(--fs-measure,38rem);margin-inline:auto}
.fs-copy p{margin-inline:auto}
.fs-copy .button{align-self:center}
.fs-copy .button{margin-top:1.2rem}

@media (max-width:820px){
  .package,.package.no-image{grid-template-columns:1fr}
  .pk-img img{min-height:0;aspect-ratio:3/2}
  .feature-split,.feature-split.flip .fs-img{grid-template-columns:1fr;order:0}
  .fs-copy{justify-content:flex-start}
  .pk-cta{width:100%;text-align:center}
}

/* ============================================================
   (section added in an earlier revision)
   ============================================================ */

/* 1. About — the portrait shows whole, words beside it */
.about-image{align-self:start}
.about-copy{align-self:center}
@media (max-width:900px){
  .about-section{grid-template-columns:1fr}
  .about-image img{max-height:70vh;width:auto;margin:0 auto}
}

/* 2. Gallery navigation — wide, thin banner buttons, one per row.
   Four fit on one screen with room to spare; the name and a one-line blurb
   sit on the picture rather than above it. */

@media (max-width:640px){
  
  
}

/* 3. "See it. Size it." — type and colour driven from FM.sections.seeIt */
.feature-band{background:var(--fb-bg,var(--ink));color:var(--fb-fg,var(--paper))}
/* v60 — THE HEADING AND THE WORDS UNDER IT ARE TWO COLOURS. Kirk: "See it size it...needs a
   separation of heading and secondary text. I want the header to be one colour and text below a
   different colour."
   THE TEMPLATE HAS BEEN SETTING `--fb-heading-fg` AND `--fb-body-fg` SINCE THE BAND WAS WRITTEN AND
   NOTHING HAS EVER READ THEM — two variables written by applySections into declarations that do not
   exist. The g113 fault, written the other way round: the data was carried and never consumed.
   Both fall back to `--fb-fg`, the single colour the band used before, so a site that sets only that
   one is unchanged. */
.feature-band h2{font-family:var(--fb-heading-font,var(--font-display));font-size:var(--fb-heading-size,var(--step-3));
  color:var(--fb-heading-fg,var(--fb-fg,var(--paper)))}
.feature-band .fb-copy p:not(.eyebrow){font-family:var(--fb-body-font,var(--font-body));
  font-size:var(--fb-body-size,var(--step-0));color:var(--fb-body-fg,var(--fb-fg,color-mix(in srgb,var(--paper) 75%,transparent)))}
.feature-band .eyebrow{color:var(--fb-eyebrow,#ffffff);opacity:1}

/* 4. Home link cards fall back gracefully when no picture is set */
.split-blank{position:absolute;inset:0;background:linear-gradient(150deg,var(--ink),var(--accent))}
.card-rooms{font-size:var(--step--1);color:var(--accent);margin:.15rem 0 0}

/* 5. About the artist — dark charcoal panel, soft white words,
      the kicker left on the accent colour. All overridable from FM.sections.about. */
.about-section{
  background:var(--ab-bg,#22262b);
  color:var(--ab-fg,#e9e7e3)
}
/* v61 — THE SAME TWO-COLOUR SPLIT AS THE SEE-IT BAND, AND THE SAME STORY: `applySections()` has set
   `--ab-heading-fg` and `--ab-body-fg` since the About panel was written and neither rule read them.
   Two panels, two pairs of variables, all four written and none consumed. Kirk: "The About artist
   also needs a Heading and secondary text separation as well."
   Both fall back to `--ab-fg`, so a panel with only one colour set is unchanged. */
.about-section .about-copy h2{color:var(--ab-heading-fg,var(--ab-fg,#f2f0ec));font-family:var(--ab-heading-font,var(--font-display));font-size:var(--ab-heading-size,var(--step-3))}
.about-section .about-copy p{color:var(--ab-body-fg,var(--ab-fg,#cdcbc7));font-family:var(--ab-body-font,var(--font-body));font-size:var(--ab-body-size,var(--step-0))}
.about-section .about-copy .eyebrow{color:var(--ab-eyebrow,var(--accent))}
.about-section .text-link{color:var(--ab-fg,#e9e7e3);border-bottom-color:var(--ab-eyebrow,var(--accent))}

/* ============================================================
   IMAGE PROTECTION
   The shield is a transparent layer over each picture: a right-click or
   a long-press lands on it rather than the <img>, so no "Save image as".
   ============================================================ */
.protect-images img{
  -webkit-user-select:none;user-select:none;-webkit-user-drag:none;
  -webkit-touch-callout:none;pointer-events:none
}
.protect-images .work-img, .protect-images .art-card .frame, .protect-images .stage-art, .protect-images .room-stage, .protect-images .svc-shot, .protect-images .hub-img, .protect-images .pk-img, .protect-images .fs-img, .protect-images .about-image, .protect-images .split-card, .protect-images .svc-tile, .protect-images .other-card, .protect-images .news-card, .protect-images .hero, .protect-images .g-band, .protect-images .s-hero{position:relative}
.protect-images .work-img::after,.protect-images .art-card .frame::after,
.protect-images .stage-art::after,.protect-images .room-stage::after,
.protect-images .svc-shot::after,.protect-images .hub-img::after,
.protect-images .pk-img::after,.protect-images .fs-img::after,
.protect-images .about-image::after{
  content:"";position:absolute;inset:0;z-index:2;pointer-events:none
}
/* pointer-events:none on the shield keeps links working; the img above is
   already pointer-events:none, so a right-click lands on the container and
   the browser offers no image to save. */

#fm-toast{
  position:fixed;left:50%;bottom:24px;transform:translate(-50%,14px);
  background:var(--ink);color:var(--paper);padding:.8rem 1.2rem;border-radius:var(--radius);
  font-size:var(--step--1);max-width:min(90vw,34rem);text-align:center;z-index:300;
  opacity:0;pointer-events:none;transition:opacity .25s,transform .25s;box-shadow:var(--shadow)
}
#fm-toast.on{opacity:1;transform:translate(-50%,0)}

/* ============================================================
   FREE TOOLS
   ============================================================ */
.tool{
  display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:clamp(1.5rem,4vw,4rem);align-items:center;
  padding:clamp(2.5rem,5vw,4.5rem) var(--gutter);border-top:1px solid var(--line)
}
.tool:nth-child(even){background:var(--paper-2)}
.tool:nth-child(even) .tool-shot{order:2}
.tool-shot{position:relative;overflow:hidden;background:var(--ink);aspect-ratio:16/10}
.tool-shot img{width:100%;height:100%;object-fit:cover}
.tool-blank{position:absolute;inset:0;background:linear-gradient(150deg,var(--ink),var(--accent))}
.tool-copy h2{font-size:var(--step-3);margin-bottom:.5rem}
.tool-copy .lead{color:var(--ink-soft)}
.tool-copy p{color:var(--ink-soft)}
.tool-points{margin:.4rem 0 1.4rem;padding-left:1.1rem;color:var(--ink-soft)}
.tool-points li{margin-bottom:.35rem}
.tool-actions{display:flex;flex-wrap:wrap;align-items:center;gap:.7rem}
.dl-note{font-size:var(--step--1);color:var(--ink-soft);width:100%}
.tool-price{font-size:var(--step--1);letter-spacing:.14em;text-transform:uppercase;color:var(--accent);margin:1.1rem 0 0}
.tool-support{margin:.5rem 0 0;font-size:.94rem}
.tool-support a{text-decoration:none;border-bottom:1px solid var(--accent)}
.tool-support span{display:block;font-size:var(--step--1);color:var(--ink-soft);margin-top:.3rem}
@media (max-width:860px){
  .tool,.tool:nth-child(even) .tool-shot{grid-template-columns:1fr;order:0}
}

/* ============================================================
   DIGITAL DOWNLOADS — the product layout, deliberately identical to .tool
   above. Two systems for the same shape (a photo, a name, a price, a
   button) would only be two things to keep in step with each other.
   ============================================================ */
.dp-product{
  display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:clamp(1.5rem,4vw,4rem);align-items:center;
  padding:clamp(2.5rem,5vw,4.5rem) var(--gutter);border-top:1px solid var(--line)
}
.dp-product:nth-child(even) .dp-shot{order:2}
/* v85 — Kirk: "the image placed in the digital download box needs to be able to be scaled so it
   fits inside the box... determine the size and shape of the photo and create a box around it with
   an intentional border so it looks like it's on purpose."

   IT WAS A CROP, NOT A FIT. `aspect-ratio:16/10` with `object-fit:cover` forces every product
   picture into one letterbox and throws away whatever does not fit — which is exactly wrong for a
   product shot, where the thing being cropped off is usually the product. A preset poster is
   portrait-ish; a screenshot is 16/9; a mock-up is square. There is no single ratio that is honest
   about all three.

   So the box takes ITS shape FROM THE PICTURE rather than imposing one. No aspect-ratio, `contain`,
   and a max-height so a tall poster cannot stretch the row out of proportion beside its text. The
   mat — padding, a hairline, a faint inner edge — is what makes an odd shape read as deliberate
   instead of as a gap: the picture is centred in a frame, the way a print is centred in a mount. */
.dp-shot{
  position:relative;display:flex;align-items:center;justify-content:center;
  background:var(--dp-mat-bg,var(--paper-2));
  border:1px solid var(--dp-mat-line,var(--line));
  padding:var(--dp-mat-pad,clamp(.7rem,1.6vw,1.4rem));
  border-radius:var(--radius,0);min-height:12rem;
  /* v86 — Kirk: "the box around the product should be closer to the shape of the product or image
     displayed. This box is far too wide."
     v85 stopped the CROP but left the box a full grid column wide, so a portrait product sat in a
     wide band of mat with its frame nowhere near it — which reads as an empty panel that happens
     to contain a picture, the opposite of the intention. `fit-content` makes the mat take its
     WIDTH from the picture the same way it already took its height, so the border hugs the shape
     whatever that shape is, and `margin-inline:auto` keeps it centred in the column it sits in. */
  width:fit-content;max-width:100%;margin-inline:auto
}
/* The faint inner edge sits on the MAT, not on the picture, so it reads as the lip of a mount and
   never as a border drawn over the photograph itself. */
.dp-shot::after{
  content:"";position:absolute;inset:var(--dp-mat-pad,clamp(.7rem,1.6vw,1.4rem));
  border:1px solid rgba(20,23,26,.10);pointer-events:none;border-radius:inherit
}
/* v87 — width/height now arrive on the tag so the browser can reserve the space. Those attributes
   would otherwise also SET the rendered size, so the CSS keeps overriding both; what survives is
   only the ratio, which is the part worth having. */
.dp-shot img{
  width:auto;max-width:100%;height:auto;max-height:var(--dp-shot-max,30rem);
  object-fit:contain;display:block
}
/* NOT an aspect-ratio on the mat itself: the mat is the picture PLUS its padding, so giving it the
   picture's ratio would squeeze the frame by exactly the padding. The attributes above give the
   image its intrinsic size, the mat shrink-wraps that, and nothing jumps — one mechanism, no
   second ratio to keep in step with the first. */
/* With no picture there is no shape to follow, so the placeholder keeps a ratio of its own rather
   than collapsing the mat to its min-height. */
.dp-blank{display:block;width:28rem;max-width:100%;aspect-ratio:16/10;background:linear-gradient(150deg,var(--ink),var(--accent))}
.dp-copy h2{margin-bottom:.5rem}
.dp-points{margin:.4rem 0 1.4rem;padding-left:1.1rem;color:var(--ink-soft)}
.dp-points li{margin-bottom:.35rem}
/* v83 — a price, not a label. It was --step--1, SMALLER than the body text above it, in uppercase
   with .14em tracking; at the size a price wants to be, that tracking reads as a gap rather than
   as emphasis, so it comes down with the size going up. Both are overridable per product. */
/* v86 — raised AGAIN, to the same size as the product name. Twice now the default has been nudged
   up a step and twice it has still read as small beside the heading, so it stops being nudged: a
   price is the second thing the eye should land on, and at --step-2 against a --step-3 heading it
   never could be. Dial it DOWN per product if a particular one is shouting. */
/* v85 — still not reading as the price. --step-1 is barely above body text; a price is the second
   thing the eye should land on after the name, so the DEFAULT moves up rather than leaving every
   product to be set by hand. The per-product size control (v83) still overrides this. */
.dp-price{font-size:var(--dp-price-size,var(--step-3));letter-spacing:.02em;font-weight:700;
  color:var(--dp-price-fg,var(--accent));margin:1.1rem 0 .8rem}
.dp-actions{display:flex;flex-wrap:wrap;gap:.7rem}
/* v79 — Kirk: "All sections will need background, font colour and size and option control."
   `--dp-fg`/`--dp-size` are set INLINE on one product's own .dp-product element (see initDigital()
   in site.js) rather than as page-wide variables, because every product shares this one page and a
   page-wide setting cannot tell one product from another.
   `#digitalPage .dp-copy h2` (ID + class + element) is deliberately MORE specific than the page-wide
   `#digitalPage h1{...}` rule a few lines up (ID + element only) — the same specificity lesson the
   .checkout-note fix already paid for: a rule that LOOKS like it should win is not the same as one
   that actually does, and the only way to know is to outrank the thing it needs to beat, not merely
   sit near it in the file. Chained THREE LEVELS DEEP: the product's own colour, then the page's own
   heading colour, then whatever the page inherits \u2014 so leaving either blank costs nothing. */
/* v86 — Kirk: "we need a separation for the header and subtext for colour and size changes in the
   digital download section."
   ADDED, NOT REPLACED. `--dp-fg` stays exactly where it was and still means "all the writing here",
   so every product he has already styled looks the same after this change; the two new variables
   simply get a turn first. That ordering is the whole design: heading colour, else the product's
   text colour, else the page's, else the theme's — and a blank at any level costs nothing. */
#digitalPage .dp-copy h2{
  color:var(--dp-head-fg,var(--dp-fg,var(--dd-heading-fg,var(--dd-fg,var(--sf-heading,inherit)))));
  font-size:var(--dp-size,var(--step-3))}
#digitalPage .dp-copy p,#digitalPage .dp-copy .lead,#digitalPage .dp-copy li{
  color:var(--dp-body-fg,var(--dp-fg,var(--dd-body-fg,var(--dd-fg,inherit))));
  font-size:var(--dp-body-size,inherit)}
/* v83 — the kicker is an .eyebrow, which sets its own colour, so the ONE line above the heading was
   the one "Text colour" never reached. Listed by its own selector rather than by loosening the rule
   above, because .dp-price is also a <p> in here and must keep its own colour. */
#digitalPage .dp-copy .eyebrow{color:var(--dp-body-fg,var(--dp-fg,var(--dd-body-fg,var(--dd-fg,inherit))))}
/* …and the price is excluded from the body rule by winning on specificity, not by luck. */
/* v86 — the body rule above now carries a font-size too, so the price has to beat it on BOTH
   properties or a subtext size would silently shrink the price back down. */
#digitalPage .dp-copy p.dp-price{color:var(--dp-price-fg,var(--accent));
  font-size:var(--dp-price-size,var(--step-3))}
/* The alternating shade and a per-product background read through the SAME variable rather than
   competing for the element \u2014 :nth-child(even) is more specific than the base rule regardless of
   which wins the cascade, so without this an even product's own chosen background would be silently
   overridden by the stripe on every other row. */
.dp-product{background:var(--dp-bg,transparent)}
.dp-product:nth-child(even){background:var(--dp-bg,var(--paper-2))}
@media (max-width:860px){
  .dp-product,.dp-product:nth-child(even) .dp-shot{grid-template-columns:1fr;order:0}
}

/* ============================================================================================
   THE BEFORE/AFTER SLIDER (v79). See the long comment beside compareSlider() in site.js for the
   mechanism — this is only the paint. `--ba-max` caps the frame so a very wide product photo
   doesn't turn into an unwieldy full-viewport strip; it sits comfortably inside the page gutter
   either way because .dp-compare centres it.
   ============================================================================================ */
.dp-compare{padding:0 var(--gutter) clamp(2.5rem,5vw,4.5rem)}
.dp-compare:last-child{padding-bottom:clamp(3rem,6vw,5.5rem)}
.ba-slider{max-width:var(--ba-max,52rem);margin-inline:auto}
.ba-frame{
  position:relative;aspect-ratio:3/2;overflow:hidden;background:var(--ink);
  touch-action:none;cursor:ew-resize;border-radius:var(--radius,0)
}
.ba-after,.ba-before{width:100%;height:100%;object-fit:cover;display:block;user-select:none;-webkit-user-drag:none}
.ba-before-wrap{position:absolute;inset:0;overflow:hidden}
.ba-tag{
  position:absolute;top:.9rem;z-index:2;font-size:var(--step--1);letter-spacing:.1em;text-transform:uppercase;
  padding:.35rem .8rem;border-radius:999px;pointer-events:none;
  /* v85 — THE SAME FAULT THE LIGHTBOX TITLE HAD IN v82, in a second place. These pills always sit on
     a dark scrim over a photograph, so their text must be a FIXED light colour. `var(--paper)`
     follows the theme, so on a dark theme the label turned dark-on-dark and disappeared into the
     very scrim meant to lift it off the picture. A colour that has to work against one known
     background is not a themeable colour. The scrim is also carrying more weight now, because a
     bright frame — a sunlit room, a white-walled interior — left .62 too thin to read against. */
  background:rgba(16,18,21,.78);color:#f3f2ef;font-weight:600;
  box-shadow:0 1px 6px rgba(16,18,21,.35)
}
.ba-tag-before{left:.9rem}
.ba-tag-after{right:.9rem}
/* The handle sits ON the clip boundary, so it always marks exactly where before ends and after
   begins — it moves with `pos`, the same number that drives the clip-path, not a separate value
   that could drift from it. */
.ba-handle{
  position:absolute;top:0;bottom:0;left:50%;width:0;z-index:3;
  display:flex;align-items:center;justify-content:center;
  transform:translateX(-50%);touch-action:none;cursor:ew-resize
}
.ba-handle:focus-visible .ba-handle-grip{outline:2px solid var(--accent);outline-offset:2px}
.ba-handle-line{position:absolute;inset:0 auto 0 auto;left:50%;width:2px;transform:translateX(-50%);
  background:var(--paper);box-shadow:0 0 0 1px rgba(20,23,26,.35)}
.ba-handle-grip{
  position:relative;width:2.6rem;height:2.6rem;border-radius:999px;background:var(--paper);
  box-shadow:0 2px 10px rgba(20,23,26,.35);display:flex;align-items:center;justify-content:center
}
.ba-handle-grip::before{content:"\2194";color:var(--ink);font-size:1.15rem;font-weight:700;line-height:1}
@media (max-width:600px){
  .ba-tag{font-size:.68rem;padding:.28rem .6rem}
  .ba-handle-grip{width:2.2rem;height:2.2rem}
}

/* ============================================================
   DESIGN PANEL — studio mode only, never rendered for visitors
   ============================================================ */
.dp-open{
  position:fixed;right:12px;bottom:92px;z-index:400;border:none;cursor:pointer;
  background:#6b46c1;color:#fff;padding:.5rem .8rem;font:inherit;font-size:.72rem;
  letter-spacing:.1em;text-transform:uppercase;border-radius:3px;opacity:.9
}
.dp{
  position:fixed;top:0;right:0;bottom:0;width:min(380px,92vw);z-index:500;
  background:#fff;border-left:1px solid #ddd;box-shadow:-14px 0 40px rgba(0,0,0,.18);
  display:flex;flex-direction:column;transform:translateX(102%);transition:transform .28s ease;
  font-family:system-ui,sans-serif;color:#1a1a1a
}
.dp.on{transform:none}
.dp header{display:flex;align-items:center;justify-content:space-between;
  padding:1rem 1.1rem;border-bottom:1px solid #e6e6e6;font-size:1.05rem}
.dp .dp-close{background:none;border:none;font-size:1.1rem;cursor:pointer;color:#666}
.dp .dp-note{margin:0;padding:.8rem 1.1rem;font-size:.78rem;color:#666;background:#f7f7f7}
.dp-body{flex:1;overflow:auto;padding:0 1.1rem 1.2rem}
.dp-body h4{margin:1.4rem 0 .5rem;font-size:.7rem;letter-spacing:.14em;text-transform:uppercase;color:#888}
.dp footer{display:flex;gap:.5rem;padding:.9rem 1.1rem;border-top:1px solid #e6e6e6}
.dp-btn{flex:1;padding:.6rem;border:1px solid #cfcfcf;background:#fff;font:inherit;font-size:.82rem;cursor:pointer;border-radius:3px}
.dp-btn.primary{background:#1a1a1a;color:#fff;border-color:#1a1a1a}

.dp-palettes{display:grid;gap:.4rem}
.dp-pal{display:flex;align-items:center;gap:.6rem;padding:.45rem .5rem;border:1px solid #e2e2e2;
  background:#fff;cursor:pointer;font:inherit;font-size:.82rem;text-align:left;border-radius:3px}
.dp-pal:hover{border-color:#999}
.dp-chips{display:flex;gap:2px}
.dp-chips i{width:16px;height:16px;border-radius:2px;border:1px solid rgba(0,0,0,.12)}

.dp-row{padding:.6rem 0;border-bottom:1px solid #f0f0f0}
.dp-row-head b{display:block;font-size:.86rem}
.dp-row-head small{display:block;color:#888;font-size:.74rem;margin-top:.1rem}
.dp-colour{display:flex;align-items:center;gap:.4rem;margin-top:.4rem}
.dp-colour input[type=color]{width:38px;height:32px;padding:0;border:1px solid #ddd;background:none;cursor:pointer}
.dp-hex{flex:1;padding:.4rem .5rem;border:1px solid #ddd;font:inherit;font-size:.8rem;border-radius:3px}
.dp-clear{border:none;background:none;color:#888;font:inherit;font-size:.72rem;cursor:pointer;text-decoration:underline}
.dp-font{width:100%;margin-top:.4rem;padding:.45rem;border:1px solid #ddd;font:inherit;font-size:.85rem;border-radius:3px}
.dp-sample{margin:.5rem 0 0;font-size:1.15rem;line-height:1.3;color:#333}
.dp-check{display:flex;gap:.5rem;align-items:center;margin-top:.6rem;font-size:.8rem;color:#444}
.dp-upload{display:inline-block;margin-top:.5rem;border:1px solid #cfcfcf;padding:.45rem .8rem;
  font-size:.8rem;cursor:pointer;border-radius:3px}
.dp-uploaded{margin:.5rem 0 0;font-size:.74rem;color:#666}
.dp-section{border:1px solid #eee;border-radius:4px;padding:.2rem .7rem .5rem;margin-bottom:.7rem}
.dp-section-name{margin:.5rem 0 0}
.dp-section-name b{font-size:.86rem}
.dp-section-name small{display:block;color:#888;font-size:.74rem}

/* design panel — named colour picks, sizes, hints */
.dp-now{display:flex;align-items:center;gap:.35rem;font-size:.76rem;color:#666;margin-top:.2rem}
.dp-now i{width:14px;height:14px;border-radius:3px;border:1px solid rgba(0,0,0,.2);display:inline-block}
.dp-picks{display:grid;grid-template-columns:repeat(3,1fr);gap:.3rem;margin-top:.45rem}
.dp-pick{display:flex;align-items:center;gap:.35rem;padding:.3rem .35rem;border:1px solid #e4e4e4;
  background:#fff;cursor:pointer;font:inherit;font-size:.7rem;border-radius:3px;text-align:left;overflow:hidden}
.dp-pick i{width:14px;height:14px;border-radius:3px;border:1px solid rgba(0,0,0,.15);flex:none}
.dp-pick span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.dp-pick[aria-pressed="true"]{border-color:#1a1a1a;box-shadow:inset 0 0 0 1px #1a1a1a}
.dp-custom-row{display:flex;align-items:center;gap:.5rem;margin-top:.45rem}
.dp-custom-label{font-size:.74rem;color:#777;flex:1}
.dp-custom{width:38px;height:28px;padding:0;border:1px solid #ddd;background:none;cursor:pointer}
.dp-sizes{display:flex;flex-wrap:wrap;gap:.3rem;margin-top:.45rem}
.dp-size{padding:.35rem .6rem;border:1px solid #e4e4e4;background:#fff;cursor:pointer;
  font:inherit;font-size:.74rem;border-radius:3px}
.dp-size[aria-pressed="true"]{border-color:#1a1a1a;box-shadow:inset 0 0 0 1px #1a1a1a}
.dp-hint{margin:.2rem 0 .6rem;font-size:.74rem;color:#777}

/* ============================================================
   HERO HEIGHT + DRAG-TO-POSITION
   A portrait subject can be cropped hard; a wide room shot cannot.
   Height is set per service, the focal point decides what survives.
   ============================================================ */
.s-hero[data-height="short"]{min-height:36vh}
.s-hero[data-height="standard"]{min-height:52vh}
.s-hero[data-height="tall"]{min-height:72vh}
.s-hero[data-height="full"]{min-height:88vh;background-size:contain;background-repeat:no-repeat;background-color:var(--ink)}
/* A "whole picture" hero is letterboxed against the ink background, so a light
   top wash blends the edges rather than dimming a photograph that fills the
   frame. Still adjustable, and still zero if a service wants none. */
.s-hero[data-height="full"]::after{background:linear-gradient(180deg,
  rgba(20,23,26,var(--sv-scrim-top,.25)),rgba(20,23,26,var(--sv-scrim-bottom,.8)))}

/* studio only — the site never shows these */
.can-drag{cursor:grab}
.can-drag.dragging{cursor:grabbing}
.can-drag::before{
  content:"Drag to reposition";position:absolute;top:12px;left:50%;transform:translateX(-50%);
  z-index:3;background:rgba(20,23,26,.8);color:#fff;font-size:.66rem;letter-spacing:.12em;
  text-transform:uppercase;padding:.3rem .7rem;border-radius:3px;pointer-events:none;
  opacity:.85;transition:opacity .2s
}
.can-drag.dragging::before{opacity:0}
img.can-drag::before{content:none}
.hero img.can-drag{cursor:grab}

@media (max-width:900px){
  .s-hero[data-height="tall"]{min-height:56vh}
  .s-hero[data-height="full"]{min-height:60vh}
  /* v75 — the same easing the service hero already gets at this width, for the same two shapes,
     under the gallery band's own names. */
  .g-band[data-height="tall"]{min-height:56vh}
  .g-band[data-height="whole"]{min-height:60vh}
}

/* ============================================================
   PACKAGES — picture one side, everything else centred
   ============================================================ */
.packages{display:grid;gap:clamp(1.5rem,3vw,2.6rem)}
.package{
  display:grid;grid-template-columns:minmax(240px,46%) 1fr;
  background:var(--white);border:1px solid var(--line);align-items:stretch;overflow:visible
}
.package.no-image{grid-template-columns:1fr}
.pk-img{overflow:hidden;background:var(--paper-2)}
.pk-img img{width:100%;height:100%;object-fit:cover;min-height:260px;transition:transform .8s ease}
.package:hover .pk-img img{transform:scale(1.03)}

.pk-body{
  position:relative;display:flex;flex-direction:column;align-items:center;text-align:center;
  padding:clamp(1.8rem,3.5vw,3rem) clamp(1.4rem,3vw,2.6rem)
}
.pk-body h3{
  font-size:clamp(1.9rem,3.6vw,3rem);font-weight:600;line-height:1.05;
  letter-spacing:-.01em;margin:0 0 .4rem
}
.pk-price{
  font-family:var(--font-display);font-size:clamp(1.2rem,2.2vw,1.7rem);
  color:var(--ink-soft);margin:0 0 2.2rem;font-weight:500
}
.pk-blurb{color:var(--ink-soft);max-width:34rem;margin:0 0 1.6rem}
.pk-list{
  list-style:none;margin:0 0 2rem;padding:0;display:grid;gap:.7rem;
  max-width:32rem;text-align:left
}
.pk-list li{position:relative;padding-left:1.1rem;color:var(--ink-soft);font-size:1.02rem}
.pk-list li::before{content:"\2022";position:absolute;left:0;color:var(--accent);font-size:1.1em;line-height:1}

/* Book Now — large, pill, Frozen Moments light blue */
.pk-cta{
  margin-top:auto;background:var(--fm-blue,#8ecae6);color:var(--fm-blue-ink,#14171a);
  border-color:var(--fm-blue,#8ecae6);border-radius:999px;
  padding:1rem 3rem;font-size:.9rem;letter-spacing:.1em
}
.pk-cta:hover{background:var(--fm-blue-hover,#6fb8d8);border-color:var(--fm-blue-hover,#6fb8d8);color:var(--fm-blue-ink,#14171a)}

/* the badge sits over the corner of the card */
.package.is-popular{overflow:visible}
.pk-badge{
  position:absolute;top:-22px;right:-22px;width:104px;height:104px;display:grid;
  place-content:center;text-align:center;color:#4a3a12;line-height:1.05;z-index:3;
  background:radial-gradient(circle at 38% 34%,#f6dd8e,#d8ad4a 62%,#c1922f);
  clip-path:polygon(50% 0%,61% 18%,82% 12%,82% 34%,100% 44%,86% 60%,95% 80%,73% 82%,64% 100%,
    50% 88%,36% 100%,27% 82%,5% 80%,14% 60%,0% 44%,18% 34%,18% 12%,39% 18%);
  box-shadow:0 6px 16px rgba(20,23,26,.22)
}
.pk-badge b{display:block;font-size:.68rem;letter-spacing:.1em;text-transform:uppercase;font-weight:600}
.pk-badge i{display:block;font-style:normal;font-size:.92rem;font-weight:700;letter-spacing:.02em}

@media (max-width:820px){
  .package,.package.no-image{grid-template-columns:1fr}
  .pk-img img{min-height:0;aspect-ratio:3/2}
  .pk-body{padding:2rem 1.2rem}
  .pk-cta{width:100%;padding:1rem 1.5rem}
  .pk-badge{width:88px;height:88px;top:-16px;right:-10px}
  .pk-list{text-align:left;justify-self:start}
}

/* ============================================================
   /art — QR landing
   ============================================================ */
.venue-bar{
  background:var(--accent);color:#fff;padding:.7rem var(--gutter);
  font-size:var(--step--1);text-align:center
}
.venue-bar b{font-weight:600}
.edition-note.urgent{color:#a2564f;border-left-color:#a2564f;font-weight:600}
.cart-venue{font-size:var(--step--1);color:var(--ink-soft);margin:.4rem 0 0}

/* ============================================================
   CLIENT GALLERY
   ============================================================ */
.client-page{min-height:60vh}
.client-gate{display:grid;place-items:center;padding:clamp(3rem,10vh,7rem) var(--gutter)}
.gate-card{background:var(--white);border:1px solid var(--line);padding:clamp(1.8rem,4vw,3rem);
  max-width:34rem;width:100%;box-shadow:var(--shadow)}
.gate-card h1{font-size:var(--step-2);margin-bottom:.7rem}
.gate-card p{color:var(--ink-soft)}
.gate-field{display:block;margin:1.6rem 0 1rem;font-size:var(--step--1);letter-spacing:.06em;
  text-transform:uppercase;color:var(--ink-soft)}
.gate-field input{display:block;width:100%;margin-top:.4rem;padding:.8rem .9rem;border:1px solid var(--line);
  font:inherit;font-size:1.1rem;letter-spacing:.02em;text-transform:none;border-radius:var(--radius);
  background:var(--paper);color:var(--ink)}
.gate-field input:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 3px rgba(47,93,98,.14)}
.gate-error{color:#a2564f;font-size:.92rem;margin-top:.8rem}
.gate-card .note{margin-top:1.2rem;font-size:var(--step--1);color:var(--ink-soft)}

.client-head{display:flex;flex-wrap:wrap;gap:1.5rem;justify-content:space-between;align-items:flex-end;
  padding:clamp(2rem,5vw,3.5rem) var(--gutter) 1rem}
.client-head h1{font-size:var(--step-3);margin-bottom:.4rem}
.client-head p{color:var(--ink-soft);margin:0}
.client-meta{font-size:var(--step--1);letter-spacing:.06em;text-transform:uppercase;color:var(--accent);margin-top:.6rem!important}
.client-actions{display:flex;flex-wrap:wrap;gap:.6rem}
.client-note{padding:0 var(--gutter);color:var(--ink-soft);font-size:.94rem;max-width:44rem}

.client-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));
  gap:clamp(1rem,2vw,1.6rem);padding:clamp(1.5rem,3vw,2.5rem) var(--gutter) 5rem}
.cg-item{margin:0;background:var(--white);border:1px solid var(--line)}
.cg-open{display:block;width:100%;padding:0;border:none;background:var(--paper-2);cursor:zoom-in;line-height:0}
.cg-open img{width:100%;aspect-ratio:3/2;object-fit:cover;display:block;transition:opacity .3s}
.cg-open:hover img{opacity:.9}
.cg-item figcaption{display:flex;justify-content:space-between;align-items:center;gap:.6rem;
  padding:.6rem .8rem;font-size:var(--step--1)}
.cg-item figcaption span{color:var(--ink-soft);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cg-dl{text-decoration:none;color:var(--accent);border-bottom:1px solid var(--accent);white-space:nowrap}

.cg-viewer{position:fixed;inset:0;z-index:500;background:rgba(12,14,16,.95);display:grid;
  place-items:center;padding:3rem 1rem 5rem}
.cg-viewer img{max-width:100%;max-height:100%;object-fit:contain}
.cg-close,.cg-nav{position:absolute;background:rgba(255,255,255,.1);border:none;color:#fff;
  cursor:pointer;font-size:1.6rem;line-height:1;padding:.5rem .8rem;border-radius:4px}
.cg-close{top:1rem;right:1rem}
.cg-nav{top:50%;transform:translateY(-50%);font-size:2.4rem}
.cg-nav.prev{left:1rem}
.cg-nav.next{right:1rem}
.cg-close:hover,.cg-nav:hover{background:rgba(255,255,255,.2)}
.cg-viewer-bar{position:absolute;left:0;right:0;bottom:0;display:flex;flex-wrap:wrap;gap:1rem;
  align-items:center;justify-content:space-between;padding:1rem var(--gutter);
  background:rgba(12,14,16,.8);color:rgba(255,255,255,.85);font-size:var(--step--1)}
.cg-viewer-bar .button{background:var(--paper);color:var(--ink);border-color:var(--paper)}
/* v49 — THE HOVER TWIN, restored. A rule that sets a button's resting colour with no matching
   hover rule in the SAME context means the hover colour never reaches that button: the resting
   rule outranks the base hover rule and the button simply does not respond. Every override needs
   its pair. (This and the per-area colour rules were both fixed in the StudioFlow chat's own v48;
   the website chat's v48 was built from v47 and did not carry them, so installing it reverted both
   — see the version-collision note in VERSION.txt.) */
.cg-viewer-bar .button:hover{background:var(--btn-hover-bg,var(--paper));color:var(--btn-hover-fg,var(--ink));border-color:var(--btn-hover-bg,var(--paper))}

@media (max-width:700px){
  .client-head{align-items:flex-start}
  .client-actions{width:100%}
  .client-actions .button{flex:1;text-align:center}
  .cg-nav{font-size:1.8rem}
}
.dp-ver{font-size:.68rem;letter-spacing:.08em;text-transform:uppercase;color:#888;margin-left:auto;margin-right:.6rem}
.from-label{font-size:var(--step--1);color:var(--ink-soft);background:var(--paper-2);
  border-left:2px solid var(--accent);padding:.6rem .8rem;margin:-.6rem 0 1.4rem}
.checkout-error{background:#fbf4f3;border-left:3px solid #a2564f;color:#7d3f39;
  padding:.8rem 1rem;font-size:.92rem;margin:.8rem 0 0}

/* cart: where it ships to decides the tax */
.cart-tax{border-top:1px solid var(--line);margin-top:.8rem;padding-top:1rem}
.ship-to{display:block;font-size:var(--step--1);letter-spacing:.06em;text-transform:uppercase;
  color:var(--ink-soft);margin-bottom:1rem}
.ship-to select{display:block;width:100%;max-width:22rem;margin-top:.35rem;padding:.6rem .7rem;
  border:1px solid var(--line);font:inherit;font-size:1rem;background:var(--paper);
  color:var(--ink);border-radius:var(--radius);text-transform:none;letter-spacing:0}
.cart-tax .line{display:flex;justify-content:space-between;font-size:.94rem;
  color:var(--ink-soft);margin-bottom:.35rem}
.cart-grand{display:flex;justify-content:space-between;align-items:baseline;
  font-family:var(--font-display);font-size:var(--step-2);margin:.8rem 0 0;
  border-top:1px solid var(--ink);padding-top:.7rem}
.tax-note{font-size:var(--step--1);color:var(--ink-soft);margin:.3rem 0}

/* ================================================================================================
   v37 — PER-AREA COLOURS, FONTS AND SIZES.
   ================================================================================================
   One block per area in site.js's AREAS table. Each reads its own prefixed variables and falls
   back to the site-wide value, so an area he has never touched looks exactly as it does today and
   clearing a control returns it to the theme rather than to something invented.

   HEADINGS AND BODY ARE STYLED SEPARATELY because that is how he asked for them — "font size
   background colour and font colour and style" for each area — and a single font rule on the
   container would let a heading inherit a body size.

   The selectors deliberately reach h1/h2/h3 and p/li rather than using `*`: a wildcard would also
   repaint buttons, prices and form fields, which have their own colours for a reason.
   ================================================================================================ */
#galleriesPage{background:var(--gp-bg,inherit);color:var(--gp-fg,inherit)}
#galleriesPage h1{color:var(--gp-heading-fg,var(--gp-fg,var(--sf-heading,inherit)));font-family:var(--gp-heading-font,var(--font-display));font-weight:var(--gp-heading-weight,inherit);font-size:var(--gp-heading-size,var(--step-4))}
#galleriesPage h2{color:var(--gp-heading-fg,var(--gp-fg,var(--sf-heading,inherit)));font-family:var(--gp-heading-font,var(--font-display));font-weight:var(--gp-heading-weight,inherit);font-size:var(--gp-heading-size,var(--step-3))}
#galleriesPage h3{color:var(--gp-heading-fg,var(--gp-fg,var(--sf-heading,inherit)));font-family:var(--gp-heading-font,var(--font-display));font-weight:var(--gp-heading-weight,inherit);font-size:var(--gp-heading-size,var(--step-1))}
#galleriesPage p,#galleriesPage li{color:var(--gp-body-fg,var(--gp-fg,inherit));font-family:var(--gp-body-font,var(--font-body));font-size:var(--gp-body-size,inherit);font-weight:var(--gp-body-weight,inherit)}
#galleriesPage .eyebrow,#galleriesPage .text-link{color:var(--gp-accent,var(--accent))}

#galleryPage{background:var(--gy-bg,inherit);color:var(--gy-fg,inherit)}
#galleryPage h1{color:var(--gy-heading-fg,var(--gy-fg,var(--sf-heading,inherit)));font-family:var(--gy-heading-font,var(--font-display));font-weight:var(--gy-heading-weight,inherit);font-size:var(--gy-heading-size,var(--step-4))}
#galleryPage h2{color:var(--gy-heading-fg,var(--gy-fg,var(--sf-heading,inherit)));font-family:var(--gy-heading-font,var(--font-display));font-weight:var(--gy-heading-weight,inherit);font-size:var(--gy-heading-size,var(--step-3))}
#galleryPage h3{color:var(--gy-heading-fg,var(--gy-fg,var(--sf-heading,inherit)));font-family:var(--gy-heading-font,var(--font-display));font-weight:var(--gy-heading-weight,inherit);font-size:var(--gy-heading-size,var(--step-1))}
#galleryPage p,#galleryPage li{color:var(--gy-body-fg,var(--gy-fg,inherit));font-family:var(--gy-body-font,var(--font-body));font-size:var(--gy-body-size,inherit);font-weight:var(--gy-body-weight,inherit)}
#galleryPage .eyebrow,#galleryPage .text-link{color:var(--gy-accent,var(--accent))}

#servicesPage{background:var(--sp-bg,inherit);color:var(--sp-fg,inherit)}
#servicesPage h1{color:var(--sp-heading-fg,var(--sp-fg,var(--sf-heading,inherit)));font-family:var(--sp-heading-font,var(--font-display));font-weight:var(--sp-heading-weight,inherit);font-size:var(--sp-heading-size,var(--step-4))}
#servicesPage h2{color:var(--sp-heading-fg,var(--sp-fg,var(--sf-heading,inherit)));font-family:var(--sp-heading-font,var(--font-display));font-weight:var(--sp-heading-weight,inherit);font-size:var(--sp-heading-size,var(--step-3))}
#servicesPage h3{color:var(--sp-heading-fg,var(--sp-fg,var(--sf-heading,inherit)));font-family:var(--sp-heading-font,var(--font-display));font-weight:var(--sp-heading-weight,inherit);font-size:var(--sp-heading-size,var(--step-1))}
#servicesPage p,#servicesPage li{color:var(--sp-body-fg,var(--sp-fg,inherit));font-family:var(--sp-body-font,var(--font-body));font-size:var(--sp-body-size,inherit);font-weight:var(--sp-body-weight,inherit)}
#servicesPage .eyebrow,#servicesPage .text-link{color:var(--sp-accent,var(--accent))}

#servicePage{background:var(--sv-bg,inherit);color:var(--sv-fg,inherit)}
#servicePage h1{color:var(--sv-heading-fg,var(--sv-fg,var(--sf-heading,inherit)));font-family:var(--sv-heading-font,var(--font-display));font-weight:var(--sv-heading-weight,inherit);font-size:var(--sv-heading-size,var(--step-4))}
#servicePage h2{color:var(--sv-heading-fg,var(--sv-fg,var(--sf-heading,inherit)));font-family:var(--sv-heading-font,var(--font-display));font-weight:var(--sv-heading-weight,inherit);font-size:var(--sv-heading-size,var(--step-3))}
#servicePage h3{color:var(--sv-heading-fg,var(--sv-fg,var(--sf-heading,inherit)));font-family:var(--sv-heading-font,var(--font-display));font-weight:var(--sv-heading-weight,inherit);font-size:var(--sv-heading-size,var(--step-1))}
#servicePage p,#servicePage li{color:var(--sv-body-fg,var(--sv-fg,inherit));font-family:var(--sv-body-font,var(--font-body));font-size:var(--sv-body-size,inherit);font-weight:var(--sv-body-weight,inherit)}
#servicePage .eyebrow,#servicePage .text-link{color:var(--sv-accent,var(--accent))}

#storePage{background:var(--sr-bg,inherit);color:var(--sr-fg,inherit)}
#storePage h1{color:var(--sr-heading-fg,var(--sr-fg,var(--sf-heading,inherit)));font-family:var(--sr-heading-font,var(--font-display));font-weight:var(--sr-heading-weight,inherit);font-size:var(--sr-heading-size,var(--step-4))}
#storePage h2{color:var(--sr-heading-fg,var(--sr-fg,var(--sf-heading,inherit)));font-family:var(--sr-heading-font,var(--font-display));font-weight:var(--sr-heading-weight,inherit);font-size:var(--sr-heading-size,var(--step-3))}
#storePage h3{color:var(--sr-heading-fg,var(--sr-fg,var(--sf-heading,inherit)));font-family:var(--sr-heading-font,var(--font-display));font-weight:var(--sr-heading-weight,inherit);font-size:var(--sr-heading-size,var(--step-1))}
#storePage p,#storePage li{color:var(--sr-body-fg,var(--sr-fg,inherit));font-family:var(--sr-body-font,var(--font-body));font-size:var(--sr-body-size,inherit);font-weight:var(--sr-body-weight,inherit)}
#storePage .eyebrow,#storePage .text-link{color:var(--sr-accent,var(--accent))}

/* v77 — Kirk: "I have a store and product page, but none of those controls do anything for the
   'cart' page." Same four rules as every other page area, nothing bespoke. */
#cartPage{background:var(--ca-bg,inherit);color:var(--ca-fg,inherit)}
#cartPage h1{color:var(--ca-heading-fg,var(--ca-fg,var(--sf-heading,inherit)));font-family:var(--ca-heading-font,var(--font-display));font-weight:var(--ca-heading-weight,inherit);font-size:var(--ca-heading-size,var(--step-4))}
#cartPage p,#cartPage li{color:var(--ca-body-fg,var(--ca-fg,inherit));font-family:var(--ca-body-font,var(--font-body));font-size:var(--ca-body-size,inherit);font-weight:var(--ca-body-weight,inherit)}
#cartPage .eyebrow,#cartPage .text-link{color:var(--ca-accent,var(--accent))}

/* v79 — the Digital Downloads page, same four rules as every other page area. */
#digitalPage{background:var(--dd-bg,inherit);color:var(--dd-fg,inherit)}
#digitalPage h1{color:var(--dd-heading-fg,var(--dd-fg,var(--sf-heading,inherit)));font-family:var(--dd-heading-font,var(--font-display));font-weight:var(--dd-heading-weight,inherit);font-size:var(--dd-heading-size,var(--step-4))}
#digitalPage p,#digitalPage li{color:var(--dd-body-fg,var(--dd-fg,inherit));font-family:var(--dd-body-font,var(--font-body));font-size:var(--dd-body-size,inherit);font-weight:var(--dd-body-weight,inherit)}
#digitalPage .eyebrow,#digitalPage .text-link{color:var(--dd-accent,var(--accent))}

.product-layout{background:var(--pr-bg,inherit);color:var(--pr-fg,inherit)}
.product-layout h1{color:var(--pr-heading-fg,var(--pr-fg,var(--sf-heading,inherit)));font-family:var(--pr-heading-font,var(--font-display));font-weight:var(--pr-heading-weight,inherit);font-size:var(--pr-heading-size,var(--step-4))}
.product-layout h2{color:var(--pr-heading-fg,var(--pr-fg,var(--sf-heading,inherit)));font-family:var(--pr-heading-font,var(--font-display));font-weight:var(--pr-heading-weight,inherit);font-size:var(--pr-heading-size,var(--step-3))}
.product-layout h3{color:var(--pr-heading-fg,var(--pr-fg,var(--sf-heading,inherit)));font-family:var(--pr-heading-font,var(--font-display));font-weight:var(--pr-heading-weight,inherit);font-size:var(--pr-heading-size,var(--step-1))}
.product-layout p,.product-layout li{color:var(--pr-body-fg,var(--pr-fg,inherit));font-family:var(--pr-body-font,var(--font-body));font-size:var(--pr-body-size,inherit);font-weight:var(--pr-body-weight,inherit)}
.product-layout .eyebrow,.product-layout .text-link{color:var(--pr-accent,var(--accent))}

.contact-layout{background:var(--ct-bg,inherit);color:var(--ct-fg,inherit)}
.contact-layout h1{color:var(--ct-heading-fg,var(--ct-fg,var(--sf-heading,inherit)));font-family:var(--ct-heading-font,var(--font-display));font-weight:var(--ct-heading-weight,inherit);font-size:var(--ct-heading-size,var(--step-4))}
.contact-layout h2{color:var(--ct-heading-fg,var(--ct-fg,var(--sf-heading,inherit)));font-family:var(--ct-heading-font,var(--font-display));font-weight:var(--ct-heading-weight,inherit);font-size:var(--ct-heading-size,var(--step-3))}
.contact-layout h3{color:var(--ct-heading-fg,var(--ct-fg,var(--sf-heading,inherit)));font-family:var(--ct-heading-font,var(--font-display));font-weight:var(--ct-heading-weight,inherit);font-size:var(--ct-heading-size,var(--step-1))}
.contact-layout p,.contact-layout li{color:var(--ct-body-fg,var(--ct-fg,inherit));font-family:var(--ct-body-font,var(--font-body));font-size:var(--ct-body-size,inherit);font-weight:var(--ct-body-weight,inherit)}
.contact-layout .eyebrow,.contact-layout .text-link{color:var(--ct-accent,var(--accent))}

/* ================================================================================================
   v71 — THE FREE TOOLS PAGE, WHICH HAD NO AREA UNTIL NOW.
   ================================================================================================
   Written to match every other area exactly, so nothing here is a special case except the one thing
   that genuinely is: this page alternates between two backgrounds, so it needs two.

   `--tl-bg-alt` falls back to `--paper-2`, which is what those bands used before, so a Kirk who
   never opens this card sees the page he has today. */
#toolsPage{background:var(--tl-bg,inherit);color:var(--tl-fg,inherit)}
#toolsPage h1{color:var(--tl-heading-fg,var(--tl-fg,var(--sf-heading,inherit)));font-family:var(--tl-heading-font,var(--font-display));font-weight:var(--tl-heading-weight,inherit);font-size:var(--tl-heading-size,var(--step-4))}
#toolsPage h2{color:var(--tl-heading-fg,var(--tl-fg,var(--sf-heading,inherit)));font-family:var(--tl-heading-font,var(--font-display));font-weight:var(--tl-heading-weight,inherit);font-size:var(--tl-heading-size,var(--step-3))}
#toolsPage h3{color:var(--tl-heading-fg,var(--tl-fg,var(--sf-heading,inherit)));font-family:var(--tl-heading-font,var(--font-display));font-weight:var(--tl-heading-weight,inherit);font-size:var(--tl-heading-size,var(--step-1))}
#toolsPage p,#toolsPage li{color:var(--tl-body-fg,var(--tl-fg,inherit));font-family:var(--tl-body-font,var(--font-body));font-size:var(--tl-body-size,inherit);font-weight:var(--tl-body-weight,inherit)}
#toolsPage .eyebrow,#toolsPage .text-link{color:var(--tl-accent,var(--accent))}
/* THE ALTERNATING BANDS. Both of them carry the id so they beat `.tool:nth-child(even)` and
   `.tool-band.alt` above, which are class rules — an id beats any number of classes, the fault that
   cost the hero size two builds running. */
#toolsPage .tool:nth-child(even),#toolsPage .tool-band.alt{background:var(--tl-bg-alt,var(--paper-2))}
/* A tool with no picture drew a gradient box that says nothing — Kirk: "not sure what the grey box
   is". With no picture the box is gone and the words take the full width, the same rule the room
   example follows: show his photograph or show nothing, never a placeholder pretending to be one. */
#toolsPage .tool:has(.tool-blank){grid-template-columns:minmax(0,1fr)}
#toolsPage .tool .tool-blank{display:none}
#toolsPage .tool:has(.tool-blank) .tool-shot{display:none}

/* ================================================================================================
   v38 — ALL FOUR COLLECTIONS ON ONE SCREEN.
   ================================================================================================
   Kirk: "I want all 4 to be on the same page and seen at the same time."

   Each hub card was an image with `aspect-ratio:16/10` and a body beside it, so the card's height
   came from the WIDTH of the picture. On a wide window that made each row several hundred pixels
   tall and four of them ran well past the fold — the more room the page had, the worse it got.

   THE HEIGHT NOW COMES FROM THE VIEWPORT INSTEAD. Four rows plus the page's own heading are given
   a share of the screen, so four fit whatever the window is doing. The image fills its half rather
   than dictating the shape, and the floors stop it collapsing to a sliver on a short laptop.
   ================================================================================================ */
.hub{--hub-row:clamp(84px,17vh,190px)}
.hub-card{grid-template-rows:var(--hub-row)}
.hub-img{aspect-ratio:auto;height:100%;min-height:0}
.hub-body{padding:clamp(.6rem,1.6vh,1.4rem) clamp(1rem,3vw,2.5rem);min-height:0;overflow:hidden}
.hub-body h2{font-size:clamp(1rem,2.2vh,1.6rem);margin:0}
.hub-body p{display:none}                 /* the blurb is what pushed each row past its share */
.hub-num{font-size:clamp(.6rem,1.3vh,.8rem)}
.hub-meta{font-size:clamp(.65rem,1.4vh,.85rem)}
/* On a phone the cards stack anyway and vertical room is the scarce thing, so let them breathe. */
@media (max-width:760px){
  .hub{--hub-row:clamp(70px,12vh,120px)}
  .hub-body h2{font-size:1rem}
}

/* ================================================================================================
   v41 — "TEXT" ON AN AREA MEANS ALL OF ITS TEXT.
   ================================================================================================
   Kirk asked where he changes the font colour for the galleries. The answer is the per-area Text
   control — but v37 only reached h1/h2/h3 and p/li, and a gallery card's caption number, its
   edition line and the hub's own labels are SPANS. So the control would have coloured the titles
   and blurbs and left the small print behind, which reads as a control that half works.

   Still not a wildcard: `*` would repaint buttons, prices and form fields, which carry their own
   colours deliberately. These are named because each one is genuinely body text in that area.
   ================================================================================================ */
#galleriesPage .hub-meta,#galleriesPage .hub-body h2{color:var(--gp-fg,inherit)}
/* v58 — `:not(.work-no)` IS THE WHOLE FIX FOR THE GALLERY NUMBERS, AND IT IS A SPECIFICITY FAULT,
   NOT A SOURCE-ORDER ONE. Kirk, three builds running: "the numbers in the gallery are not being
   controlled by the gallery colour swatch." The rule below this block —
   `#galleryPage .work-no{color:var(--accent,…)}` — is CORRECT and was never reached: `.work-no` is a
   `<span>` inside `.work-cap`, so `#galleryPage .work-cap span` matched it too, and at (1,1,1) it
   beats (1,1,0) no matter which comes last in the file. Moving it or restating it would have changed
   nothing, which is why reading the two selectors made this look already fixed.
   Found by RESOLVING the cascade — collecting every rule that sets `color` on a gallery-page
   `.work-no` and computing specificity the way a browser does — the g262 lesson, third time this has
   caught a rule that reads correctly and loses. The edition line is left alone: it follows the area's
   text colour deliberately (g244), and only the numbers were reported. */
#galleryPage .work-edition,#galleryPage .work-cap span:not(.work-no){color:var(--gy-fg,inherit)}
#galleryPage .work-cap h3,#galleryPage .work-cap p{color:var(--gy-fg,inherit)}
#servicesPage .svc-label b,#servicesPage .svc-label em{color:var(--sp-fg,inherit)}
#servicePage .svc-label b,#servicePage .svc-label em{color:var(--sv-fg,inherit)}
#storePage .work-no,#storePage .work-cap span{color:var(--sr-fg,inherit)}
.product-layout .meta,.product-layout .work-no{color:var(--pr-fg,inherit)}
.contact-layout .contact-facts b,.contact-layout .contact-facts span{color:var(--ct-fg,inherit)}
/* The eyebrow and links keep following the area's ACCENT rather than its body colour — they are
   the one thing in these blocks that is meant to stand apart. */
/* g244 — Kirk: "I also liked how the gallery colour choice would control the colour of the numbers
   inside the gallery, it was a nice added touch". g241 pointed them at the area ACCENT instead,
   which took that away. Back to the gallery's own Text colour, with the accent only if he has
   deliberately set one for that area. */
/* THE COLLECTION'S OWN ACCENT COMES FIRST. --accent is set per gallery on the page
   element, so each collection's numbers carry its own colour — which is what the
   numbers are for. The area's text colour is the fallback, for a collection with
   no accent of its own. Reversing these is what made them go white. */
#galleryPage .work-no{color:var(--accent,var(--gy-fg,inherit))}
#galleriesPage .hub-num{color:var(--accent,var(--gp-fg,inherit))}

/* g244 — THE PACKAGE PANEL ON A SERVICE PAGE. Kirk: "I also do not see how to edit the inside of
   the window in wedding services where it lists the price and what is included with the service".
   It was painted from the site-wide --ink / --ink-soft / --accent, so the per-service Text and
   Accent controls stopped at the page around it and never reached the panel itself. */
#servicePage .package{background:var(--sv-panel,var(--sv-bg,inherit))}
#servicePage .pk-body h3{color:var(--sv-heading-fg,var(--sv-fg,var(--sf-heading,inherit)));font-family:var(--sv-heading-font,var(--font-display))}
#servicePage .pk-price{color:var(--sv-accent,var(--accent))}
#servicePage .pk-body p,#servicePage .pk-list li{color:var(--sv-fg,var(--ink-soft));font-family:var(--sv-body-font,var(--font-body))}
#servicePage .pk-list li::before{color:var(--sv-accent,var(--accent))}

/* ================================================================================================
   v44 — THE HOME PAGE'S OWN SECTIONS, EACH STYLED SEPARATELY.
   ================================================================================================
   Same shape as v37's page areas: background, text, accent, and heading/body font, size and weight,
   each falling back to the site-wide value so an untouched section looks exactly as it does today.
   Named elements rather than a wildcard, for the same reason as before — buttons, prices and form
   fields carry their own colours deliberately.
   ================================================================================================ */
#siteHeader{background:var(--hd-bg,inherit);color:var(--hd-fg,inherit)}
#siteHeader h1{color:var(--hd-heading-fg,var(--hd-fg,var(--sf-heading,inherit)));font-family:var(--hd-heading-font,var(--font-display));font-weight:var(--hd-heading-weight,inherit);font-size:var(--hd-heading-size,var(--step-4))}
#siteHeader h2{color:var(--hd-heading-fg,var(--hd-fg,var(--sf-heading,inherit)));font-family:var(--hd-heading-font,var(--font-display));font-weight:var(--hd-heading-weight,inherit);font-size:var(--hd-heading-size,var(--step-3))}
#siteHeader h3{color:var(--hd-heading-fg,var(--hd-fg,var(--sf-heading,inherit)));font-family:var(--hd-heading-font,var(--font-display));font-weight:var(--hd-heading-weight,inherit);font-size:var(--hd-heading-size,var(--step-1))}
#siteHeader p,#siteHeader li,#siteHeader span,#siteHeader b,#siteHeader em,#siteHeader small{color:var(--hd-body-fg,var(--hd-fg,inherit));font-family:var(--hd-body-font,var(--font-body));font-size:var(--hd-body-size,inherit);font-weight:var(--hd-body-weight,inherit)}
#siteHeader .eyebrow,#siteHeader .text-link{color:var(--hd-accent,var(--accent))}

#homeHero{background:var(--he-bg,inherit);color:var(--he-fg,inherit)}
#homeHero h1{color:var(--he-heading-fg,var(--he-fg,var(--sf-heading,inherit)));font-family:var(--he-heading-font,var(--font-display));font-weight:var(--he-heading-weight,inherit);font-size:var(--he-heading-size,var(--step-4))}
#homeHero h2{color:var(--he-heading-fg,var(--he-fg,var(--sf-heading,inherit)));font-family:var(--he-heading-font,var(--font-display));font-weight:var(--he-heading-weight,inherit);font-size:var(--he-heading-size,var(--step-3))}
#homeHero h3{color:var(--he-heading-fg,var(--he-fg,var(--sf-heading,inherit)));font-family:var(--he-heading-font,var(--font-display));font-weight:var(--he-heading-weight,inherit);font-size:var(--he-heading-size,var(--step-1))}
#homeHero p,#homeHero li,#homeHero span,#homeHero b,#homeHero em,#homeHero small{color:var(--he-body-fg,var(--he-fg,inherit));font-family:var(--he-body-font,var(--font-body));font-size:var(--he-body-size,inherit);font-weight:var(--he-body-weight,inherit)}
#homeHero .eyebrow,#homeHero .text-link{color:var(--he-accent,var(--accent))}

#homeNews{background:var(--nw-bg,inherit);color:var(--nw-fg,inherit)}
#homeNews h1{color:var(--nw-heading-fg,var(--nw-fg,var(--sf-heading,inherit)));font-family:var(--nw-heading-font,var(--font-display));font-weight:var(--nw-heading-weight,inherit);font-size:var(--nw-heading-size,var(--step-4))}
#homeNews h2{color:var(--nw-heading-fg,var(--nw-fg,var(--sf-heading,inherit)));font-family:var(--nw-heading-font,var(--font-display));font-weight:var(--nw-heading-weight,inherit);font-size:var(--nw-heading-size,var(--step-3))}
#homeNews h3{color:var(--nw-heading-fg,var(--nw-fg,var(--sf-heading,inherit)));font-family:var(--nw-heading-font,var(--font-display));font-weight:var(--nw-heading-weight,inherit);font-size:var(--nw-heading-size,var(--step-1))}
#homeNews p,#homeNews li,#homeNews span,#homeNews b,#homeNews em,#homeNews small{color:var(--nw-body-fg,var(--nw-fg,inherit));font-family:var(--nw-body-font,var(--font-body));font-size:var(--nw-body-size,inherit);font-weight:var(--nw-body-weight,inherit)}
#homeNews .eyebrow,#homeNews .text-link{color:var(--nw-accent,var(--accent))}

#splitCards{background:var(--dr-bg,inherit);color:var(--dr-fg,inherit)}
#splitCards h1{color:var(--dr-heading-fg,var(--dr-fg,var(--sf-heading,inherit)));font-family:var(--dr-heading-font,var(--font-display));font-weight:var(--dr-heading-weight,inherit);font-size:var(--dr-heading-size,var(--step-4))}
#splitCards h2{color:var(--dr-heading-fg,var(--dr-fg,var(--sf-heading,inherit)));font-family:var(--dr-heading-font,var(--font-display));font-weight:var(--dr-heading-weight,inherit);font-size:var(--dr-heading-size,var(--step-3))}
#splitCards h3{color:var(--dr-heading-fg,var(--dr-fg,var(--sf-heading,inherit)));font-family:var(--dr-heading-font,var(--font-display));font-weight:var(--dr-heading-weight,inherit);font-size:var(--dr-heading-size,var(--step-1))}
#splitCards p,#splitCards li,#splitCards span,#splitCards b,#splitCards em,#splitCards small{color:var(--dr-body-fg,var(--dr-fg,inherit));font-family:var(--dr-body-font,var(--font-body));font-size:var(--dr-body-size,inherit);font-weight:var(--dr-body-weight,inherit)}
#splitCards .eyebrow,#splitCards .text-link{color:var(--dr-accent,var(--accent))}

#collections{background:var(--cl-bg,inherit);color:var(--cl-fg,inherit)}
#collections h1{color:var(--cl-heading-fg,var(--cl-fg,var(--sf-heading,inherit)));font-family:var(--cl-heading-font,var(--font-display));font-weight:var(--cl-heading-weight,inherit);font-size:var(--cl-heading-size,var(--step-4))}
#collections h2{color:var(--cl-heading-fg,var(--cl-fg,var(--sf-heading,inherit)));font-family:var(--cl-heading-font,var(--font-display));font-weight:var(--cl-heading-weight,inherit);font-size:var(--cl-heading-size,var(--step-3))}
#collections h3{color:var(--cl-heading-fg,var(--cl-fg,var(--sf-heading,inherit)));font-family:var(--cl-heading-font,var(--font-display));font-weight:var(--cl-heading-weight,inherit);font-size:var(--cl-heading-size,var(--step-1))}
#collections p,#collections li,#collections span,#collections b,#collections em,#collections small{color:var(--cl-body-fg,var(--cl-fg,inherit));font-family:var(--cl-body-font,var(--font-body));font-size:var(--cl-body-size,inherit);font-weight:var(--cl-body-weight,inherit)}
#collections .eyebrow,#collections .text-link{color:var(--cl-accent,var(--accent))}

#services{background:var(--sx-bg,inherit);color:var(--sx-fg,inherit)}
#services h1{color:var(--sx-heading-fg,var(--sx-fg,var(--sf-heading,inherit)));font-family:var(--sx-heading-font,var(--font-display));font-weight:var(--sx-heading-weight,inherit);font-size:var(--sx-heading-size,var(--step-4))}
#services h2{color:var(--sx-heading-fg,var(--sx-fg,var(--sf-heading,inherit)));font-family:var(--sx-heading-font,var(--font-display));font-weight:var(--sx-heading-weight,inherit);font-size:var(--sx-heading-size,var(--step-3))}
#services h3{color:var(--sx-heading-fg,var(--sx-fg,var(--sf-heading,inherit)));font-family:var(--sx-heading-font,var(--font-display));font-weight:var(--sx-heading-weight,inherit);font-size:var(--sx-heading-size,var(--step-1))}
#services p,#services li,#services span,#services b,#services em,#services small{color:var(--sx-body-fg,var(--sx-fg,inherit));font-family:var(--sx-body-font,var(--font-body));font-size:var(--sx-body-size,inherit);font-weight:var(--sx-body-weight,inherit)}
#services .eyebrow,#services .text-link{color:var(--sx-accent,var(--accent))}

#contact{background:var(--ch-bg,inherit);color:var(--ch-fg,inherit)}
#contact h1{color:var(--ch-heading-fg,var(--ch-fg,var(--sf-heading,inherit)));font-family:var(--ch-heading-font,var(--font-display));font-weight:var(--ch-heading-weight,inherit);font-size:var(--ch-heading-size,var(--step-4))}
#contact h2{color:var(--ch-heading-fg,var(--ch-fg,var(--sf-heading,inherit)));font-family:var(--ch-heading-font,var(--font-display));font-weight:var(--ch-heading-weight,inherit);font-size:var(--ch-heading-size,var(--step-3))}
#contact h3{color:var(--ch-heading-fg,var(--ch-fg,var(--sf-heading,inherit)));font-family:var(--ch-heading-font,var(--font-display));font-weight:var(--ch-heading-weight,inherit);font-size:var(--ch-heading-size,var(--step-1))}
#contact p,#contact li,#contact span,#contact b,#contact em,#contact small{color:var(--ch-body-fg,var(--ch-fg,inherit));font-family:var(--ch-body-font,var(--font-body));font-size:var(--ch-body-size,inherit);font-weight:var(--ch-body-weight,inherit)}
#contact .eyebrow,#contact .text-link{color:var(--ch-accent,var(--accent))}


/* ================================================================================================
   v45 — THE ENQUIRY FORM FOLLOWS ITS AREA.
   ================================================================================================
   Kirk: "Not a fan of the window for the get in touch page being a white box with black insets and
   i have no idea how to change this."

   He could not change it because nothing pointed at it. The panel was hard-wired to `--white` and
   the fields to `--paper`/`--ink`, and v37 deliberately kept form fields out of the per-area rules
   — the reasoning was that inputs carry their own colours for legibility. That was right for a
   BLANKET rule and wrong as a final answer: it left one visible block on his site with no control
   at all. Named explicitly, they follow the Get in touch area's own Background and Text.
   ================================================================================================ */
.contact-layout .contact-form{background:var(--ct-panel,var(--ct-bg,var(--white)));border-color:var(--ct-accent,var(--line))}
.contact-layout .contact-form label{color:var(--ct-fg,var(--ink-soft))}
.contact-layout .contact-form input,
.contact-layout .contact-form select,
.contact-layout .contact-form textarea{
  color:var(--ct-fg,var(--ink));
  /* v45 — DERIVED FROM THE AREA, so one control makes the whole block coherent. A field has to sit
     APART from the panel behind it or the form disappears into a flat rectangle, so it is the
     area's background nudged a little toward its text colour. Falling back to `--paper` would have
     left exactly the black insets he objected to, since the panel changes and the field does not. */
  background:var(--ct-field,color-mix(in srgb, var(--ct-bg,var(--paper)) 92%, var(--ct-fg,var(--ink)) 8%));
  border-color:var(--ct-accent,var(--line));
}
.contact-layout .contact-form input::placeholder,
.contact-layout .contact-form textarea::placeholder{color:var(--ct-fg,var(--ink-soft));opacity:.55}
.contact-layout .contact-form input:focus,
.contact-layout .contact-form select:focus,
.contact-layout .contact-form textarea:focus{border-color:var(--ct-accent,var(--accent))}
/* The same block on the HOME page, which is a different area with its own controls. */
#contact .contact-form{background:var(--ch-panel,var(--ch-bg,var(--white)));border-color:var(--ch-accent,var(--line))}
#contact .contact-form label{color:var(--ch-fg,var(--ink-soft))}
#contact .contact-form input,#contact .contact-form select,#contact .contact-form textarea{
  color:var(--ch-fg,var(--ink));
  background:var(--ch-field,color-mix(in srgb, var(--ch-bg,var(--paper)) 92%, var(--ch-fg,var(--ink)) 8%));
  border-color:var(--ch-accent,var(--line));
}

/* ================================================================================================
   v46 — THE WHITE HAZE OVER THE PHOTOGRAPHS.
   ================================================================================================
   Kirk: "is there a reason all of the links look like they have a white haze over them? ... The
   photos in the film strips and the 2 in the camera for hire and the galleries."

   Yes, and it was deliberate and wrong. `.svc-tile img` and `.split-card img` were set to 66% and
   72% OPACITY over the tile's own background, to dim the picture so the white label on top stayed
   readable. On a dark backdrop that reads as a moody fade; on his theme it reads as a wash of the
   page colour across every photograph — a haze.

   IT WAS ALSO REDUNDANT. Both labels ALREADY carry their own gradient scrim, dark at the bottom
   and transparent at the top, which is what makes the text readable — so the photograph was being
   faded a second time for a problem that was already solved. A photographer's tiles should show
   the photograph.

   `--tile-photo` keeps it adjustable rather than merely reversed: someone who wants the moody
   version sets it back. Hover lifts to full, as it always did in spirit.
   ================================================================================================ */
.svc-tile img{opacity:var(--tile-photo,1)}
.split-card img{opacity:var(--tile-photo,1)}
.svc-tile:hover img,.split-card:hover img{opacity:1}
/* The scrim does the work now, so it is strengthened slightly where the label sits — the text has
   to survive a bright sky under it, which was the reason for the dimming in the first place. */
.svc-label{background:linear-gradient(transparent 35%,rgba(20,23,26,.55) 62%,rgba(20,23,26,.88))}
.split-card span{background:linear-gradient(transparent,rgba(20,23,26,.6) 45%,rgba(20,23,26,.9))}

/* ================================================================================================
   v47 — LOUPE PAGE SECTIONS
   Long-form bands under a tool. Alternating background so the page reads as sections,
   and an optional dark band for the logo lockup that ships with a light mark.
   ================================================================================================ */
.tool-band{padding:clamp(2.5rem,6vw,5rem) var(--gutter);border-top:1px solid var(--line)}
.tool-band.alt{background:var(--paper-2)}
.tool-band.on-dark{background:var(--ink);color:var(--paper);border-top-color:rgba(255,255,255,.1)}
.tool-band.on-dark h2,.tool-band.on-dark h3{color:var(--paper)}
.tool-band.on-dark p,.tool-band.on-dark li{color:color-mix(in srgb,var(--paper) 82%,transparent)}
.tool-band.on-dark .lead{color:color-mix(in srgb,var(--paper) 92%,transparent)}
.tool-band-inner{max-width:52rem;margin:0 auto}
.tool-band h2{font-size:clamp(1.5rem,2.8vw,2.2rem);line-height:1.15;margin:0 0 1rem}
.tool-band h3{font-size:var(--step-1);margin:1.8rem 0 .5rem}
.tool-band p{color:var(--ink-soft);margin:0 0 1rem}
.tool-band .lead{font-size:var(--step-1);color:var(--ink)}
.tool-band ul,.tool-band ol{color:var(--ink-soft);padding-left:1.2rem;margin:0 0 1.2rem}
.tool-band li{margin-bottom:.45rem}
.tool-band .eyebrow{margin-bottom:.8rem}

/* a defined term — the four things Loupe measures */
.tool-term{margin:0 0 1.1rem}
.tool-term b{color:var(--ink);font-weight:600}
.tool-band.on-dark .tool-term b{color:var(--paper)}

.tool-aside{font-size:var(--step--1);border-left:2px solid var(--accent);padding-left:.9rem;
  margin:1.4rem 0 0}

.tool-logo{margin-bottom:1.6rem}
.tool-logo img{height:clamp(46px,7vw,72px);width:auto;display:block}

.tool-cols{display:grid;grid-template-columns:1fr 1fr;gap:clamp(1.5rem,4vw,3rem);margin-top:.5rem}
.tool-cols h3{margin-top:0}
@media (max-width:760px){.tool-cols{grid-template-columns:1fr}}

/* ================================================================================================
   v48 — MAILING LIST SIGNUP
   One field, one button. The consent sentence is plain text under the field, because on a signup
   box pressing the button IS the consent — a tick box there is one nobody reads.
   ================================================================================================ */
.signup{max-width:38rem}
.signup h3{font-size:var(--step-1);margin:0 0 .5rem}
.signup p{color:var(--ink-soft);margin:0 0 1rem}
.signup-row{display:flex;gap:.6rem;flex-wrap:wrap}
.signup-email{
  flex:1 1 16rem;min-width:0;padding:.8rem .9rem;border:1px solid var(--line);
  font:inherit;font-size:1rem;background:var(--paper);color:var(--ink);border-radius:var(--radius)
}
.signup-email:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 3px rgba(47,93,98,.14)}
.signup-go{white-space:nowrap}
/* the honeypot: off-screen rather than display:none, which some bots skip */
.signup-hp{position:absolute;left:-9999px;width:1px;height:1px;opacity:0;pointer-events:none}
.signup-consent{font-size:var(--step--1);color:var(--ink-soft);margin:.8rem 0 0!important;max-width:34rem}
.signup-said{font-size:.92rem;margin:.7rem 0 0!important}
.signup-said.bad{color:#a2564f}
.signup.done h3{color:var(--accent)}
.tool-band.on-dark .signup-email{background:rgba(255,255,255,.06);color:var(--paper);border-color:rgba(255,255,255,.25)}
.tool-band.on-dark .signup-consent{color:color-mix(in srgb,var(--paper) 70%,transparent)}

/* ================================================================================================
   v50 — TYPE HIERARCHY RESTORED INSIDE THE PER-AREA RULES

   The area rules use ID selectors, which beat every element and class rule in the stylesheet.
   Where they set a font-size with `inherit` as the fallback, an unset area variable made the
   element take its PARENT's size — so every heading collapsed to body text. (`unset` is no better:
   font-size is an inherited property, so unset IS inherit. `revert` goes to the browser's 16px.)
   The heading rules above are now split per element with each element's own base size as the
   fallback. These are the remaining cases, where the element's size is not simply h1/h2/h3.
   ================================================================================================ */

/* The package name is the biggest thing on the card, and the price sits under it at a clearly
   smaller but still prominent size. Both were being flattened to paragraph size. */
#servicePage .pk-body h3,
.pk-body h3{
  font-size:var(--sv-package-size,clamp(1.9rem,3.6vw,2.9rem));
  font-weight:600;line-height:1.05;letter-spacing:-.01em
}
#servicePage .pk-price,
.pk-price{
  font-family:var(--sv-heading-font,var(--font-display));
  font-size:var(--sv-price-size,clamp(1.15rem,2vw,1.6rem));
  font-weight:500;line-height:1.2
}

/* .lead is a deliberate step above body text — the area body rule was flattening it. */
#servicePage .lead,#galleriesPage .lead,#galleryPage .lead,#storePage .lead,
#productPage .lead,#contact .lead,#homeHero .lead,.tool-band .lead{
  font-size:var(--lead-size,var(--step-1))
}

/* The hero tagline sits between the heading and body text rather than at body size. */
#homeHero #tagline{font-size:var(--he-tagline-size,clamp(1.05rem,1.6vw,1.35rem));line-height:1.5}

/* Section headings on a service page keep their own scale rather than collapsing. */
#servicePage .s-block h2,#servicePage .section-heading h2{
  font-size:var(--sv-heading-size,clamp(1.5rem,2.8vw,2.2rem))
}

/* ================================================================================================
   v59 — THE TILE SHAPE NOW CHANGES THE HEIGHT. IT NEVER DID.
   ================================================================================================
   Kirk: "I changed the size of the west coast gallery to whole picture, and it made the image on
   the website wider, but not taller at all... all of the images look similar."

   HE IS RIGHT, AND THE WHOLE v55 MECHANISM WAS DEAD ON ARRIVAL. v55 set `--hub-shape` on the card
   and expected `.hub-img{aspect-ratio:var(--hub-shape,16/13.3)}` to read it — but v38's
   `.hub-img{aspect-ratio:auto;height:100%}`, written to fit four collections on one screen, sits
   LATER in this file at the SAME specificity and wins every time. So the variable was set in four
   places and read by one declaration that could never apply. On top of that, v38 pins every row at
   `grid-template-rows:var(--hub-row)`, so the row height is the same whatever shape is chosen.

   The only thing v55 changed was `grid-template-columns` on two of the shapes, which is exactly
   what he saw: wider, never taller.

   THE HEIGHT IS A MULTIPLE OF THE ROW, because the row is what v38 made authoritative. Fighting
   that with an aspect-ratio would put the two mechanisms back in the same argument they have been
   having since v55. v59 made that number `--hub-mult`, a multiple of the vh-based row; v62 replaced it
   with an aspect-ratio per shape, because a height in vh changes shape with the window while the panel
   draws a fixed one, and the two could only ever agree at one window size.

       short     1      the sliver, as before          <- most of a wide photograph across
       standard  1.3    Kirk: "30% taller than short"
       tall      3      a portrait crop, image column narrowed to .8fr so the box is near-square
       whole     auto   the entire photograph, nothing cropped, either orientation

   FOUR SHAPES, NOT FIVE. `full` is retired: it was a square crop nobody named, it sat between tall
   and whole looking like both, and the service heroes — which these were meant to match — have four.
   `tileShape()` in site.js folds a stored `full` onto `tall`, so a collection already set that way
   keeps a cropped tile rather than silently becoming an uncropped one.

   WHAT A TALLER BOX COSTS, stated because the names invite the opposite assumption: `object-fit:
   cover` keeps the shorter dimension and crops the other, so for a photograph WIDER than its box a
   taller card shows LESS across, not more. Only `whole` shows the whole photograph.
   ================================================================================================ */
/* ================================================================================================
   v62 — THE TILE IS THE SHAPE STUDIOFLOW SHOWS HIM, AT ANY WINDOW WIDTH.
   ================================================================================================
   Kirk: "The tile images look way better but they are not the same size as they show in studioflow,
   this should be corrected for accuracy! I prefer the image size in studioflow."

   v59 made the height a multiple of `--hub-row`, which is in VH — so the tile's proportions changed
   with the height of his window while the panel drew a fixed shape. The two could only agree on one
   window size, and they were never going to agree on his. THE PANEL IS THE PART HE DECIDES WITH, so
   the page follows it: the height comes from the picture's own WIDTH through an aspect-ratio, which
   holds the same shape at every width.

   These three ratios are the panel's own arithmetic written out — the image column's share of the
   card against the row height it used to compute, at 16:9 — and h323 compares the two every build, so
   they cannot drift apart again.

   WHAT THIS COSTS: v38 pinned the rows in vh to fit four collections on one screen. At an ordinary
   desktop width `standard` lands within a few pixels of where it did, but on a very wide window the
   tiles are taller than before. That is the trade for the shape being the one he chose. */
.hub-card{grid-template-rows:auto}
.hub-card[data-shape="short"] .hub-img{aspect-ratio:8/1.53;height:auto}
.hub-card[data-shape="standard"] .hub-img{aspect-ratio:8/1.989;height:auto}
/* The image column narrows as well, or "tall" is a tall band with a lot of empty page beside it
   rather than a taller picture — and the panel's preview is derived from this same .8fr share. */
.hub-card[data-shape="tall"]{grid-template-columns:.8fr 1.2fr}
.hub-card[data-shape="tall"] .hub-img{aspect-ratio:6.4/4.59;height:auto}

/* THE PICTURE SETS THE HEIGHT HERE, so the row is `auto` and the image is not stretched to it.
   `height:auto` is the half v55 left out: its `aspect-ratio:auto` won, but `height:100%` from v38
   did not lose, so the picture was drawn at its natural height inside a 190px box and clipped. */
.hub-card[data-shape="whole"]{grid-template-rows:auto;grid-template-columns:1.15fr 1fr}
.hub-card[data-shape="whole"] .hub-img{height:auto;aspect-ratio:auto;align-self:start}
.hub-card[data-shape="whole"] .hub-img img{height:auto;object-fit:contain}

/* A tall tile beside a short line of text leaves the words stranded halfway down a long column. */
.hub-card[data-shape="tall"] .hub-body,
.hub-card[data-shape="whole"] .hub-body{justify-content:flex-start;padding-top:clamp(2rem,5vw,4rem)}

/* ON A PHONE the card is already one column and vertical room is the scarce thing, so the taller
   shapes step back. `whole` keeps its full picture, which is the entire point of it. */
@media (max-width:820px){
  .hub-card,
  .hub-card[data-shape="tall"],
  .hub-card[data-shape="whole"]{grid-template-columns:1fr}
  /* One column on a phone, so the picture is the full width — the desktop ratio would make `tall`
     nearly a screen on its own. */
  .hub-card[data-shape="tall"] .hub-img{aspect-ratio:4/3}
  .hub-card[data-shape="short"] .hub-img{aspect-ratio:16/6}
  .hub-card[data-shape="standard"] .hub-img{aspect-ratio:16/8}
  .hub-card[data-shape="tall"] .hub-body,
  .hub-card[data-shape="whole"] .hub-body{padding-top:clamp(1.4rem,4vw,2rem)}
}

/* ================================================================================================
   v56 — THE CLOSING BAND as its own area (prefix cb).
   It used to render bare inside #servicePage and inherit --sv-bg, so recolouring it meant
   recolouring the whole wedding page. The same id/class marks it on the home and contact pages,
   so one setting covers all three — it reads the same on each, and setting it three times would
   be three chances to disagree.
   ================================================================================================ */
#closingBand,.closing-band{background:var(--cb-bg,var(--ink));color:var(--cb-fg,var(--paper))}
#closingBand h1,#closingBand h2,#closingBand h3,
.closing-band h1,.closing-band h2,.closing-band h3{
  color:var(--cb-heading-fg,var(--cb-fg,var(--sf-heading,inherit)));
  font-family:var(--cb-heading-font,var(--font-display));
  font-size:var(--cb-heading-size,var(--step-3));
  font-weight:var(--cb-heading-weight,inherit)
}
#closingBand p,#closingBand li,.closing-band p,.closing-band li{
  color:var(--cb-body-fg,var(--cb-fg,inherit));
  font-family:var(--cb-body-font,var(--font-body));
  font-size:var(--cb-body-size,inherit);
  font-weight:var(--cb-body-weight,inherit)
}
#closingBand .eyebrow,.closing-band .eyebrow{color:var(--cb-accent,var(--accent))}
/* THE ID IS DELIBERATELY ABSENT. `#closingBand .button` is specificity 101 and beats
   `.button:hover` at 10, so the resting colour wins and the button never responds —
   the g262 fault, which reached Kirk's site once already.

   Dropping the ID is necessary but NOT sufficient: `.closing-band .button` is (0,2,0)
   and `.button:hover` is also (0,2,0), a tie that source order decides, and this rule
   sits ~1400 lines later. So the hover twin below is required, not optional.

   RULE FOR ANY FUTURE AREA: a resting override needs a hover twin in the same context,
   at the same specificity. */
.closing-band .button{
  background:var(--cb-btn-bg,var(--btn-bg,var(--paper)));
  color:var(--cb-btn-fg,var(--btn-fg,var(--ink)));
  border-color:var(--cb-btn-bg,var(--btn-bg,var(--paper)))
}
.closing-band .button:hover{
  background:var(--cb-btn-hover-bg,var(--btn-hover-bg,var(--accent)));
  color:var(--cb-btn-hover-fg,var(--btn-hover-fg,var(--btn-fg,var(--paper))));
  border-color:var(--cb-btn-hover-bg,var(--btn-hover-bg,var(--accent)))
}

/* ================================================================================================
   v64 — SUPPORTING THUMBNAILS under a feature block, and the rate card.

   Both extend blocks that already existed rather than adding new types: `feature` has drawn a
   picture beside words since v11, and `pricelist` has drawn label/price rows just as long. Adding
   `productfeature` and `ratecard` beside them would have meant two ways to do one thing and two
   sets of field names to keep in step.
   ================================================================================================ */

/* --- feature: the small strip below the large picture --- */
.fs-thumbs{
  grid-column:1/-1;display:grid;gap:clamp(.5rem,1vw,.9rem);margin-top:clamp(1rem,2.5vw,1.8rem);
  grid-template-columns:repeat(auto-fit,minmax(110px,1fr))
}
.fs-thumb{display:block;line-height:0;overflow:hidden;background:var(--paper-2)}
.fs-thumb img{width:100%;aspect-ratio:1;object-fit:cover;transition:transform .5s ease,opacity .3s}
.fs-thumb:hover img{transform:scale(1.04);opacity:.92}

/* --- pricelist / rate card --- */
.pl-sub{
  font-size:var(--step-1);margin:clamp(2rem,4vw,3rem) 0 .8rem;
  color:var(--sv-heading-fg,var(--sv-fg,var(--sf-heading,inherit)));font-family:var(--sv-heading-font,var(--font-display))
}
.pl-row{
  display:flex;align-items:baseline;gap:1rem;justify-content:space-between;
  padding:.85rem 0;border-bottom:1px solid var(--line)
}
.pl-row:last-child{border-bottom:none}
.pl-what{display:flex;flex-direction:column;gap:.15rem;min-width:0}
.pl-name{font-weight:500;color:var(--sv-heading-fg,var(--sv-fg,var(--sf-heading,inherit)))}
/* The description sits under the name at a smaller size — a second column would
   squeeze the price, and on a phone it would push it onto its own line. */
.pl-note{font-size:var(--step--1);color:var(--sv-body-fg,var(--sv-fg,var(--ink-soft)))}
.pl-price{
  white-space:nowrap;font-family:var(--font-display);font-size:var(--step-1);
  color:var(--sv-accent,var(--accent))
}
.pl-addons .pl-price{font-size:var(--step-0)}
.pl-foot{font-size:var(--step--1);color:var(--sv-body-fg,var(--sv-fg,var(--ink-soft)));margin-top:1.2rem}

/* ON A PHONE the name and price stay on ONE line — the price is what the row is for, and a price
   that wraps away from its name belongs to nothing. Only the description drops below. */
@media (max-width:600px){
  .pl-row{gap:.7rem}
  .pl-price{font-size:var(--step-0)}
  .fs-thumbs{grid-template-columns:repeat(3,1fr)}
}

/* ================================================================================================
   v65 — THE ROOM FORM.  v66 adds its per-area rules (prefix rm): registering the area in AREAS is
   only half of it — without these, every setting on its card in StudioFlow would apply a variable
   nothing reads and say nothing about it. Heading/body split and the fg fallback as elsewhere.
   ================================================================================================ */
#roomPage,.room-page{background:var(--rm-bg,inherit);color:var(--rm-fg,inherit)}
#roomPage h1,.room-page h1{color:var(--rm-heading-fg,var(--rm-fg,var(--sf-heading,inherit)));
  font-family:var(--rm-heading-font,var(--font-display));
  font-size:var(--rm-heading-size,var(--step-4));font-weight:var(--rm-heading-weight,inherit)}
#roomPage h2,.room-page h2{color:var(--rm-heading-fg,var(--rm-fg,var(--sf-heading,inherit)));
  font-family:var(--rm-heading-font,var(--font-display));
  font-size:var(--rm-heading-size,var(--step-3));font-weight:var(--rm-heading-weight,inherit)}
#roomPage h3,.room-page h3{color:var(--rm-heading-fg,var(--rm-fg,var(--sf-heading,inherit)));
  font-family:var(--rm-heading-font,var(--font-display));
  font-size:var(--rm-heading-size,var(--step-1));font-weight:var(--rm-heading-weight,inherit)}
#roomPage p,#roomPage li,.room-page p,.room-page li{color:var(--rm-body-fg,var(--rm-fg,inherit));
  font-family:var(--rm-body-font,var(--font-body));font-size:var(--rm-body-size,inherit);
  font-weight:var(--rm-body-weight,inherit)}
#roomPage .eyebrow,#roomPage .text-link,.room-page .eyebrow,.room-page .text-link{
  color:var(--rm-accent,var(--accent))}
/* the panel and the fields follow the area too, so a dark room page is readable */
#roomPage .room-how,.room-page .room-how{background:var(--rm-panel,var(--paper-2))}
#roomPage .rf-field input,#roomPage .rf-field select,#roomPage .rf-field textarea,
.room-page .rf-field input,.room-page .rf-field select,.room-page .rf-field textarea{
  background:var(--rm-field,var(--paper));color:var(--rm-fg,var(--ink))}

.room-page{padding-bottom:clamp(3rem,7vw,6rem)}
.room-grid{display:grid;grid-template-columns:1.15fr 1fr;gap:clamp(2rem,5vw,4.5rem);
  padding:0 var(--gutter);align-items:start;max-width:78rem;margin:0 auto}

.room-form{display:flex;flex-direction:column;gap:1rem}
.rf-field{display:block;font-size:var(--step--1);letter-spacing:.05em;text-transform:uppercase;
  color:var(--ink-soft)}
.rf-label{display:block}
.rf-req{text-transform:none;letter-spacing:0;color:var(--accent);font-size:.92em}
.rf-field input[type=text],.rf-field input[type=email],.rf-field select,.rf-field textarea{
  display:block;width:100%;margin-top:.35rem;padding:.7rem .8rem;border:1px solid var(--line);
  font:inherit;font-size:1rem;text-transform:none;letter-spacing:0;background:var(--paper);
  color:var(--ink);border-radius:var(--radius)
}
.rf-field textarea{resize:vertical}
.rf-field input:focus,.rf-field select:focus,.rf-field textarea:focus{
  outline:none;border-color:var(--accent);box-shadow:0 0 0 3px rgba(47,93,98,.14)}
.rf-two{display:grid;grid-template-columns:1fr 1fr;gap:1rem}

/* the piece it came from */
.rf-piece{display:flex;gap:1rem;align-items:center;background:var(--paper-2);
  border:1px solid var(--line);padding:.8rem;border-radius:var(--radius)}
.rf-piece img{width:82px;height:82px;object-fit:cover;flex:none;border-radius:2px}
.rf-piece-name{font-family:var(--font-display);font-size:var(--step-1);margin:.1rem 0 0}

/* the photo */
.rf-drop{border:2px dashed var(--line);border-radius:var(--radius);padding:1.8rem 1rem;
  text-align:center;cursor:pointer;color:var(--ink-soft);text-transform:none;letter-spacing:0;
  margin-top:.35rem;transition:.2s}
.rf-drop:hover,.rf-drop.over{border-color:var(--accent);background:var(--paper-2);color:var(--ink)}
.rf-chosen{font-size:var(--step--1);color:var(--accent);text-transform:none;letter-spacing:0;
  margin:.5rem 0 0}
.rf-hp{position:absolute;left:-9999px;width:1px;height:1px;opacity:0;pointer-events:none}

/* the tick — a real checkbox, off by default, on any form he FILLS IN */
.rf-check{display:flex;gap:.6rem;align-items:flex-start;font-size:var(--step--1);
  color:var(--ink-soft);text-transform:none;letter-spacing:0;margin:.4rem 0}
.rf-check input{margin-top:.25rem;flex:none}

/* v80 — the contact page's own add-ons list, reading the same rows the service page already
   shows. Off by default, so a customer has to actually choose one; nothing here charges anything,
   it only ends up as a line in the message Kirk reads. */
.contact-addons{margin:1.4rem 0;padding:1rem 1.2rem;background:var(--paper-2);border-radius:var(--radius,0)}
.contact-addons-label{font-size:var(--step--1);letter-spacing:.1em;text-transform:uppercase;
  color:var(--ink-soft);margin:0 0 .6rem}
.contact-addon-row{display:flex;align-items:center;gap:.7rem;padding:.5rem 0;
  border-top:1px solid var(--line);cursor:pointer}
.contact-addon-row:first-child{border-top:none}
.contact-addon-row input{flex:none}
.contact-addon-row span{flex:1;font-size:.94rem}
.contact-addon-row span small{display:block;color:var(--ink-soft);font-size:var(--step--1)}
.contact-addon-row b{font-weight:600;white-space:nowrap}

.rf-said{font-size:.94rem;margin:.6rem 0 0}
.rf-said.bad{color:#a2564f}
.rf-done{text-align:center;padding:clamp(2rem,5vw,4rem) 0}
.rf-done h2{color:var(--accent);margin-bottom:.6rem}

/* how to take the photograph */
.room-how{background:var(--paper-2);padding:clamp(1.4rem,3vw,2.2rem);border-radius:var(--radius);
  position:sticky;top:calc(var(--header-h,72px) + 1rem)}
.room-how h2{font-size:var(--step-1);margin-bottom:.5rem}
.room-how > p{color:var(--ink-soft);font-size:.95rem}
.rf-example{margin:1rem 0 1.2rem}
.rf-example img{width:100%;border-radius:2px;display:block}
.rf-example span{display:block;font-size:var(--step--1);color:var(--ink-soft);margin-top:.4rem}
.room-steps{padding-left:1.1rem;margin:0 0 1rem;color:var(--ink-soft);font-size:.95rem}
.room-steps li{margin-bottom:.7rem}
.room-steps b{color:var(--ink)}
.room-why{font-size:var(--step--1);color:var(--ink-soft);border-left:2px solid var(--accent);
  padding-left:.9rem;margin:0}

.art-room-ask{margin:.6rem 0 1.2rem;font-size:var(--step--1)}
.galleries-signup{padding-top:0}
.gallery-signup{padding-top:0}
/* v110 - the compact signup under Latest News: heading and line on the left, email box and button on the right */
.news-signup{margin-top:clamp(1.2rem,3vw,2rem)}
.signup.compact{max-width:none;display:grid;grid-template-columns:minmax(0,1fr) auto;gap:.15rem 1.6rem;align-items:center;
  padding-top:1.1rem;border-top:1px solid var(--line,rgba(0,0,0,.12))}
.signup.compact h3{margin:0;grid-column:1}
.signup.compact p{margin:0;grid-column:1}
.signup.compact .signup-row{grid-column:2;grid-row:1 / span 2;flex-wrap:nowrap}
.signup.compact .signup-email{min-width:15rem}
.signup.compact .signup-consent,.signup.compact .signup-said{grid-column:1 / -1}
@media (max-width:760px){
  .signup.compact{grid-template-columns:1fr}
  .signup.compact .signup-row{grid-column:1;grid-row:auto;flex-wrap:wrap;margin-top:.7rem}
  .signup.compact .signup-email{min-width:0;flex:1 1 12rem}
}

@media (max-width:900px){
  .room-grid{grid-template-columns:1fr}
  /* The instructions go ABOVE the form on a phone — they are what makes the
     photograph usable, and nobody scrolls back up to read them afterwards. */
  .room-how{position:static;order:-1}
}
@media (max-width:560px){
  .rf-two{grid-template-columns:1fr}
}

/* ================================================================================================
   v73 — THE PARTS OF A PAGE, EACH WITH ITS OWN COLOURS.
   ================================================================================================
   Kirk, of the room page: "The instruction text in that panel is currently pale blue on light grey
   and close to unreadable." Of the free tools page: "right now the page has one background plus an
   alternate for the bands, so a colour that suits one part fights another."

   ONE FAULT, TWO PAGES. Each page had ONE set of area variables and more than one surface to put
   text on, so a single `--rm-body-fg` had to serve both a form sitting on the page background and a
   panel sitting on `--rm-panel`. There is no colour that is right on both, and nothing on the card
   said which one it would suit.

   FIVE NEW PREFIXES, EACH FALLING BACK TO ITS PAGE. `--rh-*` falls to `--rm-*`, `--tb-*` falls to
   `--tl-*`, and so on — so every one of these rules resolves today to exactly what it resolved to
   before, and the page only changes when he sets something.

   TWO THINGS THESE RULES HAVE TO GET RIGHT, both learned here the hard way:

   SPECIFICITY. `#roomPage p` is one id and one element; so is `#roomForm p`. Equal weight means the
   LATER rule wins, which is why this block sits at the END of the stylesheet and not beside the
   rules it refines. Where the existing rule carries a class as well — `#roomPage .room-how`,
   `#toolsPage .tool-band.alt` — an id alone would LOSE, so those are written with both ids.

   FONT-SIZE FALLBACKS ARE NEVER `inherit`. font-size is an inherited property, so `inherit` (and
   `unset`, which resolves to it) means "take my parent's size" — which is body text, and flattens
   every heading silently. Each fallback here is the element's own step.
   ================================================================================================ */

/* ---- the room page: the form, and the panel of instructions beside it ------------------------- */
#roomForm{background:var(--rf-bg,transparent);color:var(--rf-fg,var(--rm-fg,inherit))}
#roomForm.has-area-bg{padding:clamp(1.2rem,2.5vw,2rem);border-radius:var(--radius)}
#roomPage #roomForm h2,.room-page #roomForm h2{
  color:var(--rf-heading-fg,var(--rf-fg,var(--rm-heading-fg,var(--rm-fg,var(--sf-heading,inherit)))));
  font-family:var(--rf-heading-font,var(--rm-heading-font,var(--font-display)));
  font-size:var(--rf-heading-size,var(--rm-heading-size,var(--step-3)));
  font-weight:var(--rf-heading-weight,var(--rm-heading-weight,inherit))}
#roomPage #roomForm h3,.room-page #roomForm h3{
  color:var(--rf-heading-fg,var(--rf-fg,var(--rm-heading-fg,var(--rm-fg,var(--sf-heading,inherit)))));
  font-family:var(--rf-heading-font,var(--rm-heading-font,var(--font-display)));
  font-size:var(--rf-heading-size,var(--rm-heading-size,var(--step-1)));
  font-weight:var(--rf-heading-weight,var(--rm-heading-weight,inherit))}
/* THE FIELD LABELS ARE THIS PANEL'S HEADINGS. "Your name", "Email", "Which piece" are what a person
   reads to work out what to type, and until now they took `--ink-soft` directly and followed nothing
   at all — so on a dark form they stayed dark. The export card says plainly that "Heading colour" on
   this card means these. */
#roomPage #roomForm .rf-field,#roomPage #roomForm .rf-label,#roomPage #roomForm .rf-check,
.room-page #roomForm .rf-field,.room-page #roomForm .rf-label,.room-page #roomForm .rf-check{
  color:var(--rf-heading-fg,var(--rf-fg,var(--rm-heading-fg,var(--rm-fg,var(--ink-soft)))));
  font-family:var(--rf-heading-font,var(--rm-heading-font,inherit));
  font-weight:var(--rf-heading-weight,var(--rm-heading-weight,inherit))}
#roomPage #roomForm p,#roomPage #roomForm li,.room-page #roomForm p,.room-page #roomForm li{
  color:var(--rf-body-fg,var(--rf-fg,var(--rm-body-fg,var(--rm-fg,inherit))));
  font-family:var(--rf-body-font,var(--rm-body-font,var(--font-body)));
  font-size:var(--rf-body-size,var(--rm-body-size,inherit));
  font-weight:var(--rf-body-weight,var(--rm-body-weight,inherit))}
#roomPage #roomForm .eyebrow,#roomPage #roomForm .rf-req,#roomPage #roomForm .rf-chosen,
.room-page #roomForm .eyebrow,.room-page #roomForm .rf-req,.room-page #roomForm .rf-chosen{
  color:var(--rf-accent,var(--rm-accent,var(--accent)))}
#roomPage #roomForm .rf-drop,.room-page #roomForm .rf-drop{
  color:var(--rf-body-fg,var(--rf-fg,var(--rm-body-fg,var(--rm-fg,var(--ink-soft)))))}

/* The instructions panel. Two ids, because `#roomPage .room-how` already sets its background and an
   id alone would not beat an id plus a class. */
#roomPage #roomHow,.room-page #roomHow{
  background:var(--rh-bg,var(--rm-panel,var(--paper-2)));
  color:var(--rh-fg,var(--rm-fg,inherit))}
#roomPage #roomHow h2,.room-page #roomHow h2{
  color:var(--rh-heading-fg,var(--rh-fg,var(--rm-heading-fg,var(--rm-fg,var(--sf-heading,inherit)))));
  font-family:var(--rh-heading-font,var(--rm-heading-font,var(--font-display)));
  font-size:var(--rh-heading-size,var(--rm-heading-size,var(--step-1)));
  font-weight:var(--rh-heading-weight,var(--rm-heading-weight,inherit))}
#roomPage #roomHow h3,.room-page #roomHow h3{
  color:var(--rh-heading-fg,var(--rh-fg,var(--rm-heading-fg,var(--rm-fg,var(--sf-heading,inherit)))));
  font-family:var(--rh-heading-font,var(--rm-heading-font,var(--font-display)));
  font-size:var(--rh-heading-size,var(--rm-heading-size,var(--step-1)));
  font-weight:var(--rh-heading-weight,var(--rm-heading-weight,inherit))}
#roomPage #roomHow p,#roomPage #roomHow li,.room-page #roomHow p,.room-page #roomHow li{
  color:var(--rh-body-fg,var(--rh-fg,var(--rm-body-fg,var(--rm-fg,inherit))));
  font-family:var(--rh-body-font,var(--rm-body-font,var(--font-body)));
  font-size:var(--rh-body-size,var(--rm-body-size,inherit));
  font-weight:var(--rh-body-weight,var(--rm-body-weight,inherit))}
/* THE BOLD LEAD-IN OF EACH STEP. `.room-steps b{color:var(--ink)}` targets the `b` itself, so no
   rule aimed at the `li` around it can reach it — a dark panel would have kept black lead-ins with
   readable text under them. This is the half of the fault that a colour setting alone never fixed. */
#roomPage #roomHow .room-steps b,.room-page #roomHow .room-steps b{
  color:var(--rh-heading-fg,var(--rh-fg,var(--rm-heading-fg,var(--rm-fg,var(--ink)))))}
#roomPage #roomHow .rf-example span,.room-page #roomHow .rf-example span{
  color:var(--rh-body-fg,var(--rh-fg,var(--ink-soft)))}
#roomPage #roomHow .room-why,.room-page #roomHow .room-why{
  border-left-color:var(--rh-accent,var(--rm-accent,var(--accent)))}
#roomPage #roomHow .eyebrow,#roomPage #roomHow .text-link,
.room-page #roomHow .eyebrow,.room-page #roomHow .text-link{
  color:var(--rh-accent,var(--rm-accent,var(--accent)))}

/* ---- the free tools page: the intro, the tool blocks, the signup box -------------------------- */
#toolsPage #toolsHead{background:var(--ti-bg,transparent);color:var(--ti-fg,var(--tl-fg,inherit))}
#toolsPage #toolsHead.has-area-bg{padding-top:clamp(1.4rem,3vw,2.4rem);
  padding-bottom:clamp(1.4rem,3vw,2.4rem);border-radius:var(--radius)}
#toolsPage #toolsHead h1{color:var(--ti-heading-fg,var(--ti-fg,var(--tl-heading-fg,var(--tl-fg,var(--sf-heading,inherit)))));
  font-family:var(--ti-heading-font,var(--tl-heading-font,var(--font-display)));
  font-size:var(--ti-heading-size,var(--tl-heading-size,var(--step-4)));
  font-weight:var(--ti-heading-weight,var(--tl-heading-weight,inherit))}
#toolsPage #toolsHead h2{color:var(--ti-heading-fg,var(--ti-fg,var(--tl-heading-fg,var(--tl-fg,var(--sf-heading,inherit)))));
  font-family:var(--ti-heading-font,var(--tl-heading-font,var(--font-display)));
  font-size:var(--ti-heading-size,var(--tl-heading-size,var(--step-3)));
  font-weight:var(--ti-heading-weight,var(--tl-heading-weight,inherit))}
#toolsPage #toolsHead p{color:var(--ti-body-fg,var(--ti-fg,var(--tl-body-fg,var(--tl-fg,inherit))));
  font-family:var(--ti-body-font,var(--tl-body-font,var(--font-body)));
  font-size:var(--ti-body-size,var(--tl-body-size,inherit));
  font-weight:var(--ti-body-weight,var(--tl-body-weight,inherit))}
#toolsPage #toolsHead .eyebrow{color:var(--ti-accent,var(--tl-accent,var(--accent)))}

/* The tool blocks. TWO backgrounds, because the page genuinely alternates: the first block takes
   `--tb-bg`, every second one `--tb-bg-alt`. Both fall through to what the page did before, so an
   untouched card leaves the alternation exactly as it ships. */
#toolsPage #toolsList{color:var(--tb-fg,var(--tl-fg,inherit))}
#toolsPage #toolsList .tool{background:var(--tb-bg,transparent)}
#toolsPage #toolsList .tool:nth-child(even),#toolsPage #toolsList .tool-band.alt{
  background:var(--tb-bg-alt,var(--tl-bg-alt,var(--paper-2)))}
#toolsPage #toolsList h2{color:var(--tb-heading-fg,var(--tb-fg,var(--tl-heading-fg,var(--tl-fg,var(--sf-heading,inherit)))));
  font-family:var(--tb-heading-font,var(--tl-heading-font,var(--font-display)));
  font-size:var(--tb-heading-size,var(--tl-heading-size,var(--step-3)));
  font-weight:var(--tb-heading-weight,var(--tl-heading-weight,inherit))}
#toolsPage #toolsList h3{color:var(--tb-heading-fg,var(--tb-fg,var(--tl-heading-fg,var(--tl-fg,var(--sf-heading,inherit)))));
  font-family:var(--tb-heading-font,var(--tl-heading-font,var(--font-display)));
  font-size:var(--tb-heading-size,var(--tl-heading-size,var(--step-1)));
  font-weight:var(--tb-heading-weight,var(--tl-heading-weight,inherit))}
#toolsPage #toolsList p,#toolsPage #toolsList li{
  color:var(--tb-body-fg,var(--tb-fg,var(--tl-body-fg,var(--tl-fg,inherit))));
  font-family:var(--tb-body-font,var(--tl-body-font,var(--font-body)));
  font-size:var(--tb-body-size,var(--tl-body-size,inherit));
  font-weight:var(--tb-body-weight,var(--tl-body-weight,inherit))}
#toolsPage #toolsList .eyebrow,#toolsPage #toolsList .tool-price,
#toolsPage #toolsList .dl-note,#toolsPage #toolsList .tool-support a{
  color:var(--tb-accent,var(--tl-accent,var(--accent)))}

/* The signup box. Two ids, because `#toolsPage .tool-band.alt` above is an id AND two classes and
   would otherwise keep painting it. It defaults to the alternate band colour, which is what it wears
   today. */
#toolsPage #toolsSignup{background:var(--ts-bg,var(--tb-bg-alt,var(--tl-bg-alt,var(--paper-2))));
  color:var(--ts-fg,var(--tb-fg,var(--tl-fg,inherit)))}
#toolsPage #toolsSignup h2,#toolsPage #toolsSignup h3{
  color:var(--ts-heading-fg,var(--ts-fg,var(--tb-heading-fg,var(--tl-heading-fg,var(--tl-fg,var(--sf-heading,inherit))))));
  font-family:var(--ts-heading-font,var(--tl-heading-font,var(--font-display)));
  font-size:var(--ts-heading-size,var(--step-1));
  font-weight:var(--ts-heading-weight,var(--tl-heading-weight,inherit))}
#toolsPage #toolsSignup p,#toolsPage #toolsSignup li,#toolsPage #toolsSignup label{
  color:var(--ts-body-fg,var(--ts-fg,var(--tb-body-fg,var(--tl-body-fg,var(--tl-fg,inherit)))));
  font-family:var(--ts-body-font,var(--tl-body-font,var(--font-body)));
  font-size:var(--ts-body-size,var(--tl-body-size,inherit));
  font-weight:var(--ts-body-weight,var(--tl-body-weight,inherit))}
#toolsPage #toolsSignup .eyebrow,#toolsPage #toolsSignup .text-link{
  color:var(--ts-accent,var(--tb-accent,var(--tl-accent,var(--accent))))}

/* ================================================================================================
   v74 - TWO PARTS OF THE FREE TOOLS PAGE THAT NO SETTING COULD REACH.
   ================================================================================================
   Kirk: "I am still trying to change the section on the free tools page that shows the loupe logo on
   the white background ... i changed the one i thought it was in the tool blocks like you said and it
   didnt change."

   HE WAS RIGHT AND THE CARD WAS WRONG, in two separate places.

   (1) THE LOGO MOUNT. `.tool-shot{background:var(--ink)}` is a deliberate dark mount for a screenshot,
   and it is the ONLY background on that page no area variable has ever touched. On a dark theme `ink`
   and `paper` swap, so the mount turns WHITE and a pale logo disappears into it - which is exactly
   what he is looking at. No amount of changing the tool blocks background was ever going to move it.

   (2) THE PLAIN BANDS. v73's rule covered `.tool` and `.tool-band.alt` and NOT a `.tool-band` with
   neither class, which is most of the writing on that page. So the card promised "each tool and each
   band of writing below it" and delivered about half of that. A control that covers less than its own
   label says is worse than no control, because the failure looks like the page rather than the panel.

   `.on-dark` IS RESTORED IMMEDIATELY BELOW. Two ids beat its two classes, so the plain-band rule would
   otherwise have silently un-darkened a band whose whole purpose is to be dark. Every fallback here is
   what the element used before, so an untouched page is pixel-identical. */
#toolsPage #toolsList .tool-band{background:var(--tb-bg,transparent)}
#toolsPage #toolsList .tool-band.alt{background:var(--tb-bg-alt,var(--tl-bg-alt,var(--paper-2)))}
#toolsPage #toolsList .tool-band.on-dark{background:var(--tb-bg-dark,var(--ink))}
#toolsPage #toolsList .tool-shot{background:var(--tb-shot-bg,var(--ink))}

/* ==================================================================================================
   v81 — THE LARGER VIEW ("Own this print"). One overlay for the page, built by site.js on first
   click. Dark surround so the photograph is the only light thing on screen; the caption and the
   one button sit under it in the site's own type and button colours (the pill and its theme keys
   are inherited from .button). Nothing here is themed separately, so a Theme card change reaches
   this the same moment it reaches the rest of the site.
   ================================================================================================== */
.lb{position:fixed;inset:0;z-index:1000;background:rgba(10,12,14,.94);color:var(--paper);
  display:flex;align-items:center;justify-content:center;padding:clamp(12px,3vw,40px);
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}
.lb[hidden]{display:none}
body.lb-open{overflow:hidden}
.lb-fig{margin:0;display:flex;flex-direction:column;align-items:center;gap:1rem;max-width:min(1400px,96vw);max-height:100%;width:100%}
.lb-img{display:flex;align-items:center;justify-content:center;width:100%;min-height:0;flex:1 1 auto}
.lb-img img{max-width:100%;max-height:calc(100vh - 180px);width:auto;height:auto;object-fit:contain;
  box-shadow:0 30px 80px rgba(0,0,0,.6);background:#000;user-select:none}
.lb-cap{display:flex;align-items:center;justify-content:space-between;gap:1.5rem;width:100%;max-width:1100px;flex:0 0 auto}
.lb-text{min-width:0}
/* v82 — the collection's colour, and lettering that does not depend on the page's theme.
   `--paper` is themeable (applyTheme maps theme.paper onto it), so a site with a warm or deep
   paper painted this heading in it against a near-black overlay. These three are fixed. */
.lb-cap .eyebrow{color:var(--lb-eyebrow,rgba(250,249,247,.65));display:inline-flex;align-items:center;gap:.5rem}
.lb-cap .eyebrow::before{content:"";width:.62em;height:.62em;border-radius:999px;flex:0 0 auto;
  background:var(--lb-accent,transparent)}
.lb-cap .eyebrow:empty::before{display:none}
.lb-title{font-size:var(--step-2);margin:.15rem 0 .2rem;color:#f3f2ef}
.lb-edition{margin:0;color:rgba(250,249,247,.78);font-size:var(--step--1)}
.lb-edition[hidden]{display:none}
.lb-own{flex:0 0 auto;white-space:nowrap}
.lb-close,.lb-prev,.lb-next{position:absolute;background:transparent;border:0;color:rgba(250,249,247,.85);
  font-size:2.6rem;line-height:1;width:56px;height:56px;cursor:pointer;border-radius:999px;
  display:flex;align-items:center;justify-content:center;transition:background .2s,color .2s}
.lb-close:hover,.lb-prev:hover,.lb-next:hover{background:rgba(250,249,247,.12);color:#fff}
.lb-close{top:12px;right:12px;font-size:2.2rem}
.lb-prev{left:8px;top:50%;transform:translateY(-50%)}
.lb-next{right:8px;top:50%;transform:translateY(-50%)}
.lb-prev[hidden],.lb-next[hidden]{display:none}
.lb-close:focus-visible,.lb-prev:focus-visible,.lb-next:focus-visible,.lb-own:focus-visible{outline:2px solid var(--paper);outline-offset:2px}
@media(max-width:700px){
  .lb{padding:8px}
  .lb-img img{max-height:calc(100vh - 210px)}
  .lb-cap{flex-direction:column;align-items:stretch;text-align:center;gap:.8rem}
  .lb-cap .eyebrow{justify-content:center}   /* v82 — the dot travels with the centred name */
  .lb-own{width:100%;text-align:center}
  .lb-prev,.lb-next{width:44px;height:44px;font-size:2rem;background:rgba(0,0,0,.35)}
}

/* ============================================================
   v88 — REAL ESTATE BOOKING PAGE
   Package and add-on cards with a banded header (its own colour and
   font, one setting for the whole set) over a body that takes no
   background of its own and simply shows the page behind it, per
   Kirk's own description of the look he wanted.
   ============================================================ */
/* Generic page-level colouring — the same shape every other page area gets
   (#storePage etc): background, heading and body text, fonts and sizes, all
   optional and falling back to the site's own defaults when unset. Without
   this the "booking" entry in AREAS would write variables nothing on the
   page ever reads — exactly the orphan fault this template checks for on
   every version. The CARD system below (--bk-card-*) is separate and layers
   on top of this, since a card's banded header is not the same idea as the
   page's own heading colour. */
#bookingPage{background:var(--bk-bg,inherit);color:var(--bk-fg,inherit)}
#bookingPage h1{color:var(--bk-heading-fg,var(--bk-fg,var(--sf-heading,inherit)));font-family:var(--bk-heading-font,var(--font-display));
  font-weight:var(--bk-heading-weight,inherit);font-size:var(--bk-heading-size,var(--step-3))}
#bookingPage h2{color:var(--bk-heading-fg,var(--bk-fg,var(--sf-heading,inherit)));font-family:var(--bk-heading-font,var(--font-display));
  font-weight:var(--bk-heading-weight,inherit);font-size:var(--bk-heading-size,var(--step-1))}
/* NOT "label" — the form fields keep their own look (.bk-form label below), the same reason
   .contact-layout's equivalent rule reads "p,li" and not "p,li,label". A generic rule here would
   outrank .bk-form label on specificity (ID beats class) and silently take the muted uppercase
   field labels back to plain body text — the exact cascade shape this template checks for. */
#bookingPage p,#bookingPage li{color:var(--bk-body-fg,var(--bk-fg,inherit));font-family:var(--bk-body-font,var(--font-body));
  font-size:var(--bk-body-size,inherit);font-weight:var(--bk-body-weight,inherit)}
#bookingPage .eyebrow{color:var(--bk-accent,var(--accent))}

.bk-empty{max-width:34rem;padding:2rem var(--gutter) 4rem;display:grid;gap:1rem}
.bk-form{max-width:74rem;margin:0 auto;padding:0 var(--gutter) 4.5rem;display:grid;gap:2.5rem}
.bk-section h2{font-size:var(--step-1);margin-bottom:1rem}
.bk-cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(15rem,1fr));gap:1.1rem}

.bk-card{
  position:relative;display:block;border:1px solid var(--line);border-radius:var(--radius,0);
  overflow:hidden;cursor:pointer;background:var(--bk-bg,transparent);
  transition:border-color .15s,box-shadow .15s
}
.bk-card input{position:absolute;opacity:0;pointer-events:none}
.bk-card.on{border-color:var(--accent);box-shadow:0 0 0 2px var(--accent) inset}
.bk-card-head{
  display:block;padding:1rem 1.1rem .9rem;
  background:var(--bk-card-bg,var(--paper-2));
  color:var(--bk-card-head-fg,var(--ink));
  font-family:var(--bk-card-font,inherit)
}
.bk-card-name{display:block;font-family:var(--font-display);font-size:var(--step-0);font-weight:600}
.bk-card-sub{display:block;margin-top:.25rem;font-size:var(--step--1);
  color:var(--bk-card-sub-fg,var(--bk-card-head-fg,var(--ink-soft)));opacity:.85}
.bk-card-body{display:block;padding:1.1rem}
.bk-card-price{display:block;font-family:var(--font-display);font-size:var(--step-1);color:var(--accent)}
.bk-card-list{margin:.7rem 0 0;padding-left:1.1rem;color:var(--ink-soft);font-size:var(--step--1)}
.bk-card-list li{margin-bottom:.3rem}
.bk-qty{display:inline-flex;align-items:center;gap:.6rem;margin-top:.8rem}
.bk-qty button{width:1.9rem;height:1.9rem;border:1px solid var(--line);background:var(--paper);
  border-radius:999px;font:inherit;cursor:pointer;line-height:1}
.bk-qty button:hover{border-color:var(--accent)}
.bk-qty-n{min-width:1.4rem;text-align:center;font-variant-numeric:tabular-nums}

.bk-summary{border:1px solid var(--line);border-radius:var(--radius,0);padding:1.1rem 1.3rem;
  background:var(--paper-2);display:grid;gap:.4rem}
.bk-summary .line{display:flex;justify-content:space-between;gap:1rem;font-size:var(--step--1);color:var(--ink-soft)}
.bk-summary-total,.bk-summary-deposit{display:flex;justify-content:space-between;gap:1rem;
  border-top:1px solid var(--line);padding-top:.6rem;margin-top:.3rem}
.bk-summary-deposit{font-family:var(--font-display);font-size:var(--step-0);color:var(--accent)}

.bk-form label{display:block;margin-bottom:1rem;font-size:var(--step--1);letter-spacing:.06em;
  text-transform:uppercase;color:var(--ink-soft)}
.bk-form label small{text-transform:none;letter-spacing:0;opacity:.7}
.bk-form input,.bk-form textarea{
  display:block;width:100%;margin-top:.4rem;padding:.7rem .8rem;border:1px solid var(--line);
  font:inherit;font-size:1rem;color:var(--ink);background:var(--paper);border-radius:var(--radius);
  text-transform:none;letter-spacing:0
}
.bk-form input:focus,.bk-form textarea:focus{
  outline:none;border-color:var(--accent);box-shadow:0 0 0 3px rgba(47,93,98,.12)}
.bk-form textarea{resize:vertical}

.bk-terms{border:1px solid var(--line);border-radius:var(--radius,0);padding:1rem 1.2rem;
  background:var(--paper-2);font-size:var(--step--1);color:var(--ink-soft)}
.bk-said{margin-top:.8rem;font-size:var(--step--1)}
.bk-said.bad{color:#a2564f}

@media (max-width:640px){.bk-cards{grid-template-columns:1fr}}

/* v89 — the "N room views" line on a store card is now a button that opens the larger view. It must
   look exactly as the line did. The line was a <p>, and `#storePage p` (an ID rule) beat the class
   rule's accent colour, so what people actually saw was the page's body colour, font and size —
   a button is not a <p>, so that rule no longer reaches it and the same values are restated here. */
button.card-rooms{display:block;background:none;border:0;padding:0;margin:.15rem 0 0;font:inherit;
  font-size:var(--step--1);color:inherit;text-align:left;cursor:pointer;text-decoration:none}
#storePage button.card-rooms{color:var(--sr-body-fg,var(--sr-fg,inherit));font-family:var(--sr-body-font,var(--font-body));
  font-size:var(--sr-body-size,inherit);font-weight:var(--sr-body-weight,inherit)}
button.card-rooms:hover,button.card-rooms:focus-visible{text-decoration:underline;text-underline-offset:3px}
button.card-rooms:focus-visible{outline:2px solid currentColor;outline-offset:3px}

/* v90 — "SEE IT IN A ROOM" and "BACK TO GALLERY" in the larger view.
   The overlay is its own dark surface, so these use fixed light colours rather than the theme's
   outline-button colours (--btn-bg / --ink), which are dark on a light site and would vanish here —
   the same fault the lightbox title had in v82. The buy button keeps the Theme card's colours. */
.lb-actions{display:flex;gap:.7rem;flex:0 0 auto;flex-wrap:wrap;justify-content:flex-end;align-items:center}
.lb-room,.lb-back{font:inherit;font-size:var(--step--1);letter-spacing:.08em;text-transform:uppercase;cursor:pointer;
  color:#f3f2ef;background:rgba(10,12,14,.35);border:1px solid rgba(250,249,247,.7);border-radius:var(--btn-radius,999px);
  min-height:44px;padding:.7rem 1.4rem;transition:background .2s,border-color .2s,color .2s}
.lb-room:hover,.lb-back:hover{background:rgba(250,249,247,.16);border-color:#fff;color:#fff}
.lb-room:focus-visible,.lb-back:focus-visible{outline:2px solid #fff;outline-offset:2px}
.lb-room[hidden]{display:none}
.lb-room[aria-pressed="true"]{background:rgba(250,249,247,.14);border-color:#fff}
.lb-back{position:absolute;top:12px;left:12px;padding:.55rem 1.1rem;z-index:2}
.lb-roomcap{margin:0 0 .2rem;color:rgba(250,249,247,.82);font-size:var(--step--1)}
.lb-roomcap[hidden]{display:none}
@media (max-width:720px){
  .lb-actions{flex-direction:column;align-items:stretch;width:100%}
  .lb-room,.lb-own{width:100%;min-height:48px;text-align:center}
  .lb-back{top:8px;left:8px}
  .lb-close{top:4px;right:4px}
}

/* ============================================================
   v91 — SITE DESIGNER SUPPORT (site-design.json and the live preview)
   ============================================================ */
/* Held invisible only while a site-design.json is being applied, so there is no flash of the default
   wording or colours. A failsafe in site.js lifts it after two seconds whatever happens. */
html.sf-pending body{visibility:hidden}
/* A section the designer has hidden. In the app's preview (?sfdesign=1) it stays visible but faded,
   so it can still be clicked and brought back. */
html:not(.sf-design) [data-sf-hidden]{display:none!important}
html.sf-design [data-sf-hidden]{opacity:.35;filter:grayscale(1);outline:2px dashed rgba(120,120,120,.8);outline-offset:-2px}
/* Preview only: what can be clicked. Nothing here exists on the live site. */
html.sf-design [data-sf-key],html.sf-design [data-sf-slot],html.sf-design [data-sf-section]{cursor:pointer}
html.sf-design [data-sf-key]:hover{outline:2px solid #3b82f6;outline-offset:2px}
html.sf-design [data-sf-slot]:hover{outline:3px solid #10b981;outline-offset:-3px}
html.sf-design [data-sf-section]:hover{box-shadow:inset 0 0 0 2px rgba(139,92,246,.7)}
html.sf-design [data-sf-selected]{outline:2px solid #f59e0b!important;outline-offset:2px}
html.sf-design [data-sf-slot].sf-drop{outline:3px dashed #10b981;outline-offset:-3px;background-color:rgba(16,185,129,.12)}

/* ============================================================
   v94 — ARRANGE PIECES INSIDE A SECTION ON A 12-COLUMN GRID (Site Designer stage 2)
   ============================================================
   Only a section that site-design.json gives a `layout` for gets data-sf-layout, and only then does
   any of this apply — with no layout data the four sections look exactly as they did in v93.
   Nothing is placed at pixel positions: a block sits in whole columns of a 12-column grid, and on a
   phone (700px and under) the blocks stack in a single column in a chosen order. */
[data-sf-grid][data-sf-layout]{grid-template-columns:repeat(12,minmax(0,1fr));column-gap:0;align-items:stretch}
#splitCards[data-sf-layout]{column-gap:1px}
[data-sf-grid][data-sf-layout]>[data-sf-block]{min-width:0}
/* the hero's picture normally fills the hero from behind; as a block it is a grid item that can be
   narrower. Text and picture share the first row, so the words still sit over the picture. */
[data-sf-grid][data-sf-layout]>img[data-sf-block]{position:relative;inset:auto;width:100%;height:100%;min-height:0}
[data-sf-grid][data-sf-layout]>.hero-content{max-width:none}
@media (max-width:700px){
  [data-sf-grid][data-sf-layout]{grid-template-columns:minmax(0,1fr)}
  [data-sf-grid][data-sf-layout]>[data-sf-block]{grid-column:1 / -1!important;grid-row:auto!important}
  /* a phone cannot put words beside a picture, but the hero's words must stay over its picture */
  [data-sf-grid="home.hero"][data-sf-layout]>[data-sf-block]{grid-row:1!important;order:0!important}
  [data-sf-grid][data-sf-layout] .about-image img{max-height:70vh;width:auto;margin:0 auto}
}

/* ---- the designer's guides: only ever drawn with ?sfdesign=1 ---- */
#sfGuides{position:fixed;inset:0;z-index:2147483000;pointer-events:none}
#sfGuides .sf-col{position:fixed;background:rgba(59,130,246,.10);border-left:1px solid rgba(59,130,246,.35);border-right:1px solid rgba(59,130,246,.35)}
#sfGuides .sf-ghost{position:fixed;border:2px dashed #f59e0b;background:rgba(245,158,11,.14);box-sizing:border-box}
#sfGuides .sf-line{position:fixed;height:3px;background:#f59e0b}
#sfGuides .sf-h{position:fixed;pointer-events:auto;background:#f59e0b;border:2px solid #fff;box-shadow:0 1px 4px rgba(0,0,0,.4);box-sizing:border-box;touch-action:none}
#sfGuides .sf-h.move{width:30px;height:30px;border-radius:6px;cursor:grab}
#sfGuides .sf-h.move::before{content:"\2725";display:block;text-align:center;line-height:26px;font:600 15px/26px system-ui;color:#fff}
#sfGuides .sf-h.l,#sfGuides .sf-h.r{width:12px;height:44px;border-radius:6px;cursor:ew-resize}

/* ============================================================
   v95 — "ON THE WALL AT <HOTEL>" (art.html, hotel label scans)
   ============================================================
   A small, calm wall label: paper, a hairline, the hotel's name in capitals. Uses only theme colours, so
   it follows a dark theme. The same card is built twice: .wall-top above the picture (a phone, where
   nearly every scan happens) and .wall-in at the head of the product column on wider screens. */
.wall-card{border:1px solid var(--line);border-left:3px solid var(--accent);background:var(--paper);color:var(--ink);
  padding:.85rem 1.1rem .9rem;margin:0 0 1.4rem;max-width:34rem}
.wall-card[hidden]{display:none!important}
.wall-card p{margin:0}
/* `.wall-card .x` outranks `.product-layout p`, which would otherwise restyle these on the wider layout */
.wall-card .wall-kicker{font-family:var(--font-body);font-size:.72rem;letter-spacing:.16em;text-transform:uppercase;color:var(--ink-soft)}
.wall-card .wall-kicker .wall-venue{color:var(--ink);font-weight:600;letter-spacing:.14em}
.wall-card .wall-title{font-family:var(--font-display);font-size:1.3rem;line-height:1.25;margin-top:.35rem;color:var(--ink)}
.wall-card .wall-title b{font-weight:500}
.wall-card .wall-spec{font-family:var(--font-body);font-size:.92rem;margin-top:.2rem;color:var(--ink)}
.wall-card .wall-note{font-family:var(--font-body);font-size:.84rem;line-height:1.45;margin-top:.55rem;color:var(--ink-soft)}
.wall-top{display:none}
@media (max-width:900px){
  .wall-in{display:none!important}
  .wall-top{display:block;margin:1rem var(--gutter) 0;max-width:none}
}

/* ============================================================
   v96 — NEW EDITIONS (new.html, the "New" tag, linkable news cards)
   ============================================================ */
/* v97: the tag has its own colour (--sf-new-tag, set by the Theme card / Site Designer "New" tag colour); red by default. */
:root{--new-tag:var(--sf-new-tag,#d0021b)}
.new-tag{display:inline-block;background:var(--new-tag);color:#fff;font-size:.7rem;font-weight:700;letter-spacing:.14em;
  text-transform:uppercase;padding:.3rem .6rem;line-height:1;box-shadow:0 1px 3px rgba(0,0,0,.35)}
.work-img,.art-card .frame{position:relative}
.work-img .new-tag,.art-card .frame .new-tag{position:absolute;top:.7rem;left:.7rem;z-index:2}
.new-tag-row{margin:0 0 .6rem}
.new-meta{display:flex;flex-wrap:wrap;gap:.2rem .7rem;font-size:var(--step--1);letter-spacing:.04em;margin-top:.4rem}
.new-meta span:not(.new-coll){color:var(--ink-soft)}
.new-coll{color:var(--accent);border-bottom:1px solid var(--accent);cursor:pointer}
.new-coll:hover,.new-coll:focus-visible{color:var(--ink);border-bottom-color:var(--ink)}
.new-empty{text-align:center;max-width:36rem;margin:0 auto}
.new-empty[hidden],#newWorks[hidden]{display:none}
.hub-new{margin:0;padding:.9rem var(--gutter);border-bottom:1px solid var(--line);text-align:center}
/* a news card with a link: the title is the anchor and its ::after stretches over the whole card */
.news-card.has-link{position:relative}
.news-card .news-link{color:inherit;text-decoration:none}
.news-card .news-link::after{content:"";position:absolute;inset:0;z-index:1}
.news-card.has-link:hover h3 .news-link,.news-card .news-link:focus-visible{text-decoration:underline;text-underline-offset:.2em}
.news-card .news-link:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.news-card.has-link{cursor:pointer}
#newPage .new-works{padding-top:clamp(1rem,3vw,2rem)}
.new-meta{justify-content:center}

/* ============================================================
   v98 — ROOM FORM PIECE PICKER, ROOM LINK ON A PIECE, FRAMED NEWS PICTURE
   ============================================================ */
.rf-pick{position:relative}
.rf-pick-btn{display:flex;align-items:center;gap:.8rem;width:100%;margin-top:.35rem;padding:.45rem .8rem;min-height:3.2rem;
  text-align:left;font:inherit;font-size:1rem;text-transform:none;letter-spacing:0;cursor:pointer;
  background:var(--rm-field,var(--paper));color:var(--rm-fg,var(--ink));border:1px solid var(--line);border-radius:var(--radius)}
.rf-pick-btn:focus-visible,.rf-pick-filter:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 3px rgba(47,93,98,.14)}
.rf-pick-btn img,.rf-pick-opt img{width:44px;height:44px;object-fit:cover;flex:none;border-radius:2px;background:var(--paper-2)}
.rf-pick-t{display:flex;flex-direction:column;min-width:0;flex:1}
.rf-pick-t b{font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rf-pick-t small{font-size:.78rem;opacity:.7;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rf-pick-none{flex:1}
.rf-pick-caret{margin-left:auto;opacity:.6}
.rf-pick-panel{position:absolute;left:0;right:0;top:100%;z-index:30;margin-top:.25rem;
  background:var(--rm-field,var(--paper));color:var(--rm-fg,var(--ink));border:1px solid var(--line);
  border-radius:var(--radius);box-shadow:0 10px 30px rgba(0,0,0,.18);text-transform:none;letter-spacing:0}
.rf-pick-panel[hidden]{display:none}
.rf-pick-filter{display:block;width:calc(100% - 1rem);margin:.5rem;padding:.55rem .7rem;font:inherit;font-size:1rem;
  border:1px solid var(--line);border-radius:var(--radius);background:inherit;color:inherit}
.rf-pick-filter[hidden]{display:none}
.rf-pick-list{list-style:none;margin:0;padding:.25rem 0;max-height:min(22rem,55vh);overflow-y:auto;outline:none}
.rf-pick-opt{display:flex;align-items:center;gap:.8rem;padding:.4rem .8rem;cursor:pointer;min-height:3rem}
.rf-pick-opt.is-active,.rf-pick-opt:hover{background:var(--paper-2)}
.rf-pick-opt[aria-selected="true"] .rf-pick-t b{color:var(--accent)}
.rf-pick-empty{margin:0;padding:.8rem 1rem;color:var(--ink-soft);font-size:.95rem}
.rf-pick-empty[hidden]{display:none}
.rf-pick[hidden]{display:none}

/* the room option on a piece: a clear, quiet call to action, not a footnote */
.art-room-ask{margin:.8rem 0 1.4rem}
.art-room-ask .text-link{display:block;padding:.75rem 1rem;border:1px solid var(--line);border-radius:var(--radius);
  text-decoration:none;font-size:var(--step--1);letter-spacing:.04em;line-height:1.35}
.art-room-ask .text-link:hover,.art-room-ask .text-link:focus-visible{border-color:var(--accent);background:var(--paper-2)}

/* News: the New Editions card is a framed window onto the newest piece, at its own shape */
.news-card.news-piece{grid-column:1/-1;display:grid;grid-template-columns:minmax(0,26rem) 1fr;align-items:center;
  gap:clamp(1rem,3vw,2.2rem);padding:clamp(1rem,2.5vw,1.6rem);max-width:60rem;
  /* v100: the box follows the Site Designer / Theme card (defaults are the old look) */
  background:var(--sf-newscard-bg,var(--white));border:var(--sf-newscard-border-w,1px) solid var(--sf-newscard-border,var(--line));
  border-radius:var(--sf-newscard-radius,0)}
.news-card.news-piece .news-frame{display:flex;align-items:center;justify-content:center;background:var(--sf-newsframe-bg,var(--paper-2));
  border:var(--sf-newsframe-border-w,1px) solid var(--sf-newsframe-border,var(--line));border-radius:var(--sf-newsframe-radius,0);
  padding:clamp(.6rem,1.6vw,1rem);min-height:10rem}
.news-card.news-piece .news-frame img{display:block;width:auto;height:auto;max-width:100%;max-height:min(26rem,60vh);
  aspect-ratio:auto;object-fit:contain}
.news-card.news-piece .news-body{padding:0}
@media (max-width:700px){
  .news-card.news-piece{grid-template-columns:1fr}
}
/* the "The piece" card is only for a form opened from a piece; its display:flex was overriding [hidden] and showed an empty card with a broken picture on the general form */
.rf-piece[hidden]{display:none}

/* ============================================================
   v99 — BOOKING FOR EVERY SERVICE
   ============================================================ */
.bk-card input.bk-qty-in{position:static;opacity:1;pointer-events:auto;display:inline-block;width:5rem;margin:0;padding:.4rem .5rem}
.bk-qty{align-items:center}
.bk-qty[hidden]{display:none}
.bk-qty-unit{font-size:var(--step--1);color:var(--ink-soft)}
.bk-hint{margin:0 0 1rem;color:var(--ink-soft);font-size:var(--step--1)}
.bk-request-note{margin:.7rem 0 0;font-size:var(--step--1);font-weight:600;color:var(--ink)}
.bk-request-note[hidden]{display:none}
.bk-done{max-width:34rem}
.bk-ref{color:var(--ink-soft);font-size:var(--step--1)}
.bk-section[hidden],#bkSend[hidden]{display:none}
.bk-services .bk-card-head{border-bottom:0}
/* the "booking isn't set up" notice is only for a catalogue with nothing to book; its display:grid was overriding [hidden] and showing it on a working page */
.bk-empty[hidden]{display:none}
/* the outlined button sits on a dark picture in a service hero */
.s-hero .button-ghost{color:#fff;border-color:rgba(255,255,255,.75);background:rgba(0,0,0,.18)}
.s-hero .button-ghost:hover{background:#fff;color:var(--ink)}

/* ============================================================
   v101 — SITE DESIGNER: every part of a linked News card can be picked
   ============================================================
   On the live site the heading's link stretches over the whole card (v96) so the card is one big link.
   In the designer preview that overlay swallowed every click, so only the heading could be chosen; there it is
   switched off. (The designer never navigates anyway: its click handler cancels links.) */
html.sf-design .news-card .news-link::after{display:none}
html.sf-design .news-card.has-link{cursor:pointer}
/* hovering the box itself (the padding round the picture and text) outlines the box, like any other section */
html.sf-design .news-card[data-sf-section]:hover{box-shadow:inset 0 0 0 2px rgba(139,92,246,.7)}
/* the image-protection shield makes every <img> click-through; in the preview a picture that carries its own slot must take the click */
html.sf-design img[data-sf-slot]{pointer-events:auto}

/* v102 — real estate priced by square footage */
.bk-form .bk-hint{display:block;margin:.35rem 0 0;font-size:.8rem;line-height:1.35;text-transform:none;letter-spacing:0;opacity:.8}
.bk-form .bk-hint[hidden]{display:none}
.bk-card-incl{font-family:var(--font-body);font-size:.7em;color:var(--ink-soft)}
.bk-recap{font-weight:600}
.bk-dates{margin:6px 0 10px 1.3em;padding:0;text-align:left}.bk-dates li{margin:2px 0}

/* v112 - a bundle's "Includes:" line on a digital product */
.dp-includes{margin:.4rem 0 .9rem;color:var(--ink-soft)}
.dp-includes b{color:inherit}
