/* Site styles. Every colour, font, size and space comes from tokens.css. */

/* Base */

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

html {
  --gutter: var(--space-4);
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 72px; /* room for the pinned nav */
}

@media (min-width: 720px) {
  html { --gutter: var(--space-5); }
}

@media (min-width: 1200px) {
  html { --gutter: var(--page-margin); }
}

body {
  margin: 0;
  background: var(--color-paper);
  color: var(--color-ink);
  font-family: var(--type-body-family);
  font-size: var(--type-body-size);
  line-height: var(--type-body-line-height);
  font-weight: var(--type-body-weight);
  letter-spacing: var(--type-body-tracking);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, p, ol, ul, figure {
  margin: 0;
}

img {
  display: block;
  max-width: 100%;
  height: auto;
}

:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--color-paper), 0 0 0 4px var(--color-focus-ring);
}

/* Type styles, one class per style in tokens.json. Sizes scale down on narrow screens and cap at the token. */

.statement {
  font-family: var(--type-statement-family);
  font-size: clamp(calc(var(--type-statement-size) * 0.66), 2.2vw + 18px, var(--type-statement-size));
  line-height: var(--type-statement-line-height);
  font-weight: var(--type-statement-weight);
  letter-spacing: var(--type-statement-tracking);
  color: var(--color-ink);
}

.intro {
  font-family: var(--type-intro-family);
  font-size: clamp(calc(var(--type-intro-size) * 0.85), 1vw + 17px, var(--type-intro-size));
  line-height: var(--type-intro-line-height);
  font-weight: var(--type-intro-weight);
  letter-spacing: var(--type-intro-tracking);
}

.title {
  font-family: var(--type-title-family);
  font-size: clamp(calc(var(--type-title-size) * 0.7), 2vw + 14px, var(--type-title-size));
  line-height: var(--type-title-line-height);
  font-weight: var(--type-title-weight);
  letter-spacing: var(--type-title-tracking);
  color: var(--color-ink-muted);
}

.closing {
  font-family: var(--type-closing-family);
  font-size: clamp(calc(var(--type-closing-size) * 0.8), 0.6vw + 15px, var(--type-closing-size));
  line-height: var(--type-closing-line-height);
  font-weight: var(--type-closing-weight);
  letter-spacing: var(--type-closing-tracking);
}

.eyebrow {
  font-family: var(--type-label-family);
  font-size: var(--type-label-size);
  line-height: var(--type-label-line-height);
  font-weight: var(--type-label-weight);
  letter-spacing: var(--type-label-tracking);
  text-transform: var(--type-label-transform);
  color: var(--color-ink-muted);
}

/* The water (2 Nov): the cyanotype surface, drawn by wave.js on a canvas fixed behind the whole of Home, so the
   hero and About sit on one print and the hand ripples it anywhere on the page. Without JS or WebGL the ground
   below stands in: prussian with one soft bloom. Home runs in Indigo night, so paper here is prussian. */

.water {
  position: fixed;
  inset: 0;
  z-index: -1;
  background: radial-gradient(60% 55% at 50% 42%, color-mix(in srgb, var(--color-dye) 75%, var(--color-paper)), var(--color-paper) 100%);
  pointer-events: none;
}

.water__canvas {
  display: block;
  width: 100%;
  height: 100%;
}

/* Hero (2 Nov, the renewed direction; regrouped on Chyi's notes of the same day; way E with her polaroid from
   3 to 6 Nov; since 6 Nov, her word: "just the header, a statement of my own, and then my name and my position
   and title"): the statement, the name, the label and the three icons, one group at the centre of the water.
   Nothing else: the fish left with her note, the polaroid with this one. */

.hero {
  position: relative;
  z-index: 2; /* the nav pinned inside it must paint over everything below */
  display: grid;
  align-content: center;
  justify-items: center;
  row-gap: clamp(40px, 7vh, 64px);
  min-height: 100vh;
  min-height: 100svh;
  padding: var(--space-6) var(--gutter);
  overflow-x: clip; /* the halo is wider than a phone */
  color: var(--color-ink-strong);
  text-align: center;
}

/* A soft prussian halo behind the words and the icons (finding 1 of the audit of 2 Nov): the water's cream
   blooms drifted under the words and took them down to 2:1. The halo holds the centre at night ground without
   a visible edge, so the water still moves all round it. The same halo sits behind each project (3 Nov). */
.hero::before,
.project::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: -1;
  width: min(1100px, 140vw);
  height: min(760px, 110svh);
  translate: -50% -50%;
  background: radial-gradient(closest-side, color-mix(in srgb, var(--color-paper) 82%, transparent) 35%, color-mix(in srgb, var(--color-paper) 55%, transparent) 65%, transparent);
  pointer-events: none;
}

/* The group: the words, then the icons, centred. */
.hero__face {
  display: grid;
  justify-items: center;
  row-gap: var(--space-5);
  width: min(100%, 1040px);
}

@media (min-width: 860px) {
  .hero__face {
    row-gap: var(--space-6);
  }
}

.hero__words {
  display: grid;
  justify-items: center;
  row-gap: var(--space-3);
  pointer-events: none; /* the hand ripples the water through the words */
}

/* The name, under the statement since 6 Nov: Nanum Myeongjo, 32px at a laptop width (it was the headline at 56
   from 3 Nov, and 88 before that; "just don't make it so big", Chyi, 3 Nov). */
.hero__who {
  font-family: var(--type-statement-family);
  font-size: clamp(26px, 1.2vw + 14px, 34px);
  line-height: 1.1;
  font-weight: 400;
  letter-spacing: -0.01em;
  color: var(--color-ink-strong);
}


/* The statement, the headline since 6 Nov (way B of the lab). Since 9 Nov two sentences, who she is and her
   principle, at 40px (Chyi: "font size should be 40px"); 30px on a phone, where 40 would run to a dozen lines.
   It sat under the name at 28 from 3 to 6 Nov. */
.hero__line {
  max-width: 21em;
  font-family: var(--type-statement-family);
  font-size: 36px; /* 40 until 11 Nov (Chyi: "make the hero header font size 10% smaller") */
  line-height: 1.3;
  font-weight: 400;
  letter-spacing: var(--type-statement-tracking);
  color: var(--color-ink-strong);
  text-wrap: balance;
  margin-bottom: var(--space-4); /* 40 to the name with the row gap: the line leads, the name follows */
}

/* The label: what she does, in the first second. Mist on prussian, 10.6:1. */
.hero__name {
  color: var(--color-ink);
}

@media (max-width: 719px) {
  .hero__line { font-size: 27px; }
}

/* The reveal: the line, the name, the label and the cue rise one after another, 700ms each, at their --at.
   Shortened on 9 Nov (Chyi: "shorten the reveal animation delay"): the line starts at 0.2s, the cue at 1.1s
   (they were 1.4s and 4.6s). wave.js adds is-revealing once the page has painted; without JS everything is
   simply there. Since 10 Nov the nav is part of the group, under the label (Chyi: "it reveals first in the middle
   after the headlines and my name and my designation"): it rises after the label at its own --at, and the cue
   after it. Should the script never start the reveal, the nav still comes in by itself after five seconds: it
   is the way round the site. */
.js .hero__words > *,
.js .hero__cue {
  opacity: 0;
  translate: 0 var(--reveal-distance);
}

.js .cf-nav--home {
  opacity: 0;
  translate: 0 var(--reveal-distance);
  animation: hero-rise 700ms var(--reveal-easing) 5s both;
}

.js .hero.is-revealing :is(.hero__words > *, .hero__cue),
.js .cf-nav--home.is-revealing {
  animation: hero-rise 700ms var(--reveal-easing) both;
  animation-delay: var(--at, 0s);
}

/* The cue that the work is below (the critique's second point): one caption line at the foot of the hero, the
   last thing to rise. A link to the projects. */
.hero__cue {
  position: absolute;
  inset-inline: 0; /* centred by the margins: the reveal owns translate */
  bottom: var(--space-5);
  width: fit-content;
  margin-inline: auto;
  display: inline-flex;
  align-items: center;
  column-gap: var(--space-1);
  min-height: 44px;
  color: var(--color-ink);
  text-decoration: none;
}

.hero__cue:hover,
.hero__cue:focus-visible {
  color: var(--color-ink-strong);
}

/* Under 860px the hero's words and icons fill the screen, so the cue takes its place in the flow under them
   instead of floating over the icons. */
@media (max-width: 859px) {
  .hero__cue {
    position: static;
  }
}

@keyframes hero-rise {
  to {
    opacity: 1;
    translate: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .js .hero__words > *,
  .js .hero__cue,
  .js .cf-nav--home {
    translate: none;
  }

  .js .hero.is-revealing :is(.hero__words > *, .hero__cue),
  .js .cf-nav--home,
  .js .cf-nav--home.is-revealing {
    animation-name: hero-fade;
    animation-duration: var(--reveal-duration);
  }

  @keyframes hero-fade {
    to { opacity: 1; }
  }
}

/* Site nav (2 Nov, the renewed direction): three hand-drawn icons are the pages, the bag Work, the person About,
   the flower Play, and on an inner page the fish is the way home. Each drawing is a mask filled with the current
   colour, so the same icon is cream on the water and prussian on cream. On hover an icon grows a little and its
   handwritten label appears beneath (the label is always there for assistive tech); the current page's label
   always shows, and on a touch screen every label shows. On Home the icons sit under the hero line; on an inner
   page the current page's icon sits alone top left and the others fold out beside it (.icons--fold), over the
   opening (.icons--over), in cream over a photograph (.icons--on-photo). Past its place the row pins to the top
   as a thin translucent bar (main.js, .is-pinned), with the labels beside the icons so the bar stays thin. */

.icons {
  --glyph: 52px;
  color: var(--color-ink-strong);
}

.icons__list {
  display: flex;
  align-items: end;
  justify-content: center;
  column-gap: clamp(28px, 5vw, 64px);
  margin: 0;
  padding: 0;
  list-style: none;
}

.icons__link,
.icons__home {
  display: grid;
  justify-items: center;
  row-gap: var(--space-1);
  padding: var(--space-1);
  border-radius: var(--radius-sm);
  color: inherit;
  text-decoration: none;
}

.glyph {
  display: block;
  height: var(--glyph);
  background: currentColor;
  -webkit-mask-image: var(--mask);
  mask-image: var(--mask);
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  transition: scale var(--snap-duration) var(--turn-easing);
}

/* Each drawing keeps its own proportions from the Figma; the bag sets the height and the others take theirs. */
.glyph--fish { --mask: url("images/icons/fish.svg"); aspect-ratio: 44.8 / 36; height: calc(var(--glyph) * 0.7); }
.glyph--bag { --mask: url("images/icons/bag.svg"); aspect-ratio: 46.3 / 45.2; }
.glyph--person { --mask: url("images/icons/person.svg"); aspect-ratio: 49.7 / 60.3; height: calc(var(--glyph) * 1.3); }
.glyph--flower { --mask: url("images/icons/flower.svg"); aspect-ratio: 58 / 55.2; height: calc(var(--glyph) * 1.06); }

/* The labels under the drawings, in Spectral capitals like every label on the site (3 Nov: the hand face Chyi
   hated on the sign is gone from here too; her own lettering can replace them when it is scanned). */
.icons__label {
  font-family: var(--font-serif);
  font-size: 12px;
  line-height: 1.4;
  font-weight: 400;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  opacity: 0;
  translate: 0 -4px;
  transition: opacity var(--snap-duration) var(--turn-easing), translate var(--snap-duration) var(--turn-easing);
}

.icons__link:hover .glyph,
.icons__link:focus-visible .glyph {
  scale: 1.18;
}

.icons__link:hover .icons__label,
.icons__link:focus-visible .icons__label,
.icons__link[aria-current] .icons__label {
  opacity: 1;
  translate: none;
}

/* The press answers at once, before the click lands. */
.icons__link:active .glyph,
.icons__home:active .glyph {
  scale: 0.94;
}

@media (hover: none) {
  .icons__label {
    opacity: 1;
    translate: none;
  }
}

/* On Home the three labels are always on (the critique of 3 Nov: a first visitor on a laptop saw three doodles). */
.hero .icons__label {
  opacity: 1;
  translate: none;
}

/* On an inner page (the Figma's Work frame, Chyi's note of 2 Nov on the old row): the current page's icon alone,
   top left, with its label as drawn. The other pages fold out beside it on hover, on focus, on a tap on a touch
   screen (main.js, .is-open), and once when the page opens (.is-peeking), so a first visitor sees they are there.
   The row is only as wide as its contents, so the hover begins at the icon, not anywhere along the top. */
.icons--fold {
  --glyph: 46px;
  position: relative;
  z-index: 10;
  display: flex;
  align-items: start;
  column-gap: var(--space-4);
  width: max-content;
  padding: var(--space-4) var(--gutter);
}

.icons--fold .icons__label {
}

.icons--fold .icons__list {
  align-items: start;
  column-gap: var(--space-4);
}

/* Folded, the other pages are see-through and cannot be clicked, but they stay in the accessibility tree and in
   the tab order (finding 6), and focusing one unfolds the row. */
.icons--fold .icons__list > li {
  opacity: 0;
  translate: -12px 0;
  pointer-events: none;
  transition:
    opacity var(--snap-duration) var(--turn-easing),
    translate var(--turn-duration) var(--turn-easing);
}

.icons--fold .icons__list > li:nth-child(2) { --n: 1; }
.icons--fold .icons__list > li:nth-child(3) { --n: 2; }

.icons--fold:hover .icons__list > li,
.icons--fold:focus-within .icons__list > li,
.icons--fold.is-open .icons__list > li,
.icons--fold.is-peeking .icons__list > li,
.icons--fold.is-pinned .icons__list > li {
  opacity: 1;
  translate: none;
  pointer-events: auto;
  transition-delay: calc(var(--n, 0) * 50ms);
}

/* Pinned, the bar runs the full width of the window, like every pinned bar. */
.icons--fold.is-pinned {
  width: auto;
}

/* On a phone the row keeps its place above the page even where it floats over it on a wider screen. */
@media (max-width: 759px) {
  .icons--fold.icons--over {
    position: relative;
    inset: auto;
  }
}

/* Over whatever opens the page (the batik band on Play, the photograph on a case study). */
.icons--over {
  position: absolute;
  inset: 0 0 auto;
}

.icons--on-photo {
  color: var(--color-paper);
}

/* Past its place the nav pins to the top as a thin bar of translucent paper (2 Nov), so every page is one tap away
   anywhere on the page. main.js puts a sentinel where the nav sits and adds is-pinned once it has scrolled out of
   view. The bar fades in and settles down 8px as it arrives. Under reduced motion it only fades; under reduced
   transparency it is solid paper. On Home and Play, paper is the night ground, so the bar is translucent prussian
   with cream icons. */
.icons__sentinel {
  position: absolute;
  top: 0;
  left: 0;
  width: 1px;
  pointer-events: none;
  visibility: hidden;
}

.icons.is-pinned {
  --glyph: 26px;
  position: fixed;
  inset: 0 0 auto;
  z-index: 30;
  display: flex;
  align-items: center;
  column-gap: var(--space-4);
  padding: var(--space-2) var(--gutter);
  color: var(--color-ink-strong);
  background: color-mix(in srgb, var(--color-paper) 74%, transparent);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  backdrop-filter: blur(18px) saturate(140%);
  animation: bar-in var(--turn-duration) var(--turn-easing);
}

.icons.is-pinned .icons__home {
  position: static;
}

.icons.is-pinned .icons__list {
  align-items: center;
  column-gap: var(--space-3);
}

.icons.is-pinned .icons__link {
  grid-auto-flow: column;
  align-items: center;
  column-gap: var(--space-1);
}

.icons.is-pinned .icons__label {
  font-size: 12px;
}

/* On a cream page the pinned bar is solid paper under a hairline, as a printed guide's running head would be;
   the blur is for the water. */
body:not([data-theme="dark"]) .icons.is-pinned {
  background: var(--color-paper);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  border-bottom: 1px solid var(--color-line);
}

@keyframes bar-in {
  from {
    opacity: 0;
    translate: 0 -8px;
  }
}

@media (prefers-reduced-motion: reduce) {
  @keyframes bar-in {
    from {
      opacity: 0;
      translate: none;
    }
  }
}

@media (prefers-reduced-transparency: reduce) {
  .icons.is-pinned {
    background: var(--color-paper);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
}

/* Works */

.works {
  position: relative;
  display: grid;
  row-gap: var(--space-6);
  padding: var(--space-7) var(--gutter);
}

/* The section opens on one sentence of how I work (26 Oct), in place of the old title and the three steps. */
.works__line {
  max-width: 18em;
  color: var(--color-ink);
}

/* After the boards (1 Nov): one line pointing to Play, the proof that I build as well as design. */
.play-line {
  display: grid;
  justify-items: start;
  padding: var(--space-6) var(--gutter) var(--space-7);
}

.play-line .statement {
  max-width: 18em;
}

/* Paper textures, drawn as masks and filled with token colours. Grain: fine fractal noise in ink.
   Washi: long fibres in paper-raised. Put .tex-grain or .tex-washi on anything positioned. */

:root {
  --tex-grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1.4 0 0 0 -.55'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  --tex-fibre: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='600' height='600'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.004 .06' numOctaves='3' seed='7' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 0 -1.75'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23f)'/%3E%3C/svg%3E");
}

.tex-grain::before,
.tex-washi::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: var(--color-ink);
  -webkit-mask: var(--tex-grain);
  mask: var(--tex-grain);
  opacity: 0.2;
}

.tex-washi::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: var(--color-paper-raised);
  -webkit-mask: var(--tex-fibre);
  mask: var(--tex-fibre);
  opacity: 0.9;
}

.tex-grain > *,
.tex-washi > * {
  position: relative;
  z-index: 1;
}

/* Works: the boards (2 Nov, in place of the album of 26 Oct, which stays in lab/works/c.html). Each project is
   one sheet of a drafting pad: a faint grid on paper, and on it the things from the desk, laid where they fell.
   A tag, the one line, a notebook page in paper corners, the photograph, a print with a pencil note, then the
   result and the link. The three sheets are laid out differently from each other (board--a, b, c), so the section
   reads as a desk and not a template. On a phone the pieces stack in reading order. They fade in one after
   another; see the reveal rules at the end. */

.board {
  --pitch: 28px;
  --rule: color-mix(in srgb, var(--color-line) 55%, transparent);
  position: relative;
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--pitch);
  row-gap: calc(var(--pitch) * 1.5);
  align-items: start;
  padding: calc(var(--pitch) * 1.5) var(--pitch);
  border: 1px solid var(--color-line);
  background-color: var(--color-paper);
  background-image:
    linear-gradient(to right, var(--rule) 1px, transparent 1px),
    linear-gradient(to bottom, var(--rule) 1px, transparent 1px);
  background-size: var(--pitch) var(--pitch);
  background-position: center top;
}

.board > * {
  grid-column: 1 / -1;
}

.board__head {
  display: grid;
  justify-items: start;
  row-gap: var(--space-4);
}

/* The tag: the number and the name in a pill, like a label on a drawing. */
.board__tag {
  display: inline-flex;
  align-items: center;
  column-gap: 0.7em;
  min-height: 34px;
  padding: 0 14px;
  border: 1px solid var(--color-line);
  border-radius: var(--radius-pill);
  background: var(--color-paper-raised);
  font-family: var(--type-label-family);
  font-size: var(--type-label-size);
  line-height: var(--type-label-line-height);
  font-weight: var(--type-label-weight);
  letter-spacing: var(--type-label-tracking);
  text-transform: var(--type-label-transform);
  color: var(--color-ink-strong);
}

.board__no {
  color: var(--color-ink-muted);
}

.board__claim {
  max-width: 13em;
  font-family: var(--type-statement-family);
  font-size: clamp(26px, 1.6vw + 14px, 38px);
  line-height: 1.28;
  letter-spacing: var(--type-statement-tracking);
  color: var(--color-ink);
}

