/* Aesthetic direction:
 * Low-key, technical, unhurried / DPs, producers and line producers sourcing gear in Bali
 * - Type: Jost 400-500 display + Jost 400 body. Tracking: 0.14em display, 0.02em body.
 *   Specs set in system mono to echo lens-barrel engraving.
 * - Color: #0B0C0B page / #E8E6E0 text / #C89A4B accent, all sampled from Charlie's
 *   catalogue photographs (painted backdrop, cloth, engraved barrel markings).
 * - Density: loose. 8px scale.
 * - Radius / shadow: none - hairline borders only. Rounded cards read consumer-web.
 * - Imagery: leads. Every photograph shares one backdrop, table and key light;
 *   the page is a frame for that consistency, never a competitor to it.
 * - Motion: 180ms ease for state. Entrances are scroll-driven, composited and
 *   small enough to feel like weight rather than effect. One showpiece: the
 *   home-page reel, a scrubbed cross-dissolve. All of it costs zero JS.
 */

@font-face {
  font-family: "Jost";
  src: url("../fonts/jost-latin.woff2") format("woff2");
  font-weight: 200 600;
  font-style: normal;
  font-display: swap;
}

:root {
  /* keeps Chromium's date picker, calendar popup and scrollbars off white */
  color-scheme: dark;

  --ink: #0b0c0b;
  --surface: #141614;
  --backdrop: #3b4744;
  --backdrop-deep: #2a3331;
  --cloth: #a9afa6;
  --bone: #e8e6e0;
  --amber: #c89a4b;
  --signal: #a8362c;
  /* --signal is 3.0:1 on --ink; this lift clears AA for text use */
  --signal-text: #d96a5c;

  --hairline: rgba(169, 175, 166, 0.18);
  --hairline-strong: rgba(169, 175, 166, 0.34);

  --font-display: "Jost", "Futura", "Century Gothic", sans-serif;
  --font-body: "Jost", system-ui, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, Menlo, monospace;

  --s1: 8px;
  --s2: 16px;
  --s3: 24px;
  --s4: 40px;
  --s5: 64px;
  --s6: 96px;
  --s7: 144px;

  --bar: 72px;
  /* masthead plus the sticky filter bar beneath it; anchor targets in the
     catalogue must clear both or the jump lands under the chrome */
  --stick: calc(var(--bar) + var(--s6));
  --measure: 62ch;
  --page: 1440px;
  --gutter: clamp(20px, 5vw, 64px);

  --ease: cubic-bezier(0.2, 0, 0.1, 1);
}

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

html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--ink);
  color: var(--bone);
  font-family: var(--font-body);
  font-size: 17px;
  font-weight: 400;
  line-height: 1.6;
  letter-spacing: 0.02em;
  -webkit-font-smoothing: antialiased;
}

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

a {
  color: inherit;
  text-decoration-color: var(--hairline-strong);
  text-underline-offset: 0.3em;
}

a:hover {
  text-decoration-color: var(--amber);
}

:focus-visible {
  outline: 2px solid var(--amber);
  outline-offset: 3px;
}

button {
  font: inherit;
  color: inherit;
  background: none;
  border: none;
  cursor: pointer;
}

.skip-link {
  position: absolute;
  left: var(--gutter);
  top: -100px;
  z-index: 100;
  padding: var(--s2);
  background: var(--surface);
  border: 1px solid var(--amber);
}

.skip-link:focus {
  top: var(--s2);
}

.wrap {
  max-width: var(--page);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* --- Display type ------------------------------------------------------- */

.display {
  font-family: var(--font-display);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  line-height: 1.15;
  margin: 0;
}

.eyebrow {
  font-family: var(--font-mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.24em;
  color: var(--cloth);
  margin: 0 0 var(--s3);
}

.eyebrow::before {
  content: "";
  display: inline-block;
  width: 24px;
  height: 1px;
  margin-right: var(--s2);
  vertical-align: 0.3em;
  background: var(--amber);
}

/* --- Header ------------------------------------------------------------- */

.masthead {
  position: sticky;
  top: 0;
  z-index: 50;
  height: var(--bar);
  display: flex;
  align-items: center;
  background: var(--ink);
  border-bottom: 1px solid var(--hairline);
}

.masthead .wrap {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
}

.mark {
  display: flex;
  align-items: center;
  gap: var(--s2);
  text-decoration: none;
}

.mark svg {
  width: 46px;
  height: 46px;
  flex: none;
}

.mark-word {
  font-family: var(--font-display);
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.3em;
  color: var(--bone);
}

.nav {
  display: flex;
  align-items: center;
  gap: clamp(16px, 3vw, 40px);
  font-family: var(--font-display);
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.2em;
}

.nav a {
  text-decoration: none;
  color: var(--cloth);
  padding-block: var(--s1);
  border-bottom: 1px solid transparent;
  transition: color 180ms var(--ease), border-color 180ms var(--ease);
}

.nav a:hover {
  color: var(--bone);
}

.nav a[aria-current="page"] {
  color: var(--bone);
  border-bottom-color: var(--amber);
}

/* --- Hero --------------------------------------------------------------- */

.hero {
  position: relative;
  min-height: min(880px, calc(100svh - var(--bar)));
  display: flex;
  align-items: center;
  overflow: hidden;
  border-bottom: 1px solid var(--hairline);
}

.hero-media {
  position: absolute;
  inset: 0;
}

.hero-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 62%;
}

/* Type sits in the flat backdrop upper-left, so the scrim only has to lift
   contrast a little rather than dim the photograph. */
.hero-media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    100deg,
    rgba(11, 12, 11, 0.72) 0%,
    rgba(11, 12, 11, 0.42) 34%,
    rgba(11, 12, 11, 0.08) 62%
  );
}

