/* Caelin Roodt — design system
   Two tokens only: off-white base, ink. No accent colour.
   Restraint is the signature; the dot-dissolve motif is the one recurring device. */

:root{
  --base: #FAFAF7;
  --base-2: #F0EFE9;
  --ink: #14151A;
  --muted: #6B6A66;
  --line: #E2E0D9;

  --font-display: "Archivo", ui-sans-serif, system-ui, sans-serif;
  --font-body: "IBM Plex Sans", ui-sans-serif, system-ui, sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, monospace;

  --max: 1120px;
  --gutter: max(20px, calc((100vw - var(--max)) / 2));
}

*{ box-sizing: border-box; }
html{ scroll-behavior: smooth; }
body{
  margin: 0;
  background: var(--base);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.5;
}
img{ max-width: 100%; display: block; }

h1,h2,h3{
  font-family: var(--font-display);
  margin: 0;
  text-wrap: balance;
  font-weight: 700;
}

a{ color: inherit; }

/* .wrap sections need to stack above the hero's fixed particle canvas —
   except the products wrap, which must stay un-scoped so a spotlit card's
   z-index can escape all the way up to compare against the full-page
   spotlight overlay. Trapping it in a local stacking context here was
   what made the spotlight dim the whole page including the card itself. */
.wrap{
  position: relative;
  z-index: 1;
  padding-inline: var(--gutter);
}
.wrap:has(.products){
  z-index: auto;
}
/* The nav has to out-rank the hero, because the hero's particle canvas is
   position:fixed and covers the whole viewport. Both wraps sat at z-index 1,
   and the hero's comes later in the document, so the canvas painted over the
   nav — which meant the dashboard's own labels showed through the dropdown's
   solid background. The dropdown's z-index couldn't fix it on its own: it was
   trapped inside the nav wrap's stacking context. Kept below the spotlight
   overlay at 40 so the nav still dims with everything else. */
.wrap:has(.site-nav){
  z-index: 30;
}

.eyebrow{
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}

/* ---------- nav ---------- */
.site-nav{
  padding-block: 20px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-bottom: 1px solid var(--line);
}
.site-nav .name{
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 16px;
  text-decoration: none;
}
.site-nav .links{
  display: flex;
  gap: 28px;
  font-size: 14px;
}
.site-nav .links a{ text-decoration: none; color: var(--muted); }
.site-nav .links a:hover{ color: var(--ink); }

/* ---------- buttons ---------- */
.btn{
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 11px 22px;
  border-radius: 999px;
  background: var(--ink);
  color: var(--base);
  font-size: 14px;
  font-weight: 600;
  border: none;
  text-decoration: none;
  cursor: pointer;
}
.btn.ghost{
  background: transparent;
  color: var(--ink);
  border: 1px solid var(--line);
}
/* On hover the button's own solid shape wobbles: the CSS pill background
   hands over to a filled, deforming pill drawn on the canvas behind the
   label, so it reads as the button itself moving rather than a line
   wobbling around a static button. The handover is seamless because the
   drawn shape starts as an exact copy of the pill and eases into motion. */
.btn .btn-label{
  position: relative;
  z-index: 1;
}
.btn .btn-squiggle{
  position: absolute;
  inset: -16px;
  width: calc(100% + 32px);
  height: calc(100% + 32px);
  z-index: 0;
  opacity: 0;
  pointer-events: none;
}
.btn.is-particled{ background: transparent; }
.btn.is-particled .btn-squiggle{ opacity: 1; }
@media (prefers-reduced-motion: reduce){
  .btn.is-particled{ background: var(--ink); }
  .btn .btn-squiggle{ opacity: 0 !important; }
}

/* ---------- hero ---------- */
.hero{
  position: relative;
  padding-block: 96px 96px;
  min-height: 640px;
  display: flex;
  align-items: center;
}
/* The hero's particle canvas is fixed to the viewport, not boxed inside the
   hero section — the whole screen is the field it scatters across on load;
   the dashboard image itself resolves within a zone tracked to the hero's
   on-screen position, so it scrolls with the content while the chaos spans
   the entire window. */