/* A notebook page in paper corners, tilted a little, as on the case studies. */
.board__sketch {
  display: grid;
  row-gap: var(--space-3);
  justify-items: center;
  justify-self: end;
  width: 76%;
  rotate: var(--tilt, -2deg);
}

/* The photograph, with the corners every work photo has. */
.board__photo img {
  width: 100%;
  border-radius: var(--radius-image);
}

/* A print with a white border, tilted, and a pencil note under it. */
.board__detail {
  display: grid;
  row-gap: var(--space-2);
  justify-items: center;
  width: 64%;
  rotate: var(--tilt, 2deg);
}

.board__detail img {
  width: 100%;
  padding: 4px;
  background: var(--color-paper-raised);
  box-shadow: 0 1px 4px color-mix(in srgb, var(--color-ink-strong) 18%, transparent);
}

.board__pencil {
  font-style: italic;
  color: var(--color-ink);
  text-align: center;
}

.board__note {
  display: grid;
  justify-items: start;
  row-gap: var(--space-3);
  align-self: end;
}

.board__result {
  max-width: 20em;
  font-size: clamp(16px, 0.4vw + 14px, 19px);
  line-height: 1.5;
  color: var(--color-ink-strong);
}

.board__link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 var(--space-4);
  border: 1px solid var(--color-ink-strong);
  border-radius: var(--radius-pill);
  color: var(--color-ink-strong);
  font-family: var(--type-caption-family);
  font-size: var(--type-caption-size);
  letter-spacing: var(--type-caption-tracking);
  text-decoration: none;
  transition:
    background var(--snap-duration) var(--turn-easing),
    color var(--snap-duration) var(--turn-easing),
    scale var(--snap-duration) var(--turn-easing);
}

.board__link:hover {
  background: var(--color-ink-strong);
  color: var(--color-paper);
}

/* The press answers at once, before the click lands. */
.board__link:active {
  scale: 0.97;
}

/* From 860px the pieces take their places on the sheet. Three layouts: A (the page top right, the photograph
   across the middle), B (its mirror), C (a tall photograph down the left). */
@media (min-width: 860px) {
  .board {
    --pitch: 32px;
    padding: calc(var(--pitch) * 2);
  }

  .board__sketch,
  .board__detail {
    width: 100%;
    justify-self: stretch;
  }

  .board--a .board__head { grid-area: 1 / 1 / 2 / 8; }
  .board--a .board__sketch { grid-area: 1 / 8 / 2 / 13; }
  .board--a .board__photo { grid-area: 2 / 3 / 3 / 11; }
  .board--a .board__detail { grid-area: 3 / 1 / 4 / 5; }
  .board--a .board__note { grid-area: 3 / 6 / 4 / 12; }

  .board--b .board__sketch { grid-area: 1 / 1 / 2 / 6; }
  .board--b .board__head { grid-area: 1 / 7 / 2 / 13; }
  .board--b .board__photo { grid-area: 2 / 2 / 3 / 12; }
  .board--b .board__detail { grid-area: 3 / 9 / 4 / 12; }
  .board--b .board__note { grid-area: 3 / 1 / 4 / 7; }

  .board--c .board__head { grid-area: 1 / 1 / 2 / 8; }
  .board--c .board__sketch { grid-area: 1 / 9 / 2 / 13; }
  .board--c .board__photo { grid-area: 2 / 1 / 4 / 6; }
  .board--c .board__detail { grid-area: 2 / 8 / 3 / 12; }
  .board--c .board__note { grid-area: 3 / 7 / 4 / 13; }
}

/* A photograph held by four paper corners, as in an album. Used for the notebook pages on the boards and on the
   case studies. Square, like a print. */
.mount {
  position: relative;
  width: 100%;
  aspect-ratio: var(--ar);
}

.mount img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.mount i {
  position: absolute;
  width: 18px;
  height: 18px;
  background: var(--color-ink-strong);
  opacity: 0.82;
}

.mount i:nth-of-type(1) { top: -5px; left: -5px; clip-path: polygon(0 0, 100% 0, 0 100%); }
.mount i:nth-of-type(2) { top: -5px; right: -5px; clip-path: polygon(0 0, 100% 0, 100% 100%); }
.mount i:nth-of-type(3) { bottom: -5px; right: -5px; clip-path: polygon(100% 0, 100% 100%, 0 100%); }
.mount i:nth-of-type(4) { bottom: -5px; left: -5px; clip-path: polygon(0 0, 100% 100%, 0 100%); }

/* Foot (2 Nov, in place of the cloud footer): one line that ends the pages that scroll, Home, Play and the case
   studies. Say hello, the ways to reach me, then the colophon. On Home and Play it sits on prussian; on a case
   study, on cream. */

.foot {
  display: grid;
  row-gap: var(--space-5);
  padding: var(--space-7) var(--gutter) var(--space-5);
}

/* On a case study the next-project row is the page's last word; "Say hello." steps down a size so it does not
   compete (the critique of 3 Nov). */
.cs ~ .foot .foot__line {
  font-size: var(--type-title-size);
}

.foot__hello {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: var(--space-5);
  row-gap: var(--space-3);
}

.foot__links {
  display: flex;
  flex: none; /* the three stay together: beside "Say hello." where there is room, else on their own row (the
                 phone review of 9 Nov: Behance dropped under the other two) */
  max-width: 100%;
  flex-wrap: wrap;
  align-items: center;
  column-gap: var(--space-3);
  row-gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* The ways to reach me are icons (Chyi's note of 2 Nov): an envelope, LinkedIn and Behance drawn as line marks
   in the manner of the nav, filled with the current colour, each named for assistive tech and labelled on hover
   in the nav's label (Spectral capitals, 12px tracked; the 18px of the hand-face days went on 9 Nov, when three
   labels that size ran past the gutter on a phone). The two still waiting for an address have no href and a
   dotted ring (.todo). */
.foot__icon {
  --glyph: 24px;
  position: relative;
  display: grid;
  place-items: center;
  min-width: 44px; /* a 44px target (finding 7) */
  min-height: 44px;
  padding: var(--space-1);
  border-radius: var(--radius-sm);
  color: var(--color-ink-strong);
  text-decoration: none;
}

.foot__icon .icons__label {
  position: absolute;
  top: 100%;
  left: 50%;
  translate: -50% -4px;
  white-space: nowrap;
}

.foot__icon:hover .glyph,
.foot__icon:focus-visible .glyph {
  scale: 1.15;
}

.foot__icon:hover .icons__label,
.foot__icon:focus-visible .icons__label {
  opacity: 1;
  translate: -50% 0;
}

.foot__icon[href]:active .glyph {
  scale: 0.94;
}

.foot__icon.todo {
  padding: var(--space-1);
  background: none;
  outline: 1.5px dotted var(--color-highlight);
  outline-offset: 1px;
}

.glyph--mail { --mask: url("images/icons/mail.svg"); aspect-ratio: 32 / 24; height: calc(var(--glyph) * 0.78); }
.glyph--linkedin { --mask: url("images/icons/linkedin.svg"); aspect-ratio: 1; }
.glyph--behance { --mask: url("images/icons/behance.svg"); aspect-ratio: 36 / 32; }

/* On a touch screen every label shows (above), so here the labels take their place under the icons instead of
   floating, and the colophon wraps under them. */
@media (hover: none) {
  .foot__icon .icons__label {
    position: static;
    translate: none;
  }
}

.foot__meta {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-3);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-line);
}

/* On a phone the colophon and Back to top do not share a line (the phone review of 9 Nov): one under the other,
   both at the left. Back to top keeps its 44px box, so the gap is the small step. */
@media (max-width: 639px) {
  .foot__meta {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-1);
  }
}

.foot__back {
  display: inline-flex;
  align-items: center;
  min-height: 44px; /* a 44px target (finding 7) */
  border-radius: var(--radius-sm);
  text-decoration: none;
}

.foot__back:hover {
  color: var(--color-ink-strong);
}

/* Press feedback (2 Nov): every control answers on pointer-down, before the click lands, so nothing feels dead.
   Text links dim for the press; buttons shrink a touch (the nav icons have theirs above). Quick, with a firm stop. */
.text-link,
.foot__back {
  transition: opacity var(--snap-duration) var(--turn-easing);
}

.text-link[href]:active,
.foot__back:active {
  opacity: 0.55;
}

.pill-button {
  transition: background var(--snap-duration) var(--turn-easing), scale var(--snap-duration) var(--turn-easing);
}

.pill-button:active {
  scale: 0.97;
  background: var(--color-kabus);
}

.caption {
  font-family: var(--type-caption-family);
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-line-height);
  font-weight: var(--type-caption-weight);
  letter-spacing: var(--type-caption-tracking);
  color: var(--color-ink-muted);
}

.text-link {
  color: inherit;
  text-decoration: underline;
  text-decoration-thickness: from-font;
  text-underline-position: from-font;
  border-radius: var(--radius-sm);
}

.text-link[href]:hover {
  color: var(--color-ink-strong);
}

/* About (6 Nov, its own page again at site/about/, Chyi: "side bar is the best" of the five in lab/about/five.html;
   her words on the old section of Home: "the cutout notebook is very distasteful", "something more minimal", the
   moving water "too distracting"): a cream page, no water, two faces. The case studies' sidebar grown into About:
   a sticky column with the print, the name, the facts, the resume and the ways to reach her; beside it the story
   and the years as a table. The notebook, the glass and the sliding timeline are in git history. */

.ab {
  display: grid;
  grid-template-columns: minmax(200px, 24%) minmax(0, 1fr);
  column-gap: clamp(40px, 6vw, 96px);
  align-items: start;
  width: min(100% - 2 * var(--gutter), 1180px);
  margin: 0 auto;
  padding: calc(var(--space-5) * 2) 0 var(--space-6); /* under the centred nav since 9 Nov, as the case studies */
}

.ab-side {
  position: sticky;
  top: var(--space-6);
  display: grid;
  row-gap: var(--space-4);
}

.ab-print {
  display: block;
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  object-position: center 20%;
  border-radius: var(--radius-image);
}

.ab-name {
  font-family: var(--type-statement-family);
  font-size: 32px;
  line-height: 1.1;
  font-weight: 400;
  color: var(--color-ink-strong);
}

/* A small tracked label in capitals, as the nav labels and the sidebar facts are set. */
.caps {
  font-family: var(--font-serif);
  font-size: 12px;
  line-height: 1.4;
  font-weight: 400;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--color-ink-muted);
}

.ab-facts {
  display: grid;
  row-gap: var(--space-3);
  margin: 0;
}

.ab-facts dd {
  margin: var(--space-1) 0 0;
  font-size: 17px;
  line-height: 1.4;
  color: var(--color-ink-strong);
}

.ab-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 17px;
}

.ab-main {
  display: grid;
  row-gap: var(--space-6);
}

.ab-bio {
  display: grid;
  row-gap: var(--space-4);
  max-width: 28em;
  font-size: clamp(19px, 0.5vw + 16px, 24px);
  line-height: 1.5;
  color: var(--color-ink);
}

.ab-bio strong {
  font-weight: 400;
  color: var(--color-ink-strong);
}

.ab-years {
  display: grid;
  row-gap: var(--space-3);
}

/* The years as a table: the years, the place with the role under it, the one line. */
.ab-table {
  display: grid;
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--color-line);
}

.ab-table li {
  display: grid;
  grid-template-columns: 6em 13em minmax(0, 1fr);
  column-gap: var(--space-4);
  padding: var(--space-4) 0;
  border-bottom: 1px solid var(--color-line);
  font-size: 17px;
  line-height: 1.45;
}

.ab-table__years {
  font-variant-numeric: tabular-nums;
  color: var(--color-ink-muted);
}

.ab-table__where {
  color: var(--color-ink-strong);
}

.ab-table__where small {
  display: block;
  font-size: 15px;
  color: var(--color-ink);
}

.ab-table__line {
  font-weight: 300;
  color: var(--color-ink);
}

/* Under 860px the sidebar stops being one: a small print, then the name and the facts, then the story, one
   column. */
@media (max-width: 859px) {
  .ab {
    grid-template-columns: 1fr;
    row-gap: var(--space-6);
  }

  .ab-side {
    position: static;
  }

  .ab-print {
    width: 160px;
  }

  .ab-table li {
    grid-template-columns: 5em minmax(0, 1fr);
  }

  .ab-table__line {
    grid-column: 2;
  }
}

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

/* Outline pill, the secondary button. Edged in line-strong because people operate it. */
.pill-button {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 var(--space-4);
  border: 1px solid var(--color-line-strong);
  border-radius: var(--radius-pill);
  font-family: var(--type-caption-family);
  font-size: var(--type-caption-size);
  letter-spacing: var(--type-caption-tracking);
  color: var(--color-ink);
  cursor: pointer;
}

.pill-button:hover {
  background: var(--color-kabus);
}

.pill-button:focus-within {
  box-shadow: 0 0 0 2px var(--color-paper), 0 0 0 4px var(--color-focus-ring);
}

/* Play (2 Nov, the renewed direction): a drafting board. The page is cream grid paper; the board is a row of
   sheets that slides sideways (slider.js): the desk, with the title block drawn in CSS and Chyi's words in it,
   Pocket Personal Trainer on a phone, the rocket and the other doodles from the Figma, the pan and the food
   photograph; then the stamp maker, live; then the workshop. On a phone the sheets stack and everything on them
   flows in order. The dark theme and komorebi are gone with the band. */

.page--play {
  --pitch: 32px;
  --rule: color-mix(in srgb, var(--color-line) 70%, transparent);
  background-color: var(--color-paper);
  background-image:
    linear-gradient(to right, var(--rule) 1px, transparent 1px),
    linear-gradient(to bottom, var(--rule) 1px, transparent 1px);
  background-size: var(--pitch) var(--pitch);
}

/* The pad (Chyi's note of 2 Nov, second round: "scroll down to move to the next page", not sideways): the
   sheets stack, each one screen tall from 760px, with a dashed tear line between them, and the page scrolls on
   to the foot. (.pad, not .board: the Works boards in the lab own that name.) */
.pad {
  --sheet-h: calc(100svh - 120px); /* less the nav row above the first sheet */
  display: grid;
}

.sheet {
  position: relative;
  display: grid;
  row-gap: var(--space-5);
  width: 100%;
  padding: var(--space-5) var(--gutter) var(--space-6);
}

.sheet + .sheet {
  border-top: 1px dashed var(--color-line-strong);
}

.sheet > * {
  min-width: 0;
}

/* The title block, as on a drafting sheet, with my words in it. */
.titleblock {
  display: grid;
  grid-template-columns: auto auto;
  justify-self: end;
  border: 1.5px solid var(--color-ink-strong);
  background: var(--color-paper);
  font-family: var(--font-serif);
  font-size: 11px;
  line-height: 1.4;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--color-ink-strong);
}

.titleblock > div {
  display: flex;
  gap: var(--space-2);
  padding: 6px 12px;
  border-top: 1px solid var(--color-ink-strong);
  border-left: 1px solid var(--color-ink-strong);
}

.titleblock > div:nth-child(-n + 2) { border-top: 0; }
.titleblock > div:nth-child(odd) { border-left: 0; }

.titleblock b {
  font-weight: 400;
  color: var(--color-ink-muted);
}

/* The vertical note along the right edge of the sheet. */
.sheet__margin {
  font-family: var(--font-serif);
  font-size: 11px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--color-ink-muted);
}

/* A torn-paper label with a typed name, on the desk and on the Work page. The paper is cream, so the label keeps
   the light tokens on a night page. */
.label {
  display: inline-grid;
  place-items: center;
  min-width: 220px;
  padding: 22px 56px;
  white-space: nowrap;
  background: url("images/work/torn-label.png") center / 100% 100% no-repeat;
  font-family: var(--type-label-typed-family);
  font-size: var(--type-label-typed-size);
  line-height: var(--type-label-typed-line-height);
  letter-spacing: var(--type-label-typed-tracking);
  color: var(--color-ink-strong);
  text-decoration: none;
}

/* The phone that will hold Pocket Personal Trainer. */
.phone {
  width: min(100%, 260px);
  aspect-ratio: 9 / 19;
  padding: 10px;
  border-radius: 36px;
  background: var(--color-ink-strong);
  box-shadow: var(--shadow-float);
}

.phone__screen.phone__screen--live {
  padding: 0;
  overflow: hidden;
}

.label--ppt a {
  color: inherit;
  text-decoration: none;
}

.phone__frame {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
  border-radius: 28px;
  background: var(--color-paper-raised);
}

.phone__screen {
  display: grid;
  place-items: center;
  height: 100%;
  padding: var(--space-4);
  border-radius: 28px;
  background: var(--color-paper-raised);
  text-align: center;
}

.doodle {
  display: block;
  height: auto;
}

.doodle--camera {
  padding: 0;
  border: 0;
  background: none;
}

.doodle--camera:enabled { cursor: pointer; }

.doodle--camera img {
  display: block;
  width: 100%;
  height: auto;
}

/* The food photograph, pinned as a print with a white border. */
.print {
  margin: 0;
  padding: 6px;
  background: var(--color-paper-raised);
  box-shadow: var(--shadow-float);
}

.print img {
  width: 100%;
  height: auto;
  border-radius: 2px;
}

/* The print as a link to her cooking video (10 Nov): the "view work" disc (.collage__view) says "watch video". With a
   pointer it follows the hand over the print (main.js) and the arrow hides; on a touch screen it rests in the middle,
   a little smaller, so the print still reads as a video. */
.disc-link {
  position: relative;
  display: block;
  color: inherit;
  text-decoration: none;
  -webkit-user-drag: none;
}

.disc-link img {
  transition: scale var(--turn-duration) var(--turn-easing);
}

.disc-link:hover img { scale: 1.015; }
.disc-link:active img { scale: 0.99; }
.disc-link:focus-visible { outline: 2px solid var(--color-focus-ring); outline-offset: 4px; }

.disc-link.has-cursor { cursor: none; }
@media (min-width: 760px) {
  .sheet--desk .disc-link .collage__view > span { rotate: -7deg; } /* the words stay level on the print, tilted from 760px */
  /* Rattan Talks sits in the star's old spot, tilted the other way from the food print. */
  .sheet--desk .print.print--pod { top: 73.6%; left: 47%; width: min(10.5%, var(--desk-height) * 0.19); rotate: -5deg; }
  .sheet--desk .print--pod .collage__view > span { rotate: 5deg; }
}

.print--pod .collage__view { width: 76px; height: 76px; font-size: 14px; }

@media (hover: none) {
  .print--pod .collage__view { top: 76%; } /* resting under the cover's wordmark, not on it */
}

@media (max-width: 759px) {
  .sheet--desk .print--pod { justify-self: center; width: min(100%, 220px); }
}

.disc-link.has-cursor .collage__view {
  top: 0;
  left: 0;
  opacity: 0;
  scale: 0.6;
  will-change: transform;
  transition: opacity var(--snap-duration) var(--turn-easing), scale var(--turn-duration) var(--turn-easing);
}

.disc-link.has-cursor.is-near .collage__view {
  opacity: 1;
  scale: 1;
}

@media (hover: none) {
  .disc-link .collage__view {
    display: grid;
    width: 76px;
    height: 76px;
    font-size: 14px;
  }
}

/* The tools: the stamp maker runs in place; the others wait, hidden, for their URLs. */
.play-card {
  display: grid;
  row-gap: var(--space-3);
  align-content: start;
  width: min(100%, 560px);
  min-width: 0;
}

.play-card[hidden] {
  display: none;
}

.play-card > :first-child {
  margin-bottom: var(--space-2);
}

.play-card__text {
  max-width: 30em;
  font-size: clamp(calc(var(--type-body-size) * 0.8), 0.6vw + 14px, var(--type-body-size));
}