.hero-inner {
  position: relative;
  width: 100%;
  padding-block: var(--s6);
}

.hero-copy {
  max-width: 46ch;
}

.hero h1 {
  font-size: clamp(38px, 6.4vw, 92px);
  font-weight: 500;
  letter-spacing: 0.1em;
}

.hero-sub {
  max-width: 40ch;
  margin: var(--s3) 0 var(--s4);
  font-size: clamp(15px, 1.4vw, 19px);
  line-height: 1.55;
  color: var(--cloth);
}

.hero-meta {
  position: absolute;
  left: var(--gutter);
  bottom: var(--s4);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--cloth);
  text-align: left;
  /* caption sits on photograph, not flat backdrop */
  text-shadow: 0 1px 10px rgba(11, 12, 11, 0.95);
}

/* --- Buttons ------------------------------------------------------------ */

.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  padding: 14px var(--s3);
  font-family: var(--font-display);
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  text-decoration: none;
  border: 1px solid var(--hairline-strong);
  color: var(--bone);
  background: rgba(11, 12, 11, 0.4);
  transition: border-color 180ms var(--ease), color 180ms var(--ease),
    background-color 180ms var(--ease);
}

.btn:hover {
  border-color: var(--amber);
  color: var(--amber);
}

.btn-solid {
  background: var(--amber);
  border-color: var(--amber);
  color: var(--ink);
}

.btn-solid:hover {
  background: var(--bone);
  border-color: var(--bone);
  color: var(--ink);
}

.btn-ghost {
  padding-inline: 0;
  border: none;
  border-bottom: 1px solid var(--hairline-strong);
  background: none;
}

/* --- Sections ----------------------------------------------------------- */

.section {
  padding-block: clamp(64px, 10vw, 144px);
  border-bottom: 1px solid var(--hairline);
}

.section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s3);
  flex-wrap: wrap;
  margin-bottom: var(--s5);
}

.section-head h2 {
  font-size: clamp(24px, 3vw, 38px);
  font-weight: 400;
}

.statement {
  padding-block: clamp(72px, 12vw, 160px);
}

.statement p {
  max-width: 22ch;
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(26px, 4.4vw, 58px);
  font-weight: 300;
  line-height: 1.25;
  letter-spacing: 0.02em;
}

.statement em {
  font-style: normal;
  color: var(--amber);
}

/* --- Kits --------------------------------------------------------------- */

.kits {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 1px;
  background: var(--hairline);
  border: 1px solid var(--hairline);
}

.kit {
  display: flex;
  flex-direction: column;
  gap: var(--s2);
  padding: var(--s4) var(--s3);
  background: var(--ink);
  transition: background-color 180ms var(--ease);
}

.kit:hover {
  background: var(--surface);
}

.kit h3 {
  margin: 0;
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.16em;
}

.kit-index {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.2em;
  color: var(--amber);
}

.kit ul {
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 15px;
  color: var(--cloth);
}

.kit li {
  padding-block: 5px;
  border-bottom: 1px solid var(--hairline);
}

.kit li:last-child {
  border-bottom: none;
}

.kit-note {
  margin: 0;
  font-size: 14px;
  color: var(--cloth);
}

.kit .add {
  margin-top: auto;
}

/* --- Reel --------------------------------------------------------------- */

/* An ordered list of frames cross-faded by scroll position. Every photograph
   shares one backdrop, table and key light, so the dissolve reads as a single
   take with the lens changing rather than a slideshow. Frame count lives in
   --n and each frame carries its own --i, so extending the list (e.g. to a
   turntable of one lens) is markup only. Without scroll-timeline support or
   under reduced motion the section collapses to frame one, full height. */