.hero canvas.mark-field{
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  display: block;
  pointer-events: none;
  z-index: 0;
}
.hero .hero-text{
  position: relative;
  z-index: 1;
  max-width: 440px;
}
.hero h1{
  font-size: clamp(32px, 4.4vw, 52px);
  line-height: 1.1;
  margin-top: 14px;
}
.hero .signature-word{
  font-style: italic;
  font-weight: 600;
}
.hero p.sub{
  color: var(--muted);
  font-size: 17px;
  margin-top: 18px;
  max-width: 46ch;
}
.hero .cta-row{ margin-top: 28px; }
@media (max-width: 760px){
  .hero{ min-height: 620px; padding-block: 64px 760px; }
  /* name + CTA on one row, links wrap beneath, rather than the button
     being squeezed into a circle */
  .site-nav{ flex-wrap: wrap; gap: 10px 16px; }
  .site-nav .name{ flex: 1; }
  .site-nav .links{ order: 3; width: 100%; gap: 22px; }
  .site-nav .btn{ flex: none; white-space: nowrap; }
}

/* ---------- proof strip ---------- */
.proof-strip{
  padding-block: 22px;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--muted);
  display: flex;
  flex-wrap: wrap;
  gap: 10px 28px;
}

/* ---------- positioning statement ---------- */
.positioning{
  padding-block: 64px;
  max-width: 72ch;
}
.positioning p{
  font-size: 20px;
  line-height: 1.5;
  margin-top: 16px;
}

/* ---------- product cards ---------- */
.products{ padding-block: 56px; border-top: 1px solid var(--line); }
.products h2{ font-size: clamp(24px, 3vw, 32px); }
.card-grid{
  margin-top: 32px;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
}
/* Offer bands: the section opens on one and closes on one. The entry band
   is the front door, the ongoing band is the continuation after a build.
   Deliberately bands rather than cards in the grid — five or six cards
   orphan the last one in the auto-fit grid, and a peer card would read as
   one more thing to choose between rather than the way in or the way to
   stay. Their detail is always visible, where the cards hide theirs behind
   hover: these two are the ends of the ladder, so the reader should do the
   least work to see what they get. */
.offer-band{
  margin-top: 32px;
  display: grid;
  grid-template-columns: 220px 1fr;
  gap: 32px;
  padding: 26px 28px;
  border: 1px solid var(--line);
  background: var(--base);
  text-decoration: none;
  color: var(--ink);
  transition: border-color 0.9s cubic-bezier(0.45, 0, 0.2, 1);
}
.offer-band:hover{ border-color: var(--ink); }
.offer-band .entry-head h3{ font-size: 19px; margin-top: 10px; }
.offer-band .price{
  display: block;
  margin-top: 8px;
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--muted);
}
.offer-band p{ margin: 0; color: var(--muted); font-size: 14px; line-height: 1.5; max-width: 62ch; }
.offer-band ul{
  list-style: none;
  margin: 14px 0 0;
  padding: 0;
  display: grid;
  gap: 7px;
  font-size: 13px;
  color: var(--muted);
}
.offer-band li::before{ content: "—\00a0"; color: var(--ink); }
.offer-band .go{
  display: inline-block;
  margin-top: 16px;
  font-family: var(--font-mono);
  font-size: 13px;
}
@media (max-width: 760px){
  .offer-band{ grid-template-columns: 1fr; gap: 18px; }
}

.card{
  background: var(--base);
  padding: 28px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  text-decoration: none;
  color: var(--ink);
}
.card .price{ font-family: var(--font-mono); font-size: 13px; color: var(--muted); }
.card h3{ font-size: 19px; }
.card p{ color: var(--muted); font-size: 14px; line-height: 1.5; flex: 1; }
.card .go{ font-family: var(--font-mono); font-size: 13px; }
/* Closes the section as a footnote to every price above it. Three offers
   carry a From and one carries a band, and a range with no stated driver
   reads as "it depends" — which is the itemised-agency signal the section
   heading is arguing against. */
.price-note{
  margin-top: 20px;
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 1.6;
  color: var(--muted);
  max-width: 72ch;
}

/* ---------- principles / how I work ---------- */
/* The portrait is not a small canvas boxed in a grid column — the whole
   section is the particle field. Particles spill across its full width and
   height and converge into the portrait as the section scrolls into view;
   the text sits in a constrained column on top so it stays readable. */
