/* ============================================================================
   Ipic Play Café: design system (shared by every page)
   ----------------------------------------------------------------------------
   Loads after scrollcraft.css. Tokens first, then the classes the supporting
   pages reuse. Landing-page act styles live in index.html, not here.

   TOKENS
     :root            the Café side: bisque ground, navy ink, maroon accent
     .side--play      the Play side: navy ground, bisque ink, rose accent
                      (redefines the six tokens AND restates color)
     --split/--paint/--fired/--sheen  written by the glaze-line JS

   TYPE
     .t-display / .t-lg / .t-md  Bricolage Grotesque display sizes (h1..h3)
     .t-lede                     larger Geist lead paragraph
     .t-body                     measure-limited Geist body (ink-soft)
     .t-small                    captions, small print
     .t-label                    the one uppercase eyebrow style (use sparingly)
     .t-nums                     tabular numerals (prices, hours)

   LAYOUT
     .wrap            centred max-width column with fluid gutters
     .section         fluid block padding
     .stack           vertical rhythm (more space above headings than below)
     .cols-2          two-column split at desktop, stacked on phones

   COMPONENTS
     .btn, .btn--primary, .btn--quiet, .btn--sm   buttons and link-buttons
     .price-list      dl of dish + price rows with hairlines
     .fact-list       address / hours / contact rows in the footer and Visit
     .plate           a photograph with hairline and elevation (tilt-safe)
     .caption         figcaption style
     .skip-link       visually hidden until focused

   CHROME
     .glaze-line      the fixed hand-painted divider (landing) or the fired
                      edge line (supporting pages, add .glaze-line--edge)
     .glaze-bar       the phone-only bottom balance bar
     .site-head       supporting-page static header: ring mark, text nav, CTA
     .foot            the facts footer (address, hours, contact, page links)
   ========================================================================== */

/* Self-hosted faces (the Google Fonts stylesheet was the page's longest
   render-blocking chain). Same variable woff2 files Google serves. */