.reel {
  --n: 12;
  position: relative;
  border-bottom: 1px solid var(--hairline);
}

.reel-stage {
  position: sticky;
  top: var(--bar);
  height: calc(100svh - var(--bar));
  min-height: 460px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--s5);
  overflow: hidden;
}

.reel-head {
  width: 100%;
}

.reel-frames {
  position: relative;
  flex: none;
  width: min(
    960px,
    calc(100vw - 2 * var(--gutter)),
    calc((100svh - var(--bar) - 260px) * 1.5)
  );
  aspect-ratio: 3 / 2;
  background: var(--backdrop-deep);
}

.reel-frame {
  position: absolute;
  inset: 0;
  margin: 0;
  opacity: 0;
}

.reel-frame:first-of-type {
  opacity: 1;
}

.reel-frame picture,
.reel-frame img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.reel-frame figcaption {
  position: absolute;
  top: calc(100% + var(--s2));
  left: 0;
  right: 0;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--cloth);
}

/* --- Prep / trust ------------------------------------------------------- */

.split {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: clamp(32px, 6vw, 96px);
  align-items: start;
}

.prose {
  max-width: var(--measure);
}

.prose p {
  margin: 0 0 var(--s3);
}

.prose p:last-child {
  margin-bottom: 0;
}

.prose-lead {
  font-size: clamp(18px, 2vw, 22px);
  line-height: 1.5;
  color: var(--bone);
}

.checks {
  margin: var(--s4) 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: var(--s2);
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: 0.06em;
  color: var(--cloth);
}

.checks li {
  display: flex;
  gap: var(--s2);
}

.checks li::before {
  content: "—";
  color: var(--amber);
}

.figure figcaption {
  margin-top: var(--s2);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--cloth);
}

/* --- Catalogue ---------------------------------------------------------- */

.page-head {
  padding-block: clamp(48px, 7vw, 96px) var(--s5);
  border-bottom: 1px solid var(--hairline);
}

.page-head h1 {
  font-size: clamp(32px, 5vw, 64px);
  font-weight: 400;
}

.page-head .lede {
  max-width: 60ch;
  margin: var(--s3) 0 0;
  color: var(--cloth);
}

.filters {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s1);
  padding-block: var(--s3);
  position: sticky;
  top: var(--bar);
  z-index: 20;
  background: var(--ink);
  border-bottom: 1px solid var(--hairline);
}

.filter {
  padding: 9px var(--s2);
  font-family: var(--font-mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--cloth);
  border: 1px solid var(--hairline);
  transition: color 180ms var(--ease), border-color 180ms var(--ease);
}

.filter:hover {
  color: var(--bone);
  border-color: var(--hairline-strong);
}

.filter[aria-pressed="true"] {
  color: var(--ink);
  background: var(--bone);
  border-color: var(--bone);
}

.grid {
  display: grid;
  /* 21 cards: 3 columns divides clean, auto-fill's 4 left an orphan row */
  grid-template-columns: 1fr;
  gap: var(--s4) var(--s3);
  padding-block: var(--s5);
  margin: 0;
}

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

@media (min-width: 1024px) {
  .grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

.card {
  display: flex;
  flex-direction: column;
  gap: var(--s2);
}

.card-media {
  position: relative;
  background: var(--backdrop-deep);
  border: 1px solid var(--hairline);
}

.card-media img {
  width: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
}

.card h4 {
  margin: var(--s1) 0 0;
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.12em;
}

.card-spec {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 1.75;
  letter-spacing: 0.02em;
  color: var(--cloth);
}

.card-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s2);
  margin-top: auto;
  padding-top: var(--s2);
  border-top: 1px solid var(--hairline);
}

.card-cat {
  font-family: var(--font-mono);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: var(--cloth);
}

.add {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--cloth);
  padding: 6px 10px;
  border: 1px solid var(--hairline);
  transition: color 180ms var(--ease), border-color 180ms var(--ease);
}

.add:hover {
  color: var(--amber);
  border-color: var(--amber);
}

.add[aria-pressed="true"] {
  color: var(--amber);
  border-color: var(--amber);
}

.add[aria-pressed="true"] .add-label::after {
  content: "ed";
}

.add-mark {
  font-size: 13px;
  line-height: 1;
}

/* --- Kit drawer --------------------------------------------------------- */

.drawer-toggle {
  position: fixed;
  right: var(--gutter);
  bottom: var(--s3);
  z-index: 60;
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  padding: 14px var(--s3);
  font-family: var(--font-display);
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: var(--bone);
  background: var(--surface);
  border: 1px solid var(--hairline-strong);
}