.play-card__well {
  min-width: 0;
  aspect-ratio: 4 / 5;
  border-radius: var(--radius-image);
  background: var(--color-kabus);
}

.play-card__well--slot {
  display: grid;
  place-items: center;
  padding: var(--space-5);
  text-align: center;
}

.play-card__frame {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 5;
  border: 0;
  border-radius: var(--radius-image);
  background: var(--color-kabus);
}

/* Favourite photos: the top print sits over its two neighbours, with room at the sides for their corners. */
.gallery {
  margin: 0;
}

.gallery__frame {
  padding-inline: 5%;
}

.gallery__track {
  position: relative;
  isolation: isolate;
  margin: 0;
  padding: 0;
  list-style: none;
  aspect-ratio: 706 / 470;
  cursor: pointer;
  touch-action: pan-y;
}

.gallery:not(.is-ready) .gallery__track,
.gallery.is-single .gallery__track { cursor: auto; }

.gallery__slide {
  position: absolute;
  inset: 0;
  padding: 1.98% 2.97% 1.84% 2.83%;
  border: 1px solid var(--color-line);
  background: var(--color-paper-raised);
  box-shadow: 0 2px 6px color-mix(in srgb, var(--color-ink-strong) 16%, transparent);
  visibility: hidden;
  pointer-events: none;
}

.gallery__slide img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.gallery__slide--cover img {
  object-fit: cover;
}

/* Without script the first print is the fallback. Only the front photo is exposed to screen readers. */
.gallery:not(.is-ready) .gallery__slide:first-child,
.gallery.is-single .gallery__slide:first-child,
.gallery__slide:is(.is-current, .is-next, .is-previous) { visibility: visible; }

.gallery__slide.is-current { z-index: 3; }
.gallery__slide.is-next { z-index: 2; translate: 2.5% 5%; rotate: 4deg; }
.gallery__slide.is-previous { z-index: 1; translate: -2.5% 5%; rotate: -4deg; }

@media (prefers-reduced-motion: no-preference) {
  .gallery__slide {
    transition: translate var(--turn-duration) var(--turn-easing), rotate var(--turn-duration) var(--turn-easing);
  }
}

.gallery__controls {
  width: max-content;
  margin: max(var(--space-4), 7%) auto 0;
  display: flex;
  align-items: center;
  padding: 0 4px;
  border: 1px solid var(--color-line);
  border-radius: 999px;
  background: var(--color-paper-raised);
  font-family: var(--font-serif);
  font-size: 13px;
  letter-spacing: 0.08em;
  color: var(--color-ink-strong);
  font-variant-numeric: tabular-nums;
}

.gallery:not(.is-ready) .gallery__controls,
.gallery.is-single .gallery__controls { display: none; }

.gallery__button {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  color: inherit;
  cursor: pointer;
}

.gallery__button svg {
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: translate 150ms ease-out;
}

.gallery__button:active svg { translate: 0 1px; }
.gallery__button:focus-visible { outline: 2px solid var(--color-focus-ring); outline-offset: -4px; }

/* On a phone the tools sheet flows: the camera small, the flash and sparkles off. */
@media (max-width: 759px) {
  .sheet--tools .doodle--flash,
  .sheet--tools .doodle--sparkle-big,
  .sheet--tools .doodle--sparkle-small { display: none; }
  .sheet--tools .doodle--camera { width: 140px; justify-self: center; rotate: -4.7deg; }
  .sheet--tools .label--photos { justify-self: start; }
  .sheet--desk .phone { width: min(100%, 320px); aspect-ratio: 432 / 631; }
}

/* From 760px each sheet is one screen tall and the things on the desk take their places. */
@media (min-width: 760px) {
  .sheet {
    display: block;
    height: var(--sheet-h);
    padding: 0;
  }

  .sheet > * {
    position: absolute;
  }

  /* Measured from Chyi's Play frame of 9 Nov (Figma 109:22) on a 1440 x 780 sheet. */
  .sheet--desk {
    --desk-height: var(--sheet-h);
    --rocket-top: 27.3%;
    --rocket-width: min(9vw, var(--desk-height) * 0.19);
    height: var(--desk-height);
  }
  .sheet--desk .titleblock { top: 11.3%; right: 4%; }
  .sheet--desk .sheet__margin { top: 29.2%; right: 1.4%; writing-mode: vertical-rl; }
  .sheet--desk .label--ppt { top: 14%; left: 14%; }
  .sheet--desk .phone { top: 27%; left: 9%; width: clamp(200px, 19vw, 260px); }
  .sheet--desk .doodle--rocket { top: var(--rocket-top); left: 46%; width: var(--rocket-width); }
  .sheet--desk .doodle--lightning { top: 47.3%; left: 87.7%; width: 4%; }
  .sheet--desk .print { top: 29%; left: 60.4%; width: 26%; rotate: 7deg; }
  .sheet--desk .pan { top: 59.9%; left: 59%; width: 27.8%; }
  .sheet--desk .doodle--star { top: 4%; left: 46.5%; width: 4.1%; }
  .sheet--desk .doodle--heart { right: 5%; bottom: 3%; width: 3.6%; }
  /* Off the desk in her frame of 9 Nov; the line stays in the page for a phone, where the sheet flows. */
  .sheet--desk .sheet__note { display: none; }

  /* The stamp maker: the canvas and its controls on the left, the name and the line beside them. */
  .sheet--tools .play-card {
    top: 12%;
    left: 8%;
    display: grid;
    grid-template-columns: minmax(0, 30vw) minmax(0, 22em);
    grid-template-rows: auto auto 1fr;
    column-gap: var(--space-5);
    width: min(84%, 1040px);
  }
  .sheet--tools .play-card[hidden] { display: none; }
  .sheet--tools .stamp-maker { grid-row: 1 / -1; }
  .sheet--tools .stamp-maker__canvas { max-height: 54vh; }
  .sheet--tools .sheet__margin { top: 22%; right: 2.2%; writing-mode: vertical-rl; }
  .sheet--tools .titleblock { top: 4%; right: 4%; }

  /* 9 Nov, Chyi's Play frame (Figma 109:22), measured on a 1440 x 780 sheet: the stamp maker alone on the left, its
     line under it; on the right the camera with its flash and sparkles, the label, and the photographs in their
     print frame. The frame keeps to the sheet's height on short, wide screens. */
  .sheet--tools .play-card {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto;
    width: 30%;
  }
  .sheet--tools .stamp-maker { grid-row: auto; }
  .sheet--tools .stamp-maker__canvas { max-height: calc(var(--sheet-h) * 0.6 - 30px); }
  .sheet--tools .play-card__text { font-size: clamp(17px, 1.53vw, 22px); line-height: 1.45; }
  .sheet--tools .doodle--flash { top: 9.2%; left: 41.6%; width: 8.1%; }
  .sheet--tools .doodle--camera { top: 12.6%; left: 46.8%; width: 14.6%; rotate: -4.7deg; }
  .sheet--tools .doodle--sparkle-big { top: 9.2%; left: 61.6%; width: 2.9%; rotate: 3deg; }
  .sheet--tools .doodle--sparkle-small { top: 15.5%; left: 64.2%; width: 1.96%; rotate: 3deg; }
  .sheet--tools .label--photos { top: min(27.3%, var(--camera-foot) - 68px); left: 68.3%; z-index: 1; }
  /* 10 Nov, Chyi: the stack sat on the camera's foot. It now starts a gap under the camera (whose foot is its top
     plus 0.79 of its width, rotation included, measured), and on a short window the prints shrink so the stack
     and its controls (46px, about 0.662 of the stack's width above them) still end inside the sheet. */
  .sheet--tools {
    --camera-foot: calc(var(--sheet-h) * 0.126 + 14.6vw * 0.79);
    --gallery-top: calc(var(--camera-foot) + var(--space-4));
  }
  .sheet--tools .gallery {
    top: var(--gallery-top);
    left: 43.8%;
    width: min(49%, var(--sheet-h) * 0.82, (var(--sheet-h) - var(--gallery-top) - 46px - var(--space-3)) / 0.662);
  }

  /* The desk's phone, larger since 9 Nov: 432 x 631 on the 1440 x 780 sheet, the app cut off at its foot. */
  .sheet--desk .label--ppt { top: 2.3%; left: 10.8%; }
  .sheet--desk .phone { top: 14%; left: 8.75%; width: min(30%, var(--sheet-h) * 0.555); aspect-ratio: 432 / 631; }
}

@media (min-width: 760px) and (max-width: 1199px) {
  /* Keep the star clear of the title block and the lower print clear of the pan on a narrower desk. */
  .sheet--desk { --desk-height: max(var(--sheet-h), 50vw); }
  .sheet--desk .print.print--pod { left: 41%; }
  .sheet--desk .doodle--star {
    top: calc(var(--rocket-top) + var(--rocket-width) * 421 / 196 + var(--space-4));
    left: 54%;
  }
}

@media (min-width: 760px) and (max-width: 959px) {
  .sheet--tools .label--photos { left: auto; right: 4%; }
}

.stamp-maker {
  display: grid;
  row-gap: var(--space-4);
}

.stamp-maker__canvas {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 5;
  border-radius: var(--radius-image);
  background: var(--color-nila);
}

.stamp-maker.is-dropping .stamp-maker__canvas {
  box-shadow: 0 0 0 2px var(--color-paper), 0 0 0 4px var(--color-focus-ring);
}

.stamp-maker__controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3) var(--space-4);
}

.stamp-maker__pitch {
  flex-basis: 100%;
}

.stamp-maker__slider {
  flex: 1 1 160px;
  min-width: 0;
  min-height: 44px;
  margin: 0;
  accent-color: var(--color-kapas);
}

/* Draft markers: anything in [brackets] still needs Chyi. Visible on purpose until the copy is final. */

.todo {
  background: var(--color-highlight);
  color: var(--color-ink-strong);
  padding: 0 0.15em;
  border-radius: var(--radius-sm);
}

/* True, but the client has to OK it before it goes public. Reads as normal copy with a dotted underline. */
.check {
  text-decoration: underline dotted var(--color-nila-deep);
  text-decoration-thickness: 1.5px;
  text-underline-offset: 0.2em;
}

/* Case study (3 Nov, rebuilt on Chyi's references: the DRIP brand guidelines in Framer for the index, the rules,
   the numbered section heads and the typed captions; Ffern for the warm sidebar with its label-and-pill rows and
   the card laid on the opening photograph; "make it more analog, somewhere in between"; "combine both visuals
   and text balanced in harmony"). Cream paper. From 960px a sidebar runs the full height on the left behind a
   hairline: the torn-paper name, "Case study", the index of sections (the current one marked), and the facts at
   the foot as label-and-pill rows. The column: the opening photograph with the result on a cream card over it,
   then six numbered sections under a rule each (the number at the margin, the title, the one-sentence claim at
   the right), the two or three sentences, and the pictures in a row with a typed caption under each. On a phone
   the sidebar is a block at the top and everything stacks. The type is a step bigger than DRIP's: body 17px,
   captions and the index 14 and 15px, titles up to 56px. Since Chyi's second note of 3 Nov ("I don't like that
   there are too many font types ... keep the entire page to only 2 font types"): Spectral for everything on the
   page, light where DRIP used its small mono, and the hand face only on the nav icons' labels. Four sections:
   the problem, who it's for, the solution, what I've learnt; no Tools row. On 4 Nov Grof tried Kristina Uy's
   layout (a full-bleed opening, no sidebar; git 71ed59a); on 6 Nov Chyi kept this one ("it has a character")
   with Edna Ho's proportions: the sidebar narrow, the showcase wide. */

.cs {
  --col-pad: clamp(24px, 4.5vw, 72px); /* 6 Nov: less, so the showcase has the room */
  --side-pad: clamp(24px, 2vw, 40px);
  display: grid;
}

.cs-side {
  display: grid;
  row-gap: var(--space-5);
  padding: var(--space-4) var(--gutter) var(--space-5);
  border-bottom: 1px solid var(--color-line);
}

.cs-side__top {
  display: grid;
  justify-items: start;
  row-gap: var(--space-3);
}

/* The name, in Spectral light. */
.cs-side__name {
  font-family: var(--font-serif);
  font-size: clamp(26px, 1vw + 18px, 32px);
  line-height: 1.15;
  font-weight: 300;
  color: var(--color-ink-strong);
}

.cs-side__kind {
  font-family: var(--font-serif);
  font-size: 12px;
  line-height: 1.5;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--color-ink-strong);
}

/* The index, as on DRIP: a list, numbered, the current section's number in ochre (main.js). */
.cs-index__head {
  margin-bottom: var(--space-3);
  font-family: var(--font-serif);
  font-size: 12px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--color-ink-muted);
}

.cs-index ol {
  display: grid;
  row-gap: 6px;
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: sec;
}

.cs-index a {
  display: grid;
  grid-template-columns: 2.4em minmax(0, 1fr);
  column-gap: var(--space-2);
  min-height: 40px;
  align-items: center;
  border-radius: var(--radius-sm);
  font-family: var(--font-serif);
  font-size: 15px;
  line-height: 1.4;
  font-weight: 300;
  color: var(--color-ink);
  text-decoration: none;
  counter-increment: sec;
}

.cs-index a::before {
  content: counter(sec, decimal-leading-zero);
  color: var(--color-ink-muted);
}

.cs-index a:hover,
.cs-index a.is-here {
  color: var(--color-ink-strong);
}

.cs-index a.is-here::before {
  color: var(--color-action);
}

/* The next project is a way on, not a section: no number (the critique of 3 Nov). */
.cs-index a.cs-index__next {
  counter-increment: none;
}

.cs-index a.cs-index__next::before {
  content: "";
}

/* The facts, as on Ffern: a label, then the value in a pale pill. A value still waiting for Chyi turns
   the pill cotton. */
.cs-facts {
  display: grid;
  row-gap: var(--space-2);
  margin: 0;
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-line);
}

.cs-facts > div {
  display: grid;
  grid-template-columns: 4rem minmax(0, 1fr);
  column-gap: var(--space-3);
  align-items: center;
}

.cs-facts dt {
  font-family: var(--font-serif);
  font-size: 14px;
  line-height: 1.5;
  color: var(--color-ink);
}

.cs-facts dd {
  justify-self: start;
  max-width: 100%;
  margin: 0;
  padding: 5px 12px;
  border-radius: var(--radius-sm);
  background: var(--color-bloom);
  color: var(--color-ink-strong);
  font-family: var(--font-serif);
  font-size: 14px;
  line-height: 1.5;
  overflow-wrap: break-word;
}

.cs-facts dd:has(.todo) {
  background: var(--color-highlight);
}

.cs-facts dd .todo,
.cs-facts dd .check {
  padding: 0;
  background: none;
}

/* The draft note sits flush in the sidebar; the column's padding is for the column. */
.cs-side .cs-draft {
  padding: 0;
}

.cs-col {
  min-width: 0;
}

/* The opening photograph, across the column, with the result on a cream card over it (Ffern). On a phone the
   card sits under the photograph. */
.cs-open {
  position: relative;
  margin: 0;
  background: var(--color-kabus);
}

.cs-open img {
  width: 100%;
  height: auto;
  max-height: 84svh;
  object-fit: cover;
}

/* A square photo in the wide opening: keep the face in frame. */
.cs-open--high img {
  object-position: center 30%;
}

.cs-open__card {
  display: grid;
  row-gap: var(--space-3);
  padding: var(--space-5) var(--col-pad) var(--space-4);
  background: var(--color-paper);
}

.cs-open__result {
  max-width: 22em;
  font-family: var(--font-serif);
  font-size: clamp(19px, 0.6vw + 15px, 23px);
  line-height: 1.45;
  font-weight: 300;
  color: var(--color-ink-strong);
  text-wrap: pretty;
}

.cs-open__disc {
  font-family: var(--font-serif);
  font-size: 13px;
  line-height: 1.6;
  letter-spacing: 0.06em;
  color: var(--color-ink-muted);
}

.cs-draft {
  padding: var(--space-4) var(--col-pad) 0;
}

/* A section: a rule, the number, the title and the claim on one row, then the sentences, then the pictures. */
.cs-sec {
  display: grid;
  row-gap: var(--space-5);
  padding: var(--space-6) var(--col-pad) var(--space-7);
  border-top: 1px solid var(--color-line);
}

.cs-sec__head {
  display: grid;
  row-gap: var(--space-3);
}

.cs-sec__num {
  font-family: var(--font-serif);
  font-size: 15px;
  line-height: 1.5;
  font-weight: 300;
  letter-spacing: 0.06em;
  color: var(--color-ink-muted);
}

.cs-sec__title {
  font-family: var(--font-serif);
  font-size: clamp(32px, 2.6vw + 12px, 56px);
  line-height: 1.08;
  font-weight: 300;
  letter-spacing: -0.01em;
  color: var(--color-ink-strong);
  text-wrap: balance;
}

.cs-sec__claim {
  max-width: 24em;
  font-family: var(--font-serif);
  font-size: clamp(18px, 0.5vw + 15px, 22px);
  line-height: 1.5;
  font-weight: 300;
  color: var(--color-ink);
  text-wrap: pretty;
}

.cs-sec__body {
  display: grid;
  row-gap: var(--space-3);
  max-width: 34em;
  font-size: 17px;
  line-height: 1.6;
}

.cs-sec__body .caption {
  max-width: 34em;
}

/* Edna's trick: the key phrase in darker ink, so a skimmer can read the highlights alone. */
.key {
  color: var(--color-ink-strong);
}

/* The pictures: flat on the page, in a row of one to three, a light caption under each (DRIP). */
.cs-pics {
  display: grid;
  gap: var(--space-5) var(--space-4);
  margin: 0;
  padding: 0;
  list-style: none;
}

.cs-pics--1 { width: min(100%, 720px); }
.cs-pics--full { width: 100%; }
.cs-pics--tall { width: min(100%, 420px); }

.cs-pics figure {
  display: grid;
  row-gap: var(--space-3);
  min-width: 0;
}

.cs-pics img {
  width: 100%;
  height: auto;
  border-radius: var(--radius-image);
  background: var(--color-kabus);
}

.cs-cap {
  max-width: 30em;
  font-family: var(--font-serif);
  font-size: var(--type-caption-size); /* one caption size across the site (the critique of 3 Nov) */
  line-height: 1.6;
  font-weight: 300;
  letter-spacing: 0.01em;
  color: var(--color-ink-muted);
}

/* A picture still to come: an empty frame with the note inside, at the shape it will have. */
.cs-pics .cs-slot {
  display: grid;
  place-items: center;
  aspect-ratio: var(--ar, 16 / 10);
  padding: var(--space-4);
  border: 1px dashed var(--color-line-strong);
  border-radius: var(--radius-image);
  text-align: center;
}

/* The first sketch (1 Nov): a notebook page tipped in beside the sentences, held by paper corners and tilted a
   little, so the thinking sits beside the shipped thing. Scans replace the stand-ins. */
.cs-sketch {
  display: grid;
  justify-items: center;
  row-gap: var(--space-3);
  width: min(100%, 19em);
  margin: var(--space-2) 0 0;
}

.cs-sketch .mount {
  rotate: var(--tilt, -1.5deg);
}

.cs-sketch figcaption {
  text-align: center;
}

/* Close: the next project as a row under a rule, with an arrow. */
.cs-next {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  column-gap: var(--space-4);
  padding: var(--space-4) 0;
  border-top: 1px solid var(--color-line);
  border-bottom: 1px solid var(--color-line);
  color: inherit;
  text-decoration: none;
  border-radius: var(--radius-sm);
}

.cs-next__label {
  display: block;
  margin-bottom: var(--space-1);
  font-family: var(--font-serif);
  font-size: 12px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--color-ink-muted);
}

.cs-next__name {
  display: block;
  font-family: var(--font-serif);
  font-size: clamp(26px, 1.4vw + 16px, 36px);
  line-height: 1.15;
  font-weight: 300;
  color: var(--color-ink-strong);
}