.principles{
  position: relative;
  padding-block: 72px;
  min-height: 780px;
  display: flex;
  align-items: center;
  border-top: 1px solid var(--line);
  overflow: hidden;
}
.principles canvas.mark-field{
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  pointer-events: none;
  z-index: 0;
}
.principles > .eyebrow{ position: absolute; top: 28px; left: 0; z-index: 1; }
.principles-grid{
  position: relative;
  z-index: 1;
  max-width: 480px;
}
.principles ul{ list-style: none; margin: 0; padding: 0; display: grid; gap: 22px; }
.principles li{ max-width: 60ch; }
.principles li strong{ display: block; font-family: var(--font-display); font-size: 16px; margin-bottom: 4px; }
.principles li span{ color: var(--muted); font-size: 15px; }
@media (max-width: 760px){
  .principles{ min-height: 560px; padding-block: 64px 300px; }
  .principles-grid{ max-width: none; }
}

/* ---------- testimonials ---------- */
.testimonials{ padding-block: 56px; border-top: 1px solid var(--line); }
.t-grid{
  margin-top: 28px;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 32px;
}
.t-card{ position: relative; }
.t-card::before{
  content: "\201C";
  position: absolute;
  top: -30px;
  left: -2px;
  font-family: var(--font-display);
  font-size: 64px;
  line-height: 1;
  color: var(--ink);
  opacity: 0.1;
  pointer-events: none;
}
.t-card blockquote{
  position: relative;
  margin: 0;
  font-size: 17px;
  line-height: 1.5;
}
.t-card footer{
  margin-top: 18px;
  display: flex;
  align-items: center;
  gap: 12px;
}
.t-card footer img.t-logo{
  height: 18px;
  width: auto;
  display: block;
  opacity: 0.85;
}
.t-card footer .t-attrib{
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--muted);
  line-height: 1.4;
}
.t-card.placeholder{
  border: 1px dashed var(--line);
  padding: 20px;
  color: var(--muted);
}

/* ---------- closing cta ---------- */
.closing{
  padding-block: 64px;
  border-top: 1px solid var(--line);
  text-align: left;
}
.closing h2{ font-size: clamp(24px, 3.4vw, 36px); max-width: 20ch; }
.closing .closing-sub{
  margin: 16px 0 0;
  color: var(--muted);
  font-size: 17px;
  max-width: 52ch;
}
.closing .cta-row{ margin-top: 24px; }

/* ---------- legal pages ---------- */
.legal{ padding-block: 56px 72px; max-width: 72ch; }
.legal h1{ font-size: clamp(28px, 3.4vw, 38px); margin-top: 12px; }
.legal .updated{
  margin-top: 10px;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--muted);
}
.legal h2{ font-size: 18px; margin-top: 36px; }
.legal p, .legal li{ color: var(--muted); font-size: 15px; line-height: 1.65; }
.legal p{ margin: 12px 0 0; }
.legal ul{ margin: 12px 0 0; padding: 0; list-style: none; display: grid; gap: 8px; }
.legal li::before{ content: "—\00a0"; color: var(--ink); }
.legal a{ color: var(--ink); }

/* ---------- footer ---------- */
.site-footer{
  padding-block: 28px;
  border-top: 1px solid var(--line);
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 12px;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--muted);
}
.site-footer a{ text-decoration: none; color: var(--muted); }
.site-footer a:hover{ color: var(--ink); }

/* ---------- scroll reveal ---------- */
.reveal{
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}
.reveal.is-visible{
  opacity: 1;
  transform: translateY(0);
}
@media (prefers-reduced-motion: reduce){
  .reveal{ opacity: 1; transform: none; transition: none; }
}

/* stagger for grouped items */
.card-grid .card:nth-child(1){ transition-delay: 0ms; }
.card-grid .card:nth-child(2){ transition-delay: 90ms; }
.card-grid .card:nth-child(3){ transition-delay: 180ms; }
.card-grid .card:nth-child(4){ transition-delay: 270ms; }
.principles li:nth-child(1){ transition-delay: 0ms; }
.principles li:nth-child(2){ transition-delay: 90ms; }
.principles li:nth-child(3){ transition-delay: 180ms; }
.t-grid .t-card:nth-child(1){ transition-delay: 0ms; }
.t-grid .t-card:nth-child(2){ transition-delay: 90ms; }

/* ---------- card interaction: spotlight ---------- */
.spotlight-overlay{
  position: fixed;
  inset: 0;
  background: var(--ink);
  opacity: 0;
  pointer-events: none;
  transition: opacity 1.1s cubic-bezier(0.45, 0, 0.2, 1);
  z-index: 40;
}
.spotlight-overlay.is-active{ opacity: 0.7; }