.drawer-toggle:hover {
  border-color: var(--amber);
}

.count {
  display: inline-grid;
  place-items: center;
  min-width: 22px;
  height: 22px;
  padding-inline: 6px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0;
  color: var(--ink);
  background: var(--amber);
}

.drawer {
  position: fixed;
  inset: 0 0 0 auto;
  z-index: 70;
  width: min(440px, 100%);
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border-left: 1px solid var(--hairline-strong);
  transform: translateX(100%);
  transition: transform 220ms var(--ease);
}

.drawer.is-open {
  transform: translateX(0);
}

.drawer-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--s3) var(--s3) var(--s2);
  border-bottom: 1px solid var(--hairline);
}

.drawer-head h2 {
  margin: 0;
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.2em;
}

.drawer-close {
  position: relative;
  padding: var(--s1);
  font-size: 20px;
  line-height: 1;
  color: var(--cloth);
}

/* Hit area to 44px without disturbing the visual box. */
.drawer-close::after {
  content: "";
  position: absolute;
  inset: -6px -8px;
}

.drawer-close:hover {
  color: var(--bone);
}

.drawer-body {
  flex: 1;
  overflow-y: auto;
  padding: var(--s3);
}

.drawer-list {
  margin: 0 0 var(--s4);
  padding: 0;
  list-style: none;
}

.drawer-list li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s2);
  padding-block: var(--s2);
  font-size: 15px;
  border-bottom: 1px solid var(--hairline);
}

/* the totals rule is the group separator; a trailing row rule doubles it */
.drawer-list li:last-child {
  border-bottom: none;
}

.kit-name {
  flex: 1;
  min-width: 0;
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 400;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--bone);
}

.remove {
  position: relative;
  flex: none;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--cloth);
}

/* Hit area to 44px without growing the row. */
.remove::after {
  content: "";
  position: absolute;
  inset: -12px -8px;
}

.remove:hover {
  color: var(--signal-text);
}

.drawer-empty {
  margin: 0;
  font-size: 15px;
  color: var(--cloth);
}

.field {
  display: grid;
  gap: 6px;
  margin-bottom: var(--s3);
}

.field label {
  font-family: var(--font-mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: var(--cloth);
}

.field input,
.field textarea {
  font: inherit;
  font-size: 15px;
  color: var(--bone);
  background: var(--ink);
  border: 1px solid var(--hairline);
  padding: 11px var(--s2);
}

/* an unset date must not read as entered data */
.field input[type="date"]::-webkit-datetime-edit {
  color: var(--cloth);
}

.field input[type="date"]::-webkit-calendar-picker-indicator {
  opacity: 0.45;
}

.field input:focus,
.field textarea:focus {
  border-color: var(--amber);
}

.field-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--s2);
}

.drawer-foot {
  display: grid;
  gap: var(--s2);
  padding: var(--s3);
  border-top: 1px solid var(--hairline);
}

.drawer-foot .btn {
  justify-content: center;
}

.drawer-alt .btn-ghost {
  padding: 0;
}

.drawer-alt {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.1em;
  text-align: center;
  color: var(--cloth);
}

.scrim {
  position: fixed;
  inset: 0;
  z-index: 65;
  background: rgba(11, 12, 11, 0.72);
}

/* --- Footer ------------------------------------------------------------- */

.footer {
  padding-block: var(--s6) var(--s4);
}

.footer-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--s4);
}

.footer h2 {
  margin: 0 0 var(--s2);
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.22em;
  color: var(--cloth);
}

.footer address,
.footer nav {
  font-style: normal;
  line-height: 1.8;
}

.footer a {
  text-decoration: none;
  border-bottom: 1px solid transparent;
}

.footer a:hover {
  border-bottom-color: var(--amber);
}

.footer-social {
  display: flex;
  gap: var(--s2);
  margin-top: var(--s2);
}

.footer-social a {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border: 1px solid var(--hairline);
  color: var(--cloth);
  transition: color 180ms var(--ease), border-color 180ms var(--ease);
}

.footer-social a:hover {
  color: var(--amber);
  border-color: var(--amber);
}

.footer-social svg {
  width: 18px;
  height: 18px;
}

.colophon {
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--s2);
  margin-top: var(--s6);
  padding-top: var(--s3);
  border-top: 1px solid var(--hairline);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--cloth);
}

/* --- Utility ------------------------------------------------------------ */

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

[hidden] {
  display: none !important;
}

/* --- Responsive --------------------------------------------------------- */