.cs-next__arrow {
  font-family: var(--font-serif);
  font-size: 28px;
  font-weight: 300;
  color: var(--color-ink-strong);
  transition: translate var(--snap-duration) var(--turn-easing);
}

.cs-next:hover .cs-next__arrow {
  translate: 6px 0;
}

.cs-next:hover .cs-next__name {
  text-decoration: underline;
  text-decoration-thickness: from-font;
  text-underline-offset: 0.12em;
}

@media (min-width: 640px) {
  .cs-pics--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 760px) {
  .cs-pics--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (min-width: 960px) {
  /* The ratio (Chyi, 6 Nov, on Edna Ho's layout: "make sure showcase have more space than the side bar"):
     the sidebar is a seventh of the width at most, the showcase takes the rest. */
  .cs {
    grid-template-columns: clamp(184px, 14vw, 224px) minmax(0, 1fr);
    align-items: start;
  }

  .cs-side {
    position: sticky;
    top: 56px; /* under the pinned nav */
    grid-template-rows: auto 1fr auto;
    height: calc(100svh - 84px); /* the nav's own height before it pins, so the facts are never cut off */
    overflow: auto;
    padding: var(--space-4) var(--space-3) var(--space-5) var(--side-pad);
    border-bottom: 0;
    border-right: 1px solid var(--color-line);
  }

  /* The card over the photograph, bottom right, as on Ffern. */
  .cs-open__card {
    position: absolute;
    right: var(--col-pad);
    bottom: var(--space-5);
    width: min(26em, calc(100% - 2 * var(--col-pad)));
    padding: var(--space-4) var(--space-4) var(--space-3);
    border-radius: 6px;
    box-shadow: var(--shadow-float);
    background: color-mix(in srgb, var(--color-paper) 94%, transparent);
  }

  .cs-sec__head {
    grid-template-columns: 3.5rem minmax(0, 1.25fr) minmax(0, 1fr);
    column-gap: var(--space-5);
    align-items: start;
  }

  .cs-sec__num { padding-top: 0.9em; }
  .cs-sec__claim { padding-top: 0.75em; }

  .cs-sec__body { margin-left: calc(3.5rem + var(--space-5)); }

  /* In the narrow sidebar (6 Nov) a fact's label sits above its pill, so the pill keeps its words on a line. */
  .cs-facts {
    row-gap: var(--space-3);
  }

  .cs-facts > div {
    grid-template-columns: minmax(0, 1fr);
    row-gap: var(--space-1);
    align-items: start;
  }
}

/* Scroll to reveal. Only hidden when JS is running, so the page still reads without it. */

.js .reveal {
  opacity: 0;
  transform: translateY(var(--reveal-distance));
  transition:
    opacity var(--reveal-duration) var(--reveal-easing),
    transform var(--reveal-duration) var(--reveal-easing);
}

.js .reveal.is-visible {
  opacity: 1;
  transform: none;
}

/* A board reveals in parts: each piece in turn, 90ms apart, in the order it was laid down (--i). */
.js .reveal--parts {
  opacity: 1;
  transform: none;
  transition: none;
}

.js .reveal--parts > * {
  opacity: 0;
  translate: 0 var(--reveal-distance);
  transition:
    opacity var(--reveal-duration) var(--reveal-easing),
    translate var(--reveal-duration) var(--reveal-easing);
  transition-delay: calc(var(--i, 0) * 90ms);
}

.js .reveal--parts.is-visible > * {
  opacity: 1;
  translate: none;
}

/* Reduced motion: drop the rise, keep the fade. */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  .js .reveal {
    transform: none;
    transition: opacity var(--reveal-duration) var(--reveal-easing);
  }

  .js .reveal--parts > * {
    translate: none;
    transition: opacity var(--reveal-duration) var(--reveal-easing);
  }
}

/* Work (2 Nov, the renewed direction, brought to the Figma's Work frame on Chyi's notes of the same day; on Home
   since 3 Nov, "I want people to be able to scroll to see my work right after my hero"): the three projects one
   under the other on the water, each a screen, each with the hero's halo behind it. A torn-paper name, three
   tags, three pictures in a flat row at the frame's widths (319, 296 and 307 by 392), and the one line. The row
   of pictures is the link to the case study: with a pointer, "view work" is the cursor over it (main.js); on a
   touch screen the same disc rests on the middle picture, as drawn. The deck of 2 Nov, which turned one project
   at a time (deck.js), went with the Work page. */
.works {
  display: grid;
  row-gap: var(--space-5);
  padding: 0 var(--gutter) var(--space-6);
  overflow-x: clip; /* each project's halo is wider than a phone */
}

.project {
  position: relative;
  display: grid;
  align-content: center;
  justify-items: center;
  justify-self: center;
  width: 100%;
  max-width: 960px; /* one column: the pictures' width, and everything else centred on it */
  min-height: calc(100svh - var(--space-5));
  padding-block: var(--space-5);
  text-align: center;
}

.project > * {
  margin: 0;
}

/* The block's rhythm, on the spacing scale (Chyi, 3 Nov: "always check the margin and spacing"): the name sits
   16 above the tags, the pictures have 40 above and 40 below, the result sits 16 under the line. Nothing touches.
   The measure of the words (the line and the result) is narrower than the pictures, so the eye lands on the row
   and reads down the middle. */
/* The brand's name (11 Nov, Chyi: the torn label was "a bit weird"; "change back to Spectral font type and make it
   not clickable"): Spectral at 24 on a laptop, cream on the water, plain words. The pictures are the way in. */
.project .project__name {
  margin-bottom: var(--space-3);
  font-family: var(--font-serif);
  font-size: clamp(20px, 0.5vw + 16px, 24px);
  font-weight: 400;
  line-height: 1.2;
  color: var(--color-ink-strong);
}
.project .tags {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-2) var(--space-3);
  margin: 0 0 var(--space-5);
  padding: 0;
  list-style: none;
}
.project .collage { margin-bottom: var(--space-5); }

/* As drawn: Spectral in capitals, tracked, in a pill edged in a pale grey. 12px, not the Figma's 10, so it
   reads (finding 4). */
.tags li {
  padding: 4px 16px;
  border: 1px solid color-mix(in srgb, var(--color-ink) 65%, transparent);
  border-radius: var(--radius-pill);
  font-family: var(--font-serif);
  font-size: 12px;
  line-height: 1.5;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--color-ink-strong);
}

/* The three pictures, flat and square-cornered as drawn, the same height, each at the frame's width. The row is
   also capped by the height of the window, so the project stays on one screen. The row is a link; its pictures
   cannot be dragged off it. */
.collage {
  position: relative;
  display: grid;
  grid-template-columns: 319fr 296fr 307fr;
  column-gap: clamp(10px, 2%, 19px);
  width: min(100%, 960px, (100svh - 440px) * 2.45); /* the words, the gaps and the padding come to about 440px */
  color: inherit;
  text-decoration: none;
  -webkit-user-drag: none;
  user-select: none;
}

.collage__pic {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: var(--ar);
  object-fit: cover;
  -webkit-user-drag: none;
  transition: scale var(--turn-duration) var(--turn-easing);
}

.collage__pic--l { --ar: 319 / 392; }
.collage__pic--m { --ar: 296 / 392; }
.collage__pic--r { --ar: 307 / 392; }

/* The pictures as collages (9 Nov, Chyi: "make sure the image collage is like the reference", the Figma's Work
   frame, 423:307, whose three slots hold reference pictures: prints laid at angles on a photograph, a typeset
   page with a photograph laid over it, and cream cards strewn on white with a photograph tucked in the corner).
   All three projects, from her own pictures and words: After Work Bakes first, then Grof and A47 on her yes the
   same day. Each tile is one picture composed in CSS: sizes in cqw and positions in percent, so the composition
   holds at any width, and pieces run off the edges as they do in the reference. The shadows are contact
   shadows, paper lying on paper, not a card floating. */
.tile {
  position: relative;
  overflow: hidden;
  container-type: inline-size;
  isolation: isolate;
  background: var(--color-paper-study);
  --tile-shadow: 0 1px 2px color-mix(in srgb, black 20%, transparent), 0 3px 8px color-mix(in srgb, black 10%, transparent);
}

.tile img {
  position: absolute;
  display: block;
  object-fit: cover;
}

/* Left: three prints laid on a photograph. The places are the same for every project: a wide print top left, a
   tall one on top of it, a square one at the foot running off the edge. After Work Bakes: the dough being shaped
   as the ground, the market stall, the loaf and the bagels as prints. */
.tile__ground {
  inset: 0;
  width: 100%;
  height: 100%;
  object-position: 50% 35%;
}

.tile__print {
  box-sizing: border-box;
  padding: 3.2cqw;
  background: white;
  box-shadow: var(--tile-shadow);
}

.tile__print--wide { left: -6cqw; top: 7%; width: 64cqw; aspect-ratio: 3 / 2; rotate: 3deg; z-index: 1; }
.tile__print--tall { left: 31cqw; top: 15%; width: 56cqw; aspect-ratio: 3 / 4; rotate: -5deg; z-index: 3; }
.tile__print--square { left: 6cqw; top: 64%; width: 54cqw; aspect-ratio: 1; rotate: -3deg; z-index: 2; }

/* Middle: the brand's cover (10 Nov, Chyi's pick of five in lab/tile/five.html: "The Logo Cover is good but make
   sure the logo is centered align in the middle", with "brand's colours as bands along the foot"). The mark large
   in the middle of the card, the one line under it, and the brand's colours as
   bands along the bottom edge, like a paint chip. On each brand's own ground: A47's charcoal with its logo in the card's cream (since 10 Nov; A47 set in its serif before),
   the bakery's cream with its logo, Grof's navy with its logo. Sizes follow the tile's width. */
.tile--cover {
  --bands: min(18cqw, 60px);
  text-align: center;
}
.tile--cover-a47 { background: var(--color-a47-ink); color: var(--color-a47-ground); }
.tile--cover-awb { background: var(--color-awb-cream); color: var(--color-awb-charcoal); }
.tile--cover-grof { background: var(--color-grof-navy); color: white; }

.tile__cover {
  position: absolute;
  inset: 0 0 var(--bands) 0;
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
  row-gap: min(4.5cqw, 16px);
  padding: min(7cqw, 26px) min(7cqw, 26px) min(6cqw, 22px);
  font-family: var(--font-serif);
}

.tile__mark {
  display: grid;
  place-items: center;
  min-height: 0;
}

/* The three logos at one visual size (10 Nov, Chyi: "make sure all three logos are consistent sizes"): each drawn
   shape gets about the same area, so the compact bakery mark and the long Grof wordmark read as equals (widths from
   the drawn proportions: A47 1.36 to 1, the bakery 1.10 to 1, its file with a 2% margin, Grof 2.92 to 1). A47 and
   Grof are solid, heavy letters and the bakery's a thin line drawing, so those two sit about 8% under equal area. */
.tile .tile__logo {
  position: static; /* in the flow of the cover, unlike the tile's other pictures */
  display: block;
  height: auto;
  max-height: 100%;
  object-fit: contain;
}
.tile .tile__logo--a47 {
  width: 42cqw;
  aspect-ratio: 1584 / 1168;
  background: currentColor; /* the card's own ink: A47's logo without its red (Chyi: "dont use the colour") */
  -webkit-mask: url("images/work/a47/logo.svg") center / contain no-repeat;
  mask: url("images/work/a47/logo.svg") center / contain no-repeat;
}
.tile .tile__logo--awb { width: 43.4cqw; }
.tile .tile__logo--grof { width: 63cqw; } /* cut to the logo on the card's own navy */

.tile__cover .tile__lead {
  justify-self: center;
  max-width: 24ch;
  margin: 0;
  font-size: clamp(14px, 5.2cqw, 16px);
  line-height: 1.3;
  text-wrap: pretty;
}

.tile__bands {
  position: absolute;
  inset: auto 0 0 0;
  height: var(--bands);
  display: flex;
  box-shadow: 0 -1px 0 color-mix(in srgb, currentColor 16%, transparent);
}
.tile__bands span { flex: 1; }

/* Right: cards on white. One card tipped near the top, a second lower right running off the edge, and a
   photograph tucked into the bottom left corner. After Work Bakes: Mei Mei's drawing on a cream card, a card
   with the logo faint on it, the jar of gingerbread. */
.tile--cards { background: white; }

.tile__card {
  position: absolute;
  background: var(--color-paper-study);
  box-shadow: var(--tile-shadow);
}

.tile__card--tip { left: 23cqw; top: 7%; width: 70cqw; aspect-ratio: 4 / 3; rotate: 7deg; }
.tile__card--edge { left: 54cqw; top: 63%; width: 72cqw; aspect-ratio: 4 / 3; rotate: -7deg; }

.tile__card--logo::after {
  content: "";
  position: absolute;
  inset: 18% 22%;
  background: var(--color-awb-charcoal);
  opacity: 0.3;
  -webkit-mask: url("images/work/after-work-bakes/logo.svg") center / contain no-repeat;
  mask: url("images/work/after-work-bakes/logo.svg") center / contain no-repeat;
}

.tile__corner { left: -5cqw; top: 56%; width: 42cqw; aspect-ratio: 720 / 920; rotate: -2deg; box-shadow: var(--tile-shadow); z-index: 1; }

/* Grof: the old brand under the new. Left, the Sprout Asia grid as the ground, and on it the website, the hello
   card (whole, its own shape) and the LHDN post; middle, Grof's cover on its navy (since 10 Nov; the page with the sidekick ad laid
   over it until then); right, the quit and profitable posts as the cards, square, and the café owner from her 2025 hero
   collage in the corner (cut from images/work/grof/f/hero.jpg). */
.tile__print--hello { aspect-ratio: 698 / 876; }
.tile__card--quit { left: 30cqw; top: 6%; width: 58cqw; aspect-ratio: 1; rotate: 7deg; }
.tile__card--profit { left: 56cqw; top: 62%; width: 64cqw; aspect-ratio: 1; rotate: -7deg; }
.tile__corner--cafe { width: 54cqw; aspect-ratio: 3 / 2; top: 62%; }

/* A47: the shipped work over the look it replaced. Left, the orange Creator Studio as the ground (10 Nov, in step
   with the rewritten case study; the Mission Control notebook page until then), and on it the
   homepage and two stills from the wall, the campfire tall and the lemons square; middle, A47's cover on charcoal (since 10 Nov; the page
   with the Palm ride still until then); right, the Video and Audio sections as dark cards, the terrace door still
   in the corner. */
.tile__ground--studio { object-position: 0 0; }
.tile__card--video { left: 22cqw; top: 7%; width: 74cqw; aspect-ratio: 3 / 2; rotate: 7deg; }
.tile__card--audio { left: 48cqw; top: 60%; width: 78cqw; aspect-ratio: 3 / 2; rotate: -7deg; }
.tile__corner--door { object-position: 50% 40%; }

/* Calmer (11 Nov, way A of lab/project/two.html, Chyi's pick of the layouts): the photograph under the prints sinks
   into the brand's dark, so the prints lead, and the cards lie on a colour from the brand in place of white, so
   the three tiles read as one row. */
.project .tile--prints { background: var(--tile-dark); }
.project .tile--prints .tile__ground { opacity: 0.38; }
.project .tile--cards { background: var(--tile-soft); }
#a47 { --tile-dark: var(--color-a47-ink); --tile-soft: var(--color-a47-cream); }
#after-work-bakes { --tile-dark: var(--color-awb-charcoal); --tile-soft: var(--color-awb-taupe); }
#grof { --tile-dark: var(--color-grof-navy); --tile-soft: var(--color-grof-sky); }

/* The three projects as steps (11 Nov, Chyi: "when the user scroll to case studies pages, they will snap to a fixed
   position, then when they scroll, they will snap to the next case study, then once they moved on to the last case
   study, it will resume back to a continuous scroll"). main.js moves the page one project per scroll on a screen
   wide and tall enough, with a mouse or trackpad; here each project is made exactly one screen under the stuck
   nav bar (81px), so a step lands it whole. CSS scroll snap was tried first and dropped: one notch of a wheel in
   the hero snapped straight back to the top. */
@media (min-width: 720px) and (min-height: 600px) and (hover: hover) and (pointer: fine) {
  .js .works .project { min-height: calc(100svh - 81px); }
  .js #work { scroll-margin-top: 81px; }
  /* During a step nothing under a still hand redraws: the glass disc goes and the pictures keep their size. */
  .is-stepping .works { pointer-events: none; }
  .is-stepping .collage .collage__view { opacity: 0; transition: none; }
}

.collage:hover .collage__pic { scale: 1.015; }
.collage:active .collage__pic { scale: 0.99; }

/* On a phone the row of three was a strip 131px tall (the critique of 3 Nov, its fourth point). Since then the
   two side pictures sit as a square pair and the middle one takes the full width in its portrait crop; the gap
   between them is the small step of the scale. The middle led until the collages of 9 Nov made it the page of
   words, and that evening Chyi put the photographs first: the pair leads, the page follows. (The disc rested on
   the lead until then; without a pointer it is gone now, below.) */
@media (max-width: 639px) {
  .collage {
    grid-template-columns: 1fr 1fr;
    grid-template-areas: "l r" "m m";
    gap: var(--space-2);
    width: 100%;
  }
  .collage__pic--m { grid-area: m; --ar: 4 / 5; }
  .collage__pic--l { grid-area: l; --ar: 1; }
  .collage__pic--r { grid-area: r; --ar: 1; }
}

/* "view work": a translucent disc of the ground with the words in it. With a pointer it is the cursor over the
   pictures: main.js adds has-cursor (the arrow hides), moves the disc after the hand, and marks is-near while the
   hand is over the row, when the disc comes up. Without a pointer it rested on the middle picture, as drawn, until
   the collages of 9 Nov made that picture a page of words, where it sat like a blot over a line and a half (the
   phone review, 9 Nov): on a touch screen there is no disc now, and the link under the result is the way in. */
.collage__view {
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 2;
  display: grid;
  place-items: center;
  width: 92px;
  height: 92px;
  translate: -50% -50%;
  border-radius: 50%;
  background: color-mix(in srgb, var(--color-paper) 80%, transparent); /* firmer over white screens (finding 3) */
  color: var(--color-ink-strong);
  font-family: var(--font-serif);
  font-size: 16px;
  line-height: 1.1;
  text-align: center;
  pointer-events: none;
}

/* On Home, frosted glass (11 Nov, Chyi's pick of three in lab/project/glass.html: "let's go with the frosted, but
   the font should be spectral ( light )"): light milky glass over the pictures, a sheen along the top, the words in
   prussian in both themes. Frost and tint only: the rim bend of the lab went on 11 Nov, for the hand's sake.
   Nothing under it is magnified. */
.collage .collage__view {
  overflow: hidden;
  isolation: isolate;
  width: 101px; /* 10% under the lab's 112 (Chyi, 11 Nov: "make the disc size 10% smaller") */
  height: 101px;
  color: var(--color-on-nila); /* prussian in both themes */
  font-family: var(--font-serif);
  font-size: 17px;
  font-weight: 300;
  letter-spacing: 0.01em;
  background: color-mix(in srgb, white 42%, transparent);
  -webkit-backdrop-filter: blur(10px) saturate(1.6) brightness(1.12);
  backdrop-filter: blur(10px) saturate(1.6) brightness(1.12);
  box-shadow:
    inset 0 1px 1px color-mix(in srgb, white 90%, transparent),
    inset 0 -1px 1px color-mix(in srgb, white 45%, transparent),
    inset 0 0 0 1px color-mix(in srgb, white 55%, transparent),
    inset 0 0 14px color-mix(in srgb, white 35%, transparent),
    0 0 0 0.5px color-mix(in srgb, var(--color-on-nila) 14%, transparent), /* an edge over white screens */
    0 6px 22px color-mix(in srgb, var(--color-on-nila) 22%, transparent);
  text-shadow: 0 0 10px color-mix(in srgb, white 70%, transparent);
}
.collage .collage__view::before { /* the sheen: light along the top, a glint top left */
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background:
    radial-gradient(120% 70% at 30% 0%, color-mix(in srgb, white 55%, transparent), transparent 55%),
    linear-gradient(to top, color-mix(in srgb, white 22%, transparent), transparent 40%);
  pointer-events: none;
}