.card{
  position: relative;
  background: var(--base);
  transition: transform 1.1s cubic-bezier(0.45, 0, 0.2, 1), box-shadow 1.1s cubic-bezier(0.45, 0, 0.2, 1);
  z-index: 1;
}
.card.is-spotlit{
  transform: translateY(-6px);
  box-shadow: 0 28px 52px -22px rgba(20,21,26,0.5);
  z-index: 50;
}
.card .go{ position: relative; display: inline-block; }
.card .go::after{
  content: "";
  position: absolute;
  left: 0; bottom: -3px;
  height: 1px; width: 0%;
  background: var(--ink);
  transition: width 1s cubic-bezier(0.45, 0, 0.2, 1);
}
.card.is-spotlit .go::after{ width: 100%; }

.card-detail{
  overflow: hidden;
  max-height: 0;
  opacity: 0;
  transition: max-height 1.3s cubic-bezier(0.45, 0, 0.2, 1) 80ms, opacity 1.1s ease 80ms, margin-top 1.3s cubic-bezier(0.45, 0, 0.2, 1) 80ms;
}
.card-detail ul{
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 7px;
  font-size: 13px;
  color: var(--muted);
  border-top: 1px solid var(--line);
  padding-top: 12px;
}
.card-detail li::before{ content: "— "; color: var(--ink); }
.card.is-spotlit .card-detail{
  max-height: 280px;
  opacity: 1;
  margin-top: 12px;
}
@media (prefers-reduced-motion: reduce){
  .card, .card .go::after, .card-detail, .spotlight-overlay{ transition: none; }
}
@media (hover: none){
  /* touch devices: no spotlight dimming, detail can't hinge on hover */
  .spotlight-overlay{ display: none; }
  .card-detail{ max-height: none; opacity: 1; margin-top: 12px; }
}

/* ---------- nav dropdown ---------- */
/* Two offer pages today and more later, so the menu needs somewhere for them
   to go that doesn't grow the nav bar one item at a time. Opens on hover for
   a mouse, on click or keyboard for everything else. */
.has-menu{ position: relative; }
.has-menu > button{
  font: inherit;
  font-size: 14px;
  color: var(--muted);
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.has-menu > button::after{
  content: "";
  width: 5px; height: 5px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform 0.25s ease;
}
.has-menu > button:hover,
.has-menu[data-open="true"] > button{ color: var(--ink); }
.has-menu[data-open="true"] > button::after{ transform: translateY(1px) rotate(225deg); }
.has-menu .menu{
  position: absolute;
  top: calc(100% + 14px);
  left: -18px;
  min-width: 232px;
  padding: 8px;
  background: var(--base);
  border: 1px solid var(--line);
  display: grid;
  gap: 2px;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px);
  transition: opacity 0.25s ease, transform 0.25s ease, visibility 0.25s;
  z-index: 60;
  box-shadow: 0 18px 34px -20px rgba(20,21,26,0.34);
}
.has-menu[data-open="true"] .menu{ opacity: 1; visibility: visible; transform: translateY(0); }
.has-menu .menu a{
  display: block;
  padding: 9px 12px;
  font-size: 14px;
  color: var(--muted);
  text-decoration: none;
}
.has-menu .menu a:hover,
.has-menu .menu a:focus-visible{ color: var(--ink); background: var(--base-2); }
.has-menu .menu .sep{ height: 1px; background: var(--line); margin: 6px 0; }
@media (max-width: 760px){
  .has-menu .menu{ position: static; opacity: 1; visibility: visible; transform: none;
    border: 0; box-shadow: none; padding: 4px 0 0 14px; min-width: 0; display: none; }
  .has-menu[data-open="true"] .menu{ display: grid; }
}

/* ---------- offer pages ---------- */
.offer-hero{ padding-block: 56px 8px; }
.offer-hero h1{ font-size: clamp(30px, 4vw, 46px); margin-top: 14px; max-width: 16ch; }
.offer-hero .lede{ font-size: 19px; color: var(--muted); margin-top: 18px; max-width: 58ch; line-height: 1.5; }
.offer-meta{
  margin-top: 28px;
  padding-block: 18px;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  display: flex;
  flex-wrap: wrap;
  gap: 10px 40px;
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--muted);
}
.offer-meta strong{ color: var(--ink); font-weight: 500; }
.offer-section{ padding-block: 44px; border-top: 1px solid var(--line); }
.offer-section:first-of-type{ border-top: 0; }
.offer-section h2{ font-size: clamp(21px, 2.4vw, 26px); margin-top: 12px; max-width: 24ch; }
.offer-section > p{ color: var(--muted); font-size: 16px; line-height: 1.6; margin: 14px 0 0; max-width: 66ch; }
.offer-list{ list-style: none; margin: 22px 0 0; padding: 0; display: grid; gap: 14px; max-width: 70ch; }
.offer-list li{ color: var(--muted); font-size: 15px; line-height: 1.55; }
.offer-list li strong{ display: block; color: var(--ink); font-family: var(--font-display); font-size: 16px; margin-bottom: 3px; }
.offer-list.plain li::before{ content: "—\00a0"; color: var(--ink); }