@media (max-width: 720px) {
  :root {
    --bar: 60px;
  }

  .mark-word {
    display: none;
  }

  .nav {
    font-size: 11px;
    letter-spacing: 0.14em;
  }

  .hero-copy {
    max-width: 100%;
  }

  .hero-media::after {
    background: linear-gradient(
      170deg,
      rgba(11, 12, 11, 0.8) 0%,
      rgba(11, 12, 11, 0.45) 45%,
      rgba(11, 12, 11, 0.15) 100%
    );
  }

  .hero-inner {
    align-self: flex-start;
    padding-top: var(--s5);
  }

  .hero-meta {
    display: none;
  }

  /* wrapped chips would eat 130px of an 844 viewport; scroll them instead so
     the filter bar can stay reachable over a 9000px list */
  /* Scrolls on itself, never inside a wrapper: an overflow ancestor would
     re-parent the sticky containing block and drop the bar. */
  .filters {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    padding-block: var(--s2);
    scroll-snap-type: x proximity;
    overscroll-behavior-inline: contain;
    mask-image: linear-gradient(to left, transparent, var(--ink) 24px);
  }

  .filters::-webkit-scrollbar {
    display: none;
  }

  .filters .filter {
    flex: 0 0 auto;
  }

  .drawer-toggle {
    left: var(--gutter);
    right: var(--gutter);
    justify-content: center;
  }

  /* Gutters would leave a 350px frame in an 844px viewport. Full bleed instead,
     and inset the caption on its own so it stays aligned with the page. */
  /* The stage must stay a full viewport tall or the following section creeps
     into frame while the dissolve is still running. */
  .reel-stage {
    gap: var(--s4);
  }

  /* A 3:2 frame at 390px is 260px tall in a 784px stage -- two thirds of the
     showpiece is empty. The stage cannot shrink, so the picture grows: a
     square crop keeps the subject centred where a portrait one would cut the
     ends off a row of lenses. */
  .reel-frames {
    width: 100vw;
    aspect-ratio: 1 / 1;
  }

  .reel-frame figcaption {
    padding-inline: var(--gutter);
  }
}

/* --- Motion -------------------------------------------------------------
   Scroll-driven, so there is no timer to fall out of sync with the scrollbar
   and no observer to add to the site script. Everything
   animates transform or opacity only, and everything sits inside
   prefers-reduced-motion: no-preference. Base state is always the END state,
   so with the gate closed, or on an engine without scroll timelines, the page
   is simply the page. The one exception is .reel, which is designed to
   collapse to its first frame -- see the note above .reel. */