.collage.has-cursor {
  cursor: none;
}

.collage.has-cursor .collage__view {
  top: 0;
  left: 0;
  opacity: 0;
  scale: 0.6;
  will-change: transform;
  transition: opacity var(--snap-duration) var(--turn-easing), scale var(--turn-duration) var(--turn-easing);
}

.collage.has-cursor.is-near .collage__view {
  opacity: 1;
  scale: 1;
}

@media (hover: none) {
  .collage__view {
    display: none;
  }
}

/* The one line under the pictures is the result since 11 Nov (the idea is said once, on the cover), at 18 on a
   laptop and 16 on a phone (Chyi: "smaller font size"; it was 24). */
.project__line {
  max-width: 30em;
  font-family: var(--font-serif);
  font-size: clamp(16px, 0.3vw + 14px, 18px);
  line-height: 1.5;
  color: var(--color-ink-strong);
  text-wrap: balance;
}

/* The result, under the one line (the critique of 3 Nov): what the work did, in the caption style, so the home
   page argues for her before the case study does. Mist on prussian. */
.project .project__result {
  text-wrap: balance;
}

/* The way into the case study when there is no cursor to carry "view work" (the critique of 3 Nov): a plain
   link under the result on touch screens. With a pointer the disc is the affordance; with a keyboard the row
   itself takes focus. Set as a caption, like the result above it (the phone review of 9 Nov: at the body's 22px it
   was the loudest line of the block), in a box 44px tall for the thumb; the box's spare height comes off the
   margin, so the words still sit 16 under the result. */
.project .project__more {
  display: none;
  min-height: 44px;
  margin-top: calc(var(--space-3) - (44px - 1lh) / 2);
  font-family: var(--type-caption-family);
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-line-height);
  font-weight: var(--type-caption-weight);
  letter-spacing: var(--type-caption-tracking);
}

@media (hover: none) {
  .project .project__more {
    display: inline-flex;
    align-items: center;
  }
}

/* The pointer page (site/work/, 3 Nov): one line on the water, for anyone who lands on the old Work address. */
.pointer {
  display: grid;
  place-content: center;
  min-height: 100svh;
  padding: var(--space-6) var(--gutter);
  text-align: center;
}

/* The one-line foot (2 Nov): on a single-screen page (the Work pointer) the ways to reach me sit bottom left. */
.foot--line {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2) var(--space-4);
  padding: var(--space-4) var(--gutter);
}

.foot--line .foot__links {
  column-gap: var(--space-2);
}

/* With 44px targets the line stays slim: less padding, and the hover labels open above the icons rather than
   hanging below the bottom of the window. */
.foot--line {
  padding-block: var(--space-2);
}

.foot--line .foot__icon .icons__label {
  top: auto;
  bottom: 100%;
}

/* The A47 homepage demo (7 Nov), on the A47 case study: A47's homepage redrawn in HTML, a picture of their
   product, so inside the stage everything is A47's own: their colours (the a47- tokens), their faces, their sizes.
   Every length is A47's own pixel times --u, the stage's width over the width of the page it redraws, so the whole
   picture scales with the column like a photograph. a47-demo.js plays it once in view; the markup is the last
   frame. Under 880px the stage switches to A47's phone layout, a second composition rather than a squeeze, at
   480px wide at most and never taller than the window. */
.a47d {
  container: a47d / inline-size;
}

.a47d__stage {
  --pw: 1375;
  --ph: 900;
  --cw: 148;
  --ch: 263;
  --R: 560;
  --p: 640;
  --step: 16.2deg;
  --wall-y: 188;
  --tip-y: 352;
  --h-top: 448;
  --h-size: 64;
  --box-top: 603;
  --box-w: 680;
  --lines: 7;
  --turn: 0;
  --lift-z: 46;
  --a47-ease: cubic-bezier(0.23, 1, 0.32, 1);
  --cap: 100cqw;
  position: relative;
  width: min(100%, var(--cap));
  aspect-ratio: var(--pw) / var(--ph);
  overflow: hidden;
  border-radius: var(--radius-image);
  background: var(--color-a47-ground);
  color: var(--color-a47-ink);
  font-family: var(--font-a47-sans);
  -webkit-font-smoothing: antialiased;
}

@container a47d (max-width: 879px) {
  .a47d__stage {
    --cap: min(480px, (100svh - 120px) * 390 / 770);
    --pw: 390;
    --ph: 770;
    --cw: 136;
    --ch: 242;
    --R: 400;
    --p: 480;
    --step: 21.5deg;
    --turn: 1;
    --lift-z: 24;
    --wall-y: 158;
    --tip-y: 304;
    --h-top: 345;
    --h-size: 34;
    --box-top: 436;
    --box-w: 358;
    --lines: 7;
  }

  /* Turned one card on, the last two would swing round behind the viewer. */
  .a47d__card[data-edge] {
    display: none;
  }
}

.a47d__stage > * {
  --u: calc(min(100cqw, var(--cap)) / var(--pw));
}

.a47d__page {
  position: absolute;
  inset: 0;
}

/* The wall: a concave ring, each card turned about a point in front of it, as A47 draws it. --turn turns the
   ring by whole cards: on a phone it puts the picked card in the middle, as the live wall does when it turns. */
.a47d__wall {
  position: absolute;
  inset: 0 0 auto;
  height: calc(var(--wall-y) * 2 * var(--u));
  perspective: calc(var(--p) * var(--u));
}

.a47d__ring {
  position: absolute;
  left: 50%;
  top: 50%;
  transform-style: preserve-3d;
}

.a47d__card {
  --lift: 0px;
  --sc: 1;
  position: absolute;
  left: calc(var(--cw) * var(--u) / -2);
  top: calc(var(--ch) * var(--u) / -2);
  width: calc(var(--cw) * var(--u));
  height: calc(var(--ch) * var(--u));
  overflow: hidden;
  background: var(--color-a47-card);
  --at: calc(var(--i) + var(--turn));
  transform: translateZ(calc(var(--R) * var(--u))) rotateY(calc(var(--at) * var(--step) * -1))
    translateZ(calc(var(--R) * var(--u) * -1)) translateZ(var(--lift)) scale(var(--sc));
  filter: brightness(calc(1 - 0.055 * max(var(--at), var(--at) * -1)));
  transition: transform 500ms var(--a47-ease), box-shadow 150ms ease;
}

.a47d__card img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 0;
  background: none;
}

.a47d__card--voice {
  background: var(--color-a47-ink);
}

.a47d__wave {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(3 * var(--u));
}

.a47d__wave b {
  width: calc(3 * var(--u));
  height: calc(var(--h) * 0.32);
  background: var(--color-a47-surface);
  opacity: 0.85;
}

.a47d__top {
  position: absolute;
  inset: calc(8 * var(--u)) calc(8 * var(--u)) auto;
  display: flex;
  justify-content: space-between;
  gap: calc(6 * var(--u));
}

.a47d__tag,
.a47d__len {
  padding: calc(4 * var(--u)) calc(6 * var(--u));
  font-size: calc(10.5 * var(--u));
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  background: color-mix(in srgb, var(--color-a47-surface) 92%, transparent);
}

.a47d__shade {
  position: absolute;
  inset: 0;
  background: linear-gradient(transparent 50%, color-mix(in srgb, var(--color-a47-ink) 60%, transparent));
  opacity: 0;
  transition: opacity 200ms ease;
}

.a47d__cap {
  position: absolute;
  inset: auto calc(10 * var(--u)) calc(12 * var(--u));
  display: grid;
  gap: calc(5 * var(--u));
  color: var(--color-a47-surface);
  opacity: 0;
  transition: opacity 200ms ease;
}

.a47d__cap-title {
  font-size: calc(14 * var(--u));
  font-weight: 600;
  line-height: 1.25;
}

.a47d__cap-use {
  font-size: calc(11.5 * var(--u));
  font-weight: 600;
  line-height: 1.2;
}

.a47d__card.is-hover .a47d__shade,
.a47d__card.is-hover .a47d__cap,
.a47d__card.is-picked .a47d__shade,
.a47d__card.is-picked .a47d__cap {
  opacity: 1;
}

.a47d__card.is-pressed {
  --sc: 0.97;
  transition-duration: 110ms;
}

/* Picked: it comes forward a little and takes A47's ring, a ground-coloured gap then rust. */
.a47d__card.is-picked {
  --lift: calc(var(--lift-z) * var(--u));
  --sc: 1.04;
  box-shadow: 0 0 0 calc(2 * var(--u)) var(--color-a47-ground), 0 0 0 calc(4 * var(--u)) var(--color-a47-rust);
}

.a47d__tip {
  position: absolute;
  left: 50%;
  top: calc(var(--tip-y) * var(--u));
  padding: calc(7 * var(--u)) calc(11 * var(--u));
  font-size: calc(12.5 * var(--u));
  font-weight: 600;
  line-height: 1;
  color: var(--color-a47-rust);
  background: var(--color-a47-surface);
  border: 1px solid var(--color-a47-rule-strong);
  border-radius: calc(6 * var(--u));
  transform: translate(-50%, calc(4 * var(--u)));
  opacity: 0;
  transition: opacity 200ms ease, transform 250ms var(--a47-ease);
}

.a47d__tip.is-on {
  transform: translate(-50%, 0);
  opacity: 1;
}

.a47d__head {
  position: absolute;
  inset: calc(var(--h-top) * var(--u)) 0 auto;
  font-family: var(--font-a47-serif);
  font-size: calc(var(--h-size) * var(--u));
  font-weight: 600;
  line-height: 1.02;
  letter-spacing: -0.02em;
  text-align: center;
}

.a47d__head span {
  color: var(--color-a47-rust);
}

.a47d__box {
  position: absolute;
  left: 50%;
  top: calc(var(--box-top) * var(--u));
  width: calc(var(--box-w) * var(--u));
  padding: calc(16 * var(--u));
  background: var(--color-a47-surface);
  border: 1px solid var(--color-a47-rule-strong);
  box-shadow: 0 calc(1 * var(--u)) calc(2 * var(--u)) color-mix(in srgb, var(--color-a47-ink) 4%, transparent),
    0 calc(10 * var(--u)) calc(28 * var(--u)) color-mix(in srgb, var(--color-a47-ink) 6%, transparent);
  transform: translateX(-50%);
}

.a47d__box.is-flash {
  animation: a47d-flash 450ms var(--a47-ease);
}

@keyframes a47d-flash {
  from { border-color: var(--color-a47-rust); }
}

/* The source chip opens its own room, then the prompt pushes the box down line by line, as on the live page. */
.a47d__src {
  display: grid;
  grid-template-rows: 1fr;
  transition: grid-template-rows 250ms var(--a47-ease), opacity 200ms ease;
}

.a47d__src > div {
  min-height: 0;
  overflow: hidden;
}

.a47d__box.is-closed .a47d__src {
  grid-template-rows: 0fr;
  opacity: 0;
}

.a47d__chip {
  display: inline-flex;
  align-items: center;
  gap: calc(6 * var(--u));
  margin-bottom: calc(12 * var(--u));
  padding: calc(6 * var(--u)) calc(6 * var(--u)) calc(6 * var(--u)) calc(11 * var(--u));
  font-size: calc(12.5 * var(--u));
  font-weight: 500;
  line-height: 1;
  color: var(--color-a47-rust);
  background: color-mix(in srgb, var(--color-a47-rust) 8%, transparent);
}

.a47d__x {
  display: grid;
  place-items: center;
  width: calc(20 * var(--u));
  height: calc(20 * var(--u));
  color: var(--color-a47-muted);
}

.a47d__row {
  display: flex;
  align-items: flex-start;
  gap: calc(10 * var(--u));
  margin-bottom: calc(12 * var(--u));
}

.a47d__attach,
.a47d__send {
  flex: none;
  display: grid;
  place-items: center;
  width: calc(40 * var(--u));
  height: calc(40 * var(--u));
  border-radius: calc(6 * var(--u));
}

.a47d__attach {
  border: 1px solid var(--color-a47-rule-strong);
  font-size: calc(20 * var(--u));
  color: var(--color-a47-muted);
}

.a47d__send {
  font-size: calc(16 * var(--u));
  color: var(--color-a47-surface);
  background: var(--color-a47-rust);
  transition: background-color 200ms ease, color 200ms ease;
}

.a47d__prompt {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
  min-height: calc(32 * var(--u));
  max-height: calc((8 + var(--lines) * 24) * var(--u));
  padding-top: calc(8 * var(--u));
  overflow: hidden;
  font-size: calc(16 * var(--u));
  line-height: 1.5;
}

.a47d__typed {
  display: block;
}

.a47d__ph {
  position: absolute;
  inset: calc(8 * var(--u)) 0 auto;
  color: var(--color-a47-soft);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  opacity: 0;
}

.a47d__box.is-empty .a47d__ph {
  opacity: 1;
}

.a47d__box.is-empty .a47d__send {
  color: var(--color-a47-soft);
  background: var(--color-a47-fill);
}

.a47d__types {
  display: flex;
  gap: calc(6 * var(--u));
}

.a47d__types span {
  padding: calc(6 * var(--u)) calc(12 * var(--u));
  font-size: calc(13 * var(--u));
  line-height: 1;
  border: 1px solid var(--color-a47-rule-strong);
  border-radius: calc(6 * var(--u));
}

.a47d__types .is-on {
  color: var(--color-a47-surface);
  background: var(--color-a47-ink);
  border-color: var(--color-a47-ink);
}

/* The pointer: the macOS arrow and pointing hand at the picture's scale, hotspot on the point. It turns into the
   hand as it crosses onto the card, and leaves the last frame clean. */
.a47d__cursor {
  position: absolute;
  left: 0;
  top: 0;
  z-index: 1;
  opacity: 0;
  pointer-events: none;
  transition: transform var(--t, 0ms) cubic-bezier(0.45, 0, 0.1, 1), opacity 300ms ease;
}

.a47d__cursor svg {
  position: absolute;
  transition: opacity 120ms ease, transform 120ms ease;
}

.a47d__arrow {
  left: calc(-7.5 * var(--u));
  top: calc(-5.25 * var(--u));
  width: calc(24 * var(--u));
  height: calc(24 * var(--u));
  transform-origin: calc(7.5 * var(--u)) calc(5.25 * var(--u));
}

.a47d__hand {
  left: calc(-10 * var(--u));
  top: calc(-3.5 * var(--u));
  width: calc(26 * var(--u));
  height: calc(26 * var(--u));
  transform-origin: calc(10 * var(--u)) calc(3.5 * var(--u));
  opacity: 0;
  transform: scale(0.7);
}

.a47d__cursor[data-kind="hand"] .a47d__arrow {
  opacity: 0;
  transform: scale(0.7);
}

.a47d__cursor[data-kind="hand"] .a47d__hand {
  opacity: 1;
  transform: none;
}

.a47d__cursor[data-pressed] .a47d__hand {
  transform: scale(0.9);
}

@media (prefers-reduced-motion: reduce) {
  .a47d__stage * {
    transition: none !important;
    animation: none !important;
  }
}

/* ===== Case study, layout F (9 Nov) =====
   Chyi's own case-study layout from the Figma ("Case study layout F", frame 95:2): a pale cream page, the three icons
   centred at the top, the headline and scope line, the overview in two columns under a rule, then pictures and short
   columns of words in turn, ending on prussian. One column of 1120 at 1440 (the gutter is the page margin). Built on
   After Work Bakes first; Grof and A47 follow when they are built. */
.cf-page {
  background: var(--color-paper-study);
  color: var(--color-ink-strong);
}

.cf-nav {
  --glyph: 28px;
  padding: var(--space-4) var(--gutter) 0;
}

.cf-nav .icons__list {
  column-gap: var(--space-7);
}

.cf-nav .icons__label {
  opacity: 1;
  translate: none;
}

/* On Home alone the nav begins in the middle of the first screen, under the statement, her name and her
   designation, and rises after them (10 Nov, Chyi: "the nav bar will be in the middle first ... when the user
   scroll ... the nav bar will be sticky at the top. So that nav bar will be standardized across all different
   pages"). It is the same nav as on every page, at the same size. As the page scrolls it rides up with the words,
   and the moment it reaches the top it stays (main.js adds is-stuck; .hero__nav, the slot, keeps its place, so
   nothing jumps and it is handed back at the same spot on the way up). Stuck, it has a bar of translucent night
   behind it so it reads over the work: solid under reduced transparency. Without the script it stays in the hero.
   It lay over the top of the water from 9 Nov until then. --stick is how far from the top it rests. */
.hero__nav {
  justify-self: stretch;
}

.cf-nav--home {
  --stick: var(--space-2);
  position: relative;
  isolation: isolate;
  padding: 0;
}

.cf-nav--home::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: color-mix(in srgb, var(--color-paper) 74%, transparent);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  backdrop-filter: blur(18px) saturate(140%);
  opacity: 0;
  transition: opacity var(--turn-duration) var(--turn-easing);
  pointer-events: none;
}

.cf-nav--home.is-stuck {
  position: fixed;
  inset: 0 0 auto;
  z-index: 30;
  padding: var(--stick) var(--gutter);
}

.cf-nav--home.is-stuck::before {
  opacity: 1;
}

/* Once it has risen, or the first time it sticks (a page opened part way down, a quick scroll), it is simply
   there for good: main.js adds is-shown, and the entrance never plays again on the way back up. */
.js .cf-nav--home.is-shown {
  opacity: 1;
  translate: none;
  animation: none;
}

@media (prefers-reduced-transparency: reduce) {
  .cf-nav--home::before {
    background: var(--color-paper);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
}

.cf {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
  width: min(1120px, 100% - 2 * var(--gutter));
  margin: calc(var(--space-5) * 2) auto var(--space-7);
}

.cf-head {
  display: flex;
  flex-direction: column;
}

.cf-title {
  max-width: 773px;
  font-family: var(--font-statement);
  font-size: 40px;
  line-height: 1.3;
  font-weight: 700;
  letter-spacing: -0.027em;
  text-wrap: pretty;
  color: var(--color-ink-strong);
}

.cf-sub {
  max-width: 600px;
  margin-top: var(--space-4);
  font-family: var(--font-statement);
  font-size: 18px;
  line-height: 1.4;
  letter-spacing: -0.003em;
  color: var(--color-nila-deep);
}

.cf-overview {
  display: grid;
  grid-template-columns: minmax(0, 600px) minmax(0, 1fr);
  gap: var(--space-4);
  margin-top: var(--space-6);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-nila);
}

.cf-label {
  display: block;
  margin-bottom: var(--space-2);
  font-family: var(--font-serif);
  font-size: 12px;
  line-height: 1.4;
  font-weight: 400;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--color-ink-muted);
}

.cf-facts,
.cf-list {
  margin: 0;
  padding: 0;
  list-style: none;
  font-family: var(--font-serif);
  font-size: 17px;
  line-height: 26px;
  letter-spacing: 0;
}

.cf-facts dt,
.cf-facts dd {
  display: inline;
  margin: 0;
}

.cf-facts dt {
  margin-right: 0.3em;
}

.cf-list li + li {
  margin-top: var(--space-1);
}

/* Something Chyi must supply: a dotted underline, as .todo elsewhere. */
.cf-todo {
  text-decoration: underline dotted;
  text-underline-offset: 3px;
}

.cf-figure {
  margin: 0;
}

.cf-figure img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: var(--radius-image);
}

.cf-head .cf-figure--wide {
  margin-top: var(--space-5);
}

.cf-figure--wide img {
  aspect-ratio: 1120 / 666;
}

.cf-figure--plain img {
  border-radius: 0;
  object-fit: contain;
}

