/* ==========================================================================
   Camera lab: the public site

   Adapted from the Guell and Atelier mockups (kept beside the site in
   C:\bitgon\www\camera-lab-redesign): cream paper,
   a serif for everything, mosaic textures and pebble shapes. The admin
   keeps app.css; the two share tokens.css and site.css.

   Mobile first: the base rules describe a 360px phone, and min-width
   queries add width. Nothing below is desktop-only.

   Order: reset, text, buttons, header, the front page section by section,
   the simulator page and its sidebar, About and Contact, the footer.
   ========================================================================== */

*, *::before, *::after { box-sizing: inherit }

html {
  height: 100%;
  scroll-padding-top: calc(var(--top) + 12px);
  -webkit-text-size-adjust: 100%;
}

body {
  min-height: 100%;
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
  font-size: 17px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
  /* the hero's chimney and the pebbles lean past the edge of the page; clip
     rather than hide, so the sticky header still sticks */
  overflow-x: clip;
}

:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px }
::selection { background: color-mix(in srgb, var(--amber) 45%, transparent) }

img, svg { max-width: 100%; height: auto }
a { color: var(--accent); text-underline-offset: 3px }
a:hover { color: var(--rust) }
h1, h2, h3, h4 { margin: 0; font-weight: 600; line-height: 1.1; letter-spacing: -.015em }
p { margin: 0 }
em { font-style: italic }

/* Every icon comes from app/views/icon.php and carries .ico. */
.ico {
  width: 1.2em; height: 1.2em; flex: none;
  fill: none; stroke: currentColor; stroke-width: 1.6;
}
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.muted { color: var(--muted) }

/* a small letterspaced line above a heading, set in the serif */
.kicker {
  display: inline-flex; align-items: center; gap: 12px;
  font-size: 12px; letter-spacing: .22em; text-transform: uppercase;
  color: var(--rust);
}
.kicker::before { content: ""; width: 36px; height: 1px; background: currentColor }
.kicker--plain::before { display: none }

/* ------------------------------------------------------------- buttons
   A pebble: a soft, uneven pill. --pebble-a and --pebble-b are mirror
   images, so a pair of buttons lean toward each other. */

.btn, .pill {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 48px; padding: 0 22px;
  font: inherit; font-size: 16px; font-weight: 600; line-height: 1.2;
  color: var(--ink); text-decoration: none; white-space: nowrap;
  background: color-mix(in srgb, var(--surface) 85%, transparent);
  border: 0; border-radius: var(--pebble-a);
  box-shadow: inset 0 0 0 2px var(--accent);
  cursor: pointer;
  transition: background .2s, transform .2s;
}
.btn:hover, .pill:hover { color: var(--ink); background: var(--surface) }
.btn[hidden] { display: none }
.btn--alt, .pill--alt { border-radius: var(--pebble-b) }
.btn--primary, .pill--rust {
  color: var(--cream); background: var(--rust);
  box-shadow: inset 0 0 0 3px var(--rust), inset 0 0 0 5px var(--bg);
}
.btn--primary:hover, .pill--rust:hover { color: var(--cream); background: var(--rust-deep) }
.btn--quiet, .pill--quiet { background: transparent; box-shadow: none; color: var(--muted) }
.btn--quiet:hover, .pill--quiet:hover { background: color-mix(in srgb, var(--amber) 30%, transparent); color: var(--ink) }
.btn--sm, .pill--sm { min-height: 40px; padding: 0 16px; font-size: 15px }
.btn--block { width: 100%; justify-content: center }

/* "All simulators": on a phone, a bar across the header under the name,
   naming the simulator that is open; a tap drops the list under the
   header. Hidden from 768px up, where the sidebar is always on screen.
   Its basis is nearly the full width, so it starts its own line and
   leaves room for Feedback beside it. */
.navbtn {
  order: 9; flex: 1 1 calc(100% - 60px); min-width: 0;
  display: flex; align-items: center; gap: 10px;
  min-height: 44px; margin: 2px 0 8px; padding: 0 14px;
  font: inherit; font-size: 15px; text-align: left; white-space: nowrap;
  color: var(--ink); background: color-mix(in srgb, var(--surface) 85%, transparent);
  border: 0; border-radius: var(--pebble-b);
  box-shadow: inset 0 0 0 2px var(--accent);
  cursor: pointer;
}
.navbtn:hover { background: var(--surface) }
.navbtn .ico { width: 18px; height: 18px; color: var(--accent) }
.navbtn-all { flex: none; font-style: italic }
.navbtn-here { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--muted) }
.navbtn-caret { flex: none; margin-left: auto; color: var(--rust); transition: transform .2s }
.navbtn-caret::after { content: "\203A"; display: block; font-size: 1.3em; line-height: 1; transform: rotate(90deg) }
.navbtn[aria-expanded="true"] .navbtn-caret { transform: rotate(180deg) }

/* a chip is a state, never a decoration */
.chip {
  display: inline-block; padding: 3px 10px;
  font-size: 11px; letter-spacing: .12em; text-transform: uppercase;
  color: var(--muted); background: var(--surface-2);
  border-radius: 999px;
}
.chip--flag { color: var(--rust); background: transparent; box-shadow: inset 0 0 0 1px var(--rust) }

/* ------------------------------------------------------------- the shell */

.shell { display: flex; flex-direction: column; min-height: 100dvh }
.main { flex: 1; min-width: 0; display: flex; flex-direction: column }
.main > main { flex: 1; min-width: 0 }
.wrap { width: 100%; max-width: 1440px; margin: 0 auto; padding: 0 var(--gutter) }

/* ------------------------------------------------------------- the header
   Sticky, a little translucent, over whatever the page puts under it. */

.top {
  position: sticky; top: 0; z-index: 30;
  padding-top: env(safe-area-inset-top, 0px);
  background: color-mix(in srgb, var(--bg) 86%, transparent);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  border-bottom: 1px solid color-mix(in srgb, var(--ink) 18%, transparent);
}
.top-in {
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px;
  min-height: var(--top);
  max-width: 1440px; margin: 0 auto;
  padding: 6px 10px 6px var(--gutter);
}
.top-in .sp { flex: 1 }