@keyframes rise-in {
  from {
    opacity: 0;
    transform: translateY(var(--rise, 24px));
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes hero-drift {
  from {
    transform: translateY(-7.4%);
  }
  to {
    transform: translateY(0);
  }
}

@keyframes reel-dissolve {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

/* Frames can persist at opacity 1 because each one occludes the last. A caption
   is text on a transparent ground, so persisting would overprint all twelve
   into illegible soup -- each gets a disjoint slot and leaves before the next. */
@keyframes caption-cycle {
  0% {
    opacity: 0;
  }
  18%,
  82% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}

@keyframes caption-first {
  0%,
  82% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}

@keyframes caption-last {
  0% {
    opacity: 0;
  }
  18%,
  100% {
    opacity: 1;
  }
}

/* The hero is above the fold, so its entrance is the one thing that cannot be
   driven by scroll position. Time-based, hence no @supports gate. */
@media (prefers-reduced-motion: no-preference) {
  .hero h1,
  .hero-sub,
  .hero-copy .btn,
  .hero-meta {
    --rise: 16px;
  }

  .hero h1 {
    animation: rise-in 700ms var(--ease) 40ms both;
  }

  .hero-sub {
    animation: rise-in 700ms var(--ease) 100ms both;
  }

  .hero-copy .btn {
    animation: rise-in 700ms var(--ease) 160ms both;
  }

  .hero-meta {
    animation: rise-in 700ms var(--ease) 260ms both;
  }
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    /* The photograph lags the scroll by ~8%. It has to translate DOWN as the
       page goes up; 108% height keeps the crop covered at both ends. Sizing
       lives inside the gate so the crop is identical without it. */
    .hero-media img {
      height: 108%;
      animation: hero-drift linear both;
      animation-timeline: scroll(root block);
      animation-range: 0 100svh;
    }

    .statement p,
    .section-head,
    .figure,
    .checks li,
    .kit > *,
    .card,
    .footer-grid > div {
      animation: rise-in linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 45%;
    }

    /* Stagger is range offset, not delay: a scroll timeline has no clock. */
    .kits .kit:nth-child(2) > * {
      animation-range: entry 6% entry 51%;
    }

    .kits .kit:nth-child(3) > * {
      animation-range: entry 12% entry 57%;
    }

    .kits .kit:nth-child(4) > * {
      animation-range: entry 18% entry 63%;
    }

    .checks li:nth-child(2) {
      animation-range: entry 4% entry 49%;
    }

    .checks li:nth-child(3) {
      animation-range: entry 8% entry 53%;
    }

    .checks li:nth-child(4) {
      animation-range: entry 12% entry 57%;
    }

    /* Each frame fades IN and stays. Later frames are later in the DOM, so the
       composite is a*new + (1-a)*old -- a real dissolve. Fading the outgoing
       frame out at the same time would leave both near 0.5 mid-crossover and
       darken the picture toward --ink at every transition. */
    .reel {
      height: 310svh;
      view-timeline: --reel block;
    }

    /* The dissolve takes 45% of each frame's slot, leaving 55% held. Spanning
       the whole slot made every resting scroll position a double exposure,
       which reads as two stacked photographs rather than one lens changing. */
    .reel-frame {
      animation: reel-dissolve linear both;
      animation-timeline: --reel;
      animation-range: contain calc((var(--i) - 0.225) * 100% / var(--n))
        contain calc((var(--i) + 0.225) * 100% / var(--n));
    }

    .reel-frame:first-of-type {
      animation: none;
      opacity: 1;
    }

    /* Slot [i, i+1] -- disjoint, so exactly one caption is ever legible. The
       swap lands inside the picture's dissolve: label leaves, lens changes,
       new label arrives. */
    .reel-frame figcaption {
      animation: caption-cycle linear both;
      animation-timeline: --reel;
      animation-range: contain calc(var(--i) * 100% / var(--n)) contain
        calc((var(--i) + 1) * 100% / var(--n));
    }

    /* Ends are one-sided: the first caption is already up as the reel enters,
       the last must not blank out while its picture is still on screen. */
    .reel-frame:first-of-type figcaption {
      animation-name: caption-first;
    }

    .reel-frame:last-of-type figcaption {
      animation-name: caption-last;
    }
  }

  @media (min-width: 1024px) and (prefers-reduced-motion: no-preference) {
    /* `of :not([hidden])` because the filter hides cards in place: plain
       :nth-child still counts them and scrambles the diagonal on 9 of the 10
       pill states. Support is wider than the animation-timeline gate above. */
    .grid .card:nth-child(3n + 2 of :not([hidden])) {
      animation-range: entry 6% entry 51%;
    }

    .grid .card:nth-child(3n of :not([hidden])) {
      animation-range: entry 12% entry 57%;
    }
  }

  @media (max-width: 720px) and (prefers-reduced-motion: no-preference) {
    /* 12 frames at 310svh is a long scroll on a phone; the frame is also
       smaller, so each transition needs less distance to read. */
    .reel {
      height: 260svh;
    }
  }
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    transition-duration: 1ms !important;
    animation-duration: 1ms !important;
  }
}

/* --- Three ways to hire -------------------------------------------------- */

/* Deliberately not sticky: .filters already occupies top: var(--bar), and two
   stacked bars cost 120px of an 844px viewport. */
.ways {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1px;
  margin-top: var(--s5);
  background: var(--hairline);
  border: 1px solid var(--hairline);
}

.way {
  display: grid;
  gap: 6px;
  align-content: start;
  padding: var(--s3);
  background: var(--ink);
  text-decoration: none;
  transition: background-color 180ms var(--ease);
}

.way:hover {
  background: var(--surface);
}

.way-n {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.2em;
  color: var(--amber);
}

.way-t {
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.14em;
}

.way-d {
  font-size: 14px;
  color: var(--cloth);
}

.section-note {
  max-width: 34ch;
  margin: 0;
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 1.7;
  color: var(--cloth);
}

.consult {
  display: grid;
  gap: var(--s4);
}

.consult-act {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
  margin: 0;
}

/* --- Catalogue layers ---------------------------------------------------- */

#results {
  /* the filter scroll-reset must not park the heading under the sticky bar */
  scroll-margin-top: var(--stick);
}

.layer + .layer {
  margin-top: var(--s5);
  padding-top: var(--s5);
  border-top: 1px solid var(--hairline);
}

.layer-head h3 {
  margin: 0;
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: var(--bone);
}

.layer-head p {
  max-width: 60ch;
  margin: var(--s1) 0 0;
  font-size: 14px;
  color: var(--cloth);
}

.rate-search {
  display: block;
  padding-top: var(--s4);
}