.cf-text {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  max-width: 548px;
}

/* The case studies' running text in Figtree, regular, since 11 Nov (Chyi's pick of three faces like Work Sans but
   narrower and rounder, lab/body/narrow.html; Work Sans and Inter were tried first the same day). "reduce the font
   size by 15%": 14.5 on 24 on a laptop, 15% under the 17 on 28 the sans had; on a phone 14 on 23, kept at 14 so
   it stays readable in the hand (15% would be 13.6). Tracked -0.005em. Headings, captions and labels keep their
   faces. */
.cf-text p {
  max-width: 420px; /* 480 until 11 Nov: at Figtree's 14.5 a line held 71 to 74 characters; at 420 it holds 61 to 64 (Chyi: "Yes, narrow it") */
  font-family: var(--font-body);
  font-size: 14.5px;
  line-height: 24px;
  font-weight: 400;
  letter-spacing: -0.005em; /* tracking -5, five units wider than -10 (Chyi: "adjust the kerning to be 5% wider") */
  color: var(--color-ink-strong);
}

.cf-h2 {
  max-width: 548px;
  margin-bottom: var(--space-2);
  font-family: var(--font-statement);
  font-size: 32px;
  line-height: 1.22;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--color-ink-strong);
}

.cf-split {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-4);
  align-items: start;
  padding-block: var(--space-5);
}

.cf-split .cf-figure img {
  aspect-ratio: 548 / 485;
}

.cf-split--end .cf-figure img {
  aspect-ratio: 543 / 403;
}

.cf-block {
  padding-top: var(--space-5);
}

.cf-three {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-4);
}

.cf-three img {
  aspect-ratio: 360 / 460;
}

/* The foot on prussian (the section is data-theme="dark", so paper is prussian and the inks are light). */
.cf-foot {
  padding-top: var(--space-7);
  background: var(--color-paper);
  color: var(--color-ink);
}

.cf-next {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: var(--space-4);
  padding-bottom: var(--space-4);
  border-bottom: 1px solid var(--color-line);
  color: var(--color-ink-strong);
  text-decoration: none;
}

.cf-next__text {
  display: flex;
  flex-direction: column;
}

.cf-next__name,
.cf-next__arrow {
  font-family: var(--font-statement);
  font-size: 40px;
  line-height: 1.22;
  letter-spacing: -0.01em;
}

.cf-next__arrow {
  transition: translate var(--snap-duration) var(--turn-easing);
}

.cf-next:hover .cf-next__arrow,
.cf-next:focus-visible .cf-next__arrow {
  translate: var(--space-2) 0;
}

.cf-foot .foot__line {
  font-size: 40px;
}

@media (max-width: 899px) {
  .cf-split { grid-template-columns: minmax(0, 1fr); gap: var(--space-5); }
  .cf-overview { grid-template-columns: minmax(0, 1fr); gap: var(--space-5); }
}

@media (max-width: 719px) {
  .cf { margin-top: var(--space-6); gap: var(--space-5); }
  .cf-nav .icons__list { column-gap: var(--space-6); }
  .cf-title { font-size: 30px; }
  .cf-h2 { font-size: 26px; }
  .cf-text p { font-size: 14px; line-height: 23px; }
  .cf-three { grid-template-columns: minmax(0, 1fr); }
  .cf-three img { aspect-ratio: 4 / 5; }
  .cf-next__name, .cf-next__arrow, .cf-foot .foot__line { font-size: 30px; }
}

/* ----- The After Work Bakes logo, taken apart (9 Nov; lab: site/lab/awb-logo/frame.html) -----
   A 1120 x 666 drawing scaled to its box. The bakery's own palette (the awb tokens). The story plays once when half of
   it is in view (logo-frame.js adds .is-on); with reduced motion or no script it is the finished sheet. */
.awbs {
  --awb-ink-2: color-mix(in srgb, var(--color-awb-charcoal) 78%, transparent);
  --awb-ink-3: color-mix(in srgb, var(--color-awb-charcoal) 62%, transparent);
  --awb-leader: color-mix(in srgb, var(--color-awb-charcoal) 42%, transparent);
  position: relative;
  margin: 0;
  color: var(--color-awb-charcoal);
}
.awbs__box { position: relative; aspect-ratio: 1120 / 666; max-width: 100%; border-radius: var(--radius-image); overflow: hidden; background: var(--color-awb-cream); container-type: inline-size; }
.awbs__stage { position: absolute; left: 0; top: 0; width: 1120px; height: 666px; transform-origin: 0 0; transform: scale(calc(100cqw / 1120px)); font-family: var(--font-serif); letter-spacing: 0; }
@supports not (width: 1cqw) { .awbs__stage { transform: scale(var(--s, 1)); } }
.awbs__logo, .awbs__layer { position: absolute; left: 322.5px; top: 72px; width: 475.5px; height: 432px; }
.awbs__layer img { display: block; width: 100%; height: 100%; }
/* The logo is one drawing cut into three layers so its parts arrive one at a time; Mei Mei keeps the lines of her body
   left of the a, her hands stay on the letter. */
.awbs__word  { clip-path: polygon(29.2% 0, 100% 0, 100% 81%, 0 81%, 0 27.8%, 7.9% 27.8%, 7.9% 21.7%, 29.2% 21.7%); }
.awbs__mei   { clip-path: polygon(0 0, 29.2% 0, 29.2% 21.7%, 7.9% 21.7%, 7.9% 27.8%, 0 27.8%); }
.awbs__bakes { clip-path: inset(81% 0 0 0); }
.awbs__eyes { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.awbs__lid { fill: var(--color-awb-cream); }
.awbs__eye { fill: var(--color-awb-charcoal); transform-box: fill-box; transform-origin: center; transition: transform 70ms ease-in; }
.awbs.is-blink .awbs__eye { transform: scale(1.2, .3); }
.awbs__lines { position: absolute; inset: 0; width: 1120px; height: 666px; overflow: visible; pointer-events: none; }
.awbs__guide { fill: none; stroke: var(--color-awb-taupe); stroke-width: 1; }
.awbs__leader { fill: none; stroke: var(--awb-leader); stroke-width: 1; }
.awbs__end { fill: var(--color-awb-charcoal); opacity: .55; }
.awbs__note { position: absolute; width: 200px; display: flex; flex-direction: column; gap: 6px; font-size: 15px; line-height: 1.5; }
.awbs__note p { margin: 0; color: var(--awb-ink-2); }
.awbs__note--l { left: 48px; text-align: right; align-items: flex-end; }
.awbs__note--r { left: 872px; }
.awbs .awbs__eyebrow { font-size: 11px; line-height: 1.4; letter-spacing: .14em; text-transform: uppercase; color: var(--awb-ink-3); }
.awbs__palette { position: absolute; left: 0; right: 0; top: 586px; display: flex; justify-content: center; align-items: center; gap: 40px; margin: 0; padding: 0; list-style: none; font-size: 14px; line-height: 1.4; }
.awbs__palette li { display: flex; align-items: center; gap: 8px; }
.awbs__palette li > span:first-child { width: 16px; height: 16px; flex: none; }
.awbs__palette code { font: 400 11px/1.4 var(--font-serif); letter-spacing: .14em; color: var(--awb-ink-3); }
.awbs .t { background: var(--color-awb-taupe); }
.awbs .c { background: var(--color-awb-cream); box-shadow: inset 0 0 0 1px var(--color-awb-taupe); }
.awbs .k { background: var(--color-awb-charcoal); }
.awbs__list { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

@media (prefers-reduced-motion: no-preference) {
  .js .awbs:not(.is-on) .awbs__word { opacity: 0; transform: translateY(16px); }
  .js .awbs:not(.is-on) .awbs__bakes { clip-path: inset(81% 100% 0 0); }
  .js .awbs:not(.is-on) .awbs__mei img, .js .awbs:not(.is-on) .awbs__eyes { transform: translateY(22%); }
  .js .awbs:not(.is-on) .awbs__draw { stroke-dashoffset: 1; }
  .js .awbs:not(.is-on) .awbs__end,
  .js .awbs:not(.is-on) .awbs__note,
  .js .awbs:not(.is-on) .awbs__palette li { opacity: 0; }
  .js .awbs:not(.is-on) .awbs__note,
  .js .awbs:not(.is-on) .awbs__palette li { transform: translateY(8px); }
  .js .awbs__word { transition: opacity .7s ease-out, transform .7s cubic-bezier(.2, .7, .2, 1); }
  .js .awbs__bakes { transition: clip-path .9s cubic-bezier(.5, 0, .3, 1) 1.6s; }
  .js .awbs__mei img, .js .awbs__eyes { transition: transform .6s cubic-bezier(.2, .8, .25, 1) 2.8s; }
  .js .awbs__draw { stroke-dasharray: 1; transition: stroke-dashoffset var(--d, .45s) cubic-bezier(.3, 0, .2, 1) var(--t, 0s); }
  .js .awbs__end { transition: opacity .25s ease-out var(--t, 0s); }
  .js .awbs__note, .js .awbs__palette li { transition: opacity .5s ease-out var(--t, 0s), transform .5s ease-out var(--t, 0s); }
}

/* Narrow: the frame zooms onto the drawing and its lines; the notes go under it as a list. */
@container (max-width: 699px) {
  .awbs__note, .awbs__palette, .awbs__leader, .awbs__end { display: none; }
  .awbs__stage { transform: scale(calc(100cqw / 560px)) translate(-280px, -46px); }
}
@media (max-width: 739px) {
  .awbs__box { aspect-ratio: 560 / 470; }
  .awbs__list { position: static; width: auto; height: auto; overflow: visible; clip-path: none; white-space: normal; display: flex; flex-direction: column; gap: var(--space-3); margin: var(--space-4) 0 0; padding: 0; list-style: none; font-size: 16px; line-height: 1.5; color: var(--color-ink-strong); }
  .awbs__list p { margin: 0; }
  .awbs__list .awbs__eyebrow { display: block; margin-bottom: var(--space-1); }
  .awbs__swatches { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4); }
  .awbs__swatches span { display: inline-flex; align-items: center; gap: var(--space-2); }
  .awbs__swatches i { width: 12px; height: 12px; display: inline-block; }
}

/* ----- The After Work Bakes hero collage, in motion (9 Nov; lab: site/lab/awb-logo/hero.html) -----
   Her frame "Hero IMage" (Personal Website, 93:238): 1036 x 582, the tray of loaves under a half-black wash and four
   tiles in her places and sizes, scaled to the column. Plays once when 40% of it is in view (awb-motion.js adds .is-on);
   with reduced motion or no script it is her frame, still. */
.cf-hero { margin: var(--space-5) 0 0; }
.awbh { --awbh-line: color-mix(in srgb, black 15%, white); --awbh-card-line: color-mix(in srgb, black 21%, white); }
.awbh__box { position: relative; aspect-ratio: 1036 / 582; max-width: 100%; border-radius: 16px; overflow: hidden; container-type: inline-size; isolation: isolate; }
.awbh__box::after { content: ""; position: absolute; inset: 0; border-radius: inherit; box-shadow: inset 0 0 0 1px var(--awbh-line); pointer-events: none; z-index: 3; }
.awbh__stage { position: absolute; left: 0; top: 0; width: 1036px; height: 582px; transform-origin: 0 0; transform: scale(calc(100cqw / 1036px)); }
@supports not (width: 1cqw) { .awbh__stage { transform: scale(var(--s, 1)); } }
.awbh__bg { position: absolute; inset: 0; overflow: hidden; }
.awbh__bg img { display: block; width: 100%; height: 100%; object-fit: cover; }
.awbh__bg::after { content: ""; position: absolute; inset: 0; background: rgb(0 0 0 / .5); }
.awbh__tile { position: absolute; overflow: hidden; border-radius: 12px; background: white; }
.awbh__tile > img { display: block; width: 100%; height: 100%; object-fit: cover; }
.awbh__shaping { left: 64px; top: 59px; width: 540px; height: 224px; }
.awbh__shaping > img { object-position: 50% 100%; }
.awbh__bagels  { left: 64px; top: 298px; width: 202px; height: 224px; }
.awbh__card    { left: 283px; top: 298px; width: 321px; height: 224px; box-shadow: inset 0 0 0 1px var(--awbh-card-line); }
.awbh__loaf    { left: 631px; top: 59px; width: 351px; height: 457px; border-radius: 16px; }
.awbh__loaf::after { content: ""; position: absolute; inset: 0; border-radius: inherit; box-shadow: inset 0 0 0 1px white; }
.awbh__logo, .awbh__layer { position: absolute; left: 79.3px; top: 38px; width: 163.5px; height: 148.5px; }
.awbh__layer img { display: block; width: 100%; height: 100%; filter: brightness(0); }
.awbh__word  { clip-path: polygon(29.2% 0, 100% 0, 100% 81%, 0 81%, 0 27.8%, 7.9% 27.8%, 7.9% 21.7%, 29.2% 21.7%); }
.awbh__mei   { clip-path: polygon(0 0, 29.2% 0, 29.2% 21.7%, 7.9% 21.7%, 7.9% 27.8%, 0 27.8%); }
.awbh__bakes { clip-path: inset(81% 0 0 0); }
.awbh__eyes { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.awbh__lid { fill: white; }
.awbh__eye { fill: black; transform-box: fill-box; transform-origin: center; transition: transform 70ms ease-in; }
.awbh.is-blink .awbh__eye { transform: scale(1.2, .3); }

@media (prefers-reduced-motion: no-preference) {
  .js .awbh:not(.is-on) .awbh__bg img { transform: scale(1.1); }
  .js .awbh:not(.is-on) .awbh__bg::after { background: rgb(0 0 0 / .72); }
  .js .awbh:not(.is-on) .awbh__tile { opacity: 0; transform: translateY(24px) scale(.97); }
  .js .awbh:not(.is-on) .awbh__tile > img { transform: scale(1.15); }
  .js .awbh:not(.is-on) .awbh__word { opacity: 0; transform: translateY(8px); }
  .js .awbh:not(.is-on) .awbh__bakes { clip-path: inset(81% 100% 0 0); }
  .js .awbh:not(.is-on) .awbh__mei img, .js .awbh:not(.is-on) .awbh__eyes { transform: translateY(22%); }
  .js .awbh__bg img { transition: transform 2.2s cubic-bezier(.2, .7, .2, 1); }
  .js .awbh__bg::after { transition: background-color 1.6s ease-out; }
  .js .awbh__tile { transition: opacity .7s ease-out var(--t), transform .8s cubic-bezier(.2, .7, .2, 1) var(--t); }
  .js .awbh__tile > img { transition: transform 1.6s cubic-bezier(.2, .7, .2, 1) var(--t); }
  .js .awbh__word { transition: opacity .6s ease-out 1s, transform .6s cubic-bezier(.2, .7, .2, 1) 1s; }
  .js .awbh__bakes { transition: clip-path .7s cubic-bezier(.5, 0, .3, 1) 1.35s; }
  .js .awbh__mei img, .js .awbh__eyes { transition: transform .5s cubic-bezier(.2, .8, .25, 1) 1.9s; }
}

/* ----- Layout F, shared pieces for Grof and A47 (9 Nov) ----- */
.cf-img--top { object-position: 50% 0; }
.cf-split--end .cf-figure img.cf-img--natural { aspect-ratio: auto; height: auto; } /* a picture kept whole, in its own shape (Grof's team over the laptop, 10 Nov) */
.cf-three--square img { aspect-ratio: 1; }
.cf-cap {
  margin-top: var(--space-3);
  font-family: var(--type-caption-family);
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-line-height);
  color: var(--color-ink-muted);
}

/* A breakdown frame, still (Grof's hello card): a 1120 x 666 drawing scaled to its box, a picture in the middle and a
   fine line from each note to its part, in the manner of the After Work Bakes logo frame. Under 700 wide it zooms onto
   the picture and the notes go under it as a list (the list is also what screen readers get at every width). */
.cfa {
  --cfa-ink-2: color-mix(in srgb, var(--color-ink-strong) 78%, transparent);
  --cfa-ink-3: color-mix(in srgb, var(--color-ink-strong) 62%, transparent);
  --cfa-leader: color-mix(in srgb, var(--color-ink-strong) 42%, transparent);
  position: relative;
  margin: 0;
}
.cfa__box { position: relative; aspect-ratio: 1120 / 666; max-width: 100%; border-radius: var(--radius-image); overflow: hidden; background: var(--color-paper); container-type: inline-size; }
.cfa__stage { position: absolute; left: 0; top: 0; width: 1120px; height: 666px; transform-origin: 0 0; transform: scale(calc(100cqw / 1120px)); font-family: var(--font-serif); letter-spacing: 0; }
.cfa__card { position: absolute; display: block; border-radius: 12px; }
.cfa__lines { position: absolute; inset: 0; width: 1120px; height: 666px; pointer-events: none; }
.cfa__leader { fill: none; stroke: var(--cfa-leader); stroke-width: 1; }
.cfa__end { fill: var(--color-ink-strong); opacity: .55; }
.cfa__note { position: absolute; width: 200px; display: flex; flex-direction: column; gap: 6px; font-size: 15px; line-height: 1.5; }
.cfa__note p { margin: 0; color: var(--cfa-ink-2); }
.cfa__note--l { left: 48px; text-align: right; align-items: flex-end; }
.cfa__note--r { left: 872px; }
.cfa .cfa__eyebrow { font-size: 11px; line-height: 1.4; letter-spacing: .14em; text-transform: uppercase; color: var(--cfa-ink-3); }
.cfa__list { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
@container (max-width: 699px) {
  .cfa__note, .cfa__lines { display: none; }
  .cfa__stage { transform: scale(calc(100cqw / 560px)) translate(-280px, -78px); }
}
@media (max-width: 739px) {
  .cfa__box { aspect-ratio: 560 / 510; }
  .cfa__list { position: static; width: auto; height: auto; overflow: visible; clip-path: none; white-space: normal; display: flex; flex-direction: column; gap: var(--space-3); margin: var(--space-4) 0 0; padding: 0; list-style: none; font-size: 16px; line-height: 1.5; color: var(--color-ink-strong); }
  .cfa__list p { margin: 0; }
  .cfa__list .cfa__eyebrow { display: block; margin-bottom: var(--space-1); }
}

/* ---- A47: the studio, close up (9 Nov) ----
   Chyi: "the two photos attached is a very lazy effort, I want you to refer to daniela's case study page, study how
   she highlight each component and the showcase instead of just attaching screenshot directly." After Daniela's
   Sandhill page: each part of the studio lifted out and laid on its own panel, the panels in a bento (one wide,
   two halves, three thirds), a caption under each, and the voice picker alone beside the last words. The parts are
   redrawn in HTML in A47's faces and colours (the a47- tokens, as the homepage demo is), word for word from the
   screens captured on 9 Nov, so they stay sharp on any screen. The panels: night (the studio's charcoal), fill,
   ground and rust (A47's one accent, as a ground once, the way Sandhill gives one panel its orange). The cards on
   them float, as the product's own cards do. Everything is under .a47s. */
.a47s {
  --a47s-night: color-mix(in srgb, var(--color-a47-ink) 78%, black);
  --a47s-tint: color-mix(in srgb, var(--color-a47-rust) 8%, var(--color-a47-surface));
  --a47s-edge: color-mix(in srgb, var(--color-a47-rust) 60%, var(--color-a47-surface));
  --a47s-muted-rust: color-mix(in srgb, var(--color-a47-rust) 42%, var(--color-a47-surface));
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: var(--space-5) var(--space-4);
}

.a47s__cell { margin: 0; grid-column: span 3; }
.a47s__cell--wide { grid-column: 1 / -1; }
.a47s__cell--third { grid-column: span 2; }

.a47s__panel {
  --a47s-night: color-mix(in srgb, var(--color-a47-ink) 78%, black);
  --a47s-tint: color-mix(in srgb, var(--color-a47-rust) 8%, var(--color-a47-surface));
  --a47s-edge: color-mix(in srgb, var(--color-a47-rust) 60%, var(--color-a47-surface));
  --a47s-muted-rust: color-mix(in srgb, var(--color-a47-rust) 42%, var(--color-a47-surface));
  display: grid;
  place-items: center;
  aspect-ratio: 548 / 480;
  padding: var(--space-5);
  overflow: hidden;
  border-radius: var(--radius-image);
  font-family: var(--font-a47-sans);
  color: var(--color-a47-ink);
  text-align: left;
}

.a47s__cell--wide .a47s__panel { aspect-ratio: 1120 / 500; }
.a47s__cell--third .a47s__panel { aspect-ratio: 357 / 440; padding: var(--space-4); }

.a47s__panel--night {
  background: radial-gradient(60% 55% at 50% 38%, color-mix(in srgb, var(--color-a47-surface) 9%, transparent), transparent), var(--a47s-night);
  color: var(--color-a47-surface);
}
.a47s__panel--fill { background: var(--color-a47-fill); }
.a47s__panel--ground { background: var(--color-a47-card); }
.a47s__panel--rust { background: var(--color-a47-rust); }

.a47s p { margin: 0; }
.a47s svg, .a47s__voices svg {
  width: 16px;
  height: 16px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* The card a part sits on: white, as in the studio's left panel, floating over its ground. */
.a47s__card {
  display: grid;
  row-gap: 14px;
  width: min(100%, 340px);
  padding: 22px;
  border-radius: 12px;
  background: var(--color-a47-surface);
  color: var(--color-a47-ink);
  box-shadow: 0 1px 2px color-mix(in srgb, black 8%, transparent), 0 18px 40px color-mix(in srgb, black 14%, transparent);
}

.a47s__label { font-size: 13px; font-weight: 500; }
.a47s__small { font-size: 12.5px; line-height: 1.5; color: var(--color-a47-muted); }
.a47s__tiny { margin-top: -6px !important; font-size: 11px; line-height: 1.4; text-align: center; color: var(--color-a47-soft); }

.a47s__outline {
  display: block;
  padding: 10px;
  border: 1px solid var(--color-a47-rule-strong);
  border-radius: 6px;
  font-size: 13px;
  text-align: center;
  color: var(--color-a47-muted);
}

.a47s__generate {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 14px 18px;
  border-radius: 8px;
  background: var(--color-a47-rust);
  color: var(--color-a47-surface);
  font-size: 13px;
}
.a47s__generate b { font-size: 15px; font-weight: 600; }
.a47s__generate span { opacity: 0.8; }

/* Segmented controls, the picked one on a rust tint with a rust edge, as the studio draws them. */
.a47s__seg {
  display: inline-flex;
  padding: 3px;
  border: 1px solid var(--color-a47-rule-strong);
  border-radius: 8px;
  font-size: 13px;
  color: var(--color-a47-muted);
}
.a47s__seg > span { padding: 7px 16px; border: 1px solid transparent; border-radius: 6px; text-align: center; white-space: nowrap; }
.a47s__seg > .is-on { background: var(--a47s-tint); border-color: var(--a47s-edge); color: var(--color-a47-rust); }
.a47s__seg--full { display: flex; }
.a47s__seg--full > span { flex: 1; padding-inline: 6px; }

.a47s__line { display: flex; align-items: center; gap: 14px; }
.a47s__name { width: 64px; flex: none; font-size: 13px; font-weight: 500; }
.a47s__val { font-size: 13px; }

.a47s__slider {
  position: relative;
  flex: 1;
  height: 4px;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--color-a47-rust) var(--v), var(--color-a47-fill) var(--v));
}
.a47s__slider::after {
  content: "";
  position: absolute;
  top: 50%;
  left: var(--v);
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--color-a47-rust);
  translate: -50% -50%;
}