/* the mark and the name are in site.css, shared with the admin */

/* what you are in, beside the name, on a simulator page */
.crumb {
  min-width: 0; margin-left: 14px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: .95rem; font-style: italic; color: var(--muted);
}
.crumb a { color: var(--muted); text-decoration: none }
.crumb b { color: var(--ink); font-weight: 600 }

/* About me, Contact, Feedback and the coffee button. From 768px they sit on
   the header's line, with no frame around them; on a phone they drop to a
   second, scrolling line under it. */
.sitenav {
  order: 9; flex: 1 0 100%;
  display: flex; align-items: center; gap: 4px;
  overflow-x: auto; padding: 2px 0 8px;
  scrollbar-width: none;
}
.sitenav::-webkit-scrollbar { display: none }
.sitenav a, .sitenav .linkbtn {
  display: inline-flex; align-items: center; gap: 8px;
  min-height: 40px; padding: 0 14px;
  font: inherit; font-size: 15px; font-style: italic; white-space: nowrap;
  color: var(--ink); text-decoration: none;
  background: none; border: 0; border-radius: 999px; cursor: pointer;
}
.sitenav a:hover, .sitenav .linkbtn:hover { color: var(--ink); background: color-mix(in srgb, var(--amber) 35%, transparent) }
.sitenav a[aria-current="page"] { background: color-mix(in srgb, var(--amber) 50%, transparent) }
.feedback-btn .ico { width: 17px; height: 17px }
.feedback-btn[hidden] { display: none }
.topauth {
  padding: 8px 10px;
  font-size: .95rem; font-style: italic; text-decoration: none; white-space: nowrap;
  color: var(--ink);
}

@media (min-width: 768px) {
  .sitenav {
    order: 0; flex: 0 1 auto;
    padding: 4px; margin-right: 6px;
  }
}
/* a phone header cannot hold the crumb as well as the toggles; the
   simulator's own title is in the frame anyway */
@media (max-width: 767px) {
  .crumb { display: none }
  /* On a simulator page the second line is the "All simulators" bar and
     Feedback, as a pen alone. About me, Contact and the coffee button are
     at the foot of the list the bar opens (lab-nav.php). */
  .top--lab .sitenav { order: 10; flex: 0 0 auto; overflow: visible; padding: 2px 0 8px }
  .top--lab .sitenav > a[href] { display: none }
  .top--lab .feedback-btn { width: 44px; min-height: 44px; padding: 0; justify-content: center }
  .top--lab .feedback-words {
    position: absolute; width: 1px; height: 1px; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
  }
}
@media (max-width: 560px) {
  .topauth { display: none }
}
/* ------------------------------------------------------------- the front page

   Top to bottom: the hero on a sky, a crest of scallops and tile, the six
   groups as pebbles on a serpent bench, four pictures from the notebook on
   green, then one section per group, the street of makers for the camera
   pages, and the footer. */

/* ---- the hero */

.sky {
  position: relative; overflow: hidden;
  background:
    radial-gradient(ellipse 34% 22% at 78% 18%, color-mix(in srgb, var(--surface) 95%, transparent), transparent 70%),
    radial-gradient(ellipse 28% 16% at 30% 8%, color-mix(in srgb, var(--surface) 80%, transparent), transparent 70%),
    linear-gradient(180deg, var(--sky-deep), var(--sky) 60%, var(--gold-pale));
}
.hero {
  position: relative; z-index: 2;
  display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between;
  gap: 24px;
  max-width: 1440px; margin: 0 auto;
  padding: clamp(28px, 6vw, 72px) var(--gutter) 0;
}
.hero-words { position: relative; flex: 1 1 420px; min-width: 0; padding-bottom: clamp(32px, 8vw, 120px) }
.hero-blob {
  position: absolute; z-index: -1; left: -8%; top: -6%; width: 92%; height: 78%;
  background: color-mix(in srgb, var(--surface) 70%, transparent);
  border-radius: 58% 42% 50% 50% / 46% 56% 44% 54%;
  filter: blur(1px);
}
.hero h1 {
  margin: 0 0 0 -.04em;
  font-size: clamp(50px, 10vw, 156px); line-height: .9; letter-spacing: -.035em;
}
.hero h1 span { display: block }
.hero h1 .l2 { margin-left: .5em }
.hero h1 .l3 { margin-left: .15em }
.hero h1 em, .hero h1 .l3 em { font-style: italic; font-weight: 400; color: var(--rust) }

/* The gatehouse: a mosaic building with a chimney, a crested roof, a round
   window that shows a simulator, a rose and a green door. Pure CSS apart
   from the picture in the window. */