.rate-search input {
  font: inherit;
  font-size: 15px;
  width: min(420px, 100%);
  padding: 11px var(--s2);
  color: var(--bone);
  background: var(--ink);
  border: 1px solid var(--hairline);
}

.rate-search input:focus {
  border-color: var(--amber);
}

.rate-count {
  /* reserved so the announcement cannot shift the list under a tapping finger */
  min-height: 18px;
  margin: var(--s1) 0 0;
  font-family: var(--font-mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--cloth);
}

.rate-empty {
  margin: var(--s4) 0 0;
  padding: var(--s3);
  font-size: 15px;
  color: var(--cloth);
  border: 1px solid var(--hairline);
}

/* --- Rates: caveat, guard, tables ---------------------------------------- */

.rate-caveat,
.rate-guard {
  max-width: 78ch;
  margin-top: var(--s4);
  padding: var(--s3);
  background: var(--surface);
  border: 1px solid var(--hairline);
}

.rate-guard {
  border-color: var(--hairline-strong);
  /* clears the masthead plus the sticky filter bar; the box is shorter than
     the combined chrome, so without this the anchor jump looks dead */
  scroll-margin-top: var(--stick);
}

.rate-caveat p,
.rate-guard p {
  margin: 0 0 var(--s2);
  font-size: 14px;
  line-height: 1.65;
  color: var(--cloth);
}

.rate-caveat p:last-child,
.rate-guard p:last-child {
  margin-bottom: 0;
}

.rate-caveat strong,
.rate-guard strong {
  font-weight: 400;
  color: var(--bone);
}

.rate-guard h4 {
  margin: 0 0 var(--s1);
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: var(--amber);
}

/* Reads as a marker, not a link — it is an <a> on rows and cards and a bare
   <span> in the legend and in the terms, so the rule assumes neither. */
.guard-tag {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 5px;
  font-family: var(--font-mono);
  font-size: 9px;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  white-space: nowrap;
  vertical-align: 1px;
  color: var(--amber);
  border: 1px solid var(--hairline-strong);
  text-decoration: none;
}

a.guard-tag:hover {
  border-color: var(--amber);
}

.rate-group {
  margin-top: var(--s5);
}

.rate-group h4 {
  margin: 0 0 var(--s2);
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: var(--bone);
}

/* Fixed layout so the price and add columns cannot be pushed off a 390px
   screen by a long item name. Rows stay display: table-row — block/flex
   would strip the row and cell roles in Chrome and Safari. */
.rates {
  width: 100%;
  table-layout: fixed;
  border-collapse: collapse;
}

.rates thead th {
  padding: 0 0 var(--s1);
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 400;
  text-align: left;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: var(--cloth);
  border-bottom: 1px solid var(--hairline-strong);
}

.rates thead th:nth-child(2) {
  width: 220px;
  text-align: right;
}

.rates thead th:nth-child(3) {
  width: 72px;
}

.rates tbody th,
.rates tbody td {
  padding-block: 11px;
  vertical-align: top;
  border-bottom: 1px solid var(--hairline);
}

.rates tbody th {
  padding-right: var(--s2);
  font-weight: 400;
  font-size: 15px;
  text-align: left;
  color: var(--bone);
  overflow-wrap: anywhere;
}

.rate-cell {
  text-align: right;
}

.rate-num {
  font-family: var(--font-mono);
  font-size: 14px;
  letter-spacing: 0.02em;
  color: var(--bone);
}

.rate-cell .rate-num {
  display: block;
}

.rate-alt {
  display: block;
  margin-top: 3px;
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.5;
  color: var(--cloth);
}

.rate-unit {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  color: var(--cloth);
}

.rate-tbc {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--cloth);
}

.rate-act {
  text-align: right;
}

.add-row {
  position: relative;
  gap: 0;
  width: 32px;
  height: 32px;
  padding: 0;
  justify-content: center;
}

/* 44px target without growing the row */
.add-row::after {
  content: "";
  position: absolute;
  inset: -6px;
}

.add-row .add-mark {
  transition: transform 180ms var(--ease);
}

.add-row[aria-pressed="true"] .add-mark {
  transform: rotate(45deg);
}

.rate-foot {
  max-width: 70ch;
  margin: var(--s2) 0 0;
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.7;
  color: var(--cloth);
}

/* --- Card rates ---------------------------------------------------------- */

.card-rate {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0;
}

.card-rate .guard-tag {
  margin-left: 0;
}

.card-note {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.6;
  color: var(--cloth);
}

/* --- Kit total ----------------------------------------------------------- */

.drawer-total {
  display: grid;
  gap: 6px;
  margin-top: var(--s3);
  margin-bottom: var(--s4);
  padding-top: var(--s3);
  border-top: 1px solid var(--hairline-strong);
}