.a47s__ratios { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 5px; }
.a47s__ratio {
  display: grid;
  justify-items: center;
  align-content: center;
  row-gap: 5px;
  height: 52px;
  border: 1px solid var(--color-a47-rule-strong);
  border-radius: 6px;
  font-size: 10px;
  color: var(--color-a47-muted);
}
.a47s__ratio i { display: block; max-width: 70%; border: 1.5px solid currentColor; border-radius: 2px; font-style: normal; }
.a47s__ratio .a47s__spark { border: 0; font-size: 12px; line-height: 1; }
.a47s__ratio.is-on { background: var(--a47s-tint); border-color: var(--a47s-edge); color: var(--color-a47-rust); }

.a47s__select {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: -6px;
  padding: 11px 14px;
  border: 1px solid var(--color-a47-rule-strong);
  border-radius: 8px;
  font-size: 14px;
}

.a47s__frames { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.a47s__frames > span {
  display: grid;
  justify-items: center;
  row-gap: 3px;
  padding: 18px 8px;
  border-radius: 8px;
  background: var(--color-a47-fill);
  font-size: 11px;
  color: var(--color-a47-soft);
}
.a47s__frames svg { margin-bottom: 4px; color: var(--color-a47-muted); }
.a47s__frames b { font-size: 12px; font-weight: 500; color: var(--color-a47-ink); }

.a47s__field { display: grid; row-gap: 2px; padding: 10px 14px; border-radius: 8px; background: var(--color-a47-fill); font-size: 14px; }
.a47s__field small { font-size: 11px; color: var(--color-a47-muted); }

/* The menu: the studio's sidebar, Home picked. */
.a47s__card--menu { width: min(100%, 240px); row-gap: 18px; }
.a47s__brand { font-size: 22px; font-weight: 600; letter-spacing: -0.01em; }
.a47s__brand b { font-style: italic; color: var(--color-a47-rust); }
.a47s__nav { display: grid; row-gap: 10px; margin: 0; padding: 0; list-style: none; font-size: 15px; color: var(--color-a47-muted); }
.a47s__nav li { display: flex; align-items: center; gap: 14px; }
.a47s__navicon { display: grid; place-items: center; width: 34px; height: 34px; border-radius: 8px; background: var(--color-a47-fill); }
.a47s__nav .is-on { color: var(--color-a47-rust); }
.a47s__nav .is-on .a47s__navicon { background: var(--color-a47-rust); color: var(--color-a47-surface); }

/* Home: the studio's opening, the display line in Fraunces over the one prompt box. */
.a47s__home { display: grid; justify-items: center; row-gap: 22px; width: min(100%, 680px); }
.a47s__display { font-family: var(--font-a47-serif); font-size: clamp(26px, 3.6vw, 46px); font-weight: 500; line-height: 1.1; letter-spacing: -0.01em; text-align: center; }
.a47s__box { display: grid; row-gap: 30px; width: 100%; padding: 20px; border-radius: 8px; background: var(--color-a47-fill); color: var(--color-a47-ink); }
.a47s__ph { font-size: 16px; color: var(--color-a47-soft); }
.a47s__boxrow { display: flex; align-items: center; gap: 10px; }
.a47s__chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 14px;
  border: 1px solid var(--color-a47-rule-strong);
  border-radius: 999px;
  background: var(--color-a47-surface);
  font-size: 13px;
}
.a47s__chip.is-on { background: var(--a47s-tint); border-color: var(--a47s-edge); color: var(--color-a47-rust); }
.a47s__create {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-left: auto;
  padding: 9px 18px;
  border-radius: 999px;
  background: var(--a47s-muted-rust);
  color: var(--color-a47-surface);
  font-size: 13px;
}
.a47s__help { justify-self: start; font-size: 13px; color: color-mix(in srgb, var(--color-a47-surface) 70%, transparent); }

/* The voice picker, from the homepage's Audio section: three of the sixteen voices, each a bust on a rust disc
   with a play button. */
.a47s__panel--voices { aspect-ratio: 543 / 470; padding: var(--space-5) var(--space-5) var(--space-4); }
.a47s__voices { display: grid; row-gap: 22px; width: 100%; }
.a47s__num { font-family: var(--font-a47-serif); font-size: 36px; font-weight: 500; line-height: 1; letter-spacing: -0.01em; }
.a47s__num span { color: color-mix(in srgb, var(--color-a47-surface) 40%, transparent); }
.a47s__voices ul { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-3); margin: 0; padding: 0; list-style: none; text-align: center; }
.a47s__voices li { display: grid; justify-items: center; row-gap: 4px; }
.a47s__voices li img { display: block; width: min(100%, 132px); height: auto; aspect-ratio: 1; border-radius: 50%; margin-bottom: 8px; }
.a47s__voices li b { font-size: 15px; font-weight: 600; }
.a47s__voices li span { font-size: 12px; color: color-mix(in srgb, var(--color-a47-surface) 65%, transparent); }
.a47s__play { display: grid; place-items: center; width: 34px; height: 34px; margin-top: 8px; border: 1px solid color-mix(in srgb, var(--color-a47-surface) 35%, transparent); border-radius: 6px; }
.a47s__play svg { width: 12px; height: 12px; fill: currentColor; stroke: none; }
.a47s__vfoot { display: grid; row-gap: 4px; padding-top: 18px; border-top: 1px solid color-mix(in srgb, var(--color-a47-surface) 16%, transparent); font-size: 13px; color: color-mix(in srgb, var(--color-a47-surface) 65%, transparent); }
.a47s__vfoot b { font-size: 16px; font-weight: 600; color: var(--color-a47-surface); }

@media (max-width: 899px) {
  .a47s__cell, .a47s__cell--third { grid-column: 1 / -1; }
  .a47s__panel, .a47s__cell--third .a47s__panel, .a47s__panel--voices { aspect-ratio: auto; min-height: 420px; }
}

@media (max-width: 719px) {
  .a47s { gap: var(--space-5); }
  .a47s__panel { padding: var(--space-4) var(--space-3); min-height: 0; }
  .a47s__cell--wide .a47s__panel { aspect-ratio: auto; padding-block: var(--space-5); }
  .a47s__box { row-gap: 20px; padding: 14px; }
  .a47s__boxrow { flex-wrap: wrap; gap: 8px; }
  .a47s__chip { padding: 6px 10px; }
  .a47s__card { padding: 18px; }
  .a47s__panel--voices { padding: var(--space-4) var(--space-3); }
  .a47s__num { font-size: 28px; }
}
.cf-split > .a47s__cell { grid-column: auto; } /* the voice picker sits beside the last words, not in the bento's columns */
.a47s__voices li img { clip-path: circle(46.5%); } /* the crop's dark corners stay outside the disc */

/* The launch video, in moments (10 Nov): silent loops cut from the Grof launch video, one wide over two halves,
   a caption under each. The full 16:9 frame, cornered as a photograph. The playing is in main.js. */
.cf-loops {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-5) var(--space-4);
}
.cf-loop { margin: 0; }
.cf-loop--wide { grid-column: 1 / -1; }
.cf-loop__video {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: var(--radius-image);
  background: var(--color-paper);
  cursor: pointer;
}

@media (max-width: 719px) {
  .cf-loops { grid-template-columns: minmax(0, 1fr); }
}

/* Print beside the screen (10 Nov, Grof): the letterhead a third, the website two thirds, one height (the
   website's own shape sets it). On a phone the website leads, then the letterhead, square. */
.cf-duo {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
  gap: var(--space-4);
}
.cf-duo .cf-figure { margin: 0; }
.cf-duo__screen img { aspect-ratio: 1520 / 904; }
.cf-duo__print img { height: 100%; object-position: 60% 45%; }

@media (max-width: 719px) {
  .cf-duo { grid-template-columns: minmax(0, 1fr); gap: var(--space-5); }
  .cf-duo__screen { order: -1; }
  .cf-duo__print img { aspect-ratio: 1; height: auto; }
}

/* ----- Grof, on her direction (10 Nov) -----
   Chyi: Sprout Asia was "very full with colors, with very flat and singular and bright pop colors"; Grof is "a
   pastel color palette, paired with gradients, as well as the great scrapbooky style that combined with doodles,
   and a lot of human elements". Three frames say it: the brand world (.grofh), the before and after (.grofba) and
   the hello card taken apart (.grofs, on .cfa). Grof's colours are the grof- tokens, Sprout Asia's the sprout-
   tokens. grof-motion.js adds .is-on once each is in view, and .is-away while it is off screen. */
.grofh, .grofba, .grofs {
  --grof-ink: var(--color-grof-navy);
  --grof-doodle: var(--color-grof-orange);
  --grof-doodle-sky: color-mix(in srgb, var(--color-grof-sky) 70%, var(--color-grof-navy));
  --grof-wash:
    radial-gradient(55% 70% at 12% 8%, color-mix(in srgb, var(--color-grof-mist-lilac) 60%, var(--color-grof-sky)) 0%, transparent 70%),
    radial-gradient(50% 65% at 90% 92%, color-mix(in srgb, var(--color-grof-mist-sky) 40%, var(--color-grof-sky)) 0%, transparent 70%),
    radial-gradient(45% 55% at 62% 30%, color-mix(in srgb, var(--color-grof-peach) 30%, var(--color-grof-mist-cream)) 0%, transparent 72%),
    var(--color-grof-mist-cream);
}

/* The brand world: a 1036 x 616 stage scaled to the column, as the After Work Bakes hero is. */
.grofh__box { position: relative; aspect-ratio: 1036 / 616; max-width: 100%; border-radius: var(--radius-image); overflow: hidden; container-type: inline-size; isolation: isolate; }
.grofh__stage { position: absolute; left: 0; top: 0; width: 1036px; height: 616px; transform-origin: 0 0; transform: scale(calc(100cqw / 1036px)); }
@supports not (width: 1cqw) { .grofh__stage { transform: scale(var(--s, 1)); } }
.grofh__ground { position: absolute; inset: -8%; background: var(--grof-wash); }
.grofh__tile { position: absolute; overflow: hidden; border-radius: 14px; background: white; transform: rotate(var(--r)); box-shadow: 0 1px 2px color-mix(in srgb, var(--grof-ink) 8%, transparent), 0 14px 34px color-mix(in srgb, var(--grof-ink) 12%, transparent); }
.grofh__tile > img { display: block; width: 100%; height: 100%; object-fit: cover; }
.grofh__team     { left: 56px;  top: 56px;  width: 300px; height: 504px; }
.grofh__customer { left: 380px; top: 56px;  width: 300px; height: 300px; }
.grofh__mark     { left: 380px; top: 380px; width: 300px; height: 180px; background: var(--color-grof-navy); }
.grofh__paper    { left: 704px; top: 56px;  width: 276px; height: 276px; }
.grofh__drawn    { left: 704px; top: 356px; width: 276px; height: 204px; }
.grofh__drawn > img { object-fit: contain; padding: 18px 22px; }
.grofh__mark > img { object-fit: contain; }
/* Washi tape, the scrapbook's: a strip of peach over the team, one of sky over the paperwork. */
.grofh__tape { position: absolute; height: 22px; border-radius: 2px; opacity: .85; }
.grofh__tape--a { left: 168px; top: 44px; width: 78px; background: color-mix(in srgb, var(--color-grof-peach) 75%, transparent); transform: rotate(-5deg); }
.grofh__tape--b { left: 924px; top: 46px; width: 66px; background: color-mix(in srgb, var(--color-grof-sky) 85%, transparent); transform: rotate(14deg); }
.grofh__doodles { position: absolute; inset: 0; width: 1036px; height: 616px; overflow: visible; pointer-events: none; }
.grofh__ink { fill: none; stroke: var(--grof-doodle); stroke-width: 3.2; stroke-linecap: round; stroke-linejoin: round; }
.grofh__ink--sky { stroke: var(--grof-doodle-sky); }
.grofh__star .grofh__ink { stroke-width: 2.6; }
.grofh__star { transform-box: fill-box; }

@media (prefers-reduced-motion: no-preference) {
  .js .grofh:not(.is-on) .grofh__ground { opacity: .35; transform: scale(1.06); }
  .js .grofh:not(.is-on) .grofh__tile { opacity: 0; transform: translateY(26px) rotate(calc(var(--r) * 3)) scale(.96); }
  .js .grofh:not(.is-on) .grofh__tile > img { transform: scale(1.12); }
  .js .grofh:not(.is-on) .grofh__tape { opacity: 0; transform: translateY(-10px) rotate(0deg) scale(1.2); }
  .js .grofh:not(.is-on) .grofh__draw { stroke-dashoffset: 1; }
  .js .grofh:not(.is-on) .grofh__star { opacity: 0; }
  .js .grofh__ground { transition: opacity 1.4s ease-out, transform 2.2s cubic-bezier(.2, .7, .2, 1); }
  .js .grofh__tile { transition: opacity .7s ease-out var(--t), transform .9s cubic-bezier(.2, .7, .2, 1) var(--t); }
  .js .grofh__tile > img { transition: transform 1.6s cubic-bezier(.2, .7, .2, 1) var(--t); }
  .js .grofh__tape { transition: opacity .35s ease-out .95s, transform .45s cubic-bezier(.2, .8, .3, 1) .95s; }
  .js .grofh__tape--b { transition-delay: 1.05s; }
  .js .grofh__draw { stroke-dasharray: 1; transition: stroke-dashoffset var(--d, .6s) cubic-bezier(.45, 0, .25, 1) var(--t, 0s); }
  .js .grofh__star { transition: opacity .3s ease-out var(--t); }

  /* The loop, once it has played, while it is on screen: the gradient drifts behind, the sparkles twinkle. */
  .js .grofh.is-on .grofh__ground { animation: grofh-drift 14s ease-in-out 2.4s infinite alternate; }
  .js .grofh.is-on .grofh__star { animation: grofh-twinkle 2.8s ease-in-out 3.2s infinite; }
  .js .grofh.is-on .grofh__star--late { animation-delay: 3.9s; }
  .js .grofh.is-away .grofh__ground, .js .grofh.is-away .grofh__star { animation-play-state: paused; }
}
@keyframes grofh-drift {
  from { transform: translate(0, 0) scale(1); }
  to   { transform: translate(-3%, 2%) scale(1.06); }
}
@keyframes grofh-twinkle {
  0%, 100% { scale: 1; opacity: 1; }
  45%      { scale: .72; opacity: .55; }
  60%      { scale: 1.12; opacity: 1; }
}

/* Before and after: Sprout Asia's nine posts beside nine of Grof's, each with its palette. Real layout, not a
   scaled stage, so the labels stay readable on a phone. */
.grofba {
  position: relative;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-3);
  margin: 0;
  font-family: var(--font-serif);
  color: var(--grof-ink);
}
.grofba__side { display: grid; align-content: start; row-gap: var(--space-3); padding: var(--space-3); border-radius: var(--radius-image); }
.grofba__side--before { background: white; box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--grof-ink) 10%, transparent); }
.grofba__side--after { background: var(--grof-wash); }
.grofba__label { margin: 0; font-size: 12px; line-height: 1.3; letter-spacing: .12em; text-transform: uppercase; color: color-mix(in srgb, var(--grof-ink) 70%, transparent); }
.grofba__grid { display: block; width: 100%; height: auto; aspect-ratio: 1; border-radius: 6px; }
.grofba__posts { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 4px; margin: 0; padding: 0; list-style: none; aspect-ratio: 1; }
.grofba__posts li { min-width: 0; overflow: hidden; border-radius: 3px; background: color-mix(in srgb, var(--grof-ink) 6%, white); }
.grofba__posts img { display: block; width: 100%; height: 100%; object-fit: cover; font-size: 0; }
.grofba__chips { display: flex; gap: 6px; margin: 0; padding: 0; list-style: none; }
.grofba__chip { display: block; width: 18px; height: 18px; border-radius: var(--radius-sm); }
.grofba__chip--gradient { width: 42px; border-radius: var(--radius-pill); background: linear-gradient(90deg, color-mix(in srgb, var(--color-grof-mist-lilac) 50%, var(--color-grof-sky)), var(--color-grof-mist-cream), color-mix(in srgb, var(--color-grof-peach) 55%, white)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--grof-ink) 10%, transparent); }
.grofba__note { margin: 0; font-size: 14px; line-height: 1.4; }
.grofba__arrow { position: absolute; left: 50%; top: -6px; width: 60px; height: 40px; translate: -50% 0; overflow: visible; pointer-events: none; }
.grofba__ink { fill: none; stroke: var(--grof-doodle); stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round; }

