/* Chalkboard: the page's own layer over starter.css. The board #0E1116 with fine chalk grain and soft
   eraser smudges; chalk #E7EBF0; lavender #D2C2FF leads (buttons, the highlighted phrase, the logo's
   door), cyan #7CF3FF underlines and writes the hand-written labels, blue #4A8FE0 draws the frames,
   circles and ticks. Display Cabin Sketch 700, hand-written labels Caveat 600, body Atkinson
   Hyperlegible, all self-hosted (OFL). Everything that moves is scoped to html.js, so without script
   the page is a plain, whole document; html.rm (reduced motion) takes the same stacked forms. */

@font-face { font-family: "Cabin Sketch"; src: url(fonts/CabinSketch-Bold.woff2) format("woff2"); font-weight: 700; font-display: swap; }
@font-face { font-family: "Caveat"; src: url(fonts/Caveat-SemiBold.woff2) format("woff2"); font-weight: 600; font-display: swap; }
@font-face { font-family: "Atkinson Hyperlegible"; src: url(fonts/AtkinsonHyperlegible-Regular.woff2) format("woff2"); font-weight: 400; font-display: swap; }
@font-face { font-family: "Atkinson Hyperlegible"; src: url(fonts/AtkinsonHyperlegible-Bold.woff2) format("woff2"); font-weight: 700; font-display: swap; }
@property --o { syntax: "<number>"; inherits: true; initial-value: 1; }