.drawer-total p {
  display: flex;
  justify-content: space-between;
  gap: var(--s2);
  margin: 0;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--cloth);
}

.drawer-total .is-total {
  margin-top: 2px;
  padding-top: var(--s1);
  font-size: 14px;
  color: var(--bone);
  border-top: 1px solid var(--hairline);
}

.drawer-total .drawer-note {
  display: block;
  margin-top: var(--s1);
  font-family: var(--font-body);
  font-size: 12px;
  line-height: 1.6;
  color: var(--cloth);
}

.kit-rate {
  flex: none;
  text-align: right;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--cloth);
}

/* --- Floating WhatsApp --------------------------------------------------- */

.wa-float {
  position: fixed;
  right: var(--gutter);
  bottom: var(--s3);
  z-index: 60;
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  color: var(--bone);
  background: var(--surface);
  border: 1px solid var(--hairline-strong);
  transition: border-color 180ms var(--ease), color 180ms var(--ease);
}

.wa-float:hover {
  color: var(--amber);
  border-color: var(--amber);
}

.wa-float svg {
  width: 22px;
  height: 22px;
}

/* Stacked above the WhatsApp tile at every width: at <=720px the toggle is
   full-bleed, so side-by-side is not available. */
.drawer-toggle {
  bottom: calc(var(--s3) + 48px + var(--s1));
}

/* --- Terms --------------------------------------------------------------- */

.terms-source {
  margin: var(--s2) 0 0;
  font-family: var(--font-mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--cloth);
}

.terms {
  counter-reset: term;
  margin: 0;
  padding: 0;
  list-style: none;
}

.term {
  display: grid;
  gap: var(--s2);
  padding-block: var(--s4);
  border-bottom: 1px solid var(--hairline);
}

.term:first-child {
  padding-top: 0;
}

.term h2 {
  margin: 0;
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.16em;
}

.term h2::before {
  counter-increment: term;
  content: counter(term, decimal-leading-zero);
  display: block;
  margin-bottom: 6px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.2em;
  color: var(--amber);
}

.term ul {
  display: grid;
  gap: var(--s2);
  max-width: var(--measure);
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 16px;
  color: var(--cloth);
}

.term ul li {
  position: relative;
  padding-left: var(--s3);
}

.term ul li::before {
  content: "—";
  position: absolute;
  left: 0;
  color: var(--amber);
}

.term .rate {
  font-family: var(--font-mono);
  white-space: nowrap;
  color: var(--bone);
}

.terms-note {
  margin: var(--s4) 0 0;
  font-size: 14px;
  color: var(--cloth);
}

@media (min-width: 900px) {
  .term {
    grid-template-columns: 220px minmax(0, 1fr);
    gap: var(--s4);
  }
}

@media (max-width: 720px) {
  .ways {
    grid-template-columns: 1fr;
  }

  .rates thead th:nth-child(2) {
    width: 132px;
  }

  .rates thead th:nth-child(3) {
    width: 48px;
  }

  .rates tbody th {
    font-size: 14px;
  }

  .rate-num {
    font-size: 13px;
  }

  /* keeps "per piece, min 5" off a mid-phrase break in a 132px column */
  .rate-unit {
    display: block;
    letter-spacing: 0.04em;
  }

  .add-row {
    width: 30px;
    height: 30px;
  }

  .add-row::after {
    inset: -7px;
  }
}

/* --- Print ---------------------------------------------------------------
   A rate card is the page most likely to be printed, so the filtered-away
   rows come back and every fixed element leaves. */

@media print {
  @page {
    margin: 14mm;
  }

  body {
    background: var(--bone);
    color: var(--ink);
    font-size: 11pt;
  }

  .masthead,
  .filters,
  .rate-search,
  .add,
  .rate-act,
  .rates thead th:last-child,
  .drawer,
  .drawer-toggle,
  .wa-float,
  .scrim,
  .skip-link,
  .card-media,
  .hero-media,
  .reel,
  .footer-social {
    display: none !important;
  }

  tr[hidden],
  .card[hidden],
  .rate-group[hidden],
  .layer[hidden] {
    display: revert !important;
  }

  a,
  h1,
  h2,
  h3,
  h4,
  .rate-num,
  .rates tbody th,
  .guard-tag {
    color: var(--ink);
  }

  .rate-caveat,
  .rate-guard,
  .rates tbody th,
  .rates tbody td,
  .rates thead th {
    background: none;
    border-color: rgba(11, 12, 11, 0.35);
  }

  .rate-group,
  .term,
  tr {
    break-inside: avoid;
  }
}