@media (prefers-reduced-motion: no-preference) {
  .js .grofba:not(.is-on) .grofba__side { opacity: 0; transform: translateY(18px); }
  .js .grofba:not(.is-on) .grofba__posts li { opacity: 0; transform: scale(.86); }
  .js .grofba:not(.is-on) .grofba__side--after .grofba__chips li, .js .grofba:not(.is-on) .grofba__side--after .grofba__note { opacity: 0; transform: translateY(6px); }
  .js .grofba:not(.is-on) .grofba__ink { stroke-dashoffset: 1; }
  .js .grofba__side { transition: opacity .6s ease-out, transform .7s cubic-bezier(.2, .7, .2, 1); }
  .js .grofba__side--after { transition-delay: .25s; }
  .js .grofba__posts li { transition: opacity .45s ease-out calc(.7s + var(--i) * 90ms), transform .55s cubic-bezier(.2, .8, .3, 1) calc(.7s + var(--i) * 90ms); }
  .js .grofba__side--after .grofba__chips li, .js .grofba__side--after .grofba__note { transition: opacity .4s ease-out 1.65s, transform .4s ease-out 1.65s; }
  .js .grofba__ink { stroke-dasharray: 1; transition: stroke-dashoffset .6s cubic-bezier(.45, 0, .25, 1) .45s; }
  .js .grofba__ink--head { transition-delay: 1s; transition-duration: .2s; }
}

@media (max-width: 719px) {
  .grofba { gap: var(--space-2); }
  .grofba__side { padding: var(--space-2); row-gap: var(--space-2); }
  .grofba__label { font-size: 11px; letter-spacing: .08em; }
  .grofba__note { font-size: 13px; }
  .grofba__chip { width: 14px; height: 14px; }
  .grofba__chip--gradient { width: 30px; }
  .grofba__posts { gap: 3px; }
  .grofba__arrow { display: none; }
}

/* The hello card taken apart, on Grof's gradient, in motion as the After Work Bakes logo frame is. */
.grofs .cfa__box { background: var(--grof-wash); }
.cfa__palette { position: absolute; left: 0; right: 0; top: 596px; display: flex; justify-content: center; align-items: center; gap: 32px; margin: 0; padding: 0; list-style: none; font-size: 14px; color: var(--cfa-ink-2); }
.cfa__palette li { display: flex; align-items: center; gap: 8px; }
.cfa__palette li > span { width: 16px; height: 16px; flex: none; border-radius: 3px; }
.cfa__palette code { font: 400 11px/1.4 var(--font-serif); letter-spacing: .14em; color: var(--cfa-ink-3); }
.cfa__palette .cfa__gradient { width: 40px; border-radius: 999px; background: linear-gradient(90deg, color-mix(in srgb, var(--color-grof-mist-lilac) 50%, var(--color-grof-sky)), var(--color-grof-mist-cream), color-mix(in srgb, var(--color-grof-peach) 55%, white)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--grof-ink) 12%, transparent); }
.grofs .cfa__card { box-shadow: 0 1px 2px color-mix(in srgb, var(--grof-ink) 8%, transparent), 0 18px 40px color-mix(in srgb, var(--grof-ink) 12%, transparent); }
@container (max-width: 699px) { .cfa__palette { display: none; } }

@media (prefers-reduced-motion: no-preference) {
  .js .grofs:not(.is-on) .cfa__card { opacity: 0; transform: translateY(20px); }
  .js .grofs:not(.is-on) .cfa__draw { stroke-dashoffset: 1; }
  .js .grofs:not(.is-on) .cfa__end, .js .grofs:not(.is-on) .cfa__note, .js .grofs:not(.is-on) .cfa__palette li { opacity: 0; }
  .js .grofs:not(.is-on) .cfa__note, .js .grofs:not(.is-on) .cfa__palette li { transform: translateY(8px); }
  .js .grofs .cfa__card { transition: opacity .7s ease-out, transform .8s cubic-bezier(.2, .7, .2, 1); }
  .js .grofs .cfa__draw { stroke-dasharray: 1; transition: stroke-dashoffset .45s cubic-bezier(.3, 0, .2, 1) var(--t, 0s); }
  .js .grofs .cfa__end { transition: opacity .25s ease-out var(--t, 0s); }
  .js .grofs .cfa__note, .js .grofs .cfa__palette li { transition: opacity .5s ease-out var(--t, 0s), transform .5s ease-out var(--t, 0s); }
}

/* ----- A47, the process (10 Nov) -----
   Chyi: "update A47's hero image to match the bento-grid style of other two case studies ... the photo mission
   control photo is redundant. The whole process seems not thought through." The page keeps layout F's blocks and
   gains the thinking: the opening bento (.a47h), the two looks before (.a47ba), the research wall softened (.a47w),
   James and Jenna (.a47p), James's journey (.a47j), the three boards and the three landing versions (two rows of
   .cf-three), and the chosen direction taken apart (.a47k, on .cfa). A47's colours are the a47- tokens, inside its
   own pictures only; the cards and sheets are the site's paper. a47-motion.js adds .is-on once a frame is in view. */

/* The opening bento: a 1036 x 616 stage scaled to the column, as Grof's and After Work Bakes' are. A47's look is
   calm and square, so the tiles sit straight, with tighter corners and no tape. */
.a47h { --a47h-night: color-mix(in srgb, var(--color-a47-ink) 78%, black); }
.a47h__box { position: relative; aspect-ratio: 1036 / 616; max-width: 100%; border-radius: var(--radius-image); overflow: hidden; container-type: inline-size; isolation: isolate; background: var(--color-a47-fill); }
.a47h__stage { position: absolute; left: 0; top: 0; width: 1036px; height: 616px; transform-origin: 0 0; transform: scale(calc(100cqw / 1036px)); font-family: var(--font-a47-sans); letter-spacing: 0; color: var(--color-a47-ink); }
@supports not (width: 1cqw) { .a47h__stage { transform: scale(var(--s, 1)); } }
.a47h__tile { position: absolute; overflow: hidden; border-radius: 10px; background: var(--color-a47-surface); box-shadow: 0 1px 2px color-mix(in srgb, var(--color-a47-ink) 8%, transparent), 0 14px 34px color-mix(in srgb, var(--color-a47-ink) 10%, transparent); }
.a47h__tile > img { display: block; width: 100%; height: 100%; object-fit: cover; }
.a47h__home   { left: 56px;  top: 56px;  width: 604px; height: 320px; }
.a47h__home > img { object-position: 50% 0; }
.a47h__piece  { left: 684px; top: 56px;  width: 296px; height: 320px; }
.a47h__mark   { left: 56px;  top: 400px; width: 220px; height: 160px; display: grid; place-items: center; background: var(--color-a47-rust); }
.a47h__studio { left: 300px; top: 400px; width: 360px; height: 160px; display: grid; align-content: center; justify-items: center; row-gap: 16px; background: var(--a47h-night); }
.a47h__voice  { left: 684px; top: 400px; width: 296px; height: 160px; }
.a47h__tag { position: absolute; left: 12px; top: 12px; padding: 3px 8px; border-radius: 4px; background: color-mix(in srgb, var(--color-a47-surface) 90%, transparent); font-size: 11px; line-height: 1.4; font-weight: 600; }
.a47h__word { font-size: 31px; line-height: 1; font-weight: 600; letter-spacing: -0.01em; color: var(--color-a47-surface); }
.a47h__word b { font-style: italic; font-weight: 800; }
.a47h__ask { margin: 0; font-family: var(--font-a47-serif); font-size: 24px; line-height: 1.1; font-weight: 500; letter-spacing: -0.01em; color: var(--color-a47-surface); }
.a47h__prompt { display: flex; align-items: center; justify-content: space-between; width: 300px; height: 44px; padding: 0 8px 0 14px; border-radius: 8px; background: color-mix(in srgb, var(--color-a47-surface) 9%, transparent); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--color-a47-surface) 18%, transparent); font-size: 12px; color: color-mix(in srgb, var(--color-a47-surface) 64%, transparent); }
.a47h__create { padding: 6px 12px; border-radius: 6px; background: var(--color-a47-rust); font-weight: 600; color: var(--color-a47-surface); }
.a47h__disc { position: absolute; left: 30px; top: 24px; width: 112px; height: 112px; border-radius: 50%; background: var(--color-a47-rust); }
.a47h__voice > .a47h__bust { position: absolute; left: 14px; top: 10px; width: 150px; height: auto; object-fit: contain; }
.a47h__who { position: absolute; left: 172px; top: 34px; display: grid; row-gap: 3px; font-size: 12px; line-height: 1.35; color: var(--color-a47-muted); }
.a47h__who b { font-size: 17px; font-weight: 600; color: var(--color-a47-ink); }
.a47h__num { font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--color-a47-rust); }
.a47h__play { display: grid; place-items: center; width: 26px; height: 26px; margin-top: 8px; border-radius: 50%; background: var(--color-a47-ink); }
.a47h__play svg { width: 13px; height: 13px; fill: var(--color-a47-surface); }

@media (prefers-reduced-motion: no-preference) {
  .js .a47h:not(.is-on) .a47h__tile { opacity: 0; transform: translateY(22px) scale(.98); }
  .js .a47h:not(.is-on) .a47h__home > img, .js .a47h:not(.is-on) .a47h__piece > img { transform: scale(1.08); }
  .js .a47h__tile { transition: opacity .7s ease-out var(--t), transform .9s cubic-bezier(.2, .7, .2, 1) var(--t); }
  .js .a47h__home > img, .js .a47h__piece > img { transition: transform 1.6s cubic-bezier(.2, .7, .2, 1) var(--t); }
}

/* The two looks, before: the orange studio above, the company's website laid over its corner. Real layout, not a
   scaled stage, so the labels stay readable on a phone. */
.a47ba { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); margin: 0; font-family: var(--font-serif); }
.a47ba__shot { display: grid; row-gap: var(--space-2); }
.a47ba__shot--studio { grid-column: 1 / span 9; grid-row: 1; }
.a47ba__shot--site { grid-column: 4 / span 9; grid-row: 2; position: relative; margin-top: calc(-1 * var(--space-5)); }
.a47ba__shot img { display: block; width: 100%; height: auto; border-radius: 8px; box-shadow: 0 0 0 1px color-mix(in srgb, var(--color-ink-strong) 10%, transparent), 0 12px 30px color-mix(in srgb, var(--color-ink-strong) 12%, transparent); }
.a47ba__cap { margin: 0; font-size: 14px; line-height: 1.4; color: var(--color-ink); }
.a47ba__shot--site .a47ba__cap { text-align: right; }
.a47ba__label { display: block; font-size: 12px; line-height: 1.4; letter-spacing: .14em; text-transform: uppercase; color: var(--color-ink-muted); }

/* Pictures with a caption under them: the picture keeps its own shape (the template's pictures fill their cell). */
.a47w img, .cf-three--boards img, .cf-three--screens img { height: auto; }
.a47w img { aspect-ratio: 2240 / 1178; }
.cf-split .a47m img { aspect-ratio: 1364 / 938; }
.cf-three--boards img { aspect-ratio: 841 / 1174; box-shadow: 0 0 0 1px var(--color-line); }
.cf-three--screens img { aspect-ratio: 16 / 9; object-position: 50% 0; box-shadow: 0 0 0 1px var(--color-line); }

/* James and Jenna: two cards in her words, on the site's paper. Label, name, the line, the quote, the job they
   hire A47 for on the palest tint, and what frustrates them. */
.a47p, .a47j { --a47-sheet: color-mix(in srgb, white 55%, var(--color-paper)); font-family: var(--font-serif); color: var(--color-ink-strong); }
.a47p { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-4); }
.a47p__card { display: flex; flex-direction: column; gap: var(--space-3); padding: var(--space-4); border-radius: var(--radius-image); background: var(--a47-sheet); box-shadow: inset 0 0 0 1px var(--color-line); }
.a47p__head { display: flex; align-items: center; gap: var(--space-3); }
.a47p__face { flex: none; width: 72px; height: 72px; border-radius: 50%; box-shadow: 0 0 0 1px var(--color-line); }
.a47p__label { margin: 0; font-size: 12px; line-height: 1.4; letter-spacing: .14em; text-transform: uppercase; color: var(--color-ink-muted); }
.a47p__name { margin: 0; font-family: var(--font-statement); font-size: 28px; line-height: 1.15; font-weight: 700; letter-spacing: -0.01em; }
.a47p__line { margin: 0; font-size: 17px; line-height: 26px; color: var(--color-ink); }
.a47p__quote { margin: 0; font-family: var(--font-statement); font-size: 20px; line-height: 1.45; letter-spacing: -0.003em; }
.a47p__job { display: grid; row-gap: var(--space-1); padding: var(--space-3); border-radius: 8px; background: var(--color-bloom); }
.a47p__job p:last-child { margin: 0; font-size: 16px; line-height: 25px; }
.a47p__pain { display: grid; row-gap: var(--space-1); margin-top: auto; }
.a47p__pain ul { display: grid; row-gap: 2px; margin: 0; padding: 0; list-style: none; font-size: 16px; line-height: 25px; }
.a47p__pain li { position: relative; padding-left: var(--space-3); }
.a47p__pain li::before { content: ""; position: absolute; left: 0; top: 12px; width: 8px; height: 1px; background: var(--color-ink-muted); }

/* James's first two weeks: nine stages across, her emotion curve above them. */
.a47j { margin: 0; }
.a47j__sheet { padding: var(--space-4); border-radius: var(--radius-image); background: var(--a47-sheet); box-shadow: inset 0 0 0 1px var(--color-line); }
.a47j__title { margin: var(--space-1) 0 var(--space-4); font-family: var(--font-statement); font-size: 22px; line-height: 1.3; font-weight: 700; letter-spacing: -0.01em; }
.a47j__legend { display: none; }
.a47j__chart { position: relative; }
.a47j__axis { position: absolute; left: 0; font-size: 12px; line-height: 1; letter-spacing: .14em; text-transform: uppercase; color: var(--color-ink-muted); }
.a47j__axis--up { top: 10px; }
.a47j__axis--down { top: 98px; }
.a47j__curve { position: absolute; left: 0; top: 0; width: 100%; height: 120px; overflow: visible; }
.a47j__path { fill: none; stroke: var(--color-ink-strong); stroke-width: 1.5; stroke-linejoin: round; }
.a47j__stages { display: grid; grid-template-columns: repeat(9, minmax(0, 1fr)); margin: 0; padding: 0; list-style: none; }
.a47j__stages li { position: relative; display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 144px var(--space-1) 0; text-align: center; }
.a47j__dot { position: absolute; left: 50%; top: calc(16px + (1 - var(--v)) * 88px); width: 11px; height: 11px; margin: -5.5px 0 0 -5.5px; border-radius: 50%; background: var(--color-ink-strong); box-shadow: 0 0 0 3px var(--a47-sheet); }
.a47j__num { font-size: 12px; line-height: 1.4; letter-spacing: .14em; color: var(--color-ink-muted); }
.a47j__name { font-size: 14px; line-height: 1.3; font-weight: 700; text-wrap: balance; }
.a47j__feel { font-size: 13px; line-height: 1.3; font-style: italic; color: var(--color-ink); }
.a47j__stages .is-low .a47j__dot { background: var(--color-action); }
.a47j__stages .is-low .a47j__feel { color: var(--color-action); }

@media (prefers-reduced-motion: no-preference) {
  .js .a47j:not(.is-on) .a47j__path { stroke-dashoffset: 1; }
  .js .a47j:not(.is-on) .a47j__dot { opacity: 0; scale: .4; }
  .js .a47j__path { stroke-dasharray: 1; transition: stroke-dashoffset 1.9s cubic-bezier(.45, 0, .25, 1) .2s; }
  .js .a47j__dot { transition: opacity .3s ease-out calc(.2s + var(--i) * .21s), scale .35s cubic-bezier(.2, .8, .3, 1) calc(.2s + var(--i) * .21s); }
}

/* The chosen direction taken apart, on the shared annotated frame: the board is tall, so it stands a little
   higher than Grof's card and the narrow view zooms to fit it. */
.a47k .cfa__box { background: color-mix(in srgb, white 55%, var(--color-paper)); box-shadow: inset 0 0 0 1px var(--color-line); }
.a47k .cfa__card { border-radius: 8px; box-shadow: 0 0 0 1px var(--color-line), 0 18px 40px color-mix(in srgb, var(--color-ink-strong) 12%, transparent); }
@container (max-width: 699px) {
  .a47k .cfa__stage { transform: scale(calc(100cqw / 560px)) translate(-280px, -22px); }
}
@media (max-width: 739px) {
  .a47k .cfa__box { aspect-ratio: 560 / 561; }
  .a47k .cfa__list .cfa__eyebrow { font-size: 12px; } /* the 12px floor */
}
@media (prefers-reduced-motion: no-preference) {
  .js .a47k:not(.is-on) .cfa__card { opacity: 0; transform: translateY(20px); }
  .js .a47k:not(.is-on) .cfa__draw { stroke-dashoffset: 1; }
  .js .a47k:not(.is-on) .cfa__end, .js .a47k:not(.is-on) .cfa__note, .js .a47k:not(.is-on) .cfa__palette li { opacity: 0; }
  .js .a47k:not(.is-on) .cfa__note, .js .a47k:not(.is-on) .cfa__palette li { transform: translateY(8px); }
  .js .a47k .cfa__card { transition: opacity .7s ease-out, transform .8s cubic-bezier(.2, .7, .2, 1); }
  .js .a47k .cfa__draw { stroke-dasharray: 1; transition: stroke-dashoffset .45s cubic-bezier(.3, 0, .2, 1) var(--t, 0s); }
  .js .a47k .cfa__end { transition: opacity .25s ease-out var(--t, 0s); }
  .js .a47k .cfa__note, .js .a47k .cfa__palette li { transition: opacity .5s ease-out var(--t, 0s), transform .5s ease-out var(--t, 0s); }
}

@media (max-width: 719px) {
  .cf-three--boards img { aspect-ratio: 841 / 1174; }
  .cf-three--screens img { aspect-ratio: 16 / 9; }
  .a47ba__shot--site { margin-top: calc(-1 * var(--space-4)); }
  .a47p { grid-template-columns: minmax(0, 1fr); }
  .a47p__card, .a47j__sheet { padding: var(--space-3); }
  .a47p__quote { font-size: 18px; }
  /* The journey reads down the page: number, stage and feeling on the left, and on the right a short track where
     the dot sits further right the better he feels. */
  .a47j__curve, .a47j__axis { display: none; }
  .a47j__legend { display: block; margin: calc(-1 * var(--space-2)) 0 var(--space-3); font-size: 13px; line-height: 1.4; color: var(--color-ink-muted); }
  .a47j__title { font-size: 20px; }
  .a47j__stages { grid-template-columns: minmax(0, 1fr); row-gap: var(--space-2); }
  .a47j__stages li { display: grid; grid-template-columns: 28px minmax(0, 1fr) 88px; column-gap: var(--space-2); align-items: center; padding: 0; text-align: left; }
  .a47j__stages li::after { content: ""; grid-column: 3; grid-row: 1 / span 2; height: 1px; background: var(--color-line); }
  .a47j__num { grid-column: 1; grid-row: 1 / span 2; }
  .a47j__name { grid-column: 2; grid-row: 1; text-wrap: wrap; }
  .a47j__feel { grid-column: 2; grid-row: 2; }
  .a47j__dot { position: relative; z-index: 1; grid-column: 3; grid-row: 1 / span 2; left: auto; top: auto; margin: 0; justify-self: start; translate: calc(var(--v) * 77px) 0; }
}