.gatehouse {
  position: relative; flex: 0 1 520px; min-width: min(100%, 300px);
  height: clamp(400px, 52vw, 640px); margin: 0 0 40px;
}
.gh-chimney {
  position: absolute; z-index: 1; left: 60%; top: 0;
  width: clamp(52px, 5.4vw, 76px); height: 58%;
  border-radius: 40px 40px 10px 10px;
  background: conic-gradient(var(--accent) 25%, var(--cream) 0 50%, var(--accent) 0 75%, var(--cream) 0) 0 0 / 18px 18px;
  box-shadow: inset 0 0 0 4px var(--cream);
}
.gh-cap {
  position: absolute; z-index: 2; left: calc(60% - 14px); top: -46px;
  width: calc(clamp(52px, 5.4vw, 76px) + 28px); height: 62px;
  border-radius: 50% 50% 46% 54% / 64% 60% 40% 36%;
  background: var(--rust) url(../img/mosaic-warm.svg) 0 0 / 90px;
  box-shadow: inset 0 -6px 0 var(--cream);
}
.gh-tower {
  position: absolute; z-index: 1; left: 4%; top: 20%; width: 26%; height: 30%;
  border-radius: 50% 50% 12px 12px / 60% 60% 12px 12px;
  background: var(--rust) url(../img/mosaic-cool.svg) 0 0 / 110px;
}
.gh-wall {
  position: absolute; z-index: 3; left: 0; right: 0; bottom: 0; height: 74%;
  border-radius: 46% 54% 4px 4px / 34% 42% 4px 4px;
  background: var(--rust) url(../img/mosaic-warm.svg) 0 0 / 160px;
  box-shadow: 0 40px 70px -40px oklch(0.35 0.1 40 / 0.7);
}
.gh-crest {
  position: absolute; left: -3%; right: -3%; top: -18px; height: 64px;
  border-radius: 48% 52% 50% 50% / 100% 100% 40% 40%;
  background: radial-gradient(circle at 50% 50%, var(--accent) 0 3px, transparent 4px) 0 0 / 22px 22px, var(--cream);
  box-shadow: 0 6px 0 var(--cream-2);
}
.gh-scallop {
  position: absolute; left: 0; right: 0; top: 40px; height: 34px;
  background: radial-gradient(ellipse 11px 30px at 50% 0, var(--cream) 94%, transparent 100%) 0 0 / 38px 34px repeat-x;
}
/* The picture fills the whole opening and the cream frame is drawn over it
   (::after), so the frame always sits in front of the picture. clip-path
   clips the picture to the arch; overflow and border-radius alone let its
   corners show over the frame in Chrome. */
.gh-window {
  position: absolute; left: 11%; top: 24%; width: 50%; height: 56%;
  border-radius: 50% 50% 10px 10px / 38% 38% 10px 10px;
  background: var(--cream);
  box-shadow: 0 0 0 4px var(--accent);
}
.gh-window::after {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  border: 10px solid var(--cream);
  border-radius: inherit;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 35%, transparent);
}
.gh-window-in {
  position: relative; display: block; width: 100%; height: 100%; overflow: hidden;
  border-radius: inherit;
  clip-path: inset(0 round 50% 50% 10px 10px / 38% 38% 10px 10px);
  background: var(--sky);
}
.gh-window img { display: block; width: 100%; height: 100%; object-fit: cover }
.gh-mullions {
  position: absolute; inset: 0; pointer-events: none;
  background:
    linear-gradient(90deg, transparent calc(33% - 2px), var(--accent) calc(33% - 2px) 33%, transparent 33% calc(66% - 2px), var(--accent) calc(66% - 2px) 66%, transparent 66%),
    linear-gradient(0deg, transparent calc(40% - 2px), var(--accent) calc(40% - 2px) 40%, transparent 40%);
}
.gh-rose {
  position: absolute; right: 12%; top: 32%; width: 18%; aspect-ratio: 1;
  border-radius: 50%;
  background: conic-gradient(var(--accent) 25%, var(--cream) 0 50%, var(--accent) 0 75%, var(--cream) 0) 0 0 / 12px 12px;
  box-shadow: 0 0 0 6px var(--cream), 0 0 0 9px var(--accent);
}
.gh-door {
  position: absolute; right: 9%; bottom: 0; width: 24%; height: 34%;
  border-radius: 999px 999px 0 0;
  background: var(--green);
  box-shadow: inset 0 0 0 6px var(--cream), inset 0 0 0 9px var(--green), inset 0 0 0 10px color-mix(in srgb, var(--cream) 50%, transparent);
}

/* ---- the crest between the hero and the page: scallops, a cream ledge,
   a rust line and a band of tile */
.crest { position: relative; z-index: 3; margin-top: 18px }
.crest-scallop {
  height: 58px;
  background:
    radial-gradient(ellipse 13px 50px at 50% 100%, var(--cream) 94%, transparent 100%) 0 6px / 44px 58px repeat-x,
    radial-gradient(ellipse 18px 42px at 50% 100%, var(--cream-2) 94%, transparent 100%) 21px 14px / 71px 58px repeat-x;
}
.crest-ledge { height: 18px; background: var(--cream); box-shadow: inset 0 -3px 0 var(--gold-deep) }
.crest-line { height: 6px; background: var(--rust) }
.crest-tile { height: 90px; background: var(--rust) url(../img/mosaic-warm.svg) 0 0 / 150px }
.crest--short .crest-tile { height: 40px }

/* ---- the bench: the six groups as pebbles on a serpent */
.bench {
  position: relative; padding: 70px 0 30px;
  background: radial-gradient(ellipse 50% 40% at 85% 10%, var(--gold-pale), transparent 70%), var(--bg);
}
.bench-head { max-width: 1440px; margin: 0 auto; padding: 0 var(--gutter) }
.bench h2, .notebook h2, .street h2 {
  margin: 0;
  font-size: clamp(38px, 6vw, 88px); line-height: .95; letter-spacing: -.03em;
}
.bench h2 { max-width: 12ch }
.bench h2 em { font-style: italic; font-weight: 400; color: var(--accent) }