@font-face { font-family: "Bricolage Grotesque"; font-style: normal; font-weight: 600 700; font-stretch: 100%; font-display: swap;
  src: url(/assets/bricolage-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: "Bricolage Grotesque"; font-style: normal; font-weight: 600 700; font-stretch: 100%; font-display: swap;
  src: url(/assets/bricolage-latin-ext.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: "Geist"; font-style: normal; font-weight: 400 600; font-display: swap;
  src: url(/assets/geist-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: "Geist"; font-style: normal; font-weight: 400 600; font-display: swap;
  src: url(/assets/geist-latin-ext.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }

/* ---------------------------------------------------------- state props --
   Registered so they animate, inherit and hold a sane value before the JS has
   run. No transition is ever declared on any of them. */
@property --sc-p  { syntax: "<number>"; inherits: true; initial-value: 0; }
@property --split { syntax: "<number>"; inherits: true; initial-value: 50; }
@property --paint { syntax: "<number>"; inherits: true; initial-value: 0; }
@property --fired { syntax: "<number>"; inherits: true; initial-value: 0; }
@property --sheen { syntax: "<number>"; inherits: true; initial-value: 0; }
@property --cap   { syntax: "<number>"; inherits: true; initial-value: 0; }
/* the two halves of the cap window: the chips and the CTA leave on --capA,
   the lockup arrives on --capB. They meet at --cap 0.35 and never overlap. */
@property --capA  { syntax: "<number>"; inherits: true; initial-value: 0; }
@property --capB  { syntax: "<number>"; inherits: true; initial-value: 0; }
@property --px    { syntax: "<number>"; inherits: true; initial-value: 0.5; }
@property --py    { syntax: "<number>"; inherits: true; initial-value: 0.5; }
@property --fire  { syntax: "<number>"; inherits: true; initial-value: 0; }
@property --rowp  { syntax: "<number>"; inherits: false; initial-value: 1; }
@property --pool  { syntax: "<number>"; inherits: false; initial-value: 0.5; }

:root {
  /* readable floors: 16px small print on a phone, 17px on a desktop, and a
     measure that counts CHARACTERS: 62ch of Geist is 86 characters a line,
     which is past the comfortable ceiling. 54ch lands at about 75. */
  --sc-measure: 54ch;
  --sc-t-sm: clamp(1rem, 0.94rem + 0.24vw, 1.0625rem);
  --sc-canvas: #EFE7DC; --sc-surface: #E3D8C8;
  --sc-ink: #203040;    --sc-ink-soft: #515C69;
  --sc-accent: #5A150E; --sc-accent-ink: #F7F0E7;
  --sc-font-display: "Bricolage Grotesque", "Archivo", system-ui, sans-serif;
  --sc-font-text: "Geist", system-ui, -apple-system, "Segoe UI", sans-serif;
  --sc-font-mono: "Geist", system-ui, sans-serif;
  --sc-shadow-color: 215 30% 12%;
  --sc-r-sm: 4px; --sc-r-md: 8px; --sc-r-lg: 14px;

  /* brand colours used by the glaze line itself, never as UI accents */
  --bisque: #EFE7DC; --navy: #1B2838; --rose: #CD9A8E; --maroon: #5A150E;

  /* the glaze-line state. JS writes these on :root every frame it changes. */
  --split: 50;   /* 0..62, the divider position in vw (desktop) or svh (phone) */
  --paint: 0;    /* 0..1 painted length = page progress */
  --fired: 0;    /* 0..1 rose -> maroon at the close */
  --sheen: 0;    /* 0..1 the one white band travelling down the stroke */
  --line-gap: clamp(1.25rem, 3vw, 2.75rem);   /* copy's distance from the line */
  --vhu: 1vh;
}
@supports (height: 1svh) { :root { --vhu: 1svh; } }

.side--play {
  --sc-canvas: #1B2838; --sc-surface: #243448;
  --sc-ink: #F1EAE0;    --sc-ink-soft: #B9C0CC;
  --sc-accent: #CD9A8E; --sc-accent-ink: #1B2838;
  color: var(--sc-ink);
  background: var(--sc-canvas);
  /* light-on-dark compensation: a touch more leading and tracking */
  line-height: calc(var(--sc-leading-body) + 0.05);
  letter-spacing: calc(var(--sc-track-normal) + 0.01em);
}
.side--play .t-body, .side--play .sc-body { font-weight: 500; }

/* The engine sets scroll-behavior: smooth on <html>. That also smooths the
   browser's own scroll-into-view when focus moves, which animates over the top
   of the repair a pinned act needs and lands a tab stop off screen. Focus wins;
   the two places that want a smooth jump (the ticks and the sheet's waypoints)
   ask for it in JavaScript instead. */
html { scroll-padding-top: 5rem; scroll-behavior: auto; }
body { background: var(--sc-canvas); color: var(--sc-ink); }

/* ------------------------------------------------------------------ type -- */
.t-display, .t-lg, .t-md {
  font-family: var(--sc-font-display);
  font-weight: 650;
  font-variation-settings: "opsz" 96;
  line-height: var(--sc-leading-none);
  letter-spacing: var(--sc-track-tight);
  text-wrap: balance;
  margin: 0;
}
.t-display { font-size: clamp(2.2rem, 1.3rem + 2.6vw, 4.4rem); }
.t-lg { font-size: clamp(1.9rem, 1.2rem + 2vw, 3.4rem); line-height: 1.02; }
.t-md { font-size: clamp(1.35rem, 1.05rem + 1vw, 2rem); line-height: 1.08; letter-spacing: var(--sc-track-snug); font-weight: 600; }
.side--play :is(.t-display, .t-lg, .t-md) { font-weight: 700; letter-spacing: calc(var(--sc-track-tight) + 0.01em); }
.t-lede { font-size: var(--sc-t-lg); line-height: 1.5; letter-spacing: var(--sc-track-snug); max-width: 40ch; text-wrap: pretty; margin: 0; }
.t-body { max-width: var(--sc-measure); color: var(--sc-ink-soft); text-wrap: pretty; margin: 0; }
.t-small { font-size: var(--sc-t-sm); color: var(--sc-ink-soft); line-height: 1.5; text-wrap: pretty; margin: 0; }
.t-label { font-size: var(--sc-t-xs); letter-spacing: var(--sc-track-wide); text-transform: uppercase; color: var(--sc-ink-soft); font-weight: 500; margin: 0; }
.t-nums { font-variant-numeric: tabular-nums; }
strong { font-weight: 600; }
a { color: inherit; text-decoration-thickness: 1px; text-underline-offset: 0.22em; transition: color var(--sc-d-fast) var(--sc-ease-out); }
a:hover { color: var(--sc-accent); }
.side--play a:hover { color: var(--sc-accent); }
p { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }
h1, h2, h3 { margin: 0; }

/* ---------------------------------------------------------------- layout -- */
.wrap { width: 100%; max-width: var(--sc-maxw); margin-inline: auto; padding-inline: var(--sc-gutter); }
.section { padding-block: var(--sc-section); }
.stack > * + * { margin-top: var(--sc-4); }
.stack > :is(h1, h2, h3) { margin-top: var(--sc-7); }
.stack > :is(h1, h2, h3):first-child { margin-top: 0; }
.stack > :is(h1, h2, h3) + * { margin-top: var(--sc-4); }
.stack > .btn-row { margin-top: var(--sc-6); }
.cols-2 { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--sc-8) var(--sc-7); align-items: start; }
@media (max-width: 860px) { .cols-2 { grid-template-columns: 1fr; gap: var(--sc-7); } }
.rule { height: 1px; border: 0; background: var(--sc-hairline-strong); margin: 0; }

/* --------------------------------------------------------------- buttons -- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.5em;
  min-height: 2.9rem; padding: 0.7em 1.35em;
  font-family: var(--sc-font-text); font-weight: 600; font-size: var(--sc-t-base);
  line-height: 1; letter-spacing: var(--sc-track-normal); white-space: nowrap;
  border-radius: var(--sc-r-md); border: 1px solid transparent; text-decoration: none;
  color: var(--sc-ink); background: transparent; cursor: pointer;
  transition: background-color var(--sc-d-fast) var(--sc-ease-out), color var(--sc-d-fast) var(--sc-ease-out),
              border-color var(--sc-d-fast) var(--sc-ease-out), transform 100ms var(--sc-ease-out), box-shadow var(--sc-d-fast) var(--sc-ease-out);
}
.btn:active { transform: translateY(1px); }
.btn:focus-visible { outline: 2px solid var(--sc-accent); outline-offset: 3px; }
.btn--primary:focus-visible { outline: 2px solid var(--sc-accent-ink); outline-offset: 0; box-shadow: 0 0 0 4px var(--sc-accent), var(--sc-e2); }
.btn--primary { background: var(--sc-accent); color: var(--sc-accent-ink); box-shadow: var(--sc-e1), var(--sc-edge); }
.btn--primary:hover { color: var(--sc-accent-ink); background: color-mix(in oklab, var(--sc-accent) 88%, var(--sc-ink)); box-shadow: var(--sc-e2); }
.side--play .btn--primary:hover { background: color-mix(in oklab, var(--sc-accent) 86%, white); }
.btn--quiet { border-color: var(--sc-hairline-strong); }
.btn--quiet:hover { border-color: var(--sc-ink); color: var(--sc-ink); }
.btn--sm { min-height: 44px; padding: 0.55em 1em; font-size: var(--sc-t-sm); }
.btn-row { display: flex; flex-wrap: wrap; gap: var(--sc-3) var(--sc-4); align-items: center; }
.link-arrow { font-weight: 600; text-decoration: none; border-bottom: 1px solid var(--sc-hairline-strong); padding-bottom: 0.1em; }
.link-arrow:hover { border-color: currentColor; }

/* ------------------------------------------------------------- price list -- */
.price-list { margin: 0; font-variant-numeric: tabular-nums; }
.price-list > div { display: grid; grid-template-columns: 1fr auto; gap: var(--sc-4); align-items: baseline; padding: 0.55em 0; border-top: 1px solid var(--sc-hairline); }
.price-list > div:first-child { border-top: 0; }
.price-list dt { margin: 0; font-weight: 500; }
.price-list dd { margin: 0; color: var(--sc-ink-soft); white-space: nowrap; }
.price-list .note { grid-column: 1 / -1; font-size: var(--sc-t-sm); color: var(--sc-ink-soft); }

/* -------------------------------------------------------------- fact list -- */
.fact-list { display: grid; gap: var(--sc-2) var(--sc-5); margin: 0; }
.fact-list div { display: grid; grid-template-columns: 7.5rem minmax(0, 1fr); gap: var(--sc-3); align-items: baseline; }
.fact-list dt { margin: 0; font-size: var(--sc-t-sm); color: var(--sc-ink-soft); }
.fact-list dd { margin: 0; }
@media (max-width: 480px) { .fact-list div { grid-template-columns: 1fr; gap: 0.15rem; } }

/* ----------------------------------------------------------------- plates -- */
.plate { position: relative; margin: 0; border-radius: var(--sc-r-lg); overflow: clip; box-shadow: var(--sc-e2), var(--sc-edge); background: var(--sc-surface); }
/* Every framed photograph carries a ~20px LQIP of itself as the frame's own
   background (inline data URI on the figure, ~200 bytes each), so a reveal or
   a lazy load can never land on an empty box. The hero does the same thing
   with .plane--poster; this is that pattern, applied to the flat frames.   */
.plate, .foot .foot-photo, .clipbox { background-size: cover; background-position: 50% 50%; background-repeat: no-repeat; }
.plate img { width: 100%; height: auto; display: block; }
.plate--tilt { transform-style: preserve-3d; }
.caption { margin-top: var(--sc-3); font-size: var(--sc-t-sm); color: var(--sc-ink-soft); text-wrap: pretty; max-width: var(--sc-measure); }
figure { margin: 0; }

/* -------------------------------------------------------------- skip link -- */
.skip-link { position: absolute; left: var(--sc-gutter); top: -4rem; z-index: 200; padding: 0.6em 1em; background: var(--sc-ink); color: var(--sc-canvas); border-radius: var(--sc-r-md); text-decoration: none; font-weight: 600; }
.skip-link:focus-visible { top: var(--sc-4); outline: 2px solid var(--sc-accent); outline-offset: 3px; }
.visually-hidden { position: absolute !important; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }

/* ============================================================ GLAZE LINE ==
   A fixed, full-height brushstroke. Three copies of one baked path stack:
   bisque base, rose paint (clipped by --paint from the top), maroon fired
   (opacity --fired). The sheen rect travels down once at the close.       */
.glaze-line {
  position: fixed; top: 0; left: 0; height: 100vh; height: 100dvh; width: 56px;
  z-index: var(--sc-z-chrome);
  transform: translateX(calc(var(--split) * 1vw - 28px));
  will-change: transform;
  touch-action: none;
  user-select: none; -webkit-user-select: none;
}
.glaze-line svg { position: absolute; inset: 0; width: 56px; height: 100%; overflow: visible; }
.gl-base { fill: var(--bisque); stroke: var(--navy); stroke-width: 0.9; stroke-opacity: 0.4; vector-effect: non-scaling-stroke; }
.gl-paint { fill: var(--rose); clip-path: inset(0 0 calc((1 - var(--paint)) * 100%) 0); }
.gl-fired { fill: var(--maroon); opacity: var(--fired); }
.gl-sheen { fill: url(#gl-sheen-grad); opacity: calc(var(--fired) * 0.9); transform: translateY(calc(-14% + var(--sheen) * 128%)); will-change: transform; }
[data-sc-cue]:focus-within { opacity: 1 !important; }
.glaze-line:focus-visible { outline: none; }
.glaze-line:focus-visible .gl-base { stroke: var(--maroon); stroke-opacity: 1; stroke-width: 2; }
@media (hover: hover) and (pointer: fine) {
  .glaze-line { cursor: col-resize; }
  .glaze-line.is-dragging { cursor: col-resize; }
}
/* the top cap: labels either side, the one CTA hung on the Café side */
.gl-cap { position: absolute; top: clamp(0.9rem, 2.2vh, 1.5rem); left: 28px; display: flex; align-items: center; gap: 0; white-space: nowrap; pointer-events: none; }
.gl-label { font-family: var(--sc-font-display); font-weight: 700; font-size: clamp(1.05rem, 0.9rem + 0.5vw, 1.35rem); letter-spacing: -0.02em; line-height: 1; padding: 0.45em 0.6em; border-radius: var(--sc-r-sm); }
.gl-label--play { position: absolute; right: calc(100% + 0.9rem); top: 0; color: var(--bisque); background: color-mix(in oklab, var(--navy) 84%, transparent); }
.gl-label--cafe { margin-left: 0.9rem; color: var(--navy); background: color-mix(in oklab, var(--bisque) 88%, transparent); }
/* the two word chips are labels, not the stroke: they take their own hover so
   the pointer does not promise a drag or a photograph over a word. */
.gl-label { pointer-events: auto; cursor: default; }
.gl-cta { pointer-events: auto; margin-left: 1rem; }
.gl-cap .sheet-btn { pointer-events: auto; margin-left: 0.55rem; padding: 0.5em 0.85em; }
.gl-tag { position: absolute; left: 52px; top: 5.5rem; writing-mode: vertical-rl;
  transform: translateY(calc((1 - var(--fired)) * -10px)) rotate(180deg);
  font-size: var(--sc-t-xs); letter-spacing: 0.08em; text-transform: uppercase; color: var(--sc-ink-soft);
  white-space: nowrap; opacity: var(--fired); pointer-events: none; }
.gl-lockup { position: absolute; left: calc(28px + var(--sc-gutter)); top: clamp(0.9rem, 2.2vh, 1.5rem);
  width: clamp(180px, 16vw, 260px); max-width: none; height: auto; pointer-events: none; }

/* ---- MORPH B: the split name closes -------------------------------------
   Not a crossfade. Three interpolable things move together on one window,
   --cap, written by the page rAF as remap(p6, 0.44, 0.66):
     1. the two chips travel toward each other along the cap
     2. the Play pill is EATEN from the left by a clip inset
     3. the lockup is revealed by the mirror wipe, growing out of the point
        where the two chips met
   --cap starts before --fired (0.48), so the name closes and THEN the line
   fires, in that order. No opacity crossfade anywhere in the three.        */
.glaze-line { --capA: clamp(0, calc(var(--cap) / 0.35), 1);
               --capB: clamp(0, calc((var(--cap) - 0.35) / 0.65), 1); }
/* both chips are eaten, mirrored, toward the point where they meet */
.gl-label--play { transform: translateX(calc(var(--capA) * 3.2rem));
  clip-path: inset(0 0 0 calc(var(--capA) * 100%) round var(--sc-r-sm)); }
.gl-label--cafe { transform: translateX(calc(var(--capA) * -1.1rem));
  clip-path: inset(0 calc(var(--capA) * 100%) 0 0 round var(--sc-r-sm)); }
/* the CTA slides down out of the cap on the same first half. The close's own
   primary CTA is on screen from p6 0.26, so the label is never absent. */
.gl-cap .gl-cta, .gl-cap .sheet-btn { transform: translateY(calc(var(--capA) * 3.6rem)); opacity: calc(1 - var(--capA)); }
/* the lockup only starts growing once the band it grows into is empty */
.gl-lockup { clip-path: inset(0 calc((1 - var(--capB)) * 100%) 0 0); }
/* opacity: 0 is still focusable AND still clickable. The class flips on the
   same value at which --capA reaches 1 and the opacity reaches 0, so an
   invisible control is never in the tab order and never takes a pointer. */
.glaze-line.is-capped :is(.gl-label, .gl-cta, .gl-cap .sheet-btn) { visibility: hidden; pointer-events: none; }
.glaze-line.is-capped .gl-cap .gl-cta { pointer-events: none; }
/* a control that has focus is never mid-morph: focus outranks the chrome */
.glaze-line :is(.gl-cta, .sheet-btn):focus { opacity: 1 !important; visibility: visible !important; transform: none !important; }
/* supporting pages: the argument is already resolved, the line sits fired at the edge */
.glaze-line--edge { --split: 0; --paint: 1; --fired: 1; --sheen: 1; pointer-events: none; }
.glaze-line--edge .gl-cap { display: none; }

/* the phone balance bar. Landing page only; JS swaps it in below 860px. */
.glaze-bar { display: none; }
@media (max-width: 860px) {
  .glaze-line { display: none; }
  .glaze-line--edge { display: block; width: 28px; transform: translateX(-14px); }
  .glaze-line--edge svg { width: 28px; }
  .glaze-bar {
    position: fixed; left: 0; right: 0; bottom: 0; height: calc(56px + env(safe-area-inset-bottom, 0px)); z-index: var(--sc-z-chrome);
    display: grid; grid-template-columns: auto auto minmax(48px, 1fr) auto auto; align-items: center; gap: 0.5rem;
    padding: 0 0.6rem; padding-bottom: env(safe-area-inset-bottom, 0px);
    background: color-mix(in oklab, var(--navy) 94%, transparent);
    color: var(--bisque); box-shadow: 0 -1px 0 color-mix(in oklab, var(--bisque) 14%, transparent);
    -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  }
  .glaze-bar .gb-label { font-family: var(--sc-font-display); font-weight: 700; font-size: 1rem; letter-spacing: -0.02em; line-height: 1; }
  .glaze-bar .gb-track { position: relative; height: 44px; min-width: 0; }
  .glaze-bar .gb-track svg { position: absolute; left: 0; top: 50%; width: 100%; height: 22px; transform: translateY(-50%); overflow: visible; }
  .glaze-bar .gl-base { stroke-opacity: 0.25; }
  .glaze-bar .gb-marker { position: absolute; inset: 0; transform: translateX(calc(var(--split) * 1%)); will-change: transform; pointer-events: none; }
  .glaze-bar .gb-marker::after { content: ""; position: absolute; top: 50%; left: 0; width: 12px; height: 12px; margin: -6px 0 0 -6px; border-radius: 50%; background: var(--bisque); box-shadow: 0 0 0 2px var(--navy); }
  .glaze-bar .gl-cta { margin: 0; min-height: 44px; padding: 0.55em 0.8em; }
  .glaze-bar .sheet-btn { min-height: 44px; padding: 0.5em 0.6em; color: var(--bisque);
    background: color-mix(in oklab, var(--bisque) 12%, transparent); border-color: color-mix(in oklab, var(--bisque) 38%, transparent); }
  .glaze-bar .sheet-btn:hover { background: color-mix(in oklab, var(--bisque) 20%, transparent); border-color: var(--bisque); color: var(--bisque); }
  .glaze-bar .sheet-btn:focus-visible { outline-color: var(--rose); }
  .glaze-bar .gb-lockup { display: none; }
}

/* ------------------------------------------------------------- site head --
   Supporting pages only. The landing page has no bar; the line is the chrome. */
.site-head { position: relative; z-index: 50; }
.site-head .wrap { display: flex; align-items: center; gap: var(--sc-5); padding-block: var(--sc-4); padding-left: calc(var(--sc-gutter) + 1.25rem); }
.site-head .mark { display: inline-flex; align-items: center; min-height: 44px; gap: 0.7rem; text-decoration: none; font-family: var(--sc-font-display); font-weight: 700; font-size: 1.1rem; letter-spacing: -0.02em; }
.site-head .mark img { width: 40px; height: 40px; border-radius: 50%; }
.site-head nav { margin-left: auto; }
.site-head nav ul { display: flex; flex-wrap: wrap; gap: var(--sc-2) var(--sc-5); }
.site-head nav a { text-decoration: none; font-weight: 500; font-size: var(--sc-t-sm); padding: 0.4em 0; border-bottom: 1px solid transparent; }
.site-head nav a:hover, .site-head nav a[aria-current="page"] { border-bottom-color: currentColor; }
.site-head .btn { flex-shrink: 0; }
@media (max-width: 860px) {
  .site-head .wrap { flex-wrap: wrap; padding-left: calc(var(--sc-gutter) + 0.5rem); }
  .site-head nav ul { gap: 0 var(--sc-5); }
  .site-head nav a { display: inline-flex; align-items: center; min-height: 44px; padding: 0.75em 0; }
  .site-head nav { order: 3; width: 100%; margin: 0; }
  .site-head .btn { margin-left: auto; }
}

/* ------------------------------------------------------------------ foot --
   The facts block. On the landing page it lives inside the closing act's
   stage; on supporting pages it is an ordinary footer at the end.         */
.foot { font-size: var(--sc-t-sm); }
.foot .foot-grid { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr) auto; gap: var(--sc-6) var(--sc-7); align-items: start; }
.foot .foot-addr { font-style: normal; }
.foot .foot-addr p + p { margin-top: var(--sc-2); }
.foot .foot-nav ul { display: flex; flex-wrap: wrap; gap: 0.4rem 1.1rem; }
.foot .foot-nav a { text-decoration: none; font-weight: 500; border-bottom: 1px solid var(--sc-hairline-strong); }
.foot .foot-nav a:hover { border-bottom-color: currentColor; }
.foot .foot-contact > ul { display: grid; gap: 0.35rem; }
.foot .foot-photo { width: clamp(88px, 9vw, 132px); border-radius: var(--sc-r-md); overflow: clip; box-shadow: var(--sc-e1); }
.foot .foot-photo img { width: 100%; height: auto; display: block; }
.foot .foot-fine { margin-top: var(--sc-5); padding-top: var(--sc-4); border-top: 1px solid var(--sc-hairline); display: flex; flex-wrap: wrap; gap: var(--sc-2) var(--sc-5); color: var(--sc-ink-soft); font-size: var(--sc-t-sm); }
.foot .foot-fine .credit { margin-left: auto; }
@media (max-width: 860px) {
  .foot .foot-grid { grid-template-columns: 1fr; gap: var(--sc-5); }
  /* thumb-sized rows: the height replaces the gap rather than adding to it */
  .foot .foot-nav ul { gap: 0 var(--sc-5); }
  .foot .foot-contact > ul { gap: 0; }
  .foot .foot-nav a, .foot .foot-contact a { display: inline-flex; align-items: center; min-height: 44px; }
  .foot .foot-photo { display: none; }
  .foot .foot-fine .credit { margin-left: 0; }
}

/* ----------------------------------------------------------- reduced motion */
@media (prefers-reduced-motion: reduce) {
  .btn, a { transition-duration: 0ms; }
  .gl-sheen { display: none; }
}

/* ============================================================== THE CAP ==
   A sibling scrim under the fixed chrome, never a pseudo-element of the
   labels: the verification pass hides the copy to photograph the frame
   beneath, so a scrim that lived on the label would never be measured.
   Two halves, each clipped by the same --split inset the sides use, running
   the ground colour from full at the top to nothing at 5.5rem.            */
.cap-scrim { position: fixed; left: 0; right: 0; top: 0; height: 5.5rem; z-index: calc(var(--sc-z-chrome) - 1); pointer-events: none; }
.cap-scrim > span { position: absolute; inset: 0; display: block; }
.cap-scrim .cs-play { clip-path: inset(0 calc(100% - var(--split) * 1vw) 0 0);
  background: linear-gradient(180deg, var(--navy) 0, var(--navy) 70%, color-mix(in oklab, var(--navy) 40%, transparent) 87%, transparent 100%); }
.cap-scrim .cs-cafe { clip-path: inset(0 0 0 calc(var(--split) * 1vw));
  background: linear-gradient(180deg, var(--bisque) 0, var(--bisque) 70%, color-mix(in oklab, var(--bisque) 42%, transparent) 87%, transparent 100%); }
@media (max-width: 860px) { .cap-scrim { display: none; } }

/* ------------------------------------------------------------ the ticks --
   Six waypoints on the stroke, positioned from the act tops the line's own
   layout() already measures. The visible notch touches the stroke; the 44px
   hit box is offset to the Café side so it can never start a drag.        */
.gl-ticks { position: absolute; left: 0; right: 0; top: 5.5rem; bottom: 2.5rem; pointer-events: none; }
.gl-tick {
  position: absolute; top: calc(var(--at, 0) * 100%); left: 22px;
  width: 44px; height: 44px; margin-top: -22px; padding: 0;
  background: none; border: 0; cursor: pointer; pointer-events: auto;
  display: flex; align-items: center; justify-content: flex-start;
}
.gl-tick::before { content: ""; width: 16px; height: 2px; border-radius: 1px; margin-left: 2px; flex: none;
  background: var(--bisque); box-shadow: 0 0 0 1px var(--navy);
  transition: width 140ms var(--sc-ease-out), background-color 140ms var(--sc-ease-out); }
.gl-tick:hover::before, .gl-tick:focus-visible::before { width: 20px; background: var(--maroon); box-shadow: 0 0 0 1px color-mix(in oklab, var(--bisque) 70%, transparent); }
.gl-tick:focus-visible { outline: 2px solid var(--sc-accent); outline-offset: 2px; border-radius: var(--sc-r-sm); }
.gl-tick-label {
  position: absolute; left: 30px; top: 50%; transform: translateY(-50%);
  white-space: nowrap; font-size: var(--sc-t-xs); font-weight: 600; letter-spacing: 0.01em;
  color: var(--navy); background: color-mix(in oklab, var(--bisque) 94%, transparent);
  border: 1px solid color-mix(in oklab, var(--navy) 18%, transparent);
  padding: 0.35em 0.6em; border-radius: var(--sc-r-sm);
  opacity: 0; visibility: hidden; transition: opacity 140ms var(--sc-ease-out), visibility 0s linear 140ms;
}
.gl-tick:hover .gl-tick-label, .gl-tick:focus-visible .gl-tick-label { opacity: 1; visibility: visible; transition-delay: 0s; }
@media (max-width: 860px) { .gl-ticks { display: none; } }

/* the same six waypoints on the phone bar, as marks only: six 44px targets
   will not fit a 150px track, so the sheet's Jump to list is the phone route. */
.gb-tick { position: absolute; top: 50%; left: calc(var(--at, 0) * 100%); width: 1px; height: 10px; margin: -5px 0 0 0;
  border-radius: 1px; background: color-mix(in oklab, var(--bisque) 62%, transparent); pointer-events: none; }
/* six marks on a ~110px track are below the resolution of the object: the
   first, the middle and the last read, and the sheet's Jump to list is the
   phone route to all six. */
.gb-tick:nth-child(2), .gb-tick:nth-child(3), .gb-tick:nth-child(5) { display: none; }

/* ============================================================= THE SHEET ==
   One panel on all seven pages. Native popover, so Escape, dismiss by click
   outside and focus return to the button are the browser's, and it still
   opens with JavaScript switched off. */
.sheet-btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 44px; min-width: 44px; padding: 0.6em 0.95em;
  font-family: var(--sc-font-text); font-weight: 600; font-size: var(--sc-t-sm);
  line-height: 1; letter-spacing: var(--sc-track-normal); white-space: nowrap;
  color: var(--sc-ink); background: color-mix(in oklab, var(--sc-canvas) 90%, transparent);
  border: 1px solid var(--sc-hairline-strong); border-radius: var(--sc-r-md);
  cursor: pointer; -webkit-appearance: none; appearance: none;
  transition: background-color var(--sc-d-fast) var(--sc-ease-out), border-color var(--sc-d-fast) var(--sc-ease-out), transform 100ms var(--sc-ease-out);
}
.sheet-btn:hover { border-color: var(--sc-ink); background: var(--sc-canvas); }
.sheet-btn:active { transform: translateY(1px); }
.sheet-btn:focus-visible { outline: 2px solid var(--sc-accent); outline-offset: 3px; }

.sheet {
  position: fixed; inset: auto; margin: 0; padding: 0; border: 0; overflow: visible;
  z-index: calc(var(--sc-z-chrome) + 20);
  width: min(27rem, calc(100vw - var(--sc-gutter) * 2));
  background: var(--sc-canvas); color: var(--sc-ink);
  border: 1px solid var(--sc-hairline-strong); border-radius: var(--sc-r-lg);
  box-shadow: var(--sc-e3), var(--sc-edge);
  right: var(--sc-gutter); bottom: 5rem;
  opacity: 0;
  transition: opacity 180ms var(--sc-ease-out), overlay 240ms allow-discrete, display 240ms allow-discrete;
}
.sheet:popover-open { opacity: 1; }
@starting-style { .sheet:popover-open { opacity: 0; } }
.sheet::backdrop { background: color-mix(in oklab, var(--navy) 32%, transparent); }
.sheet-in { padding: var(--sc-5); max-height: min(46rem, calc(100svh - 8rem)); overflow-y: auto; overscroll-behavior: contain;
  clip-path: inset(0 100% 0 0); transition: clip-path 260ms var(--sc-ease-out); }
.sheet:popover-open .sheet-in { clip-path: inset(0 0 0 0); }
@starting-style { .sheet:popover-open .sheet-in { clip-path: inset(0 100% 0 0); } }
/* on the landing page the panel grows out of the brushstroke itself */
@media (min-width: 861px) {
  .sheet--line { left: calc(var(--split) * 1vw + 34px); top: 5.5rem; right: auto; bottom: auto; }
}
.sheet .t-label + * { margin-top: var(--sc-3); }
.sheet nav + p, .sheet nav + .sheet-facts, .sheet .sheet-facts + .btn { margin-top: var(--sc-5); }
/* the facts strip leads the sheet, so it carries no divider of its own */
.sheet-in > .sheet-facts:first-child { border-top: 0; padding-top: 0; }
.sheet .sheet-cta + .t-label { margin-top: var(--sc-6); }
.sheet-nav a { display: block; text-decoration: none; padding: 0.55rem 0; border-top: 1px solid var(--sc-hairline); }
.sheet-nav li:first-child a { border-top: 0; }
.sheet-nav a > b { display: block; font-family: var(--sc-font-display); font-weight: 650; font-size: 1.15rem; line-height: 1.1; letter-spacing: var(--sc-track-snug); }
.sheet-nav a > span { display: block; margin-top: 0.15rem; font-size: var(--sc-t-sm); color: var(--sc-ink-soft); text-wrap: pretty; }
.sheet-nav a:hover > b, .sheet-nav a:focus-visible > b { color: var(--sc-accent); }
.sheet-nav a[aria-current="page"] > b::after { content: " ·"; color: var(--sc-accent); }
.sheet-jump { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.sheet-jump a { display: inline-flex; align-items: center; min-height: 44px; padding: 0 0.7rem; text-decoration: none;
  font-size: var(--sc-t-sm); font-weight: 500; border: 1px solid var(--sc-hairline-strong); border-radius: var(--sc-r-md); }
.sheet-jump a:hover, .sheet-jump a:focus-visible { border-color: var(--sc-ink); color: var(--sc-accent); }
.sheet-facts { font-size: var(--sc-t-sm); border-top: 1px solid var(--sc-hairline); padding-top: var(--sc-4); }
.sheet-facts p + p { margin-top: var(--sc-2); }
.sheet-facts a { display: inline-flex; align-items: center; min-height: 44px; }
.sheet-cta { width: 100%; margin-top: var(--sc-4); }
.sheet :is(a, button):focus-visible { outline: 2px solid var(--sc-accent); outline-offset: 2px; border-radius: var(--sc-r-sm); }
@media (max-width: 860px) {
  /* rises from the balance bar, and never under it */
  .sheet, .sheet--line { left: 0.75rem; right: 0.75rem; width: auto; top: auto;
    bottom: calc(56px + env(safe-area-inset-bottom, 0px) + 0.6rem); }
  .page .sheet { bottom: calc(60px + env(safe-area-inset-bottom, 0px) + 0.6rem); }
  .sheet-in { max-height: calc(100svh - 12rem); clip-path: inset(100% 0 0 0); }
}
/* a browser with no popover support would leave the panel permanently open,
   so it is not shown there at all: the footer nav is the route on those. */
@supports not selector(:popover-open) { .sheet, .sheet-btn { display: none; } }
@media (prefers-reduced-transparency: reduce) {
  .cap-scrim .cs-play { background: var(--navy); height: 4rem; }
  .cap-scrim .cs-cafe { background: var(--bisque); height: 4rem; }
  .sheet-btn { background: var(--sc-canvas); }
}
@media (prefers-reduced-motion: reduce) {
  .sheet, .sheet-in, .gl-tick::before, .gl-tick-label { transition-duration: 0ms; }
  .sheet-in, .sheet:popover-open .sheet-in { clip-path: none; }
}

/* Focus completes an act's stagger at once: no tab stop is ever left mid-fade.
   The same shape as the engine's own [data-sc-cue]:focus-within rule above. */
.act.is-focus-in :is([data-sc-in], [data-sc-stagger] > *) {
  opacity: 1 !important; transform: none !important;
  transition-delay: 0ms !important; transition-duration: 0ms !important; }

@media (min-width: 861px) {
  /* A standalone action link is a 45px pointer target on a mouse screen too.
     The box is a pseudo-element, not padding, so the underline stays on the
     word: the same trick the phone breakpoint below already uses for the
     inline links inside a sentence. */
  .link-arrow { position: relative; }
  .link-arrow::after { content: ""; position: absolute; inset: -12px 0; }
  .btn-row { row-gap: var(--sc-5); }
}

/* ------------------------------------------------------- touch targets --
   A word-sized text link is still a thumb-sized target: the box is widened
   where that costs nothing, and expanded with a hit area where a visible
   underline has to stay attached to the word. */
@media (max-width: 860px) {
  .site-head nav a, .foot-nav a { min-width: 46px; justify-content: center; }
  .link-arrow, .fact-list dd a, .foot .foot-contact a, .sheet-facts a { position: relative; }
  /* a real 44px box for every standalone action link. The underline stays on
     the word: it is drawn by ::before against the text line, not on the box. */
  .link-arrow, .fact-list dd a, .foot-contact a, .foot-nav a {
    display: inline-flex; align-items: center; min-height: 46px;
    border-bottom: 0; padding-bottom: 0; position: relative;
  }
  .link-arrow::before, .fact-list dd a::before, .foot-contact a::before, .foot-nav a::before {
    content: ""; position: absolute; left: 0; right: 0; top: calc(50% + 0.62em); height: 1px;
    background: var(--sc-hairline-strong);
  }
  .link-arrow:hover::before, .fact-list dd a:hover::before,
  .foot-contact a:hover::before, .foot-nav a:hover::before { background: currentColor; }
  /* the enlarged boxes must not touch each other */
  .btn-row { row-gap: var(--sc-2); }
  .foot .foot-contact > ul, .foot .foot-nav ul { gap: 0; }
  /* an inline link inside a sentence keeps its line box (WCAG 2.5.8 inline
     exception) but gets a thumb-sized hit area that costs no layout. */
  .faq a, .t-body a, .t-small a, .t-lede a, .ph p a { position: relative; }
  .faq a::after, .t-body a::after, .t-small a::after, .t-lede a::after, .ph p a::after {
    content: ""; position: absolute; inset: -13px -3px; }
}

/* =================================================== VIEW TRANSITIONS ==
   The chrome stops being a picture of chrome and behaves like a fixed object
   in the building: the brushstroke and the ring mark persist across every
   navigation instead of blinking. 0 KB. Firefox falls back to an ordinary
   navigation, which is today's behaviour, so there is nothing to polyfill.
   Exactly one .glaze-line and one .site-head .mark img per document, so the
   names are unique at capture time.                                        */
@view-transition { navigation: auto; }
.glaze-line { view-transition-name: glaze-line; }
.site-head .mark { view-transition-name: cafe-mark; }
@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; }
}
:root.is-calm .glaze-line, :root.is-calm .site-head .mark { view-transition-name: none; }

/* ============================================== MORPH A: THE GLAZE FIRES ==
   The card on the table says the glazes become bright and glossy after
   firing. These five swatches do that, on the shelf pan.

   Every hex is the mean of a 24x24 patch of the jar body in the client's own
   photograph. Nothing here was hand-picked.
     file: assets/source/cafe/83ae2f_075be70ff8084400b59c11c5bdbc9834~mv2.jpg
           (2731 x 2048, full res)
     Turquoise   x 683  y 419   #6BC3D7
     Dark Blue   x 1063 y 585   #C0ADC9
     Aubergine   x 117  y 1044  #8882AA
     Coffee      x 585  y 1044  #EAA159
     Black       x 960  y 1060  #24292B
   The unfired state is the jar colour exactly as it is. The fired state is a
   saturation of the same colour, which is the client's own claim, not a new
   one. They are content inside a figure, never UI: not links, not buttons,
   never maroon, never in the accent role.                                   */
.glaze-swatches { display: flex; flex-wrap: wrap; gap: var(--sc-3) var(--sc-5); margin: 0; }
.glaze-swatches li { display: flex; align-items: center; gap: 0.55rem; font-size: var(--sc-t-sm); font-weight: 500; }
.sw {
  --fire: 1;
  position: relative; flex: none; width: 40px; height: 40px; background: var(--jar);
  /* eight calc()ed radii: an irregular chalky blob at --fire 0, a clean disc
     at 1. border-radius interpolates natively between two eight-value forms.
     On a 40px box the 22-point travel is 9px of real deformation, so the shape
     carries the idea rather than wobbling by two pixels. */
  border-radius:
    calc(72% - var(--fire) * 22%) calc(28% + var(--fire) * 22%) calc(64% - var(--fire) * 14%) calc(36% + var(--fire) * 14%) /
    calc(34% + var(--fire) * 16%) calc(66% - var(--fire) * 16%) calc(58% - var(--fire) * 8%) calc(42% + var(--fire) * 8%);
  box-shadow: 0 0 0 1px color-mix(in oklab, var(--sc-ink) 14%, transparent);
}
/* --fire drives shape and gloss ONLY. The unfired hex is the jar exactly as it
   is in the photograph; RESEARCH.md contains no fired hex, so none is depicted.
   A saturate() here made Coffee read orange and Dark Blue read lilac, which is
   the client's own product shown wrong. The verified claim is "bright and
   glossy after firing", and gloss is what the specular says. */
.sw::after { content: ""; position: absolute; left: 24%; top: 18%; width: 40%; height: 32%;
  border-radius: 50%; opacity: var(--fire);
  background: radial-gradient(closest-side, rgba(255,255,255,0.85), rgba(255,255,255,0)); }
.sw--turquoise { --jar: #6BC3D7; }
.sw--darkblue  { --jar: #C0ADC9; }
.sw--aubergine { --jar: #8882AA; }
.sw--coffee    { --jar: #EAA159; }
.sw--black     { --jar: #24292B; }

/* ============================================================= THE MARK ==
   A loaded brush mark of wet glaze. It rides BEHIND the OS pointer, which is
   never hidden: there is no `cursor: none` anywhere on this site, so the
   pointer keeps its system size, the user's contrast setting and macOS
   shake-to-find. The ring is transparent inside, so it can never obscure
   text, and it is pointer-events: none in every state without exception.   */
.cur {
  position: fixed; left: 0; top: 0; z-index: 60;
  width: 30px; height: 30px; border-radius: 50%;
  border: 1.5px solid var(--rose); background-color: transparent;
  opacity: 0; pointer-events: none; will-change: transform; contain: layout paint;
  transition: opacity 160ms var(--sc-ease-out), width 180ms var(--sc-ease-out),
              height 180ms var(--sc-ease-out), background-color 180ms var(--sc-ease-out),
              border-color 180ms var(--sc-ease-out), border-radius 180ms var(--sc-ease-out);
}
.cur.is-on { opacity: 0.55; }
/* a photograph: it grows and loads with rose. Never over type: the state
   reader returns the nearest match, and .copy is in the selector union. */
.cur--piece.is-on { width: 44px; height: 44px; background-color: color-mix(in oklab, var(--rose) 30%, transparent); }
/* a link: smaller means more precise */
.cur--link.is-on { width: 20px; height: 20px; border-width: 2px; border-color: var(--maroon); }
/* the CTA. The only filled maroon pointer state on the site. The state is
   keyed to the ground beneath it: on the bisque side the button is filled
   maroon, so a maroon ring on a maroon button is invisible and the mark
   flips to bisque. .side--play's own accent is rose, so there the maroon
   ring still reads and the default stands. JS writes data-g on the mark. */
.cur--book.is-on { width: 24px; height: 24px; border-width: 2px; border-color: var(--maroon);
  background-color: color-mix(in oklab, var(--maroon) 18%, transparent); }
.cur--book.is-on[data-g="maroon"] { border-color: var(--bisque);
  background-color: color-mix(in oklab, var(--bisque) 22%, transparent); }
/* the peak object: the capsule says the line can be dragged */
.cur--line.is-on { width: 8px; height: 48px; border-radius: 4px; border-color: transparent; background-color: var(--rose); }
/* an I-beam is information */
.cur--off.is-on { opacity: 0; }
@media (prefers-reduced-motion: reduce) { .cur { display: none; } }

/* ------------------------------------------------- inline link tap targets --
   Inline vertical padding overflows the line box, so the hit area reaches 44px
   while the running-text setting and the line rhythm stay exactly as they are. */
p > a:not([class]), li > a:not([class]), dd > a:not([class]) { padding-block: 12px; margin-block: -12px; }