html {
  scrollbar-gutter: stable; scrollbar-color: #2a313c var(--stage);
  --lav: #d2c2ff; --cyan: #7cf3ff; --blue: #4a8fe0; --muted: #838c98; --rule: #3a414c;
  --grain: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22260%22%20height%3D%22260%22%3E%3Cfilter%20id%3D%22n%22%3E%3CfeTurbulence%20type%3D%22fractalNoise%22%20baseFrequency%3D%22.8%22%20numOctaves%3D%223%22%20stitchTiles%3D%22stitch%22%2F%3E%3CfeColorMatrix%20values%3D%220%200%200%200%201%200%200%200%200%201%200%200%200%200%201%200%200%200%20.075%200%22%2F%3E%3C%2Ffilter%3E%3Crect%20width%3D%22100%25%22%20height%3D%22100%25%22%20filter%3D%22url(%23n)%22%2F%3E%3C%2Fsvg%3E");
  --chalkline: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20300%2020%22%20preserveAspectRatio%3D%22none%22%3E%3Cpath%20d%3D%22M3%2013C60%206%20120%2015%20180%209s90%203%20114-2%22%20fill%3D%22none%22%20stroke%3D%22%237CF3FF%22%20stroke-width%3D%225%22%20stroke-linecap%3D%22round%22%20opacity%3D%22.92%22%2F%3E%3Cpath%20d%3D%22M20%2017c70-5%20150-3%20250-7%22%20fill%3D%22none%22%20stroke%3D%22%237CF3FF%22%20stroke-width%3D%222.2%22%20stroke-linecap%3D%22round%22%20opacity%3D%22.55%22%2F%3E%3C%2Fsvg%3E");
}
/* The board: grain over the whole page and soft eraser smudges where a hand wiped it. */
body {
  background: var(--grain), radial-gradient(1200px 500px at 20% 4%, rgba(255, 255, 255, 0.045), transparent 70%), radial-gradient(900px 420px at 85% 30%, rgba(255, 255, 255, 0.035), transparent 70%), radial-gradient(1000px 500px at 30% 62%, rgba(255, 255, 255, 0.03), transparent 70%), radial-gradient(900px 500px at 75% 88%, rgba(255, 255, 255, 0.03), transparent 70%), var(--stage);
  font-family: "Atkinson Hyperlegible", "Segoe UI", sans-serif; font-weight: 400; -webkit-font-smoothing: antialiased;
}
h1, h2, h3, .tier-kind { font-family: "Cabin Sketch", Georgia, serif; font-weight: 700; }
.hand { font-family: "Caveat", cursive; font-weight: 600; color: var(--cyan); line-height: 1.1; }
.chalk { filter: url(#chalk); }
.defs { position: absolute; width: 0; height: 0; }
::selection { background: var(--lav); color: var(--stage); }
:focus-visible { outline: 2px dashed var(--cyan); outline-offset: 4px; border-radius: 6px; }
a { color: inherit; }
img { max-width: 100%; }
html.viewing { overflow: hidden; scrollbar-gutter: auto; }
/* A cyan chalk underline, drawn under the hero's last phrase and under "Yours should make people stop." */
.u { background: var(--chalkline) left 100% / 100% 0.22em no-repeat; padding-bottom: 0.08em; }

/* The call to action: lavender, a hand-cut edge, one look everywhere it appears. */
.cta { display: inline-flex; align-items: center; justify-content: center; gap: 0.5em; background: var(--lav); color: var(--stage); text-decoration: none; font-family: "Atkinson Hyperlegible", sans-serif; font-weight: 700; border-radius: 10px 14px 9px 13px; box-shadow: 0 0 0 2px color-mix(in srgb, var(--lav) 45%, transparent), 3px 4px 0 0 color-mix(in srgb, var(--paper) 18%, transparent); transition: background-color 0.2s ease, translate 0.2s ease, box-shadow 0.2s ease; white-space: nowrap; }
.cta:hover { background: #e1d6ff; translate: -1px -1px; box-shadow: 0 0 0 2px color-mix(in srgb, var(--lav) 55%, transparent), 4px 5px 0 0 color-mix(in srgb, var(--paper) 22%, transparent); }
.cta:active { background: #c2adff; translate: 1px 1px; }
.cta-s { padding: 0.62em 1.15em; font-size: 0.95rem; }
.cta-l { padding: 1em 1.7em; font-size: clamp(1.02rem, 1.3vw, 1.15rem); }

/* The Dame Digital family bar and footer (site/public/assets/family/). The bar scrolls away above the header, over the
   top of a first scene that stays at the top of the page, so the canvas and every pin keep their coordinates and the
   scene's content stays in view; the opening gives up the bar's height (--fam-give) at its top instead. The bar stays
   under the piece viewer, whose Close sits where it would. The Dame Digital line is the last row of .foot, so it sits
   over the canvas and leaves the plate with it. */
html { --fam-give: calc(var(--fam-h, 44px) + 1px); --top-h: 86px; }
.fam.fam-b { z-index: 40; }
html.plate { --fam-give: 0px; }
html.plate .fam { display: none; }

/* The header: the house mark and the name, and the way in, on a board scrim. It starts under the family bar and holds
   the top once the bar has gone: sticky, at the height it draws, with its margin taking back that height and the bar's
   so main still starts at the top of the page. */
.top { position: sticky; top: 0; z-index: 20; box-sizing: border-box; height: var(--top-h); margin-bottom: calc(-1 * (var(--top-h) + var(--fam-give))); display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 16px clamp(16px, 3.4vw, 48px) 26px; background: linear-gradient(rgb(14, 17, 22) 62%, rgba(14, 17, 22, 0)); }
.brand { display: inline-flex; align-items: center; gap: 0.6rem; text-decoration: none; font-family: "Cabin Sketch", serif; font-weight: 700; font-size: 1.4rem; }
.brand img { display: block; }
.top nav { display: flex; align-items: center; gap: clamp(0.8rem, 2.2vw, 2rem); font-size: 0.98rem; }
.top nav a:not(.cta) { text-decoration: none; color: var(--paper); padding: 0.4em 0; }
/* Every header link takes a tap at least 44 by 44 px: an invisible hit area, centred on the link and never
   smaller than it, so nothing it draws and nothing around it moves. */
.top .brand, .top nav a { position: relative; }
.top .brand::after, .top nav a::after { content: ""; position: absolute; inset: min(0px, calc(50% - 22px)); }
.top nav a:not(.cta):hover { text-decoration: underline; text-underline-offset: 0.35em; text-decoration-color: var(--cyan); text-decoration-thickness: 2px; }

/* The opening. */
.hero { position: relative; }
.hero-pin { display: grid; grid-template-columns: minmax(0, 46%) 1fr; grid-template-rows: 1fr auto; align-items: center; padding: calc(92px + var(--fam-give)) clamp(16px, 3.6vw, 52px) clamp(24px, 6vh, 60px); place-items: initial; }
.plate-img { position: absolute; inset: 0; z-index: 0; transition: opacity 0.9s ease-out; }
.plate-img img { width: 100%; height: 100%; object-fit: cover; object-position: right center; display: block; }
/* The box the live house stands in: where the still draws it. */
.hero-house { position: absolute; left: 44%; top: 17%; width: 53%; height: 66%; pointer-events: none; }
.hl { position: relative; z-index: 1; grid-column: 1; grid-row: 1; align-self: center; margin: 0; font-size: clamp(3.2rem, 7.4vw, 7.6rem); line-height: 1.02; letter-spacing: -0.005em; text-wrap: balance; color: var(--paper); transform-origin: 0 50%; will-change: transform; }
.hero-foot { position: relative; z-index: 1; grid-column: 1 / -1; grid-row: 2; display: flex; align-items: flex-end; justify-content: space-between; gap: 2rem; width: 100%; }
.lede { max-width: 36ch; margin: 0; font-size: clamp(1.02rem, 1.2vw, 1.15rem); color: var(--paper); }
.arrow { position: absolute; right: clamp(200px, 17vw, 250px); bottom: 40px; width: 90px; height: 70px; }
.hint { position: absolute; z-index: 1; right: clamp(16px, 3.6vw, 52px); top: calc(100px + var(--fam-give)); margin: 0; font-size: 1.6rem; rotate: -3deg; }
/* Live: the house is drawn by the scene in its box; the still gives way to the canvas once it has drawn. */
/* The canvas fades in over the still once its first frame has drawn (the page adds scene-on), and the
   still steps back under it. Until then, and on every still rung, the still is the opening. */
.js .stage { opacity: 0; transition: opacity 0.9s ease-out; }
html.scene-on .stage { opacity: 1; }
html.scene-on:not([data-rung="still"]) .plate-img { opacity: 0; }
html[data-rung="still"] .hint, html[data-rung="webgl1"] .hint, .no-js .hint { display: none !important; }
/* One hint per pointer: the pointer line with a mouse, the touch line on a coarse pointer. */
.hint[data-hint="touch"] { display: none; }
@media (pointer: coarse) {
  .hint[data-hint="pointer"] { display: none; }
  .js .hint[data-hint="touch"] { display: block; }
}
/* Without script the opening still takes a full screen, so on a phone the headline sits below the house. */
.no-js .hero-pin { min-height: 100vh; min-height: 100svh; }
html.plate main > :not(.hero), html.plate .top, html.plate .hero-pin > :not(.plate-img), html.plate .foot { visibility: hidden; }
/* The underline is drawn on, left to right, once the page has opened. */
.js:not(.rm) .hl .u { animation: chalk-under 1.1s 0.9s cubic-bezier(.4, 0, .2, 1) both; }
@keyframes chalk-under { from { background-size: 0% 0.22em; } to { background-size: 100% 0.22em; } }
.js:not(.rm) .arrow path { stroke-dasharray: 1; animation: chalk-draw 0.8s 1.7s ease-out both; }
@keyframes chalk-draw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
/* A tall screen: the house above, the headline below it. */
@media (orientation: portrait) {
  .hero-pin { grid-template-columns: 1fr; grid-template-rows: 1fr auto auto; }
  .hero-house { left: 6%; width: 88%; top: 13%; height: 36%; }
  .hl { grid-row: 2; align-self: end; margin-bottom: 4vh; font-size: clamp(3rem, 9.6vw, 7rem); }
  .hero-foot { grid-row: 3; }
  .plate-img img { object-position: 72% 0; }
}

/* The work strip. */
.work { position: relative; }
.work-pin { display: block; padding: 0; }
.work-h { margin: 0; font-size: clamp(1.9rem, 3.6vw, 3.6rem); line-height: 1.04; max-width: 18ch; }
.piece-open { position: relative; display: block; width: 100%; padding: 0; border: 0; background: none; color: inherit; cursor: zoom-in; border-radius: 6px; }
.frame { position: relative; display: block; aspect-ratio: 16 / 10; overflow: clip; border-radius: 6px; background: #161b23; transform-origin: 50% 50%; }
.frame img { display: block; width: 100%; height: 100%; object-fit: cover; }
.frame-pair { display: flex; gap: 0; }
.frame-pair img { width: 50%; }
/* The chalk frame round the piece at the centre, drawn round it as it arrives. */
.cframe { position: absolute; inset: -12px; width: calc(100% + 24px); height: calc(100% + 24px); pointer-events: none; overflow: visible; z-index: 4; }
.cframe path { stroke-width: 3px; }
.cframe .c2 { stroke-width: 1.4px; }
.js:not(.rm) .cframe path { stroke-dasharray: 1; stroke-dashoffset: calc(1 - clamp(0, (var(--o, 1) - 0.55) / 0.4, 1)); }
.piece-cap h3 { margin: 0.75em 0 0.2em; font-size: clamp(1.8rem, 3vw, 2.9rem); line-height: 1; }
.piece-cap p { margin: 0; max-width: 46ch; color: var(--muted); }
.piece-cap .made { margin-top: 0.4em; color: var(--cyan); font-family: "Caveat", cursive; font-weight: 600; font-size: 1.55rem; line-height: 1.1; }
.work-count { margin: 0; font-family: "Caveat", cursive; font-weight: 600; font-size: 1.7rem; color: var(--paper); font-variant-numeric: tabular-nums; padding: 6px 20px; }
.work-count .ring { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.more { margin-top: 1.4rem; }
.js .piece .more { display: none; }
.more-shots { list-style: none; margin: 0 0 1.2rem; padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr)); gap: 14px; }
.more-shots img { display: block; width: 100%; border-radius: 6px; }
.more-shots .tall { max-width: 320px; }
.more-facts { margin: 0 0 1.2rem; padding-left: 1.1em; max-width: 60ch; }
.more-facts li { margin: 0.3em 0; }
.live { color: var(--lav); font-weight: 700; text-underline-offset: 0.3em; text-decoration-color: var(--cyan); }

/* Stacked form: no script, reduced motion, and below 768 px without the sideways row. */
.work-pin { padding: 120px clamp(16px, 4vw, 56px) 80px; }
.track { display: grid; gap: 64px; margin-top: 40px; }
.work-count { display: none; }
/* Under reduced motion there is no sideways row at any width, so the stacked four take their natural height
   unpinned, as the phone's block below does; the starter's pin would clip them to one viewport. */
.js.rm .work[data-span] { height: auto; }
.js.rm .work > .pin { position: relative; height: auto; overflow: visible; display: block; }

@media (min-width: 768px) {
  .js:not(.rm) .work { margin-top: -100vh; margin-top: -100svh; }
  .js:not(.rm) .work:not(.on) .work-pin { visibility: hidden; }
  .js:not(.rm) .work.on .work-pin { background: var(--grain), radial-gradient(900px 420px at 80% 30%, rgba(255, 255, 255, 0.035), transparent 70%), var(--stage); }
  .js:not(.rm) .work-pin { padding: 0; }
  .js:not(.rm) .work-h { position: absolute; z-index: 2; left: clamp(16px, 3.6vw, 52px); top: 96px; opacity: var(--intro, 1); }
  /* Pieces sit 0.71 of their width apart (40vw on a wide screen): a neighbour shows only as its giant chalk
     letter at the edge of the screen, filled with its picture, until it travels to the centre. */
  .js:not(.rm) .track { --cw: min(56vw, 84vh); position: absolute; left: 0; top: calc(50% - var(--cw) * 0.3125 + 2vh); display: flex; gap: 0; margin: 0; padding: 0 calc(50vw - var(--cw) / 2); will-change: transform; }
  .js:not(.rm) .piece + .piece { margin-left: calc(var(--cw) * -0.29); }
  @media (orientation: portrait) { .js:not(.rm) .track { --cw: min(76vw, 84vh); } }
  /* z-index follows --o, set by page.js (round() is newer than Chromium 109 and Firefox 115). */
  .js:not(.rm) .piece:not(:first-child) { position: relative; z-index: 1; }
  .js:not(.rm) .piece { flex: 0 0 var(--cw); width: var(--cw); }
  .js:not(.rm) .piece:first-child .frame { z-index: 3; }
  .js:not(.rm) .piece .frame { scale: calc(0.84 + var(--o, 1) * 0.16); transition: none; }
  .js:not(.rm) .piece .cframe { scale: calc(0.84 + var(--o, 1) * 0.16); opacity: calc(clamp(0, (var(--o, 1) - 0.6) / 0.3, 1) * clamp(0, (var(--intro, 1) - 0.85) / 0.15, 1)); }
  .js:not(.rm) .piece-cap { opacity: calc(var(--o, 1) * var(--intro, 1)); translate: calc(var(--side, 0) * (1 - var(--o, 1)) * 40px) calc((1 - var(--o, 1)) * 18px); }
  .js:not(.rm) .work-count { display: block; position: absolute; right: clamp(16px, 3.6vw, 52px); bottom: 5vh; opacity: var(--intro, 1); }
  /* Chalk letters: away from the centre a piece shows only through its giant letter, drawn in Cabin
     Sketch's rough chalk outline; reaching the centre the letter grows past the frame while a
     rectangle opens from the middle, and the frame is whole. */
  .js:not(.rm) .work.on .piece .frame {
    -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
    -webkit-mask-position: center; mask-position: center;
    -webkit-mask-size: auto calc(78% + var(--o, 1) * 420%), calc(var(--o, 1) * 100%) calc(var(--o, 1) * 100%);
    mask-size: auto calc(78% + var(--o, 1) * 420%), calc(var(--o, 1) * 100%) calc(var(--o, 1) * 100%);
    mask-composite: add;
  }
  .js:not(.rm) .work.on .piece .frame { -webkit-mask-image: var(--solid), linear-gradient(#000 0 0); mask-image: var(--solid), linear-gradient(#000 0 0); }
  .js:not(.rm) .work.on .piece .frame::after { -webkit-mask: var(--glyph) center / auto calc(78% + var(--o, 1) * 420%) no-repeat; mask: var(--glyph) center / auto calc(78% + var(--o, 1) * 420%) no-repeat; }
}
/* The carve: the wipe is cut by the letter's solid shape (so it never stripes the piece it opens onto),
   and the letter itself is drawn over it in chalk, the outline and the scribble of Cabin Sketch, fading as
   the piece reaches the centre. Away from the centre the picture under the letter is dimmed and softened
   to dust, so no line of a neighbour's text reads through it. */
.piece[data-piece="dame"], .piece[data-piece="damedigital"] { --glyph: url(glyph-D.svg); --solid: url(glyph-D-solid.webp); }
.piece[data-piece="3dp-yyc"] { --glyph: url(glyph-3.svg); --solid: url(glyph-3-solid.webp); }
.piece[data-piece="wild-rose-rates"] { --glyph: url(glyph-W.svg); --solid: url(glyph-W-solid.webp); }
.js:not(.rm) .work.on .piece .frame::after, .js:not(.rm) .piece .frame::after { content: ""; position: absolute; inset: 0; z-index: 2; pointer-events: none; background: var(--paper); opacity: calc(clamp(0, (0.85 - var(--o, 1)) / 0.45, 1) * 0.9); }
.js:not(.rm) .work.on .piece .frame img, .js:not(.rm) .piece .frame img { filter: brightness(calc(0.22 + 0.78 * clamp(0, (var(--o, 1) - 0.3) / 0.6, 1))) blur(calc(clamp(0, (0.85 - var(--o, 1)) / 0.45, 1) * 5px)); }
@media (max-width: 767px) {
  .js .work[data-span] { height: auto; }
  /* Block, not the starter's centring grid: a grid item sizes to the row's full width and the page
     scrolls sideways (measured at 390: the row 2145 px wide). */
  .js .work > .pin { position: relative; height: auto; overflow: visible; display: block; }
  .js:not(.rm) .track { display: flex; gap: 6vw; overflow-x: auto; scroll-snap-type: x mandatory; margin: 32px calc(-1 * clamp(16px, 4vw, 56px)) 0; padding: 14px 7vw 12px; scrollbar-width: none; }
  .js:not(.rm) .track { box-sizing: border-box; width: 100vw; max-width: 100vw; }
  .js:not(.rm) .piece { flex: 0 0 84vw; scroll-snap-align: center; }
  .cframe { inset: -8px; width: calc(100% + 16px); height: calc(100% + 16px); }
  @supports (animation-timeline: view()) {
    .js:not(.rm) .piece .frame, .js:not(.rm) .piece .cframe { animation: carve linear both; }
    .js:not(.rm) .piece .frame, .js:not(.rm) .piece .cframe { animation-timeline: view(inline); animation-range: cover 0% cover 100%; }
    .js:not(.rm) .piece .frame { -webkit-mask: linear-gradient(#000 0 0) center / calc(var(--o) * 100%) calc(var(--o) * 100%) no-repeat, var(--solid) center / auto calc(78% + var(--o) * 420%) no-repeat; mask-composite: add; }
    /* On the row a neighbour is half on screen well into its swipe, so its chalk letter stays near the
       card's size and is gone before it could grow into blown-up scribble; the dimmed picture still opens
       through the solid wipe. */
    .js:not(.rm) .work.on .piece .frame::after, .js:not(.rm) .piece .frame::after { -webkit-mask: var(--glyph) center / auto calc(78% + var(--o) * 40%) no-repeat; mask: var(--glyph) center / auto calc(78% + var(--o) * 40%) no-repeat; opacity: calc(clamp(0, (0.78 - var(--o)) / 0.14, 1) * 0.92); }
    /* The picture stays dark under the letter until the card is nearly centred, then comes up at once. */
    .js:not(.rm) .work.on .piece .frame img, .js:not(.rm) .piece .frame img { filter: brightness(calc(0.16 + 0.84 * clamp(0, (var(--o) - 0.7) / 0.22, 1))) blur(calc(clamp(0, (0.88 - var(--o)) / 0.2, 1) * 5px)); }
  }
  /* Without a scroll timeline the phone row shows each piece whole, so the chalk letter is not drawn. */
  @supports not (animation-timeline: view()) { .js:not(.rm) .piece .frame::after { display: none; } }
  html { --top-h: 78px; }
  .top { padding-inline: 16px; gap: 0.6rem; background: linear-gradient(rgb(14, 17, 22) 70%, rgba(14, 17, 22, 0)); }
  .top nav { gap: 0.7rem; font-size: 0.9rem; }
  .brand, .top nav a { white-space: nowrap; }
  .brand { font-size: 1.15rem; gap: 0.45rem; }
  .brand img { width: 28px; height: 25px; }
  .top .cta-s { padding: 0.55em 0.9em; font-size: 0.82rem; }
  .top nav a[href="#offer"] { display: none; }
  /* Under 375 the name, "Work" and the button need about 330 px and the header has 288 at 320, so the
     name ran into "Work" and the button past the edge. "Work" goes, as "What we make" does under 768;
     the section is the next thing down the page. */
  @media (max-width: 374px) { .top nav a[href="#work"] { display: none; } }
  /* In the flow now, so what the switch ran past the edge at 320 would scroll the page sideways: a tighter header there. */
  @media (max-width: 374px) { .top { padding-inline: 12px; gap: 0.4rem; } .top nav { gap: 0.5rem; } }
  .hero-pin { padding-top: calc(72px + var(--fam-give)); }
  /* The house stands right under the header here, so it and the still step down by the bar too, the still's foot
     clipped by the pin; the headline and the button below hold their place. */
  .hero-house { left: 5%; width: 90%; top: calc(7% + var(--fam-give)); height: 40%; }
  .plate-img { inset: var(--fam-give) 0 calc(-1 * var(--fam-give)); }
  .hl { font-size: clamp(2.6rem, 12.4vw, 3.4rem); margin-bottom: 3vh; }
  .hero-foot { flex-direction: column; align-items: flex-start; gap: 1.1rem; }
  .plate-img img { object-position: center top; }
  .hint, .arrow { display: none; }
  /* A phone shows the touch line, small, over the top of the house. */
  @media (pointer: coarse) { .js .hint[data-hint="touch"] { display: block; top: calc(78px + var(--fam-give)); right: 16px; font-size: 1.25rem; } }
}
/* Every preview moves as its piece scrolls into view, at every width (page.js writes --pan and --zoom
   from the scroll: the picture drifts across its frame and settles as the frame reaches the middle). */
.js:not(.rm) .piece .frame img { transform: translate3d(calc(var(--panx, 0) * 1%), calc(var(--pan, 0) * 1%), 0) scale(var(--zoom, 1)); transform-origin: 50% 50%; will-change: transform; }
@keyframes carve { 0% { --o: 0.15; } 38%, 62% { --o: 1; } 100% { --o: 0.15; } }

/* The statement and its three proofs. */
.say { position: relative; padding: 26vh clamp(16px, 4vw, 56px) 18vh; }
.say-h { margin: 0; max-width: 17ch; font-size: clamp(2.4rem, 5.6vw, 5.6rem); line-height: 1.04; }
.say-hot { color: var(--lav); }
/* The underline under the lavender phrase is chalked in, left to right, as the section passes. */
.js:not(.rm) .say-hot.u { background-size: calc(clamp(0, (var(--p, 1) - 0.3) / 0.22, 1) * 100%) 0.22em; --lo: 0.3; --hi: 0.52; }
.proofs { list-style: none; margin: 12vh 0 0 auto; padding: 0; max-width: 44rem; display: grid; gap: 0; }
.proofs li { position: relative; font-size: clamp(1rem, 1.25vw, 1.15rem); color: var(--muted); border-top: 2px dashed color-mix(in srgb, var(--paper) 22%, transparent); padding: 1.5rem 0 1.5rem 3.2rem; }
.proofs strong { display: block; color: var(--paper); font-weight: 700; font-size: clamp(1.25rem, 1.7vw, 1.5rem); line-height: 1.2; margin-bottom: 0.3em; }
.tick { position: absolute; left: 0; top: 1.6rem; width: 30px; height: 30px; }
/* Each proof rises in whole, by opacity, and its tick is chalked on as it lands. */
.js .proofs li { --r: clamp(0, (var(--p) - 0.18 - var(--k, 0) * 0.04) / 0.1, 1); opacity: var(--r); translate: 0 calc((1 - var(--r)) * 28px); --lo: calc(0.18 + var(--k, 0) * 0.04); --hi: calc(0.28 + var(--k, 0) * 0.04); }
.js .proofs li:nth-child(2) { --k: 1; }
.js .proofs li:nth-child(3) { --k: 2; }
.js:not(.rm) .tick path { stroke-dasharray: 1; stroke-dashoffset: calc(1 - clamp(0, (var(--r) - 0.4) / 0.6, 1)); }

/* The offer: five tiers by name, what each holds; the name crossing the middle is the one being written. */
.offer { position: relative; padding: 16vh clamp(16px, 4vw, 56px); }
.offer-h { margin: 0 0 8vh; font-size: clamp(2.2rem, 4.4vw, 4.2rem); line-height: 1; }
.tiers { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(32px, 5vw, 80px); }
.tier-kind { margin: 0 0 0.6rem; font-family: "Caveat", cursive; font-weight: 600; font-size: 2rem; line-height: 1.1; color: var(--cyan); }
.tier { position: relative; border-top: 2px dashed color-mix(in srgb, var(--paper) 22%, transparent); padding: 1.3rem 0 1.5rem; }
.tier h3 { margin: 0 0 0.25em; font-size: clamp(2rem, 3.4vw, 3.2rem); line-height: 1; }
.tier p { margin: 0; max-width: 44ch; color: var(--muted); }
/* Each service asks for a quote: a hand-written lavender link under its description. */
.tier .quote { display: inline-flex; align-items: center; min-height: 44px; margin-top: 0.35em; font-family: "Caveat", cursive; font-weight: 600; font-size: 1.65rem; line-height: 1.1; color: var(--lav); text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 0.18em; }
.tier .quote:hover { color: var(--cyan); }
.tier .quote:focus-visible { outline: 2px solid var(--cyan); outline-offset: 4px; border-radius: 4px; }
@media (max-width: 900px) { .tiers { grid-template-columns: 1fr; } }
/* Each row's rule is chalked over in cyan from the left as its name crosses the middle. */
.js:not(.rm) .tier::before { content: ""; position: absolute; left: 0; top: -4px; height: 0.4em; width: calc(var(--hot, 0) * 100%); background: var(--chalkline) left center / 100% 100% no-repeat; opacity: calc(0.4 + var(--hot, 0) * 0.6); }

/* With the scene drawn, the statement, offer and process sit on it: the house carries through behind
   them beside their type, so these sections keep the board showing and the finale loses its covering edge. */
html.js.scene-on:not([data-rung="still"]):not(.rm) .finale::before { display: none; }

/* The process, in one line that lights word by word, then five numbered chalk circles on a dashed line. */
.process { position: relative; padding: 18vh clamp(16px, 4vw, 56px) 22vh; }
.process-line { margin: 0; max-width: 17ch; font-family: "Cabin Sketch", serif; font-weight: 700; font-size: clamp(2.1rem, 5vw, 5rem); line-height: 1.06; color: var(--paper); }
.js .process-line .word > span { --lit: clamp(0, (var(--p) - 0.12) * 3.4 * var(--n) - var(--i), 1); color: color-mix(in oklab, var(--paper) calc(var(--lit) * 100%), var(--muted)); --lo: calc(0.12 + var(--i) / (3.4 * var(--n))); --hi: calc(0.12 + (var(--i) + 1) / (3.4 * var(--n))); }
/* The word being lit flashes cyan for a moment, then settles to chalk. */
.js:not(.rm) .process-line .word > span { --heat: clamp(0, var(--lit) * (1 - var(--lit)) * 4, 1); color: color-mix(in oklab, var(--cyan) calc(var(--heat) * 100%), color-mix(in oklab, var(--paper) calc(var(--lit) * 100%), var(--muted))); }
.rm .process-line .word > span { color: var(--paper); }
.steps { display: flex; justify-content: center; margin: 9vh 0 0; padding: 0; max-width: min(1080px, 56vw); position: relative; }
.steps::before { content: ""; position: absolute; left: 10%; right: 10%; top: 31px; border-top: 3px dashed color-mix(in srgb, var(--blue) 60%, transparent); }
.steps li { list-style: none; flex: 1; position: relative; text-align: center; font-size: 0.98rem; color: var(--paper); }
.steps i { display: grid; place-items: center; width: 64px; height: 64px; margin: 0 auto 12px; position: relative; font-style: normal; font-family: "Cabin Sketch", serif; font-weight: 700; font-size: 1.9rem; color: var(--paper); background: var(--stage); border-radius: 50%; }
.steps i svg { position: absolute; inset: -4px; width: 72px; height: 72px; }
/* The circles are chalked round one after another as the line finishes lighting. */
.js:not(.rm) .steps li { --c: clamp(0, (var(--p, 1) - 0.36 - var(--k, 0) * 0.035) / 0.07, 1); opacity: calc(0.25 + var(--c) * 0.75); --lo: calc(0.36 + var(--k, 0) * 0.035); --hi: calc(0.43 + var(--k, 0) * 0.035); }
.js:not(.rm) .steps li:nth-child(2) { --k: 1; } .js:not(.rm) .steps li:nth-child(3) { --k: 2; } .js:not(.rm) .steps li:nth-child(4) { --k: 3; } .js:not(.rm) .steps li:nth-child(5) { --k: 4; }
.js:not(.rm) .steps i path { stroke-dasharray: 1; stroke-dashoffset: calc(1 - var(--c)); }
@media (max-width: 767px) {
  .steps { flex-direction: column; align-items: flex-start; gap: 14px; margin-top: 6vh; max-width: none; }
  .steps::before { left: 31px; right: auto; top: 20px; bottom: 20px; border-top: 0; border-left: 3px dashed color-mix(in srgb, var(--blue) 60%, transparent); }
  .steps li { display: flex; align-items: center; gap: 16px; text-align: left; }
  .steps i { margin: 0; flex: none; }
}

/* The finale: where the house comes back, door open, beside the ask. */
.finale { position: relative; }
/* The scene rises into view under a soft edge, never a hard line under the process. */
.finale::before { content: ""; position: absolute; inset: 0 0 auto; height: 45vh; background: linear-gradient(var(--stage), color-mix(in oklab, var(--stage) 0%, transparent)); pointer-events: none; z-index: 1; }
.finale-pin { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr); align-items: end; padding: 96px clamp(16px, 3.6vw, 52px) 8vh; place-items: initial; z-index: 2; }
.fin-house { grid-column: 2; grid-row: 1; align-self: stretch; min-height: 50vh; background: url(still-390.webp) center 0 / auto 100% no-repeat; mix-blend-mode: screen; opacity: 0.8; }
html.scene-on:not([data-rung="still"]) .fin-house { background: none; }
.ask { grid-column: 1; grid-row: 1; display: grid; gap: 1.1rem; justify-items: start; max-width: 40rem; align-self: end; }
.ask h2 { margin: 0; font-size: clamp(3rem, 7.2vw, 6.8rem); line-height: 1; }
.ask p { margin: 0 0 0.6rem; color: var(--paper); font-size: clamp(1.02rem, 1.25vw, 1.15rem); max-width: 40ch; }
@media (orientation: portrait), (max-width: 767px) {
  .finale-pin { grid-template-columns: 1fr; grid-template-rows: 1fr auto; }
  .fin-house { grid-column: 1; grid-row: 1; min-height: 34vh; }
  .ask { grid-column: 1; grid-row: 2; }
}
.no-js .finale-pin { min-height: 90vh; }

/* The chalk tray: wood, a stick of each colour and the eraser, above the footer. */
.tray { position: relative; z-index: 1; height: 34px; margin: 0 clamp(16px, 3.4vw, 48px); border-radius: 4px 4px 2px 2px; background: linear-gradient(180deg, #8a6440, #5e4129 60%, #4a3220); box-shadow: 0 8px 18px -8px rgba(0, 0, 0, 0.6), inset 0 2px 0 rgba(255, 255, 255, 0.18); }
.tray i { position: absolute; top: -9px; height: 13px; border-radius: 3px 6px 6px 3px; box-shadow: inset 0 -3px 0 rgba(0, 0, 0, 0.12); }
/* Each stick sits at its share of the tray (8, 15, 22, 29%) or one gap past the stick before it, whichever is
   further right, so on a wide tray they keep their spread and on a narrow one they never overlap. */
.tray { --g: 12px; --w1: 70px; --w2: 54px; --w3: 62px; --w4: 44px; }
.tray i:nth-child(1) { left: 8%; width: var(--w1); }
.tray i:nth-child(2) { left: max(15%, calc(8% + var(--w1) + var(--g))); width: var(--w2); }
.tray i:nth-child(3) { left: max(22%, calc(15% + var(--w2) + var(--g)), calc(8% + var(--w1) + var(--w2) + 2 * var(--g))); width: var(--w3); }
.tray i:nth-child(4) { left: max(29%, calc(22% + var(--w3) + var(--g)), calc(15% + var(--w2) + var(--w3) + 2 * var(--g)), calc(8% + var(--w1) + var(--w2) + var(--w3) + 3 * var(--g))); width: var(--w4); }
/* A phone's tray is too short for full-length sticks beside the eraser: half-length sticks, a smaller gap. */
@media (max-width: 479px) { .tray { --g: 8px; --w1: 35px; --w2: 27px; --w3: 31px; --w4: 22px; } }
.tray .e { top: -20px; width: 120px; height: 24px; right: 70px; border-radius: 4px; background: linear-gradient(180deg, #3f3a36 0 40%, #c9b79c 40%); }
@media (max-width: 767px) { .tray .e { right: 24px; width: 90px; } }

/* The footer: the name and its copyright at the left, the Privacy link at the right, stacked and left-aligned at 720px
   and narrower, with the Dame Digital line (family.css) wrapping onto its last row. Every line 0.875rem; the
   link is underlined at rest too, since chalk against muted is under 3:1 and colour alone would not mark it. */
.foot { position: relative; z-index: 1; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 1rem 2rem; padding: 36px clamp(16px, 3.6vw, 52px) 40px; border-top: 1px solid var(--rule); background: var(--stage); font-size: 0.875rem; line-height: 1.5; color: var(--muted); }
.foot p { margin: 0; }
.foot .foot-name { font-family: "Cabin Sketch", serif; font-weight: 700; color: var(--paper); }
/* The privacy page's link sits at the right (2026-10-22), under the name in the stack below 720px. */
.foot .foot-links { margin-left: auto; }
.foot a { display: inline-flex; align-items: center; min-height: 44px; color: var(--paper); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 0.3em; text-decoration-color: color-mix(in srgb, var(--paper) 45%, transparent); }
@media (hover: hover) { .foot a:hover { text-decoration-color: var(--cyan); text-decoration-thickness: 2px; } }
@media (max-width: 720px) { .foot { flex-direction: column; align-items: flex-start; justify-content: flex-start; gap: 16px; padding: 32px clamp(16px, 3.6vw, 52px); } .foot .foot-links { margin-left: 0; } }

/* The viewer. */
.viewer { position: fixed; inset: 0; z-index: 50; overflow: auto; overscroll-behavior: contain; }
.viewer-in { min-height: 100%; background: var(--grain), var(--stage); padding: 0 0 10vh; }
.viewer-close { position: fixed; top: 16px; right: clamp(16px, 3vw, 40px); z-index: 2; padding: 0.7em 1.2em; border: 2px dashed color-mix(in srgb, var(--paper) 40%, transparent); border-radius: 10px 14px 9px 13px; background: rgba(14, 17, 22, 0.9); color: var(--paper); font: 700 0.95rem "Atkinson Hyperlegible", sans-serif; cursor: pointer; }
.viewer-close:hover { border-color: var(--cyan); }
.viewer-lead { display: block; width: 100%; height: 78vh; overflow: clip; }
.viewer-lead img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: top; }
.viewer-lead.pair { display: flex; }
.viewer-lead.pair img { width: 50%; }
.viewer-text { padding: 6vh clamp(16px, 4vw, 56px) 3vh; display: grid; gap: 0.6rem; max-width: 60rem; }
.viewer-text h2 { margin: 0; font-size: clamp(2.6rem, 6vw, 5.6rem); line-height: 1; }
.viewer-text p { margin: 0; font-size: clamp(1.05rem, 1.3vw, 1.2rem); max-width: 50ch; }
.viewer-text .made { color: var(--cyan); font-family: "Caveat", cursive; font-weight: 600; font-size: 1.7rem; }
.viewer .more { display: block; padding: 0 clamp(16px, 4vw, 56px); }

@media (prefers-reduced-motion: reduce) {
  .plate-img { transition: none; }
  .hl .u, .arrow path { animation: none; }
}
/* A tall screen: the house stands below the steps, so they take the width. */
@media (orientation: portrait) { .steps { max-width: none; } }
@media (prefers-reduced-motion: reduce) { .js .stage { transition: none; } }

/* The oldest browsers the flagship serves (Chromium 109, Firefox ESR 115) have no color-mix(): a rule
   using it is dropped whole there, so each gets its plain rgba equal here, and the process line lights
   word by word by opacity instead of colour, so it still moves. */
@supports not (color: color-mix(in srgb, red 50%, blue)) {
  .cta { box-shadow: 0 0 0 2px rgba(210, 194, 255, 0.45), 3px 4px 0 0 rgba(231, 235, 240, 0.18); }
  .cta:hover { box-shadow: 0 0 0 2px rgba(210, 194, 255, 0.55), 4px 5px 0 0 rgba(231, 235, 240, 0.22); }
  .proofs li, .tier { border-top: 2px dashed rgba(231, 235, 240, 0.22); }
  .steps::before { border-top: 3px dashed rgba(74, 143, 224, 0.6); }
  .finale::before { background: linear-gradient(#0e1116, rgba(14, 17, 22, 0)); }
  .viewer-close { border: 2px dashed rgba(231, 235, 240, 0.4); }
  .js .process-line .word > span, .js:not(.rm) .process-line .word > span { color: var(--paper); opacity: calc(0.4 + var(--lit) * 0.6); }
  .rm .process-line .word > span { opacity: 1; }
  @media (max-width: 767px) { .steps::before { border-top: 0; border-left: 3px dashed rgba(74, 143, 224, 0.6); } }
}