.serpent { position: relative; margin-top: 10px }
.serpent svg {
  position: absolute; left: 0; top: 50%; width: 100%;
  height: clamp(200px, 28vw, 340px); transform: translateY(-50%);
  overflow: visible; pointer-events: none;
}
.serpent .s-cream { fill: none; stroke: var(--cream); stroke-width: 96; stroke-linecap: round }
.serpent .s-warm { fill: none; stroke: url(#serpent-warm); stroke-width: 80; stroke-linecap: round }
.serpent .s-cool { fill: none; stroke: url(#serpent-cool); stroke-width: 22; stroke-linecap: round }
.serpent .s-edge { fill: none; stroke: var(--cream); stroke-width: 10; stroke-linecap: round }

.pebbles {
  position: relative;
  display: flex; flex-wrap: wrap; justify-content: center; align-items: center;
  gap: 14px clamp(8px, 2vw, 28px);
  padding: 40px clamp(12px, 3vw, 40px) 50px;
}
.pebble {
  --size: 150px; --dy: 0px; --rot: 0deg;
  position: relative; display: block;
  width: var(--size); aspect-ratio: 1;
  margin-top: var(--dy); padding: 10px;
  transform: rotate(var(--rot));
  color: var(--ink); text-decoration: none;
  border-radius: 50%;
  background: var(--rust) url(../img/mosaic-warm.svg) 0 0 / 110px;
  box-shadow: 0 24px 40px -24px oklch(0.3 0.08 40 / 0.7);
  transition: transform .3s;
}
.pebble:hover { color: var(--ink); transform: rotate(0deg) scale(1.04) }
.pebble-in {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
  width: 100%; height: 100%; padding: 10px;
  border-radius: inherit; background: var(--surface); text-align: center;
}
.pebble-num { font-style: italic; font-size: clamp(24px, 3vw, 40px); line-height: 1; color: var(--rust) }
.pebble-name { font-weight: 600; font-size: clamp(14px, 1.3vw, 19px); line-height: 1.1 }
.pebble-meta { font-size: 13px; font-style: italic; color: var(--accent) }

.pebble:nth-child(6n+1) { --size: clamp(140px, 19vw, 250px); --rot: -6deg }
.pebble:nth-child(6n+2) { --size: clamp(128px, 15vw, 200px); --rot: 4deg; background-image: url(../img/mosaic-cool.svg); background-color: var(--accent) }
.pebble:nth-child(6n+2) .pebble-in { background: var(--gold-pale) }
.pebble:nth-child(6n+3) { --size: clamp(118px, 12vw, 170px); --rot: -3deg; background-image: url(../img/mosaic-garden.svg); background-color: var(--green) }
.pebble:nth-child(6n+4) { --size: clamp(136px, 17vw, 230px); --rot: 7deg; background-image: url(../img/mosaic-mixed.svg) }
.pebble:nth-child(6n+4) .pebble-in { background: var(--sky-pale) }
.pebble:nth-child(6n+5) { --size: clamp(136px, 16vw, 210px); --rot: -8deg; background-image: url(../img/mosaic-cool.svg); background-color: var(--accent) }
.pebble:nth-child(6n+6) { --size: clamp(150px, 20vw, 270px); --rot: 3deg }
.pebble:nth-child(6n+6) .pebble-in { background: var(--gold-pale) }

@media (min-width: 768px) {
  .pebble:nth-child(6n+1) { --dy: -60px }
  .pebble:nth-child(6n+2) { --dy: 70px }
  .pebble:nth-child(6n+3) { --dy: -20px }
  .pebble:nth-child(6n+4) { --dy: 90px }
  .pebble:nth-child(6n+5) { --dy: -70px }
  .pebble:nth-child(6n+6) { --dy: 30px }
  .pebbles { padding-bottom: 80px }
}

/* ---- waves between the coloured sections */
.wave { display: block; width: 100%; height: 70px }
.wave path { fill: currentColor }
.wave--to-green { background: var(--bg); color: var(--green) }
.wave--to-paper { background: var(--green); color: var(--bg) }
@media (min-width: 768px) { .wave { height: 90px } }

/* ---- the notebook: four pictures, on green */
.notebook {
  position: relative;
  padding: 30px var(--gutter) 90px;
  background: radial-gradient(ellipse 40% 30% at 10% 80%, var(--green-lit), transparent 70%), var(--green);
  color: var(--cream);
}
.notebook-in { max-width: 1440px; margin: 0 auto }
.notebook h2 { margin-left: clamp(0px, 20vw, 360px); color: var(--cream) }
.notebook h2 em { font-style: italic; font-weight: 400; color: var(--gold) }
.notebook-lede { margin: 16px 0 0 clamp(0px, 20vw, 360px); max-width: 48ch; font-size: 17px; line-height: 1.55; color: var(--cream-2) }
.notes {
  display: flex; flex-wrap: wrap; justify-content: center; align-items: flex-start;
  gap: 0 clamp(12px, 3vw, 40px);
  margin-top: 40px;
}
.note {
  --w: 300px; --dy: 0px; --rot: 0deg;
  flex: 1 1 240px; max-width: var(--w);
  display: flex; flex-direction: column; gap: 8px;
  margin: var(--dy) 0 30px; padding: 24px 30px 70px;
  text-align: center;
  transform: rotate(var(--rot));
  color: var(--cream-ink); text-decoration: none;
  border-radius: 48% 52% 44% 56% / 30% 34% 26% 30%;
  background: var(--cream);
  box-shadow: 0 30px 50px -30px oklch(0.15 0.05 165 / 0.8);
  transition: transform .3s;
}
.note:hover { color: var(--cream-ink); transform: rotate(0deg) translateY(-6px) }
.note-pic {
  aspect-ratio: 5 / 4; overflow: hidden;
  border-radius: 50% 50% 18px 18px / 40% 40% 18px 18px;
  background: var(--gold-pale);
  box-shadow: 0 0 0 5px var(--cream), 0 0 0 9px var(--ring, var(--amber));
}
.note-pic img { display: block; width: 100%; height: 100%; object-fit: cover }
.note-kicker { margin-top: 10px; font-size: 11.5px; letter-spacing: .2em; text-transform: uppercase; color: oklch(0.42 0.14 40) }
.note-title { font-weight: 600; font-size: 26px; line-height: 1.1 }
.note-text { font-size: 15.5px; line-height: 1.5; font-style: italic }
/* The pebble's lower corners curve in a long way, so the words are
   centred and kept narrower than the picture; the bottom padding above
   leaves room for the curve under the last line. */
.note-kicker, .note-title, .note-text { padding: 0 6px }

.note:nth-child(4n+1) { --w: 300px; --rot: -3deg; --ring: var(--amber) }
.note:nth-child(4n+2) { --w: 270px; --rot: 4deg; --ring: oklch(0.4 0.1 255); background: oklch(0.9 0.06 80); border-radius: 38% 62% 56% 44% / 24% 30% 34% 28% }
.note:nth-child(4n+2) .note-pic { border-radius: 46% 54% 50% 50% / 50% 46% 54% 50%; box-shadow: 0 0 0 5px oklch(0.9 0.06 80), 0 0 0 9px var(--ring) }
.note:nth-child(4n+3) { --w: 320px; --rot: -1.5deg; --ring: oklch(0.48 0.16 40); background: oklch(0.92 0.04 230); border-radius: 56% 44% 60% 40% / 34% 26% 30% 24% }
.note:nth-child(4n+3) .note-pic { border-radius: 50% 44% 18px 50% / 40% 36% 18px 40%; box-shadow: 0 0 0 5px oklch(0.92 0.04 230), 0 0 0 9px var(--ring) }
.note:nth-child(4n+4) { --w: 280px; --rot: 5deg; --ring: oklch(0.38 0.07 165); border-radius: 44% 56% 38% 62% / 28% 34% 24% 32% }
.note:nth-child(4n+4) .note-pic { border-radius: 50% 50% 50% 50% / 60% 60% 40% 40% }

@media (min-width: 768px) {
  .note:nth-child(4n+2) { --dy: 90px }
  .note:nth-child(4n+3) { --dy: -20px }
  .note:nth-child(4n+4) { --dy: 100px }
  .notebook { padding-bottom: 120px }
  .notes { margin-top: 56px }
}

/* ---- one section per group, each on its own sheet of paper */
.organs { background: var(--bg) }
.organ { max-width: 1440px; margin: 0 auto; padding: clamp(36px, 6vw, 72px) var(--gutter) 10px }
.organ-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 22px }
.organ-num { font-style: italic; font-size: clamp(40px, 6vw, 80px); line-height: 1; color: var(--rust) }
.organ h2 { font-size: clamp(34px, 4.6vw, 62px); line-height: 1.02; letter-spacing: -.02em }
.organ-meta { font-size: 12px; letter-spacing: .22em; text-transform: uppercase; color: var(--rust); margin-left: auto }
.organ-blurb { margin: 12px 0 0; max-width: 56ch; font-size: 17px; line-height: 1.55 }

.cards { display: grid; gap: 24px 18px; margin-top: 30px; grid-template-columns: 1fr }
.card {
  --rot: 0deg;
  position: relative;
  display: flex; flex-direction: column; gap: 6px;
  padding: 12px 14px 18px;
  color: var(--ink); text-decoration: none;
  background: var(--surface);
  border-radius: var(--pebble-c);
  box-shadow: var(--shadow), inset 0 0 0 1px color-mix(in srgb, var(--ink) 12%, transparent);
  transform: rotate(var(--rot));
  transition: transform .25s;
}
.card:hover { color: var(--ink); transform: rotate(0deg) translateY(-4px) }
.card-pic {
  margin: 4px 6px 10px; overflow: hidden; aspect-ratio: 16 / 10;
  border-radius: 40px 18px 36px 16px / 22px 36px 20px 32px;
  background: var(--surface-2);
  box-shadow: 0 0 0 4px var(--surface), 0 0 0 7px var(--group, var(--accent));
}
.card-pic img { display: block; width: 100%; height: 100%; object-fit: cover }
.card-kicker { font-size: 11px; letter-spacing: .2em; text-transform: uppercase; color: var(--rust) }
.card h3 { font-size: 1.25rem; line-height: 1.15 }
.card p { font-size: .95rem; line-height: 1.45; font-style: italic; color: var(--muted) }
.card .chip { align-self: flex-start; margin-top: 6px }
.card:nth-child(4n+1) { --rot: -1.2deg }
.card:nth-child(4n+2) { --rot: .8deg; border-radius: var(--pebble-d) }
.card:nth-child(4n+2) .card-pic { border-radius: 18px 40px 16px 36px / 32px 20px 36px 22px }
.card:nth-child(4n+3) { --rot: -.4deg }
.card:nth-child(4n+4) { --rot: 1.4deg; border-radius: var(--pebble-d) }
.card:nth-child(4n+4) .card-pic { border-radius: 18px 40px 16px 36px / 32px 20px 36px 22px }

@media (min-width: 560px)  { .cards { grid-template-columns: repeat(2, minmax(0, 1fr)) } }
@media (min-width: 960px)  { .cards { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 30px 24px } }
@media (min-width: 1280px) { .cards { grid-template-columns: repeat(4, minmax(0, 1fr)) } }

/* the group colours: the ring round a card's picture, and the tab in the
   sidebar. A new group needs a line here to get one. */
.side-group--lens,     .organ--lens     { --group: var(--tab-blue) }
.side-group--exposure, .organ--exposure { --group: var(--tab-amber) }
.side-group--motion,   .organ--motion   { --group: var(--tab-green) }
.side-group--finish,   .organ--finish   { --group: var(--tab-violet) }
.side-group--ref,      .organ--ref      { --group: var(--tab-teal) }
.side-group--settings, .organ--settings { --group: var(--tab-red) }

/* ---- the street of makers: one house per camera brand, then the models */
.street {
  position: relative; margin-top: clamp(36px, 6vw, 72px); padding-top: 50px;
  background: linear-gradient(var(--sky), var(--gold-pale));
}
.street-head { max-width: 1440px; margin: 0 auto; padding: 0 var(--gutter) }
.street h2 em { font-style: italic; font-weight: 400; color: var(--rust) }
.street-lede { margin: 18px 0 0 clamp(0px, 10vw, 180px); max-width: 40ch; font-size: 17px; line-height: 1.55 }
.houses {
  display: flex; align-items: flex-end;
  margin-top: 70px; padding: 70px var(--gutter) 0;
  overflow-x: auto; scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
}
.house {
  --w: 200px; --h: 400px; --wall: #c4552a; --door: var(--accent); --cx: 30%;
  position: relative; flex: 0 0 auto;
  width: var(--w); height: var(--h); margin-left: -6px;
  scroll-snap-align: start;
  display: flex; flex-direction: column; align-items: center; justify-content: flex-end; gap: 14px;
  padding: 30px 14px 0;
  color: var(--cream-ink); text-decoration: none;
  border-radius: 50% 50% 0 0 / 26% 26% 0 0;
  isolation: isolate;
  transition: transform .25s;
}
/* The wall is drawn by ::before rather than the house itself, so the
   chimney and its cap (z-index -1) can sit behind it and only show above
   the roof line. */
.house::before {
  content: ""; position: absolute; inset: 0; z-index: 0;
  border-radius: inherit;
  background: var(--wall) var(--tex, none) 0 0 / 120px;
  box-shadow: inset 0 0 0 4px var(--cream);
}
.house-name, .house-door { position: relative; z-index: 1 }
.house:hover { color: var(--cream-ink); transform: translateY(-6px) }
.house-chimney {
  position: absolute; z-index: -1; left: var(--cx); top: -54px; width: 34px; height: 90px;
  border-radius: 18px 18px 6px 6px;
  background: conic-gradient(var(--accent) 25%, var(--cream) 0 50%, var(--accent) 0 75%, var(--cream) 0) 0 0 / 12px 12px;
  box-shadow: inset 0 0 0 3px var(--cream);
}
.house-cap {
  position: absolute; z-index: -1; left: calc(var(--cx) - 10px); top: -78px; width: 54px; height: 34px;
  border-radius: 50% 50% 40% 40% / 70% 70% 30% 30%;
  background: var(--rust) url(../img/mosaic-warm.svg) 0 0 / 60px;
  box-shadow: inset 0 -4px 0 var(--cream);
}
.house-name {
  padding: 7px 16px;
  border-radius: 22px 12px 22px 12px / 14px 22px 14px 22px;
  background: var(--cream);
  box-shadow: inset 0 0 0 2px var(--amber);
  font-weight: 600; font-size: 17px; white-space: nowrap;
}
/* The number above the word, so "6 bodies" fits the narrowest door. */
.house-door {
  display: grid; place-content: center; justify-items: center; gap: 2px;
  text-align: center;
  width: 62%; aspect-ratio: 3 / 4.4;
  border-radius: 50% 50% 0 0 / 34% 34% 0 0;
  background: var(--door);
  box-shadow: inset 0 0 0 6px var(--cream), inset 0 0 0 9px var(--door), inset 0 0 0 10px color-mix(in srgb, var(--cream) 50%, transparent);
  color: var(--cream); font-size: 12px; letter-spacing: .16em; text-transform: uppercase;
  font-variant-numeric: tabular-nums;
}
.house-door b { font-size: 22px; font-weight: 600; letter-spacing: 0 }
.house:nth-child(9n+1) { --w: 200px; --h: 400px; --wall: #c4552a; --tex: url(../img/mosaic-warm.svg); --door: oklch(0.4 0.1 255); --cx: 30% }
.house:nth-child(9n+2) { --w: 175px; --h: 330px; --wall: #f4ecd9; --door: oklch(0.48 0.16 40); --cx: 60%; border-radius: 72% 28% 0 0 / 34% 20% 0 0 }
.house:nth-child(9n+3) { --w: 220px; --h: 450px; --wall: #2c4f8f; --tex: url(../img/mosaic-cool.svg); --door: oklch(0.38 0.07 165); --cx: 20%; border-radius: 50% 50% 0 0 / 40% 40% 0 0 }
.house:nth-child(9n+4) { --w: 165px; --h: 310px; --wall: #e8913a; --tex: url(../img/mosaic-warm.svg); --door: oklch(0.4 0.1 255); --cx: 55%; border-radius: 26% 74% 0 0 / 22% 34% 0 0 }
.house:nth-child(9n+5) { --w: 205px; --h: 380px; --wall: #e9dcc0; --door: oklch(0.48 0.16 40); --cx: 35%; border-radius: 50% 50% 0 0 / 16% 16% 0 0 }
.house:nth-child(9n+6) { --w: 190px; --h: 430px; --wall: #3f6b52; --tex: url(../img/mosaic-garden.svg); --door: oklch(0.4 0.1 255); --cx: 62%; border-radius: 64% 36% 0 0 / 30% 42% 0 0 }
.house:nth-child(9n+7) { --w: 170px; --h: 320px; --wall: #c4552a; --tex: url(../img/mosaic-mixed.svg); --door: oklch(0.38 0.07 165); --cx: 25%; border-radius: 50% 50% 0 0 / 44% 44% 0 0 }
.house:nth-child(9n+8) { --w: 185px; --h: 370px; --wall: #f4ecd9; --door: oklch(0.48 0.16 40); --cx: 50%; border-radius: 38% 62% 0 0 / 20% 28% 0 0 }
.house:nth-child(9n+9) { --w: 215px; --h: 410px; --wall: #8fb3cf; --tex: url(../img/mosaic-cool.svg); --door: oklch(0.38 0.07 165); --cx: 40%; border-radius: 50% 50% 0 0 / 30% 30% 0 0 }
.street-ledge { height: 18px; background: var(--cream) }
.street-line { height: 6px; background: var(--rust) }

/* ------------------------------------------------------------- a simulator

   The simulator is its own document in a frame, filling everything below
   the header. From 768px the sidebar lists every simulator beside it. */

.body--side { display: flex; flex-direction: column; flex: 1 }
/* --top-h is the header's real height, set by assets/js/labnav.js: on a
   phone the header takes two lines, more than --top. */
.simpage {
  display: flex; flex-direction: column;
  height: calc(100dvh - var(--top-h, calc(var(--top) + env(safe-area-inset-top, 0px))));
}
.simframe { flex: 1; width: 100%; min-height: 0; border: 0; background: var(--bg) }

/* ---- the sidebar: every simulator, grouped, each with its thumbnail */
.side { display: none }
.side--lab.open { display: block }
.side a {
  display: flex; align-items: center; gap: 10px;
  min-height: 42px; padding: 5px 10px 5px 6px;
  font-size: .94rem; color: var(--ink); text-decoration: none;
  border-radius: 20px 10px 20px 10px / 12px 20px 12px 20px;
}
.side a:nth-child(even) { border-radius: 10px 20px 10px 20px / 20px 12px 20px 12px }
.side a:hover { color: var(--ink); background: color-mix(in srgb, var(--amber) 35%, transparent) }
.side a[aria-current="page"] { background: var(--rust); color: var(--cream) }
.side img {
  width: 40px; height: 25px; flex: none;
  object-fit: cover; border-radius: 10px 6px 10px 6px / 6px 10px 6px 10px; background: #000;
}
/* The group names head each list: upright, larger and on a stronger tint
   than the simulator names under them, so the six parts stand out. */
.side h2.side-group {
  margin: 24px 0 8px; padding: 8px 14px;
  font-size: 1.08rem; font-weight: 600; font-style: normal; line-height: 1.3;
  color: color-mix(in srgb, var(--group, var(--tab-slate)) 45%, var(--ink));
  background: color-mix(in srgb, var(--group, var(--tab-slate)) 26%, transparent);
  border-left: 5px solid var(--group, var(--tab-slate));
  border-radius: 0 16px 16px 0 / 0 12px 12px 0;
}
.side h2.side-group:first-child { margin-top: 0 }
.side-group-num { font-style: italic; font-weight: 400; color: var(--rust); margin-right: 6px }

/* Camera sensors: a button per brand, its models beside it. On a phone the
   models open in place under the brand; from 768px they fly out to the
   right of the sidebar on hover or focus. */
.side-brand-btn {
  all: unset; box-sizing: border-box;
  display: flex; align-items: center; gap: 10px; width: 100%;
  min-height: 42px; padding: 5px 10px;
  font-size: .94rem; color: var(--ink);
  border-radius: 20px 10px 20px 10px / 12px 20px 12px 20px; cursor: pointer;
}
.side-brand-btn::after { content: "\203A"; margin-left: 4px; color: var(--muted) }
.side-brand-btn .count { margin-left: auto; font-size: .82rem; font-style: italic; color: var(--accent); font-variant-numeric: tabular-nums }
.side-brand-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px }
.side-brand.here > .side-brand-btn { font-weight: 600 }
.side-fly { display: none; padding-left: 14px }
.side-brand.open .side-fly { display: block }

/* the phone's site links at the foot of the list */
.side-foot {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  margin-top: 24px; padding-top: 16px;
  border-top: 1px solid color-mix(in srgb, var(--ink) 15%, transparent);
}
.side .side-foot a { min-height: 40px; padding: 0 14px; font-style: italic; border-radius: 999px }
.side .side-foot a.coffee {
  padding: 3px 14px 3px 3px; font-style: normal;
  color: #fff; background: var(--rust);
}
.side .side-foot a.coffee:hover { color: #fff; background: var(--rust-deep) }

@media (max-width: 767px) {
  .side--lab.open {
    position: fixed; left: 0; right: 0; z-index: 25;
    top: var(--top-h, calc(var(--top) + env(safe-area-inset-top, 0px)));
    max-height: calc(100dvh - var(--top-h, calc(var(--top) + env(safe-area-inset-top, 0px))));
    overflow: auto;
    padding: 12px 12px calc(20px + env(safe-area-inset-bottom, 0px));
    background: var(--bg);
    border-bottom: 5px solid var(--rust);
    box-shadow: 0 14px 30px rgb(0 0 0 / .18);
  }
}

@media (min-width: 768px) {
  .body--side { display: grid; grid-template-columns: var(--side) minmax(0, 1fr) }
  .side { display: block }
  .navbtn, .side-foot { display: none }
  .side--lab {
    position: sticky;
    top: calc(var(--top) + env(safe-area-inset-top, 0px));
    height: calc(100dvh - var(--top) - env(safe-area-inset-top, 0px));
    overflow: auto;
    padding: 14px 12px 30px;
    background: var(--surface-2);
    border-right: 1px solid color-mix(in srgb, var(--ink) 15%, transparent);
  }
  .side-brand-btn:hover,
  .side-brand:hover > .side-brand-btn,
  .side-brand:focus-within > .side-brand-btn { background: color-mix(in srgb, var(--amber) 35%, transparent) }
  /* Hidden with visibility rather than display, so it can wait a moment
     before closing: a pointer heading for a model on a slight diagonal
     crosses the next brand down, and should not lose the list for it. */
  .side-brand .side-fly,
  .side-brand.open .side-fly {
    display: block; visibility: hidden; opacity: 0;
    position: fixed; left: var(--side); z-index: 30;
    margin-top: -42px;
    min-width: 230px; padding: 6px;
    background: var(--surface);
    border-radius: var(--pebble-c);
    box-shadow: 0 0 0 2px var(--accent), 0 10px 28px rgb(0 0 0 / .16);
    transition: opacity .1s .25s, visibility 0s .35s;
  }
  .side-brand:hover .side-fly,
  .side-brand:focus-within .side-fly {
    visibility: visible; opacity: 1; z-index: 31;
    transition: opacity .1s .06s, visibility 0s .06s;
  }
  /* a bridge from the button across the sidebar's padding and scrollbar,
     so the pointer never leaves the brand on its way to the list */
  .side-fly::before { content: ""; position: absolute; top: 0; bottom: 0; left: -48px; width: 48px }
}

/* ------------------------------------------------------------- text pages
   About me, Contact and the 404: a headline, a line under it, the page. */

.page { max-width: 1180px; margin: 0 auto; padding: 0 var(--gutter) clamp(40px, 7vw, 80px) }
.page-hero { position: relative; padding: clamp(28px, 6vw, 72px) 0 clamp(18px, 3vw, 30px) }
.page-hero h1 { font-size: clamp(42px, 7vw, 96px); line-height: .95; letter-spacing: -.03em }
.page-hero h1 em { font-style: italic; font-weight: 400; color: var(--rust) }
.page-hero .lede { margin: 18px 0 0 clamp(0px, 4vw, 60px); max-width: 48ch; font-size: 18px; line-height: 1.6 }
.lede a { color: var(--accent) }

.about { display: grid; gap: 28px; padding-top: 10px }
.about-photo { margin: 0; padding: 8px 6px 0 }
.about-photo img {
  display: block; width: 100%; max-width: 280px; height: auto;
  border-radius: 50% 50% 18px 18px / 36% 36% 18px 18px;
  background: var(--line);
  box-shadow: 0 0 0 5px var(--surface), 0 0 0 9px var(--accent);
}
.about-text { max-width: 62ch; font-size: 1.08rem }
.about-text p { margin: 0 0 14px }
.about-links { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin-top: 24px }
@media (min-width: 768px) {
  .about { grid-template-columns: 280px 1fr; gap: 48px; align-items: start }
  .about--nophoto { grid-template-columns: 1fr }
}

/* the panel: a sheet of cream with a soft, uneven corner */
.panel {
  padding: clamp(20px, 4vw, 36px);
  background: var(--surface);
  border-radius: var(--pebble-c);
  box-shadow: var(--shadow), inset 0 0 0 1px color-mix(in srgb, var(--ink) 12%, transparent);
}
.panel > h2, .panel > h3 { margin-bottom: 10px }
.contact-form { max-width: 760px }
.form-grid { display: grid; gap: 0 16px }
@media (min-width: 640px) { .form-grid { grid-template-columns: 1fr 1fr } }
.hp { position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden }

.field { margin-bottom: 16px }
.field label { display: block; margin-bottom: 6px; font-size: .95rem; font-weight: 600 }
.field .opt { font-weight: 400; font-style: italic; color: var(--muted) }
.field input, .field select, .field textarea {
  width: 100%; min-height: var(--tap); padding: 10px 14px;
  font: inherit; font-size: 1rem;
  color: var(--ink); background: var(--bg);
  border: 1px solid color-mix(in srgb, var(--ink) 25%, transparent);
  border-radius: 16px 8px 16px 8px / 8px 16px 8px 16px;
}
.field textarea { min-height: 120px; resize: vertical; border-radius: 22px 10px 22px 10px / 10px 22px 10px 22px }
.field input:focus-visible, .field select:focus-visible, .field textarea:focus-visible {
  border-color: var(--accent); outline: 2px solid var(--accent); outline-offset: -1px;
}
.field .hint { margin: 6px 0 0; font-size: .88rem; color: var(--muted) }

.flash {
  margin: 0 0 16px; padding: 12px 16px;
  font-size: .95rem; font-weight: 500;
  background: var(--surface);
  border-radius: var(--pebble-d);
  box-shadow: inset 0 0 0 1px var(--line);
}
.flash--ok { color: var(--ok); background: color-mix(in srgb, var(--ok) 10%, var(--surface)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ok) 40%, transparent) }
.flash--error { color: var(--bad); background: color-mix(in srgb, var(--bad) 10%, var(--surface)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--bad) 40%, transparent) }

/* ------------------------------------------------------------- the footer
   A band of tile with a cream pebble on it: what the lab is, a way in,
   the site links. */

.foot {
  position: relative; margin-top: auto;
  padding: clamp(50px, 8vw, 90px) var(--gutter) calc(50px + env(safe-area-inset-bottom, 0px));
  background: var(--rust) url(../img/mosaic-warm.svg) 0 0 / 150px;
}
.foot-blob {
  max-width: 760px; margin: 0 auto 0 clamp(0px, 8vw, 140px);
  padding: clamp(36px, 7vw, 80px) clamp(28px, 9vw, 120px);
  border-radius: 46% 54% 40% 60% / 52% 38% 62% 48%;
  background: var(--cream); color: var(--cream-ink);
  box-shadow: 0 0 0 8px oklch(0.4 0.1 255);
}
.foot-blob h2 { font-size: clamp(26px, 3.6vw, 46px); line-height: 1.05; letter-spacing: -.02em }
.foot-blob h2 em { font-style: italic; font-weight: 400; color: oklch(0.48 0.16 40) }
.foot-about { margin: 16px 0 0; max-width: 52ch; font-size: 15.5px; line-height: 1.55 }
.foot-blob .btn { color: var(--cream-ink); background: color-mix(in srgb, var(--cream) 80%, transparent); box-shadow: inset 0 0 0 2px oklch(0.4 0.1 255) }
.foot-blob .btn:hover { background: var(--cream) }
/* About, Contact and the coffee pill: one row of pebbles, the same height. */
.foot-nav { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-top: 24px }
.foot-nav .btn { box-shadow: inset 0 0 0 2px color-mix(in srgb, oklch(0.4 0.1 255) 55%, transparent) }
.foot-blob .coffee {
  min-height: 40px; padding: 4px 18px 4px 4px; gap: 10px;
  font-size: 15px; color: var(--cream);
  border-radius: var(--pebble-a);
  box-shadow: inset 0 0 0 2px var(--rust), inset 0 0 0 3px color-mix(in srgb, var(--cream) 60%, transparent);
}
.foot-blob .coffee:hover { color: var(--cream) }
.foot-blob .coffee-face { width: 32px; height: 32px }
.foot-say { margin: 22px 0 0; font-size: 13px; font-style: italic }
/* Up to 1023px the corners blobs.js moves (about half the width across and
   half the height down) cut through the first and last lines: on a phone
   the pebble is a tall ellipse, on a tablet a wide one with long curves.
   Here the curves reach at most about 200px across and 100 to 130px down,
   so the text sits in the straight part between them. The !important is
   what lets this win over the style blobs.js writes on the element; the
   pebble holds still at these widths as a result. */
@media (max-width: 1023px) {
  .foot-blob {
    padding: 64px clamp(30px, 6vw, 64px);
    border-radius: min(46%, 170px) min(54%, 190px) min(42%, 160px) min(58%, 200px) / 120px 100px 130px 110px !important;
  }
}