/* day-by-day / week-by-week runner */
.runbook{ margin-top: 24px; display: grid; gap: 1px; background: var(--line); border: 1px solid var(--line); }
.runbook .step{ background: var(--base); padding: 20px 22px; display: grid; grid-template-columns: 116px 1fr; gap: 24px; }
.runbook .step .when{ font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted); padding-top: 2px; }
.runbook .step p{ margin: 0; color: var(--muted); font-size: 15px; line-height: 1.55; }
.runbook .step p strong{ color: var(--ink); font-family: var(--font-display); display: block; margin-bottom: 3px; font-size: 16px; }
@media (max-width: 680px){ .runbook .step{ grid-template-columns: 1fr; gap: 8px; } }

/* two-column: what's in / what's not */
.split{ margin-top: 24px; display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 1px; background: var(--line); border: 1px solid var(--line); }
.split > div{ background: var(--base); padding: 24px 26px; }
.split h3{ font-size: 16px; }
.split ul{ list-style: none; margin: 14px 0 0; padding: 0; display: grid; gap: 9px; font-size: 14px; color: var(--muted); line-height: 1.5; }
.split li::before{ content: "—\00a0"; color: var(--ink); }

/* price bands */
.tiers{ margin-top: 24px; display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 1px; background: var(--line); border: 1px solid var(--line); }
.tiers > div{ background: var(--base); padding: 26px 28px; }
.tiers .price{ font-family: var(--font-mono); font-size: 13px; color: var(--muted); }
.tiers h3{ font-size: 18px; margin-top: 8px; }
.tiers p{ color: var(--muted); font-size: 14.5px; line-height: 1.55; margin: 12px 0 0; }
.tiers ul{ list-style: none; margin: 14px 0 0; padding: 0; display: grid; gap: 8px; font-size: 13.5px; color: var(--muted); line-height: 1.5; }
.tiers li::before{ content: "—\00a0"; color: var(--ink); }

.faq{ margin-top: 22px; display: grid; gap: 22px; max-width: 70ch; }
.faq h3{ font-size: 16px; }
.faq p{ color: var(--muted); font-size: 15px; line-height: 1.6; margin: 8px 0 0; }

.offer-cta{ padding-block: 52px; border-top: 1px solid var(--line); }
.offer-cta h2{ font-size: clamp(22px, 3vw, 30px); max-width: 20ch; }
.offer-cta p{ color: var(--muted); font-size: 17px; margin: 14px 0 0; max-width: 52ch; }
.offer-cta .cta-row{ margin-top: 24px; }
.backlink{ font-family: var(--font-mono); font-size: 13px; color: var(--muted); text-decoration: none; display: inline-block; margin-top: 8px; }
.backlink:hover{ color: var(--ink); }

/* ---------- cookie consent ---------- */
.consent{
  position: fixed;
  left: 20px; right: 20px; bottom: 20px;
  max-width: 560px;
  z-index: 80;
  background: var(--base);
  border: 1px solid var(--ink);
  padding: 20px 22px;
  display: grid;
  gap: 16px;
  opacity: 0;
  transform: translateY(12px);
  transition: opacity 0.5s ease, transform 0.5s cubic-bezier(0.45, 0, 0.2, 1);
  box-shadow: 0 24px 44px -26px rgba(20,21,26,0.5);
}
.consent.is-in{ opacity: 1; transform: translateY(0); }
.consent p{ margin: 0; font-size: 14px; line-height: 1.55; color: var(--muted); }
.consent-actions{ display: flex; gap: 10px; flex-wrap: wrap; }
.consent-actions button{
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  padding: 9px 20px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--ink);
  cursor: pointer;
}
.consent-actions button:hover{ border-color: var(--ink); }
.consent-actions button.is-primary{ background: var(--ink); color: var(--base); border-color: var(--ink); }
@media (prefers-reduced-motion: reduce){ .consent{ transition: none; } }
